Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
26 changes: 9 additions & 17 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
repos:
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort
args: [ "." ]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
entry: mypy appium/ test/functional
pass_filenames: false
additional_dependencies: [types-python-dateutil==2.8.19.13]
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
args: [ ".", "-l", "120", "-S" ]
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
hooks:
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format
31 changes: 31 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
line-length = 128
indent-width = 4

[lint]
select = [
# Pyflakes
"F",
# Pylint
"PL",
# isort
"I",
]

[lint.per-file-ignores]
"__init__.py" = [
# unused-import
"F401",
# import violations
"E402"
]
"**/{test,docs}/*" = [
# https://docs.astral.sh/ruff/rules/magic-value-comparison/
"PLR2004"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to prevent error like below:

test/unit/webdriver/network_test.py:33:45: PLR2004 Magic value used in comparison, consider replacing `2` with a constant variable
   |
31 |             body='{"value": {"wifi": true, "data": false, "airplaneMode": false}}',
32 |         )
33 |         assert driver.network_connection == 2
   |                                             ^ PLR2004
34 | 
35 |     @httpretty.activate
   |

]

[lint.pylint]

max-args = 6

[format]
quote-style = "single"
4 changes: 1 addition & 3 deletions appium/options/android/common/adb/adb_exec_timeout_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ def adb_exec_timeout(self, value: Union[timedelta, int]) -> None:
Maximum time to wait until single ADB command is executed.
20000 ms by default.
"""
self.set_capability(
ADB_EXEC_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
)
self.set_capability(ADB_EXEC_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ def app_wait_duration(self, value: Union[timedelta, int]) -> None:
Maximum amount of time to wait until the application under test is started
(e.g. an activity returns the control to the caller). 20000 ms by default.
"""
self.set_capability(
APP_WAIT_DURATION, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
)
self.set_capability(APP_WAIT_DURATION, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ def avd_launch_timeout(self, value: Union[timedelta, int]) -> None:
Maximum timeout to wait until Android Emulator is started.
60000 ms by default.
"""
self.set_capability(
AVD_LAUNCH_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
)
self.set_capability(AVD_LAUNCH_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ def avd_ready_timeout(self, value: Union[timedelta, int]) -> None:
Maximum timeout to wait until Android Emulator is fully booted and is ready for usage.
60000 ms by default
"""
self.set_capability(
AVD_READY_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
)
self.set_capability(AVD_READY_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ def auto_webview_timeout(self, value: Union[timedelta, int]) -> None:
"""
Timeout to wait until a web view is available.
"""
self.set_capability(
AUTO_WEBVIEW_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
)
self.set_capability(AUTO_WEBVIEW_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value)
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,4 @@ def espresso_build_config(self, value: Union[Dict[str, Any], str]) -> None:
https://github.com/appium/appium-espresso-driver#espresso-build-config
for more information on how to properly construct such config.
"""
self.set_capability(
ESPRESSO_BUILD_CONFIG, value if isinstance(value, str) else json.dumps(value, ensure_ascii=False)
)
self.set_capability(ESPRESSO_BUILD_CONFIG, value if isinstance(value, str) else json.dumps(value, ensure_ascii=False))
1 change: 0 additions & 1 deletion appium/options/flutter_integration/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class FlutterOptions(
FlutterServerLaunchTimeOutOption,
FlutterSystemPortOption,
):

@property
def default_capabilities(self) -> Dict:
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@


class FlutterElementWaitTimeOutOption(SupportsCapabilities):

@property
def flutter_element_wait_timeout(self) -> Optional[timedelta]:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@
# specific language governing permissions and limitations
# under the License.

from typing import Optional

from appium.options.common.supports_capabilities import SupportsCapabilities

FLUTTER_ENABLE_MOCK_CAMERA = 'flutterEnableMockCamera'


class FlutterEnableMockCameraOption(SupportsCapabilities):

@property
def flutter_enable_mock_camera(self) -> bool:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@


class FlutterServerLaunchTimeOutOption(SupportsCapabilities):

@property
def flutter_server_launch_timeout(self) -> Optional[timedelta]:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@


class FlutterSystemPortOption(SupportsCapabilities):

@property
def flutter_system_port(self) -> Optional[int]:
"""
Expand Down
4 changes: 1 addition & 3 deletions appium/options/ios/xcuitest/app/app_push_timeout_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,4 @@ def app_push_timeout(self, value: Union[timedelta, int]) -> None:
Works for real devices only.
The default value is 30000ms.
"""
self.set_capability(
APP_PUSH_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
)
self.set_capability(APP_PUSH_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value)
4 changes: 1 addition & 3 deletions appium/options/ios/xcuitest/wda/wda_launch_timeout_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ def wda_launch_timeout(self, value: Union[timedelta, int]) -> None:
Timeout to wait for WebDriverAgent to be pingable,
after its building is finished. Defaults to 60000ms.
"""
self.set_capability(
WDA_LAUNCH_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
)
self.set_capability(WDA_LAUNCH_TIMEOUT, int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value)
9 changes: 4 additions & 5 deletions appium/webdriver/appium_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
MAIN_SCRIPT_PATH = 'appium/build/lib/main.js'
STATUS_URL = '/status'
DEFAULT_BASE_PATH = '/'
HTTP_STATUS_ERROR = 400


class AppiumServiceError(RuntimeError):
Expand Down Expand Up @@ -97,7 +98,7 @@ def start(self, **kwargs: Any) -> sp.Popen:
error_msg: Optional[str] = None
startup_failure_msg = (
'Appium server process is unable to start. Make sure proper values have been '
f'provided to \'node\' ({node}), \'npm\' ({npm}) and \'main_script\' ({main_script}) '
f"provided to 'node' ({node}), 'npm' ({npm}) and 'main_script' ({main_script}) "
f'method arguments.'
)
if timeout_ms > 0:
Expand Down Expand Up @@ -206,7 +207,7 @@ def is_service_listening(url: str, timeout: float = 5, custom_validator: Optiona
# noinspection PyUnresolvedReferences
try:
resp = conn.request('HEAD', url)
if resp.status < 400:
if resp.status < HTTP_STATUS_ERROR:
return True
except urllib3.exceptions.HTTPError:
pass
Expand Down Expand Up @@ -235,9 +236,7 @@ def find_executable(executable: str) -> Optional[str]:
def get_node() -> str:
result = find_executable('node')
if result is None:
raise AppiumServiceError(
'NodeJS main executable cannot be found. Make sure it is installed and present in PATH'
)
raise AppiumServiceError('NodeJS main executable cannot be found. Make sure it is installed and present in PATH')
return result


Expand Down
4 changes: 1 addition & 3 deletions appium/webdriver/extensions/device_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ def get_device_time(self, format: Optional[str] = None) -> str:
try:
return self.assert_extension_exists(ext_name).execute_script(ext_name, {'format': format})
except UnknownMethodException:
return self.mark_extension_absence(ext_name).execute(Command.GET_DEVICE_TIME_POST, {'format': format})[
'value'
]
return self.mark_extension_absence(ext_name).execute(Command.GET_DEVICE_TIME_POST, {'format': format})['value']

def _add_commands(self) -> None:
# noinspection PyProtectedMember,PyUnresolvedReferences
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@


class FlutterCommand:

def __init__(self, driver: WebDriver) -> None:
self.driver = driver

Expand Down Expand Up @@ -84,7 +83,7 @@ def perform_double_click(self, element: WebElement, offset: Optional[Tuple[int,
Returns:
None:
"""
opts: Dict[str, Union[WebElement, Dict[str, int]]] = {"origin": element}
opts: Dict[str, Union[WebElement, Dict[str, int]]] = {'origin': element}
if offset is not None:
opts['offset'] = {'x': offset[0], 'y': offset[1]}
self.execute_flutter_command('doubleClick', opts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@


class FlutterFinder:

def __init__(self, using: str, value: str) -> None:
self.using = using
self.value = value
Expand Down
4 changes: 1 addition & 3 deletions appium/webdriver/extensions/images_comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ def find_image_occurrence(
}
return self.execute(Command.COMPARE_IMAGES, options)['value']

def get_images_similarity(
self, base64_image1: bytes, base64_image2: bytes, **opts: Any
) -> Dict[str, Union[bytes, Dict]]:
def get_images_similarity(self, base64_image1: bytes, base64_image2: bytes, **opts: Any) -> Dict[str, Union[bytes, Dict]]:
"""Performs images matching to calculate the similarity score between them.

The flow there is similar to the one used in
Expand Down
4 changes: 1 addition & 3 deletions appium/webdriver/extensions/keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@


class Keyboard(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence):
def hide_keyboard(
self, key_name: Optional[str] = None, key: Optional[str] = None, strategy: Optional[str] = None
) -> Self:
def hide_keyboard(self, key_name: Optional[str] = None, key: Optional[str] = None, strategy: Optional[str] = None) -> Self:
"""Hides the software keyboard on the device.

In iOS, use `key_name` to press
Expand Down
4 changes: 1 addition & 3 deletions appium/webdriver/extensions/remote_fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ def pull_folder(self, path: str) -> str:
# TODO: Remove the fallback
return self.mark_extension_absence(ext_name).execute(Command.PULL_FOLDER, {'path': path})['value']

def push_file(
self, destination_path: str, base64data: Optional[str] = None, source_path: Optional[str] = None
) -> Self:
def push_file(self, destination_path: str, base64data: Optional[str] = None, source_path: Optional[str] = None) -> Self:
"""Puts the data from the file at `source_path`, encoded as Base64, in the file specified as `path`.

Specify either `base64data` or `source_path`, if both specified default to `source_path`
Expand Down
8 changes: 3 additions & 5 deletions appium/webdriver/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def __init__(
instance = extension(self.execute)
method_name = instance.method_name()
if hasattr(WebDriver, method_name):
logger.debug(f'Overriding the method \'{method_name}\'')
logger.debug(f"Overriding the method '{method_name}'")

# add a new method named 'instance.method_name()' and call it
setattr(WebDriver, method_name, getattr(instance, method_name))
Expand Down Expand Up @@ -382,9 +382,7 @@ def find_element(self, by: str = AppiumBy.ID, value: Union[str, Dict, None] = No

return self.execute(RemoteCommand.FIND_ELEMENT, {'using': by, 'value': value})['value']

def find_elements(
self, by: str = AppiumBy.ID, value: Union[str, Dict, None] = None
) -> Union[List[MobileWebElement], List]:
def find_elements(self, by: str = AppiumBy.ID, value: Union[str, Dict, None] = None) -> Union[List[MobileWebElement], List]:
"""
Find elements given a AppiumBy strategy and locator

Expand Down Expand Up @@ -471,7 +469,7 @@ def orientation(self, value: str) -> None:
if value.upper() in allowed_values:
self.execute(Command.SET_SCREEN_ORIENTATION, {'orientation': value})
else:
raise WebDriverException('You can only set the orientation to \'LANDSCAPE\' and \'PORTRAIT\'')
raise WebDriverException("You can only set the orientation to 'LANDSCAPE' and 'PORTRAIT'")

def assert_extension_exists(self, ext_name: str) -> Self:
"""
Expand Down
26 changes: 12 additions & 14 deletions script/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@


def get_current_version():
current = (
io.open(os.path.join(os.path.dirname('__file__'), 'appium', 'version.py'), encoding='utf-8').read().rstrip()
)
current = io.open(os.path.join(os.path.dirname('__file__'), 'appium', 'version.py'), encoding='utf-8').read().rstrip()
print('The current version is {}, type a new one'.format(MESSAGE_YELLOW.format(current)))
return current

Expand Down Expand Up @@ -78,8 +76,9 @@ def upload_sdist(new_version_num):
call_bash_script('twine upload "{}"'.format(push_file))
except Exception as e:
print(
'Failed to upload {} to pypi. '
'Please fix the original error and push it again later. Original error: {}'.format(push_file, e)
'Failed to upload {} to pypi. ' 'Please fix the original error and push it again later. Original error: {}'.format(
push_file, e
)
)


Expand All @@ -96,7 +95,7 @@ def ensure_publication(new_version_num):
for line in sys.stdin:
if line.rstrip().lower() == 'y':
return
exit('Canceled release process.')
sys.exit('Canceled release process.')


def build_sdist():
Expand All @@ -105,9 +104,9 @@ def build_sdist():

def validate_release_env():
if os.system('which twine') != 0:
exit("Please get twine via 'pip install twine'")
sys.exit("Please get twine via 'pip install twine'")
if os.system('which gitchangelog') != 0:
exit(
sys.exit(
"Please get twine via 'pip install gitchangelog' or 'pip install git+git://github.com/vaab/gitchangelog.git' for Python 3.7"
)

Expand All @@ -116,14 +115,13 @@ def build() -> None:
shutil.rmtree(BUILT_APPIUM_DIR_PATH, ignore_errors=True)
status, output = subprocess.getstatusoutput('{} setup.py install'.format(os.getenv('PYTHON_BIN_PATH')))
if status != 0:
exit(f'Failed to build the package:\n{output}')
sys.exit(f'Failed to build the package:\n{output}')


def get_py_files_in_dir(root_dir: str) -> List[str]:
return [
file_path[len(root_dir) :]
for file_path in glob.glob(f"{root_dir}/**/*.py", recursive=True)
+ glob.glob(f"{root_dir}/**/*.typed", recursive=True)
for file_path in glob.glob(f'{root_dir}/**/*.py', recursive=True) + glob.glob(f'{root_dir}/**/*.typed', recursive=True)
]


Expand All @@ -142,11 +140,11 @@ def assert_files_count_in_package() -> None:
print(f"'{APPIUM_DIR_PATH}' has '{diff}' files than {BUILT_APPIUM_DIR_PATH}")
diff = built_files_set.difference(original_files_set)
if diff:
print(f"{BUILT_APPIUM_DIR_PATH} has {diff} files than {APPIUM_DIR_PATH}")
print(f'{BUILT_APPIUM_DIR_PATH} has {diff} files than {APPIUM_DIR_PATH}')

exit(
sys.exit(
f"Python files in '{BUILT_APPIUM_DIR_PATH}' may differ from '{APPIUM_DIR_PATH}'. "
"Please make sure setup.py is configured properly."
'Please make sure setup.py is configured properly.'
)


Expand Down
Loading
Loading