Skip to content

[py] Various type hinting improvements #15740

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: trunk
Choose a base branch
from

Conversation

DeflateAwning
Copy link
Contributor

@DeflateAwning DeflateAwning commented May 14, 2025

User description

💥 What does this PR do?

Improves type hinting support


PR Type

Enhancement


Description

  • Add and refine type hints across actions modules

  • Use Literal and Union for stricter typing

  • Update method signatures for better type safety

  • Add docstrings to clarify argument types


Changes walkthrough 📝

Relevant files
Enhancement
7 files
action_builder.py
Refine pointer input method type hints                                     
+1/-1     
input_device.py
Update pause method to use Union type hints                           
+2/-1     
interaction.py
Add Literal and Union type hints for sources and kinds     
+12/-3   
key_input.py
Add type hints and Literal usage for key actions                 
+13/-7   
pointer_input.py
Add and refine type hints for pointer actions                       
+14/-13 
wheel_actions.py
Add type hints and docstrings for wheel actions                   
+16/-3   
wheel_input.py
Add type hints and docstrings for wheel input and scroll origin
+19/-6   

Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • @selenium-ci selenium-ci added the C-py Python Bindings label May 14, 2025
    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Type Mismatch

    In TypingInteraction.init, the source parameter is typed as str but in usage it's passed a KeyInput object. This type mismatch could cause type checking errors.

    def __init__(self, source: str, type_: Literal["keyUp", "keyDown"], key: str) -> None:
        super().__init__(source)
    Circular Import

    The imports from key_input, pointer_input, and wheel_input modules may create circular imports since these modules also import from interaction.py.

    from .key_input import KeyInput
    from .pointer_input import PointerInput
    from .wheel_input import WheelInput

    Copy link
    Contributor

    qodo-merge-pro bot commented May 14, 2025

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Fix parameter type annotation

    The source parameter type is incorrect. In the TypingInteraction constructor,
    source should be of type KeyInput to match the parent class Interaction which
    now expects a Union[KeyInput, PointerInput, WheelInput] parameter.

    py/selenium/webdriver/common/actions/key_input.py [49-52]

    -def __init__(self, source: str, type_: Literal["keyUp", "keyDown"], key: str) -> None:
    +def __init__(self, source: KeyInput, type_: Literal["keyUp", "keyDown"], key: str) -> None:
         super().__init__(source)
         self.type = type_
         self.key = key
    • Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly identifies that the source parameter should be typed as KeyInput to match the updated base class constructor, improving type safety and consistency. However, this is a minor correctness and maintainability improvement, not a critical bug fix.

    Medium
    Fix inconsistent parameter documentation

    The duration parameter is used as milliseconds in the action dictionary but
    documented as seconds. Either update the implementation to convert seconds to
    milliseconds or update the type annotation to clarify it expects milliseconds.

    py/selenium/webdriver/common/actions/wheel_input.py [65-71]

     def create_scroll(
         self, x: int, y: int, delta_x: int, delta_y: int, duration: Union[float, int], origin: Union[str, WebElement, Dict[str, str]]
     ) -> None:
    +    """
    +    :Args:
    +     - duration: The duration to pause for after the scroll, in milliseconds.
    +    """

    [To ensure code accuracy, apply this suggestion manually]

    Suggestion importance[1-10]: 6

    __

    Why: The suggestion highlights a documentation mismatch regarding the duration parameter's unit, which helps prevent confusion for users. This is a minor but useful documentation fix, not a functional or critical code change.

    Low
    Possible issue
    Fix time unit inconsistency

    The docstring states duration is in seconds, but the implementation in the
    method body uses milliseconds (multiplies by 1000 like in create_pause). Either
    update the docstring to indicate milliseconds or convert the duration in the
    implementation.

    py/selenium/webdriver/common/actions/wheel_input.py [65-73]

     def create_scroll(
         self, x: int, y: int, delta_x: int, delta_y: int, duration: Union[float, int], origin: Union[str, WebElement, Dict[str, str]]
     ) -> None:
         """
         :Args:
          - duration: The duration to pause for after the scroll, in seconds.
         """
    +    if isinstance(origin, WebElement):
    +        origin = {"element-6066-11e4-a52e-4f735466cecf": origin.id}
    +    self.add_action(
    +        {
    +            "type": "scroll",
    +            "x": x,
    +            "y": y,
    +            "deltaX": delta_x,
    +            "deltaY": delta_y,
    +            "duration": int(duration * 1000),
    +            "origin": origin,
    +        }
    +    )

    [To ensure code accuracy, apply this suggestion manually]

    Suggestion importance[1-10]: 8

    __

    Why: This suggestion addresses a potential bug where the duration unit in the implementation does not match the docstring, which could lead to incorrect behavior. Correcting this ensures the code behaves as documented, making it an important fix.

    Medium
    Fix circular import dependency

    There's a circular import issue in the interaction.py file. The imports for
    KeyInput, PointerInput, and WheelInput are used in type annotations but these
    classes themselves import from interaction.py, creating a circular dependency.
    Use string literals for type annotations instead.

    py/selenium/webdriver/common/actions/interaction.py [42-43]

    -def __init__(self, source: Union[KeyInput, PointerInput, WheelInput]) -> None:
    +def __init__(self, source: Union["KeyInput", "PointerInput", "WheelInput"]) -> None:
         self.source = source
    • Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: Using string literal type annotations can help prevent circular import issues, which is a reasonable and contextually accurate suggestion. However, this is a precautionary measure rather than a critical fix, so it merits a moderate score.

    Medium
    General
    Add missing type annotation

    The button parameter in create_pointer_up method lacks type annotation while
    other similar methods have proper type hints. Add appropriate type annotation to
    maintain consistency.

    py/selenium/webdriver/common/actions/pointer_input.py [62-63]

    -def create_pointer_up(self, button) -> None:
    +def create_pointer_up(self, button: int) -> None:
         self.add_action({"type": "pointerUp", "duration": 0, "button": button})
    • Apply / Chat
    Suggestion importance[1-10]: 5

    __

    Why: Adding a type annotation for the button parameter improves code clarity and consistency, but it is a minor enhancement that does not affect functionality or correctness.

    Low
    General
    Fix parameter type annotation

    The origin parameter type annotation is too restrictive. It's defined as str but
    the implementation in create_scroll accepts Union[str, WebElement, Dict[str,
    str]]. Update the type annotation to match the accepted types.

    py/selenium/webdriver/common/actions/wheel_actions.py [35-49]

     def scroll(
         self,
         x: int = 0,
         y: int = 0,
         delta_x: int = 0,
         delta_y: int = 0,
         duration: Union[float, int] = 0,
    -    origin: str = "viewport",
    +    origin: Union[str, WebElement, Dict[str, str]] = "viewport",
     ) -> "WheelActions":
         """
         :Args:
          - duration: The duration of the scroll, in seconds.
         """
         self.source.create_scroll(x, y, delta_x, delta_y, duration, origin)
         return self
    • Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly updates the type annotation for the origin parameter to match the accepted types in the implementation, improving type safety and clarity. This is a moderate improvement for maintainability and correctness.

    Medium
    Ensure consistent duration handling

    The duration parameter is stored directly, but in other implementations like
    create_pause, durations are converted to milliseconds. Consider converting the
    duration to milliseconds for consistency or document the expected unit clearly.

    py/selenium/webdriver/common/actions/interaction.py [47-52]

     def __init__(self, source: Union[KeyInput, PointerInput, WheelInput], duration: Union[int, float] = 0) -> None:
         """
         :Args:
          - duration: duration of the pause in seconds"""
         super().__init__(source)
    -    self.duration = duration
    +    self.duration = int(duration * 1000)  # Convert to milliseconds for consistency
    • Apply / Chat
    Suggestion importance[1-10]: 6

    __

    Why: The suggestion highlights a potential inconsistency in how duration is handled and proposes converting it to milliseconds, which could prevent subtle bugs. However, it is not critical unless the rest of the codebase expects milliseconds, so the impact is moderate.

    Low
    Learned
    best practice
    Complete parameter documentation

    The documentation is incomplete, only explaining the duration parameter. Add
    documentation for all parameters to improve code maintainability and prevent
    misuse. This is especially important for parameters like x, y, delta_x, and
    delta_y.

    py/selenium/webdriver/common/actions/wheel_actions.py [35-47]

     def scroll(
         self,
         x: int = 0,
         y: int = 0,
         delta_x: int = 0,
         delta_y: int = 0,
         duration: Union[float, int] = 0,
         origin: str = "viewport",
     ) -> "WheelActions":
         """
         :Args:
    -     - duration: The duration of the scroll, in seconds.
    +     - x: The x coordinate to scroll to
    +     - y: The y coordinate to scroll to
    +     - delta_x: The distance in pixels to scroll on the x-axis
    +     - delta_y: The distance in pixels to scroll on the y-axis
    +     - duration: The duration of the scroll, in seconds
    +     - origin: The origin of the scroll coordinates (viewport or element)
         """
    • Apply / Chat
    Suggestion importance[1-10]: 6

    __

    Why:
    Relevant best practice - Add clear documentation for method parameters to prevent misuse and improve code maintainability.

    Low
    • More

    @cgoldberg
    Copy link
    Contributor

    Thanks. Take a look at the AI bot's feedback and fix whatever is appropriate (he's often wrong) and I'll review this tomorrow.

    @cgoldberg
    Copy link
    Contributor

    @DeflateAwning

    CI tests are failing due to this:

    E   ImportError: cannot import name 'Interaction' from partially initialized module 'selenium.webdriver.common.actions.interaction' (most likely due to a circular import)
    

    There are also a bunch of linting errors. You can fix those (or at least see what's failing) by running: tox -c py/tox.ini -e linting from the main directory in your repo.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    3 participants