From 7c5f02783f31f3ca9a937e1963ce14fe01aa377e Mon Sep 17 00:00:00 2001 From: vyuroshchin Date: Tue, 11 Aug 2026 13:36:35 +0300 Subject: [PATCH] chore: add PERF, FURB, SIM ruff rules --- .ruff.toml | 12 ++--- appium/webdriver/appium_service.py | 6 +-- appium/webdriver/extensions/action_helpers.py | 4 +- .../flutter_integration/flutter_commands.py | 5 +- pyproject.toml | 4 +- .../flutter_integration/helper/options.py | 5 +- test/functional/ios/safari_tests.py | 4 +- test/unit/webdriver/app_test.py | 45 ++++++++-------- test/unit/webdriver/context_test.py | 6 +-- test/unit/webdriver/device/common_test.py | 4 +- test/unit/webdriver/device/keyboard_test.py | 25 +++++---- test/unit/webdriver/device/lock_test.py | 11 ++-- test/unit/webdriver/log_events_test.py | 2 +- test/unit/webdriver/log_test.py | 2 +- test/unit/webdriver/screen_record_test.py | 8 +-- test/unit/webdriver/webdriver_test.py | 14 ++--- test/unit/webdriver/webelement_test.py | 7 +-- uv.lock | 52 +++++++++---------- 18 files changed, 105 insertions(+), 111 deletions(-) diff --git a/.ruff.toml b/.ruff.toml index 09d820222..c6098e28c 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -3,12 +3,12 @@ indent-width = 4 [lint] select = [ - # Pyflakes - "F", - # Pylint - "PL", - # isort - "I", + "F", # Pyflakes + "PL", # Pylint + "I", # isort + "PERF", # perflint + "FURB", # Refurb + "SIM" # Simplify ] [lint.per-file-ignores] diff --git a/appium/webdriver/appium_service.py b/appium/webdriver/appium_service.py index 93c926c65..46f5f55b9 100644 --- a/appium/webdriver/appium_service.py +++ b/appium/webdriver/appium_service.py @@ -82,14 +82,14 @@ def start(self, **kwargs: Any) -> sp.Popen: """ self.stop() - env = kwargs['env'] if 'env' in kwargs else None + env = kwargs.get('env') node: str = kwargs.get('node') or get_node() npm: str = kwargs.get('npm') or get_npm() main_script: str = kwargs.get('main_script') or get_main_script(node, npm) # A workaround for https://github.com/appium/python-client/issues/534 default_std = sp.DEVNULL if sys.platform == 'win32' else sp.PIPE - stdout = kwargs['stdout'] if 'stdout' in kwargs else default_std - stderr = kwargs['stderr'] if 'stderr' in kwargs else default_std + stdout = kwargs.get('stdout', default_std) + stderr = kwargs.get('stderr', default_std) timeout_ms = int(kwargs['timeout_ms']) if 'timeout_ms' in kwargs else STARTUP_TIMEOUT_MS args: List[str] = [node, main_script] if 'args' in kwargs: diff --git a/appium/webdriver/extensions/action_helpers.py b/appium/webdriver/extensions/action_helpers.py index 9c3709223..0bb740ec0 100644 --- a/appium/webdriver/extensions/action_helpers.py +++ b/appium/webdriver/extensions/action_helpers.py @@ -113,12 +113,10 @@ def tap(self, positions: List[Tuple[int, int]], duration: Optional[int] = None) actions.w3c_actions.pointer_action.release() actions.perform() else: - finger = 0 actions = ActionChains(cast('WebDriver', self)) actions.w3c_actions.devices = [] - for position in positions: - finger += 1 + for finger, position in enumerate(positions, start=1): x = position[0] y = position[1] diff --git a/appium/webdriver/extensions/flutter_integration/flutter_commands.py b/appium/webdriver/extensions/flutter_integration/flutter_commands.py index 5e469cae1..3f43ef29b 100644 --- a/appium/webdriver/extensions/flutter_integration/flutter_commands.py +++ b/appium/webdriver/extensions/flutter_integration/flutter_commands.py @@ -154,10 +154,7 @@ def inject_mock_image(self, value: str) -> str: Returns: str: Image ID of the injected image. """ - if os.path.isfile(value): - base64_encoded_image = encode_file_to_base64(value) - else: - base64_encoded_image = value + base64_encoded_image = encode_file_to_base64(value) if os.path.isfile(value) else value return self.execute_flutter_command('injectImage', {'base64Image': base64_encoded_image}) def activate_injected_image(self, image_id: str) -> None: diff --git a/pyproject.toml b/pyproject.toml index 4584c5b5b..9958ffd34 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,12 +42,12 @@ dev = [ "httpretty~=1.1", "mock~=5.2", "mypy>=1.17,<3.0", - "pre-commit~=4.2", + "pre-commit~=4.6", "pytest>=8.4,<10.0", "pytest-cov>=6.2,<8.0", "pytest-xdist~=3.8", "python-dateutil~=2.9", - "ruff~=0.15", + "ruff~=0.16", "types-python-dateutil~=2.9", # for release diff --git a/test/functional/flutter_integration/helper/options.py b/test/functional/flutter_integration/helper/options.py index 0a44f372b..8b2e29639 100644 --- a/test/functional/flutter_integration/helper/options.py +++ b/test/functional/flutter_integration/helper/options.py @@ -82,10 +82,7 @@ def device_name() -> str: Get a unique device name for the current worker. Uses the base device name and appends the port number for uniqueness. """ - if is_platform_android(): - prefix = 'Android Emulator' - else: - prefix = os.environ['IPHONE_MODEL'] + prefix = 'Android Emulator' if is_platform_android() else os.environ['IPHONE_MODEL'] worker_info = get_worker_info() diff --git a/test/functional/ios/safari_tests.py b/test/functional/ios/safari_tests.py index 624979f80..1093879e6 100644 --- a/test/functional/ios/safari_tests.py +++ b/test/functional/ios/safari_tests.py @@ -54,7 +54,7 @@ def driver() -> Generator['WebDriver', None, None]: def test_context(driver: 'WebDriver') -> None: """Test Safari context switching.""" contexts = driver.contexts - assert 'NATIVE_APP' == contexts[0] + assert contexts[0] == 'NATIVE_APP' assert contexts[1].startswith('WEBVIEW_') driver.switch_to.context(contexts[1]) assert 'WEBVIEW_' in driver.current_context @@ -73,7 +73,7 @@ def test_navigation(driver: 'WebDriver') -> None: driver.get('http://google.com') for _ in range(5): time.sleep(0.5) - if 'Google' == driver.title: + if driver.title == 'Google': return pytest.fail('The title was wrong') diff --git a/test/unit/webdriver/app_test.py b/test/unit/webdriver/app_test.py index 347675358..e0051167d 100644 --- a/test/unit/webdriver/app_test.py +++ b/test/unit/webdriver/app_test.py @@ -26,10 +26,10 @@ def test_install_app(driver_func): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') result = driver.install_app('path/to/app') - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'app': 'path/to/app', 'appPath': 'path/to/app'}], 'script': 'mobile: installApp', - } == get_httpretty_request_body(httpretty.last_request()) + } assert isinstance(result, WebDriver) @@ -40,10 +40,10 @@ def test_remove_app(driver_func): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') result = driver.remove_app('com.app.id') - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'appId': 'com.app.id', 'bundleId': 'com.app.id'}], 'script': 'mobile: removeApp', - } == get_httpretty_request_body(httpretty.last_request()) + } assert isinstance(result, WebDriver) @@ -54,10 +54,10 @@ def test_app_installed(driver_func): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": true}') result = driver.is_app_installed('com.app.id') - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'appId': 'com.app.id', 'bundleId': 'com.app.id'}], 'script': 'mobile: isAppInstalled', - } == get_httpretty_request_body(httpretty.last_request()) + } assert result is True @@ -68,10 +68,10 @@ def test_terminate_app(driver_func): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": true}') result = driver.terminate_app('com.app.id') - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'appId': 'com.app.id', 'bundleId': 'com.app.id'}], 'script': 'mobile: terminateApp', - } == get_httpretty_request_body(httpretty.last_request()) + } assert result is True @@ -82,10 +82,10 @@ def test_activate_app(driver_func): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') result = driver.activate_app('com.app.id') - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'appId': 'com.app.id', 'bundleId': 'com.app.id'}], 'script': 'mobile: activateApp', - } == get_httpretty_request_body(httpretty.last_request()) + } assert isinstance(result, WebDriver) @@ -96,7 +96,7 @@ def test_background_app(driver_func): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') result = driver.background_app(0) - assert {'args': [{'seconds': 0}], 'script': 'mobile: backgroundApp'} == get_httpretty_request_body(httpretty.last_request()) + assert get_httpretty_request_body(httpretty.last_request()) == {'args': [{'seconds': 0}], 'script': 'mobile: backgroundApp'} assert isinstance(result, WebDriver) @@ -107,10 +107,10 @@ def test_query_app_state(driver_func): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": 3}') result = driver.query_app_state('com.app.id') - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'appId': 'com.app.id', 'bundleId': 'com.app.id'}], 'script': 'mobile: queryAppState', - } == get_httpretty_request_body(httpretty.last_request()) + } assert result is ApplicationState.RUNNING_IN_BACKGROUND @@ -125,8 +125,8 @@ def test_app_strings(driver_func): ) result = driver.app_strings() - assert {'args': [{}], 'script': 'mobile: getAppStrings'} == get_httpretty_request_body(httpretty.last_request()) - assert "You can't wipe my data, you are a monkey!" == result['monkey_wipe_data'], result + assert get_httpretty_request_body(httpretty.last_request()) == {'args': [{}], 'script': 'mobile: getAppStrings'} + assert result['monkey_wipe_data'] == "You can't wipe my data, you are a monkey!", result @pytest.mark.parametrize('driver_func', [android_w3c_driver, ios_w3c_driver]) @@ -140,10 +140,11 @@ def test_app_strings_with_lang(driver_func): ) result = driver.app_strings('en') - assert {'args': [{'language': 'en'}], 'script': 'mobile: getAppStrings'} == get_httpretty_request_body( - httpretty.last_request() - ) - assert "You can't wipe my data, you are a monkey!" == result['monkey_wipe_data'], result + assert get_httpretty_request_body(httpretty.last_request()) == { + 'args': [{'language': 'en'}], + 'script': 'mobile: getAppStrings', + } + assert result['monkey_wipe_data'] == "You can't wipe my data, you are a monkey!", result @pytest.mark.parametrize('driver_func', [android_w3c_driver, ios_w3c_driver]) @@ -157,8 +158,8 @@ def test_app_strings_with_lang_and_file(driver_func): ) result = driver.app_strings('en', 'some_file') - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'language': 'en', 'stringFile': 'some_file'}], 'script': 'mobile: getAppStrings', - } == get_httpretty_request_body(httpretty.last_request()) - assert "You can't wipe my data, you are a monkey!" == result['monkey_wipe_data'], result + } + assert result['monkey_wipe_data'] == "You can't wipe my data, you are a monkey!", result diff --git a/test/unit/webdriver/context_test.py b/test/unit/webdriver/context_test.py index b83dd82d4..7198984c7 100644 --- a/test/unit/webdriver/context_test.py +++ b/test/unit/webdriver/context_test.py @@ -31,7 +31,7 @@ def test_get_contexts(self): httpretty.GET, appium_command('/session/1234567890/contexts'), body='{"value": ["NATIVE_APP", "CHROMIUM"]}' ) - assert ['NATIVE_APP', 'CHROMIUM'] == driver.contexts + assert driver.contexts == ['NATIVE_APP', 'CHROMIUM'] @httpretty.activate def test_switch_to_context(self): @@ -40,7 +40,7 @@ def test_switch_to_context(self): driver.switch_to.context(None) - assert {'name': None} == get_httpretty_request_body(httpretty.last_request()) + assert get_httpretty_request_body(httpretty.last_request()) == {'name': None} @httpretty.activate def test_switch_to_context_native_app(self): @@ -49,4 +49,4 @@ def test_switch_to_context_native_app(self): driver.switch_to.context('NATIVE_APP') - assert {'name': 'NATIVE_APP'} == get_httpretty_request_body(httpretty.last_request()) + assert get_httpretty_request_body(httpretty.last_request()) == {'name': 'NATIVE_APP'} diff --git a/test/unit/webdriver/device/common_test.py b/test/unit/webdriver/device/common_test.py index 465349029..596e988e6 100644 --- a/test/unit/webdriver/device/common_test.py +++ b/test/unit/webdriver/device/common_test.py @@ -24,7 +24,7 @@ def test_open_notifications(self): driver = android_w3c_driver() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.open_notifications(), WebDriver) - assert {'args': [], 'script': 'mobile: openNotifications'} == get_httpretty_request_body(httpretty.last_request()) + assert get_httpretty_request_body(httpretty.last_request()) == {'args': [], 'script': 'mobile: openNotifications'} @httpretty.activate def test_current_package(self): @@ -35,4 +35,4 @@ def test_current_package(self): body='{"value": ".ExamplePackage"}', ) assert driver.current_package == '.ExamplePackage' - assert {'args': [], 'script': 'mobile: getCurrentPackage'} == get_httpretty_request_body(httpretty.last_request()) + assert get_httpretty_request_body(httpretty.last_request()) == {'args': [], 'script': 'mobile: getCurrentPackage'} diff --git a/test/unit/webdriver/device/keyboard_test.py b/test/unit/webdriver/device/keyboard_test.py index 33f31a535..ebffc8e0a 100644 --- a/test/unit/webdriver/device/keyboard_test.py +++ b/test/unit/webdriver/device/keyboard_test.py @@ -88,16 +88,17 @@ def test_hide_keyboard(self): driver = ios_w3c_driver() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.hide_keyboard(), WebDriver) - assert {'args': [{}], 'script': 'mobile: hideKeyboard'} == get_httpretty_request_body(httpretty.last_request()) + assert get_httpretty_request_body(httpretty.last_request()) == {'args': [{}], 'script': 'mobile: hideKeyboard'} @httpretty.activate def test_hide_keyboard_with_key(self): driver = ios_w3c_driver() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.hide_keyboard(key_name='Done'), WebDriver) - assert {'args': [{'keys': ['Done']}], 'script': 'mobile: hideKeyboard'} == get_httpretty_request_body( - httpretty.last_request() - ) + assert get_httpretty_request_body(httpretty.last_request()) == { + 'args': [{'keys': ['Done']}], + 'script': 'mobile: hideKeyboard', + } @httpretty.activate def test_hide_keyboard_with_key_and_strategy(self): @@ -105,22 +106,24 @@ def test_hide_keyboard_with_key_and_strategy(self): httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.hide_keyboard(strategy='pressKey', key='Done'), WebDriver) # only 'keys' works - assert {'args': [{'keys': ['Done']}], 'script': 'mobile: hideKeyboard'} == get_httpretty_request_body( - httpretty.last_request() - ) + assert get_httpretty_request_body(httpretty.last_request()) == { + 'args': [{'keys': ['Done']}], + 'script': 'mobile: hideKeyboard', + } @httpretty.activate def test_is_keyboard_shown(self): driver = ios_w3c_driver() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) driver.is_keyboard_shown(), WebDriver - assert {'script': 'mobile: isKeyboardShown', 'args': []} == get_httpretty_request_body(httpretty.last_request()) + assert get_httpretty_request_body(httpretty.last_request()) == {'script': 'mobile: isKeyboardShown', 'args': []} @httpretty.activate def test_press_button(self): driver = ios_w3c_driver() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) driver.press_button('Home') - assert {'script': 'mobile: pressButton', 'args': [{'name': 'Home'}]} == get_httpretty_request_body( - httpretty.last_request() - ) + assert get_httpretty_request_body(httpretty.last_request()) == { + 'script': 'mobile: pressButton', + 'args': [{'name': 'Home'}], + } diff --git a/test/unit/webdriver/device/lock_test.py b/test/unit/webdriver/device/lock_test.py index 1cd89c41a..603efffbd 100644 --- a/test/unit/webdriver/device/lock_test.py +++ b/test/unit/webdriver/device/lock_test.py @@ -96,16 +96,17 @@ def test_touch_id(self): driver = ios_w3c_driver() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.touch_id(True), WebDriver) - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'script': 'mobile: sendBiometricMatch', 'args': [{'match': True, 'type': 'touchId'}], - } == get_httpretty_request_body(httpretty.last_request()) + } @httpretty.activate def test_enroll_biometric(self): driver = ios_w3c_driver() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.toggle_touch_id_enrollment(), WebDriver) - assert {'script': 'mobile: enrollBiometric', 'args': [{'isEnabled': True}]} == get_httpretty_request_body( - httpretty.last_request() - ) + assert get_httpretty_request_body(httpretty.last_request()) == { + 'script': 'mobile: enrollBiometric', + 'args': [{'isEnabled': True}], + } diff --git a/test/unit/webdriver/log_events_test.py b/test/unit/webdriver/log_events_test.py index 244aa8223..2469efc39 100644 --- a/test/unit/webdriver/log_events_test.py +++ b/test/unit/webdriver/log_events_test.py @@ -33,7 +33,7 @@ def test_get_events(self): assert events['appium:funEvent'] == [12347] d = get_httpretty_request_body(httpretty.last_request()) - assert 'type' not in d.keys() + assert 'type' not in d @httpretty.activate def test_get_events_args(self): diff --git a/test/unit/webdriver/log_test.py b/test/unit/webdriver/log_test.py index f3b76d351..f7f554bf5 100644 --- a/test/unit/webdriver/log_test.py +++ b/test/unit/webdriver/log_test.py @@ -43,4 +43,4 @@ def test_get_log(): assert log_types == ['logs as array'] d = get_httpretty_request_body(httpretty.last_request()) - assert {'type': 'syslog'} == d + assert d == {'type': 'syslog'} diff --git a/test/unit/webdriver/screen_record_test.py b/test/unit/webdriver/screen_record_test.py index a8ddee1b2..c56da8c73 100644 --- a/test/unit/webdriver/screen_record_test.py +++ b/test/unit/webdriver/screen_record_test.py @@ -25,7 +25,7 @@ def test_start_recording_screen(self): d = get_httpretty_request_body(httpretty.last_request()) assert d['options']['user'] == 'userA' assert d['options']['pass'] == '12345' - assert 'password' not in d['options'].keys() + assert 'password' not in d['options'] @httpretty.activate def test_stop_recording_screen(self): @@ -40,7 +40,7 @@ def test_stop_recording_screen(self): d = get_httpretty_request_body(httpretty.last_request()) assert d['options']['user'] == 'userA' assert d['options']['pass'] == '12345' - assert 'password' not in d['options'].keys() + assert 'password' not in d['options'] class TestWebDriverScreenRecordIOS: @@ -56,7 +56,7 @@ def test_start_recording_screen(self): d = get_httpretty_request_body(httpretty.last_request()) assert d['options']['user'] == 'userA' assert d['options']['pass'] == '12345' - assert 'password' not in d['options'].keys() + assert 'password' not in d['options'] @httpretty.activate def test_stop_recording_screen(self): @@ -71,4 +71,4 @@ def test_stop_recording_screen(self): d = get_httpretty_request_body(httpretty.last_request()) assert d['options']['user'] == 'userA' assert d['options']['pass'] == '12345' - assert 'password' not in d['options'].keys() + assert 'password' not in d['options'] diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index 17db27afc..6515c5239 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -132,8 +132,8 @@ def test_create_session_register_uridirect(self): client_config=client_config, ) - assert 'http://localhost2:4800/special/path/wd/hub' == driver.command_executor._client_config.remote_server_addr - assert ['NATIVE_APP', 'CHROMIUM'] == driver.contexts + assert driver.command_executor._client_config.remote_server_addr == 'http://localhost2:4800/special/path/wd/hub' + assert driver.contexts == ['NATIVE_APP', 'CHROMIUM'] assert isinstance(driver.command_executor, AppiumConnection) @httpretty.activate @@ -171,8 +171,8 @@ def test_create_session_register_uridirect_no_direct_connect_path(self): SERVER_URL_BASE, options=UiAutomator2Options().load_capabilities(desired_caps), client_config=client_config ) - assert SERVER_URL_BASE == driver.command_executor._client_config.remote_server_addr - assert ['NATIVE_APP', 'CHROMIUM'] == driver.contexts + assert driver.command_executor._client_config.remote_server_addr == SERVER_URL_BASE + assert driver.contexts == ['NATIVE_APP', 'CHROMIUM'] assert isinstance(driver.command_executor, AppiumConnection) @httpretty.activate @@ -211,7 +211,7 @@ def test_create_session_remote_server_addr_treatment_with_appiumclientconfig(sel client_config=client_config, ) - assert SERVER_URL_BASE == driver.command_executor._client_config.remote_server_addr + assert driver.command_executor._client_config.remote_server_addr == SERVER_URL_BASE assert isinstance(driver.command_executor, AppiumConnection) @httpretty.activate @@ -415,10 +415,10 @@ def test_extention_command_check(self): ) is True ) - assert { + assert get_httpretty_request_body(httpretty.last_request()) == { 'args': [{'component': 'io.appium.android.apis/.accessibility.AccessibilityNodeProviderActivity'}], 'script': 'mobile: startActivity', - } == get_httpretty_request_body(httpretty.last_request()) + } def test_get_client_config_and_connection_with_empty_config(self): command_executor, client_config = _get_remote_connection_and_client_config( diff --git a/test/unit/webdriver/webelement_test.py b/test/unit/webdriver/webelement_test.py index a37f229a4..a37c2ec68 100644 --- a/test/unit/webdriver/webelement_test.py +++ b/test/unit/webdriver/webelement_test.py @@ -49,15 +49,12 @@ def test_send_key(self): @httpretty.activate def test_send_key_with_file(self): driver = android_w3c_driver() - # Should not send this file - tmp_f = tempfile.NamedTemporaryFile() httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/element/element_id/value')) - try: + # Should not send this file + with tempfile.NamedTemporaryFile() as tmp_f: element = MobileWebElement(driver, 'element_id') element.send_keys(tmp_f.name) - finally: - tmp_f.close() d = get_httpretty_request_body(httpretty.last_request()) assert d['text'] == ''.join(d['value']) diff --git a/uv.lock b/uv.lock index a2825c41b..1a470c976 100644 --- a/uv.lock +++ b/uv.lock @@ -64,13 +64,13 @@ dev = [ { name = "httpretty", specifier = "~=1.1" }, { name = "mock", specifier = "~=5.2" }, { name = "mypy", specifier = ">=1.17,<3.0" }, - { name = "pre-commit", specifier = "~=4.2" }, + { name = "pre-commit", specifier = "~=4.6" }, { name = "pytest", specifier = ">=8.4,<10.0" }, { name = "pytest-cov", specifier = ">=6.2,<8.0" }, { name = "pytest-xdist", specifier = "~=3.8" }, { name = "python-dateutil", specifier = "~=2.9" }, { name = "python-semantic-release", specifier = ">=10.3.1,<10.7.0" }, - { name = "ruff", specifier = "~=0.15" }, + { name = "ruff", specifier = "~=0.16" }, { name = "sphinx", specifier = ">=4.0,<9.0" }, { name = "sphinx-rtd-theme", specifier = "~=3.0" }, { name = "sphinxcontrib-apidoc", specifier = "~=0.6" }, @@ -915,7 +915,7 @@ wheels = [ [[package]] name = "pre-commit" -version = "4.6.1" +version = "4.6.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -924,9 +924,9 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/3a/ddb78f32a0814e66b18a099377a106a2dcdce92d86a034d69d65df9b256e/pre_commit-4.6.1.tar.gz", hash = "sha256:03e809865c7d178b9979d06c761fcbfe6808fdaded8581a745bb110e52050421", size = 198646, upload-time = "2026-07-21T20:56:58.225Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/89/1f3e8e1fc3e97de0fa963495832f581f025f29471602a309e48808244292/pre_commit-4.6.2.tar.gz", hash = "sha256:8f5d7bfb021ecdbcd9d49d89847082dd24172ccde534390081a679ad046e2441", size = 198670, upload-time = "2026-08-10T22:07:18.421Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/49/bc925106abcdac498074f2cbe6137e94e09f418dd2b7775df5b577dc0313/pre_commit-4.6.1-py2.py3-none-any.whl", hash = "sha256:0e3b2942510d1fb34eec167a3ec57331bf8442122f1153a9fb8b58f5c49b2717", size = 226186, upload-time = "2026-07-21T20:56:57.064Z" }, + { url = "https://files.pythonhosted.org/packages/45/e2/bbb7129c9e7999a6b8ee9cca3b66486c25c423ab5a75f34071798b74ce94/pre_commit-4.6.2-py2.py3-none-any.whl", hash = "sha256:e2dde9a75d3bce11bd3831c26d134df00a2803c1d818be6a0383c3dcda25dc4e", size = 226202, upload-time = "2026-08-10T22:07:16.942Z" }, ] [[package]] @@ -1310,27 +1310,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.16.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/25/7113f6d5498888c5fb7db34081cba7d5971c4cb1bfb26819966eee68f003/ruff-0.16.1.tar.gz", hash = "sha256:fedad7c801dabd3fb9741d76aca39246e6ddd9ca446a015875207bf19f1e6bc7", size = 4877500, upload-time = "2026-07-30T19:37:01.379Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/bd/694da69368e0973de65df2ddc73ab18d43c469d5963d9b150911de6bc513/ruff-0.16.1-py3-none-linux_armv6l.whl", hash = "sha256:58edb313b88f0c5460a26adf5f39a37a3be789494a15e3e411e35fa78b89f9a0", size = 10839126, upload-time = "2026-07-30T19:36:13.697Z" }, - { url = "https://files.pythonhosted.org/packages/3f/f0/b626e5d5bd0dd9576263658ef12885e2288afd1029a48e26ffed65ec1ac1/ruff-0.16.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fde5a99e2f97479af66edd6622c6d5a2a7592c77cf4153d9e4428f5eeb55b60c", size = 11070253, upload-time = "2026-07-30T19:36:17.14Z" }, - { url = "https://files.pythonhosted.org/packages/83/63/f40acfb6b35b88623e71684942b552c3edd96035f5d98f313815f7b277de/ruff-0.16.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e0d4c20532fca4f7fa609369161d968dd28f65d83dabbd61d8e9c7edbf7001f6", size = 10561425, upload-time = "2026-07-30T19:36:20.04Z" }, - { url = "https://files.pythonhosted.org/packages/aa/dd/14ec0e9c2b4d315547dd38765004b4863e354e1b52cb308272215d9f6f6d/ruff-0.16.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30affbcedf59ad5703d9c91f82266e02b47739f797e1a7b6e158e5526a6dae38", size = 10948879, upload-time = "2026-07-30T19:36:22.476Z" }, - { url = "https://files.pythonhosted.org/packages/33/e9/9d870cbae575030fdef595f04b4b97573c525b5497cce4f4498cf2f85446/ruff-0.16.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24e9c631573cbca9d20f1283f8f479b2afa4a8503504822bd71a293889f16743", size = 10643691, upload-time = "2026-07-30T19:36:24.914Z" }, - { url = "https://files.pythonhosted.org/packages/c4/09/12743d544e2173f53ecd27217c65f90d2bc0f8424a66a60339e56bbc0457/ruff-0.16.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b41bdd48fb420987a9b5212e4957c26ad4abce401fa9ea9d4d85843727945f4f", size = 11435354, upload-time = "2026-07-30T19:36:28.447Z" }, - { url = "https://files.pythonhosted.org/packages/7f/89/a1652b2daee52083c9554a6333b678a8b01d0400f976827bb87857f9449a/ruff-0.16.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b0d1e1393b7648079e13669de1c1f4fde06d4583e84d8fd5c1551e0a77a2aa75", size = 12259033, upload-time = "2026-07-30T19:36:31.326Z" }, - { url = "https://files.pythonhosted.org/packages/16/96/ecdcb8c54ee7b123b487f807eb014e6e019155a0b81dfb669acd52f28ce3/ruff-0.16.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07bf434b1c95f4e093be4532068ef4fcf00924eb2ade8796075980902d6fd54a", size = 11667981, upload-time = "2026-07-30T19:36:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/cd/90/c52e12e0d862e9572f2a33aa227409143520abe53111e9a6babbac7b4af8/ruff-0.16.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39897739f112253ee4fdd2e8aa9a4f9ded99fb2be367d5f31dfa4ded6025584c", size = 11468183, upload-time = "2026-07-30T19:36:37.339Z" }, - { url = "https://files.pythonhosted.org/packages/2c/6b/4ffb7ad1d83eb16cf8cbb3c8815d3f11c88460fd162d4b372a2059be1c2a/ruff-0.16.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:82ae3c0c0d74daf17b968a10b7b3bb3ef297ab7de0c1f749646b25e690ccb150", size = 11470071, upload-time = "2026-07-30T19:36:39.91Z" }, - { url = "https://files.pythonhosted.org/packages/9c/72/32ae7db4c0b5e32ab611787caa19d1546800676d79f7483b7100a3561bf4/ruff-0.16.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4d5f2ed10f8242d83fc08d521301089364e3375375705356f20c0e31606ef3ef", size = 10919503, upload-time = "2026-07-30T19:36:42.65Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ca/3d901ba6ad6fc38da39c3448fc6c59ac945679293a17c3ceb6d6c1cba13e/ruff-0.16.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a4665b309891f83f3e3c25447935f1213e9abbd4b5640af7a1f2def9f8d413c1", size = 10649861, upload-time = "2026-07-30T19:36:45.18Z" }, - { url = "https://files.pythonhosted.org/packages/92/79/894ef1ced26552d5f8c9cf6d85b0687840e1128c55aeab7b9c2d54a0d880/ruff-0.16.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26e9ca5c9bc3971f20d3cf18a957f52ffd6a5f6564ff15c4912a144dcac22494", size = 11148137, upload-time = "2026-07-30T19:36:47.936Z" }, - { url = "https://files.pythonhosted.org/packages/2d/69/3609a09fa1cb46cc28b762363e440a354204e5dff01bd0c8d7437874d6b9/ruff-0.16.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:67e1e1e3fa4f0c82f0e36d4cd61e661f6e7a6196cb1aa92fe0828fa7b8f257cd", size = 11559211, upload-time = "2026-07-30T19:36:50.448Z" }, - { url = "https://files.pythonhosted.org/packages/fc/8a/fb22af2fd78a736e241fabf67e30ce1799a64244026377a49e133af90762/ruff-0.16.1-py3-none-win32.whl", hash = "sha256:d31765e131295b8445caf301e3e8a85b34d1b9b211b4109b7ba457888b051806", size = 10838258, upload-time = "2026-07-30T19:36:53.298Z" }, - { url = "https://files.pythonhosted.org/packages/d4/35/e57fd9fb5d423961df087a00b12d42c0a830288dc2f3b45ecca299158b4f/ruff-0.16.1-py3-none-win_amd64.whl", hash = "sha256:09b05e8b90c2cb06ad63464350e7a45e8e44a2dfe52072ebfba6666ca8d3f596", size = 11961111, upload-time = "2026-07-30T19:36:56.107Z" }, - { url = "https://files.pythonhosted.org/packages/cb/46/240ea004bf6dc4feb40e9832f2205a476a47dd5b8a3f8211a5fc5f95e20e/ruff-0.16.1-py3-none-win_arm64.whl", hash = "sha256:dbaadaac38c70239f056d306b7476f246b0bf000fa6b3876402acbf5b227eaf8", size = 11309414, upload-time = "2026-07-30T19:36:58.79Z" }, +version = "0.16.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/e1/4508a569211b35599016e84ba65c1a992b7a4004b4b6c4bea02a851cba1b/ruff-0.16.2.tar.gz", hash = "sha256:c3d7828d12e8927a6fc65fe38e2c2541b9e762d360a1786d752cb1b8883b3c9c", size = 4885811, upload-time = "2026-08-07T13:31:01.432Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/57/db19951540f98859c956b50bdb4d31089b4d91e9f15e2968e7d5193806d5/ruff-0.16.2-py3-none-linux_armv6l.whl", hash = "sha256:3c8de4cf2181f01d57946d87d777aa52916976fc09942aed89938fab5e013318", size = 10847925, upload-time = "2026-08-07T13:30:14.468Z" }, + { url = "https://files.pythonhosted.org/packages/13/5a/995fe85a8470d3e391ac0f7fa8054bb454eaf33ee138196d6172ed1079c0/ruff-0.16.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a48cc05c6fbc811ca81b5d7ba95375affea6582d1b8024e455e41afbbf55344", size = 11072662, upload-time = "2026-08-07T13:30:18.143Z" }, + { url = "https://files.pythonhosted.org/packages/32/53/370d767c61c71a971a4ace36703a7ecd8c393956349a7325d7fab2b56827/ruff-0.16.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a2c0d14fcbb26c91f0f867a6dc9bd71bbc30b1b6151829c884f23faeab2e5700", size = 10566771, upload-time = "2026-08-07T13:30:20.899Z" }, + { url = "https://files.pythonhosted.org/packages/85/d6/9d96948caf5a632be62d62202d5ec914d6856f204fd79eb036e5915e79ea/ruff-0.16.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:335c621622c4650330be50842561c6586ac6971bb8ab5407fe34dcc9efb16bbe", size = 10975825, upload-time = "2026-08-07T13:30:23.517Z" }, + { url = "https://files.pythonhosted.org/packages/3b/92/ea87129b3414acb0b5770563779c51804d37ac67675c7ba35447ddb14773/ruff-0.16.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e66910f2c37cc753f9ef6580c914a621b80c4fa3549d3e3521e29d0f5bfc3f", size = 10649437, upload-time = "2026-08-07T13:30:26.097Z" }, + { url = "https://files.pythonhosted.org/packages/ac/43/f8f291dcd4af5bb7872b74fdfa41a7cd7c856ca1d4069670971cf1b9f5cb/ruff-0.16.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7e36fbfba65510548156902bcf1350a979a958ce0347ce0f90d73894036b39f", size = 11446761, upload-time = "2026-08-07T13:30:28.752Z" }, + { url = "https://files.pythonhosted.org/packages/71/4a/ef991fb2fcf516ab71f0808adcdd8da5e18c8cde447f4ceaf5f47a5132a5/ruff-0.16.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f0eab35f80df8f134aae5d1630e751901321d317cc8e50dc39e36fa3ed34cd12", size = 12336364, upload-time = "2026-08-07T13:30:31.468Z" }, + { url = "https://files.pythonhosted.org/packages/f3/24/f615e74f307e6ca0e56a482872477b856c70d530aa356abfb6dfe5ca8a80/ruff-0.16.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40ea8c0594feb894e89c8c61ab9c103d38b0ea72dfde6c594107147ca31b1140", size = 11630720, upload-time = "2026-08-07T13:30:34.426Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d3/8ef50149e8412a77f7ab409efdef0e2b23803707a3863da4fc64cb23d459/ruff-0.16.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab3d62dde0b19facdd632008cc4827fc28ada7736c6bd35ab6f1050f0bfed53f", size = 11466130, upload-time = "2026-08-07T13:30:36.958Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a7/a19334985c4dea8c381981fa252cd854c7ee52dc4b1686dc16f4a911c702/ruff-0.16.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e43e1f5b8388da9eca1b9e88328d47a5cec794633ccf6f7484ac2dd15eee92c0", size = 11523634, upload-time = "2026-08-07T13:30:39.822Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6c/96d192b0e742412ceda08c0a50f9669b253dde9fd6a60ea1a10c9fa79a63/ruff-0.16.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c24788a980581e1d7ea3a0cbe4344c4fbeb0a6a9b1f4713aa46bb104f8294690", size = 10949807, upload-time = "2026-08-07T13:30:42.745Z" }, + { url = "https://files.pythonhosted.org/packages/fa/51/e26599ceca11e79ee255c7df515995561edf87e9ca1893284e44d98f5a86/ruff-0.16.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:81806b08329130005dd4a8a8394a0c9da8c6f4cafb16ba438d2a2ee6a18bedf1", size = 10646891, upload-time = "2026-08-07T13:30:45.522Z" }, + { url = "https://files.pythonhosted.org/packages/68/01/800c4b1f97bc8d7c6029e06b1f20473a3cf1e13c4933d8f3342add83fc55/ruff-0.16.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4ce4e02bad779bef557f541a1b31f20d6abeae1cc05ed1b1ac019d4ffd1044c8", size = 11162063, upload-time = "2026-08-07T13:30:48.131Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d0/1477ea50fc5a0d4b0b71d1d63d50770bdd794d90b43e37a7618e63ec9894/ruff-0.16.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e0422abdf70070255fc4073ce9dfc814cc03db577013761ddd09bc1e4a9a4fbd", size = 11556038, upload-time = "2026-08-07T13:30:50.686Z" }, + { url = "https://files.pythonhosted.org/packages/b8/76/a7776f32048d991e16d4fa8ff91790b877342d3596cc3ed04acdbf1aaedc/ruff-0.16.2-py3-none-win32.whl", hash = "sha256:bf3a63d78fb39f4bf5ac8ae52051c5520505301abe19ba4e204c453b3f09bb0b", size = 10872850, upload-time = "2026-08-07T13:30:53.471Z" }, + { url = "https://files.pythonhosted.org/packages/00/0d/929c800d920e61397d82a01b60bffc68da3052c17d31de59efaad2e4ed75/ruff-0.16.2-py3-none-win_amd64.whl", hash = "sha256:bcabe2f6d0fc7819f1431793005af4e4de7371927d037345bf941252b195b9fa", size = 12023338, upload-time = "2026-08-07T13:30:56.193Z" }, + { url = "https://files.pythonhosted.org/packages/5b/6c/93e26c22c5f78ff87363e07da49c84955affbeb1098bd1936bf3b3f293bf/ruff-0.16.2-py3-none-win_arm64.whl", hash = "sha256:d614e95cedf38a2053fd351c55b103ba30d017d61688fdbfd40ee0412852a99f", size = 11374065, upload-time = "2026-08-07T13:30:58.775Z" }, ] [[package]]