Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 44 additions & 25 deletions py/selenium/webdriver/common/action_chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@
# specific language governing permissions and limitations
# under the License.

"""The ActionChains implementation,"""
"""The ActionChains implementation."""
from __future__ import annotations

import warnings
from typing import TYPE_CHECKING
from typing import List
from typing import Optional
from typing import Union

from selenium.webdriver.remote.webelement import WebElement

Expand All @@ -27,6 +33,17 @@
from .actions.wheel_input import WheelInput
from .utils import keys_to_typing

if TYPE_CHECKING:
from selenium.webdriver import Chrome
from selenium.webdriver import Edge
from selenium.webdriver import Firefox
from selenium.webdriver import Ie
from selenium.webdriver import Safari

AnyDriver = Union[Chrome, Firefox, Safari, Ie, Edge]

AnyDevice = Union[PointerInput, KeyInput, WheelInput]


class ActionChains:
"""ActionChains are a way to automate low level interactions such as mouse
Expand Down Expand Up @@ -61,7 +78,7 @@ class ActionChains:
another.
"""

def __init__(self, driver, duration=250, devices=None):
def __init__(self, driver: AnyDriver, duration: int = 250, devices: Optional[List[AnyDevice]] = None) -> None:
"""Creates a new ActionChains.

:Args:
Expand All @@ -82,18 +99,18 @@ def __init__(self, driver, duration=250, devices=None):
wheel = device
self.w3c_actions = ActionBuilder(driver, mouse=mouse, keyboard=keyboard, wheel=wheel, duration=duration)

def perform(self):
def perform(self) -> None:
"""Performs all stored actions."""
self.w3c_actions.perform()

def reset_actions(self):
def reset_actions(self) -> None:
"""Clears actions that are already stored locally and on the remote
end."""
self.w3c_actions.clear_actions()
for device in self.w3c_actions.devices:
device.clear_actions()

def click(self, on_element=None):
def click(self, on_element: Optional[WebElement] = None) -> "ActionChains":
"""Clicks an element.

:Args:
Expand All @@ -109,7 +126,7 @@ def click(self, on_element=None):

return self

def click_and_hold(self, on_element=None):
def click_and_hold(self, on_element: Optional[WebElement] = None) -> "ActionChains":
"""Holds down the left mouse button on an element.

:Args:
Expand All @@ -124,7 +141,7 @@ def click_and_hold(self, on_element=None):

return self

def context_click(self, on_element=None):
def context_click(self, on_element: Optional[WebElement] = None) -> "ActionChains":
"""Performs a context-click (right click) on an element.

:Args:
Expand All @@ -140,7 +157,7 @@ def context_click(self, on_element=None):

return self

def double_click(self, on_element=None):
def double_click(self, on_element: Optional[WebElement] = None) -> "ActionChains":
"""Double-clicks an element.

:Args:
Expand All @@ -156,7 +173,7 @@ def double_click(self, on_element=None):

return self

def drag_and_drop(self, source, target):
def drag_and_drop(self, source: WebElement, target: WebElement) -> "ActionChains":
"""Holds down the left mouse button on the source element, then moves
to the target element and releases the mouse button.

Expand All @@ -168,7 +185,7 @@ def drag_and_drop(self, source, target):
self.release(target)
return self

def drag_and_drop_by_offset(self, source, xoffset, yoffset):
def drag_and_drop_by_offset(self, source: WebElement, xoffset: int, yoffset: int) -> "ActionChains":
"""Holds down the left mouse button on the source element, then moves
to the target offset and releases the mouse button.

Expand All @@ -182,7 +199,7 @@ def drag_and_drop_by_offset(self, source, xoffset, yoffset):
self.release()
return self

def key_down(self, value, element=None):
def key_down(self, value: str, element: Optional[WebElement] = None) -> "ActionChains":
"""Sends a key press only, without releasing it. Should only be used
with modifier keys (Control, Alt and Shift).

Expand All @@ -203,7 +220,7 @@ def key_down(self, value, element=None):

return self

def key_up(self, value, element=None):
def key_up(self, value: str, element: Optional[WebElement] = None) -> "ActionChains":
"""Releases a modifier key.

:Args:
Expand All @@ -223,7 +240,7 @@ def key_up(self, value, element=None):

return self

def move_by_offset(self, xoffset, yoffset):
def move_by_offset(self, xoffset: int, yoffset: int) -> "ActionChains":
"""Moving the mouse to an offset from current mouse position.

:Args:
Expand All @@ -236,7 +253,7 @@ def move_by_offset(self, xoffset, yoffset):

return self

def move_to_element(self, to_element):
def move_to_element(self, to_element: WebElement) -> "ActionChains":
"""Moving the mouse to the middle of an element.

:Args:
Expand All @@ -248,7 +265,7 @@ def move_to_element(self, to_element):

return self

def move_to_element_with_offset(self, to_element, xoffset, yoffset):
def move_to_element_with_offset(self, to_element: WebElement, xoffset: int, yoffset: int) -> "ActionChains":
"""Move the mouse by an offset of the specified element. Offsets are
relative to the in-view center point of the element.

Expand All @@ -263,15 +280,15 @@ def move_to_element_with_offset(self, to_element, xoffset, yoffset):

return self

def pause(self, seconds):
def pause(self, seconds: Union[float, int]) -> "ActionChains":
"""Pause all inputs for the specified duration in seconds."""

self.w3c_actions.pointer_action.pause(seconds)
self.w3c_actions.key_action.pause(seconds)

return self

def release(self, on_element=None):
def release(self, on_element: Optional[WebElement] = None) -> "ActionChains":
"""Releasing a held mouse button on an element.

:Args:
Expand All @@ -286,7 +303,7 @@ def release(self, on_element=None):

return self

def send_keys(self, *keys_to_send):
def send_keys(self, *keys_to_send: str) -> "ActionChains":
"""Sends keys to current focused element.

:Args:
Expand All @@ -301,7 +318,7 @@ def send_keys(self, *keys_to_send):

return self

def send_keys_to_element(self, element, *keys_to_send):
def send_keys_to_element(self, element: WebElement, *keys_to_send: str) -> "ActionChains":
"""Sends keys to an element.

:Args:
Expand All @@ -313,7 +330,7 @@ def send_keys_to_element(self, element, *keys_to_send):
self.send_keys(*keys_to_send)
return self

def scroll_to_element(self, element: WebElement):
def scroll_to_element(self, element: WebElement) -> "ActionChains":
"""If the element is outside the viewport, scrolls the bottom of the
element to the bottom of the viewport.

Expand All @@ -324,7 +341,7 @@ def scroll_to_element(self, element: WebElement):
self.w3c_actions.wheel_action.scroll(origin=element)
return self

def scroll_by_amount(self, delta_x: int, delta_y: int):
def scroll_by_amount(self, delta_x: int, delta_y: int) -> "ActionChains":
"""Scrolls by provided amounts with the origin in the top left corner
of the viewport.

Expand All @@ -336,7 +353,7 @@ def scroll_by_amount(self, delta_x: int, delta_y: int):
self.w3c_actions.wheel_action.scroll(delta_x=delta_x, delta_y=delta_y)
return self

def scroll_from_origin(self, scroll_origin: ScrollOrigin, delta_x: int, delta_y: int):
def scroll_from_origin(self, scroll_origin: ScrollOrigin, delta_x: int, delta_y: int) -> "ActionChains":
"""Scrolls by provided amount based on a provided origin. The scroll
origin is either the center of an element or the upper left of the
viewport plus any offsets. If the origin is an element, and the element
Expand Down Expand Up @@ -364,7 +381,9 @@ def scroll_from_origin(self, scroll_origin: ScrollOrigin, delta_x: int, delta_y:
)
return self

def scroll(self, x: int, y: int, delta_x: int, delta_y: int, duration: int = 0, origin: str = "viewport"):
def scroll(
self, x: int, y: int, delta_x: int, delta_y: int, duration: int = 0, origin: str = "viewport"
) -> "ActionChains":
"""Sends wheel scroll information to the browser to be processed.

:Args:
Expand All @@ -386,8 +405,8 @@ def scroll(self, x: int, y: int, delta_x: int, delta_y: int, duration: int = 0,

# Context manager so ActionChains can be used in a 'with .. as' statements.

def __enter__(self):
def __enter__(self) -> "ActionChains":
return self # Return created instance of self.

def __exit__(self, _type, _value, _traceback):
def __exit__(self, _type, _value, _traceback) -> None:
pass # Do nothing, does not require additional cleanup.
10 changes: 5 additions & 5 deletions py/selenium/webdriver/common/alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Alert:
self.assertEqual("Do you wish to quit?", alert_text)
"""

def __init__(self, driver):
def __init__(self, driver) -> None:
"""Creates a new Alert.

:Args:
Expand All @@ -54,15 +54,15 @@ def __init__(self, driver):
self.driver = driver

@property
def text(self):
def text(self) -> str:
"""Gets the text of the Alert."""
return self.driver.execute(Command.W3C_GET_ALERT_TEXT)["value"]

def dismiss(self):
def dismiss(self) -> None:
"""Dismisses the alert available."""
self.driver.execute(Command.W3C_DISMISS_ALERT)

def accept(self):
def accept(self) -> None:
"""Accepts the alert available.

:Usage:
Expand All @@ -72,7 +72,7 @@ def accept(self):
"""
self.driver.execute(Command.W3C_ACCEPT_ALERT)

def send_keys(self, keysToSend):
def send_keys(self, keysToSend: str) -> None:
"""Send Keys to the Alert.

:Args:
Expand Down
2 changes: 1 addition & 1 deletion py/selenium/webdriver/ie/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,4 @@ def to_capabilities(self) -> dict:

@property
def default_capabilities(self) -> dict:
return DesiredCapabilities.INTERNETEXPLORER.copy()
return DesiredCapabilities.INTERNETEXPLORER.copy()