Skip to content
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

chore: Use proper type declarations for methods returning self instances #1039

Merged
merged 7 commits into from
Oct 4, 2024
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
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ types-python-dateutil = "~=2.9"

[packages]
selenium = "~=4.24"
typing-extensions = "~=4.12.2"
36 changes: 18 additions & 18 deletions appium/webdriver/extensions/action_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.mouse_button import MouseButton
from selenium.webdriver.common.actions.pointer_input import PointerInput
from typing_extensions import Self

from appium.webdriver.webelement import WebElement

if TYPE_CHECKING:
# noinspection PyUnresolvedReferences
from appium.webdriver.webdriver import WebDriver


class ActionHelpers:
def scroll(self, origin_el: WebElement, destination_el: WebElement, duration: Optional[int] = None) -> 'WebDriver':
def scroll(self, origin_el: WebElement, destination_el: WebElement, duration: Optional[int] = None) -> Self:
"""Scrolls from one element to another

Args:
Expand All @@ -48,7 +50,7 @@ def scroll(self, origin_el: WebElement, destination_el: WebElement, duration: Op

touch_input = PointerInput(interaction.POINTER_TOUCH, 'touch')

actions = ActionChains(self)
actions = ActionChains(cast('WebDriver', self))
actions.w3c_actions = ActionBuilder(self, mouse=touch_input)

# https://github.com/SeleniumHQ/selenium/blob/3c82c868d4f2a7600223a1b3817301d0b04d28e4/py/selenium/webdriver/common/actions/pointer_actions.py#L83
Expand All @@ -59,11 +61,9 @@ def scroll(self, origin_el: WebElement, destination_el: WebElement, duration: Op
actions.w3c_actions.pointer_action.move_to(destination_el)
actions.w3c_actions.pointer_action.release()
actions.perform()
return cast('WebDriver', self)
return self

def drag_and_drop(
self, origin_el: WebElement, destination_el: WebElement, pause: Optional[float] = None
) -> 'WebDriver':
def drag_and_drop(self, origin_el: WebElement, destination_el: WebElement, pause: Optional[float] = None) -> Self:
"""Drag the origin element to the destination element

Args:
Expand All @@ -74,17 +74,17 @@ def drag_and_drop(
Returns:
Union['WebDriver', 'ActionHelpers']: Self instance
"""
actions = ActionChains(self)
actions = ActionChains(cast('WebDriver', self))
# 'mouse' pointer action
actions.w3c_actions.pointer_action.click_and_hold(origin_el)
if pause is not None and pause > 0:
actions.w3c_actions.pointer_action.pause(pause)
actions.w3c_actions.pointer_action.move_to(destination_el)
actions.w3c_actions.pointer_action.release()
actions.perform()
return cast('WebDriver', self)
return self

def tap(self, positions: List[Tuple[int, int]], duration: Optional[int] = None) -> 'WebDriver':
def tap(self, positions: List[Tuple[int, int]], duration: Optional[int] = None) -> Self:
"""Taps on an particular place with up to five fingers, holding for a
certain time

Expand All @@ -100,7 +100,7 @@ def tap(self, positions: List[Tuple[int, int]], duration: Optional[int] = None)
Union['WebDriver', 'ActionHelpers']: Self instance
"""
if len(positions) == 1:
actions = ActionChains(self)
actions = ActionChains(cast('WebDriver', self))
actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, 'touch'))
x = positions[0][0]
y = positions[0][1]
Expand All @@ -114,7 +114,7 @@ def tap(self, positions: List[Tuple[int, int]], duration: Optional[int] = None)
actions.perform()
else:
finger = 0
actions = ActionChains(self)
actions = ActionChains(cast('WebDriver', self))
actions.w3c_actions.devices = []

for position in positions:
Expand All @@ -132,9 +132,9 @@ def tap(self, positions: List[Tuple[int, int]], duration: Optional[int] = None)
new_input.create_pause(0.1)
new_input.create_pointer_up(MouseButton.LEFT)
actions.perform()
return cast('WebDriver', self)
return self

def swipe(self, start_x: int, start_y: int, end_x: int, end_y: int, duration: int = 0) -> 'WebDriver':
def swipe(self, start_x: int, start_y: int, end_x: int, end_y: int, duration: int = 0) -> Self:
"""Swipe from one point to another point, for an optional duration.

Args:
Expand All @@ -152,7 +152,7 @@ def swipe(self, start_x: int, start_y: int, end_x: int, end_y: int, duration: in
"""
touch_input = PointerInput(interaction.POINTER_TOUCH, 'touch')

actions = ActionChains(self)
actions = ActionChains(cast('WebDriver', self))
actions.w3c_actions = ActionBuilder(self, mouse=touch_input)
actions.w3c_actions.pointer_action.move_to_location(start_x, start_y)
actions.w3c_actions.pointer_action.pointer_down()
Expand All @@ -161,9 +161,9 @@ def swipe(self, start_x: int, start_y: int, end_x: int, end_y: int, duration: in
actions.w3c_actions.pointer_action.move_to_location(end_x, end_y)
actions.w3c_actions.pointer_action.release()
actions.perform()
return cast('WebDriver', self)
return self

def flick(self, start_x: int, start_y: int, end_x: int, end_y: int) -> 'WebDriver':
def flick(self, start_x: int, start_y: int, end_x: int, end_y: int) -> Self:
"""Flick from one point to another point.

Args:
Expand All @@ -178,11 +178,11 @@ def flick(self, start_x: int, start_y: int, end_x: int, end_y: int) -> 'WebDrive
Returns:
Union['WebDriver', 'ActionHelpers']: Self instance
"""
actions = ActionChains(self)
actions = ActionChains(cast('WebDriver', self))
actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, 'touch'))
actions.w3c_actions.pointer_action.move_to_location(start_x, start_y)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.move_to_location(end_x, end_y)
actions.w3c_actions.pointer_action.release()
actions.perform()
return cast('WebDriver', self)
return self
9 changes: 3 additions & 6 deletions appium/webdriver/extensions/android/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING, cast

from selenium.common.exceptions import UnknownMethodException
from typing_extensions import Self

from appium.protocols.webdriver.can_execute_commands import CanExecuteCommands
from appium.protocols.webdriver.can_execute_scripts import CanExecuteScripts
from appium.protocols.webdriver.can_remember_extension_presence import CanRememberExtensionPresence
from appium.webdriver.mobilecommand import MobileCommand as Command

if TYPE_CHECKING:
from appium.webdriver.webdriver import WebDriver


class Common(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence):
def open_notifications(self) -> 'WebDriver':
def open_notifications(self) -> Self:
"""Open notification shade in Android (API Level 18 and above)

Returns:
Expand All @@ -37,7 +34,7 @@ def open_notifications(self) -> 'WebDriver':
except UnknownMethodException:
# TODO: Remove the fallback
self.mark_extension_absence(ext_name).execute(Command.OPEN_NOTIFICATIONS, {})
return cast('WebDriver', self)
return self

@property
def current_package(self) -> str:
Expand Down
18 changes: 7 additions & 11 deletions appium/webdriver/extensions/android/gsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import TYPE_CHECKING, cast

from selenium.common.exceptions import UnknownMethodException
from typing_extensions import Self

from appium.common.helper import extract_const_attributes
from appium.common.logger import logger
Expand All @@ -23,9 +22,6 @@
from appium.protocols.webdriver.can_remember_extension_presence import CanRememberExtensionPresence
from appium.webdriver.mobilecommand import MobileCommand as Command

if TYPE_CHECKING:
from appium.webdriver.webdriver import WebDriver


class GsmCallActions:
CALL = 'call'
Expand Down Expand Up @@ -53,7 +49,7 @@ class GsmVoiceState:


class Gsm(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence):
def make_gsm_call(self, phone_number: str, action: str) -> 'WebDriver':
def make_gsm_call(self, phone_number: str, action: str) -> Self:
"""Make GSM call (Emulator only)

Android only.
Expand Down Expand Up @@ -82,9 +78,9 @@ def make_gsm_call(self, phone_number: str, action: str) -> 'WebDriver':
except UnknownMethodException:
# TODO: Remove the fallback
self.mark_extension_absence(ext_name).execute(Command.MAKE_GSM_CALL, args)
return cast('WebDriver', self)
return self

def set_gsm_signal(self, strength: int) -> 'WebDriver':
def set_gsm_signal(self, strength: int) -> Self:
"""Set GSM signal strength (Emulator only)

Android only.
Expand Down Expand Up @@ -113,9 +109,9 @@ def set_gsm_signal(self, strength: int) -> 'WebDriver':
self.mark_extension_absence(ext_name).execute(
Command.SET_GSM_SIGNAL, {'signalStrength': strength, 'signalStrengh': strength}
)
return cast('WebDriver', self)
return self

def set_gsm_voice(self, state: str) -> 'WebDriver':
def set_gsm_voice(self, state: str) -> Self:
"""Set GSM voice state (Emulator only)

Android only.
Expand Down Expand Up @@ -143,7 +139,7 @@ def set_gsm_voice(self, state: str) -> 'WebDriver':
except UnknownMethodException:
# TODO: Remove the fallback
self.mark_extension_absence(ext_name).execute(Command.SET_GSM_VOICE, args)
return cast('WebDriver', self)
return self

def _add_commands(self) -> None:
# noinspection PyProtectedMember,PyUnresolvedReferences
Expand Down
14 changes: 5 additions & 9 deletions appium/webdriver/extensions/android/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import TYPE_CHECKING, cast

from selenium.common.exceptions import UnknownMethodException
from typing_extensions import Self

from appium.common.helper import extract_const_attributes
from appium.common.logger import logger
Expand All @@ -23,9 +22,6 @@
from appium.protocols.webdriver.can_remember_extension_presence import CanRememberExtensionPresence
from appium.webdriver.mobilecommand import MobileCommand as Command

if TYPE_CHECKING:
from appium.webdriver.webdriver import WebDriver


class NetSpeed:
GSM = 'gsm' # GSM/CSD (up: 14.4(kbps), down: 14.4(kbps))
Expand Down Expand Up @@ -114,7 +110,7 @@ def set_network_connection(self, connection_type: int) -> int:
Command.SET_NETWORK_CONNECTION, {'parameters': {'type': connection_type}}
)['value']

def toggle_wifi(self) -> 'WebDriver':
def toggle_wifi(self) -> Self:
"""Toggle the wifi on the device, Android only.
This API only works reliably on emulators (any version) and real devices
since API level 31.
Expand All @@ -129,9 +125,9 @@ def toggle_wifi(self) -> 'WebDriver':
)
except UnknownMethodException:
self.mark_extension_absence(ext_name).execute(Command.TOGGLE_WIFI, {})
return cast('WebDriver', self)
return self

def set_network_speed(self, speed_type: str) -> 'WebDriver':
def set_network_speed(self, speed_type: str) -> Self:
"""Set the network speed emulation.

Android Emulator only.
Expand All @@ -158,7 +154,7 @@ def set_network_speed(self, speed_type: str) -> 'WebDriver':
except UnknownMethodException:
# TODO: Remove the fallback
self.mark_extension_absence(ext_name).execute(Command.SET_NETWORK_SPEED, {'netspeed': speed_type})
return cast('WebDriver', self)
return self

def _add_commands(self) -> None:
# noinspection PyProtectedMember,PyUnresolvedReferences
Expand Down
14 changes: 5 additions & 9 deletions appium/webdriver/extensions/android/power.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import TYPE_CHECKING, cast

from selenium.common.exceptions import UnknownMethodException
from typing_extensions import Self

from appium.protocols.webdriver.can_execute_commands import CanExecuteCommands
from appium.protocols.webdriver.can_execute_scripts import CanExecuteScripts
from appium.protocols.webdriver.can_remember_extension_presence import CanRememberExtensionPresence
from appium.webdriver.mobilecommand import MobileCommand as Command

if TYPE_CHECKING:
from appium.webdriver.webdriver import WebDriver


class Power(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence):
AC_OFF, AC_ON = 'off', 'on'

def set_power_capacity(self, percent: int) -> 'WebDriver':
def set_power_capacity(self, percent: int) -> Self:
"""Emulate power capacity change on the connected emulator.

Android only.
Expand All @@ -49,9 +45,9 @@ def set_power_capacity(self, percent: int) -> 'WebDriver':
except UnknownMethodException:
# TODO: Remove the fallback
self.mark_extension_absence(ext_name).execute(Command.SET_POWER_CAPACITY, args)
return cast('WebDriver', self)
return self

def set_power_ac(self, ac_state: str) -> 'WebDriver':
def set_power_ac(self, ac_state: str) -> Self:
"""Emulate power state change on the connected emulator.

Android only.
Expand All @@ -73,7 +69,7 @@ def set_power_ac(self, ac_state: str) -> 'WebDriver':
except UnknownMethodException:
# TODO: Remove the fallback
self.mark_extension_absence(ext_name).execute(Command.SET_POWER_AC, args)
return cast('WebDriver', self)
return self

def _add_commands(self) -> None:
# noinspection PyProtectedMember,PyUnresolvedReferences
Expand Down
10 changes: 3 additions & 7 deletions appium/webdriver/extensions/android/sms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import TYPE_CHECKING, cast

from selenium.common.exceptions import UnknownMethodException
from typing_extensions import Self

from appium.protocols.webdriver.can_execute_commands import CanExecuteCommands
from appium.protocols.webdriver.can_execute_scripts import CanExecuteScripts
from appium.protocols.webdriver.can_remember_extension_presence import CanRememberExtensionPresence
from appium.webdriver.mobilecommand import MobileCommand as Command

if TYPE_CHECKING:
from appium.webdriver.webdriver import WebDriver


class Sms(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence):
def send_sms(self, phone_number: str, message: str) -> 'WebDriver':
def send_sms(self, phone_number: str, message: str) -> Self:
"""Emulate send SMS event on the connected emulator.

Android only.
Expand All @@ -48,7 +44,7 @@ def send_sms(self, phone_number: str, message: str) -> 'WebDriver':
except UnknownMethodException:
# TODO: Remove the fallback
self.mark_extension_absence(ext_name).execute(Command.SEND_SMS, args)
return cast('WebDriver', self)
return self

def _add_commands(self) -> None:
# noinspection PyProtectedMember,PyUnresolvedReferences
Expand Down
Loading
Loading