diff --git a/.gitchangelog.rc b/.gitchangelog.rc deleted file mode 100644 index 450926501..000000000 --- a/.gitchangelog.rc +++ /dev/null @@ -1,288 +0,0 @@ -# -*- coding: utf-8; mode: python -*- -## -## Format -## -## ACTION: [AUDIENCE:] COMMIT_MSG [!TAG ...] -## -## Description -## -## ACTION is one of 'chg', 'fix', 'new' -## -## Is WHAT the change is about. -## -## 'chg' is for refactor, small improvement, cosmetic changes... -## 'fix' is for bug fixes -## 'new' is for new features, big improvement -## -## AUDIENCE is optional and one of 'dev', 'usr', 'pkg', 'test', 'doc' -## -## Is WHO is concerned by the change. -## -## 'dev' is for developpers (API changes, refactors...) -## 'usr' is for final users (UI changes) -## 'pkg' is for packagers (packaging changes) -## 'test' is for testers (test only related changes) -## 'doc' is for doc guys (doc only changes) -## -## COMMIT_MSG is ... well ... the commit message itself. -## -## TAGs are additionnal adjective as 'refactor' 'minor' 'cosmetic' -## -## They are preceded with a '!' or a '@' (prefer the former, as the -## latter is wrongly interpreted in github.) Commonly used tags are: -## -## 'refactor' is obviously for refactoring code only -## 'minor' is for a very meaningless change (a typo, adding a comment) -## 'cosmetic' is for cosmetic driven change (re-indentation, 80-col...) -## 'wip' is for partial functionality but complete subfunctionality. -## -## Example: -## -## new: usr: support of bazaar implemented -## chg: re-indentend some lines !cosmetic -## new: dev: updated code to be compatible with last version of killer lib. -## fix: pkg: updated year of licence coverage. -## new: test: added a bunch of test around user usability of feature X. -## fix: typo in spelling my name in comment. !minor -## -## Please note that multi-line commit message are supported, and only the -## first line will be considered as the "summary" of the commit message. So -## tags, and other rules only applies to the summary. The body of the commit -## message will be displayed in the changelog without reformatting. - - -## -## ``ignore_regexps`` is a line of regexps -## -## Any commit having its full commit message matching any regexp listed here -## will be ignored and won't be reported in the changelog. -## -ignore_regexps = [ - r'@minor', r'!minor', - r'@cosmetic', r'!cosmetic', - r'@refactor', r'!refactor', - r'@wip', r'!wip', - r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[p|P]kg:', - r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[d|D]ev:', - r'^(.{3,3}\s*:)?\s*[fF]irst commit.?\s*$', - r'^$', ## ignore commits with empty messages -] - - -## ``section_regexps`` is a list of 2-tuples associating a string label and a -## list of regexp -## -## Commit messages will be classified in sections thanks to this. Section -## titles are the label, and a commit is classified under this section if any -## of the regexps associated is matching. -## -## Please note that ``section_regexps`` will only classify commits and won't -## make any changes to the contents. So you'll probably want to go check -## ``subject_process`` (or ``body_process``) to do some changes to the subject, -## whenever you are tweaking this variable. -## -section_regexps = [ - ('New', [ - r'^([nN]ew|[fF]eat|[aA]dd)\s*(:|)\s*([^\n]*)$', - ]), - ('Fix', [ - r'^[fF]ix\s*(:|)\s*([^\n]*)$', - ]), - ('Test', [ - r'^([tT]est|[cC][iI])\s*(:|)\s*([^\n]*)$', - ]), - ('Other', None ## Match all lines - ), - -] - - -## ``body_process`` is a callable -## -## This callable will be given the original body and result will -## be used in the changelog. -## -## Available constructs are: -## -## - any python callable that take one txt argument and return txt argument. -## -## - ReSub(pattern, replacement): will apply regexp substitution. -## -## - Indent(chars=" "): will indent the text with the prefix -## Please remember that template engines gets also to modify the text and -## will usually indent themselves the text if needed. -## -## - Wrap(regexp=r"\n\n"): re-wrap text in separate paragraph to fill 80-Columns -## -## - noop: do nothing -## -## - ucfirst: ensure the first letter is uppercase. -## (usually used in the ``subject_process`` pipeline) -## -## - final_dot: ensure text finishes with a dot -## (usually used in the ``subject_process`` pipeline) -## -## - strip: remove any spaces before or after the content of the string -## -## - SetIfEmpty(msg="No commit message."): will set the text to -## whatever given ``msg`` if the current text is empty. -## -## Additionally, you can `pipe` the provided filters, for instance: -#body_process = Wrap(regexp=r'\n(?=\w+\s*:)') | Indent(chars=" ") -#body_process = Wrap(regexp=r'\n(?=\w+\s*:)') -#body_process = noop -body_process = ReSub(r'((^|\n)[A-Z]\w+(-\w+)*: .*(\n\s+.*)*)+$', r'') | strip - - -## ``subject_process`` is a callable -## -## This callable will be given the original subject and result will -## be used in the changelog. -## -## Available constructs are those listed in ``body_process`` doc. -subject_process = (strip | - ReSub(r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n@]*)(@[a-z]+\s+)*$', r'\4') | - SetIfEmpty("No commit message.") | ucfirst | final_dot) - - -## ``tag_filter_regexp`` is a regexp -## -## Tags that will be used for the changelog must match this regexp. -## -tag_filter_regexp = r'^[vV]{1}[0-9]+\.[0-9]+(\.[0-9]*)?$' - - -## ``unreleased_version_label`` is a string or a callable that outputs a string -## -## This label will be used as the changelog Title of the last set of changes -## between last valid tag and HEAD if any. -unreleased_version_label = "(unreleased)" - - -## ``output_engine`` is a callable -## -## This will change the output format of the generated changelog file -## -## Available choices are: -## -## - rest_py -## -## Legacy pure python engine, outputs ReSTructured text. -## This is the default. -## -## - mustache() -## -## Template name could be any of the available templates in -## ``templates/mustache/*.tpl``. -## Requires python package ``pystache``. -## Examples: -## - mustache("markdown") -## - mustache("restructuredtext") -## -## - makotemplate() -## -## Template name could be any of the available templates in -## ``templates/mako/*.tpl``. -## Requires python package ``mako``. -## Examples: -## - makotemplate("restructuredtext") -## -output_engine = rest_py -#output_engine = mustache("restructuredtext") -#output_engine = mustache("markdown") -#output_engine = makotemplate("restructuredtext") - - -## ``include_merge`` is a boolean -## -## This option tells git-log whether to include merge commits in the log. -## The default is to include them. -include_merge = False - - -## ``log_encoding`` is a string identifier -## -## This option tells gitchangelog what encoding is outputed by ``git log``. -## The default is to be clever about it: it checks ``git config`` for -## ``i18n.logOutputEncoding``, and if not found will default to git's own -## default: ``utf-8``. -log_encoding = 'utf-8' - - -## ``publish`` is a callable -## -## Sets what ``gitchangelog`` should do with the output generated by -## the output engine. ``publish`` is a callable taking one argument -## that is an interator on lines from the output engine. -## -## Some helper callable are provided: -## -## Available choices are: -## -## - stdout -## -## Outputs directly to standard output -## (This is the default) -## -## - FileInsertAtFirstRegexMatch(file, pattern, idx=lamda m: m.start()) -## -## Creates a callable that will parse given file for the given -## regex pattern and will insert the output in the file. -## ``idx`` is a callable that receive the matching object and -## must return a integer index point where to insert the -## the output in the file. Default is to return the position of -## the start of the matched string. -## -## - FileRegexSubst(file, pattern, replace, flags) -## -## Apply a replace inplace in the given file. Your regex pattern must -## take care of everything and might be more complex. Check the README -## for a complete copy-pastable example. -## -# publish = FileInsertIntoFirstRegexMatch( -# "CHANGELOG.rst", -# r'/(?P[0-9]+\.[0-9]+(\.[0-9]+)?)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n/', -# idx=lambda m: m.start(1) -# ) -#publish = stdout - - -## ``revs`` is a list of callable or a list of string -## -## callable will be called to resolve as strings and allow dynamical -## computation of these. The result will be used as revisions for -## gitchangelog (as if directly stated on the command line). This allows -## to filter exaclty which commits will be read by gitchangelog. -## -## To get a full documentation on the format of these strings, please -## refer to the ``git rev-list`` arguments. There are many examples. -## -## Using callables is especially useful, for instance, if you -## are using gitchangelog to generate incrementally your changelog. -## -## Some helpers are provided, you can use them:: -## -## - FileFirstRegexMatch(file, pattern): will return a callable that will -## return the first string match for the given pattern in the given file. -## If you use named sub-patterns in your regex pattern, it'll output only -## the string matching the regex pattern named "rev". -## -## - Caret(rev): will return the rev prefixed by a "^", which is a -## way to remove the given revision and all its ancestor. -## -## Please note that if you provide a rev-list on the command line, it'll -## replace this value (which will then be ignored). -## -## If empty, then ``gitchangelog`` will act as it had to generate a full -## changelog. -## -## The default is to use all commits to make the changelog. -#revs = ["^1.0.3", ] -#revs = [ -# Caret( -# FileFirstRegexMatch( -# "CHANGELOG.rst", -# r"(?P[0-9]+\.[0-9]+(\.[0-9]+)?)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n")), -# "HEAD" -#] -revs = [] diff --git a/.github/actions/setup-appium-server/action.yml b/.github/actions/setup-appium-server/action.yml new file mode 100644 index 000000000..a9177d4e8 --- /dev/null +++ b/.github/actions/setup-appium-server/action.yml @@ -0,0 +1,65 @@ +name: 'Start Appium Server' +description: 'Start Appium server with configurable arguments and wait for startup' + +inputs: + port: + description: 'Appium server port' + required: false + default: '4723' + host: + description: 'Appium server host' + required: false + default: '127.0.0.1' + timeout: + description: 'Timeout in seconds to wait for server startup' + required: false + default: '25' + server_args: + description: 'Additional server arguments (space-separated)' + required: false + default: '' + log_file: + description: 'Log file name' + required: false + default: 'appium.log' + +runs: + using: 'composite' + steps: + - name: Start Appium server + shell: bash + run: | + nohup appium server \ + --port=${{ inputs.port }} \ + --address=${{ inputs.host }} \ + --log-no-colors \ + --log-timestamp \ + --keep-alive-timeout 1200 \ + ${{ inputs.server_args }} \ + 2>&1 > ${{ inputs.log_file }} & + + - name: Wait for Appium server to start + shell: bash + run: | + TIMEOUT_SEC=${{ inputs.timeout }} + INTERVAL_SEC=1 + + start_time=$(date +%s) + while true; do + current_time=$(date +%s) + elapsed=$((current_time - start_time)) + + if nc -z ${{ inputs.host }} ${{ inputs.port }}; then + echo "Appium server is running after $elapsed seconds" + cat ${{ inputs.log_file }} + exit 0 + fi + + if [[ "$elapsed" -ge "$TIMEOUT_SEC" ]]; then + echo "${elapsed} seconds timeout reached: Appium server is NOT running" + exit 1 + fi + + echo "Waiting $elapsed seconds for Appium server to start..." + sleep "$INTERVAL_SEC" + done diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 13a08e874..140328bc4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,17 @@ version: 2 updates: -- package-ecosystem: pip +- package-ecosystem: uv directory: "/" schedule: interval: daily time: "11:00" open-pull-requests-limit: 10 +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + time: "11:00" + open-pull-requests-limit: 10 + commit-message: + prefix: "ci" + include: "scope" diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index 6227a2900..b301858d9 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -3,8 +3,6 @@ name: Functional Tests on: # Run by manual at this time workflow_dispatch: - push: - branches: [ master ] pull_request: branches: [ master ] @@ -12,6 +10,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +env: + APPIUM_TEST_SERVER_PORT: '4723' + APPIUM_TEST_SERVER_HOST: '127.0.0.1' + PYTHONUNBUFFERED: 1 + jobs: ios_test: strategy: @@ -21,20 +24,21 @@ jobs: - target: test/functional/ios/safari_tests.py name: func_test_ios1 - runs-on: macos-14 + runs-on: macos-15 # Please make sure the available Xcode versions and iOS versions # on the runner images. https://github.com/actions/runner-images env: - XCODE_VERSION: 15.3 - IOS_VERSION: 17.4 - IPHONE_MODEL: iPhone 15 Plus + XCODE_VERSION: '16.4' + IOS_VERSION: '18.5' + IPHONE_MODEL: 'iPhone 16 Plus' + PREBUILT_WDA_PATH: ${{ github.workspace }}/wda/WebDriverAgentRunner-Runner.app steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Install Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: 'lts/*' @@ -42,38 +46,63 @@ jobs: uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: ${{ env.XCODE_VERSION }} - - run: defaults write com.apple.iphonesimulator PasteboardAutomaticSync -bool false - - uses: futureware-tech/simulator-action@v3 + - name: Install Appium and drivers + run: | + npm install -g appium + appium driver install xcuitest + appium driver run xcuitest download-wda-sim --platform=ios --outdir=$(dirname "$PREBUILT_WDA_PATH") + + - name: Start Appium server + uses: ./.github/actions/setup-appium-server + with: + port: ${{ env.APPIUM_TEST_SERVER_PORT }} + host: ${{ env.APPIUM_TEST_SERVER_HOST }} + server_args: '--relaxed-security' + + - name: Start iOS Simulator UI + run: | + defaults write com.apple.iphonesimulator PasteboardAutomaticSync -bool false + open -Fn "$(xcode-select --print-path)/Applications/Simulator.app" + - name: Prepare iOS simulator + uses: futureware-tech/simulator-action@v5 with: - # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md model: ${{ env.IPHONE_MODEL }} os_version: ${{ env.IOS_VERSION }} + wait_for_boot: true + shutdown_after_job: false - # needed? - - run: brew install ffmpeg + - name: Finalize iOS simulator boot + run: xcrun --sdk iphonesimulator --show-sdk-version - # Start Appium - - run: npm install -g appium - - run: | - appium driver install xcuitest - appium driver run xcuitest build-wda --sdk=${{ env.IOS_VERSION }} --name='${{ env.IPHONE_MODEL }}' - appium plugin install images - appium plugin install execute-driver - nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log & + - name: Set up Python + uses: actions/setup-python@v7 + with: + python-version: 3.14 - - name: Set up Python 3.12 - uses: actions/setup-python@v5 + - name: Cache uv modules + uses: actions/cache@v6 with: - python-version: 3.12 + path: | + ~/.cache/uv + .venv + key: ${{ runner.os }}-uv-shared-${{ hashFiles('**/uv.lock') }} + restore-keys: | + ${{ runner.os }}-uv-shared- + + - name: Install uv + run: make install-uv - - run: | - # Separate 'run' creates differnet pipenv env. Does them in one run for now. - pip install --upgrade pip - pip install --upgrade pipenv - pipenv lock --clear - pipenv install -d --system - pytest ${{ matrix.test_targets.target}} --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + - name: Run Tests + run: | + uv run pytest -v ${{ matrix.test_targets.target}} \ + --doctest-modules \ + --junitxml=junit/test-results.xml \ + --cov=com \ + --cov-report=xml \ + --cov-report=html + env: + LOCAL_PREBUILT_WDA: ${{ env.PREBUILT_WDA_PATH }} - name: Save server output if: ${{ always() }} @@ -88,7 +117,7 @@ jobs: fail-fast: false matrix: test_targets: - - target: test/functional/android/appium_service_tests.py test/functional/android/chrome_tests.py + - target: test/functional/android/appium_service_tests.py test/functional/android/chrome_tests.py test/functional/android/bidi_tests.py name: func_test_android1 runs-on: ubuntu-latest @@ -98,25 +127,36 @@ jobs: ARCH: x86 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: actions/setup-java@v4 + - uses: actions/setup-java@v5.6.0 with: distribution: 'temurin' java-version: '17' + - name: Install ffmpeg + run: | + sudo apt-get update + sudo apt-get install -y ffmpeg + - name: Install Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: 'lts/*' - # Start Appium - - run: npm install -g appium - - run: | + - name: Install Appium and drivers + run: | + npm install -g appium appium driver install uiautomator2 appium driver install espresso appium plugin install execute-driver - nohup appium --use-plugins=execute-driver --relaxed-security --log-timestamp --log-no-colors 2>&1 > appium.log & + + - name: Start Appium server + uses: ./.github/actions/setup-appium-server + with: + port: ${{ env.APPIUM_TEST_SERVER_PORT }} + host: ${{ env.APPIUM_TEST_SERVER_HOST }} + server_args: '--relaxed-security --use-plugins=execute-driver' - name: Enable KVM group perms run: | @@ -125,14 +165,14 @@ jobs: sudo udevadm trigger --name-match=kvm - name: AVD cache - uses: actions/cache@v3 + uses: actions/cache@v6 id: avd-cache with: path: | ~/.android/avd/* ~/.android/adb* key: avd-${{ env.API_LEVEL }} - - name: create AVD and generate snapshot for caching + - name: Create AVD and generate snapshot for caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: @@ -144,23 +184,29 @@ jobs: disable-animations: false script: echo "Generated AVD snapshot for caching." - - name: Set up Python 3.12 - uses: actions/setup-python@v5 + - name: Set up Python 3.14 + uses: actions/setup-python@v7 with: - python-version: 3.12 + python-version: 3.14 - - name: run tests + - name: Cache uv modules + uses: actions/cache@v6 + with: + path: | + ~/.cache/uv + .venv + key: ${{ runner.os }}-uv-shared-${{ hashFiles('**/uv.lock') }} + restore-keys: | + ${{ runner.os }}-uv-shared- + + - name: Run tests uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ env.API_LEVEL }} arch: ${{ env.ARCH }} script: | - # Separate 'run' creates differnet pipenv env. Does them in one run for now. - pip install --upgrade pip - pip install --upgrade pipenv - pipenv lock --clear - pipenv install -d --system - pytest ${{ matrix.test_targets.target}} --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + make install-uv + uv run pytest -v ${{ matrix.test_targets.target}} --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html target: google_apis profile: Nexus 5X disable-spellchecker: true @@ -185,7 +231,7 @@ jobs: fail-fast: false matrix: include: - - platform: macos-14 + - platform: macos-15 e2e-tests: flutter-ios - platform: ubuntu-latest e2e-tests: flutter-android @@ -196,17 +242,18 @@ jobs: API_LEVEL: 28 ARCH: x86 CI: true - XCODE_VERSION: 15.4 - IOS_VERSION: 17.5 - IPHONE_MODEL: iPhone 15 + XCODE_VERSION: 16.4 + IOS_VERSION: 18.5 + IPHONE_MODEL: iPhone 16 FLUTTER_ANDROID_APP: "https://github.com/AppiumTestDistribution/appium-flutter-server/releases/latest/download/app-debug.apk" FLUTTER_IOS_APP: "https://github.com/AppiumTestDistribution/appium-flutter-server/releases/latest/download/ios.zip" + PREBUILT_WDA_PATH: ${{ github.workspace }}/wda/WebDriverAgentRunner-Runner.app steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: actions/setup-java@v4 + - uses: actions/setup-java@v5.6.0 if: matrix.e2e-tests == 'flutter-android' with: distribution: 'zulu' @@ -219,25 +266,54 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - - name: Set up Python 3.12 - uses: actions/setup-python@v5 + - name: Set up Python 3.14 + uses: actions/setup-python@v7 with: - python-version: 3.12 + python-version: 3.14 - name: Install Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: 'lts/*' - - name: Install Appium - run: npm install --location=global appium + - name: Select Xcode + if: matrix.e2e-tests == 'flutter-ios' + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ env.XCODE_VERSION }} - - name: Install Android drivers and Run Appium + - name: Install Appium and drivers if: matrix.e2e-tests == 'flutter-android' run: | + npm install --location=global appium appium driver install uiautomator2 appium driver install appium-flutter-integration-driver --source npm - nohup appium --allow-insecure=adb_shell --relaxed-security --log-timestamp --log-no-colors 2>&1 > appium_flutter_android.log & + + - name: Install Appium and drivers + if: matrix.e2e-tests == 'flutter-ios' + run: | + npm install --location=global appium + appium driver install xcuitest + appium driver run xcuitest download-wda-sim --platform=ios --outdir=$(dirname "$PREBUILT_WDA_PATH") + appium driver install appium-flutter-integration-driver --source npm + + - name: Start Appium server + uses: ./.github/actions/setup-appium-server + with: + port: ${{ env.APPIUM_TEST_SERVER_PORT }} + host: ${{ env.APPIUM_TEST_SERVER_HOST }} + server_args: '--relaxed-security' + log_file: appium-${{ matrix.e2e-tests }}.log + + - name: Cache uv modules + uses: actions/cache@v6 + with: + path: | + ~/.cache/uv + .venv + key: ${{ runner.os }}-uv-shared-${{ hashFiles('**/uv.lock') }} + restore-keys: | + ${{ runner.os }}-uv-shared- - name: Run Android tests if: matrix.e2e-tests == 'flutter-android' @@ -245,55 +321,48 @@ jobs: with: api-level: ${{ env.API_LEVEL }} script: | - pip install --upgrade pip - pip install --upgrade pipenv - pipenv lock --clear - pipenv install -d --system - export PLATFORM=android - pytest test/functional/flutter_integration/*_test.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + make install-uv + uv run pytest -v test/functional/flutter_integration/*_test.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html target: default disable-spellchecker: true disable-animations: true - - name: Save server output - if: always() && matrix.e2e-tests == 'flutter-android' - uses: actions/upload-artifact@master - with: - name: appium-flutter-android.log - path: appium_flutter_android.log - - - name: Select Xcode + - name: Start iOS Simulator UI if: matrix.e2e-tests == 'flutter-ios' - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: ${{ env.XCODE_VERSION }} + run: | + defaults write com.apple.iphonesimulator PasteboardAutomaticSync -bool false + open -Fn "$(xcode-select --print-path)/Applications/Simulator.app" - - uses: futureware-tech/simulator-action@v3 + - uses: futureware-tech/simulator-action@v5 if: matrix.e2e-tests == 'flutter-ios' with: # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md model: ${{ env.IPHONE_MODEL }} os_version: ${{ env.IOS_VERSION }} + wait_for_boot: true + shutdown_after_job: false - - name: install dependencies + - name: Finalize iOS simulator boot if: matrix.e2e-tests == 'flutter-ios' - run: brew install ffmpeg - - - name: Install IOS drivers and Run Appium - if: matrix.e2e-tests == 'flutter-ios' - run: | - appium driver install xcuitest - appium driver install appium-flutter-integration-driver --source npm - appium driver run xcuitest build-wda - nohup appium --allow-insecure=adb_shell --relaxed-security --log-timestamp --log-no-colors 2>&1 > appium_ios.log & + run: xcrun --sdk iphonesimulator --show-sdk-version - name: Run IOS tests if: matrix.e2e-tests == 'flutter-ios' run: | - # Separate 'run' creates differnet pipenv env. Does them in one run for now. - pip install --upgrade pip - pip install --upgrade pipenv - pipenv lock --clear - pipenv install -d --system + make install-uv export PLATFORM=ios - pytest test/functional/flutter_integration/*_test.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + uv run pytest -v test/functional/flutter_integration/*_test.py \ + --doctest-modules \ + --junitxml=junit/test-results.xml \ + --cov=com \ + --cov-report=xml \ + --cov-report=html + env: + LOCAL_PREBUILT_WDA: ${{ env.PREBUILT_WDA_PATH }} + + - name: Save server output + if: ${{ always() }} + uses: actions/upload-artifact@master + with: + name: appium-${{ matrix.e2e-tests }}.log + path: appium-${{ matrix.e2e-tests }}.log diff --git a/.github/workflows/lock-update.yml b/.github/workflows/lock-update.yml new file mode 100644 index 000000000..8af24642e --- /dev/null +++ b/.github/workflows/lock-update.yml @@ -0,0 +1,31 @@ +name: Update uv.lock + +on: + pull_request: + types: [ opened, synchronize ] + paths: + - 'pyproject.toml' + +permissions: + contents: write + pull-requests: write + +jobs: + uv-lock-update: + if: github.actor == 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ github.head_ref }} + - name: Set up Python + uses: actions/setup-python@v7 + with: + python-version: '3.12' + - name: Install uv + run: make install-uv + - run: uv lock + - uses: stefanzweifel/git-auto-commit-action@v7 + with: + commit_message: "chore: Refresh uv.lock" diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml index 51c3a5065..929df1336 100644 --- a/.github/workflows/pr-title.yml +++ b/.github/workflows/pr-title.yml @@ -3,14 +3,8 @@ on: pull_request: types: [opened, edited, synchronize, reopened] - jobs: lint: - name: https://www.conventionalcommits.org - runs-on: ubuntu-latest - steps: - - uses: beemojs/conventional-pr-action@v3 - with: - config-preset: angular - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: appium/appium-workflows/.github/workflows/pr-title.yml@main + with: + config-preset: angular diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 000000000..55d4d59bf --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,50 @@ +name: Release + +on: + workflow_dispatch: + # push: + # branches: [ master ] + +permissions: + contents: write + id-token: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Set up Python + uses: actions/setup-python@v7 + with: + python-version: '3.12' + + - name: Install uv + run: make install-uv + + - name: Semantic Release Version + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: uv run semantic-release version + + - name: Check if dist directory exists + id: check_dist + run: | + if [ -d "dist" ]; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + + - name: Publish to PyPI + if: steps.check_dist.outputs.exists == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ + + - name: Publish GitHub Release + if: steps.check_dist.outputs.exists == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: uv run semantic-release publish diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 02d9c472d..37cfa1624 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -12,30 +12,25 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} - - name: Install tox - run: pip install tox - - name: Run Tox - run: tox -e py - - # test-win: - # runs-on: windows-latest - # strategy: - # matrix: - # python-version: ["3.7", "3.8", "3.9", "3.10"] - # steps: - # - uses: actions/checkout@v3 - # - name: Set up Python ${{ matrix.python-version }} - # uses: actions/setup-python@v3 - # with: - # python-version: ${{ matrix.python-version }} - # - name: Install tox - # run: pip install tox - # - name: Run Tox - # run: tox -e py + - name: Cache uv modules + uses: actions/cache@v6 + with: + path: | + ~/.cache/uv + .venv + key: ${{ runner.os }}-uv-shared-${{ hashFiles('**/uv.lock') }} + restore-keys: | + ${{ runner.os }}-uv-shared- + - name: Install uv + run: make install-uv + - name: Run Checks + run: make check + - name: Run Unit Tests + run: make unittest diff --git a/.gitignore b/.gitignore index 911a3616f..9ad0aa1d1 100644 --- a/.gitignore +++ b/.gitignore @@ -24,8 +24,7 @@ __pycache__ # Virtual Environments venv* +.venv .tox -Pipfile.lock - .coverage diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 17b86e2a6..b40175c99 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,15 @@ repos: -- repo: https://github.com/astral-sh/ruff-pre-commit - # Ruff version. - rev: v0.9.0 - hooks: - # Run the linter. - - id: ruff - args: [ --fix ] - # Run the formatter. - - id: ruff-format + - repo: local + hooks: + - id: ruff-check + name: ruff check + entry: uv run ruff check + language: system + types_or: [python, pyi] + args: [--fix, --show-fixes] + + - id: ruff-format + name: ruff format + entry: uv run ruff format + language: system + types_or: [python, pyi] diff --git a/.ruff.toml b/.ruff.toml index 96cebc8fc..09d820222 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -13,8 +13,6 @@ select = [ [lint.per-file-ignores] "__init__.py" = [ - # unused-import - "F401", # import violations "E402" ] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..2f3043b43 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2336 @@ +# CHANGELOG + + + +## v5.3.1 (2026-04-19) + +### Bug Fixes + +- Replace assert with ValueError for state validation + ([#1219](https://github.com/appium/python-client/pull/1219), + [`2193837`](https://github.com/appium/python-client/commit/2193837fc0af579231f08315431c6a2347bc2b65)) + +### Chores + +- **deps-dev**: Bump ruff from 0.15.10 to 0.15.11 + ([#1217](https://github.com/appium/python-client/pull/1217), + [`30dad44`](https://github.com/appium/python-client/commit/30dad44a9ab991c14134119b876ca80c21d10e88)) + +- **deps-dev**: Bump ruff from 0.15.7 to 0.15.8 + ([#1210](https://github.com/appium/python-client/pull/1210), + [`7181b20`](https://github.com/appium/python-client/commit/7181b201d0cd94561fe5f07e8bcb0bf03b8ca0e0)) + +- **deps-dev**: Bump ruff from 0.15.8 to 0.15.9 + ([#1214](https://github.com/appium/python-client/pull/1214), + [`21fdecb`](https://github.com/appium/python-client/commit/21fdecbdf975515087e4c88e04c3356b288f5ac6)) + +- **deps-dev**: Bump ruff from 0.15.9 to 0.15.10 + ([#1216](https://github.com/appium/python-client/pull/1216), + [`9016e94`](https://github.com/appium/python-client/commit/9016e9431dd9e8c0218e1499c516dcf70642b7e4)) + + +## v5.3.0 (2026-03-28) + +### Bug Fixes + +- **test**: Simplify assertion for AndroidKeyMetastate in test_has_some_metastates + ([#1211](https://github.com/appium/python-client/pull/1211), + [`ad8c5c9`](https://github.com/appium/python-client/commit/ad8c5c9ce33e85d6b417f2545df83b32e56c7fd0)) + +### Chores + +- **deps-dev**: Bump pytest-cov from 7.0.0 to 7.1.0 + ([#1209](https://github.com/appium/python-client/pull/1209), + [`8466c27`](https://github.com/appium/python-client/commit/8466c27b8759fc18169a48d7f7ae49cc33fce0a9)) + +- **deps-dev**: Bump ruff from 0.15.4 to 0.15.5 + ([#1205](https://github.com/appium/python-client/pull/1205), + [`628a731`](https://github.com/appium/python-client/commit/628a73111c315860754a7e0cc88f3b68917f3fc2)) + +- **deps-dev**: Bump ruff from 0.15.5 to 0.15.6 + ([#1207](https://github.com/appium/python-client/pull/1207), + [`9b81d2a`](https://github.com/appium/python-client/commit/9b81d2a42fbca4d4c4c4f2d54ce183c627479f85)) + +- **deps-dev**: Bump ruff from 0.15.6 to 0.15.7 + ([#1208](https://github.com/appium/python-client/pull/1208), + [`339fff9`](https://github.com/appium/python-client/commit/339fff93d0ac7472140e7869790e203f5160ad60)) + +### Continuous Integration + +- **deps**: Bump futureware-tech/simulator-action from 4 to 5 + ([#1206](https://github.com/appium/python-client/pull/1206), + [`a3c13dc`](https://github.com/appium/python-client/commit/a3c13dc98e9d50fb19bd1e37bdbdf86887587144)) + +### Features + +- Add AndroidKeyMetastate class for keyboard metastate constants + ([#1211](https://github.com/appium/python-client/pull/1211), + [`ad8c5c9`](https://github.com/appium/python-client/commit/ad8c5c9ce33e85d6b417f2545df83b32e56c7fd0)) + +- **android**: Add AndroidKeyMetastate class for keyboard metastate constants + ([#1211](https://github.com/appium/python-client/pull/1211), + [`ad8c5c9`](https://github.com/appium/python-client/commit/ad8c5c9ce33e85d6b417f2545df83b32e56c7fd0)) + + +## v5.2.7 (2026-03-05) + +### Bug Fixes + +- Fix type checker errors for pyright ([#1203](https://github.com/appium/python-client/pull/1203), + [`cd4699a`](https://github.com/appium/python-client/commit/cd4699a786fe65edd0ce525eadf36d944c01c2d5)) + +### Chores + +- Modify metadata ([#1199](https://github.com/appium/python-client/pull/1199), + [`e993461`](https://github.com/appium/python-client/commit/e9934619131f757e51faf484bfdea3ca491b2ecf)) + +- Remove issac's email as invalid one ([#1199](https://github.com/appium/python-client/pull/1199), + [`e993461`](https://github.com/appium/python-client/commit/e9934619131f757e51faf484bfdea3ca491b2ecf)) + +- **deps-dev**: Bump ruff from 0.15.0 to 0.15.1 + ([#1200](https://github.com/appium/python-client/pull/1200), + [`13bf27b`](https://github.com/appium/python-client/commit/13bf27bc3247221fab9fdf173e30ba3b998dd9fa)) + +- **deps-dev**: Bump ruff from 0.15.1 to 0.15.2 + ([#1201](https://github.com/appium/python-client/pull/1201), + [`3c33eae`](https://github.com/appium/python-client/commit/3c33eae0ed5e5c2c555fd02e4a011c4377a1103d)) + +- **deps-dev**: Bump ruff from 0.15.2 to 0.15.4 + ([#1202](https://github.com/appium/python-client/pull/1202), + [`2a14455`](https://github.com/appium/python-client/commit/2a14455f0e85f99f6a520783b4e95dfcfc5abdb5)) + +### Continuous Integration + +- Enable auto release to master + ([`52203a4`](https://github.com/appium/python-client/commit/52203a4613e3a3694e1cba5c34a45fb7b2e2fda4)) + +- Update the trigger ([#1199](https://github.com/appium/python-client/pull/1199), + [`e993461`](https://github.com/appium/python-client/commit/e9934619131f757e51faf484bfdea3ca491b2ecf)) + + +## v5.2.6 (2026-02-12) + +### Bug Fixes + +- Update readme and to kick a release to test out auto release + ([`a4cda69`](https://github.com/appium/python-client/commit/a4cda696bc872f3879a2e7d36df852471f672211)) + +### Chores + +- **deps-dev**: Bump ruff from 0.14.14 to 0.15.0 + ([#1198](https://github.com/appium/python-client/pull/1198), + [`1114b10`](https://github.com/appium/python-client/commit/1114b1033865cf0112da0877f56f68e910daac28)) + +- **deps-dev**: Bump types-python-dateutil + ([#1197](https://github.com/appium/python-client/pull/1197), + [`ae2802e`](https://github.com/appium/python-client/commit/ae2802ef16d4337e81dd01cf6dcc4360a60a8509)) + +### Continuous Integration + +- Add skip to publish if not package was made + ([`bb8b4b3`](https://github.com/appium/python-client/commit/bb8b4b35cd3ece54c857568005168b9d0b6e19a8)) + +- Create automatic release action ([#1196](https://github.com/appium/python-client/pull/1196), + [`208c35c`](https://github.com/appium/python-client/commit/208c35c27da10b78bfd346c3ecdd34d78b920473)) + + +## v5.2.5 (2026-01-24) + +### Chores + +- Add a few new caps in the standard ([#1175](https://github.com/appium/python-client/pull/1175), + [`b22b031`](https://github.com/appium/python-client/commit/b22b0316b18e551695344d11e25e940a7f7ec297)) + +- Enable dependabot for uv ([#1181](https://github.com/appium/python-client/pull/1181), + [`fd138de`](https://github.com/appium/python-client/commit/fd138deb519b5ed7cd2a4a80a639294ec8b42ad4)) + +- Update iOS e2e tests ([#1178](https://github.com/appium/python-client/pull/1178), + [`3677e0c`](https://github.com/appium/python-client/commit/3677e0c3e347a457f3f72b204b0644403725be3b)) + +- **deps**: Bump actions/cache from 3 to 4 + ([#1184](https://github.com/appium/python-client/pull/1184), + [`936e146`](https://github.com/appium/python-client/commit/936e146c05216fe1c620efb7c5e34892ae7e7dcc)) + +- **deps**: Bump actions/cache from 4 to 5 + ([#1191](https://github.com/appium/python-client/pull/1191), + [`aa41b80`](https://github.com/appium/python-client/commit/aa41b80ebfd6c05f3f5b45dbc66ec41b12200040)) + +- **deps**: Bump actions/checkout from 4 to 6 + ([#1186](https://github.com/appium/python-client/pull/1186), + [`7ce850b`](https://github.com/appium/python-client/commit/7ce850bfff817a748dc63ea27c00774c333e76c6)) + +- **deps**: Bump actions/setup-java from 4 to 5 + ([#1183](https://github.com/appium/python-client/pull/1183), + [`91e1855`](https://github.com/appium/python-client/commit/91e18558f78f048a423ea69ededea97596685abe)) + +- **deps**: Bump actions/setup-node from 4 to 6 + ([#1188](https://github.com/appium/python-client/pull/1188), + [`3f8eeec`](https://github.com/appium/python-client/commit/3f8eeec1f499efbe7e82007b22bed7d8a687a316)) + +- **deps**: Bump actions/setup-python from 4 to 6 + ([#1187](https://github.com/appium/python-client/pull/1187), + [`7708ebe`](https://github.com/appium/python-client/commit/7708ebe35761969cb5fad80e9a1a709553a119d1)) + +- **deps**: Bump selenium from 4.33.0 to 4.36.0 + ([#1182](https://github.com/appium/python-client/pull/1182), + [`64c0119`](https://github.com/appium/python-client/commit/64c011926cf804dc8edf27e7c15ffeb2568a45f5)) + +- **deps**: Bump stefanzweifel/git-auto-commit-action from 5 to 7 + ([#1185](https://github.com/appium/python-client/pull/1185), + [`8389732`](https://github.com/appium/python-client/commit/8389732af5392254325a1616a00ea42df22b6bbe)) + +- **deps-dev**: Bump pytest-cov from 6.3.0 to 7.0.0 + ([#1194](https://github.com/appium/python-client/pull/1194), + [`32aca30`](https://github.com/appium/python-client/commit/32aca304057ee68bb2f1a3c0495054d245e4b955)) + +- **deps-dev**: Bump python-semantic-release from 10.3.2 to 10.5.3 + ([#1195](https://github.com/appium/python-client/pull/1195), + [`4844534`](https://github.com/appium/python-client/commit/48445348e313f6d256bdee5b9229772e87674470)) + +### Continuous Integration + +- Add commit message configuration for Dependabot + ([`b68fa61`](https://github.com/appium/python-client/commit/b68fa6158e7c1f7df5479b50af50b937b1d2511d)) + +- Add GitHub Actions to Dependabot configuration + ([`c2edb68`](https://github.com/appium/python-client/commit/c2edb6874da805f8a4e7ba345f31303a51ba4fb6)) + +- Use py 3.14 ([#1193](https://github.com/appium/python-client/pull/1193), + [`3bb2021`](https://github.com/appium/python-client/commit/3bb20212f67cdbe73d72ff8ff9541a5f57cc8393)) + +- Use the central repo's workflow + ([`e59b853`](https://github.com/appium/python-client/commit/e59b853497ae04706137cf252bfa3b92e6a1e229)) + +- Use the latest appium flutter integration driver on CI + ([#1176](https://github.com/appium/python-client/pull/1176), + [`f61c059`](https://github.com/appium/python-client/commit/f61c059d189f19e01ca6bd11670e6d07c550ec31)) + +### Documentation + +- Clean up CHANGELOG by removing old sections + ([`d4f3e16`](https://github.com/appium/python-client/commit/d4f3e16d33cdc22651e99f1f161ff8e79f78328e)) + +- Fix the units for bitRate value + ([`4634378`](https://github.com/appium/python-client/commit/4634378e8e1fe78b962b0d5280a6bf1b05b9b15d)) + +### Testing + +- Fix accidental missing deps + ([`b04f65e`](https://github.com/appium/python-client/commit/b04f65e58ca7d86bc3b5a2cf2d3a8f61dd225f81)) + +- Update Android tests to the canonical pytest format + ([#1180](https://github.com/appium/python-client/pull/1180), + [`b9564c7`](https://github.com/appium/python-client/commit/b9564c78bc22d1fc4b0e345199c9ede7584ad1c3)) + +- Update flutter tests to canonic pytest format + ([#1179](https://github.com/appium/python-client/pull/1179), + [`ed27b1f`](https://github.com/appium/python-client/commit/ed27b1fad14467b15779abb2942627373977f243)) + + +## v5.2.4 (2025-09-11) + +### Chores + +- Add an error handling in _adjust_image_payload + ([#1172](https://github.com/appium/python-client/pull/1172), + [`dc301ec`](https://github.com/appium/python-client/commit/dc301ec5303f6d5fa6af0ec4370d1ffe88ef1f1d)) + +## v5.2.3 (2025-09-09) + +### Bug Fixes + +- Adjust images payload for image comparison API + ([#1170](https://github.com/appium/python-client/pull/1170), + [`b471a05`](https://github.com/appium/python-client/commit/b471a050833c59bb5cacf0872013bd5dc1f24491)) + +### Continuous Integration + +- Update CI config ([#1171](https://github.com/appium/python-client/pull/1171), + [`f867ea5`](https://github.com/appium/python-client/commit/f867ea580c86e043b5fbb586149a18ad87d08239)) + + +## v5.2.2 (2025-08-15) + +### Chores + +- Remvoe unnecessary lines in the changelog and readme + ([`840e958`](https://github.com/appium/python-client/commit/840e95831176f80b5a48921c711f62b5457652bf)) + +- Stop using existing release script ([#1166](https://github.com/appium/python-client/pull/1166), + [`a6238e2`](https://github.com/appium/python-client/commit/a6238e278452a23227cef8d6b4896d259b357ffc)) + +### Documentation + +- Add one more step + ([`d99f699`](https://github.com/appium/python-client/commit/d99f6995e8b2b5295180b7c6b8d54e79fe05bf46)) + + +## v5.2.1 (2025-08-14) + +### Chores + +- Revert version created by release script checking + ([#1164](https://github.com/appium/python-client/pull/1164), + [`04a8580`](https://github.com/appium/python-client/commit/04a8580f999843bc9d121c1ed4ce872761350f31)) + +- Use semantic release changelog instead of gitchangelog + ([#1163](https://github.com/appium/python-client/pull/1163), + [`dd3709e`](https://github.com/appium/python-client/commit/dd3709e084e802d6534d51151be1bd45456a4ebd)) + +- Use semantic-release for most of release script execution + ([#1165](https://github.com/appium/python-client/pull/1165), + [`f6c4687`](https://github.com/appium/python-client/commit/f6c46878c12ae0a8a9ff82e1e9755f325eb8e7cf)) + +### Documentation + +- Manage sphinx stuff via uv ([#1162](https://github.com/appium/python-client/pull/1162), + [`df66645`](https://github.com/appium/python-client/commit/df66645ab284193f8f673d491c8daddcce381a71)) + +- Update readme ([#1165](https://github.com/appium/python-client/pull/1165), + [`f6c4687`](https://github.com/appium/python-client/commit/f6c46878c12ae0a8a9ff82e1e9755f325eb8e7cf)) + + +## v5.2.0 (2025-08-07) + +### Bug Fixes + +- Restore mypy linting ([#1156](https://github.com/appium/python-client/pull/1156), + [`d3c7511`](https://github.com/appium/python-client/commit/d3c7511d6cf6de3a4717b6c691d047785106bed5)) + +### Chores + +- Update uv version ([#1160](https://github.com/appium/python-client/pull/1160), + [`ee8af97`](https://github.com/appium/python-client/commit/ee8af97dcbfe7e129fedce066ccb4138c6c43329)) + +- Use uv build to build the package ([#1159](https://github.com/appium/python-client/pull/1159), + [`c095f79`](https://github.com/appium/python-client/commit/c095f79997171ab076584fea94d6fac0bd3e23ce)) + +- Use uv for version ([#1160](https://github.com/appium/python-client/pull/1160), + [`ee8af97`](https://github.com/appium/python-client/commit/ee8af97dcbfe7e129fedce066ccb4138c6c43329)) + +- Use version via uv ([#1160](https://github.com/appium/python-client/pull/1160), + [`ee8af97`](https://github.com/appium/python-client/commit/ee8af97dcbfe7e129fedce066ccb4138c6c43329)) + +### Continuous Integration + +- Add a script to automatically update uv.lock upon dependabot updates + ([#1158](https://github.com/appium/python-client/pull/1158), + [`1a1cf34`](https://github.com/appium/python-client/commit/1a1cf34975224a47b6365a5524d19a409a2ccffd)) + +### Features + +- Switch package management from pipenv to uv + ([#1155](https://github.com/appium/python-client/pull/1155), + [`7af0fd4`](https://github.com/appium/python-client/commit/7af0fd4c1ffc3b52e912dae662199033b6c55f58)) + + +## v5.1.3 (2025-08-07) + +### Chores + +- Fix some mypy ([#1153](https://github.com/appium/python-client/pull/1153), + [`4e1aafd`](https://github.com/appium/python-client/commit/4e1aafd9a0580d9ce3e5aaaa0eb223dad16e4881)) + +- Fix some mypy errors ([#1153](https://github.com/appium/python-client/pull/1153), + [`4e1aafd`](https://github.com/appium/python-client/commit/4e1aafd9a0580d9ce3e5aaaa0eb223dad16e4881)) + +- Revert protocol ([#1152](https://github.com/appium/python-client/pull/1152), + [`ab6c7bb`](https://github.com/appium/python-client/commit/ab6c7bb5aa01ca1be729dfa85cd604c591af0615)) + +- Wrong usage of CanFindElements #1148 ([#1152](https://github.com/appium/python-client/pull/1152), + [`ab6c7bb`](https://github.com/appium/python-client/commit/ab6c7bb5aa01ca1be729dfa85cd604c591af0615)) + +- **deps-dev**: Update pytest-cov requirement from ~=5.0 to ~=6.2 + ([#1136](https://github.com/appium/python-client/pull/1136), + [`5e14916`](https://github.com/appium/python-client/commit/5e149160132d7a83d21d3a3252aeb2fe3f630306)) + +- **deps-dev**: Update ruff requirement from ~=0.12.4 to ~=0.12.5 + ([#1149](https://github.com/appium/python-client/pull/1149), + [`1457866`](https://github.com/appium/python-client/commit/145786676474211a27f7ab1763afc73d545da2b2)) + +- **deps-dev**: Update ruff requirement from ~=0.12.5 to ~=0.12.7 + ([#1151](https://github.com/appium/python-client/pull/1151), + [`abf210a`](https://github.com/appium/python-client/commit/abf210ab77015e475200f3db42f61e4eaa2a6773)) + +### Testing + +- Add bidi example in test ([#1154](https://github.com/appium/python-client/pull/1154), + [`f8922da`](https://github.com/appium/python-client/commit/f8922daa965e25db4322c7d77369a2e5c133e61e)) + +- Add bidi log example test ([#1154](https://github.com/appium/python-client/pull/1154), + [`f8922da`](https://github.com/appium/python-client/commit/f8922daa965e25db4322c7d77369a2e5c133e61e)) + + +## v5.1.2 (2025-07-23) + +### Chores + +- Fix typos ([#1133](https://github.com/appium/python-client/pull/1133), + [`a1b33c3`](https://github.com/appium/python-client/commit/a1b33c3e632382316b73540a7339a51ad57b9a2b)) + +- Inherit CanFindElements ([#1148](https://github.com/appium/python-client/pull/1148), + [`7ca9425`](https://github.com/appium/python-client/commit/7ca942533786b5e9fb991cee3bd4c373fc1e99b4)) + +- Remove unused commands ([#1132](https://github.com/appium/python-client/pull/1132), + [`a5f0147`](https://github.com/appium/python-client/commit/a5f0147dabe7cf7c927b9ffeabb41a7672bef801)) + +- **deps**: Bump selenium from 4.32.0 to 4.33.0 + ([#1130](https://github.com/appium/python-client/pull/1130), + [`617ba6c`](https://github.com/appium/python-client/commit/617ba6cd943ad4ca15148fae6ee1aed949d123ff)) + +- **deps-dev**: Update pytest requirement from ~=8.3 to ~=8.4 + ([#1134](https://github.com/appium/python-client/pull/1134), + [`0f9dd3b`](https://github.com/appium/python-client/commit/0f9dd3bc22274998add55fb0c6fa4ba956f0a47f)) + +- **deps-dev**: Update ruff requirement from ~=0.11.10 to ~=0.11.11 + ([#1128](https://github.com/appium/python-client/pull/1128), + [`2f2205f`](https://github.com/appium/python-client/commit/2f2205f1763a62992279c71e5e3cc518e7fc05c0)) + +- **deps-dev**: Update ruff requirement from ~=0.11.11 to ~=0.11.12 + ([#1131](https://github.com/appium/python-client/pull/1131), + [`ba38ccd`](https://github.com/appium/python-client/commit/ba38ccdf2afd9b13641a8bcfb171329acf937b32)) + +- **deps-dev**: Update ruff requirement from ~=0.11.12 to ~=0.11.13 + ([#1135](https://github.com/appium/python-client/pull/1135), + [`0887cc1`](https://github.com/appium/python-client/commit/0887cc1d6bb9d6accb46542ad83504f5f0718e1b)) + +- **deps-dev**: Update ruff requirement from ~=0.11.13 to ~=0.12.1 + ([#1139](https://github.com/appium/python-client/pull/1139), + [`e75c58f`](https://github.com/appium/python-client/commit/e75c58f5548e930003d0c4fac485ad2a05cda8cb)) + +- **deps-dev**: Update ruff requirement from ~=0.11.8 to ~=0.11.10 + ([#1127](https://github.com/appium/python-client/pull/1127), + [`128666e`](https://github.com/appium/python-client/commit/128666e7d858b52e75fb3778c7de95c39b0182db)) + +- **deps-dev**: Update ruff requirement from ~=0.12.1 to ~=0.12.2 + ([#1142](https://github.com/appium/python-client/pull/1142), + [`884062d`](https://github.com/appium/python-client/commit/884062d045ea47e58d33478e2d0ad477c4aeffe5)) + +- **deps-dev**: Update ruff requirement from ~=0.12.2 to ~=0.12.3 + ([#1144](https://github.com/appium/python-client/pull/1144), + [`772723b`](https://github.com/appium/python-client/commit/772723babc06888141163fd90c893fda1bd73996)) + +- **deps-dev**: Update ruff requirement from ~=0.12.3 to ~=0.12.4 + ([#1146](https://github.com/appium/python-client/pull/1146), + [`d43a190`](https://github.com/appium/python-client/commit/d43a190cc99dcae31f13c074b7f7ac9e7552f9d9)) + +- **deps-dev**: Update tox requirement from ~=4.25 to ~=4.26 + ([#1126](https://github.com/appium/python-client/pull/1126), + [`157ec01`](https://github.com/appium/python-client/commit/157ec011c279a56ebceb7bf5becd733c562ce9f3)) + +- **deps-dev**: Update tox requirement from ~=4.26 to ~=4.27 + ([#1138](https://github.com/appium/python-client/pull/1138), + [`c0ed394`](https://github.com/appium/python-client/commit/c0ed394765cc8f7567edd069b36903b2bbde3883)) + +### Continuous Integration + +- Apply prebuilt wda ([#1141](https://github.com/appium/python-client/pull/1141), + [`e3bcc37`](https://github.com/appium/python-client/commit/e3bcc3768d44b1ff1c85711f5553141443f40d0b)) + +### Documentation + +- Re-run the gen code ([#1129](https://github.com/appium/python-client/pull/1129), + [`3457e49`](https://github.com/appium/python-client/commit/3457e499f04e3d34d881ef6362cabe0751dd7a2d)) + + +## v5.1.1 (2025-05-06) + +### Chores + +- **deps**: Bump selenium from 4.31.0 to 4.32.0 + ([#1124](https://github.com/appium/python-client/pull/1124), + [`9e27a99`](https://github.com/appium/python-client/commit/9e27a998113a31fcc1440e08f52cb79cd26a81d7)) + +### Documentation + +- Update compatibility matrix + ([`9e42c7f`](https://github.com/appium/python-client/commit/9e42c7faf7c298dec1b32d25d8e71328ec17c073)) + +- Update README.md + ([`48371a7`](https://github.com/appium/python-client/commit/48371a7714fbdbb6bd7dabc5ae5762eb80be6fc6)) + + +## v5.1.0 (2025-05-05) + +### Chores + +- **deps**: Bump selenium from 4.29.0 to 4.30.0 + ([#1108](https://github.com/appium/python-client/pull/1108), + [`96f7e6b`](https://github.com/appium/python-client/commit/96f7e6bf2377bf1e07b30f8b3571fc24bdff9c7e)) + +- **deps**: Bump selenium from 4.30.0 to 4.31.0 + ([#1113](https://github.com/appium/python-client/pull/1113), + [`f59f23d`](https://github.com/appium/python-client/commit/f59f23df08e7e3c4f64d63afcb81d22445d21010)) + +- **deps**: Update typing-extensions requirement + ([#1115](https://github.com/appium/python-client/pull/1115), + [`24f9f7f`](https://github.com/appium/python-client/commit/24f9f7f8530abf376f833ea73541288f569c9f31)) + +- **deps**: Update typing-extensions requirement + ([#1112](https://github.com/appium/python-client/pull/1112), + [`e3add90`](https://github.com/appium/python-client/commit/e3add903b79921bc2dc315affadb4571014f2e48)) + +- **deps-dev**: Update ruff requirement from ~=0.10.0 to ~=0.11.2 + ([#1107](https://github.com/appium/python-client/pull/1107), + [`bfaefa1`](https://github.com/appium/python-client/commit/bfaefa1c458c5d98842a3c786d466a5094a824b8)) + +- **deps-dev**: Update ruff requirement from ~=0.11.2 to ~=0.11.3 + ([#1111](https://github.com/appium/python-client/pull/1111), + [`c403235`](https://github.com/appium/python-client/commit/c4032354223833ccc62869f059233cb188f56774)) + +- **deps-dev**: Update ruff requirement from ~=0.11.3 to ~=0.11.4 + ([#1114](https://github.com/appium/python-client/pull/1114), + [`d27b924`](https://github.com/appium/python-client/commit/d27b924185736524e24558575b1100e1b333b39a)) + +- **deps-dev**: Update ruff requirement from ~=0.11.4 to ~=0.11.7 + ([#1118](https://github.com/appium/python-client/pull/1118), + [`c3b86b8`](https://github.com/appium/python-client/commit/c3b86b8adb26c0155ec4b72ffc295f7fbe57fd00)) + +- **deps-dev**: Update ruff requirement from ~=0.11.7 to ~=0.11.8 + ([#1122](https://github.com/appium/python-client/pull/1122), + [`2680a28`](https://github.com/appium/python-client/commit/2680a28e16259089b370d747ef0d90fb8b043198)) + +- **deps-dev**: Update tox requirement from ~=4.24 to ~=4.25 + ([#1109](https://github.com/appium/python-client/pull/1109), + [`a46dd88`](https://github.com/appium/python-client/commit/a46dd88500e48ac89ac05db0f066560eedb38730)) + +### Continuous Integration + +- Tune CC title script + ([`c37352a`](https://github.com/appium/python-client/commit/c37352ad2753aa6005fa5e52e56683335551d039)) + +### Features + +- Add method for interacting with the Flutter integration driver + ([#1123](https://github.com/appium/python-client/pull/1123), + [`635e762`](https://github.com/appium/python-client/commit/635e762678dcfff721dab5e52da41e4609c1d114)) + +### Testing + +- Use timeout in client_config instead of the global var + ([#1120](https://github.com/appium/python-client/pull/1120), + [`727631d`](https://github.com/appium/python-client/commit/727631d33087beca86ccacc6b931e162fd5b8c49)) + + +## v5.0.0 (2025-03-24) + +### Chores + +- **deps-dev**: Update mock requirement from ~=5.1 to ~=5.2 + ([#1100](https://github.com/appium/python-client/pull/1100), + [`bbc1e91`](https://github.com/appium/python-client/commit/bbc1e91543986724f86a07ffa3a2218c38b8d0d8)) + +- **deps-dev**: Update pre-commit requirement from ~=4.1 to ~=4.2 + ([#1104](https://github.com/appium/python-client/pull/1104), + [`d2326b9`](https://github.com/appium/python-client/commit/d2326b9cc82a5be18feb191852061a5596393c70)) + +- **deps-dev**: Update ruff requirement from ~=0.9.10 to ~=0.10.0 + ([#1102](https://github.com/appium/python-client/pull/1102), + [`6707365`](https://github.com/appium/python-client/commit/670736582711df1a5303c794ff58aa7d7127d649)) + +- **deps-dev**: Update ruff requirement from ~=0.9.5 to ~=0.9.7 + ([#1097](https://github.com/appium/python-client/pull/1097), + [`74224e0`](https://github.com/appium/python-client/commit/74224e090e6ccbba51fa9fca4a7d097ea242ff4c)) + +- **deps-dev**: Update ruff requirement from ~=0.9.7 to ~=0.9.9 + ([#1099](https://github.com/appium/python-client/pull/1099), + [`5605d9b`](https://github.com/appium/python-client/commit/5605d9b4bc07554bd66c9d339aeee9bda010aa55)) + +- **deps-dev**: Update ruff requirement from ~=0.9.9 to ~=0.9.10 + ([#1101](https://github.com/appium/python-client/pull/1101), + [`4d8abfa`](https://github.com/appium/python-client/commit/4d8abfa041c67b0cd05f1ce7d7ea96572cb10a58)) + +### Features + +- Define AppiumClientConfig ([#1070](https://github.com/appium/python-client/pull/1070), + [`525d5b8`](https://github.com/appium/python-client/commit/525d5b8b5d8c9919470c4c5a191a6d5c1090027e)) + + +## v4.5.1 (2025-02-22) + +### Bug Fixes + +- Prevent warning log when initialize a webdriver using version 4.5.0 (selenium v4.26+) + ([#1098](https://github.com/appium/python-client/pull/1098), + [`68ceca7`](https://github.com/appium/python-client/commit/68ceca73ac83cef40ec90bdbb73305e384073983)) + +### Chores + +- **deps**: Bump selenium from 4.28.0 to 4.28.1 + ([#1088](https://github.com/appium/python-client/pull/1088), + [`a1ead29`](https://github.com/appium/python-client/commit/a1ead29fc1c0aa156f1144b8f24bddb42358770a)) + +- **deps**: Bump selenium from 4.28.1 to 4.29.0 + ([#1096](https://github.com/appium/python-client/pull/1096), + [`f53deb3`](https://github.com/appium/python-client/commit/f53deb3440a8b06a7f83726596eacc52eb1cfef4)) + +- **deps-dev**: Update pre-commit requirement from ~=3.5 to ~=4.1 + ([#1085](https://github.com/appium/python-client/pull/1085), + [`e5201fd`](https://github.com/appium/python-client/commit/e5201fdb3028df44c993f0375680f605702e8369)) + +- **deps-dev**: Update ruff requirement from ~=0.9.2 to ~=0.9.3 + ([#1089](https://github.com/appium/python-client/pull/1089), + [`f8a4f56`](https://github.com/appium/python-client/commit/f8a4f5693185d7f59156e55f13d80bc002b198a5)) + +- **deps-dev**: Update ruff requirement from ~=0.9.3 to ~=0.9.5 + ([#1092](https://github.com/appium/python-client/pull/1092), + [`82c40b5`](https://github.com/appium/python-client/commit/82c40b50577d4155c3215724babc3ca56b587ac2)) + +- **deps-dev**: Update tox requirement from ~=4.23 to ~=4.24 + ([#1086](https://github.com/appium/python-client/pull/1086), + [`121be97`](https://github.com/appium/python-client/commit/121be9769cd8bd631fd6423a341be9dfb7e1658c)) + +### Documentation + +- Update README.md + ([`733504e`](https://github.com/appium/python-client/commit/733504e8304ca6901363351ec29770fcf9719fe7)) + +### Testing + +- Pytest does not require test classes unless you need grouping or fixtures with class scope. + ([#1094](https://github.com/appium/python-client/pull/1094), + [`2218933`](https://github.com/appium/python-client/commit/22189335caccd89daffc3519bba8c90360be5fd1)) + +- Use pytest without class-based structures, using parameterization for better reusability. + ([#1095](https://github.com/appium/python-client/pull/1095), + [`c2732dd`](https://github.com/appium/python-client/commit/c2732ddc85b7362de3fc9e59d0c97b4e3bd02496)) + + +## v4.5.0 (2025-01-22) + +### Chores + +- Update tags + ([`aa486f3`](https://github.com/appium/python-client/commit/aa486f3bd287fe00185bebb254b5b9b6bc0440fb)) + +- **deps**: Bump selenium from 4.27.1 to 4.28.0 + ([#1084](https://github.com/appium/python-client/pull/1084), + [`b10a11e`](https://github.com/appium/python-client/commit/b10a11e051e5741db7c91bf05f390ce178a2e0bd)) + +- **deps-dev**: Update ruff requirement from ~=0.8.1 to ~=0.8.3 + ([#1074](https://github.com/appium/python-client/pull/1074), + [`2605001`](https://github.com/appium/python-client/commit/2605001d5c1952779d289038966577cb4d2298b4)) + +- **deps-dev**: Update ruff requirement from ~=0.8.3 to ~=0.8.4 + ([#1078](https://github.com/appium/python-client/pull/1078), + [`6d4c633`](https://github.com/appium/python-client/commit/6d4c633901a18c5797c1d84c1c06bf5652fc328b)) + +- **deps-dev**: Update ruff requirement from ~=0.8.4 to ~=0.8.5 + ([#1079](https://github.com/appium/python-client/pull/1079), + [`5db72cf`](https://github.com/appium/python-client/commit/5db72cfb12b5e3c07f3280ad7fb006ceb04ee5b2)) + +- **deps-dev**: Update ruff requirement from ~=0.8.5 to ~=0.8.6 + ([#1080](https://github.com/appium/python-client/pull/1080), + [`a1986d4`](https://github.com/appium/python-client/commit/a1986d4821d2878456eb2760be9487ee83c99c17)) + +- **deps-dev**: Update ruff requirement from ~=0.8.6 to ~=0.9.0 + ([#1081](https://github.com/appium/python-client/pull/1081), + [`4cdbed7`](https://github.com/appium/python-client/commit/4cdbed78c9d45f9b59c0cfabfbcb5acb91901de1)) + +- **deps-dev**: Update ruff requirement from ~=0.9.0 to ~=0.9.1 + ([#1082](https://github.com/appium/python-client/pull/1082), + [`8117add`](https://github.com/appium/python-client/commit/8117add172b4cfd0ad03c96d09873eb0162d649d)) + +- **deps-dev**: Update ruff requirement from ~=0.9.1 to ~=0.9.2 + ([#1083](https://github.com/appium/python-client/pull/1083), + [`0ea049a`](https://github.com/appium/python-client/commit/0ea049af1db4f4cd89ce169879e38a6be354ca90)) + + +## v4.4.0 (2024-11-29) + +### Bug Fixes + +- Adding selenium typing ([#1071](https://github.com/appium/python-client/pull/1071), + [`00e9a6e`](https://github.com/appium/python-client/commit/00e9a6e6e934ab9c9cc1e92aacb05b6bbefd08ff)) + +- Using single quotes ([#1071](https://github.com/appium/python-client/pull/1071), + [`00e9a6e`](https://github.com/appium/python-client/commit/00e9a6e6e934ab9c9cc1e92aacb05b6bbefd08ff)) + +### Chores + +- Dump ruff + ([`e4f06ab`](https://github.com/appium/python-client/commit/e4f06abf1f6bc302bde373071d1e3c007a67c03a)) + +- **deps**: Bump selenium from 4.26.1 to 4.27.0 + ([#1067](https://github.com/appium/python-client/pull/1067), + [`ea61c2e`](https://github.com/appium/python-client/commit/ea61c2e8f80c64365610321ef0e6f512280fdbc0)) + +- **deps**: Bump selenium from 4.27.0 to 4.27.1 + ([#1068](https://github.com/appium/python-client/pull/1068), + [`dd8ef74`](https://github.com/appium/python-client/commit/dd8ef742e850cb74fc0d2ed897e638278d696d42)) + +- **deps-dev**: Update ruff requirement from ~=0.7.3 to ~=0.7.4 + ([#1063](https://github.com/appium/python-client/pull/1063), + [`fef190e`](https://github.com/appium/python-client/commit/fef190ed8064c9e6fe717fb1bdfee5019edc28f3)) + +### Features + +- Added typing for AppiumBy ([#1071](https://github.com/appium/python-client/pull/1071), + [`00e9a6e`](https://github.com/appium/python-client/commit/00e9a6e6e934ab9c9cc1e92aacb05b6bbefd08ff)) + +- Added typing for AppiumBy types ([#1071](https://github.com/appium/python-client/pull/1071), + [`00e9a6e`](https://github.com/appium/python-client/commit/00e9a6e6e934ab9c9cc1e92aacb05b6bbefd08ff)) + + +## v4.3.0 (2024-11-12) + +### Chores + +- Update pre-commit ([#1058](https://github.com/appium/python-client/pull/1058), + [`cd1070a`](https://github.com/appium/python-client/commit/cd1070af807d7ff1c42e4d2270452560738e254d)) + +- **deps-dev**: Update ruff requirement from ~=0.7.0 to ~=0.7.2 + ([#1057](https://github.com/appium/python-client/pull/1057), + [`86f4d48`](https://github.com/appium/python-client/commit/86f4d4847d09e9a1077d3126ebad6e0faca2b3b0)) + +- **deps-dev**: Update ruff requirement from ~=0.7.2 to ~=0.7.3 + ([#1060](https://github.com/appium/python-client/pull/1060), + [`f26f763`](https://github.com/appium/python-client/commit/f26f763f138813781bb8d5382bf3c7c8ae61adf5)) + +### Documentation + +- Update CHANGELOG.rst + ([`6bd041a`](https://github.com/appium/python-client/commit/6bd041a8812bdf5a6a35a44ab4d207efab4a6854)) + +- Update the readme ([#1054](https://github.com/appium/python-client/pull/1054), + [`94a6da7`](https://github.com/appium/python-client/commit/94a6da755ef3e3af88b0fba6322a2e69dc123d37)) + +### Features + +- Require selenium 4.26+ ([#1054](https://github.com/appium/python-client/pull/1054), + [`94a6da7`](https://github.com/appium/python-client/commit/94a6da755ef3e3af88b0fba6322a2e69dc123d37)) + +- Support selenium 4.26+: support ClientConfig and refactoring internal implementation + ([#1054](https://github.com/appium/python-client/pull/1054), + [`94a6da7`](https://github.com/appium/python-client/commit/94a6da755ef3e3af88b0fba6322a2e69dc123d37)) + + +## v4.2.1 (2024-10-31) + + +## v4.1.1 (2024-10-31) + +### Chores + +- Allow selenium binging up to 4.25 ([#1055](https://github.com/appium/python-client/pull/1055), + [`a22306e`](https://github.com/appium/python-client/commit/a22306ea1eb035148d8c801ff2c3321f4c02708c)) + +- Revert unnecessary change ([#1046](https://github.com/appium/python-client/pull/1046), + [`27595c4`](https://github.com/appium/python-client/commit/27595c40cceb33219cecd28c14c0e8fbdb566a37)) + +- Update precommit config + ([`b8daf2c`](https://github.com/appium/python-client/commit/b8daf2c67cbcdbbc10a75b9a45f4a415a5057b95)) + +- Update release script + ([`7ac1fd9`](https://github.com/appium/python-client/commit/7ac1fd9bcdba2fa29bea8c2f746da30f5420920f)) + +- Use proper type declarations for methods returning self instances + ([#1039](https://github.com/appium/python-client/pull/1039), + [`be51520`](https://github.com/appium/python-client/commit/be51520d2e204a63035fc99eaa1f796db3fed615)) + +- Use ruff (isort, pylint and pyflakes) instead of individual isort, pylint and black libraries + ([#1043](https://github.com/appium/python-client/pull/1043), + [`8f2b059`](https://github.com/appium/python-client/commit/8f2b059586f9e73fb431043a655729f655719884)) + +- **deps**: Update selenium requirement from ~=4.24 to ~=4.25 + ([#1026](https://github.com/appium/python-client/pull/1026), + [`5778a50`](https://github.com/appium/python-client/commit/5778a502fb6203395bc1e5043ddb430342593493)) + +- **deps**: Update sphinx requirement from <7.0,>=4.0 to >=4.0,<9.0 + ([#1009](https://github.com/appium/python-client/pull/1009), + [`2dab159`](https://github.com/appium/python-client/commit/2dab159ef8cfd7d1b70ea382d4fd65246c7bc61e)) + +- **deps**: Update sphinx-rtd-theme requirement from <3.0 to <4.0 + ([#1040](https://github.com/appium/python-client/pull/1040), + [`fdbd03a`](https://github.com/appium/python-client/commit/fdbd03ab6a966601223c1d3dadbff21363c2e1d3)) + +- **deps-dev**: Update pytest-cov requirement from ~=4.1 to ~=5.0 + ([#975](https://github.com/appium/python-client/pull/975), + [`2c775ee`](https://github.com/appium/python-client/commit/2c775ee518c17b8a95d8ec1302d9fb1654498d12)) + +- **deps-dev**: Update ruff requirement from ~=0.6.9 to ~=0.7.0 + ([#1049](https://github.com/appium/python-client/pull/1049), + [`36786ef`](https://github.com/appium/python-client/commit/36786ef9c504e06f16212a5730e0d9274dca8fad)) + +- **deps-dev**: Update tox requirement from ~=4.20 to ~=4.21 + ([#1037](https://github.com/appium/python-client/pull/1037), + [`e4b40ae`](https://github.com/appium/python-client/commit/e4b40aefc573429d40d51b60ac03ca2961b3313e)) + +- **deps-dev**: Update tox requirement from ~=4.21 to ~=4.22 + ([#1047](https://github.com/appium/python-client/pull/1047), + [`0a403bc`](https://github.com/appium/python-client/commit/0a403bcd650ae3e759b55ef370618364f897ccfa)) + +- **deps-dev**: Update tox requirement from ~=4.22 to ~=4.23 + ([#1048](https://github.com/appium/python-client/pull/1048), + [`7ac6bb8`](https://github.com/appium/python-client/commit/7ac6bb833022b7dd6c753fd806904ab9f3e9fb79)) + +### Documentation + +- Add options matrix in readme ([#1046](https://github.com/appium/python-client/pull/1046), + [`27595c4`](https://github.com/appium/python-client/commit/27595c40cceb33219cecd28c14c0e8fbdb566a37)) + +- Add tweak pathds ([#1046](https://github.com/appium/python-client/pull/1046), + [`27595c4`](https://github.com/appium/python-client/commit/27595c40cceb33219cecd28c14c0e8fbdb566a37)) + +- Update selenium compatibility matrix + ([`f3632a6`](https://github.com/appium/python-client/commit/f3632a6a1f413dbabff1fd5b7c1f605b5b33fb8b)) + +### Features + +- Add a separate function for service startup validation + ([#1038](https://github.com/appium/python-client/pull/1038), + [`90b9978`](https://github.com/appium/python-client/commit/90b9978601e834518b19092b3d66f241d6c420a5)) + +### Testing + +- Cleanup duplicated tests more ([#1032](https://github.com/appium/python-client/pull/1032), + [`fea88d1`](https://github.com/appium/python-client/commit/fea88d1397d2721fa4da8a48a1a1a5cd6bbde6c7)) + +- Cleanup func tests for ios more ([#1036](https://github.com/appium/python-client/pull/1036), + [`2b48a09`](https://github.com/appium/python-client/commit/2b48a09a707e669b1d8caa9d48ca578ecc34f3e4)) + +- Cleanup functional tests and move to unit test to CI stable + ([#1024](https://github.com/appium/python-client/pull/1024), + [`9cdfe5c`](https://github.com/appium/python-client/commit/9cdfe5c7cb58c4cd9495a15658ed17a5681b79d6)) + +- Cleanup ios ([#1034](https://github.com/appium/python-client/pull/1034), + [`8773351`](https://github.com/appium/python-client/commit/877335152c0e0e705e36867d4449631d5385925a)) + +- Cleanup test more ([#1032](https://github.com/appium/python-client/pull/1032), + [`fea88d1`](https://github.com/appium/python-client/commit/fea88d1397d2721fa4da8a48a1a1a5cd6bbde6c7)) + +- Cleanup tests more ([#1033](https://github.com/appium/python-client/pull/1033), + [`9a3a633`](https://github.com/appium/python-client/commit/9a3a6337c375d3ece124df459e231fbfd0f2d8b1)) + +- Just remove existing ones ([#1032](https://github.com/appium/python-client/pull/1032), + [`fea88d1`](https://github.com/appium/python-client/commit/fea88d1397d2721fa4da8a48a1a1a5cd6bbde6c7)) + +- Remove some functional test which is tested in unit tets + ([#1033](https://github.com/appium/python-client/pull/1033), + [`9a3a633`](https://github.com/appium/python-client/commit/9a3a6337c375d3ece124df459e231fbfd0f2d8b1)) + +- Remvoe location tests ([#1033](https://github.com/appium/python-client/pull/1033), + [`9a3a633`](https://github.com/appium/python-client/commit/9a3a6337c375d3ece124df459e231fbfd0f2d8b1)) + + +## v4.2.0 (2024-09-23) + +### Bug Fixes + +- Add missing __init__.py ([#1029](https://github.com/appium/python-client/pull/1029), + [`25da847`](https://github.com/appium/python-client/commit/25da8476e2826bf8d495030a395080ddc83bc7a7)) + +### Chores + +- **deps**: Update selenium requirement from ~=4.23 to ~=4.24 + ([#1018](https://github.com/appium/python-client/pull/1018), + [`8d53160`](https://github.com/appium/python-client/commit/8d531601d2ed0d2abf1a0ed253214afe630a418f)) + +- **deps-dev**: Update black requirement from <24.0.0 to <25.0.0 + ([#950](https://github.com/appium/python-client/pull/950), + [`87ec961`](https://github.com/appium/python-client/commit/87ec96177e9a4bcec67099fbd3acb6d3e0a838fb)) + +- **deps-dev**: Update pylint requirement from ~=3.2.6 to ~=3.2.7 + ([#1019](https://github.com/appium/python-client/pull/1019), + [`d8c1260`](https://github.com/appium/python-client/commit/d8c126009be3916058b926f1ea38770486fe7a10)) + +- **deps-dev**: Update tox requirement from ~=4.18 to ~=4.19 + ([#1020](https://github.com/appium/python-client/pull/1020), + [`54a9ef1`](https://github.com/appium/python-client/commit/54a9ef17d349d7978b391825a9c0fe2a8ca266bf)) + +- **deps-dev**: Update tox requirement from ~=4.19 to ~=4.20 + ([#1021](https://github.com/appium/python-client/pull/1021), + [`bb8d509`](https://github.com/appium/python-client/commit/bb8d50920f6dc417f38f7ee5fd74a783e9558b72)) + +### Documentation + +- Modify readme + ([`d0ad068`](https://github.com/appium/python-client/commit/d0ad06893d3b1635eacfa06e50a74cdcf874d019)) + +### Features + +- Add flutter integration driver commands and tests + ([#1022](https://github.com/appium/python-client/pull/1022), + [`2ffa930`](https://github.com/appium/python-client/commit/2ffa930270b455131217c2d8373fd32096b2c95c)) + + +## v4.1.0 (2024-08-17) + +### Chores + +- Remove non-reference variables, import and fix test names to run them properly + ([#1006](https://github.com/appium/python-client/pull/1006), + [`e34ca80`](https://github.com/appium/python-client/commit/e34ca80812713d16806ab09af7f35f98e5b7a846)) + +- **deps**: Update selenium requirement from ~=4.22 to ~=4.23 + ([#1003](https://github.com/appium/python-client/pull/1003), + [`1c5321a`](https://github.com/appium/python-client/commit/1c5321abaf238ea752dc9a3581143328ce8b5b03)) + +- **deps-dev**: Update pylint requirement from ~=3.2.2 to ~=3.2.5 + ([#1000](https://github.com/appium/python-client/pull/1000), + [`d20db86`](https://github.com/appium/python-client/commit/d20db86741220b9d155bf16391f41260cc0d552b)) + +- **deps-dev**: Update pylint requirement from ~=3.2.5 to ~=3.2.6 + ([#1005](https://github.com/appium/python-client/pull/1005), + [`6d66d92`](https://github.com/appium/python-client/commit/6d66d92673956c3e077ecf6909b4662cc182dd72)) + +- **deps-dev**: Update pytest requirement from ~=8.2 to ~=8.3 + ([#1004](https://github.com/appium/python-client/pull/1004), + [`e75f8e9`](https://github.com/appium/python-client/commit/e75f8e9274a80a17f324b112c55698b0b298d53c)) + +- **deps-dev**: Update tox requirement from ~=4.15 to ~=4.16 + ([#1002](https://github.com/appium/python-client/pull/1002), + [`3f3f11a`](https://github.com/appium/python-client/commit/3f3f11aa5ab27a96e22fab10c74863b0380d2349)) + +- **deps-dev**: Update tox requirement from ~=4.16 to ~=4.18 + ([#1013](https://github.com/appium/python-client/pull/1013), + [`f7b0256`](https://github.com/appium/python-client/commit/f7b0256d7821eab0d302995765a6bde34931164a)) + +### Continuous Integration + +- Move Azure to GHA (Android) ([#1007](https://github.com/appium/python-client/pull/1007), + [`b148174`](https://github.com/appium/python-client/commit/b148174f14e014ac961f185d3bac715e5c8e32c3)) + +- Moving to GHA ([#1010](https://github.com/appium/python-client/pull/1010), + [`fb06ca1`](https://github.com/appium/python-client/commit/fb06ca12dbe4c1be936f0c0525a864ee932a5614)) + +- Run func_test_android4 ([#1010](https://github.com/appium/python-client/pull/1010), + [`fb06ca1`](https://github.com/appium/python-client/commit/fb06ca12dbe4c1be936f0c0525a864ee932a5614)) + +- Run other android tests on GHA ([#1008](https://github.com/appium/python-client/pull/1008), + [`0e13381`](https://github.com/appium/python-client/commit/0e13381c7c7b7b0f7a00d8a5145fd2b591a3763d)) + +- Run other android tests on GHA a few more + ([#1008](https://github.com/appium/python-client/pull/1008), + [`0e13381`](https://github.com/appium/python-client/commit/0e13381c7c7b7b0f7a00d8a5145fd2b591a3763d)) + +### Documentation + +- Replace badge source ([#1012](https://github.com/appium/python-client/pull/1012), + [`834c854`](https://github.com/appium/python-client/commit/834c8549b82ef0dd0d5a8307fe6635045b6c3ac0)) + +### Features + +- Add app_path property ("appPath") to Mac2Options + ([#1014](https://github.com/appium/python-client/pull/1014), + [`18c4723`](https://github.com/appium/python-client/commit/18c4723e7f7ebfca104bff92a720c667f1269223)) + +### Testing + +- Fix tests ([#1010](https://github.com/appium/python-client/pull/1010), + [`fb06ca1`](https://github.com/appium/python-client/commit/fb06ca12dbe4c1be936f0c0525a864ee932a5614)) + + +## v4.0.1 (2024-07-08) + +### Bug Fixes + +- Typo and update test ([#992](https://github.com/appium/python-client/pull/992), + [`a9af896`](https://github.com/appium/python-client/commit/a9af896bc08735e2927c8ace90be2e420b09ce5e)) + +### Chores + +- Add mobile: replacements to clipboard API wrappers + ([#998](https://github.com/appium/python-client/pull/998), + [`19d4f4b`](https://github.com/appium/python-client/commit/19d4f4b2ab02caed0dcbe781196698e279230d5b)) + +- Remove IOS_UIAUTOMATION ([#979](https://github.com/appium/python-client/pull/979), + [`9e63569`](https://github.com/appium/python-client/commit/9e63569b570d7a897264110a18c621c7a25f72ae)) + +- **deps**: Update selenium requirement from ~=4.18 to ~=4.19 + ([#976](https://github.com/appium/python-client/pull/976), + [`7bd1b06`](https://github.com/appium/python-client/commit/7bd1b0665028771d06036b2b31fe76d9d32490a4)) + +- **deps**: Update selenium requirement from ~=4.19 to ~=4.20 + ([#981](https://github.com/appium/python-client/pull/981), + [`cdc715b`](https://github.com/appium/python-client/commit/cdc715b686e41ab39c61e37448b934f32aa498af)) + +- **deps**: Update selenium requirement from ~=4.20 to ~=4.21 + ([#991](https://github.com/appium/python-client/pull/991), + [`850055d`](https://github.com/appium/python-client/commit/850055db9b5a44f30b0821f73672b19611173a27)) + +- **deps**: Update selenium requirement from ~=4.21 to ~=4.22 + ([#996](https://github.com/appium/python-client/pull/996), + [`6e06805`](https://github.com/appium/python-client/commit/6e06805dc80f382a54442fa5a30de4ce4d3388c2)) + +- **deps**: Update sphinx-rtd-theme requirement from <2.0 to <3.0 + ([#935](https://github.com/appium/python-client/pull/935), + [`81a50e3`](https://github.com/appium/python-client/commit/81a50e344d26e4124e8019d0736f6240ac46267b)) + +- **deps-dev**: Update pylint requirement from ~=3.1.0 to ~=3.2.2 + ([#993](https://github.com/appium/python-client/pull/993), + [`fa7e6d4`](https://github.com/appium/python-client/commit/fa7e6d44e13ea586bcbe73a1ba4464b97516ff51)) + +- **deps-dev**: Update pytest requirement from ~=8.1 to ~=8.2 + ([#983](https://github.com/appium/python-client/pull/983), + [`9c142b8`](https://github.com/appium/python-client/commit/9c142b8916269e420e5feb11b869feabf3eb583b)) + +- **deps-dev**: Update tox requirement from ~=4.14 to ~=4.15 + ([#982](https://github.com/appium/python-client/pull/982), + [`7551deb`](https://github.com/appium/python-client/commit/7551deb2c2bd4331385f8a6fb7dd60762d113865)) + +- **deps-dev**: Update types-python-dateutil requirement + ([#973](https://github.com/appium/python-client/pull/973), + [`1871e4a`](https://github.com/appium/python-client/commit/1871e4af09dd54e66f4483d0951d1df09b60faa0)) + +### Continuous Integration + +- Add initial gha to run by manual ([#984](https://github.com/appium/python-client/pull/984), + [`328c8d3`](https://github.com/appium/python-client/commit/328c8d3d941352503d9ff69baa9dddea40eddfe4)) + +- Bump conventional-pr-action to v3 ([#989](https://github.com/appium/python-client/pull/989), + [`f256501`](https://github.com/appium/python-client/commit/f2565016b4a6f4a5fe5381d843960f46a71a1b02)) + +- Enable trigger + ([`f6e2b53`](https://github.com/appium/python-client/commit/f6e2b5335af8aef0e07c1d444fc85a0d7be6481d)) + +- Move the file + ([`85e921c`](https://github.com/appium/python-client/commit/85e921c8a1149d27f5136f723140f9770ee692dd)) + +- Use gha instead of Azure for iOS in Azure + ([#987](https://github.com/appium/python-client/pull/987), + [`5442e60`](https://github.com/appium/python-client/commit/5442e60b6c219cfb539d73c3d2277148b9f8311c)) + +### Documentation + +- Fix typo ([#992](https://github.com/appium/python-client/pull/992), + [`a9af896`](https://github.com/appium/python-client/commit/a9af896bc08735e2927c8ace90be2e420b09ce5e)) + +- Missing appium python client version in the compatibility matrix + ([`91aa2a1`](https://github.com/appium/python-client/commit/91aa2a11de3d4d9a7f36e062a932d7aba8d77ba1)) + +- Update docstring ([#986](https://github.com/appium/python-client/pull/986), + [`67a561d`](https://github.com/appium/python-client/commit/67a561d40b814b68b76381731a4da99805d79b3f)) + +### Testing + +- Fix one test ([#992](https://github.com/appium/python-client/pull/992), + [`a9af896`](https://github.com/appium/python-client/commit/a9af896bc08735e2927c8ace90be2e420b09ce5e)) + + +## v4.0.0 (2024-03-11) + +### Chores + +- Remove deprecated AppiumBy.WINDOWS_UI_AUTOMATION + ([#968](https://github.com/appium/python-client/pull/968), + [`706f3f5`](https://github.com/appium/python-client/commit/706f3f5e91b666f91f197e9149d959d6126b8b44)) + +- **deps-dev**: Update pylint requirement from ~=3.0.3 to ~=3.1.0 + ([#966](https://github.com/appium/python-client/pull/966), + [`3330b9a`](https://github.com/appium/python-client/commit/3330b9ae75f67b8c1b572f837d7f3f1e2cfe7a82)) + +- **deps-dev**: Update pytest requirement from ~=8.0 to ~=8.1 + ([#969](https://github.com/appium/python-client/pull/969), + [`9136957`](https://github.com/appium/python-client/commit/9136957c42190da413aa8ebf5173cbfe9b5fb39b)) + +- **deps-dev**: Update python-dateutil requirement from ~=2.8 to ~=2.9 + ([#967](https://github.com/appium/python-client/pull/967), + [`08d7fbb`](https://github.com/appium/python-client/commit/08d7fbb4c0346744d34c383ec849fcbcfedb0c09)) + +- **deps-dev**: Update tox requirement from ~=4.12 to ~=4.13 + ([#957](https://github.com/appium/python-client/pull/957), + [`12200e7`](https://github.com/appium/python-client/commit/12200e7adf18cfe145a735de7f083974a19d902f)) + +- **deps-dev**: Update tox requirement from ~=4.13 to ~=4.14 + ([#972](https://github.com/appium/python-client/pull/972), + [`6492c27`](https://github.com/appium/python-client/commit/6492c27339b661b4fcd518a92c1c45d288d9de88)) + +### Documentation + +- Update readme + ([`aca3593`](https://github.com/appium/python-client/commit/aca359309c6e16c0848ca27489458035e72f0c4a)) + +### Features + +- Remove MultiAction and TouchAction ([#960](https://github.com/appium/python-client/pull/960), + [`4d8db65`](https://github.com/appium/python-client/commit/4d8db65bfb672180a9bd0a52a3254ddd1f4c5eb0)) + +### Breaking Changes + +- Remove MultiAction and TouchAction as non-w3c WebDriver-defined methods. Please use w3c actions + instead. + + +## v3.2.1 (2024-02-25) + +### Bug Fixes + +- Unclosed file <_io.BufferedReader name error by proper cleanup of subprocess.Popen process + ([#965](https://github.com/appium/python-client/pull/965), + [`ac9965d`](https://github.com/appium/python-client/commit/ac9965da3839d4709625d2912abc577f52bc2dc1)) + + +## v3.2.0 (2024-02-23) + +### Bug Fixes + +- Add return self in MultiAction#add ([#964](https://github.com/appium/python-client/pull/964), + [`2e0ff4e`](https://github.com/appium/python-client/commit/2e0ff4e043eb8efd114d0f9f1f9f5c99a7d08d96)) + +### Chores + +- **deps**: Update selenium requirement from ~=4.15 to ~=4.17 + ([#948](https://github.com/appium/python-client/pull/948), + [`bdac0b8`](https://github.com/appium/python-client/commit/bdac0b89b51d70ffea12df15adaec86ba4a986a2)) + +- **deps**: Update selenium requirement from ~=4.17 to ~=4.18 + ([#958](https://github.com/appium/python-client/pull/958), + [`1c6dcdf`](https://github.com/appium/python-client/commit/1c6dcdf642aaaa46facc6174d80a339fa49684f4)) + +- **deps-dev**: Update pytest requirement from ~=7.4 to ~=8.0 + ([#953](https://github.com/appium/python-client/pull/953), + [`92583ce`](https://github.com/appium/python-client/commit/92583ce39003b740bb5e57bbf2114d283d884d22)) + +- **deps-dev**: Update tox requirement from ~=4.11 to ~=4.12 + ([#947](https://github.com/appium/python-client/pull/947), + [`5be0ea0`](https://github.com/appium/python-client/commit/5be0ea08ef291cff4651b23fb820812562e8cf0d)) + +### Documentation + +- Tweak docstring ([#961](https://github.com/appium/python-client/pull/961), + [`686d486`](https://github.com/appium/python-client/commit/686d4864185b86bc61038099be116ec68fe3c0c9)) + +- Update example in readme ([#945](https://github.com/appium/python-client/pull/945), + [`e2d238e`](https://github.com/appium/python-client/commit/e2d238e10a526ab041e9fed428d996e14adde1ce)) + +- Update links ([#944](https://github.com/appium/python-client/pull/944), + [`39a89c8`](https://github.com/appium/python-client/commit/39a89c86357d00ee12db2af74ea3906c118fdec0)) + +- Update W3C actions example in readme ([#946](https://github.com/appium/python-client/pull/946), + [`ea9e09e`](https://github.com/appium/python-client/commit/ea9e09e45c0650a39b7861b15ece85f8a77fdbc9)) + +### Features + +- Add pause in drag_and_drop ([#961](https://github.com/appium/python-client/pull/961), + [`686d486`](https://github.com/appium/python-client/commit/686d4864185b86bc61038099be116ec68fe3c0c9)) + + +## v3.1.1 (2023-12-14) + +### Bug Fixes + +- Self.command_executor instance in _update_command_executor + ([#940](https://github.com/appium/python-client/pull/940), + [`17639ea`](https://github.com/appium/python-client/commit/17639ea682c06fe5ea23fb5999dcf009b7baa36c)) + +- Typo in ActionHelpers ([#937](https://github.com/appium/python-client/pull/937), + [`63770e8`](https://github.com/appium/python-client/commit/63770e8cba8c1d9d4bb3324b621bc96b037d242f)) + +### Chores + +- **deps**: Update selenium requirement from ~=4.14 to ~=4.15 + ([#933](https://github.com/appium/python-client/pull/933), + [`876233e`](https://github.com/appium/python-client/commit/876233e115ef68839f614e89f3dd7bd523222d36)) + +- **deps-dev**: Update pylint requirement from ~=3.0.1 to ~=3.0.3 + ([#939](https://github.com/appium/python-client/pull/939), + [`69ca059`](https://github.com/appium/python-client/commit/69ca0595727043645d5c0d9488e2b51e77784075)) + +### Documentation + +- Address options in the migration guide ([#929](https://github.com/appium/python-client/pull/929), + [`1e281bf`](https://github.com/appium/python-client/commit/1e281bf085138ee85187770c263ffd91e5a83e58)) + +- Adress options in the migration guide ([#929](https://github.com/appium/python-client/pull/929), + [`1e281bf`](https://github.com/appium/python-client/commit/1e281bf085138ee85187770c263ffd91e5a83e58)) + +- Update changelog + ([`1a81153`](https://github.com/appium/python-client/commit/1a811534c92427885dfc1954deef4c2976d1c5b3)) + + +## v3.1.0 (2023-10-13) + +### Chores + +- **deps**: Update selenium requirement from ~=4.12 to ~=4.13 + ([#915](https://github.com/appium/python-client/pull/915), + [`894380b`](https://github.com/appium/python-client/commit/894380b697bef35f98510b41a8ddafb2a3d21aa8)) + +- **deps**: Update selenium requirement from ~=4.13 to ~=4.14 + ([#923](https://github.com/appium/python-client/pull/923), + [`6f1cf34`](https://github.com/appium/python-client/commit/6f1cf34aa61551aaf37eb68a534ce4f8aca6a683)) + +- **deps-dev**: Update pylint requirement from ~=2.17.5 to ~=3.0.1 + ([#922](https://github.com/appium/python-client/pull/922), + [`3d7324e`](https://github.com/appium/python-client/commit/3d7324e4aeae731e5eb01d3881f246a5bb753798)) + +### Continuous Integration + +- Use appium from the release branch + ([`8d58eb7`](https://github.com/appium/python-client/commit/8d58eb7e31331ea473d209c5bc42346fd7b8fe3d)) + +### Documentation + +- Update README.md ([#912](https://github.com/appium/python-client/pull/912), + [`fa7ba6e`](https://github.com/appium/python-client/commit/fa7ba6ee5ee91c914f69e34547993af62995462f)) + +- Update README.md for v3 ([#912](https://github.com/appium/python-client/pull/912), + [`fa7ba6e`](https://github.com/appium/python-client/commit/fa7ba6ee5ee91c914f69e34547993af62995462f)) + +### Features + +- Add missing platformVersion and browserName options + ([#925](https://github.com/appium/python-client/pull/925), + [`d93a6ca`](https://github.com/appium/python-client/commit/d93a6caadb071598454fb7af0569576258ac4093)) + + +## v3.0.0 (2023-09-08) + +### Bug Fixes + +- Add missing dependencies for types-python-dateutil + ([#891](https://github.com/appium/python-client/pull/891), + [`78bbb73`](https://github.com/appium/python-client/commit/78bbb73fdea80eac98468096d8e187f2def8f866)) + +- Handle the situation where payload is already a dictionary + ([#892](https://github.com/appium/python-client/pull/892), + [`9edf6eb`](https://github.com/appium/python-client/commit/9edf6ebfff75d4b2d84b67e6601bed764613aa8e)) + +### Chores + +- Run pre-commit autoupdate ([#890](https://github.com/appium/python-client/pull/890), + [`0cf35fc`](https://github.com/appium/python-client/commit/0cf35fc2be341beae51e5ec14407ca73f16eb29e)) + +- Update isort revision to 5.12.0 ([#889](https://github.com/appium/python-client/pull/889), + [`2853ac0`](https://github.com/appium/python-client/commit/2853ac0b8814cea4a6192c69b56b508a667042c8)) + +- **deps**: Update selenium requirement from ~=4.10 to ~=4.11 + ([#899](https://github.com/appium/python-client/pull/899), + [`2223f11`](https://github.com/appium/python-client/commit/2223f11b213162b21984fbece871a210fea48e39)) + +- **deps-dev**: Update mock requirement from ~=5.0 to ~=5.1 + ([#893](https://github.com/appium/python-client/pull/893), + [`5f11530`](https://github.com/appium/python-client/commit/5f11530f93306a3c4c669fce327b2aef30c5e58c)) + +- **deps-dev**: Update pylint requirement from ~=2.17.3 to ~=2.17.5 + ([#897](https://github.com/appium/python-client/pull/897), + [`60b8ed5`](https://github.com/appium/python-client/commit/60b8ed5f9e50d056171f45994d811f6970a3f7d9)) + +- **deps-dev**: Update pytest requirement from ~=7.2 to ~=7.4 + ([#884](https://github.com/appium/python-client/pull/884), + [`fb8415e`](https://github.com/appium/python-client/commit/fb8415edf11e5f7302e24df5c3354c0c69fe8776)) + +- **deps-dev**: Update tox requirement from ~=4.6 to ~=4.8 + ([#902](https://github.com/appium/python-client/pull/902), + [`d5b84b8`](https://github.com/appium/python-client/commit/d5b84b899e4abad6afd914d0e5342476cb955de2)) + +- **deps-dev**: Update tox requirement from ~=4.8 to ~=4.11 + ([#906](https://github.com/appium/python-client/pull/906), + [`e344b7a`](https://github.com/appium/python-client/commit/e344b7a27a55dceebcfda22842efa6dfe965e39b)) + +- **deps-dev**: Update typing-extensions requirement + ([#885](https://github.com/appium/python-client/pull/885), + [`43ad4db`](https://github.com/appium/python-client/commit/43ad4db272b8115e752177a8336a05dc3943e79e)) + +### Continuous Integration + +- Add pylint_quotes for pylint to use single quote as primary method + ([#886](https://github.com/appium/python-client/pull/886), + [`b142e00`](https://github.com/appium/python-client/commit/b142e00e3f47065752c80f71f2f8cb80bf2500f7)) + +### Documentation + +- Update changelogs and version + ([`6496619`](https://github.com/appium/python-client/commit/64966198b542cabd7bdb4d0dd6bdb1a4f8f0bf08)) + +- Update README.md ([#898](https://github.com/appium/python-client/pull/898), + [`a1792ff`](https://github.com/appium/python-client/commit/a1792ffa51f472dd631c406dcf2f92fe78ae47e5)) + +### Features + +- Update selenium dependency to 4.12 ([#908](https://github.com/appium/python-client/pull/908), + [`2e49569`](https://github.com/appium/python-client/commit/2e49569ed45751df4c6953466f9769336698c033)) + +### Refactoring + +- Remove several previously deprecated APIs + ([#909](https://github.com/appium/python-client/pull/909), + [`264f202`](https://github.com/appium/python-client/commit/264f202ca5cd5cbcb1a139ef5cc29095d12e2cce)) + +### Testing + +- Fix broken TestContextSwitching by replacing selendroid with ApiDemos + ([#895](https://github.com/appium/python-client/pull/895), + [`06fe1b5`](https://github.com/appium/python-client/commit/06fe1b5e558059c3608df9dcf3f66420e60952ee)) + +- Remove selendroid-test-app.apk from apps folder + ([#895](https://github.com/appium/python-client/pull/895), + [`06fe1b5`](https://github.com/appium/python-client/commit/06fe1b5e558059c3608df9dcf3f66420e60952ee)) + +- Remove unused import pytest from applications_tests.py + ([#895](https://github.com/appium/python-client/pull/895), + [`06fe1b5`](https://github.com/appium/python-client/commit/06fe1b5e558059c3608df9dcf3f66420e60952ee)) + +- Replace usage of selendroid app from 'test_install_app' in applications_tests.py + ([#895](https://github.com/appium/python-client/pull/895), + [`06fe1b5`](https://github.com/appium/python-client/commit/06fe1b5e558059c3608df9dcf3f66420e60952ee)) + +- Replace usage of selendroid app from 'test_install_app' in applications_tests.py + ([#891](https://github.com/appium/python-client/pull/891), + [`78bbb73`](https://github.com/appium/python-client/commit/78bbb73fdea80eac98468096d8e187f2def8f866)) + +- Selendroid cleanup ([#895](https://github.com/appium/python-client/pull/895), + [`06fe1b5`](https://github.com/appium/python-client/commit/06fe1b5e558059c3608df9dcf3f66420e60952ee)) + +### Breaking Changes + +- Removed obsolete all_sessions and session properties BREAKING CHANGE: Removed the obsolete + start_activity method BREAKING CHANGE: Removed the obsolete end_test_coverage method BREAKING + CHANGE: Removed the following obsolete arguments from the driver constructor: + desired_capabilities, browser_profile, proxy BREAKING CHANGE: Removed obsolete set_value and + set_text methods BREAKING CHANGE: Removed the obsolete MobileBy class BREAKING CHANGE: Removed + obsolete application management methods: launch_app, close_app, reset BREAKING CHANGE: Removed + obsolete IME methods: available_ime_engines, is_ime_active, activate_ime_engine, + deactivate_ime_engine, active_ime_engine + +- The minimum supported Python version set to 3.8 BREAKING CHANGE: The minimum supported selenium + version set to 4.12 + + +## v2.11.1 (2023-06-13) + +### Chores + +- Left a comment + ([`54a082e`](https://github.com/appium/python-client/commit/54a082e3fd2b20cb505a9464d51c6be91c16a926)) + + +## v2.11.0 (2023-06-09) + +### Chores + +- Set version with / ([#793](https://github.com/appium/python-client/pull/793), + [`f304f65`](https://github.com/appium/python-client/commit/f304f6509796580111240770a5f310fa6536f11c)) + +- Update comment ([#793](https://github.com/appium/python-client/pull/793), + [`f304f65`](https://github.com/appium/python-client/commit/f304f6509796580111240770a5f310fa6536f11c)) + +### Features + +- Make the UA format with same as other clients + ([#793](https://github.com/appium/python-client/pull/793), + [`f304f65`](https://github.com/appium/python-client/commit/f304f6509796580111240770a5f310fa6536f11c)) + + +## v2.10.2 (2023-06-08) + +### Bug Fixes + +- Update the constructor for compatibility with python client 4.10 + ([#879](https://github.com/appium/python-client/pull/879), + [`c0f38bf`](https://github.com/appium/python-client/commit/c0f38bf293fbae141bed8a9c49643a7b8b75efed)) + +### Chores + +- Nump the version + ([`8bb7b4c`](https://github.com/appium/python-client/commit/8bb7b4ccac8f54d2922e90ace30108ef7dd70057)) + +- Remove duplicated clean command ([#809](https://github.com/appium/python-client/pull/809), + [`2f45ef9`](https://github.com/appium/python-client/commit/2f45ef935c12dec2ab8de044ce6a1c1e0b9aa46f)) + +- Set the max selenium deps version ([#874](https://github.com/appium/python-client/pull/874), + [`2e7a6a3`](https://github.com/appium/python-client/commit/2e7a6a3e80852883d30d3d5e3859a5fdd1e29eb6)) + +- **deps-dev**: Update pytest-cov requirement from ~=4.0 to ~=4.1 + ([#872](https://github.com/appium/python-client/pull/872), + [`74f39ed`](https://github.com/appium/python-client/commit/74f39eda8129a45a9798b948733d726b76237973)) + +- **deps-dev**: Update tox requirement from ~=4.5 to ~=4.6 + ([#877](https://github.com/appium/python-client/pull/877), + [`a4e4118`](https://github.com/appium/python-client/commit/a4e411848f7e46af4d0484925dbbc55061aee5f7)) + +- **deps-dev**: Update typing-extensions requirement + ([#871](https://github.com/appium/python-client/pull/871), + [`1e4c574`](https://github.com/appium/python-client/commit/1e4c574718bdbbb00fb6c81b7499f1a746294ab3)) + +### Continuous Integration + +- Add py11 for the unit test ([#875](https://github.com/appium/python-client/pull/875), + [`5a4b6d0`](https://github.com/appium/python-client/commit/5a4b6d0729601b3fdb821e93ebe24bf2d248c65b)) + +- Add python 11 ([#874](https://github.com/appium/python-client/pull/874), + [`2e7a6a3`](https://github.com/appium/python-client/commit/2e7a6a3e80852883d30d3d5e3859a5fdd1e29eb6)) + +### Documentation + +- Address version management recommendation in the readme + ([#874](https://github.com/appium/python-client/pull/874), + [`2e7a6a3`](https://github.com/appium/python-client/commit/2e7a6a3e80852883d30d3d5e3859a5fdd1e29eb6)) + +- Improve usage examples ([#873](https://github.com/appium/python-client/pull/873), + [`1f6dec3`](https://github.com/appium/python-client/commit/1f6dec384e7c911a134662ee2393221d0af298b9)) + +- Merge the matrix pr into README.md ([#874](https://github.com/appium/python-client/pull/874), + [`2e7a6a3`](https://github.com/appium/python-client/commit/2e7a6a3e80852883d30d3d5e3859a5fdd1e29eb6)) + + +## v2.10.1 (2023-05-20) + +### Bug Fixes + +- W3C errors to exception classes mapping ([#869](https://github.com/appium/python-client/pull/869), + [`5c20a35`](https://github.com/appium/python-client/commit/5c20a358ae94c996ea3ddd4964ad828005b17801)) + + +## v2.10.0 (2023-05-11) + +### Bug Fixes + +- Update connection manager creation ([#864](https://github.com/appium/python-client/pull/864), + [`2dbce79`](https://github.com/appium/python-client/commit/2dbce790fe6b87ff489a3dcf1d4872f9e2873595)) + +### Chores + +- Bump and correct version + ([`49d38dd`](https://github.com/appium/python-client/commit/49d38ddb18fc7341bb901a6642f15823a7bc80b6)) + +- **deps**: Update selenium requirement from ~=4.7 to ~=4.9 + ([#852](https://github.com/appium/python-client/pull/852), + [`0cfa3ef`](https://github.com/appium/python-client/commit/0cfa3ef79ae93cb917ff76d446b57cefbec5ed8f)) + +- **deps-dev**: Update mypy requirement from ~=1.1 to ~=1.2 + ([#848](https://github.com/appium/python-client/pull/848), + [`bb76339`](https://github.com/appium/python-client/commit/bb76339bc6b9bc3ae8eab7de1c416a1ff906317e)) + +- **deps-dev**: Update pylint requirement from ~=2.17.1 to ~=2.17.2 + ([#847](https://github.com/appium/python-client/pull/847), + [`37e357b`](https://github.com/appium/python-client/commit/37e357b1371f0e76ddbe3d0954d3315df19c15d1)) + +- **deps-dev**: Update pylint requirement from ~=2.17.2 to ~=2.17.3 + ([#853](https://github.com/appium/python-client/pull/853), + [`4031de2`](https://github.com/appium/python-client/commit/4031de2aad7918da0e3b083fc2be5a37865e4d79)) + +- **deps-dev**: Update tox requirement from ~=4.4 to ~=4.5 + ([#854](https://github.com/appium/python-client/pull/854), + [`790ffed`](https://github.com/appium/python-client/commit/790ffedc4440db92666fb1a5b17193e7b5b88343)) + +### Refactoring + +- Move driver-specific commands to use extensions (part1) + ([#856](https://github.com/appium/python-client/pull/856), + [`622f3df`](https://github.com/appium/python-client/commit/622f3df7f3871e7f3442af29ff274d855b10bb49)) + +- Move driver-specific commands to use extensions (part2) + ([#859](https://github.com/appium/python-client/pull/859), + [`d988f3c`](https://github.com/appium/python-client/commit/d988f3c51c03f61cca39289450c009aafb0fe30a)) + + +## v2.9.0 (2023-04-01) + +### Bug Fixes + +- Set_value and set_text sent incorrect data + ([#831](https://github.com/appium/python-client/pull/831), + [`91dc04b`](https://github.com/appium/python-client/commit/91dc04bd4313227b860158cd0d72d45723bcc664)) + +### Chores + +- **deps-dev**: Update mypy requirement from ~=0.991 to ~=1.0 + ([#828](https://github.com/appium/python-client/pull/828), + [`2e19f0d`](https://github.com/appium/python-client/commit/2e19f0d8139c2ab265346f033b809cac4b49d118)) + +- **deps-dev**: Update mypy requirement from ~=1.0 to ~=1.1 + ([#836](https://github.com/appium/python-client/pull/836), + [`8c845c1`](https://github.com/appium/python-client/commit/8c845c1a33c9ed6045e7f60884608ba1f7430817)) + +- **deps-dev**: Update pylint requirement from ~=2.15.10 to ~=2.16.0 + ([#826](https://github.com/appium/python-client/pull/826), + [`6acf1f0`](https://github.com/appium/python-client/commit/6acf1f0577940c3cdf216d27ba1cedf122abee60)) + +- **deps-dev**: Update pylint requirement from ~=2.16.0 to ~=2.16.1 + ([#827](https://github.com/appium/python-client/pull/827), + [`cb7d8c5`](https://github.com/appium/python-client/commit/cb7d8c508a23e5a57e70cfd6d942255c9109ef65)) + +- **deps-dev**: Update pylint requirement from ~=2.16.1 to ~=2.16.2 + ([#829](https://github.com/appium/python-client/pull/829), + [`0cb646d`](https://github.com/appium/python-client/commit/0cb646d28053afa82b16a3daea0a408498893de8)) + +- **deps-dev**: Update pylint requirement from ~=2.16.2 to ~=2.16.3 + ([#834](https://github.com/appium/python-client/pull/834), + [`11beb71`](https://github.com/appium/python-client/commit/11beb71f7b9d9ae4b96abac62a8ef901165bff06)) + +- **deps-dev**: Update pylint requirement from ~=2.16.3 to ~=2.17.0 + ([#838](https://github.com/appium/python-client/pull/838), + [`cbcc539`](https://github.com/appium/python-client/commit/cbcc539827658c7aaa16147f8da7907405c59031)) + +- **deps-dev**: Update pylint requirement from ~=2.17.0 to ~=2.17.1 + ([#843](https://github.com/appium/python-client/pull/843), + [`6d558c0`](https://github.com/appium/python-client/commit/6d558c0411e3e46d06f03c7fe72337e72699e599)) + +- **deps-dev**: Update tox requirement from ~=4.3 to ~=4.4 + ([#823](https://github.com/appium/python-client/pull/823), + [`ec81af5`](https://github.com/appium/python-client/commit/ec81af5cec22ea1f9b390b8147d95895040789bb)) + +- **deps-dev**: Update typing-extensions requirement + ([#830](https://github.com/appium/python-client/pull/830), + [`c2a80fa`](https://github.com/appium/python-client/commit/c2a80fa716d3ff12b850019dd6638bfde909408f)) + +### Features + +- Can provide a custom connection ([#844](https://github.com/appium/python-client/pull/844), + [`2c92c04`](https://github.com/appium/python-client/commit/2c92c04b3d470ec00ce96d2696483ae02f4df0d8)) + +- Respect the given executor ([#844](https://github.com/appium/python-client/pull/844), + [`2c92c04`](https://github.com/appium/python-client/commit/2c92c04b3d470ec00ce96d2696483ae02f4df0d8)) + + +## v2.8.1 (2023-01-20) + +### Chores + +- Update docstring in touch_action.py ([#797](https://github.com/appium/python-client/pull/797), + [`c8cb24a`](https://github.com/appium/python-client/commit/c8cb24a1a7c7e60821ef25462110283b4bc0408e)) + +- Update precommit ([#787](https://github.com/appium/python-client/pull/787), + [`c78e240`](https://github.com/appium/python-client/commit/c78e2406b07ffefceff35ed3ffd52e89ef521dfd)) + +- **deps**: Update selenium requirement from ~=4.5 to ~=4.7 + ([#801](https://github.com/appium/python-client/pull/801), + [`ab13d72`](https://github.com/appium/python-client/commit/ab13d7265d2956995806f73368e242170395d2b3)) + +- **deps**: Update sphinx requirement from <6.0,>=4.0 to >=4.0,<7.0 + ([#814](https://github.com/appium/python-client/pull/814), + [`8b96d05`](https://github.com/appium/python-client/commit/8b96d054f2474f1a2349f144cd3f30d8613962b3)) + +- **deps-dev**: Update black requirement from ~=22.10.0 to ~=22.12.0 + ([#807](https://github.com/appium/python-client/pull/807), + [`8c51dc3`](https://github.com/appium/python-client/commit/8c51dc3d06f6ffdfe6f556176012998fe8db524f)) + +- **deps-dev**: Update isort requirement from ~=5.10 to ~=5.11 + ([#808](https://github.com/appium/python-client/pull/808), + [`8d8fb02`](https://github.com/appium/python-client/commit/8d8fb02bdb081f06cd51b8c39b74971c1ab81a55)) + +- **deps-dev**: Update mock requirement from ~=4.0 to ~=5.0 + ([#812](https://github.com/appium/python-client/pull/812), + [`3c59823`](https://github.com/appium/python-client/commit/3c59823e94b5c19e60b00addc3454868897ac1df)) + +- **deps-dev**: Update mypy requirement from ~=0.982 to ~=0.991 + ([#798](https://github.com/appium/python-client/pull/798), + [`47db483`](https://github.com/appium/python-client/commit/47db48349d7b90bc18f0df1b926e24287ccb5a06)) + +- **deps-dev**: Update pre-commit requirement from ~=2.20 to ~=2.21 + ([#811](https://github.com/appium/python-client/pull/811), + [`55ac01f`](https://github.com/appium/python-client/commit/55ac01faaff90dd14a87b94193fb30bb8511f124)) + +- **deps-dev**: Update pylint requirement from ~=2.15.3 to ~=2.15.4 + ([#788](https://github.com/appium/python-client/pull/788), + [`a41b2fc`](https://github.com/appium/python-client/commit/a41b2fc6c42a6f6318a08b0a7c19f0785cff41d4)) + +- **deps-dev**: Update pylint requirement from ~=2.15.4 to ~=2.15.5 + ([#790](https://github.com/appium/python-client/pull/790), + [`6c27689`](https://github.com/appium/python-client/commit/6c2768931fc11a17dbed9f2b635ba4628c3426cc)) + +- **deps-dev**: Update pylint requirement from ~=2.15.5 to ~=2.15.6 + ([#799](https://github.com/appium/python-client/pull/799), + [`63464f8`](https://github.com/appium/python-client/commit/63464f8a1c1e85afa2b03897e745f1c17d2fcb6c)) + +- **deps-dev**: Update pylint requirement from ~=2.15.6 to ~=2.15.7 + ([#800](https://github.com/appium/python-client/pull/800), + [`36c602c`](https://github.com/appium/python-client/commit/36c602c4efc8385ae0cbf916cfa4e8e50b7868c9)) + +- **deps-dev**: Update pylint requirement from ~=2.15.7 to ~=2.15.8 + ([#804](https://github.com/appium/python-client/pull/804), + [`3903e29`](https://github.com/appium/python-client/commit/3903e29d73cc6bd69fc9bf353a6c32714ec5ab97)) + +- **deps-dev**: Update pylint requirement from ~=2.15.8 to ~=2.15.9 + ([#810](https://github.com/appium/python-client/pull/810), + [`644aa72`](https://github.com/appium/python-client/commit/644aa724b7939aae01bdcd055b0541bf879bde2b)) + +- **deps-dev**: Update pylint requirement from ~=2.15.9 to ~=2.15.10 + ([#816](https://github.com/appium/python-client/pull/816), + [`01d96fd`](https://github.com/appium/python-client/commit/01d96fd8a4645c1ba0df89a8bdd372693f5c98b0)) + +- **deps-dev**: Update pytest requirement from ~=7.1 to ~=7.2 + ([#791](https://github.com/appium/python-client/pull/791), + [`d5f7a25`](https://github.com/appium/python-client/commit/d5f7a2571f3bed15ad26edb5d1fd907c4508f965)) + +- **deps-dev**: Update tox requirement from ~=3.26 to ~=3.27 + ([#792](https://github.com/appium/python-client/pull/792), + [`df5bcb8`](https://github.com/appium/python-client/commit/df5bcb8725e3fead2ada8e0f368fa9cd24ac3555)) + +- **deps-dev**: Update tox requirement from ~=3.27 to ~=4.0 + ([#806](https://github.com/appium/python-client/pull/806), + [`45ca8cf`](https://github.com/appium/python-client/commit/45ca8cf6069dd515c1bd6bc4ae7656f7e2e7ed3a)) + +- **deps-dev**: Update tox requirement from ~=4.0 to ~=4.1 + ([#813](https://github.com/appium/python-client/pull/813), + [`827011e`](https://github.com/appium/python-client/commit/827011e2dbe39c887edfb562848b9fb3eff54a1b)) + +- **deps-dev**: Update tox requirement from ~=4.1 to ~=4.2 + ([#815](https://github.com/appium/python-client/pull/815), + [`7941203`](https://github.com/appium/python-client/commit/79412033c600a1369559d8b5cce084c471f072d9)) + +- **deps-dev**: Update tox requirement from ~=4.2 to ~=4.3 + ([#817](https://github.com/appium/python-client/pull/817), + [`0651afc`](https://github.com/appium/python-client/commit/0651afcf2350e8dec41779d242d7c5972b39b174)) + +### Features + +- Add status tentatively ([#820](https://github.com/appium/python-client/pull/820), + [`431aba1`](https://github.com/appium/python-client/commit/431aba1de859df4d5b34bd1d0216d4a9caa53a0d)) + + +## v2.7.1 (2022-10-11) + +### Chores + +- **deps**: Update selenium requirement from ~=4.4 to ~=4.5 + ([#780](https://github.com/appium/python-client/pull/780), + [`905eca6`](https://github.com/appium/python-client/commit/905eca69daa252238def9618ddd52588e5a28976)) + +- **deps-dev**: Update black requirement from ~=22.8.0 to ~=22.10.0 + ([#784](https://github.com/appium/python-client/pull/784), + [`c9e2632`](https://github.com/appium/python-client/commit/c9e2632e64214c96c1c19aad53734016dff59dfc)) + +- **deps-dev**: Update mypy requirement from ~=0.971 to ~=0.981 + ([#777](https://github.com/appium/python-client/pull/777), + [`38c1fb3`](https://github.com/appium/python-client/commit/38c1fb31199cb22952e1089cb5a8da583f1dfff9)) + +- **deps-dev**: Update mypy requirement from ~=0.981 to ~=0.982 + ([#782](https://github.com/appium/python-client/pull/782), + [`d7edba4`](https://github.com/appium/python-client/commit/d7edba49973613d5d6d74bebdb6e3c7b75f0dcec)) + +- **deps-dev**: Update pylint requirement from ~=2.15.2 to ~=2.15.3 + ([#774](https://github.com/appium/python-client/pull/774), + [`7d82821`](https://github.com/appium/python-client/commit/7d82821a03a42827ebe13c71c2742e175545a192)) + +- **deps-dev**: Update pytest-cov requirement from ~=3.0 to ~=4.0 + ([#779](https://github.com/appium/python-client/pull/779), + [`62bc72c`](https://github.com/appium/python-client/commit/62bc72ca114967490784823b1e1da6d11791f492)) + +- **deps-dev**: Update typing-extensions requirement + ([#783](https://github.com/appium/python-client/pull/783), + [`1848fdf`](https://github.com/appium/python-client/commit/1848fdf915dc57d22cc04964b69239f6bc3c7250)) + +### Continuous Integration + +- Comment out win for now ([#773](https://github.com/appium/python-client/pull/773), + [`46a09b8`](https://github.com/appium/python-client/commit/46a09b81028c0d1b87f21d4d1c42de674c074e07)) + +- Remove unit test section ([#773](https://github.com/appium/python-client/pull/773), + [`46a09b8`](https://github.com/appium/python-client/commit/46a09b81028c0d1b87f21d4d1c42de674c074e07)) + +- Run unit tests on actions ([#773](https://github.com/appium/python-client/pull/773), + [`46a09b8`](https://github.com/appium/python-client/commit/46a09b81028c0d1b87f21d4d1c42de674c074e07)) + +- Tweak trigger ([#773](https://github.com/appium/python-client/pull/773), + [`46a09b8`](https://github.com/appium/python-client/commit/46a09b81028c0d1b87f21d4d1c42de674c074e07)) + +### Refactoring + +- Make service startup failures more helpful + ([#786](https://github.com/appium/python-client/pull/786), + [`033071d`](https://github.com/appium/python-client/commit/033071d0603b9bade3bc49c92459b064ae574a02)) + + +## v2.7.0 (2022-09-22) + +### Bug Fixes + +- Move dev-only dependencies to [dev-packages] section + ([#772](https://github.com/appium/python-client/pull/772), + [`1a0246c`](https://github.com/appium/python-client/commit/1a0246cec0c3bf5f98fbf8ac20e1d5258f8e3e4f)) + +### Chores + +- **deps**: Update pylint requirement from ~=2.15.2 to ~=2.15.3 + ([#770](https://github.com/appium/python-client/pull/770), + [`83f3c81`](https://github.com/appium/python-client/commit/83f3c817bd6f979b1febdf4d643640b2d6c49d82)) + +### Continuous Integration + +- Fix runner name + ([`02a39a3`](https://github.com/appium/python-client/commit/02a39a31b9829635e91498ceea2099af5a4a493f)) + +### Documentation + +- Update changelog for 2.6.2 + ([`7a5fa26`](https://github.com/appium/python-client/commit/7a5fa26f3d066d311952a1b39983afa3e2c44547)) + +### Features + +- Add appArguments option to WindowsOptions + ([#768](https://github.com/appium/python-client/pull/768), + [`85cb104`](https://github.com/appium/python-client/commit/85cb1042373012d4c21fab2482090fe25a9422ac)) + + +## v2.6.2 (2022-09-16) + +### Bug Fixes + +- Use total_seconds property of timedelta ([#767](https://github.com/appium/python-client/pull/767), + [`b31b5eb`](https://github.com/appium/python-client/commit/b31b5ebe19eeeaf4216c712d213ae93f576f5943)) + +### Chores + +- **deps**: Bump black from 22.6.0 to 22.8.0 + ([#763](https://github.com/appium/python-client/pull/763), + [`806d5df`](https://github.com/appium/python-client/commit/806d5dff7f5b60723d68f249e5da7656db6a836b)) + +- **deps**: Update astroid requirement from ~=2.9 to ~=2.12 + ([#762](https://github.com/appium/python-client/pull/762), + [`89193b9`](https://github.com/appium/python-client/commit/89193b9b677cd4bb7c163a778450d17723c89798)) + +- **deps**: Update pylint requirement from ~=2.14.5 to ~=2.15.0 + ([#761](https://github.com/appium/python-client/pull/761), + [`130766c`](https://github.com/appium/python-client/commit/130766c97910d44c997bffbb563edb2c8d6629b3)) + +- **deps**: Update pylint requirement from ~=2.15.0 to ~=2.15.2 + ([#765](https://github.com/appium/python-client/pull/765), + [`7734ea2`](https://github.com/appium/python-client/commit/7734ea2fe3668809545db2729bb41c0f383a77cb)) + +- **deps**: Update tox requirement from ~=3.25 to ~=3.26 + ([#766](https://github.com/appium/python-client/pull/766), + [`fbfccca`](https://github.com/appium/python-client/commit/fbfcccab17b49aa77063a80969a013b8246be861)) + +### Continuous Integration + +- Add Conventional commit format validation + ([#764](https://github.com/appium/python-client/pull/764), + [`047e927`](https://github.com/appium/python-client/commit/047e9277db99c97b00f3fed7e008e3227a8e9f34)) + +- Update Conventional Commits config preset + ([`98ab48d`](https://github.com/appium/python-client/commit/98ab48d6a3ebf108a4c45de20ef55b4aec5b09ea)) + +### Documentation + +- Update changelog for 2.6.1 + ([`0a929c6`](https://github.com/appium/python-client/commit/0a929c6dc3a98a191995d70ba0160aaf256313f7)) + + +## v2.6.1 (2022-08-11) + +### Bug Fixes + +- Backwards compatible behaviour of swipe and scroll in action_helpers + ([#744](https://github.com/appium/python-client/pull/744), + [`677c1a2`](https://github.com/appium/python-client/commit/677c1a2121053a0435f3e0d8f7798077a41aa067)) + +- Fix options in mac2 ([#759](https://github.com/appium/python-client/pull/759), + [`0b711ae`](https://github.com/appium/python-client/commit/0b711aeb304e272f7b1a84ba59aa2bbd1edb4fb0)) + +- Move py.typed to the hierarchy root ([#751](https://github.com/appium/python-client/pull/751), + [`af83bba`](https://github.com/appium/python-client/commit/af83bba3b75d501bb063313e7edb3216765a9042)) + +- Typos/copypaste in various options ([#750](https://github.com/appium/python-client/pull/750), + [`c0b80dc`](https://github.com/appium/python-client/commit/c0b80dc8e8acf2f1c79a9e871f4ca23fb6d0b71d)) + +### Chores + +- **deps**: Update mypy requirement from ~=0.961 to ~=0.971 + ([#749](https://github.com/appium/python-client/pull/749), + [`2a41c39`](https://github.com/appium/python-client/commit/2a41c398b588d88030f5fd128487b9d3eeb0afb5)) + +- **deps**: Update pylint requirement from ~=2.14.3 to ~=2.14.4 + ([#742](https://github.com/appium/python-client/pull/742), + [`23ed3be`](https://github.com/appium/python-client/commit/23ed3be57d613aae4dc7b1737f35e2577ffcc706)) + +- **deps**: Update pylint requirement from ~=2.14.4 to ~=2.14.5 + ([#747](https://github.com/appium/python-client/pull/747), + [`8e10ad8`](https://github.com/appium/python-client/commit/8e10ad83ad1fc0948759a3830ce3d90cd0f53b46)) + +- **deps**: Update selenium requirement from ~=4.3 to ~=4.4 + ([#757](https://github.com/appium/python-client/pull/757), + [`ff50af0`](https://github.com/appium/python-client/commit/ff50af081c75817f7e4bbfc582fcb0755214eac3)) + +- **deps**: Update typing-extensions requirement from ~=4.2 to ~=4.3 + ([#745](https://github.com/appium/python-client/pull/745), + [`8f53696`](https://github.com/appium/python-client/commit/8f53696db85f00dcdaf7d8b969c30bcc24ce7d1d)) + +- **deps-dev**: Update pre-commit requirement from ~=2.19 to ~=2.20 + ([#746](https://github.com/appium/python-client/pull/746), + [`217acf1`](https://github.com/appium/python-client/commit/217acf168e4c772d67a745509a9e51e70e643c10)) + +### Documentation + +- Update changelog for 2.6.0 + ([`970f853`](https://github.com/appium/python-client/commit/970f8533e4b75c01fd592912a446344327dc0ac4)) + + +## v2.6.0 (2022-06-28) + +### Chores + +- Improve autocompletion for methods returning self instance + ([#739](https://github.com/appium/python-client/pull/739), + [`ce4de83`](https://github.com/appium/python-client/commit/ce4de83b443b050e295c5c1af0938ce720198bc8)) + +- **deps**: Bump black from 22.3.0 to 22.6.0 + ([#741](https://github.com/appium/python-client/pull/741), + [`ac39368`](https://github.com/appium/python-client/commit/ac39368b57bcb91ab72bdf09ed7b19f96a9f6544)) + +### Documentation + +- Update changelog for 2.5.0 + ([`50458bb`](https://github.com/appium/python-client/commit/50458bb3b7ebc74a8a1d417c450b95e43201f0b1)) + +### Features + +- Add Android drivers options ([#740](https://github.com/appium/python-client/pull/740), + [`470e836`](https://github.com/appium/python-client/commit/470e83674ecce5e5ff947427ed0c443cb7df4ae1)) + +### Refactoring + +- Remove previously deprecated methods and mark reset/close/launch APIs as deprecated + ([#738](https://github.com/appium/python-client/pull/738), + [`4c166f4`](https://github.com/appium/python-client/commit/4c166f45516a432ec807195f91fc2f208a3a3c08)) + + +## v2.5.0 (2022-06-25) + +### Chores + +- Bump version to 2.4.0 + ([`c400357`](https://github.com/appium/python-client/commit/c400357ca0028e7a83124a91331cf69c31be91c4)) + +- **deps**: Update pylint requirement from ~=2.14.1 to ~=2.14.2 + ([#725](https://github.com/appium/python-client/pull/725), + [`cc999ce`](https://github.com/appium/python-client/commit/cc999cea4a34510b42af22663c9c8d5037ab9bb2)) + +- **deps**: Update pylint requirement from ~=2.14.1 to ~=2.14.2 + ([#725](https://github.com/appium/python-client/pull/725), + [`15b106c`](https://github.com/appium/python-client/commit/15b106c5769fc7b5307f8daecdcfbc7f3cc7dea4)) + +- **deps**: Update pylint requirement from ~=2.14.2 to ~=2.14.3 + ([#733](https://github.com/appium/python-client/pull/733), + [`0a0cff2`](https://github.com/appium/python-client/commit/0a0cff2e02ad19a2cb336c3e92fcc7378ed57fe2)) + +- **deps**: Update selenium requirement from ~=4.2 to ~=4.3 + ([#736](https://github.com/appium/python-client/pull/736), + [`6eca124`](https://github.com/appium/python-client/commit/6eca12427bcd8be6fd6760193b0321d5bc088a2b)) + +### Features + +- Add Gecko driver options ([#735](https://github.com/appium/python-client/pull/735), + [`b4e17a3`](https://github.com/appium/python-client/commit/b4e17a3a1efe33f08ac9ef883891b9fad4449a41)) + +- Add Mac2Driver options ([#730](https://github.com/appium/python-client/pull/730), + [`312c229`](https://github.com/appium/python-client/commit/312c229fa89b6387236553c6f036085a835d3ed8)) + +- Add Safari driver options ([#731](https://github.com/appium/python-client/pull/731), + [`2201e90`](https://github.com/appium/python-client/commit/2201e90eec53cd3df29ed9cfcb5ba94d300fb7a0)) + +- Add Windows driver options ([#732](https://github.com/appium/python-client/pull/732), + [`d480eba`](https://github.com/appium/python-client/commit/d480ebaa1fcc52239d2a71d288e73e103f504429)) + +- Add xcuitest driver options ([#737](https://github.com/appium/python-client/pull/737), + [`0264d81`](https://github.com/appium/python-client/commit/0264d81d60c30b187da7b2e58cc67f6aad0def5f)) + +### Refactoring + +- Make system_port and system_host options common + ([#734](https://github.com/appium/python-client/pull/734), + [`5b958b5`](https://github.com/appium/python-client/commit/5b958b53f1df486314ca82cb35adce9161147aef)) + + +## v2.4.0 (2022-06-17) + +### Chores + +- Add better error handling for session creation responses + ([#727](https://github.com/appium/python-client/pull/727), + [`22dfeca`](https://github.com/appium/python-client/commit/22dfeca560f8f0d5527bfdc0e0200055ee3e30f5)) + +- Update comments to locator patches ([#724](https://github.com/appium/python-client/pull/724), + [`0fcea82`](https://github.com/appium/python-client/commit/0fcea82c9bcaf9137bc7b1591c37b092927751a2)) + +### Documentation + +- Update changelog for 2.3.0 + ([`8321b9c`](https://github.com/appium/python-client/commit/8321b9c5122b1f848c34d0dc230e38d522e09fa9)) + +### Features + +- Add common options ([#728](https://github.com/appium/python-client/pull/728), + [`60ec7ce`](https://github.com/appium/python-client/commit/60ec7ce69a9224eab28af3e89bf9ea1acb920ac4)) + + +## v2.3.0 (2022-06-13) + +### Chores + +- Disable pylint checks fail CI ([#719](https://github.com/appium/python-client/pull/719), + [`a394281`](https://github.com/appium/python-client/commit/a3942815a7b60548785db0ea2f8506b25b0693e2)) + +- **deps**: Update mypy requirement from ~=0.942 to ~=0.950 + ([#712](https://github.com/appium/python-client/pull/712), + [`336a762`](https://github.com/appium/python-client/commit/336a76257e809f5562e287d68322d9f256d880c7)) + +- **deps**: Update mypy requirement from ~=0.950 to ~=0.960 + ([#714](https://github.com/appium/python-client/pull/714), + [`956417a`](https://github.com/appium/python-client/commit/956417a55de28123bcf2404ebbbc95b0d9fcd072)) + +- **deps**: Update mypy requirement from ~=0.960 to ~=0.961 + ([#718](https://github.com/appium/python-client/pull/718), + [`0ff83df`](https://github.com/appium/python-client/commit/0ff83df100a4bae2d5547e0ba501b501890f6374)) + +- **deps**: Update selenium requirement from ~=4.1 to ~=4.2 + ([#715](https://github.com/appium/python-client/pull/715), + [`697bb64`](https://github.com/appium/python-client/commit/697bb64db15378dfbcd6b4bc3f4931da520259a5)) + +- **deps**: Update sphinx requirement from <5.0,>=4.0 to >=4.0,<6.0 + ([#716](https://github.com/appium/python-client/pull/716), + [`1385efc`](https://github.com/appium/python-client/commit/1385efc80d87cb50c600548229ff74d9106c402b)) + +- **deps**: Update tox requirement from ~=3.24 to ~=3.25 + ([#709](https://github.com/appium/python-client/pull/709), + [`f5b0526`](https://github.com/appium/python-client/commit/f5b0526f903eee98f443b47d6fec7a4f1d0a4838)) + +- **deps**: Update typing-extensions requirement from ~=4.1 to ~=4.2 + ([#711](https://github.com/appium/python-client/pull/711), + [`cb1a4ea`](https://github.com/appium/python-client/commit/cb1a4eaed0628a064deb70ba04fe5a5cd53312a4)) + +- **deps-dev**: Update pre-commit requirement from ~=2.17 to ~=2.18 + ([#708](https://github.com/appium/python-client/pull/708), + [`4f8064f`](https://github.com/appium/python-client/commit/4f8064fff2d6d7f197112f2e83be0eacbbec4265)) + +- **deps-dev**: Update pre-commit requirement from ~=2.18 to ~=2.19 + ([#713](https://github.com/appium/python-client/pull/713), + [`df33c85`](https://github.com/appium/python-client/commit/df33c85371d933ed0678f759ccf660343c66662a)) + +### Documentation + +- Update README with the new options format + ([#722](https://github.com/appium/python-client/pull/722), + [`a2bba19`](https://github.com/appium/python-client/commit/a2bba19360a6205fc6f0679b595ae560181e70c3)) + +### Features + +- Add base options for all supported automation names + ([#721](https://github.com/appium/python-client/pull/721), + [`d4c44b4`](https://github.com/appium/python-client/commit/d4c44b4b68c611be88007ee666ee8f59c79ce9f1)) + +- Add support for w3c options ([#720](https://github.com/appium/python-client/pull/720), + [`c27138c`](https://github.com/appium/python-client/commit/c27138c0505a6595f9c5f48f3e4d3ccb996301cd)) + +### Testing + +- Use Appium2 to run functional tests ([#723](https://github.com/appium/python-client/pull/723), + [`b267665`](https://github.com/appium/python-client/commit/b26766583830ae83e20416629c8bdd24b58e5658)) + + +## v2.2.0 (2022-03-30) + +### Chores + +- Relax selenium version as same as before + ([`96681e9`](https://github.com/appium/python-client/commit/96681e924b4310bcaa23c839746b4923925a2d96)) + +- **deps**: Bump black from 22.1.0 to 22.3.0 + ([#705](https://github.com/appium/python-client/pull/705), + [`79406bc`](https://github.com/appium/python-client/commit/79406bc044f564261e83d6a5ae689b0adcfc7632)) + +- **deps**: Update mypy requirement from ~=0.930 to ~=0.941 + ([#696](https://github.com/appium/python-client/pull/696), + [`ce526e6`](https://github.com/appium/python-client/commit/ce526e6f587adcf9c37690dd1a427ec71871de3e)) + +- **deps**: Update mypy requirement from ~=0.941 to ~=0.942 + ([#703](https://github.com/appium/python-client/pull/703), + [`56ce5b0`](https://github.com/appium/python-client/commit/56ce5b029a2e878f0fe0c97042f58372327d7a64)) + +- **deps**: Update pylint requirement from ~=2.12 to ~=2.13 + ([#702](https://github.com/appium/python-client/pull/702), + [`8826bb3`](https://github.com/appium/python-client/commit/8826bb35ea529a480226361b87b3b345206a6493)) + +- **deps**: Update pytest requirement from ~=7.0 to ~=7.1 + ([#694](https://github.com/appium/python-client/pull/694), + [`7dbf323`](https://github.com/appium/python-client/commit/7dbf3237bff5b503049c47d5815250acb8d6180a)) + +- **deps**: Update typing-extensions requirement from ~=4.0 to ~=4.1 + ([#684](https://github.com/appium/python-client/pull/684), + [`23553df`](https://github.com/appium/python-client/commit/23553dfc7cb1a87e2fa79a81bb0f36b00bdc5169)) + +### Documentation + +- Update missing changelog + ([`c972382`](https://github.com/appium/python-client/commit/c97238216e828266819f82538c77a993fdf39cf2)) + +### Features + +- Add non-w3c but still need commands ([#701](https://github.com/appium/python-client/pull/701), + [`09a0cd0`](https://github.com/appium/python-client/commit/09a0cd0c72cc9e63c26c516f8bd8a4ac7b211808)) + + +## v2.1.4 (2022-02-27) + + +## v2.1.3 (2022-02-25) + +### Chores + +- Bump mypy ([#675](https://github.com/appium/python-client/pull/675), + [`72f942d`](https://github.com/appium/python-client/commit/72f942d2152ee1b0d7539f3bf2705b50d01133f7)) + +- Restrict selenium client version ([#686](https://github.com/appium/python-client/pull/686), + [`2c04e4c`](https://github.com/appium/python-client/commit/2c04e4ce59ed04b91088ca55d1d3698653de6ebc)) + +- **deps**: Bump black from 21.12b0 to 22.1.0 + ([#681](https://github.com/appium/python-client/pull/681), + [`7a7be33`](https://github.com/appium/python-client/commit/7a7be33827f8a92c3efbd9003c537ae259ad59cd)) + +- **deps**: Update pytest requirement from ~=6.2 to ~=7.0 + ([#682](https://github.com/appium/python-client/pull/682), + [`588f83f`](https://github.com/appium/python-client/commit/588f83f28007d58e03c17759a5a5b807f4a08ae8)) + +- **deps-dev**: Update pre-commit requirement from ~=2.16 to ~=2.17 + ([#678](https://github.com/appium/python-client/pull/678), + [`71410ba`](https://github.com/appium/python-client/commit/71410bab56522ae3ca36ee7fcb6dee349d6bc65a)) + +### Refactoring + +- Update types descriptions for mixin classes + ([#677](https://github.com/appium/python-client/pull/677), + [`895cde1`](https://github.com/appium/python-client/commit/895cde1aa674aaab2f958ae251de0daefd049c02)) + +### Testing + +- Update find element/s methods ([#674](https://github.com/appium/python-client/pull/674), + [`7dbf4f2`](https://github.com/appium/python-client/commit/7dbf4f2f7ce43f60eded19fa247bb2177b65bafd)) + +- Update tests to use find_element(by...) ([#674](https://github.com/appium/python-client/pull/674), + [`7dbf4f2`](https://github.com/appium/python-client/commit/7dbf4f2f7ce43f60eded19fa247bb2177b65bafd)) + + +## v2.1.2 (2021-12-30) + +### Bug Fixes + +- Default duration in tap ([#673](https://github.com/appium/python-client/pull/673), + [`24b50d8`](https://github.com/appium/python-client/commit/24b50d8138ea6ae008b0557991c0b5dcd75a15d0)) + + +## v2.1.1 (2021-12-24) + +### Chores + +- Specify touch ([#670](https://github.com/appium/python-client/pull/670), + [`6b21a67`](https://github.com/appium/python-client/commit/6b21a6713ff34eb5b8fca71fc24105ff6d2e1c0f)) + +- **deps**: Bump black from 21.11b1 to 21.12b0 + ([#664](https://github.com/appium/python-client/pull/664), + [`02d6c8c`](https://github.com/appium/python-client/commit/02d6c8c5d21a1b3b135a5904edfa6acd03f1ac18)) + +- **deps**: Update astroid requirement from ~=2.8 to ~=2.9 + ([#661](https://github.com/appium/python-client/pull/661), + [`758b2cd`](https://github.com/appium/python-client/commit/758b2cd37f075a08f492575e7b938206f2828fd6)) + +- **deps**: Update pylint requirement from ~=2.11 to ~=2.12 + ([#662](https://github.com/appium/python-client/pull/662), + [`6c7c80c`](https://github.com/appium/python-client/commit/6c7c80c0c7211b9d5a2034a52d576738e53bdccb)) + +- **deps-dev**: Update pre-commit requirement from ~=2.15 to ~=2.16 + ([#663](https://github.com/appium/python-client/pull/663), + [`1b94c5f`](https://github.com/appium/python-client/commit/1b94c5fa3568b90dc90d1d4bb5634a573d07aa5a)) + +### Continuous Integration + +- Remove ==2021.5.29 ([#653](https://github.com/appium/python-client/pull/653), + [`e5cb9ab`](https://github.com/appium/python-client/commit/e5cb9abee0272399289d698fba06a7ddd5fbd039)) + +### Features + +- Use 'touch' pointer action ([#670](https://github.com/appium/python-client/pull/670), + [`6b21a67`](https://github.com/appium/python-client/commit/6b21a6713ff34eb5b8fca71fc24105ff6d2e1c0f)) + + +## v2.1.0 (2021-11-26) + +### Chores + +- Add deprecated mark for find_element_by* + ([#657](https://github.com/appium/python-client/pull/657), + [`d7cb6b5`](https://github.com/appium/python-client/commit/d7cb6b59598fb594b56d77c47abb02f4f07fa452)) + +- Relax selenium version control ([#656](https://github.com/appium/python-client/pull/656), + [`ace98dc`](https://github.com/appium/python-client/commit/ace98dc0dd9be7cd468ddfd775f5f55d24f7fb1d)) + +- Tweak keyword in metadata + ([`2a462be`](https://github.com/appium/python-client/commit/2a462becfe31dc4e18559ba246b0856fd3eb2488)) + +### Features + +- Add AppiumBy instead of MobileBy ([#659](https://github.com/appium/python-client/pull/659), + [`b70422b`](https://github.com/appium/python-client/commit/b70422b67f5254523ed360e1d196df0df04feab4)) + + +## v2.0.0 (2021-11-08) + +### Chores + +- Add Deprecated for -windows uiautomation + ([#649](https://github.com/appium/python-client/pull/649), + [`8ec5441`](https://github.com/appium/python-client/commit/8ec5441d2b5074180eafd8cc7dc511e1d8615496)) + +- Add deprecated mark in MultiAction class + ([#648](https://github.com/appium/python-client/pull/648), + [`1a54fe9`](https://github.com/appium/python-client/commit/1a54fe9010d2305ab9ec2b6f2a6382279832f42d)) + +- Add deprecation mark in touch actions and multi touch + ([#648](https://github.com/appium/python-client/pull/648), + [`1a54fe9`](https://github.com/appium/python-client/commit/1a54fe9010d2305ab9ec2b6f2a6382279832f42d)) + +- Add logger ([#649](https://github.com/appium/python-client/pull/649), + [`8ec5441`](https://github.com/appium/python-client/commit/8ec5441d2b5074180eafd8cc7dc511e1d8615496)) + +- Add Python 3.9 as metadata + ([`f4d5489`](https://github.com/appium/python-client/commit/f4d5489ae576a3ad126aa99bca7531a89c153d6a)) + +- Adding deprecation mark in touch actions and multi touch + ([#648](https://github.com/appium/python-client/pull/648), + [`1a54fe9`](https://github.com/appium/python-client/commit/1a54fe9010d2305ab9ec2b6f2a6382279832f42d)) + +- Cleanup no longer needed code in w3c, bump dev Pipfile + ([#646](https://github.com/appium/python-client/pull/646), + [`658cadd`](https://github.com/appium/python-client/commit/658cadd065411caf5299450a610fe9fd725cdceb)) + +- Deprecate -windows uiautomation ([#649](https://github.com/appium/python-client/pull/649), + [`8ec5441`](https://github.com/appium/python-client/commit/8ec5441d2b5074180eafd8cc7dc511e1d8615496)) + +- **deps**: Update isort requirement from ~=5.9 to ~=5.10 + ([#650](https://github.com/appium/python-client/pull/650), + [`a195bf0`](https://github.com/appium/python-client/commit/a195bf0affb813ad1729a90b2096620b27eb5478)) + +- **deps**: Update pylint requirement from ~=2.10 to ~=2.11 + ([#638](https://github.com/appium/python-client/pull/638), + [`9baa378`](https://github.com/appium/python-client/commit/9baa3786480c68f00e6bb1a6ea8c5b79fc4c0d62)) + +- **deps**: Update pytest-cov requirement from ~=2.12 to ~=3.0 + ([#641](https://github.com/appium/python-client/pull/641), + [`4643402`](https://github.com/appium/python-client/commit/4643402c287dd75ef0ed68dee1e15229116cc00d)) + +- **deps**: Update sphinx requirement from <4.0,>=3.0 to >=3.0,<5.0 + ([#603](https://github.com/appium/python-client/pull/603), + [`2df9031`](https://github.com/appium/python-client/commit/2df9031ea83701decd855f0bc8c33c6aaa09a0e5)) + +- **deps**: Update sphinx-rtd-theme requirement from <1.0 to <2.0 + ([#637](https://github.com/appium/python-client/pull/637), + [`a2d3df1`](https://github.com/appium/python-client/commit/a2d3df1aa65654727aa8becc104e4c1207c84ab2)) + +### Continuous Integration + +- Add --pre ([#651](https://github.com/appium/python-client/pull/651), + [`9871231`](https://github.com/appium/python-client/commit/9871231bb89b089a1ac93bf7cbc35439a5783ea5)) + +- Set pipenv==2021.5.29 to prevent dependencies error + ([#651](https://github.com/appium/python-client/pull/651), + [`9871231`](https://github.com/appium/python-client/commit/9871231bb89b089a1ac93bf7cbc35439a5783ea5)) + +### Documentation + +- Update readme + ([`45b389d`](https://github.com/appium/python-client/commit/45b389d6e183561a57fef9c7c8ea28d15121093d)) + +- Update readme + ([`4bc118b`](https://github.com/appium/python-client/commit/4bc118b2158712f972dd43136d32241f05dc94c7)) + +- Update readme ([#648](https://github.com/appium/python-client/pull/648), + [`1a54fe9`](https://github.com/appium/python-client/commit/1a54fe9010d2305ab9ec2b6f2a6382279832f42d)) + +### Features + +- Change base selenium client version to selenium 4 + ([#636](https://github.com/appium/python-client/pull/636), + [`c7d4193`](https://github.com/appium/python-client/commit/c7d4193a26c766da66fa16ecb89fc698a781826c)) + + +## v1.3.0 (2021-09-26) + +### Chores + +- Add placeholder ([#615](https://github.com/appium/python-client/pull/615), + [`e48085d`](https://github.com/appium/python-client/commit/e48085d27968a93d9cfb5d86964ac84198b52214)) + +- **deps**: Update astroid requirement from ~=2.5 to ~=2.7 + ([#629](https://github.com/appium/python-client/pull/629), + [`76ef1e7`](https://github.com/appium/python-client/commit/76ef1e77b6cb48ac62bee02e5b8003c5fa50a3e2)) + +- **deps**: Update mypy requirement from ~=0.812 to ~=0.910 + ([#616](https://github.com/appium/python-client/pull/616), + [`5f603ce`](https://github.com/appium/python-client/commit/5f603cecb9464335f4e1b99e21a880dff12a958a)) + +- **deps**: Update pylint requirement from ~=2.8 to ~=2.10 + ([#628](https://github.com/appium/python-client/pull/628), + [`36b4990`](https://github.com/appium/python-client/commit/36b4990bd8c34ce32cf013754058b3eb928d2186)) + +- **deps**: Update tox requirement from ~=3.23 to ~=3.24 + ([#619](https://github.com/appium/python-client/pull/619), + [`bc9eb18`](https://github.com/appium/python-client/commit/bc9eb1850f3fb26392e2055ce082c055b86c18dd)) + +- **deps**: Update types-python-dateutil requirement + ([#633](https://github.com/appium/python-client/pull/633), + [`e85d7d4`](https://github.com/appium/python-client/commit/e85d7d402f93f24d21e116040a06d6ee95d2e5a6)) + +- **deps-dev**: Update pre-commit requirement from ~=2.13 to ~=2.15 + ([#634](https://github.com/appium/python-client/pull/634), + [`31eda77`](https://github.com/appium/python-client/commit/31eda777d0761689b84a1503f6b7c896f1df361a)) + +### Features + +- Add command with `setattr` ([#615](https://github.com/appium/python-client/pull/615), + [`e48085d`](https://github.com/appium/python-client/commit/e48085d27968a93d9cfb5d86964ac84198b52214)) + +- Add satellites in set_location ([#620](https://github.com/appium/python-client/pull/620), + [`cfb6ee6`](https://github.com/appium/python-client/commit/cfb6ee6487217d0b01c42b2b9d291779ea17dd85)) + +- Do not raise an error in case method is already defined + ([#632](https://github.com/appium/python-client/pull/632), + [`f8d3a38`](https://github.com/appium/python-client/commit/f8d3a38639557081700a273c5dcc641e42112aba)) + + +## v1.2.0 (2021-06-06) + +### Chores + +- **deps**: Update isort requirement from ~=5.7 to ~=5.8 + ([#596](https://github.com/appium/python-client/pull/596), + [`91a9d67`](https://github.com/appium/python-client/commit/91a9d6701430599637bb6895f9ffb078ee4bd052)) + +- **deps**: Update pylint requirement from ~=2.7 to ~=2.8 + ([#600](https://github.com/appium/python-client/pull/600), + [`18db735`](https://github.com/appium/python-client/commit/18db7355a6f92be5f85fb7ef07b06b78bb9387af)) + +- **deps**: Update pytest-cov requirement from ~=2.11 to ~=2.12 + ([#606](https://github.com/appium/python-client/pull/606), + [`ba408b7`](https://github.com/appium/python-client/commit/ba408b74f0d30fc06a51e77f68fc5cfd4ac8f99a)) + +- **deps-dev**: Update pre-commit requirement from ~=2.11 to ~=2.12 + ([#599](https://github.com/appium/python-client/pull/599), + [`d0bfdd6`](https://github.com/appium/python-client/commit/d0bfdd63ca10a0950306d0e8e10a720317ce4d91)) + +- **deps-dev**: Update pre-commit requirement from ~=2.12 to ~=2.13 + ([#607](https://github.com/appium/python-client/pull/607), + [`37258a3`](https://github.com/appium/python-client/commit/37258a392b630686797e3f7bdcc038bdd6e89d83)) + +### Features + +- Allow to add a command dynamically ([#608](https://github.com/appium/python-client/pull/608), + [`b4c15e2`](https://github.com/appium/python-client/commit/b4c15e2abe0ce477c2b7fc36cb78e8fd9aae12f0)) + + +## v1.1.0 (2021-03-10) + +### Chores + +- Add table for screen_record kwarg ([#582](https://github.com/appium/python-client/pull/582), + [`1a8c736`](https://github.com/appium/python-client/commit/1a8c73675b25aa3b33a591fddb6a56dce82cf647)) + +- Address selenium-4 branch in readme ([#566](https://github.com/appium/python-client/pull/566), + [`9c7fbce`](https://github.com/appium/python-client/commit/9c7fbce68d97187a9d1aa07d13c86e0e291e39e4)) + +- Apply Black code formatter ([#571](https://github.com/appium/python-client/pull/571), + [`344953a`](https://github.com/appium/python-client/commit/344953a49c7d66c77b2fa9b998a89a26d0e1f0d7)) + +- Fix functional keyboard tests with appium v1.21.0-beta.0 + ([#574](https://github.com/appium/python-client/pull/574), + [`70048fc`](https://github.com/appium/python-client/commit/70048fc7c504aea1e57b6bc71c701db7beb60c2c)) + +- Fix iOS app management functional tests ([#575](https://github.com/appium/python-client/pull/575), + [`74f599d`](https://github.com/appium/python-client/commit/74f599d847f9624221ce7b27aa2570231dd56de3)) + +- Update pipfile to respect isort v5 ([#577](https://github.com/appium/python-client/pull/577), + [`173d3aa`](https://github.com/appium/python-client/commit/173d3aae4289015b0e9a28e5e3bb0e7ccc86061f)) + +- **deps**: Update astroid requirement from ~=2.4 to ~=2.5 + ([#587](https://github.com/appium/python-client/pull/587), + [`d5f29f0`](https://github.com/appium/python-client/commit/d5f29f08a2fe9b5a9cca4162726c7cfb4faa42e9)) + +- **deps**: Update isort requirement from ~=5.0 to ~=5.7 + ([#578](https://github.com/appium/python-client/pull/578), + [`3706e87`](https://github.com/appium/python-client/commit/3706e87068bd384895272fac6611c8f0c64716c8)) + +- **deps**: Update mypy requirement from ~=0.800 to ~=0.812 + ([#589](https://github.com/appium/python-client/pull/589), + [`db035dd`](https://github.com/appium/python-client/commit/db035dd0f4cca60c33293951e1bc0761054b0cdc)) + +- **deps**: Update pylint requirement from ~=2.6 to ~=2.7 + ([#588](https://github.com/appium/python-client/pull/588), + [`0ecad2f`](https://github.com/appium/python-client/commit/0ecad2fa1bf7e5e876372eede24f664492fd4fc5)) + +- **deps**: Update tox requirement from ~=3.21 to ~=3.22 + ([#586](https://github.com/appium/python-client/pull/586), + [`3c31a65`](https://github.com/appium/python-client/commit/3c31a65cef9a93e065920e4add2d74b12bc0f436)) + +- **deps**: Update tox requirement from ~=3.22 to ~=3.23 + ([#593](https://github.com/appium/python-client/pull/593), + [`66208fd`](https://github.com/appium/python-client/commit/66208fdbbc8f0a8b0e90376b404135b57e797fa5)) + +- **deps-dev**: Update pre-commit requirement from ~=2.10 to ~=2.11 + ([#595](https://github.com/appium/python-client/pull/595), + [`e49dc78`](https://github.com/appium/python-client/commit/e49dc784d376145f12afe2f61a8ee7348c2ee08e)) + +### Continuous Integration + +- Added py39-dev ([#557](https://github.com/appium/python-client/pull/557), + [`1ae8c25`](https://github.com/appium/python-client/commit/1ae8c25d3e1da457f4a16710c0b04dc709140277)) + +- Added py39-dev for travis ([#557](https://github.com/appium/python-client/pull/557), + [`1ae8c25`](https://github.com/appium/python-client/commit/1ae8c25d3e1da457f4a16710c0b04dc709140277)) + +- Move azure project to Appium CI, update readme + ([#564](https://github.com/appium/python-client/pull/564), + [`3e60e8f`](https://github.com/appium/python-client/commit/3e60e8fff4cfca93541c73c45f9662cdfe6475bc)) + +- Remove travis ([#581](https://github.com/appium/python-client/pull/581), + [`1bf0553`](https://github.com/appium/python-client/commit/1bf05530dbccc2478a58bbd45fb8e0ce092bcceb)) + +- Upgrade xcode and macos ([#556](https://github.com/appium/python-client/pull/556), + [`9402c6f`](https://github.com/appium/python-client/commit/9402c6ff99de70d42a1031db95bb934942b08a41)) + +- Upgrade xcode ver and macos ([#556](https://github.com/appium/python-client/pull/556), + [`9402c6f`](https://github.com/appium/python-client/commit/9402c6ff99de70d42a1031db95bb934942b08a41)) + +- Use node v12 ([#585](https://github.com/appium/python-client/pull/585), + [`8eb4c3f`](https://github.com/appium/python-client/commit/8eb4c3f7c2cb95ee81eb9c664de265edf473d9dc)) + +### Documentation + +- Fix wrong code example in README.md ([#555](https://github.com/appium/python-client/pull/555), + [`17af195`](https://github.com/appium/python-client/commit/17af19565cc1b443b2aecb86291db68a450c420f)) + +### Features + +- Add optional location speed attribute for android devices + ([#594](https://github.com/appium/python-client/pull/594), + [`ce78c0d`](https://github.com/appium/python-client/commit/ce78c0de2e15307ae20a8cc3a496f6c794fdeec6)) + +- Add warning to drop forceMjsonwp for W3C + ([#567](https://github.com/appium/python-client/pull/567), + [`e51bcd2`](https://github.com/appium/python-client/commit/e51bcd269cab41b680971026e2974a2bf468a8a2)) + +- Added descriptions for newly added screenrecord opts + ([#540](https://github.com/appium/python-client/pull/540), + [`d8d4aea`](https://github.com/appium/python-client/commit/d8d4aea950e5c20d5299e131f9a9a5075a7d3aa4)) + +- Added docstring for macOS screenrecord option + ([#580](https://github.com/appium/python-client/pull/580), + [`ed5af31`](https://github.com/appium/python-client/commit/ed5af31a38e3bc34af32f601bf9ca0d800bcbc69)) + + +## v1.0.2 (2020-07-15) + +### Chores + +- Add checking package file count comparison in release script + ([#547](https://github.com/appium/python-client/pull/547), + [`e3bd534`](https://github.com/appium/python-client/commit/e3bd5344697757bb8f1fc5722e132e13fa6e8194)) + +- Add file count in release script ([#547](https://github.com/appium/python-client/pull/547), + [`e3bd534`](https://github.com/appium/python-client/commit/e3bd5344697757bb8f1fc5722e132e13fa6e8194)) + +- Add the workaround to avoid service freezes on Windows + ([#552](https://github.com/appium/python-client/pull/552), + [`95b01c9`](https://github.com/appium/python-client/commit/95b01c945241559c84804d897a1dddde2feb58d9)) + + +## v1.0.1 (2020-05-18) + +### Bug Fixes + +- Broken package ([#545](https://github.com/appium/python-client/pull/545), + [`e4e29f8`](https://github.com/appium/python-client/commit/e4e29f83f9feb4c1a6aa979e3c977af7ff996698)) + + +## v1.0.0 (2020-05-17) + +- Initial Release diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index e14a3001c..000000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,5933 +0,0 @@ -Changelog -========= - - -v5.1.1 (2025-05-07) -------------------- -- Bump 5.1.1. [Kazuaki Matsuo] -- Docs: update README.md. [Kazuaki Matsuo] -- Chore(deps): bump selenium from 4.31.0 to 4.32.0 (#1124) [Kazuaki - Matsuo, dependabot[bot], dependabot[bot]] - - * chore(deps): bump selenium from 4.31.0 to 4.32.0 - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.31.0 to 4.32.0. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.31.0...selenium-4.32.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-version: 4.32.0 - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Docs: update compatibility matrix. [Kazuaki Matsuo] -- Update changelog for 5.1.0. [Kazuaki Matsuo] - - -v5.1.0 (2025-05-05) -------------------- - -New -~~~ -- Feat: add method for interacting with the Flutter integration driver - (#1123) [Oleg Matskiv] - -Test -~~~~ -- Test: use timeout in client_config instead of the global var (#1120) - [Kazuaki Matsuo] -- Ci: Tune CC title script. [Mykola Mokhnach] - -Other -~~~~~ -- Bump 5.1.0. [Kazuaki Matsuo] -- Chore(deps-dev): update ruff requirement from ~=0.11.7 to ~=0.11.8 - (#1122) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.11.7...0.11.8) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-version: 0.11.8 - dependency-type: direct:development - ... -- Chore(deps): update typing-extensions requirement (#1115) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing_extensions) to permit the latest version. - - [Release notes](https://github.com/python/typing_extensions/releases) - - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - - [Commits](https://github.com/python/typing_extensions/compare/4.13.1...4.13.2) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-version: 4.13.2 - dependency-type: direct:production - ... -- Chore(deps-dev): update ruff requirement from ~=0.11.4 to ~=0.11.7 - (#1118) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.11.4...0.11.7) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-version: 0.11.7 - dependency-type: direct:development - ... -- Chore(deps): bump selenium from 4.30.0 to 4.31.0 (#1113) - [dependabot[bot], dependabot[bot]] - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.30.0 to 4.31.0. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.30.0...selenium-4.31.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-version: 4.31.0 - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Chore(deps-dev): update ruff requirement from ~=0.11.3 to ~=0.11.4 - (#1114) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.11.3...0.11.4) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-version: 0.11.4 - dependency-type: direct:development - ... -- Chore(deps): update typing-extensions requirement (#1112) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing_extensions) to permit the latest version. - - [Release notes](https://github.com/python/typing_extensions/releases) - - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - - [Commits](https://github.com/python/typing_extensions/compare/4.12.2...4.13.1) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-version: 4.13.1 - dependency-type: direct:production - ... -- Chore(deps-dev): update ruff requirement from ~=0.11.2 to ~=0.11.3 - (#1111) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.11.2...0.11.3) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-version: 0.11.3 - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.10.0 to ~=0.11.2 - (#1107) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.10.0...0.11.2) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.24 to ~=4.25 (#1109) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.24.0...4.25.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps): bump selenium from 4.29.0 to 4.30.0 (#1108) - [dependabot[bot], dependabot[bot]] - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.29.0 to 4.30.0. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.29.0...selenium-4.30.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Update changelog for 5.0.0. [Kazuaki Matsuo] - - -v5.0.0 (2025-03-23) -------------------- - -New -~~~ -- Feat: define AppiumClientConfig (#1070) [Copilot - <175728472+Copilot@users.noreply.github.com> * update readme * - remove redundant command_executor check * modify a bit * fix typo - and apply comment * use new variable --------- Co-authored-by: - Copilot <175728472+Copilot@users.noreply.github.com>, Kazuaki Matsuo] - - * initial implementation - - * remove - - * add appium/webdriver/client_config.py - - * remove duplicated args - - * remove duplicated args - - * fix typo - - * add file_detector and remove redundant config - - * add test to check remote_server_addr priority - - * remove PLR0913, address http://127.0.0.1:4723 - - * update the readme - - * add comment - - * fix typo - - * extract - - * extract and followed the selenium - - * add comment - - * Update webdriver.py - - * Apply suggestions from code review - -Other -~~~~~ -- Bump 5.0.0. [Kazuaki Matsuo] -- Chore(deps-dev): update pre-commit requirement from ~=4.1 to ~=4.2 - (#1104) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v4.1.0...v4.2.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.10 to ~=0.10.0 - (#1102) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.10...0.10.0) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.9 to ~=0.9.10 - (#1101) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.9...0.9.10) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update mock requirement from ~=5.1 to ~=5.2 (#1100) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [mock](https://github.com/testing-cabal/mock) to permit the latest version. - - [Changelog](https://github.com/testing-cabal/mock/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/testing-cabal/mock/compare/5.1.0...5.2.0) - - --- - updated-dependencies: - - dependency-name: mock - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.7 to ~=0.9.9 - (#1099) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.7...0.9.9) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.5 to ~=0.9.7 - (#1097) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.5...0.9.7) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Update changelog for 4.5.1. [Kazuaki Matsuo] - - -v4.5.1 (2025-02-23) -------------------- - -Fix -~~~ -- Prevent warning log when initialize a webdriver using version 4.5.0 - (selenium v4.26+) (#1098) [testerxiaodong] - - Remove the parameter 'remote_ server _ addr' for initializing AppiumConnection at appium/webdriver/webdriver.py file line 220 - -Test -~~~~ -- Test: Pytest does not require test classes unless you need grouping or - fixtures with class scope. (#1094) [Dor Blayzer] -- Test: use pytest without class-based structures, using - parameterization for better reusability. (#1095) [Dor Blayzer] - -Other -~~~~~ -- Bump 4.5.1. [Kazuaki Matsuo] -- Chore(deps): bump selenium from 4.28.1 to 4.29.0 (#1096) - [dependabot[bot], dependabot[bot]] - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.28.1 to 4.29.0. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/commits) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.3 to ~=0.9.5 - (#1092) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.3...0.9.5) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update pre-commit requirement from ~=3.5 to ~=4.1 - (#1085) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v3.5.0...v4.1.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.2 to ~=0.9.3 - (#1089) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.2...0.9.3) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps): bump selenium from 4.28.0 to 4.28.1 (#1088) - [dependabot[bot], dependabot[bot]] - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.28.0 to 4.28.1. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/commits) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - update-type: version-update:semver-patch - ... -- Chore(deps-dev): update tox requirement from ~=4.23 to ~=4.24 (#1086) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.23.0...4.24.1) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Docs: update README.md. [Kazuaki Matsuo] -- Update changelog for 4.5.0. [Kazuaki Matsuo] - - -v4.5.0 (2025-01-22) -------------------- -- Bump 4.5.0. [Kazuaki Matsuo] -- Chore: update tags. [Kazuaki Matsuo] -- Chore(deps): bump selenium from 4.27.1 to 4.28.0 (#1084) [Kazuaki - Matsuo, dependabot[bot], dependabot[bot]] - - * chore(deps): bump selenium from 4.27.1 to 4.28.0 - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.27.1 to 4.28.0. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/commits/selenium-4.28.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.1 to ~=0.9.2 - (#1083) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.1...0.9.2) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.9.0 to ~=0.9.1 - (#1082) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.9.0...0.9.1) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.8.6 to ~=0.9.0 - (#1081) [Kazuaki Matsuo, dependabot[bot], dependabot[bot]] - - * chore(deps-dev): update ruff requirement from ~=0.8.6 to ~=0.9.0 - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.8.6...0.9.0) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.8.5 to ~=0.8.6 - (#1080) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.8.5...0.8.6) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.8.4 to ~=0.8.5 - (#1079) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/commits) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.8.3 to ~=0.8.4 - (#1078) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.8.3...0.8.4) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update ruff requirement from ~=0.8.1 to ~=0.8.3 - (#1074) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.8.1...0.8.3) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Update changelog for 4.4.0. [Kazuaki Matsuo] - - -v4.4.0 (2024-11-29) -------------------- - -New -~~~ -- Feat: Added typing for AppiumBy (#1071) [Brijesh] - - * feat: Added typing for AppiumBy types - - * fix: using single quotes - - * fix: adding selenium typing - - * fix: pipeline - -Other -~~~~~ -- Bump 4.4.0. [Kazuaki Matsuo] -- Chore: dump ruff. [Kazuaki Matsuo] -- Chore(deps): bump selenium from 4.27.0 to 4.27.1 (#1068) - [dependabot[bot], dependabot[bot]] - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.27.0 to 4.27.1. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/commits) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - update-type: version-update:semver-patch - ... -- Chore(deps): bump selenium from 4.26.1 to 4.27.0 (#1067) - [dependabot[bot], dependabot[bot]] - - Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.26.1 to 4.27.0. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/commits/selenium-4.27.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Chore(deps-dev): update ruff requirement from ~=0.7.3 to ~=0.7.4 - (#1063) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.7.3...0.7.4) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Update changelog for 4.3.0. [Kazuaki Matsuo] - - -v4.3.0 (2024-11-12) -------------------- - -New -~~~ -- Feat: support selenium 4.26+: support ClientConfig and refactoring - internal implementation (#1054) [Kazuaki Matsuo] - - * feat: require selenium 4.26+ - - * update executor command - - * add more code - - * tweak the init - - * tweak arguments - - * fix test - - * apply add_command - - * use add_command - - * add GLOBAL_DEFAULT_TIMEOUT - - * add a workaround fix - - * use 4.26.1 - - * remove possible redundant init - - * add warning - - * add todo - - * add description more - - * use Tuple or python 3.8 and lower - - * add example of ClientConfig - - * add read timeout example - - * update readme - - * correct headers - - * more timeout - - * simplify a bit - - * tweak the readme - - * docs: update the readme - - * get new headers - - * fix type for py3.8 - - * fix review - - * fix review, extract locator_converter - -Other -~~~~~ -- Bump 4.3.0. [Kazuaki Matsuo] -- Chore(deps-dev): update ruff requirement from ~=0.7.2 to ~=0.7.3 - (#1060) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.7.2...0.7.3) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore: update pre-commit (#1058) [Kazuaki Matsuo] - - * chore: update pre-commit - - * use proper pre-commit -- Chore(deps-dev): update ruff requirement from ~=0.7.0 to ~=0.7.2 - (#1057) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.7.0...0.7.2) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Docs: update CHANGELOG.rst. [Kazuaki Matsuo] -- Update changelog for 4.2.1. [Kazuaki Matsuo] - - -v4.2.1 (2024-10-31) -------------------- -- Bump 4.2.1. [Kazuaki Matsuo] -- Update changelog for 4.1.1. [Kazuaki Matsuo] - - -v4.1.1 (2024-10-31) -------------------- - -New -~~~ -- Feat: Add a separate function for service startup validation (#1038) - [Mykola Mokhnach] - -Test -~~~~ -- Test: cleanup func tests for ios more (#1036) [Kazuaki Matsuo] -- Test: cleanup ios (#1034) [Kazuaki Matsuo] -- Test: cleanup tests more (#1033) [Kazuaki Matsuo] - - * test: remove some functional test which is tested in unit tets - - * test: remvoe location tests - - * remove finger - - * remove more - - * more - - * more - - * cleanup more -- Test: cleanup test more (#1032) [Kazuaki Matsuo] - - * test: cleanup duplicated tests more - - * test: just remove existing ones -- Test: cleanup functional tests and move to unit test to CI stable - (#1024) [Kazuaki Matsuo] - -Other -~~~~~ -- Bump 4.1.1. [Kazuaki Matsuo] -- Chore: allow selenium binging up to 4.25 (#1055) [Kazuaki Matsuo] - - * chore: allow selenium binging up to 4.25 - - * use 4.25 - - * fix syntax -- Docs: update selenium compatibility matrix. [Kazuaki Matsuo] -- Docs: add options matrix in readme (#1046) [Kazuaki Matsuo] - - * docs: add options matrix in readme - - * chore: revert unnecessary change - - * docs: add tweak pathds -- Chore(deps-dev): update ruff requirement from ~=0.6.9 to ~=0.7.0 - (#1049) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [ruff](https://github.com/astral-sh/ruff) to permit the latest version. - - [Release notes](https://github.com/astral-sh/ruff/releases) - - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - - [Commits](https://github.com/astral-sh/ruff/compare/0.6.9...0.7.0) - - --- - updated-dependencies: - - dependency-name: ruff - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.22 to ~=4.23 (#1048) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.22.0...4.23.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.21 to ~=4.22 (#1047) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.21.0...4.22.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore: use ruff (isort, pylint and pyflakes) instead of individual - isort, pylint and black libraries (#1043) [Kazuaki Matsuo] - - * apply ruff format and check --fix - - * add .ruff.toml - - * remove unused rule - - * fix pypo - - * remove pylint etc - - * split lint and format - - * add check to call lint and format - - * add fix - - * modify prefix - - * tweak -- Chore(deps): update sphinx-rtd-theme requirement from <3.0 to <4.0 - (#1040) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) to permit the latest version. - - [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst) - - [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/0.1.8...3.0.0) - - --- - updated-dependencies: - - dependency-name: sphinx-rtd-theme - dependency-type: direct:production - ... -- Chore(deps): update selenium requirement from ~=4.24 to ~=4.25 (#1026) - [Mykola Mokhnach, dependabot[bot], dependabot[bot]] - - * chore(deps): update selenium requirement from ~=4.24 to ~=4.25 - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.24.0...selenium-4.25.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update pytest-cov requirement from ~=4.1 to ~=5.0 - (#975) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest-cov](https://github.com/pytest-dev/pytest-cov) to permit the latest version. - - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v4.1.0...v5.0.0) - - --- - updated-dependencies: - - dependency-name: pytest-cov - dependency-type: direct:development - ... -- Chore(deps): update sphinx requirement from <7.0,>=4.0 to >=4.0,<9.0 - (#1009) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [sphinx](https://github.com/sphinx-doc/sphinx) to permit the latest version. - - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - - [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES.rst) - - [Commits](https://github.com/sphinx-doc/sphinx/compare/v4.0.0...v8.0.2) - - --- - updated-dependencies: - - dependency-name: sphinx - dependency-type: direct:production - ... -- Chore: Use proper type declarations for methods returning self - instances (#1039) [Mykola Mokhnach] -- Chore(deps-dev): update tox requirement from ~=4.20 to ~=4.21 (#1037) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.20.0...4.21.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore: update precommit config. [Kazuaki Matsuo] -- Chore: update release script. [Kazuaki Matsuo] -- Update changelog for 4.2.0. [Kazuaki Matsuo] - - -v4.2.0 (2024-09-24) -------------------- - -New -~~~ -- Feat: Add flutter integration driver commands and tests (#1022) - [MummanaSubramanya] - -Fix -~~~ -- Add missing __init__.py (#1029) [Kazuaki Matsuo] - -Other -~~~~~ -- Chore(deps-dev): update tox requirement from ~=4.19 to ~=4.20 (#1021) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.19.0...4.20.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.18 to ~=4.19 (#1020) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.18.0...4.19.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Update README.md. [Kazuaki Matsuo] -- Chore(deps-dev): update pylint requirement from ~=3.2.6 to ~=3.2.7 - (#1019) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v3.2.6...v3.2.7) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.23 to ~=4.24 (#1018) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.23.0...selenium-4.24.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update black requirement from <24.0.0 to <25.0.0 - (#950) [Mykola Mokhnach, dependabot[bot], dependabot[bot]] - - * chore(deps-dev): update black requirement from <24.0.0 to <25.0.0 - - Updates the requirements on [black](https://github.com/psf/black) to permit the latest version. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/compare/18.3a0...24.1.0) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:development - ... -- Docs: modify readme. [Kazuaki Matsuo] -- Update changelog for 4.1.0. [Kazuaki Matsuo] - - -v4.1.0 (2024-08-17) -------------------- - -New -~~~ -- Feat: add app_path property ("appPath") to Mac2Options (#1014) - [Kazuaki Matsuo, a-fultz] - -Test -~~~~ -- Ci: moving to GHA (#1010) [Kazuaki Matsuo] - - * ci: run func_test_android4 - - * test: fix tests - - * fix tests - - * remove azure related - - * use assert - - * fix black lint - - * use python 3.12 - - * use newer python - - * use 3.9 for now - - * Revert "fix black lint" - - This reverts commit 228fe8a316d0bd361ead94ddb29da6f66abb7a09. - - * remove a new line -- Ci: run other android tests on GHA (#1008) [Kazuaki Matsuo] - - - ci: run other android tests on GHA a few more -- Ci: move Azure to GHA (Android) (#1007) [Kazuaki Matsuo] - - * ci: move Azure to GHA (Android) - -Other -~~~~~ -- Bump 4.1.0. [Kazuaki Matsuo] -- Chore(deps-dev): update tox requirement from ~=4.16 to ~=4.18 (#1013) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.16.0...4.18.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Docs: replace badge source (#1012) [Kazuaki Matsuo] -- Chore(deps-dev): update pylint requirement from ~=3.2.5 to ~=3.2.6 - (#1005) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v3.2.5...v3.2.6) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore: remove non-reference variables, import and fix test names to - run them properly (#1006) [Kazuaki Matsuo] -- Chore(deps-dev): update pytest requirement from ~=8.2 to ~=8.3 (#1004) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest/releases) - - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest/compare/8.2.0...8.3.1) - - --- - updated-dependencies: - - dependency-name: pytest - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=3.2.2 to ~=3.2.5 - (#1000) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v3.2.2...v3.2.5) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.15 to ~=4.16 (#1002) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.15.0...4.16.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.22 to ~=4.23 (#1003) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.22.0...selenium-4.23.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Update changelog for 4.0.1. [Kazuaki Matsuo] - - -v4.0.1 (2024-07-09) -------------------- - -Fix -~~~ -- Typo and update test (#992) [Kazuaki Matsuo] - - * docs: fix typo - - * fix more typos - - * test: fix one test - -Test -~~~~ -- Ci: enable trigger. [Kazuaki Matsuo] -- Ci: Bump conventional-pr-action to v3 (#989) [Mykola Mokhnach] -- Ci: use gha instead of Azure for iOS in Azure (#987) [Kazuaki Matsuo] - - ci: use gha instead of Azure for iOS in Azure -- Ci: move the file. [Kazuaki Matsuo] -- Ci: add initial gha to run by manual (#984) [Kazuaki Matsuo] - -Other -~~~~~ -- Bump 4.0.1. [Kazuaki Matsuo] -- Chore: Add mobile: replacements to clipboard API wrappers (#998) - [Mykola Mokhnach] - - * chore: Add mobile: replacements to clipboard API wrappers - - * Fix order - - * update tests -- Chore(deps): update selenium requirement from ~=4.21 to ~=4.22 (#996) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.21.0...selenium-4.22.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update pylint requirement from ~=3.1.0 to ~=3.2.2 - (#993) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v3.1.0...v3.2.2) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.20 to ~=4.21 (#991) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.20.0...selenium-4.21.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Docs: missing appium python client version in the compatibility - matrix. [Kazuaki Matsuo] -- Chore(deps): update sphinx-rtd-theme requirement from <2.0 to <3.0 - (#935) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) to permit the latest version. - - [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst) - - [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/0.1.8...2.0.0) - - --- - updated-dependencies: - - dependency-name: sphinx-rtd-theme - dependency-type: direct:production - ... -- Chore(deps-dev): update tox requirement from ~=4.14 to ~=4.15 (#982) - [Kazuaki Matsuo, dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.14.0...4.15.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Docs: update docstring (#986) [Kazuaki Matsuo] -- Chore(deps-dev): update pytest requirement from ~=8.1 to ~=8.2 (#983) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest/releases) - - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest/compare/8.1.0...8.2.0) - - --- - updated-dependencies: - - dependency-name: pytest - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.19 to ~=4.20 (#981) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.19.0...selenium-4.20.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore: remove IOS_UIAUTOMATION (#979) [zeufack] -- Chore(deps): update selenium requirement from ~=4.18 to ~=4.19 (#976) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.18.0...selenium-4.19.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update types-python-dateutil requirement (#973) - [dependabot[bot], dependabot[bot]] - - --- - updated-dependencies: - - dependency-name: types-python-dateutil - dependency-type: direct:development - ... -- Update changelog for 4.0.0. [Kazuaki Matsuo] - - -v4.0.0 (2024-03-12) -------------------- - -New -~~~ -- Feat: remove MultiAction and TouchAction (#960) [Kazuaki Matsuo] - - BREAKING CHANGE: Remove MultiAction and TouchAction as non-w3c WebDriver-defined methods. Please use w3c actions instead. - -Other -~~~~~ -- Bump 4.0.0. [Kazuaki Matsuo] -- Chore(deps-dev): update tox requirement from ~=4.13 to ~=4.14 (#972) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.13.0...4.14.1) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.12 to ~=4.13 (#957) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.12.0...4.13.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update pytest requirement from ~=8.0 to ~=8.1 (#969) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest/releases) - - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest/compare/8.0.0...8.1.0) - - --- - updated-dependencies: - - dependency-name: pytest - dependency-type: direct:development - ... -- Docs: update readme. [Kazuaki Matsuo] -- Chore: remove deprecated AppiumBy.WINDOWS_UI_AUTOMATION (#968) - [Kazuaki Matsuo] -- Chore(deps-dev): update python-dateutil requirement from ~=2.8 to - ~=2.9 (#967) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [python-dateutil](https://github.com/dateutil/dateutil) to permit the latest version. - - [Release notes](https://github.com/dateutil/dateutil/releases) - - [Changelog](https://github.com/dateutil/dateutil/blob/master/NEWS) - - [Commits](https://github.com/dateutil/dateutil/compare/2.8.0...2.9.0) - - --- - updated-dependencies: - - dependency-name: python-dateutil - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=3.0.3 to ~=3.1.0 - (#966) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v3.0.3...v3.1.0) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Update changelog for 3.2.1. [Kazuaki Matsuo] - - -v3.2.1 (2024-02-26) -------------------- - -Fix -~~~ -- Unclosed file <_io.BufferedReader name error by proper cleanup of - subprocess.Popen process (#965) [WrrngnCode] - - https://github.com/appium/python-client/issues/962 - add a Popen.communicate call after terminate to ensure that file stdout and sdterr file descriptors are closed properly. - -Other -~~~~~ -- Bump 3.2.1. [Kazuaki Matsuo] -- Update changelog for 3.2.0. [Kazuaki Matsuo] - - -v3.2.0 (2024-02-24) -------------------- - -New -~~~ -- Feat: add pause in drag_and_drop (#961) [Kazuaki Matsuo] - - * feat: add pause in drag_and_drop - - * docs: tweak docstring - - * Update action_helpers.py - - * apply pause only when the value is not negative - -Fix -~~~ -- Add return self in MultiAction#add (#964) [Kazuaki Matsuo] - -Other -~~~~~ -- Bump 3.2.0. [Kazuaki Matsuo] -- Chore(deps): update selenium requirement from ~=4.17 to ~=4.18 (#958) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.17.0...selenium-4.18.1) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update pytest requirement from ~=7.4 to ~=8.0 (#953) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest/releases) - - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest/compare/7.4.0...8.0.0) - - --- - updated-dependencies: - - dependency-name: pytest - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.15 to ~=4.17 (#948) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.15.0...selenium-4.17.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Docs: update W3C actions example in readme (#946) [Dor Blayzer] -- Chore(deps-dev): update tox requirement from ~=4.11 to ~=4.12 (#947) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.11.0...4.12.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Docs: update example in readme (#945) [Kazuaki Matsuo] -- Docs: update links (#944) [Kazuaki Matsuo] -- Update changelog for 3.1.1. [Kazuaki Matsuo] - - -v3.1.1 (2023-12-15) -------------------- - -Fix -~~~ -- Typo in ActionHelpers (#937) [kkb912002] - - touc -> touch -- Self.command_executor instance in _update_command_executor (#940) - [Kazuaki Matsuo] - -Other -~~~~~ -- Bump 3.1.1. [Kazuaki Matsuo] -- Chore(deps-dev): update pylint requirement from ~=3.0.1 to ~=3.0.3 - (#939) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v3.0.1...v3.0.3) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.14 to ~=4.15 (#933) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.14.0...selenium-4.15.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Docs: address options in the migration guide (#929) [Kazuaki Matsuo] - - * docs: adress options in the migration guide - - * Update README.md - - * Update README.md -- Docs: update changelog. [Kazuaki Matsuo] -- Update changelog for 3.1.0. [Kazuaki Matsuo] - - -v3.1.0 (2023-10-13) -------------------- - -New -~~~ -- Feat: Add missing platformVersion and browserName options (#925) - [Mykola Mokhnach] - -Test -~~~~ -- Ci: Use appium from the release branch. [Mykola Mokhnach] - -Other -~~~~~ -- Bump 3.1.0. [Kazuaki Matsuo] -- Chore(deps): update selenium requirement from ~=4.13 to ~=4.14 (#923) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.13.0...selenium-4.14.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update pylint requirement from ~=2.17.5 to ~=3.0.1 - (#922) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v2.17.5...v3.0.1) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.12 to ~=4.13 (#915) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.12.0...selenium-4.13.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Docs: update README.md for v3 (#912) [Kazuaki Matsuo] - - * docs: update README.md - - * Update README.md -- Update changelog for 3.0.0. [Kazuaki Matsuo] - - -v3.0.0 (2023-09-08) -------------------- - -New -~~~ -- Feat!: Update selenium dependency to 4.12 (#908) [Mykola Mokhnach] - - BREAKING CHANGE: The minimum supported Python version set to 3.8 - BREAKING CHANGE: The minimum supported selenium version set to 4.12 - -Fix -~~~ -- Handle the situation where payload is already a dictionary (#892) - [Mykola Mokhnach] -- Add missing dependencies for types-python-dateutil (#891) [Dor - Blayzer] - - * fix: Add missing dependencies for types-python-dateutil - - * test: replace usage of selendroid app from 'test_install_app' in applications_tests.py - - * Revert "test: replace usage of selendroid app from 'test_install_app' in applications_tests.py" - - This reverts commit dcdf08b67d24257700923c89ae2643f26af2892f. - -Test -~~~~ -- Test: selendroid cleanup (#895) [Dor Blayzer] - - * test: replace usage of selendroid app from 'test_install_app' in applications_tests.py - - * test: remove unused import pytest from applications_tests.py - - * test: fix broken TestContextSwitching by replacing selendroid with ApiDemos - - * test: remove selendroid-test-app.apk from apps folder -- Ci: add pylint_quotes for pylint to use single quote as primary method - (#886) [Kazuaki Matsuo] - -Other -~~~~~ -- Bump 3.0.0. [Kazuaki Matsuo] -- Chore(deps-dev): update tox requirement from ~=4.8 to ~=4.11 (#906) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.8.0...4.11.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Refactor!: remove several previously deprecated APIs (#909) [Mykola - Mokhnach] - - BREAKING CHANGE: Removed obsolete all_sessions and session properties - BREAKING CHANGE: Removed the obsolete start_activity method - BREAKING CHANGE: Removed the obsolete end_test_coverage method - BREAKING CHANGE: Removed the following obsolete arguments from the driver constructor: desired_capabilities, browser_profile, proxy - BREAKING CHANGE: Removed obsolete set_value and set_text methods - BREAKING CHANGE: Removed the obsolete MobileBy class - BREAKING CHANGE: Removed obsolete application management methods: launch_app, close_app, reset - BREAKING CHANGE: Removed obsolete IME methods: available_ime_engines, is_ime_active, activate_ime_engine, deactivate_ime_engine, active_ime_engine -- Chore(deps-dev): update tox requirement from ~=4.6 to ~=4.8 (#902) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.6.0...4.8.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.10 to ~=4.11 (#899) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/commits) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update pylint requirement from ~=2.17.3 to ~=2.17.5 - (#897) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - - [Release notes](https://github.com/pylint-dev/pylint/releases) - - [Commits](https://github.com/pylint-dev/pylint/compare/v2.17.3...v2.17.5) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Docs: Update README.md (#898) [Dor Blayzer] - - Some typos and grammar fixes -- Chore(deps-dev): update mock requirement from ~=5.0 to ~=5.1 (#893) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [mock](https://github.com/testing-cabal/mock) to permit the latest version. - - [Changelog](https://github.com/testing-cabal/mock/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/testing-cabal/mock/compare/5.0.0...5.1.0) - - --- - updated-dependencies: - - dependency-name: mock - dependency-type: direct:development - ... -- Chore: run pre-commit autoupdate (#890) [Kazuaki Matsuo] -- Chore: update isort revision to 5.12.0 (#889) [Dor Blayzer] -- Chore(deps-dev): update pytest requirement from ~=7.2 to ~=7.4 (#884) - [dependabot[bot]] -- Chore(deps-dev): update typing-extensions requirement (#885) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing_extensions) to permit the latest version. - - [Release notes](https://github.com/python/typing_extensions/releases) - - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - - [Commits](https://github.com/python/typing_extensions/compare/4.6.0...4.7.0) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-type: direct:development - ... -- Docs: update changelogs and version. [Kazuaki Matsuo] - - -v2.11.1 (2023-06-13) --------------------- -- Revert "chore: remove duplicated clean command" (#881) [Kazuaki - Matsuo] - - * Revert "chore: remove duplicated clean command (#809)" - - This reverts commit 2f45ef935c12dec2ab8de044ce6a1c1e0b9aa46f. - - * chore: left a comment - - * trim spaces -- Update changelog. [Kazuaki Matsuo] - - -v2.11.0 (2023-06-09) --------------------- - -New -~~~ -- Feat: make the UA format with same as other clients (#793) [Kazuaki - Matsuo] - - * chore: set version with / - - * chore: update comment - - * update test - - * update tests - -Other -~~~~~ -- Update changelog for 2.10.2. [Kazuaki Matsuo] - - -v2.10.2 (2023-06-08) --------------------- - -Fix -~~~ -- Update the constructor for compatibility with python client 4.10 - (#879) [Mykola Mokhnach] - -Test -~~~~ -- Ci: add py11 for the unit test (#875) [Kazuaki Matsuo] - -Other -~~~~~ -- Bump 2.10.2. [Kazuaki Matsuo] -- Chore: remove duplicated clean command (#809) [Kazuaki Matsuo] - - * remove clear - - * remove clear more -- Chore(deps-dev): update tox requirement from ~=4.5 to ~=4.6 (#877) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.5.0...4.6.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Docs: address version management recommendation in the readme (#874) - [Kazuaki Matsuo] - - * chore: set the max selenium deps version - - * ci: add python 11 - - * Update unit-test.yml - - * add note in the readme - - * Update README.md - - * docs: merge the matrix pr into README.md -- Docs: Improve usage examples (#873) [Mykola Mokhnach] -- Chore(deps-dev): update pytest-cov requirement from ~=4.0 to ~=4.1 - (#872) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest-cov](https://github.com/pytest-dev/pytest-cov) to permit the latest version. - - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v4.0.0...v4.1.0) - - --- - updated-dependencies: - - dependency-name: pytest-cov - dependency-type: direct:development - ... -- Chore(deps-dev): update typing-extensions requirement (#871) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing_extensions) to permit the latest version. - - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - - [Commits](https://github.com/python/typing_extensions/compare/4.5.0...4.6.0) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-type: direct:development - ... -- Chore: nump the version. [Kazuaki Matsuo] -- Update changelog for 2.10.1. [Kazuaki Matsuo] - - -v2.10.1 (2023-05-20) --------------------- - -Fix -~~~ -- W3C errors to exception classes mapping (#869) [Mykola Mokhnach] - - * fix: W3C errors to exception classes mapping - - * Imports - - * Tune - -Other -~~~~~ -- Chrom: bump the version. [Kazuaki Matsuo] -- Update changelog for 2.10.0. [Kazuaki Matsuo] - - -v2.10.0 (2023-05-11) --------------------- - -Fix -~~~ -- Update connection manager creation (#864) [Mykola Mokhnach] - -Other -~~~~~ -- Refactor: Move driver-specific commands to use extensions (part2) - (#859) [Mykola Mokhnach] -- Chore(deps): update selenium requirement from ~=4.7 to ~=4.9 (#852) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.7.0...selenium-4.9.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Refactor: Move driver-specific commands to use extensions (part1) - (#856) [Mykola Mokhnach] -- Chore(deps-dev): update pylint requirement from ~=2.17.2 to ~=2.17.3 - (#853) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.17.2...v2.17.3) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.4 to ~=4.5 (#854) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.4.0...4.5.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update mypy requirement from ~=1.1 to ~=1.2 (#848) - [dependabot[bot]] -- Chore(deps-dev): update pylint requirement from ~=2.17.1 to ~=2.17.2 - (#847) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.17.1...v2.17.2) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore: bump and correct version. [Kazuaki Matsuo] -- Update changelog for 2.9.0. [Kazuaki Matsuo] - - -v2.9.0 (2023-04-02) -------------------- - -New -~~~ -- Feat: respect the given executor (#844) [Kazuaki Matsuo] - - * feat: can provide a custom connection - - * add tests - - * tweak tests - - * lint - - * tweak - - * add comment - - * fix lint - - * tweak - - * add test - - * tweak review - -Fix -~~~ -- Set_value and set_text sent incorrect data (#831) [eyJhb] - -Other -~~~~~ -- Update changelog for 2.8.0. [Kazuaki Matsuo] -- Chore(deps-dev): update pylint requirement from ~=2.17.0 to ~=2.17.1 - (#843) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.17.0...v2.17.1) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.16.3 to ~=2.17.0 - (#838) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.16.3...v2.17.0) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update mypy requirement from ~=1.0 to ~=1.1 (#836) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v1.0.0...v1.1.1) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.16.2 to ~=2.16.3 - (#834) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.16.2...v2.16.3) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update typing-extensions requirement (#830) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing_extensions) to permit the latest version. - - [Release notes](https://github.com/python/typing_extensions/releases) - - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - - [Commits](https://github.com/python/typing_extensions/compare/4.4.0...4.5.0) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.16.1 to ~=2.16.2 - (#829) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.16.1...v2.16.2) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update mypy requirement from ~=0.991 to ~=1.0 (#828) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.991...v1.0.0) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.16.0 to ~=2.16.1 - (#827) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.16.0...v2.16.1) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.10 to ~=2.16.0 - (#826) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.10...v2.16.0) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.3 to ~=4.4 (#823) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.3.0...4.4.2) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Update changelog for 2.8.1. [Kazuaki Matsuo] - - -v2.8.1 (2023-01-20) -------------------- - -New -~~~ -- Feat: add status tentatively (#820) [Kazuaki Matsuo] - - * feat: add status tentatively - - * update test - - * fix docstring - - * fix typo - - * fix lint - - -v2.8.0 (2023-01-20) -------------------- - -New -~~~ -- Feat: add status tentatively. [Kazuaki Matsuo] - -Fix -~~~ -- Fix lint. [Kazuaki Matsuo] -- Fix typo. [Kazuaki Matsuo] -- Fix docstring. [Kazuaki Matsuo] - -Other -~~~~~ -- Update test. [Kazuaki Matsuo] -- Chore(deps-dev): update tox requirement from ~=4.2 to ~=4.3 (#817) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.2.0...4.3.1) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps): update sphinx requirement from <6.0,>=4.0 to >=4.0,<7.0 - (#814) [dependabot[bot]] -- Chore(deps-dev): update pylint requirement from ~=2.15.9 to ~=2.15.10 - (#816) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.9...v2.15.10) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.1 to ~=4.2 (#815) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.1.0...4.2.1) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=4.0 to ~=4.1 (#813) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/4.0.0...4.1.1) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update mock requirement from ~=4.0 to ~=5.0 (#812) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [mock](https://github.com/testing-cabal/mock) to permit the latest version. - - [Release notes](https://github.com/testing-cabal/mock/releases) - - [Changelog](https://github.com/testing-cabal/mock/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/testing-cabal/mock/compare/4.0.0...5.0.0) - - --- - updated-dependencies: - - dependency-name: mock - dependency-type: direct:development - ... -- Chore(deps-dev): update pre-commit requirement from ~=2.20 to ~=2.21 - (#811) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.20.0...v2.21.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.8 to ~=2.15.9 - (#810) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.8...v2.15.9) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update isort requirement from ~=5.10 to ~=5.11 (#808) - [Kazuaki Matsuo, dependabot[bot], dependabot[bot]] - - Updates the requirements on [isort](https://github.com/pycqa/isort) to permit the latest version. - - [Release notes](https://github.com/pycqa/isort/releases) - - [Changelog](https://github.com/PyCQA/isort/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pycqa/isort/compare/5.10.0...5.11.1) - - --- - updated-dependencies: - - dependency-name: isort - dependency-type: direct:development - ... -- Chore(deps-dev): update black requirement from ~=22.10.0 to ~=22.12.0 - (#807) [Kazuaki Matsuo, dependabot[bot], dependabot[bot]] - - Updates the requirements on [black](https://github.com/psf/black) to permit the latest version. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/compare/22.10.0...22.12.0) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=3.27 to ~=4.0 (#806) - [Kazuaki Matsuo, dependabot[bot], dependabot[bot]] - - * chore(deps-dev): update tox requirement from ~=3.27 to ~=4.0 - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.27.0...4.0.2) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.7 to ~=2.15.8 - (#804) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.7...v2.15.8) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.5 to ~=4.7 (#801) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.5.0...selenium-4.7.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.6 to ~=2.15.7 - (#800) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.6...v2.15.7) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.5 to ~=2.15.6 - (#799) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.5...v2.15.6) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore: update docstring in touch_action.py (#797) [Kazuaki Matsuo, - wojciodataist] - - add detailed information to long_press duration param -- Chore(deps-dev): update mypy requirement from ~=0.982 to ~=0.991 - (#798) [Kazuaki Matsuo, dependabot[bot], dependabot[bot]] - - * chore(deps-dev): update mypy requirement from ~=0.982 to ~=0.991 - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.982...v0.991) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:development - ... -- Chore(deps-dev): update tox requirement from ~=3.26 to ~=3.27 (#792) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.26.0...3.27.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:development - ... -- Chore(deps-dev): update pytest requirement from ~=7.1 to ~=7.2 (#791) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest/releases) - - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest/compare/7.1.0...7.2.0) - - --- - updated-dependencies: - - dependency-name: pytest - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.4 to ~=2.15.5 - (#790) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.4...v2.15.5) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.3 to ~=2.15.4 - (#788) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.3...v2.15.4) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Chore: update precommit (#787) [Kazuaki Matsuo] -- Update changelog for 2.7.1. [Kazuaki Matsuo] -- Bump 2.7.1. [Kazuaki Matsuo] - - -v2.7.1 (2022-10-11) -------------------- - -Test -~~~~ -- Ci: run unit tests on actions (#773) [Kazuaki Matsuo] - - * ci: run unit tests on actions - - * ci: remove unit test section - - * ci: comment out win for now - - * ci: tweak trigger - -Other -~~~~~ -- Refactor: Make service startup failures more helpful (#786) [Mykola - Mokhnach] -- Chore(deps-dev): update typing-extensions requirement (#783) [Kazuaki - Matsuo, dependabot[bot], dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing_extensions) to permit the latest version. - - [Release notes](https://github.com/python/typing_extensions/releases) - - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - - [Commits](https://github.com/python/typing_extensions/compare/4.3.0...4.4.0) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-type: direct:development - ... -- Chore(deps-dev): update black requirement from ~=22.8.0 to ~=22.10.0 - (#784) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [black](https://github.com/psf/black) to permit the latest version. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/compare/22.8.0...22.10.0) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:development - ... -- Chore(deps-dev): update mypy requirement from ~=0.981 to ~=0.982 - (#782) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.981...v0.982) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:development - ... -- Chore(deps-dev): update pytest-cov requirement from ~=3.0 to ~=4.0 - (#779) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pytest-cov](https://github.com/pytest-dev/pytest-cov) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest-cov/releases) - - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v3.0.0...v4.0.0) - - --- - updated-dependencies: - - dependency-name: pytest-cov - dependency-type: direct:development - ... -- Chore(deps): update selenium requirement from ~=4.4 to ~=4.5 (#780) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.4.0...selenium-4.5.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps-dev): update mypy requirement from ~=0.971 to ~=0.981 - (#777) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.971...v0.981) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:development - ... -- Chore(deps-dev): update pylint requirement from ~=2.15.2 to ~=2.15.3 - (#774) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.2...v2.15.3) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:development - ... -- Bump 2.7.0. [Kazuaki Matsuo] -- Update changelog for 2.6.3. [Kazuaki Matsuo] - - -v2.7.0 (2022-09-22) -------------------- - -New -~~~ -- Feat: Add appArguments option to WindowsOptions (#768) [Mykola - Mokhnach] - -Fix -~~~ -- Move dev-only dependencies to [dev-packages] section (#772) [Mykola - Mokhnach] - -Test -~~~~ -- Ci: Fix runner name. [Mykola Mokhnach] - -Other -~~~~~ -- Chore(deps): update pylint requirement from ~=2.15.2 to ~=2.15.3 - (#770) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.2...v2.15.3) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Docs: Update changelog for 2.6.2. [Kazuaki Matsuo] - - -v2.6.2 (2022-09-16) -------------------- - -Fix -~~~ -- Use total_seconds property of timedelta (#767) [Mykola Mokhnach] - -Test -~~~~ -- Ci: Update Conventional Commits config preset. [Mykola Mokhnach] -- Ci: Add Conventional commit format validation (#764) [Mykola Mokhnach] - - * ci: Add Conventional commit format validation - - * Rename - -Other -~~~~~ -- Chore(deps): update tox requirement from ~=3.25 to ~=3.26 (#766) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.25.0...3.26.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:production - ... -- Chore(deps): update pylint requirement from ~=2.15.0 to ~=2.15.2 - (#765) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.15.0...v2.15.2) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Chore(deps): update astroid requirement from ~=2.9 to ~=2.12 (#762) - [dependabot[bot], dependabot[bot]] - - Updates the requirements on [astroid](https://github.com/PyCQA/astroid) to permit the latest version. - - [Release notes](https://github.com/PyCQA/astroid/releases) - - [Changelog](https://github.com/PyCQA/astroid/blob/main/ChangeLog) - - [Commits](https://github.com/PyCQA/astroid/compare/v2.9.0...v2.12.5) - - --- - updated-dependencies: - - dependency-name: astroid - dependency-type: direct:production - ... -- Chore(deps): bump black from 22.6.0 to 22.8.0 (#763) [dependabot[bot], - dependabot[bot]] - - Bumps [black](https://github.com/psf/black) from 22.6.0 to 22.8.0. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/compare/22.6.0...22.8.0) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Chore(deps): update pylint requirement from ~=2.14.5 to ~=2.15.0 - (#761) [dependabot[bot], dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.14.5...v2.15.0) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Docs: Update changelog for 2.6.1. [Kazuaki Matsuo] - - -v2.6.1 (2022-08-11) -------------------- - -Fix -~~~ -- Fix options in mac2 (#759) [Kazuaki Matsuo] -- Backwards compatible behaviour of swipe and scroll in action_helpers - (#744) [jatalahd] - - * Backwards compatible behaviour of swipe and scroll in action_helpers - - - Fixed handling the duration argument in swipe() and scroll() helpers - - Functionality is now the same as in older versions using TouchActions - - Fixes #743 - - * Backwards compatible behaviour of swipe and scroll in action_helpers - - - Fixed handling the duration argument in swipe() and scroll() helpers - - Functionality is now the same as in older versions using TouchActions - - Fixes #743 - - * Backwards compatible behaviour of swipe and scroll in action_helpers - - - Fixed handling the duration argument in swipe() and scroll() helpers - - Functionality is now the same as in older versions using TouchActions - - Fixes #743 - - * Backwards compatible behaviour of swipe and scroll in action_helpers - - - Fixed handling the duration argument in swipe() and scroll() helpers - - Functionality is now the same as in older versions using TouchActions - - Fixes #743 - - * Backwards compatible behaviour of swipe and scroll in action_helpers - - - Fixed handling the duration argument in swipe() and scroll() helpers - - Functionality is now the same as in older versions using TouchActions - - Fixes #743 -- Move py.typed to the hierarchy root (#751) [Mykola Mokhnach] -- Typos/copypaste in various options (#750) [Mykola Mokhnach] - -Other -~~~~~ -- Chore(deps): update selenium requirement from ~=4.3 to ~=4.4 (#757) - [dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.3.0...selenium-4.4.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps): update mypy requirement from ~=0.961 to ~=0.971 (#749) - [dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.961...v0.971) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:production - ... -- Chore(deps): update pylint requirement from ~=2.14.4 to ~=2.14.5 - (#747) [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.14.4...v2.14.5) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Chore(deps-dev): update pre-commit requirement from ~=2.19 to ~=2.20 - (#746) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.19.0...v2.20.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Chore(deps): update typing-extensions requirement from ~=4.2 to ~=4.3 - (#745) [dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing_extensions) to permit the latest version. - - [Release notes](https://github.com/python/typing_extensions/releases) - - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - - [Commits](https://github.com/python/typing_extensions/compare/4.2.0...4.3.0) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-type: direct:production - ... -- Chore(deps): update pylint requirement from ~=2.14.3 to ~=2.14.4 - (#742) [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.14.3...v2.14.4) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Docs: Update changelog for 2.6.0. [Kazuaki Matsuo] - - -v2.6.0 (2022-06-28) -------------------- - -New -~~~ -- Feat: Add Android drivers options (#740) [Mykola Mokhnach] - -Other -~~~~~ -- Chore(deps): bump black from 22.3.0 to 22.6.0 (#741) [dependabot[bot]] - - Bumps [black](https://github.com/psf/black) from 22.3.0 to 22.6.0. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/compare/22.3.0...22.6.0) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Chore: Improve autocompletion for methods returning self instance - (#739) [Mykola Mokhnach] -- Refactor: Remove previously deprecated methods and mark - reset/close/launch APIs as deprecated (#738) [Mykola Mokhnach] -- Docs: Update changelog for 2.5.0. [Kazuaki Matsuo] - - -v2.5.0 (2022-06-25) -------------------- - -New -~~~ -- Feat: Add xcuitest driver options (#737) [Mykola Mokhnach] -- Feat: Add Gecko driver options (#735) [Mykola Mokhnach] -- Feat: Add Windows driver options (#732) [Mykola Mokhnach] -- Feat: Add Safari driver options (#731) [Mykola Mokhnach] -- Feat: Add Mac2Driver options (#730) [Mykola Mokhnach] - -Other -~~~~~ -- Chore(deps): update selenium requirement from ~=4.2 to ~=4.3 (#736) - [dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.2.0...selenium-4.3.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps): update pylint requirement from ~=2.14.2 to ~=2.14.3 - (#733) [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.14.2...v2.14.3) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Refactor: Make system_port and system_host options common (#734) - [Mykola Mokhnach] -- Chore(deps): update pylint requirement from ~=2.14.1 to ~=2.14.2 - (#725) [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.14.1...v2.14.2) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Chore: bump version to 2.4.0. [Kazuaki Matsuo] -- Chore(deps): update pylint requirement from ~=2.14.1 to ~=2.14.2 - (#725) [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.14.1...v2.14.2) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... - - -v2.4.0 (2022-06-17) -------------------- - -New -~~~ -- Feat: Add common options (#728) [Mykola Mokhnach] - -Other -~~~~~ -- Chore: Add better error handling for session creation responses (#727) - [Mykola Mokhnach] -- Docs: Update changelog for 2.3.0. [Kazuaki Matsuo] -- Bump 2.3.0. [Kazuaki Matsuo] -- Chore: Update comments to locator patches (#724) [VladimirPodolyan] - - * Update webelement.py - - * update comment section - - * CR fixes - - -v2.3.0 (2022-06-13) -------------------- - -New -~~~ -- Feat: Add base options for all supported automation names (#721) - [Mykola Mokhnach] -- Feat: Add support for w3c options (#720) [Mykola Mokhnach] - -Test -~~~~ -- Test: Use Appium2 to run functional tests (#723) [Mykola Mokhnach] - -Other -~~~~~ -- Docs: Update README with the new options format (#722) [Mykola - Mokhnach] -- Chore(deps): update mypy requirement from ~=0.960 to ~=0.961 (#718) - [dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.960...v0.961) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:production - ... -- Chore: Disable pylint checks fail CI (#719) [Mykola Mokhnach] -- Chore(deps): update selenium requirement from ~=4.1 to ~=4.2 (#715) - [dependabot[bot]] - - Updates the requirements on [selenium](https://github.com/SeleniumHQ/Selenium) to permit the latest version. - - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.1.0...selenium-4.2.0) - - --- - updated-dependencies: - - dependency-name: selenium - dependency-type: direct:production - ... -- Chore(deps): update sphinx requirement from <5.0,>=4.0 to >=4.0,<6.0 - (#716) [dependabot[bot]] - - Updates the requirements on [sphinx](https://github.com/sphinx-doc/sphinx) to permit the latest version. - - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - - [Changelog](https://github.com/sphinx-doc/sphinx/blob/5.x/CHANGES) - - [Commits](https://github.com/sphinx-doc/sphinx/compare/v4.0.0...v5.0.0) - - --- - updated-dependencies: - - dependency-name: sphinx - dependency-type: direct:production - ... -- Chore(deps): update mypy requirement from ~=0.950 to ~=0.960 (#714) - [dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.950...v0.960) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:production - ... -- Chore(deps-dev): update pre-commit requirement from ~=2.18 to ~=2.19 - (#713) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.18.0...v2.19.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Chore(deps): update mypy requirement from ~=0.942 to ~=0.950 (#712) - [dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.942...v0.950) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:production - ... -- Chore(deps): update typing-extensions requirement from ~=4.1 to ~=4.2 - (#711) [dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing) to permit the latest version. - - [Release notes](https://github.com/python/typing/releases) - - [Changelog](https://github.com/python/typing/blob/master/typing_extensions/CHANGELOG) - - [Commits](https://github.com/python/typing/compare/4.1.0...4.2.0) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-type: direct:production - ... -- Chore(deps): update tox requirement from ~=3.24 to ~=3.25 (#709) - [dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.24.0...3.25.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:production - ... -- Chore(deps-dev): update pre-commit requirement from ~=2.17 to ~=2.18 - (#708) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.17.0...v2.18.1) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Update changelog for 2.2.0. [Kazuaki Matsuo] - - -v2.2.0 (2022-03-30) -------------------- - -New -~~~ -- Feat: add non-w3c but still need commands (#701) [Kazuaki Matsuo] - - * add non-w3c but still need commands - - * fix id as $ - -Other -~~~~~ -- Bump 2.2.0. [Kazuaki Matsuo] -- Chore(deps): bump black from 22.1.0 to 22.3.0 (#705) [dependabot[bot]] - - Bumps [black](https://github.com/psf/black) from 22.1.0 to 22.3.0. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/compare/22.1.0...22.3.0) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:production - update-type: version-update:semver-minor - ... -- Revert: pylint (#706) [Kazuaki Matsuo] -- Chore: relax selenium version as same as before. [Kazuaki Matsuo] -- Chore(deps): update mypy requirement from ~=0.941 to ~=0.942 (#703) - [dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.941...v0.942) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:production - ... -- Chore(deps): update pylint requirement from ~=2.12 to ~=2.13 (#702) - [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Changelog](https://github.com/PyCQA/pylint/blob/main/ChangeLog) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.12.0...v2.13.0) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Chore(deps): update mypy requirement from ~=0.930 to ~=0.941 (#696) - [dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.930...v0.941) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:production - ... -- Chore(deps): update typing-extensions requirement from ~=4.0 to ~=4.1 - (#684) [dependabot[bot]] - - Updates the requirements on [typing-extensions](https://github.com/python/typing) to permit the latest version. - - [Release notes](https://github.com/python/typing/releases) - - [Changelog](https://github.com/python/typing/blob/master/typing_extensions/CHANGELOG) - - [Commits](https://github.com/python/typing/compare/4.0.0...4.1.1) - - --- - updated-dependencies: - - dependency-name: typing-extensions - dependency-type: direct:production - ... -- Chore(deps): update pytest requirement from ~=7.0 to ~=7.1 (#694) - [dependabot[bot]] - - Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest/releases) - - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest/compare/7.0.0...7.1.0) - - --- - updated-dependencies: - - dependency-name: pytest - dependency-type: direct:production - ... -- Docs: update missing changelog. [Kazuaki Matsuo] - - -v2.1.4 (2022-02-28) -------------------- -- Bump 2.1.4. [Kazuaki Matsuo] -- Update changelog for 2.1.3. [Kazuaki Matsuo] - - -v2.1.3 (2022-02-26) -------------------- - -Test -~~~~ -- Test: update tests to use find_element(by...) (#674) [Kazuaki Matsuo] - - * test: update find element/s methods - - * fix arguments - - * fix default value - -Other -~~~~~ -- Bump 2.1.3. [Kazuaki Matsuo] -- Chore: restrict selenium client version (#686) [Kazuaki Matsuo] -- Chore(deps): bump black from 21.12b0 to 22.1.0 (#681) - [dependabot[bot]] - - Bumps [black](https://github.com/psf/black) from 21.12b0 to 22.1.0. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/commits/22.1.0) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:production - ... -- Chore(deps): update pytest requirement from ~=6.2 to ~=7.0 (#682) - [dependabot[bot]] - - Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest/releases) - - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest/compare/6.2.0...7.0.0) - - --- - updated-dependencies: - - dependency-name: pytest - dependency-type: direct:production - ... -- Chore(deps-dev): update pre-commit requirement from ~=2.16 to ~=2.17 - (#678) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.16.0...v2.17.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Refactor: Update types descriptions for mixin classes (#677) [Mykola - Mokhnach] -- Chore: bump mypy (#675) [Kazuaki Matsuo] -- Update changelog for 2.1.2. [Kazuaki Matsuo] - - -v2.1.2 (2021-12-30) -------------------- - -Fix -~~~ -- Default duration in tap (#673) [Kazuaki Matsuo] - -Other -~~~~~ -- Bump 2.1.2. [Kazuaki Matsuo] -- Update changelog for 2.1.1. [Kazuaki Matsuo] - - -v2.1.1 (2021-12-24) -------------------- - -New -~~~ -- Feat: use 'touch' pointer action (#670) [Kazuaki Matsuo] - - * chore: specify touch - - * comment out touch in drag_and_drop - - * fix mypy - - * add desctiption of touch action - -Test -~~~~ -- Ci: remove ==2021.5.29 (#653) [Kazuaki Matsuo] - - * ci: remove ==2021.5.29 - - * bump black - -Other -~~~~~ -- Bump 2.1.1. [Kazuaki Matsuo] -- Chore(deps): bump black from 21.11b1 to 21.12b0 (#664) - [dependabot[bot]] - - Bumps [black](https://github.com/psf/black) from 21.11b1 to 21.12b0. - - [Release notes](https://github.com/psf/black/releases) - - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - - [Commits](https://github.com/psf/black/commits) - - --- - updated-dependencies: - - dependency-name: black - dependency-type: direct:production - ... -- Chore(deps-dev): update pre-commit requirement from ~=2.15 to ~=2.16 - (#663) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.15.0...v2.16.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Chore(deps): update pylint requirement from ~=2.11 to ~=2.12 (#662) - [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Changelog](https://github.com/PyCQA/pylint/blob/main/ChangeLog) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.11.0...v2.12.1) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Chore(deps): update astroid requirement from ~=2.8 to ~=2.9 (#661) - [dependabot[bot]] - - Updates the requirements on [astroid](https://github.com/PyCQA/astroid) to permit the latest version. - - [Release notes](https://github.com/PyCQA/astroid/releases) - - [Changelog](https://github.com/PyCQA/astroid/blob/main/ChangeLog) - - [Commits](https://github.com/PyCQA/astroid/compare/v2.8.0...v2.9.0) - - --- - updated-dependencies: - - dependency-name: astroid - dependency-type: direct:production - ... -- Update changelog for 2.1.0. [Kazuaki Matsuo] - - -v2.1.0 (2021-11-27) -------------------- - -New -~~~ -- Feat: add AppiumBy instead of MobileBy (#659) [Kazuaki Matsuo] - - * feat: add AppiumBy instead of MobileBy - - * add class description - - * use deprecated:: - -Other -~~~~~ -- Bump 2.1.0. [Kazuaki Matsuo] -- Chore: add deprecated mark for find_element_by* (#657) [Kazuaki - Matsuo] -- Chore: relax selenium version control (#656) [Kazuaki Matsuo] -- Chore: tweak keyword in metadata. [Kazuaki Matsuo] -- Update changelog for 2.0.0. [Kazuaki Matsuo] - - -v2.0.0 (2021-11-09) -------------------- - -New -~~~ -- Feat: Change base selenium client version to selenium 4 (#636) - [Kazuaki Matsuo] - - - Changed base selenium client version to v4 - - No longer forceMjsonwp works - - Add strict_ssl option in webdriver.Remote - -Test -~~~~ -- Ci: set pipenv==2021.5.29 to prevent dependencies error (#651) - [Kazuaki Matsuo] - - * ci: add --pre - - * specify pipenv as same as the previous ok case - - * set 2021.5.29 in tox as well - -Other -~~~~~ -- Bump 2.0.0. [Kazuaki Matsuo] -- Docs: update readme. [Kazuaki Matsuo] -- Chore: add Python 3.9 as metadata. [Kazuaki Matsuo] -- Chore(deps): update isort requirement from ~=5.9 to ~=5.10 (#650) - [dependabot[bot]] - - Updates the requirements on [isort](https://github.com/pycqa/isort) to permit the latest version. - - [Release notes](https://github.com/pycqa/isort/releases) - - [Changelog](https://github.com/PyCQA/isort/blob/main/CHANGELOG.md) - - [Commits](https://github.com/pycqa/isort/compare/5.9.0...5.10.0) - - --- - updated-dependencies: - - dependency-name: isort - dependency-type: direct:production - ... -- Update changelog for 2.0.0.rc6. [Kazuaki Matsuo] -- Bump 2.0.0.rc6. [Kazuaki Matsuo] -- Docs: update readme. [Kazuaki Matsuo] -- Chore: adding deprecation mark in touch actions and multi touch (#648) - [Kazuaki Matsuo] - - * chore: add deprecation mark in touch actions and multi touch - - * chore: add deprecated mark in MultiAction class - - * docs: update readme -- Chore: deprecate -windows uiautomation (#649) [Kazuaki Matsuo] - - * chore: add Deprecated for -windows uiautomation - - * chore: add logger -- Update changelog for 2.0.0.rc5. [Kazuaki Matsuo] -- Bump 2.0.0.rc5. [Kazuaki Matsuo] -- Chore(deps): update sphinx requirement from <4.0,>=3.0 to >=3.0,<5.0 - (#603) [Kazuaki Matsuo, dependabot[bot]] - - Updates the requirements on [sphinx](https://github.com/sphinx-doc/sphinx) to permit the latest version. - - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - - [Changelog](https://github.com/sphinx-doc/sphinx/blob/4.x/CHANGES) - - [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.0.0...v4.0.0) -- Update gitchangelog once. [Kazuaki Matsuo] -- Chore(deps): update sphinx-rtd-theme requirement from <1.0 to <2.0 - (#637) [Kazuaki Matsuo, dependabot[bot]] - - Updates the requirements on [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) to permit the latest version. - - [Release notes](https://github.com/readthedocs/sphinx_rtd_theme/releases) - - [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst) - - [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/0.1.8...1.0.0) - - --- - updated-dependencies: - - dependency-name: sphinx-rtd-theme - dependency-type: direct:production - ... -- Chore: cleanup no longer needed code in w3c, bump dev Pipfile (#646) - [Kazuaki Matsuo] - - chore: cleanup no longer needed code in w3c, bump dev Pipfile -- Chore(deps): update pylint requirement from ~=2.10 to ~=2.11 (#638) - [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Changelog](https://github.com/PyCQA/pylint/blob/main/ChangeLog) - - [Commits](https://github.com/PyCQA/pylint/compare/v2.10.0...v2.11.1) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Chore(deps): update pytest-cov requirement from ~=2.12 to ~=3.0 (#641) - [dependabot[bot]] - - Updates the requirements on [pytest-cov](https://github.com/pytest-dev/pytest-cov) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest-cov/releases) - - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.12.0...v3.0.0) - - --- - updated-dependencies: - - dependency-name: pytest-cov - dependency-type: direct:production - ... -- Update changelog for 1.3.0. [Kazuaki Matsuo] - - -v1.3.0 (2021-09-27) -------------------- - -New -~~~ -- Feat: do not raise an error in case method is already defined (#632) - [Kazuaki Matsuo] -- Feat: add satellites in set_location (#620) [Kazuaki Matsuo] - - * feat: add satellites in set_location - - * fix review -- Feat: Add command with `setattr` (#615) [Kazuaki Matsuo] - - * chore: add placeholder - - * move to extention way - - * revert pytest - - * add todo - - * call method_name instead of wrapper - - * remove types - - * rename a method - - * add examples - - * add types-python-dateutil as error message - - * add example more - - * tweak naming - - * Explicit Dict - -Other -~~~~~ -- Bump 1.3.0. [Kazuaki Matsuo] -- Chore(deps): update types-python-dateutil requirement (#633) - [dependabot[bot]] - - Updates the requirements on [types-python-dateutil](https://github.com/python/typeshed) to permit the latest version. - - [Release notes](https://github.com/python/typeshed/releases) - - [Commits](https://github.com/python/typeshed/commits) - - --- - updated-dependencies: - - dependency-name: types-python-dateutil - dependency-type: direct:production - ... -- Chore(deps-dev): update pre-commit requirement from ~=2.13 to ~=2.15 - (#634) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.13.0...v2.15.0) - - --- - updated-dependencies: - - dependency-name: pre-commit - dependency-type: direct:development - ... -- Chore(deps): update mypy requirement from ~=0.812 to ~=0.910 (#616) - [dependabot[bot]] - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.812...v0.910) - - --- - updated-dependencies: - - dependency-name: mypy - dependency-type: direct:production - ... -- Chore(deps): update astroid requirement from ~=2.5 to ~=2.7 (#629) - [dependabot[bot]] - - Updates the requirements on [astroid](https://github.com/PyCQA/astroid) to permit the latest version. - - [Release notes](https://github.com/PyCQA/astroid/releases) - - [Changelog](https://github.com/PyCQA/astroid/blob/main/ChangeLog) - - [Commits](https://github.com/PyCQA/astroid/compare/astroid-2.5...v2.7.2) - - --- - updated-dependencies: - - dependency-name: astroid - dependency-type: direct:production - ... -- Chore(deps): update pylint requirement from ~=2.8 to ~=2.10 (#628) - [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Changelog](https://github.com/PyCQA/pylint/blob/main/ChangeLog) - - [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.8.0...v2.10.2) - - --- - updated-dependencies: - - dependency-name: pylint - dependency-type: direct:production - ... -- Chore(deps): update tox requirement from ~=3.23 to ~=3.24 (#619) - [dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.23.0...3.24.0) - - --- - updated-dependencies: - - dependency-name: tox - dependency-type: direct:production - ... -- Update changelog for 1.2.0. [Kazuaki Matsuo] - - -v1.2.0 (2021-06-07) -------------------- - -New -~~~ -- Feat: allow to add a command dynamically (#608) [Kazuaki Matsuo] - - * add add_commmand in python - - * add test - - * add exceptions, tweak method - - * append docstring - - * add $id example - - * use pytest.raises - - * add examples as docstring - -Other -~~~~~ -- Bump 1.2.0. [Kazuaki Matsuo] -- Chore(deps-dev): update pre-commit requirement from ~=2.12 to ~=2.13 - (#607) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.12.0...v2.13.0) -- Chore(deps): update pytest-cov requirement from ~=2.11 to ~=2.12 - (#606) [Kazuaki Matsuo, dependabot[bot]] - - * chore(deps): update pytest-cov requirement from ~=2.11 to ~=2.12 - - Updates the requirements on [pytest-cov](https://github.com/pytest-dev/pytest-cov) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest-cov/releases) - - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.11.0...v2.12.0) -- Chore(deps): update pylint requirement from ~=2.7 to ~=2.8 (#600) - [dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog) - - [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.7.0...pylint-2.8.1) -- Chore(deps-dev): update pre-commit requirement from ~=2.11 to ~=2.12 - (#599) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.11.0...v2.12.0) -- Chore(deps): update isort requirement from ~=5.7 to ~=5.8 (#596) - [dependabot[bot]] - - Updates the requirements on [isort](https://github.com/pycqa/isort) to permit the latest version. - - [Release notes](https://github.com/pycqa/isort/releases) - - [Changelog](https://github.com/PyCQA/isort/blob/develop/CHANGELOG.md) - - [Commits](https://github.com/pycqa/isort/compare/5.7.0...5.8.0) - - -v1.1.0 (2021-03-10) -------------------- - -New -~~~ -- Feat: Add optional location speed attribute for android devices (#594) - [salabogdan] -- Feat: Added docstring for macOS screenrecord option (#580) [Mori - Atsushi] - - * Added docstring for macOS screenrecord option - - * tweak - - * review comment -- Feat: add warning to drop forceMjsonwp for W3C (#567) [Kazuaki Matsuo] - - * tweak - - * fix test - - * print warning - - * revert test - - * Update webdriver.py - - * fix autopep8 -- Feat: Added descriptions for newly added screenrecord opts (#540) - [Mori Atsushi] - - * Add description for newly added opts for screen record - - * Updates - -Test -~~~~ -- Ci: Use node v12 (#585) [Mori Atsushi] - - * Use node 12 on ci - - * Update copyright - - * Update README for doc - - * tweak - - * fix copyright - - * try py310 - - * remove py310 -- Ci: remove travis (#581) [Mori Atsushi] - - * Removed travis and run unit test on azure - - * review comment - - * run tox on azure pipelines - - * removed tox-travis from pipfile -- Ci: move azure project to Appium CI, update readme (#564) [Kazuaki - Matsuo] -- Ci: Added py39-dev for travis (#557) [Mori Atsushi] - - * ci: Added py39-dev - - * Add xv option for debug - - * [debug] pip list - - * Avoid error in py39 - - * Updated modules in pre-commit -- Ci: upgrade xcode and macos (#556) [Mori Atsushi] - - * ci: upgrade xcode ver and macos - - * Upgrade iOS ver for functional tests - - * Changed xcode to 11.6 - -Other -~~~~~ -- Chore(deps-dev): update pre-commit requirement from ~=2.10 to ~=2.11 - (#595) [dependabot[bot]] - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.10.0...v2.11.0) -- Chore(deps): update tox requirement from ~=3.22 to ~=3.23 (#593) - [dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/3.23.0/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.22.0...3.23.0) -- Chore(deps): update pylint requirement from ~=2.6 to ~=2.7 (#588) - [Mori Atsushi, dependabot[bot]] - - Updates the requirements on [pylint](https://github.com/PyCQA/pylint) to permit the latest version. - - [Release notes](https://github.com/PyCQA/pylint/releases) - - [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog) - - [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.6.0...pylint-2.7.0) -- Chore(deps): update astroid requirement from ~=2.4 to ~=2.5 (#587) - [dependabot[bot]] - - Updates the requirements on [astroid](https://github.com/PyCQA/astroid) to permit the latest version. - - [Release notes](https://github.com/PyCQA/astroid/releases) - - [Changelog](https://github.com/PyCQA/astroid/blob/master/ChangeLog) - - [Commits](https://github.com/PyCQA/astroid/compare/astroid-2.4.0...astroid-2.5) -- Chore(deps): update mypy requirement from ~=0.800 to ~=0.812 (#589) - [Mori Atsushi, dependabot[bot]] - - * chore(deps): update mypy requirement from ~=0.800 to ~=0.812 - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.800...v0.812) - - Signed-off-by: dependabot[bot] - - * Fix mypy error with mypy v0.812 (#590) - - * chore(deps): update mypy requirement from ~=0.800 to ~=0.812 - - Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - - [Release notes](https://github.com/python/mypy/releases) - - [Commits](https://github.com/python/mypy/compare/v0.800...v0.812) -- Chore(deps): update tox requirement from ~=3.21 to ~=3.22 (#586) - [dependabot[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.21.0...3.22.0) -- Chore: Add table for screen_record kwarg (#582) [Mori Atsushi] - - * Add table for kwarg - - * update - - * Add missing doc to stop_recording - - * Push auto-generated changes by sphinx - - * delete duplicated entry [skip ci] -- Chore(deps): update isort requirement from ~=5.0 to ~=5.7 (#578) - [dependabot-preview[bot]] - - Updates the requirements on [isort](https://github.com/pycqa/isort) to permit the latest version. - - [Release notes](https://github.com/pycqa/isort/releases) - - [Changelog](https://github.com/PyCQA/isort/blob/develop/CHANGELOG.md) - - [Commits](https://github.com/pycqa/isort/compare/5.0.0...5.7.0) -- Create Dependabot config file (#579) [dependabot-preview[bot], - dependabot-preview[bot]] -- Chore: Update pipfile to respect isort v5 (#577) [Mori Atsushi] -- Chore: Fix iOS app management functional tests (#575) [Mori Atsushi] - - * Added sleep to wait the app has gone - - * Upgrade AndroidSDK to 30 from 27 - - * Added sleep to ios tc - - * Fix android activities test - - * Revert android sdk ver - - * Used timer instead of fixed wait time - - * Created wait_for - - * Update test/functional/test_helper.py - - * review comments - - * review comments - - * Extend callable type - - * fix - - * review comment - - * review comment - - * review comment - - * fix comment -- Chore: Fix functional keyboard tests with appium v1.21.0-beta.0 (#574) - [Mori Atsushi] - - * Fix function keyboard tests - - * Updated class name for keyboard -- Chore: Apply Black code formatter (#571) [Mori Atsushi] - - * Applied black (length: 120, String skipped) - - * Updated related to ci - - * Update README -- Chore: address selenium-4 branch in readme (#566) [Kazuaki Matsuo] -- Docs: fix wrong code example in README.md (#555) [sanlengjingvv] -- Update changelog for 1.0.2. [Kazuaki Matsuo] - - -v1.0.2 (2020-07-15) -------------------- -- Bump 1.0.2. [Kazuaki Matsuo] -- Chore: Add the workaround to avoid service freezes on Windows (#552) - [Mykola Mokhnach] -- Chore: add checking package file count comparison in release script - (#547) [Kazuaki Matsuo] - - * chore: Add file count in release script - - * use f string for Python 3 :P - - * handle exit in method -- Update changelog for 1.0.1. [Kazuaki Matsuo] - - -v1.0.1 (2020-05-18) -------------------- - -Fix -~~~ -- Broken package (#545) [Kazuaki Matsuo] - - * add appium/webdriver/py.typed in find_packages - - * fix - -Other -~~~~~ -- Bump 1.0.1. [Kazuaki Matsuo] -- Update changelog for 1.0.0. [Kazuaki Matsuo] - - -v1.0.0 (2020-05-16) -------------------- - -New -~~~ -- Feat: Added Makefile (#530) [Mori Atsushi] - - * Created setup.cfg - - * Updated lib ver for pre-commit - - * Fix ci.sh to set failure even when one command failed - - * Fix pylint error - - * Add help to Makefile - - * Update README - - * Add check-all command -- Feat: Merge python3 branch to master (#526) [Hannes Hauer, Hannes - Hauer * chore: Update readme and - gitchangelog section role (#524) (#525) * chore: tweak changelog - filter * address stoping Python 2 support * 2 instead of 2.0... - * tweak readme * Revert some unexpected changes * review - comments * Changed bound for TypeVar * Fix crashing ci * - Remove beta Co-authored-by: dependabot-preview[bot] - <27856297+dependabot-preview[bot]@users.noreply.github.com>, Kazuaki - Matsuo, Kazuaki Matsuo, Mori Atsushi, Mykola Mokhnach, Mykola - Mokhnach, Nrupesh Patel, Nrupesh Patel, Venkatesh, Venkatesh] - - * Drop py2 support (#478) - - * Drop py2 support - - * Support 3.7+ - - * Add explicit type declarations (#482) - - * Fixed mypy warning: touch_action.py - - * Fixed mypy warning: multi_action.py - - * Fixed mypy warning: extensions/android - - * Fixed mypy warning: extensions/search_context - - * Updated - - * Revert some changes to run unit test - - * Review comments - - * Updates - - * Updates - - * Add mypy check to ci.sh - - * Add mypy to Pipfile - - * Updates - - * Update README - - * Revert unexpected changes - - * Updates Dict - - * Revert unexpected changes - - * Updates - - * Review comments - - * Review comments - - * tweak - - * Restore and modify changes - - * Fix wrong return type - - * Add comments - - * Revert unexpected changes - - * Fix mypy error - - * updates - - * Add mypy to pre-commit (#485) - - * chore: Applied some py3 formats (#486) - - * Removed unused import - - * Removed unnecessary codes - - * Applied f'' format instead ''.format() - - * Fixes - - * tweak - - * chore: Fix mypy errors under test folder (#487) - - * Fix mypy errors under test folder - - * Add mypy check for test folder to pre-commit - - * Add mypy check to ci - - * chore: Remove unittest dependency (#488) - - * Removed unnecessary codes from calling super - - * Removed unittest dependency - - * Upgrade the dependencies to the latest - - * Removed unused args - - * Review comments - - * Update mock requirement from ~=3.0 to ~=4.0 (#502) - - Updates the requirements on [mock](https://github.com/testing-cabal/mock) to permit the latest version. - - [Release notes](https://github.com/testing-cabal/mock/releases) - - [Changelog](https://github.com/testing-cabal/mock/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/testing-cabal/mock/compare/3.0.0...4.0.0) - - Signed-off-by: dependabot-preview[bot] - - * Add 'from' to except (#503) - - * Update pre-commit requirement from ~=1.21 to ~=2.1 (#506) - - Updates the requirements on [pre-commit](https://github.com/pre-commit/pre-commit) to permit the latest version. - - [Release notes](https://github.com/pre-commit/pre-commit/releases) - - [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md) - - [Commits](https://github.com/pre-commit/pre-commit/compare/v1.21.0...v2.1.0) - - Signed-off-by: dependabot-preview[bot] - - * doc: Add script to generate sphinx doc (#508) - - * Add quickstart template files - - * Update conf file - - * Update - - * Update settings - - * Change project name - - * Add script to generate docs - - * Changed header title - - * Add new line to usage section - - * Add py.typed file(PEP561) - - * Replace \n with new line - - * tweak - - * Use sphinx format for tables - - * Rebase python3 branch with master (#522) - - * Update pytest-cov requirement from ~=2.6 to ~=2.8 (#489) - - Updates the requirements on [pytest-cov](https://github.com/pytest-dev/pytest-cov) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest-cov/releases) - - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.6.0...v2.8.1) - - Signed-off-by: dependabot-preview[bot] - - * Update autopep8 requirement from ~=1.4 to ~=1.5 (#490) - - Updates the requirements on [autopep8](https://github.com/hhatto/autopep8) to permit the latest version. - - [Release notes](https://github.com/hhatto/autopep8/releases) - - [Commits](https://github.com/hhatto/autopep8/compare/v1.4...v1.5) - - Signed-off-by: dependabot-preview[bot] - - * Update tox-travis requirement from ~=0.11 to ~=0.12 (#491) - - Updates the requirements on [tox-travis](https://github.com/tox-dev/tox-travis) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox-travis/releases) - - [Changelog](https://github.com/tox-dev/tox-travis/blob/master/HISTORY.rst) - - [Commits](https://github.com/tox-dev/tox-travis/compare/0.11...0.12) - - Signed-off-by: dependabot-preview[bot] - - * Update tox requirement from ~=3.6 to ~=3.14 (#494) - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.6.0...3.14.3) - - Signed-off-by: dependabot-preview[bot] - - * chore: Fix find_by_images_tests.py (#495) - - * chore: Fix find_by_images_tests.py - - * Add installation opencv4nodejs - - * Fix typo - - * Add taking screen record to find_by_image_test - - * Fix errors on the emulator - - * Remove unused imports - - * feat: Add viewmatcher (#480) - - * Add android view matcher as strategy locator - - * Add docstring - - * Add functional test - - * Remove find_elements_by_android_data_matcher - - * Fix docstring - - * tweak docstring - - * Bump 0.50 - - * Update changelog for 0.50 - - * Fix flaky functional tests (#473) - - * Run all tests - - * Fix apk file path - - * Skip find_element_by_image test cases - - * Skip context switching test - - * Skip multi tap test on CI - - * Change strategy for waiting element - - * Add functions for same steps - - * Restore unexpected changes - - * Fix touch_action_tests - - * Fix - - * Fix - Fix test_driver_swipe - - * fix - - * Create _move_to_[target_view] - - * [test_driver_swipe] Add wait - - * feat: Add idempotency key header to create session requests (#514) - - * feat: Override send_keys without file upload function (#515) - - * add send_keys_direct - - * override send_keys - - * tune - - * add unittest instead of functional test - - * tweak syntax - - * Bump 0.51 - - * Update changelog for 0.51 - - * test: Fix test_clear flaky functional test (#519) - - * test: Add unit test for set_value (setImmediateValue) (#518) - - * chore: Fix int - str comparison error in ios desired capabilities (#517) - - if number >= PytestXdistWorker.COUNT: - -Fix -~~~ -- Tune mixin types, so linters could recognize them better (#536) - [Mykola Mokhnach] - -Test -~~~~ -- Test: Add appium_service functional test (#531) [Mori Atsushi] - - * Add appium_service functional test - - * Fix expressions - -Other -~~~~~ -- Bump 1.0.0. [Kazuaki Matsuo] -- Chore: Updates docstring (#533) [Mori Atsushi] - - * Updates docstring - - * Add description to Returns field - - * Remove type from docstring - - Since type hint already added to args - - * Set default lang to en - - * Change usage style in docstring - - * Updates - - * Remove rtype - - unnecessary anymore since type hint works for auto completion - - * tweak - - * Update return type - - * Restore types for keyword args - - * Remove types from Return field - - Except for property and TypeVar -- Chore: Remove saucetestcase from the client (#539) [Mykola Mokhnach] -- Chore: add py.typed in package, add maintainers (#538) [Kazuaki - Matsuo] -- Docs: Update documentation (#527) [Kazuaki Matsuo] - - * Chore: correct license, update readme - - * cleanup - - * docs: update the url of documentation -- Chore: Update readme and gitchangelog section role (#524) [Kazuaki - Matsuo] - - * chore: tweak changelog filter - - * address stoping Python 2 support - - * 2 instead of 2.0... - - * tweak readme -- Update changelog for 0.52. [Kazuaki Matsuo] - - -v0.52 (2020-04-23) ------------------- - -Fix -~~~ -- Handling of dictionary-values in WebElement.get_attribute() (#521) - [Hannes Hauer] - -Test -~~~~ -- Test: Add unit test for set_value (setImmediateValue) (#518) [Nrupesh - Patel] -- Test: Fix test_clear flaky functional test (#519) [Nrupesh Patel] - -Other -~~~~~ -- Bump 0.52. [Kazuaki Matsuo] -- Chore: Fix int - str comparison error in ios desired capabilities - (#517) [Venkatesh] - - if number >= PytestXdistWorker.COUNT: -- Update changelog for 0.51. [Kazuaki Matsuo] - - -v0.51 (2020-04-12) ------------------- - -New -~~~ -- Feat: Override send_keys without file upload function (#515) [Kazuaki - Matsuo] - - * add send_keys_direct - - * override send_keys - - * tune - - * add unittest instead of functional test - - * tweak syntax -- Feat: Add idempotency key header to create session requests (#514) - [Mykola Mokhnach] - -Fix -~~~ -- Fix flaky functional tests (#473) [Mori Atsushi] - - * Run all tests - - * Fix apk file path - - * Skip find_element_by_image test cases - - * Skip context switching test - - * Skip multi tap test on CI - - * Change strategy for waiting element - - * Add functions for same steps - - * Restore unexpected changes - - * Fix touch_action_tests - - * Fix - - * Fix - Fix test_driver_swipe - - * fix - - * Create _move_to_[target_view] - - * [test_driver_swipe] Add wait - -Other -~~~~~ -- Bump 0.51. [Kazuaki Matsuo] -- Update changelog for 0.50. [Kazuaki Matsuo] - - -v0.50 (2020-02-10) ------------------- - -New -~~~ -- Feat: Add viewmatcher (#480) [Mori Atsushi] - - * Add android view matcher as strategy locator - - * Add docstring - - * Add functional test - - * Remove find_elements_by_android_data_matcher - - * Fix docstring - - * tweak docstring - -Test -~~~~ -- Ci: Take screen record as evidence (#481) [Mori Atsushi] - - * Take screen record for android - - * Take screen record for iOS - - * Save screen record for iOS - -Other -~~~~~ -- Bump 0.50. [Kazuaki Matsuo] -- Chore: Fix find_by_images_tests.py (#495) [Mori Atsushi] - - * chore: Fix find_by_images_tests.py - - * Add installation opencv4nodejs - - * Fix typo - - * Add taking screen record to find_by_image_test - - * Fix errors on the emulator - - * Remove unused imports -- Update tox requirement from ~=3.6 to ~=3.14 (#494) [dependabot- - preview[bot]] - - Updates the requirements on [tox](https://github.com/tox-dev/tox) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox/releases) - - [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst) - - [Commits](https://github.com/tox-dev/tox/compare/3.6.0...3.14.3) -- Update tox-travis requirement from ~=0.11 to ~=0.12 (#491) - [dependabot-preview[bot]] - - Updates the requirements on [tox-travis](https://github.com/tox-dev/tox-travis) to permit the latest version. - - [Release notes](https://github.com/tox-dev/tox-travis/releases) - - [Changelog](https://github.com/tox-dev/tox-travis/blob/master/HISTORY.rst) - - [Commits](https://github.com/tox-dev/tox-travis/compare/0.11...0.12) -- Update autopep8 requirement from ~=1.4 to ~=1.5 (#490) [dependabot- - preview[bot]] - - Updates the requirements on [autopep8](https://github.com/hhatto/autopep8) to permit the latest version. - - [Release notes](https://github.com/hhatto/autopep8/releases) - - [Commits](https://github.com/hhatto/autopep8/compare/v1.4...v1.5) -- Update pytest-cov requirement from ~=2.6 to ~=2.8 (#489) [dependabot- - preview[bot]] - - Updates the requirements on [pytest-cov](https://github.com/pytest-dev/pytest-cov) to permit the latest version. - - [Release notes](https://github.com/pytest-dev/pytest-cov/releases) - - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.6.0...v2.8.1) -- Chore: add try/catch in release script (#479) [Kazuaki Matsuo] - - * Add m and try/catch in pushing - - * fix error message - - * remove -m since it does not work for this usage -- [CI] Run with iOS 13.3 and Xcode 11.3 (#477) [Mori Atsushi] - - * [CI] Run with iOS 13.3 and Xcode 11.3 - - * Skip the case which has problem on Xcode 11.3 - - * Update FyndByIOClassChainTests along to iOS13 - - * Update FyndByElementWebelementTests along to iOS13 - - * Update KeyboardTests along to iOS13 - - * Update webdriver_tests along to iOS13 - - * Run test_find_element_by_isvisible with simpleIsVisibleCheck caps - - * Run test_hide_keyboard_no_key_name - - * Remove unused codes - - * [Readme] py.test -> pytest -- Update changelog for 0.49. [Kazuaki Matsuo] - - -v0.49 (2019-12-24) ------------------- - -New -~~~ -- Add IME unittest (#475) [Mori Atsushi] -- Add new locator strategy find_elements_by_windows_uiautomation and - test. [Manoj Kumar] -- Add new locator strategy find_element_by_windows_uiautomation. [Manoj - Kumar] - -Fix -~~~ -- Fix functional test broken by previous commit. [Manoj Kumar] -- Fix CI (Failed iOS) (#460) [Mori Atsushi] - - * Fix CI (Failed iOS) - - * Fix variable name - -Other -~~~~~ -- Bump 0.49. [Kazuaki Matsuo] -- Move session/execute_mobile commands to mixin class (#471) [Mori - Atsushi] - - * Fix get_all_sessions - - * Revert changes - - * Move execute_mobile_command codes to mixin class - - * Update docstring - - It's same to webdriver.py - - * Use /sessions as endpoint for all_sessions - - https://github.com/appium/appium-base-driver/blob/master/docs/mjsonwp/protocol-methods.md - - * Delete unnecessary codes -- Replace apk for functional test (#470) [Mori Atsushi] - - * Replace apk for functional test - - https://github.com/appium/android-apidemos/releases/tag/v3.1.0 - - * Use sdkVer 27 - - * Update app package name - - * Fix: can't find android device - - * review comments - - * tweak -- Support for log_event and get_events command (#469) [Mori Atsushi] - - * Use appium/events as endpoint to get events - - * Removed unnecessary codes - - * Update unittest along to changes - - * Update docstring - - * Created LogEvents class - - * Support log_event - - * Add unittest for log_event - - * Add functional test for log_event and get_event - - * review comments - - * Restore events API - - * Add type as arg to get_events - - * tweak - - * Removed type arg from get_events - - It isn't implemented yet for now - - * Add type arg to get_event - - The value isn't passed to the server for now. - - * Updated along to type -- Cleaned up test codes (#466) [Mori Atsushi] - - * Deleted unnecessary codes - - * Move functional tests to correct class - - * Move some tests - - * Created search_context/windows_test - - * [functional] Created search_context package - - * Remove class method decolator - - * Fix import error - - * Add BaseTestCase for ios functional testcases - - * Add test_helper for android functional test - - * Add __init__.py - - * Deleted unused imports -- Move search context methods from webdriver and webelement to - search_context (#461) [Mori Atsushi] - - * Move ios search context methods to search_context file - - * Move android search text methods - - * Move windows search context - - * Move mobile search context - - * Divided search_context into each class - - * Move custom and image methods - - * Move contents in search_context.py to __init__.py - - * Add rtype to each docstring for auto completion in IDE - - * Add comments -- [CI] Run functional tests nightly (#463) [Mori Atsushi] - - * [CI] Run functional tests nightly - - * Extend timeout to wait for 2nd session created - - * Skip flaky test_all_sessions -- Revert some changes to fix broken codes (#462) [Mori Atsushi] - - * Revert some changes - - * Fix typo -- Move commands from webdriver as mixins class (#459) [Manoj Kumar] - - * move to mixins class - - * Create common class with its tests - - * incorporating PR comments -- Update changelog for 0.48. [Kazuaki Matsuo] -- Bump 0.48. [Kazuaki Matsuo] - - -v0.48 (2019-10-22) ------------------- - -New -~~~ -- Add docs on start activity with args. [Manoj Kumar] -- Add unit tests Activate app. [Manoj Kumar] -- Add unit tests for keyboard API (#452) [Manoj Kumar] - - * Add Unit tests for Keyboard API - - * incorporating review comments - - * change per review comment -- Feat: Adding getAllSessions (#446) [Manoj Kumar] - - * Adding getAllSessions - - * adjust per lint - - * fix comments -- Add downloads badge (#441) [Mori Atsushi] - -Fix -~~~ -- Fix docstring, add getting available port number (#448) [Kazuaki - Matsuo] - - * fix docstring, add getting available port number - - * add WebDriverWait - - * define custom wait - - * move get available port in another module - - * follow python wait condition name -- Fix CI fails (Updated iOS ver) (#440) [Mori Atsushi] - - * Updated iOS ver to fix CI fails - - * Update capability for safari test on ios - - * Fix travis CI fails -- Fix CI fails (#436) [Mori Atsushi] - - * Skip taking the screenshot not in CI - - * Skip py38 on travis -- Fix isort behavior for mock (#432) [Mori Atsushi] - - * Fix isort behavior for mock - - * Add guide to add 3rd party modules to isort conf - - * Add guide for docstrings - - * Delete unnecessary codes -- Fix android flaky tests (#413) [Mori Atsushi] - - * Fix android flaky tests - - * Use androidSdkVer 27 for emulator - - * Skip find_by_accessibility_id, find_by_uiautomator - - * Changed from https://github.com/ki4070ma/python-client/pull/5 - - * Add save_appium_log.yml - - * Don't run flaky tests on CI - - * Rename class name - -Test -~~~~ -- Test: Add unit tests for application_tests (#454) [Manoj Kumar] - - * Add unit tests for application_tests - - * change body values to be empty -- Test: add Unit tests currentPackage (#453) [Manoj Kumar] -- Test: add unit test unlock (#450) [Manoj Kumar] -- Ci: try run all scripts and exit 1 when something fails (#431) - [Kazuaki Matsuo] - - * try run all scripts and exit 1 when something fails - - * ignore link in Python 3.7 because of runtime error - -Other -~~~~~ -- Docs: Minor fix in README (#445) [Aliakbar] -- AndroidKey class for Key Codes added. (#443) [Aliakbar] - - * AndroidKey class for Key Codes added. - - AndroidKey enum from java client ported. Instead of using unreadable numbers in code we can use these constant in order to write more readable code. - - * Android native key test - - Test for native key module which contains key codes for android keys. - - * Fixed # sign in comment instead of * - - * Change returns - - Instead of `if` and two return statements. - - * Used AndroidKey.XXX instead of numbers in tests - - * Make fuctions similar to is_gamepad_button - - Used a similar sentence format for similar functions as is_gamepad_button. - - * Make function names as is in java-client - - * Underscore in the beginning of constant removed -- Run unittest with python3.8 (#433) [Mori Atsushi] -- Bump 0.47. [Kazuaki Matsuo] -- Update changelog for 0.47. [Kazuaki Matsuo] - - -v0.47 (2019-08-22) ------------------- - -New -~~~ -- Add events property (#429) [Dan Graham] - - * add GET_SESSION - - * add events property, this property will get the current information of the session and get the events timings - - * add method for getting session_capabilities - - * update docstring - - * apply isort -- Add screenrecord unittest (#426) [Mori Atsushi] - - * Fix wrong docstring - - * Add screen_record unittest - - * Rename class names - - * Move test files - - * Fix docstring -- Add videoFilters option documentation (#419) [Mykola Mokhnach] -- Add remote_fs unittest (#410) [Mori Atsushi] - - * Add test_push_file unittest - - * Add test_pull_file unittest - - * Add remote_fs error cases unittest - -Fix -~~~ -- CI doesn't fail even if autopep8 makes changes (#422) [Mori Atsushi] - - * Fix: CI doesn't fail even if autopep8 makes changes - - * Fix: CI failure - -Other -~~~~~ -- Change altitude optional as arg for set_location (#415) [Mori Atsushi] - - * Change altitude optional as arg for set_location - - * Add comments - - * review comments -- Update docstring (#407) [Mori Atsushi] - - * Remove import error on pycharm - - And update docstring - - * Update docstring - - * Update docstring - - * Fix import error - - * fix - - * fix import order - - * tweak -- Update changelog for 0.46. [Kazuaki Matsuo] - - -v0.46 (2019-06-27) ------------------- -- Bump 0.46. [Kazuaki Matsuo] -- Bug fix joining path in _get_main_script (#408) [Nicholas Frederick] -- Update changelog for 0.45. [Kazuaki Matsuo] - - -v0.45 (2019-06-26) ------------------- - -New -~~~ -- Add execute driver (#406) [Kazuaki Matsuo] - - * add execute driver - - * append docstring -- Add how to solve pipenv error to readme (#403) [Mori Atsushi] - - * Add how to solve pipenv error to readme - - * review comments - - * tweak - - * review comments -- Add autocompletion for pycharm (#404) [Mori Atsushi] - - * Add autocompletion for pycharm - - * Removed flaky tests from running -- Add unit test for open_notifications (#398) [tabatask] - -Other -~~~~~ -- Bump 0.45. [Kazuaki Matsuo] -- Moving reset method from WebDriver to Applications (#399) [Mayura] -- Run android functional tests on ci (#396) [Mori Atsushi] - - * Add android functional test to ci - - * Add missing param - - * Add run_test template - - * Fixed: test running failed - - * Fixed - - * Fixed - - * fixed - - * Add run_android_test - - * Changed emulator to Nexus6 - - * Run all android tests - - * fixed - - * Resolve python-dateutil dependency - - * Run on 3 workers - - * Add chromedriver installation - - * Skip failed test cases on ci - - * fixed - - * Extend adbExecTimeout - - * Add script source to comment - - * Run 5 workers for android - - * Use Node11 - - * Extend wait time - - * Reduced running android functional tests - - * Revert some changes -- Use the same format for docstring (#395) [Mori Atsushi] - - * Update docstring - - * Update docstring - - * Update docstring - - * tweak - - * tweak - - * tweak - - * tweak - - * tweak - - * Update docstring - - * Update docstring - - * Update docstring - - * Update docstring - - * tweak - - * Update -- Publish functional test report (#394) [Mori Atsushi] - - * Move functional tests to template - - * Add publish_test_result - - * Fix typo -- Divide functional appium tests into each module(iOS) (#391) [Mori - Atsushi] - - * Divide ios appium_tests to each module - - * Fix test file name - - * Add CI status badge -- Run iOS functional tests on azure pipelines (#390) [Mori Atsushi] - - * Set up CI with Azure Pipelines - - * review comments - - * update README -- Update changelog for 0.44. [Kazuaki Matsuo] - - -v0.44 (2019-05-24) ------------------- - -Fix -~~~ -- Installed selenium4 when 'setup.py install' (#389) [Mori Atsushi] - - * Fix: installed selenium4 when setup.py install - - * Keep existing comparison operator -- Fix ios functional tests failed (#385) [Mori Atsushi] - - * Fix safari test(iOS) - - * Fix: find_by_ios_predicate - - * Delete find_by_uiautomation_tests - - since uiautomation is deprecated - - * Move non test files - - * Replace test app with the latest - - * Fix tests failed along to replaced test app - - * review comments - -Other -~~~~~ -- Bump 0.44. [Kazuaki Matsuo] -- Support get_display_density (#388) [Mori Atsushi] - - * Support get_display_density - - * Add get_display_density unittest - - * Add api doc - - * Add return description to api doc -- Support set_network_speed (#386) [Mori Atsushi] - - * Support set_nework_speed - - * Add set_network_speed unittest - - * Add api doc - - * revert unexpected change - - * revert change -- Update changelog for 0.43. [Kazuaki Matsuo] - - -v0.43 (2019-05-18) ------------------- - -New -~~~ -- Add assertions for w3c (#384) [Kazuaki Matsuo] -- Add isort to pre-commit (#379) [Mori Atsushi] - - * Add isort to pre-commit - - * Add isort.conf - - * Applied isort for test/unit - - * Add current dir to isrot arg - - * Add check to ci.sh - - * Use exit code for condition check in ci.sh - -Fix -~~~ -- Fix functional tests failed (android, push_file) (#375) [Mori - Atsushi] - - * Fix: test_push_file - - * Move remove_fs tests - - * Move teardown process - - * Delete selendroid test - - * tweak - - * Update along to review comments - - * Replace double quote with single quote under android dir - - * Remove creating tmp file - - * tweak -- Fix functional tests failed (android, ime/multi_action) (#372) [Mori - Atsushi] - - * Fix test failed: ime_tests, multi_action_tests - - * revert change and add impl for python3 - - * Remove py3 dependency - - * Change deepcopy to copy - - * Update ime_tests -- Fix functional tests failed (android, touch_action) (#374) [Mori - Atsushi] - - * Fix: test_drag_and_drop - - * Fix: test_long_press - - * Fix: long_press_x_y, swipe - - * Fix: press_and_wait - - * Fix: driver_drag_and_drop - - * Tweak - - * Add SLEEPY_TIME - - * Remove set with sleep and find_element - -Other -~~~~~ -- Bump 0.43. [Kazuaki Matsuo] -- [RD-34891] Assign w3c property on the command executor. (#382) - [Erustus Agutu] -- Get rid of sessionId (#383) [Kazuaki Matsuo] -- Divide functional appium tests into each module(android) (#378) [Mori - Atsushi] - - * Move non test files - - * Divide appium_tests into each module tests(android) - - * Skip contexts, find_by_image tests - - * Removed unnecessary codes -- Introduced pipfile (#376) [Mori Atsushi] - - * Added Pipfile - - Just created by pipenv install -r ci-requirements.txt - - * Introduced pipenv - - * Add Pipfile.lock to gitignore - - * Cover any minor versions for packages -- Move android commands to android package (#371) [Mori Atsushi] - - * Reorder mobilecommands - - * Move android commands to android package - - * Update setup.py to include added packages - - * Changed find_packages to whitelist style -- Update changelog for 0.42. [Kazuaki Matsuo] - - -v0.42 (2019-05-10) ------------------- - -New -~~~ -- Add return value. [Atsushi Mori] -- Add set_power_ac unittest. [Atsushi Mori] -- Added set_power_capacity unittest. [Atsushi Mori] - -Fix -~~~ -- Fix functional tests failed (android, appium_tests) (#366) [Mori - Atsushi] - - * Fix test failed: test_send_keys, test_screen_record - - * Fix test failed: test_update_settings - - * Fix test failed: test_start_activity_other_app - - * Move and rename helper package - - * Update along to review comments - - * Add return value to wait_for_element -- Fix poll_url in Python 3 (#370) [Kazuaki Matsuo] -- Fix functional tests failed (#364) [Mori Atsushi] - - * Fix test failed: element_location_in_view, set_text - - * Fix test failed: test_push_file - - * Merge test_pull_test into test_push_test - - * Fix test failed: test_pull_folder - - * Enable running by both py2 and py3 - - * Removed unnecessary codes - - * Remove magic number - -Other -~~~~~ -- Bump 0.42. [Kazuaki Matsuo] -- Support get_performance_data, get_performance_data_types (#368) [Mori - Atsushi] - - * Support get_performance_data, get_performance_data_types - - * Add api doc - - * Add performance unittest - - * Tweak - - * Update api doc -- Support set_gsm_voice (#367) [Mori Atsushi] - - * Support set_gsm_voice - - * Add set_gsm_voice unittest - - * Fix typo -- Support get_system_bars (#363) [Mori Atsushi] - - * Support get_system_bars - - * Add api doc - - * Add get_system_bars unittest - - * Remove FIXME -- Support make_gsm_call (#360) [Mori Atsushi] - - * Move const to gsm_signal_strength - - * Support make_gsm_call - - * Add make_gsm_call unittest - - * Move const to gsm class - - * Move get_dict_const to common.helper - - * Rename func - - * Use OrderedDict to keep defined order -- Support set_gsm_signal (#357) [Mori Atsushi] - - * Support set_gsm_signal - - * Fix: NONE_OR_UNKNOWN doesn't work - - * Add set_gsm_signal unittest - - * Use int for signal strength const - - * Raise exception when signal strength is out of range - - * Fix: wrong class name - - * Removed args validation - - Since arg validation already done by server side - - * Show warning log when arg is out of range - - * Some changes for less maintenance -- Mobile:pinchOpen and mobile:pinchClose no longer implemented in appium - drivers (#358) [Jonah] -- Remove unnecessary codes. [Atsushi Mori] -- Replace 'on' with AC_ON. [Atsushi Mori] -- Update api doc. [Atsushi Mori] -- Define AC_OFF, AC_ON as const. [Atsushi Mori] -- Skip pylint warnings. [Atsushi Mori] -- Update api doc. [Atsushi Mori] -- Support set_power_ac. [Atsushi Mori] -- Support set_power_capacity. [Atsushi Mori] -- Update changelog for 0.41. [Kazuaki Matsuo] -- Bump 0.41. [Kazuaki Matsuo] - - -v0.41 (2019-04-23) ------------------- - -New -~~~ -- Add send sms support (#351) [Mori Atsushi] - - * Support sendSms function - - * Added api doc - - * Add sms unittest - - * Revert unexpected changes - - * Update api doc -- Add pixelFormat in docstring (#346) [Kazuaki Matsuo] -- Add fingerprint unittest (#345) [Mori Atsushi] -- Add shake unittest (#344) [Mori Atsushi] - -Fix -~~~ -- Fix True/False in image settings, add boolean value in settings test - (#352) [Kazuaki Matsuo] - - * Fix True/False in image settings, add boolean value in settings test - - * use is for boolean - -Other -~~~~~ -- Make keep alive True by default (#348) [Kazuaki Matsuo] -- Move settings to mixin classes (#347) [Mori Atsushi] -- Update changelog for 0.40. [Kazuaki Matsuo] - - -v0.40 (2019-03-14) ------------------- - -Fix -~~~ -- Fix RuntimeError: maximum recursion depth exceeded in cmp happened - (#343) [Kazuaki Matsuo] - - * fix maximum recursion depth exceeded in sub classes - - * add docstring - - * add comparison of a number of commands - - * use issubclass to ensure the class is sub - -Other -~~~~~ -- Bump 0.40. [Kazuaki Matsuo] -- Update missing changelog in 0.39. [Kazuaki Matsuo] - - -v0.39 (2019-02-27) ------------------- - -New -~~~ -- Add direct connect flag to be able to handle directConnectXxxxc (#338) - [Kazuaki Matsuo] - - * add direct connect feature - - * rmeove todo - - * update readme, extract _update_command_executor - - * add logger - - * make log level info - - * show warning if no directConnectXxxxx in dict - - * tweak error message - - * tweak message format -- Add datamatcher (#335) [Kazuaki Matsuo] - - * add datamatcher - - * add zero case - - * defines search context for driver and element - -Other -~~~~~ -- Update changelog for 0.38. [Kazuaki Matsuo] -- Bump 0.38. [Kazuaki Matsuo] - - -v0.38 (2019-02-11) ------------------- -- Bump 0.38. [Kazuaki Matsuo] -- Remove io.open from getting version code (#334) [Kazuaki Matsuo] - - * remove io.open - - * remove appium module from release script - - -v0.37 (2019-02-10) ------------------- - -New -~~~ -- Add AppiumConnection to customise user agent (#327) [Kazuaki Matsuo] -- Add a test for reset (#326) [Kazuaki Matsuo] -- Add a simple class to control Appium execution from the client code - (#324) [Mykola Mokhnach] -- Add pressure option (#322) [Kazuaki Matsuo] - - * add pressure option - - * add a test, tweak comment and the method - - * fix typo -- Add a test case using another session id (#320) [Kazuaki Matsuo] - -Fix -~~~ -- Fix passing options to screen record commands (#330) [Mykola Mokhnach] - -Other -~~~~~ -- Cast set_location arguments to float (#332) [Mykola Mokhnach] -- Update changelog for 0.36. [Kazuaki MATSUO] -- Bump 0.36. [Kazuaki MATSUO] - - -v0.36 (2019-01-18) ------------------- -- Bump 0.36. [Kazuaki MATSUO] -- Import keyboard, add tests (#319) [Kazuaki Matsuo] -- Update changelog for 0.35. [Kazuaki MATSUO] - - -v0.35 (2019-01-17) ------------------- - -New -~~~ -- Add location unittest (#317) [Mori Atsushi] - - * Add test_location - - * Add test_set_location - - * Add test_toggle_location_services -- Add settings unittest (#315) [Mori Atsushi] - - * Add settings unittest - - * Remove unused import -- Added format to device_time as argument (#312) [Mori Atsushi] -- Add devicetime unittest (#309) [Mori Atsushi] - - * Add device time test - - * Removed unnecessary check from device time test - - * Changed assertion for device time test - - Along to review comments - - * Changed quote for string from double to single -- Add activities unittest (#310) [Tadashi Nemoto] - - * Add test_start_activity - - * Add current_activity and wait_activity - - * Fix pytest 4.0.2 - - * Add test_start_activity_with_opts - - * Added options -- Add network unittest (#308) [Mori Atsushi] - - * Add network connection test - - * Added set network connection test - - * Add toggle wifi test - - * Removed unnecessary codes from toggle wifi test - - * Changed assertion for set network connection test -- Add touch action unittest (#306) [Tadashi Nemoto] - - * Add press test - - * Add test_long_press - - * Add test_wait - - * Add remaining tests - - * Add tap - - * 10 -> 9 - - * Modify based on comment -- Add precommit (#304) [Kazuaki Matsuo] - - * add pre-commit hook - -Fix -~~~ -- Fixing broken pypi long description rendering (#303) [Prabhash] - - reference: https://packaging.python.org/guides/making-a-pypi-friendly-readme - - Tested at https://pypi.org/project/delayed-assert -- Fix overridden mixin method call (#297) [Mykola Mokhnach] - -Other -~~~~~ -- Bump 0.35. [Kazuaki MATSUO] -- Move device_time to a mixin class (#314) [Mori Atsushi] -- Define getting httpretty request body decoded by utf-8 (#313) [Kazuaki - Matsuo] - - * define httpretty_last_request_body - - * replace the order - - * update - - * rename -- Move action and keyboard helpers to mixin classes (#307) [Mykola - Mokhnach] -- Extract more webdriver methods into specialized mixin classes (#302) - [Mykola Mokhnach] -- Move specialized method groups to mixin classes (#301) [Mykola - Mokhnach] -- Update changelog for 0.34. [Kazuaki MATSUO] - - -v0.34 (2018-12-18) ------------------- - -Fix -~~~ -- Fix missing package, missing commands and a test (#296) [Kazuaki - Matsuo] - - * add extensions into package - - * add tests for context to make sure it loads - - * move command definition from extensions to root - -Other -~~~~~ -- Bump 0.34. [Kazuaki MATSUO] -- Update changelog for 0.33. [Kazuaki MATSUO] - - -v0.33 (2018-12-18) ------------------- - -New -~~~ -- Add newline in release script because of autopep8 (#292) [Kazuaki - Matsuo] - -Other -~~~~~ -- Bump 0.33. [Kazuaki MATSUO] -- Move read version (#294) [Kazuaki Matsuo] -- Update changelog for 0.32. [Kazuaki MATSUO] - - -v0.32 (2018-12-18) ------------------- - -New -~~~ -- Add unit tests for isLocked Library (#288) [Venkatesh Singh] - - * Add unit tests for isLocked Lib - - * moved isLocked library tests in lock.py -- Add unit test for lock lib (#287) [Venkatesh Singh] - - * Add unit test for lock lib - -Fix -~~~ -- Fixed few failing tests in appium_tests.py (#278) - [RajeshkumarAyyadurai] - - * fixed few failing tests in appium_tests.py - - * updated few tests in appium_tests.py by removing uiautomator strategy -- Fixed failing tests in find_by_accessibility_id_tests.py. - [RajeshkumarAyyadurai] - -Other -~~~~~ -- Bump 0.32. [Kazuaki MATSUO] -- Split driver methods into mixin classes (#291) [Mykola Mokhnach] -- Run with tox on travis (#290) [Kazuaki Matsuo] - - * run with tox on travis - - * update readme -- Improve pytest, adding pytest.ini and set default arguments (#284) - [Kazuaki Matsuo] -- Extract bytes and add a test for set clipboard (#282) [Kazuaki Matsuo] - - * extract bytes and add a test for set clipboard -- Introduce httpretty for unittest to mock Appium server (#281) [Kazuaki - Matsuo] - - * add httpretty - - * add clipboard tests as an example - - * add test for forceMjsonwp -- Update setup elements (#280) [Kazuaki Matsuo] - - * update setup elements - - * remove docgen since we can use markdown format in pypi -- Release automation (#276) [Kazuaki Matsuo] -- Updated requirements.txt file with version (#275) - [RajeshkumarAyyadurai] - - * updated required dependecies with version number as a best practice - - * updated required dependencies with version - - * updated pylint library version to support for python 2.7 -- Append document for recording screen (#271) [Kazuaki Matsuo] - - * append document for recording screen - - * add since appium 1.10.0 - - * remove Only works for real devices since the feature can work on both -- Update changelog for 0.31. [Kazuaki MATSUO] - - -v0.31 (2018-11-21) ------------------- -- V0.31. [Kazuaki MATSUO] -- Driver.push_file(destination_path, source_path) feature (#270) [Javon - Davis] - - * used base64 library for conversion - - * remove unnecessary library use - - * changed text in test file - - * * Using context when reading file - * changed docstring format - * Catch error thrown if file not present and present user with a better message - - * fixed incorrect file path in test - - * removed change in pul_file that broke backwards compat and updated docstring description for `destination_path` - - -v0.30 (2018-10-31) ------------------- - -New -~~~ -- Add release section in readme. [Kazuaki MATSUO] - -Fix -~~~ -- Fix python3 set_clipboard error (#267) [Kazuaki Matsuo] - - * fix python3 set_clipboard error - - * apply formatter - -Other -~~~~~ -- V0.30. [Kazuaki MATSUO] - - -v0.29 (2018-10-30) ------------------- - -New -~~~ -- Add an endpoint for pressing buttons (#262) [Alex] -- Add custom locator strategy (#260) [Jonathan Lipps] -- Add a duration for scroll for ios (#256) [Kazuaki Matsuo] - - * add a duration for scroll for ios - - * tweak default duration - - * apply autoformat - - * set 600 duration by default if it's w3c spec - - * skip wait if duration is none - - * add comment -- Add finger print (#252) [Kazuaki Matsuo] - - * add fingre print - - * apply auto format -- Add find_elements w3c for webelement (#251) [Kazuaki Matsuo] - - * add find_elements w3c for webelement - - * add tests for child elements - - * add todo for future work -- Add a github issue template (#250) [Kazuaki Matsuo] -- Add xdist port handling (#248) [Kazuaki Matsuo] - - * add handling port number to run ios tests in parallel - - * define PytestXdistWorker - - * use gw0 if the number of worker is over the count of workers -- Add autopep8 (#243) [Kazuaki Matsuo] - - * apply autopep8 - - * add development section as the first draft - - * relax max-line-length - - * add global-config -- Add toggle wifi command (#241) [joshuazhusince1986] - - * add toggle_wifi command - - * update comment to indicate toggle_wifi is only for Android -- Add selenium into ci-requirements (#240) [Kazuaki Matsuo] - - fix pylint - - add --py3k -- Add travis to run pylint and unit tests (#239) [Kazuaki Matsuo] - - * add pylint - - * add rcfile - - * tweak pylint - - * fix lint - - * add running pytest - - * tweak indentations -- Add tag view for android (#238) [Kazuaki Matsuo] - - * add tag view for android - - * fix typo... and tweak names of arguments - - * tweak docstring - - * add find element by viewtag section in readme - -Other -~~~~~ -- V0.29. [Kazuaki MATSUO] -- Bump selenium 3.14.1, call RemoteCommand without workaround (#259) - [Kazuaki Matsuo] - - * bump selenium 3.14.1, call RemoteCommand without workaround - - * make attributeValue check safe - - * define str = basestring for Python 2 - - * apply formatter - - * add missing value check -- Update obsolete link for mobile json wire protocol spec. (#257) - [Andrei Petre] -- Remove always_match and use first_match instead (#246) [Kazuaki - Matsuo] - - remove always_match and use first_match instead -- Use normal element for find image by (#236) [Kazuaki Matsuo] - - * use normal element - - * get rid of png - - * get rid of imagelement.py - - * apply formatter -- Typo fix: finiding -> finding (#245) [Andrew Fuller] -- Tweak PyPi URLs and add a badge (#232) [Kazuaki Matsuo] - - -v0.28 (2018-07-13) ------------------- - -Fix -~~~ -- Fix base64 encoded string (#231) [Kazuaki Matsuo] - -Other -~~~~~ -- V0.28. [Isaac Murchie] - - -v0.27 (2018-07-10) ------------------- - -New -~~~ -- Add support for is keyboard shown command. [Jonathan Lipps] -- Add find by image commands and tests (#224) [Jonathan Lipps] - - * add find by image commands and tests - - * remove and ignore pytest cache files - - * address review comments - - * fix docstrings -- Add flags argument to press_keycode (#222) [Mykola Mokhnach] - - * Add flags argument to press_keycode - - * Add flags to long press as well -- Add an endpoint for getting battery info (#217) [Mykola Mokhnach] -- Add wrappers for OpenCV-based image comparison (#216) [Mykola - Mokhnach] - - * Add wrappers for OpenCV-based image comparison - - * Tune some docs -- Add clipboard handlers (#209) [Mykola Mokhnach] - - * Add clipboard handlers - - * Fix documentation - - * fix options notation -- Add applications management endpoint handlers (#204) [Mykola Mokhnach] -- Add methods for start/stop screen record API endpoints (#201) [Mykola - Mokhnach] - - * Add methods for start/stop screen record API endpoints - - * Fix typo - - * Add a separate test for Android and get rid of redundant stuff - - * Tune documentation - - * Add videoSize arg description - - * Fix arg name -- Add appium prefix in create session and fix find_elements for W3C - (#196) [Kazuaki Matsuo] - - * add appium prefix in create session - - * fix find_elements by w3c for Appium - - * introduce forceMjsonwp - - * refine a bit - - * fix some tests - - * update the docset -- Add endpoints for lock/unlock. [Mykola Mokhnach] - -Other -~~~~~ -- V0.27. [Isaac Murchie] -- Set None as default value to lock device (#227) [Miguel Hernández] - - * Set 0 as default value to lock device - - * Set None as default value instead of 0 -- Avoid setting coordinates to null for touch actions (#214) [Mykola - Mokhnach] -- Change QUERY_APP_STATE request type to POST (#205) [Mykola Mokhnach] - - -v0.26 (2018-01-09) ------------------- -- V0.26. [Isaac Murchie] - - -v0.25 (2018-01-09) ------------------- - -New -~~~ -- Add method for getting current package. [Isaac Murchie] -- Add tests for ios class chain and rename methods a bit. [Kazuaki - MATSUO] -- Add class chain. [Kazuaki MATSUO] -- Add toggleTouchIdEnrollment. [Dan Graham] - -Fix -~~~ -- Fix typos in the README. [Mel Shafer] - -Other -~~~~~ -- V0.25. [Isaac Murchie] -- Only if key_name, key, and strategy are None do we need to set the - strategy to 'tapOutside'. This change allows setting just the strategy - to some other value, like 'swipeDown'. (#181) [Daniel Freer] -- Correct a wording. [Kazuaki MATSUO] -- Create README.md. [Kazuaki Matsuo] -- Append class chain related descriptions. [Kazuaki MATSUO] -- Update README to include instructions for using iOS predicates. [Emil - Petersen] -- Update docs for UIAutomation selector to include version requirement. - [Emil Petersen] - - -v0.24 (2016-12-20) ------------------- - -New -~~~ -- Added test cases for clear and find elements by ios predicate string. - [ben.zhou] -- Added clear to driver. Added find elements by ios predicate string. - [ben.zhou] - -Other -~~~~~ -- V0.24. [Isaac Murchie] -- DontStopAppOnReset instead of stopAppOnReset. [s.zubov] - - -v0.23 (2016-11-10) ------------------- - -New -~~~ -- Added touchId to driver (#143) [Dan Graham] - - * Added touchId to driver - - Wrote a test for it (still need help running Python tests though). Updated capabilities to use iOS 10.1 - -Other -~~~~~ -- V0.23. [Isaac Murchie] - - -v0.22 (2016-03-16) ------------------- -- V0.22. [Isaac Murchie] -- Use id instead of elementId. [Isaac Murchie] - - -v0.21 (2016-01-20) ------------------- - -New -~~~ -- Add device_time property. [Isaac Murchie] - -Fix -~~~ -- Fix saucetestcase to run under Python3. [Ling Lin] - - The module 'new' was removed. Instead of new.newclass, use type(). - -Other -~~~~~ -- V0.21. [Isaac Murchie] -- Update README.md. [tophercf] - - smallest win in history - - -v0.20 (2015-10-12) ------------------- -- V0.20. [Isaac Murchie] -- Revert actions change. [Isaac Murchie] - - -v0.19 (2015-10-09) ------------------- -- V0.19. [Isaac Murchie] -- Change 'actions' to 'gestures' in single action. [Isaac Murchie] - - -v0.18 (2015-10-07) ------------------- - -New -~~~ -- Add string file argument to driver.app_strings. [Isaac Murchie] -- Add wait_activity method for webdriver. [zhaoqifa] -- Add el.location_in_view method. [Isaac Murchie] - -Fix -~~~ -- Fixed typographical error, changed accomodate to accommodate in - README. [orthographic-pedant] -- Fix bug with monkeypatching. [Isaac Murchie] -- Fix to issue #71. [James Salt] -- Fix start_activity for Python 3.x. [Artur Tanistra] -- Fix start_activity for Python3. [Isaac Murchie] - -Other -~~~~~ -- V0.18. [Isaac Murchie] -- Remove dependency on enum. [Isaac Murchie] -- Bump version. [Isaac Murchie] -- Use WebDriverWait to implement wait_activity. [zhaoqifa] -- Make tap duration be handled as ms, not s. [Isaac Murchie] -- Bump version. [Isaac Murchie] -- Bump version. [Isaac Murchie] -- Move monkeypatched set_value into WebElement. [Isaac Murchie] - - -v0.14 (2015-03-06) ------------------- - -Fix -~~~ -- Fix issue with single tap. [Isaac Murchie] -- Fix handling of sauce test case so ImportError is suppressed. [Isaac - Murchie] - -Other -~~~~~ -- Bump version. [Isaac Murchie] -- Bump version. [Isaac Murchie] - - -v0.12 (2015-01-13) ------------------- - -New -~~~ -- Add base class for Sauce tests. [Isaac Murchie] -- Add remaining optional arguments to start_activity method. [Isaac - Murchie] - -Fix -~~~ -- Fix package names for starting activity. [Isaac Murchie] - -Other -~~~~~ -- Bump version. [Isaac Murchie] -- Update README.md. [Mikhail Martin] - - Missing dot causes errors. -- Update webdriver.py. [urtow] - - -v0.11 (2014-11-14) ------------------- - -New -~~~ -- Add toggle_location_services. [Isaac Murchie] - -Other -~~~~~ -- Bump version. [Isaac Murchie] -- Update webdriver.py. [urtow] - - Start_y - y-coordinate for start, not end - - -v0.10 (2014-09-24) ------------------- - -New -~~~ -- Added start_activity and tests. [Eric Millin] -- Added 'keyevent' since it is needed for Selendroid. [Payman Delshad] -- Add set_text method for Android. [Isaac Murchie] - -Other -~~~~~ -- Bump version. [Isaac Murchie] -- Removed complex_find, added get_settings, update_settings. [Jonah - Stiennon] -- Make long_press works with 'duration' parameter. [ianxiaohanxu] - - Add a new parameter 'duration = None' to _get_opts -- Typo fix! [Cass] -- Update README.md. [Johan Lundstroem] - - Verison -> Version -- Revert "Fix for #23: Re-add 'keyevent' temporarily." [Payman Delshad] - - This reverts commit ccbcaf809704bf1ac752d1b4446d1175b7434c36. - - -v0.9 (2014-07-07) ------------------ - -New -~~~ -- Add some more tests, fix others. [Isaac Murchie] -- Add ConnectionType enum. [Isaac Murchie] -- Add methods for Android ime access. [Isaac Murchie] -- Add network connection methods. [Isaac Murchie] -- Add strategy to hide_keyboard. [Isaac Murchie] -- Add necessary ios attributes. [Brad Pitcher] -- Add pull_file method. [Isaac Murchie] -- Add support for open_notifications. [Isaac Murchie] -- Add optional argument 'language' to app_strings. [Isaac Murchie] -- Add context method for simplicity. [Isaac Murchie] -- Add find methods to WebElement. [Isaac Murchie] -- Add reset and hide_keyboard. [Isaac Murchie] -- Add PyPi packaging setup. [Isaac Murchie] -- Add miscellaneous methods. [Isaac Murchie] -- Add touch and multi touch. [Isaac Murchie] -- Add accessibility id locator strategy. [Isaac Murchie] -- Add Android UIAutomator locator strategy. [Isaac Murchie] -- Add iOS UIAutomation locator strategy. [Isaac Murchie] -- Add context methods. [Isaac Murchie] - -Fix -~~~ -- Fix for #23: Re-add 'keyevent' temporarily. [Payman Delshad] -- Fix keycode command. [Isaac Murchie] -- Fix for Python 3. [Isaac Murchie] -- Fix typos with context. [Alexander Bayandin] -- Fix typo in README (resolve #12) [Alexander Bayandin] -- Fix timing. [Isaac Murchie] -- Fix setup for egg distro, and add install instructions. [Isaac - Murchie] - -Other -~~~~~ -- Bump version. [Isaac Murchie] -- Bump version. [Isaac Murchie] -- Change call to single-gesture tap. [Isaac Murchie] -- Bump version. [Isaac Murchie] -- Renamed keyevent to press_keycode and added long_press_keycode. - [Payman Delshad] -- Bump version. [Isaac Murchie] -- Numerous fixes. [Alexander Bayandin] - - 1. fix comparation with None - 2. remove unused imports - 3. fix imports order (according to pep8) - 4. style fixes (according to pep8) - 5. another minor fixes -- Update zoom/pinch signatures. [Isaac Murchie] -- Remove tag name, use class. [Isaac Murchie] -- Don't send multitouch for single finger tap. [Isaac Murchie] -- Miscellaneous fixes. [Isaac Murchie] -- Update desired caps. [Isaac Murchie] -- Basic module structure. [Isaac Murchie] - - diff --git a/Makefile b/Makefile index 21fe11d13..4ed823f49 100644 --- a/Makefile +++ b/Makefile @@ -1,36 +1,50 @@ .PHONY: Commands for developers .PHONY: check-all -check-all: ## Run all lint checks and unittest - @echo "[Notice] If you'd like to run commands with same env to CI, please run \`tox\`." - @bash ci.sh +check-all: check unittest .PHONY: check check: check-lint check-format .PHONY: check-lint check-lint: - python -m ruff check . + uv run ruff check . + uv run mypy appium .PHONY: check-format check-format: - python -m ruff format --check . + uv run ruff format --check . .PHONY: fix fix: fix-lint fix-format .PHONY: fix-lint fix-lint: - python -m ruff check --fix . + uv run ruff check --fix . .PHONY: fix-format fix-format: - python -m ruff format . - + uv run ruff format . + +.PHONY: install-uv +install-uv: + @command -v uv >/dev/null 2>&1 || { \ + echo "Installing uv"; \ + curl -LsSf https://astral.sh/uv/install.sh | sh; \ + if [ -n "$$GITHUB_PATH" ]; then \ + echo "PATH=$$HOME/.local/bin:$$PATH" >> $$GITHUB_PATH; \ + else \ + echo "Please restart your shell or run 'exec $$SHELL'"; \ + fi; \ + } + +.PHONY: sync-dev +sync-dev: + uv sync --dev .PHONY: unittest unittest: ## Run unittest - python -m pytest $(ARGS) test/unit/ + uv run pytest $(ARGS) test/unit/ .PHONY: help help: ## Display this help screen diff --git a/Pipfile b/Pipfile deleted file mode 100644 index f0fea58fe..000000000 --- a/Pipfile +++ /dev/null @@ -1,19 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -httpretty = "~=1.1" -mock = "~=5.2" -pre-commit = "~=4.2" -pytest = "~=8.4" -pytest-cov = "~=5.0" -python-dateutil = "~=2.9" -ruff = "~=0.11.13" -tox = "~=4.26" -types-python-dateutil = "~=2.9" - -[packages] -selenium = "==4.33.0" -typing-extensions = "~=4.13.2" diff --git a/README.md b/README.md index c1688a55d..3fe6fe8bc 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ download and unarchive the source tarball (Appium-Python-Client-X.X.tar.gz). ```shell tar -xvf Appium-Python-Client-X.X.tar.gz cd Appium-Python-Client-X.X - python setup.py install + pip install . ``` 3. Install from source via [GitHub](https://github.com/appium/python-client). @@ -34,7 +34,7 @@ download and unarchive the source tarball (Appium-Python-Client-X.X.tar.gz). ```shell git clone git@github.com:appium/python-client.git cd python-client - python setup.py install + pip install . ``` ## Compatibility Matrix @@ -56,8 +56,8 @@ the Selenium Python binding update might affect the Appium Python Client behavio For example, some changes in the Selenium binding could break the Appium client. > **Note** -> We strongly recommend you manage dependencies with version management tools such as Pipenv and requirements.txt -> to keep compatible version combinations. +> We strongly recommend you manage dependencies with version management tools such as +> [uv](https://docs.astral.sh/uv/) to keep compatible version combinations. ### Quick migration guide from v4 to v5 @@ -71,21 +71,19 @@ For example, some changes in the Selenium binding could break the Appium client. options=UiAutomator2Options().load_capabilities(desired_caps), direct_connection=True, keep_alive=False, - strict_ssl=False + strict_ssl=False, ) # after from appium.webdriver.client_config import AppiumClientConfig + client_config = AppiumClientConfig( remote_server_addr=SERVER_URL_BASE, direct_connection=True, keep_alive=False, ignore_certificates=True, ) - driver = webdriver.Remote( - options=UiAutomator2Options().load_capabilities(desired_caps), - client_config=client_config - ) + driver = webdriver.Remote(options=UiAutomator2Options().load_capabilities(desired_caps), client_config=client_config) ``` - Note that you can keep using `webdriver.Remote(url, options=options, client_config=client_config)` format as well. In such case the `remote_server_addr` argument of `AppiumClientConfig` constructor would have priority over the `url` argument of `webdriver.Remote` constructor. @@ -97,8 +95,6 @@ For example, some changes in the Selenium binding could break the Appium client. - [appium/webdriver/extensions/action_helpers.py](appium/webdriver/extensions/action_helpers.py) - https://www.selenium.dev/documentation/webdriver/actions_api/ - https://www.youtube.com/watch?v=oAJ7jwMNFVU - - https://appiumpro.com/editions/30-ios-specific-touch-action-methods - - https://appiumpro.com/editions/29-automating-complex-gestures-with-the-w3c-actions-api - Deprecated `AppiumBy.WINDOWS_UI_AUTOMATION`, which has no usage right now. ### Quick migration guide from v2 to v3 @@ -140,7 +136,7 @@ from selenium.webdriver.common.actions.pointer_input import PointerInput actions = ActionChains(driver) # override as 'touch' pointer action -actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch")) +actions.w3c_actions = ActionBuilder(driver, 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.pause(2) @@ -175,6 +171,7 @@ environment: import pytest from appium import webdriver + # Options are only available since client version 2.3.0 # If you use an older client then switch to desired_capabilities # instead: https://github.com/appium/python-client/pull/720 @@ -202,7 +199,7 @@ def appium_service(): service.stop() -def create_ios_driver(custom_opts = None): +def create_ios_driver(custom_opts=None): options = XCUITestOptions() options.platformVersion = '13.4' options.udid = '123456789ABC' @@ -212,7 +209,7 @@ def create_ios_driver(custom_opts = None): return webdriver.Remote(f'http://{APPIUM_HOST}:{APPIUM_PORT}', options=options) -def create_android_driver(custom_opts = None): +def create_android_driver(custom_opts=None): options = UiAutomator2Options() options.platformVersion = '10' options.udid = '123456789ABC' @@ -251,9 +248,7 @@ def android_driver(): def test_ios_click(appium_service, ios_driver_factory): # Usage of the context manager ensures the driver session is closed properly # after the test completes. Otherwise, make sure to call `driver.quit()` on teardown. - with ios_driver_factory({ - 'appium:app': '/path/to/app/UICatalog.app.zip' - }) as driver: + with ios_driver_factory({'appium:app': '/path/to/app/UICatalog.app.zip'}) as driver: el = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='item') el.click() @@ -261,10 +256,12 @@ def test_ios_click(appium_service, ios_driver_factory): def test_android_click(appium_service, android_driver_factory): # Usage of the context manager ensures the driver session is closed properly # after the test completes. Otherwise, make sure to call `driver.quit()` on teardown. - with android_driver_factory({ - 'appium:app': '/path/to/app/test-app.apk', - 'appium:udid': '567890', - }) as driver: + with android_driver_factory( + { + 'appium:app': '/path/to/app/test-app.apk', + 'appium:udid': '567890', + } + ) as driver: el = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='item') el.click() ``` @@ -302,6 +299,7 @@ Then python client will switch its endpoint to the one specified by the values o ```python from appium import webdriver + # Options are only available since client version 2.3.0 # If you use an older client then switch to desired_capabilities # instead: https://github.com/appium/python-client/pull/720 @@ -310,22 +308,21 @@ from appium.webdriver.client_config import AppiumClientConfig # load_capabilities API could be used to # load options mapping stored in a dictionary -options = XCUITestOptions().load_capabilities({ - 'platformVersion': '13.4', - 'deviceName': 'iPhone Simulator', - 'app': '/full/path/to/app/UICatalog.app.zip', -}) - -client_config = AppiumClientConfig( - remote_server_addr='http://127.0.0.1:4723', - direct_connection=True +options = XCUITestOptions().load_capabilities( + { + 'platformVersion': '13.4', + 'deviceName': 'iPhone Simulator', + 'app': '/full/path/to/app/UICatalog.app.zip', + } ) +client_config = AppiumClientConfig(remote_server_addr='http://127.0.0.1:4723', direct_connection=True) + driver = webdriver.Remote( # Appium1 points to http://127.0.0.1:4723/wd/hub by default 'http://127.0.0.1:4723', options=options, - client_config=client_config + client_config=client_config, ) ``` @@ -335,6 +332,7 @@ driver = webdriver.Remote( ```python from appium import webdriver + # Options are only available since client version 2.3.0 # If you use an older client then switch to desired_capabilities # instead: https://github.com/appium/python-client/pull/720 @@ -359,10 +357,7 @@ from appium import webdriver from selenium.webdriver.remote.client_config import ClientConfig -client_config = ClientConfig( - remote_server_addr='http://127.0.0.1:4723', - ignore_certificates=True -) +client_config = ClientConfig(remote_server_addr='http://127.0.0.1:4723', ignore_certificates=True) driver = webdriver.Remote(client_config.remote_server_addr, options=options, client_config=client_config) ``` @@ -380,12 +375,9 @@ import urllib3 from appium.webdriver.appium_connection import AppiumConnection # Retry connection error up to 3 times. -init_args_for_pool_manage = { - 'retries': urllib3.util.retry.Retry(total=3, connect=3, read=False) -} +init_args_for_pool_manage = {'retries': urllib3.util.retry.Retry(total=3, connect=3, read=False)} appium_executor = AppiumConnection( - remote_server_addr='http://127.0.0.1:4723', - init_args_for_pool_manage=init_args_for_pool_manage + remote_server_addr='http://127.0.0.1:4723', init_args_for_pool_manage=init_args_for_pool_manage ) options = XCUITestOptions() @@ -404,19 +396,22 @@ from appium.options.ios import XCUITestOptions from appium.webdriver.appium_connection import AppiumConnection + class CustomAppiumConnection(AppiumConnection): # Can add your own methods for the custom class pass + custom_executor = CustomAppiumConnection(remote_server_addr='http://127.0.0.1:4723') -options = XCUITestOptions().load_capabilities({ - 'platformVersion': '13.4', - 'deviceName': 'iPhone Simulator', - 'app': '/full/path/to/app/UICatalog.app.zip', -}) +options = XCUITestOptions().load_capabilities( + { + 'platformVersion': '13.4', + 'deviceName': 'iPhone Simulator', + 'app': '/full/path/to/app/UICatalog.app.zip', + } +) driver = webdriver.Remote(custom_executor, options=options) - ``` The `AppiumConnection` can set `selenium.webdriver.remote.client_config.ClientConfig` as well. @@ -444,68 +439,102 @@ You have two methods to extend the read timeout. - Apply `ruff` as pre commit hook - Run `make` command for development. See `make help` output for details - Docstring style: [Google Style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) -- `gitchangelog` generates `CHANGELOG.rst` ### Setup -- `pip install --user pipenv` -- `python -m pipenv lock --clear` - - If you experience `Locking Failed! unknown locale: UTF-8` error, then refer [pypa/pipenv#187](https://github.com/pypa/pipenv/issues/187) to solve it. -- `python -m pipenv install --dev --system` -- `pre-commit install` +```bash +make install-uv +exec $SHELL +make sync-dev +``` + +Running above commands should automatically setup the virtual environment for the project +using the default system Python version and put it into the `.venv` folder under the project root. +If you'd like to customize the Python version then run the following command before `make sync-dev`: -### Run tests +```bash +uv venv --python +``` -You can run all of the tests running on CI via `tox` in your local. +where `` is the actual Python version, for example `3.12`. + +If you want to customize the folder where uv stores the virtual environment by default +(e.g. `.venv`) then add an argument containing the destination folder path to the above command: ```bash -$ tox +uv venv /venv/root/folder ``` -You also can run particular tests like below. +In order to activate the newly created virtual environment you may either source it: + +```bash +source /venv/root/folder/bin/activate +``` + +or add it to PATH: + +```bash +export "PATH=/venv/root/folder/bin:$PATH" +``` + +### Linting And Formatting + +Run linter and format checks + +```bash +make check +``` + +Address autofixable linter and formatting issues + +```bash +make fix +``` + +### Testing #### Unit ```bash -$ pytest test/unit +make unittest ``` -Run with `pytest-xdist` +Run in parallel (2 threads) ```bash -$ pytest -n 2 test/unit +make unittest ARGS="-n 2" ``` #### Functional ```bash -$ pytest test/functional/ios/search_context/find_by_ios_class_chain_tests.py +uv run pytest test/functional/ios/search_context/find_by_ios_class_chain_tests.py ``` #### In parallel for iOS 1. Create simulators named 'iPhone X - 8100' and 'iPhone X - 8101' -2. Install test libraries via pip, `pip install pytest pytest-xdist` -3. Run tests +1. Run tests ```bash -$ pytest -n 2 test/functional/ios/search_context/find_by_ios_class_chain_tests.py +uv run pytest -n 2 test/functional/ios/search_context/find_by_ios_class_chain_tests.py ``` ## Release -Follow the below steps. +In case you need to release a version manually. ```bash -$ pip install twine -$ pip install git+git://github.com/vaab/gitchangelog.git # Getting via GitHub repository is necessary for Python 3.7 -# Type the new version number and 'yes' if you can publish it -# You can test the command with DRY_RUN -$ DRY_RUN=1 ./release.sh -$ ./release.sh # release -``` +rm -rf dist +# bumping the version, building a package and creating a tag. +uv run semantic-release version --patch|--minor|--major -If the `pypi` was not able to publish with user name and password, please try out `-u` and `-p` option by yourself with `twine` such as `twine upload -u -p dist/Appium-Python-Client-4.1.0.tar.gz`. +# To publish the version's module to pypi +UV_PUBLISH_TOKEN= uv publish + +# To push built modules in 'dist' directory to the GH release page. +uv run semantic-release publish +``` ## License diff --git a/appium/options/android/__init__.py b/appium/options/android/__init__.py index 8926c5a87..e4ab2bd1c 100644 --- a/appium/options/android/__init__.py +++ b/appium/options/android/__init__.py @@ -1,2 +1,4 @@ from .espresso.base import EspressoOptions from .uiautomator2.base import UiAutomator2Options + +__all__ = ['EspressoOptions', 'UiAutomator2Options'] diff --git a/appium/options/common/__init__.py b/appium/options/common/__init__.py index a7a37ea6f..7545b4793 100644 --- a/appium/options/common/__init__.py +++ b/appium/options/common/__init__.py @@ -1 +1,3 @@ from .base import AppiumOptions + +__all__ = ['AppiumOptions'] diff --git a/appium/options/common/base.py b/appium/options/common/base.py index c546c5058..5ac7b2e36 100644 --- a/appium/options/common/base.py +++ b/appium/options/common/base.py @@ -55,6 +55,9 @@ class AppiumOptions( 'setWindowRect', 'timeouts', 'unhandledPromptBehavior', + 'strictFileInteractability', # WebDriver spec v2 https://www.w3.org/TR/webdriver2/ + 'userAgent', # WebDriver spec v2 https://www.w3.org/TR/webdriver2/ + 'webSocketUrl', # WebDriver BiDi ] ) _OSS_W3C_CONVERSION = { @@ -69,7 +72,7 @@ def __init__(self) -> None: # FIXME: https://github.com/SeleniumHQ/selenium/issues/10755 self._ignore_local_proxy = False - def set_capability(self: T, name: str, value: Any) -> T: + def set_capability(self: T, name: str, value: Any) -> T: # type: ignore[override] w3c_name = name if name in self.W3C_CAPABILITY_NAMES or ':' in name else f'{APPIUM_PREFIX}{name}' if value is None: if w3c_name in self._caps: diff --git a/appium/options/flutter_integration/__init__.py b/appium/options/flutter_integration/__init__.py index ba044a8aa..731671682 100644 --- a/appium/options/flutter_integration/__init__.py +++ b/appium/options/flutter_integration/__init__.py @@ -13,3 +13,5 @@ # limitations under the License. from .base import FlutterOptions + +__all__ = ['FlutterOptions'] diff --git a/appium/options/gecko/__init__.py b/appium/options/gecko/__init__.py index 1dfd32877..3ad9508a6 100644 --- a/appium/options/gecko/__init__.py +++ b/appium/options/gecko/__init__.py @@ -1 +1,3 @@ from .base import GeckoOptions + +__all__ = ['GeckoOptions'] diff --git a/appium/options/ios/__init__.py b/appium/options/ios/__init__.py index 21e82f751..e38c958d0 100644 --- a/appium/options/ios/__init__.py +++ b/appium/options/ios/__init__.py @@ -1,2 +1,4 @@ from .safari.base import SafariOptions from .xcuitest.base import XCUITestOptions + +__all__ = ['SafariOptions', 'XCUITestOptions'] diff --git a/appium/options/ios/xcuitest/base.py b/appium/options/ios/xcuitest/base.py index 02143a095..0d349934c 100644 --- a/appium/options/ios/xcuitest/base.py +++ b/appium/options/ios/xcuitest/base.py @@ -72,6 +72,7 @@ from .wda.keychain_path_option import KeychainPathOption from .wda.max_typing_frequency_option import MaxTypingFrequencyOption from .wda.mjpeg_server_port_option import MjpegServerPortOption +from .wda.prebuilt_wda_path_option import PrebuiltWdaPathOption from .wda.process_arguments_option import ProcessArgumentsOption from .wda.result_bundle_path_option import ResultBundlePathOption from .wda.screenshot_quality_option import ScreenshotQualityOption @@ -83,6 +84,7 @@ from .wda.use_native_caching_strategy_option import UseNativeCachingStrategyOption from .wda.use_new_wda_option import UseNewWdaOption from .wda.use_prebuilt_wda_option import UsePrebuiltWdaOption +from .wda.use_preinstalled_wda_option import UsePreinstalledWdaOption from .wda.use_simple_build_test_option import UseSimpleBuildTestOption from .wda.use_xctestrun_file_option import UseXctestrunFileOption from .wda.wait_for_idle_timeout_option import WaitForIdleTimeoutOption @@ -171,6 +173,7 @@ class XCUITestOptions( KeychainPathOption, MaxTypingFrequencyOption, MjpegServerPortOption, + PrebuiltWdaPathOption, ProcessArgumentsOption, ResultBundlePathOption, ScreenshotQualityOption, @@ -182,6 +185,7 @@ class XCUITestOptions( UseNativeCachingStrategyOption, UseNewWdaOption, UsePrebuiltWdaOption, + UsePreinstalledWdaOption, UseSimpleBuildTestOption, UseXctestrunFileOption, WaitForIdleTimeoutOption, diff --git a/appium/options/ios/xcuitest/wda/prebuilt_wda_path_option.py b/appium/options/ios/xcuitest/wda/prebuilt_wda_path_option.py new file mode 100644 index 000000000..f26d12f0a --- /dev/null +++ b/appium/options/ios/xcuitest/wda/prebuilt_wda_path_option.py @@ -0,0 +1,39 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, 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 Optional + +from appium.options.common.supports_capabilities import SupportsCapabilities + +PREBUILT_WDA_PATH = 'prebuiltWDAPath' + + +class PrebuiltWdaPathOption(SupportsCapabilities): + @property + def prebuilt_wda_path(self) -> Optional[str]: + """ + The path to the prebuilt WebDriverAgent. + """ + return self.get_capability(PREBUILT_WDA_PATH) + + @prebuilt_wda_path.setter + def prebuilt_wda_path(self, value: str) -> None: + """ + The path to the prebuilt WebDriverAgent. This should be the path to the + WebDriverAgent.xcarchive file or the WebDriverAgent.app bundle. + """ + self.set_capability(PREBUILT_WDA_PATH, value) diff --git a/appium/options/ios/xcuitest/wda/use_preinstalled_wda_option.py b/appium/options/ios/xcuitest/wda/use_preinstalled_wda_option.py new file mode 100644 index 000000000..547d87f90 --- /dev/null +++ b/appium/options/ios/xcuitest/wda/use_preinstalled_wda_option.py @@ -0,0 +1,40 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, 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 Optional + +from appium.options.common.supports_capabilities import SupportsCapabilities + +USE_PREINSTALLED_WDA = 'usePreinstalledWDA' + + +class UsePreinstalledWdaOption(SupportsCapabilities): + @property + def use_preinstalled_wda(self) -> Optional[bool]: + """ + Whether to use a preinstalled WebDriverAgent. + """ + return self.get_capability(USE_PREINSTALLED_WDA) + + @use_preinstalled_wda.setter + def use_preinstalled_wda(self, value: bool) -> None: + """ + Whether to use a preinstalled WebDriverAgent. If true, Appium will not + build and install the WebDriverAgent, but will use an existing one. + Defaults to false. + """ + self.set_capability(USE_PREINSTALLED_WDA, value) diff --git a/appium/options/mac/__init__.py b/appium/options/mac/__init__.py index 41a091df5..4c9945356 100644 --- a/appium/options/mac/__init__.py +++ b/appium/options/mac/__init__.py @@ -1 +1,3 @@ from .mac2.base import Mac2Options + +__all__ = ['Mac2Options'] diff --git a/appium/options/windows/__init__.py b/appium/options/windows/__init__.py index 12d31fe34..2a4617c6e 100644 --- a/appium/options/windows/__init__.py +++ b/appium/options/windows/__init__.py @@ -1 +1,3 @@ from .windows.base import WindowsOptions + +__all__ = ['WindowsOptions'] diff --git a/appium/protocols/webdriver/can_find_elements.py b/appium/protocols/webdriver/can_find_elements.py index 088d9fb0b..07b0b8279 100644 --- a/appium/protocols/webdriver/can_find_elements.py +++ b/appium/protocols/webdriver/can_find_elements.py @@ -12,13 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import TYPE_CHECKING, Dict, List, Protocol, Union +from typing import TYPE_CHECKING, Dict, List, Protocol, Union, runtime_checkable if TYPE_CHECKING: from appium.webdriver.webelement import WebElement +@runtime_checkable class CanFindElements(Protocol): + """Protocol for objects that can find web elements. + + Any class implementing this protocol must provide: + - find_element(by, value): Find a single element + - find_elements(by, value): Find multiple elements + """ + def find_element(self, by: str, value: Union[str, Dict, None] = None) -> 'WebElement': ... def find_elements(self, by: str, value: Union[str, Dict, None] = None) -> List['WebElement']: ... diff --git a/appium/version.py b/appium/version.py index d946ff722..6398ce531 100644 --- a/appium/version.py +++ b/appium/version.py @@ -1 +1,17 @@ -version = '5.1.1' +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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 importlib.metadata import version as _metadata_version + +version = _metadata_version('Appium-Python-Client') diff --git a/appium/webdriver/__init__.py b/appium/webdriver/__init__.py index 062d726b1..6a0abb2ce 100644 --- a/appium/webdriver/__init__.py +++ b/appium/webdriver/__init__.py @@ -18,3 +18,5 @@ from .webdriver import WebDriver as Remote from .webelement import WebElement + +__all__ = ['Remote', 'WebElement'] diff --git a/appium/webdriver/common/appiumby.py b/appium/webdriver/common/appiumby.py index 145268992..371573ab0 100644 --- a/appium/webdriver/common/appiumby.py +++ b/appium/webdriver/common/appiumby.py @@ -49,5 +49,6 @@ class AppiumBy(By): '-flutter semantics label', '-flutter type', '-flutter key', + '-flutter text', '-flutter text containing', ] diff --git a/appium/webdriver/extensions/android/activities.py b/appium/webdriver/extensions/android/activities.py index 807b6a1f7..cdcfdc25c 100644 --- a/appium/webdriver/extensions/android/activities.py +++ b/appium/webdriver/extensions/android/activities.py @@ -12,35 +12,33 @@ # See the License for the specific language governing permissions and # limitations under the License. -from selenium.common.exceptions import TimeoutException, UnknownMethodException +from selenium.common.exceptions import TimeoutException from selenium.webdriver.support.ui import WebDriverWait 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 -class Activities(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Activities(CanExecuteCommands, CanExecuteScripts): @property def current_activity(self) -> str: """Retrieves the current activity running on the device. + Requires the Appium driver to support the `mobile: getCurrentActivity` execute method. + Returns: str: The current activity name running on the device """ ext_name = 'mobile: getCurrentActivity' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_CURRENT_ACTIVITY)['value'] + return self.execute_script(ext_name) def wait_activity(self, activity: str, timeout: int, interval: int = 1) -> bool: """Wait for an activity: block until target activity presents or time out. This is an Android-only method. + Requires the Appium driver to support the `mobile: getCurrentActivity` execute method. + Args: activity: target activity timeout: max wait time, in seconds @@ -50,14 +48,9 @@ def wait_activity(self, activity: str, timeout: int, interval: int = 1) -> bool: `True` if the target activity is shown """ try: - WebDriverWait(self, timeout, interval).until(lambda d: d.current_activity == activity) + WebDriverWait(self, timeout, interval).until( # type: ignore[type-var] + lambda d: d.current_activity == activity + ) return True except TimeoutException: return False - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.GET_CURRENT_ACTIVITY, - 'GET', - '/session/$sessionId/appium/device/current_activity', - ) diff --git a/appium/webdriver/extensions/android/common.py b/appium/webdriver/extensions/android/common.py index fe75260b5..a1036c82d 100644 --- a/appium/webdriver/extensions/android/common.py +++ b/appium/webdriver/extensions/android/common.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -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 class Common(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): @@ -28,32 +26,10 @@ def open_notifications(self) -> Self: Returns: Union['WebDriver', 'Common']: Self instance """ - ext_name = 'mobile: openNotifications' - try: - self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.OPEN_NOTIFICATIONS, {}) + self.execute_script('mobile: openNotifications') return self @property def current_package(self) -> str: """Retrieves the current package running on the device.""" - ext_name = 'mobile: getCurrentPackage' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_CURRENT_PACKAGE)['value'] - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.GET_CURRENT_PACKAGE, - 'GET', - '/session/$sessionId/appium/device/current_package', - ) - self.command_executor.add_command( - Command.OPEN_NOTIFICATIONS, - 'POST', - '/session/$sessionId/appium/device/open_notifications', - ) + return self.execute_script('mobile: getCurrentPackage') diff --git a/appium/webdriver/extensions/android/display.py b/appium/webdriver/extensions/android/display.py index 28abdcbbf..4ee29ba79 100644 --- a/appium/webdriver/extensions/android/display.py +++ b/appium/webdriver/extensions/android/display.py @@ -12,18 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -from selenium.common.exceptions import UnknownMethodException - 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 -class Display(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Display(CanExecuteCommands, CanExecuteScripts): def get_display_density(self) -> int: """Get the display density, Android only + Requires the Appium driver to support the `mobile: getDisplayDensity` execute method. + Returns: The display density of the Android device(dpi) @@ -34,15 +32,4 @@ def get_display_density(self) -> int: int: The display density """ ext_name = 'mobile: getDisplayDensity' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_DISPLAY_DENSITY)['value'] - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.GET_DISPLAY_DENSITY, - 'GET', - '/session/$sessionId/appium/device/display_density', - ) + return self.execute_script(ext_name) diff --git a/appium/webdriver/extensions/android/gsm.py b/appium/webdriver/extensions/android/gsm.py index ed43d3c66..56aedbd53 100644 --- a/appium/webdriver/extensions/android/gsm.py +++ b/appium/webdriver/extensions/android/gsm.py @@ -12,15 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -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 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 class GsmCallActions: @@ -48,7 +45,7 @@ class GsmVoiceState: ON = 'on' -class Gsm(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Gsm(CanExecuteCommands, CanExecuteScripts): def make_gsm_call(self, phone_number: str, action: str) -> Self: """Make GSM call (Emulator only) @@ -73,11 +70,7 @@ def make_gsm_call(self, phone_number: str, action: str) -> Self: f'(e.g. {GsmCallActions.__name__}.CALL)' ) args = {'phoneNumber': phone_number, 'action': action} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.MAKE_GSM_CALL, args) + self.execute_script(ext_name, args) return self def set_gsm_signal(self, strength: int) -> Self: @@ -102,13 +95,7 @@ def set_gsm_signal(self, strength: int) -> Self: f'{strength} is out of range. Consider using one of {list(constants.keys())} constants. ' f'(e.g. {GsmSignalStrength.__name__}.GOOD)' ) - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, {'strength': strength}) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute( - Command.SET_GSM_SIGNAL, {'signalStrength': strength, 'signalStrengh': strength} - ) + self.execute_script(ext_name, {'strength': strength}) return self def set_gsm_voice(self, state: str) -> Self: @@ -134,14 +121,5 @@ def set_gsm_voice(self, state: str) -> Self: f'(e.g. {GsmVoiceState.__name__}.HOME)' ) args = {'state': state} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.SET_GSM_VOICE, args) + self.execute_script(ext_name, args) return self - - def _add_commands(self) -> None: - self.command_executor.add_command(Command.MAKE_GSM_CALL, 'POST', '/session/$sessionId/appium/device/gsm_call') - self.command_executor.add_command(Command.SET_GSM_SIGNAL, 'POST', '/session/$sessionId/appium/device/gsm_signal') - self.command_executor.add_command(Command.SET_GSM_VOICE, 'POST', '/session/$sessionId/appium/device/gsm_voice') diff --git a/appium/webdriver/extensions/android/nativekey.py b/appium/webdriver/extensions/android/nativekey.py index 05b558790..59362681d 100644 --- a/appium/webdriver/extensions/android/nativekey.py +++ b/appium/webdriver/extensions/android/nativekey.py @@ -13,6 +13,50 @@ # limitations under the License. +class AndroidKeyMetastate: + """Keyboard metastate constants for Android key events. + + These constants can be combined with bitwise OR and passed to + Keyboard.press_keycode or Keyboard.long_press_keycode as metastate. + Values are based on android.view.KeyEvent. + https://developer.android.com/reference/android/view/KeyEvent + """ + + # No modifiers. + NONE = 0 + + # This mask is used to check whether one of the SHIFT meta keys is pressed. + META_SHIFT_ON = 0x01 + META_SHIFT_LEFT_ON = 0x40 + META_SHIFT_RIGHT_ON = 0x80 + + # This mask is used to check whether one of the ALT meta keys is pressed. + META_ALT_ON = 0x02 + META_ALT_LEFT_ON = 0x10 + META_ALT_RIGHT_ON = 0x20 + + # This mask is used to check whether one of the SYM meta keys is pressed. + META_SYM_ON = 0x04 + + # This mask is used to check whether the FUNCTION meta key is pressed. + META_FUNCTION_ON = 0x08 + + # This mask is used to check whether one of the CTRL meta keys is pressed. + META_CTRL_ON = 0x1000 + META_CTRL_LEFT_ON = 0x2000 + META_CTRL_RIGHT_ON = 0x4000 + + # This mask is used to check whether one of the META meta keys is pressed. + META_META_ON = 0x10000 + META_META_LEFT_ON = 0x20000 + META_META_RIGHT_ON = 0x40000 + + # Lock key states. + META_CAPS_LOCK_ON = 0x100000 + META_NUM_LOCK_ON = 0x200000 + META_SCROLL_LOCK_ON = 0x400000 + + class AndroidKey: # Key code constant: Unknown key code. UNKNOWN = 0 diff --git a/appium/webdriver/extensions/android/network.py b/appium/webdriver/extensions/android/network.py index 6054e29d9..ad039104c 100644 --- a/appium/webdriver/extensions/android/network.py +++ b/appium/webdriver/extensions/android/network.py @@ -12,15 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -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 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 class NetSpeed: @@ -41,7 +38,7 @@ class NetworkMask: AIRPLANE_MODE = 0b001 -class Network(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Network(CanExecuteCommands, CanExecuteScripts): @property def network_connection(self) -> int: """Returns an integer bitmask specifying the network connection type. @@ -51,18 +48,19 @@ def network_connection(self) -> int: This API only works reliably on emulators (any version) and real devices since API level 31. + + Requires the Appium driver to support the `mobile: getConnectivity` execute method. + + Returns: + The current network connection bitmask """ ext_name = 'mobile: getConnectivity' - try: - result_map = self.assert_extension_exists(ext_name).execute_script(ext_name) - return ( - (NetworkMask.WIFI if result_map['wifi'] else 0) - | (NetworkMask.DATA if result_map['data'] else 0) - | (NetworkMask.AIRPLANE_MODE if result_map['airplaneMode'] else 0) - ) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_NETWORK_CONNECTION, {})['value'] + result_map = self.execute_script(ext_name) + return ( + (NetworkMask.WIFI if result_map['wifi'] else 0) + | (NetworkMask.DATA if result_map['data'] else 0) + | (NetworkMask.AIRPLANE_MODE if result_map['airplaneMode'] else 0) + ) def set_network_connection(self, connection_type: int) -> int: """Sets the network connection type. Android only. @@ -88,43 +86,39 @@ def set_network_connection(self, connection_type: int) -> int: This API only works reliably on emulators (any version) and real devices since API level 31. + Requires the Appium driver to support the `mobile: setConnectivity` and + `mobile: getConnectivity` execute methods. + Args: connection_type: a member of the enum `appium.webdriver.ConnectionType` - Return: - int: Set network connection type + Returns: + The current network connection bitmask after applying the change """ ext_name = 'mobile: setConnectivity' - try: - return self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - 'wifi': bool(connection_type & NetworkMask.WIFI), - 'data': bool(connection_type & NetworkMask.DATA), - 'airplaneMode': bool(connection_type & NetworkMask.AIRPLANE_MODE), - }, - ) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute( - Command.SET_NETWORK_CONNECTION, {'parameters': {'type': connection_type}} - )['value'] + self.execute_script( + ext_name, + { + 'wifi': bool(connection_type & NetworkMask.WIFI), + 'data': bool(connection_type & NetworkMask.DATA), + 'airplaneMode': bool(connection_type & NetworkMask.AIRPLANE_MODE), + }, + ) + return self.network_connection 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. + Requires the Appium driver to support the `mobile: getConnectivity` and + `mobile: setConnectivity` execute methods. + Returns: Union['WebDriver', 'Network']: Self instance """ ext_name = 'mobile: setConnectivity' - try: - self.assert_extension_exists(ext_name).execute_script( - ext_name, {'wifi': not (self.network_connection & NetworkMask.WIFI)} - ) - except UnknownMethodException: - self.mark_extension_absence(ext_name).execute(Command.TOGGLE_WIFI, {}) + self.execute_script(ext_name, {'wifi': not (self.network_connection & NetworkMask.WIFI)}) return self def set_network_speed(self, speed_type: str) -> Self: @@ -132,6 +126,8 @@ def set_network_speed(self, speed_type: str) -> Self: Android Emulator only. + Requires the Appium driver to support the `mobile: networkSpeed` execute method. + Args: speed_type: The network speed type. A member of the const appium.webdriver.extensions.android.network.NetSpeed. @@ -149,27 +145,5 @@ def set_network_speed(self, speed_type: str) -> Self: f'(e.g. {NetSpeed.__name__}.LTE)' ) ext_name = 'mobile: networkSpeed' - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, {'speed': speed_type}) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.SET_NETWORK_SPEED, {'netspeed': speed_type}) + self.execute_script(ext_name, {'speed': speed_type}) return self - - def _add_commands(self) -> None: - self.command_executor.add_command(Command.TOGGLE_WIFI, 'POST', '/session/$sessionId/appium/device/toggle_wifi') - self.command_executor.add_command( - Command.GET_NETWORK_CONNECTION, - 'GET', - '/session/$sessionId/network_connection', - ) - self.command_executor.add_command( - Command.SET_NETWORK_CONNECTION, - 'POST', - '/session/$sessionId/network_connection', - ) - self.command_executor.add_command( - Command.SET_NETWORK_SPEED, - 'POST', - '/session/$sessionId/appium/device/network_speed', - ) diff --git a/appium/webdriver/extensions/android/performance.py b/appium/webdriver/extensions/android/performance.py index f5781cf3f..97acddcd3 100644 --- a/appium/webdriver/extensions/android/performance.py +++ b/appium/webdriver/extensions/android/performance.py @@ -14,15 +14,11 @@ from typing import Dict, List, Union -from selenium.common.exceptions import UnknownMethodException - 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 -class Performance(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Performance(CanExecuteCommands, CanExecuteScripts): def get_performance_data( self, package_name: str, data_type: str, data_read_timeout: Union[int, None] = None ) -> List[List[str]]: @@ -31,12 +27,15 @@ def get_performance_data( Android only. + Requires the Appium driver to support the `mobile: getPerformanceData` execute method. + Args: package_name: The package name of the application data_type: The type of system state which wants to read. It should be one of the supported performance data types. Check :func:`.get_performance_data_types` for supported types - data_read_timeout: The number of attempts to read + data_read_timeout: Legacy parameter retained for compatibility; ignored by + `mobile: getPerformanceData` Usage: self.driver.get_performance_data('my.app.package', 'cpuinfo', 5) @@ -46,19 +45,15 @@ def get_performance_data( """ ext_name = 'mobile: getPerformanceData' args: Dict[str, Union[str, int]] = {'packageName': package_name, 'dataType': data_type} - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - if data_read_timeout is not None: - args['dataReadTimeout'] = data_read_timeout - return self.mark_extension_absence(ext_name).execute(Command.GET_PERFORMANCE_DATA, args)['value'] + return self.execute_script(ext_name, args) def get_performance_data_types(self) -> List[str]: """Returns the information types of the system state which is supported to read as like cpu, memory, network traffic, and battery. Android only. + Requires the Appium driver to support the `mobile: getPerformanceDataTypes` execute method. + Usage: self.driver.get_performance_data_types() @@ -66,20 +61,4 @@ def get_performance_data_types(self) -> List[str]: Available data types """ ext_name = 'mobile: getPerformanceDataTypes' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_PERFORMANCE_DATA_TYPES)['value'] - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.GET_PERFORMANCE_DATA, - 'POST', - '/session/$sessionId/appium/getPerformanceData', - ) - self.command_executor.add_command( - Command.GET_PERFORMANCE_DATA_TYPES, - 'POST', - '/session/$sessionId/appium/performanceData/types', - ) + return self.execute_script(ext_name) diff --git a/appium/webdriver/extensions/android/power.py b/appium/webdriver/extensions/android/power.py index 537ab6803..7b8b574ec 100644 --- a/appium/webdriver/extensions/android/power.py +++ b/appium/webdriver/extensions/android/power.py @@ -12,16 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -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 -class Power(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Power(CanExecuteCommands, CanExecuteScripts): AC_OFF, AC_ON = 'off', 'on' def set_power_capacity(self, percent: int) -> Self: @@ -29,6 +26,8 @@ def set_power_capacity(self, percent: int) -> Self: Android only. + Requires the Appium driver to support the `mobile: powerCapacity` execute method. + Args: percent: The power capacity to be set. Can be set from 0 to 100 @@ -40,11 +39,7 @@ def set_power_capacity(self, percent: int) -> Self: """ ext_name = 'mobile: powerCapacity' args = {'percent': percent} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.SET_POWER_CAPACITY, args) + self.execute_script(ext_name, args) return self def set_power_ac(self, ac_state: str) -> Self: @@ -52,6 +47,8 @@ def set_power_ac(self, ac_state: str) -> Self: Android only. + Requires the Appium driver to support the `mobile: powerAC` execute method. + Args: ac_state: The power ac state to be set. Use `Power.AC_OFF`, `Power.AC_ON` @@ -64,17 +61,5 @@ def set_power_ac(self, ac_state: str) -> Self: """ ext_name = 'mobile: powerAC' args = {'state': ac_state} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.SET_POWER_AC, args) + self.execute_script(ext_name, args) return self - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.SET_POWER_CAPACITY, - 'POST', - '/session/$sessionId/appium/device/power_capacity', - ) - self.command_executor.add_command(Command.SET_POWER_AC, 'POST', '/session/$sessionId/appium/device/power_ac') diff --git a/appium/webdriver/extensions/android/sms.py b/appium/webdriver/extensions/android/sms.py index f5769c561..c4ada1f50 100644 --- a/appium/webdriver/extensions/android/sms.py +++ b/appium/webdriver/extensions/android/sms.py @@ -12,21 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -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 -class Sms(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Sms(CanExecuteCommands, CanExecuteScripts): def send_sms(self, phone_number: str, message: str) -> Self: """Emulate send SMS event on the connected emulator. Android only. + Requires the Appium driver to support the `mobile: sendSms` execute method. + Args: phone_number: The phone number of message sender message: The message to send @@ -39,12 +38,5 @@ def send_sms(self, phone_number: str, message: str) -> Self: """ ext_name = 'mobile: sendSms' args = {'phoneNumber': phone_number, 'message': message} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.SEND_SMS, args) + self.execute_script(ext_name, args) return self - - def _add_commands(self) -> None: - self.command_executor.add_command(Command.SEND_SMS, 'POST', '/session/$sessionId/appium/device/send_sms') diff --git a/appium/webdriver/extensions/android/system_bars.py b/appium/webdriver/extensions/android/system_bars.py index a02c21f8f..30cb9cd2b 100644 --- a/appium/webdriver/extensions/android/system_bars.py +++ b/appium/webdriver/extensions/android/system_bars.py @@ -14,20 +14,18 @@ from typing import Dict, Union -from selenium.common.exceptions import UnknownMethodException - 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 -class SystemBars(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class SystemBars(CanExecuteCommands, CanExecuteScripts): def get_system_bars(self) -> Dict[str, Dict[str, Union[int, bool]]]: """Retrieve visibility and bounds information of the status and navigation bars. Android only. + Requires the Appium driver to support the `mobile: getSystemBars` execute method. + Returns: A dictionary whose keys are - statusBar @@ -44,15 +42,4 @@ def get_system_bars(self) -> Dict[str, Dict[str, Union[int, bool]]]: - height """ ext_name = 'mobile: getSystemBars' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_SYSTEM_BARS)['value'] - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.GET_SYSTEM_BARS, - 'GET', - '/session/$sessionId/appium/device/system_bars', - ) + return self.execute_script(ext_name) diff --git a/appium/webdriver/extensions/applications.py b/appium/webdriver/extensions/applications.py index b259422ec..dc729f409 100644 --- a/appium/webdriver/extensions/applications.py +++ b/appium/webdriver/extensions/applications.py @@ -13,17 +13,13 @@ # limitations under the License. from typing import Any, Dict, Union -from selenium.common.exceptions import InvalidArgumentException, 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 ..mobilecommand import MobileCommand as Command - -class Applications(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Applications(CanExecuteCommands, CanExecuteScripts): def background_app(self, seconds: int) -> Self: """Puts the application in the background on the device for a certain duration. @@ -37,11 +33,7 @@ def background_app(self, seconds: int) -> Self: """ ext_name = 'mobile: backgroundApp' args = {'seconds': seconds} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.BACKGROUND, args) + self.execute_script(ext_name, args) return self def is_app_installed(self, bundle_id: str) -> bool: @@ -54,22 +46,13 @@ def is_app_installed(self, bundle_id: str) -> bool: `True` if app is installed """ ext_name = 'mobile: isAppInstalled' - try: - return self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - 'bundleId': bundle_id, - 'appId': bundle_id, - }, - ) - except (UnknownMethodException, InvalidArgumentException): - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute( - Command.IS_APP_INSTALLED, - { - 'bundleId': bundle_id, - }, - )['value'] + return self.execute_script( + ext_name, + { + 'bundleId': bundle_id, + 'appId': bundle_id, + }, + ) def install_app(self, app_path: str, **options: Any) -> Self: """Install the application found at `app_path` on the device. @@ -91,22 +74,14 @@ def install_app(self, app_path: str, **options: Any) -> Self: Returns: Union['WebDriver', 'Applications']: Self instance """ - ext_name = 'mobile: installApp' - try: - self.assert_extension_exists(ext_name).execute_script( - 'mobile: installApp', - { - 'app': app_path, - 'appPath': app_path, - **(options or {}), - }, - ) - except (UnknownMethodException, InvalidArgumentException): - # TODO: Remove the fallback - data: Dict[str, Any] = {'appPath': app_path} - if options: - data.update({'options': options}) - self.mark_extension_absence(ext_name).execute(Command.INSTALL_APP, data) + self.execute_script( + 'mobile: installApp', + { + 'app': app_path, + 'appPath': app_path, + **(options or {}), + }, + ) return self def remove_app(self, app_id: str, **options: Any) -> Self: @@ -125,21 +100,14 @@ def remove_app(self, app_id: str, **options: Any) -> Self: Union['WebDriver', 'Applications']: Self instance """ ext_name = 'mobile: removeApp' - try: - self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - 'appId': app_id, - 'bundleId': app_id, - **(options or {}), - }, - ) - except (UnknownMethodException, InvalidArgumentException): - # TODO: Remove the fallback - data: Dict[str, Any] = {'appId': app_id} - if options: - data.update({'options': options}) - self.mark_extension_absence(ext_name).execute(Command.REMOVE_APP, data) + self.execute_script( + ext_name, + { + 'appId': app_id, + 'bundleId': app_id, + **(options or {}), + }, + ) return self def terminate_app(self, app_id: str, **options: Any) -> bool: @@ -156,21 +124,14 @@ def terminate_app(self, app_id: str, **options: Any) -> bool: True if the app has been successfully terminated """ ext_name = 'mobile: terminateApp' - try: - return self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - 'appId': app_id, - 'bundleId': app_id, - **(options or {}), - }, - ) - except (UnknownMethodException, InvalidArgumentException): - # TODO: Remove the fallback - data: Dict[str, Any] = {'appId': app_id} - if options: - data.update({'options': options}) - return self.mark_extension_absence(ext_name).execute(Command.TERMINATE_APP, data)['value'] + return self.execute_script( + ext_name, + { + 'appId': app_id, + 'bundleId': app_id, + **(options or {}), + }, + ) def activate_app(self, app_id: str) -> Self: """Activates the application if it is not running @@ -183,17 +144,13 @@ def activate_app(self, app_id: str) -> Self: Union['WebDriver', 'Applications']: Self instance """ ext_name = 'mobile: activateApp' - try: - self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - 'appId': app_id, - 'bundleId': app_id, - }, - ) - except (UnknownMethodException, InvalidArgumentException): - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.ACTIVATE_APP, {'appId': app_id}) + self.execute_script( + ext_name, + { + 'appId': app_id, + 'bundleId': app_id, + }, + ) return self def query_app_state(self, app_id: str) -> int: @@ -207,22 +164,13 @@ def query_app_state(self, app_id: str) -> int: class for more details. """ ext_name = 'mobile: queryAppState' - try: - return self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - 'appId': app_id, - 'bundleId': app_id, - }, - ) - except (UnknownMethodException, InvalidArgumentException): - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute( - Command.QUERY_APP_STATE, - { - 'appId': app_id, - }, - )['value'] + return self.execute_script( + ext_name, + { + 'appId': app_id, + 'bundleId': app_id, + }, + ) def app_strings(self, language: Union[str, None] = None, string_file: Union[str, None] = None) -> Dict[str, str]: """Returns the application strings from the device for the specified @@ -241,34 +189,4 @@ def app_strings(self, language: Union[str, None] = None, string_file: Union[str, data['language'] = language if string_file is not None: data['stringFile'] = string_file - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name, data) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_APP_STRINGS, data)['value'] - - def _add_commands(self) -> None: - self.command_executor.add_command(Command.BACKGROUND, 'POST', '/session/$sessionId/appium/app/background') - self.command_executor.add_command( - Command.IS_APP_INSTALLED, - 'POST', - '/session/$sessionId/appium/device/app_installed', - ) - self.command_executor.add_command(Command.INSTALL_APP, 'POST', '/session/$sessionId/appium/device/install_app') - self.command_executor.add_command(Command.REMOVE_APP, 'POST', '/session/$sessionId/appium/device/remove_app') - self.command_executor.add_command( - Command.TERMINATE_APP, - 'POST', - '/session/$sessionId/appium/device/terminate_app', - ) - self.command_executor.add_command( - Command.ACTIVATE_APP, - 'POST', - '/session/$sessionId/appium/device/activate_app', - ) - self.command_executor.add_command( - Command.QUERY_APP_STATE, - 'POST', - '/session/$sessionId/appium/device/app_state', - ) - self.command_executor.add_command(Command.GET_APP_STRINGS, 'POST', '/session/$sessionId/appium/app/strings') + return self.execute_script(ext_name, data) diff --git a/appium/webdriver/extensions/clipboard.py b/appium/webdriver/extensions/clipboard.py index f5354f2e7..c5a6e5445 100644 --- a/appium/webdriver/extensions/clipboard.py +++ b/appium/webdriver/extensions/clipboard.py @@ -15,23 +15,21 @@ import base64 from typing import Optional -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.clipboard_content_type import ClipboardContentType -from ..mobilecommand import MobileCommand as Command - -class Clipboard(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Clipboard(CanExecuteCommands, CanExecuteScripts): def set_clipboard( self, content: bytes, content_type: str = ClipboardContentType.PLAINTEXT, label: Optional[str] = None ) -> Self: """Set the content of the system clipboard + Requires the Appium driver to support the `mobile: setClipboard` execute method. + Args: content: The content to be set as bytearray string content_type: One of ClipboardContentType items. Only ClipboardContentType.PLAINTEXT @@ -48,16 +46,14 @@ def set_clipboard( } if label: options['label'] = label - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, options) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.SET_CLIPBOARD, options) + self.execute_script(ext_name, options) return self def set_clipboard_text(self, text: str, label: Optional[str] = None) -> Self: """Copies the given text to the system clipboard + Requires the Appium driver to support the `mobile: setClipboard` execute method. + Args: text: The text to be set label:label argument, which only works for Android @@ -70,6 +66,8 @@ def set_clipboard_text(self, text: str, label: Optional[str] = None) -> Self: def get_clipboard(self, content_type: str = ClipboardContentType.PLAINTEXT) -> bytes: """Receives the content of the system clipboard + Requires the Appium driver to support the `mobile: getClipboard` execute method. + Args: content_type: One of ClipboardContentType items. Only ClipboardContentType.PLAINTEXT is supported on Android @@ -79,29 +77,15 @@ def get_clipboard(self, content_type: str = ClipboardContentType.PLAINTEXT) -> b """ ext_name = 'mobile: getClipboard' options = {'contentType': content_type} - try: - base64_str = self.assert_extension_exists(ext_name).execute_script(ext_name, options) - except UnknownMethodException: - # TODO: Remove the fallback - base64_str = self.mark_extension_absence(ext_name).execute(Command.GET_CLIPBOARD, options)['value'] + base64_str = self.execute_script(ext_name, options) return base64.b64decode(base64_str) def get_clipboard_text(self) -> str: """Receives the text of the system clipboard + Requires the Appium driver to support the `mobile: getClipboard` execute method. + Returns: The actual clipboard text or an empty string if the clipboard is empty """ return self.get_clipboard(ClipboardContentType.PLAINTEXT).decode('UTF-8') - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.SET_CLIPBOARD, - 'POST', - '/session/$sessionId/appium/device/set_clipboard', - ) - self.command_executor.add_command( - Command.GET_CLIPBOARD, - 'POST', - '/session/$sessionId/appium/device/get_clipboard', - ) diff --git a/appium/webdriver/extensions/device_time.py b/appium/webdriver/extensions/device_time.py index 22ac3c25a..ad79e49c9 100644 --- a/appium/webdriver/extensions/device_time.py +++ b/appium/webdriver/extensions/device_time.py @@ -14,33 +14,28 @@ from typing import Optional -from selenium.common.exceptions import UnknownMethodException - 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 ..mobilecommand import MobileCommand as Command -class DeviceTime(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class DeviceTime(CanExecuteCommands, CanExecuteScripts): @property def device_time(self) -> str: """Returns the date and time from the device. + Requires the Appium driver to support the `mobile: getDeviceTime` execute method. + Return: str: The date and time """ ext_name = 'mobile: getDeviceTime' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.GET_DEVICE_TIME_GET, {})['value'] + return self.execute_script(ext_name) def get_device_time(self, format: Optional[str] = None) -> str: """Returns the date and time from the device. + Requires the Appium driver to support the `mobile: getDeviceTime` execute method. + Args: format: The set of format specifiers. Read https://momentjs.com/docs/ to get the full list of supported datetime format specifiers. @@ -57,19 +52,4 @@ def get_device_time(self, format: Optional[str] = None) -> str: ext_name = 'mobile: getDeviceTime' if format is None: return self.device_time - 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'] - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.GET_DEVICE_TIME_GET, - 'GET', - '/session/$sessionId/appium/device/system_time', - ) - self.command_executor.add_command( - Command.GET_DEVICE_TIME_POST, - 'POST', - '/session/$sessionId/appium/device/system_time', - ) + return self.execute_script(ext_name, {'format': format}) diff --git a/appium/webdriver/extensions/flutter_integration/flutter_commands.py b/appium/webdriver/extensions/flutter_integration/flutter_commands.py index fd4d49681..5e469cae1 100644 --- a/appium/webdriver/extensions/flutter_integration/flutter_commands.py +++ b/appium/webdriver/extensions/flutter_integration/flutter_commands.py @@ -290,7 +290,7 @@ def execute_flutter_command(self, scriptName: str, params: dict) -> Any: """ return self.driver.execute_script(f'flutter: {scriptName}', params) - def __get_locator_options(self, locator: Union[WebElement, 'FlutterFinder']) -> Dict[str, dict]: + def __get_locator_options(self, locator: Union[WebElement, 'FlutterFinder']) -> Dict[str, Union[dict, WebElement]]: if isinstance(locator, WebElement): return {'element': locator} return {'locator': locator.to_dict()} diff --git a/appium/webdriver/extensions/flutter_integration/flutter_finder.py b/appium/webdriver/extensions/flutter_integration/flutter_finder.py index 2e5db4ece..0aed46a9a 100644 --- a/appium/webdriver/extensions/flutter_integration/flutter_finder.py +++ b/appium/webdriver/extensions/flutter_integration/flutter_finder.py @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import Tuple, Union +from typing import Tuple, Union, cast from selenium.webdriver.common.by import ByType as SeleniumByType @@ -30,23 +30,23 @@ def __init__(self, using: Union[SeleniumByType, AppiumByType], value: str) -> No @staticmethod def by_key(value: str) -> 'FlutterFinder': - return FlutterFinder(AppiumBy.FLUTTER_INTEGRATION_KEY, value) + return FlutterFinder(cast(AppiumByType, AppiumBy.FLUTTER_INTEGRATION_KEY), value) @staticmethod def by_text(value: str) -> 'FlutterFinder': - return FlutterFinder(AppiumBy.FLUTTER_INTEGRATION_TEXT, value) + return FlutterFinder(cast(AppiumByType, AppiumBy.FLUTTER_INTEGRATION_TEXT), value) @staticmethod def by_semantics_label(value: str) -> 'FlutterFinder': - return FlutterFinder(AppiumBy.FLUTTER_INTEGRATION_SEMANTICS_LABEL, value) + return FlutterFinder(cast(AppiumByType, AppiumBy.FLUTTER_INTEGRATION_SEMANTICS_LABEL), value) @staticmethod def by_type(value: str) -> 'FlutterFinder': - return FlutterFinder(AppiumBy.FLUTTER_INTEGRATION_TYPE, value) + return FlutterFinder(cast(AppiumByType, AppiumBy.FLUTTER_INTEGRATION_TYPE), value) @staticmethod def by_text_containing(value: str) -> 'FlutterFinder': - return FlutterFinder(AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING, value) + return FlutterFinder(cast(AppiumByType, AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING), value) def to_dict(self) -> dict: return {'using': self.using, 'value': self.value} diff --git a/appium/webdriver/extensions/hw_actions.py b/appium/webdriver/extensions/hw_actions.py index b6bbb468b..4f80bcab5 100644 --- a/appium/webdriver/extensions/hw_actions.py +++ b/appium/webdriver/extensions/hw_actions.py @@ -14,19 +14,17 @@ from typing import Optional -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 ..mobilecommand import MobileCommand as Command - -class HardwareActions(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class HardwareActions(CanExecuteCommands, CanExecuteScripts): def lock(self, seconds: Optional[int] = None) -> Self: - """Lock the device. No changes are made if the device is already unlocked. + """Lock the device. No changes are made if the device is already locked. + + Requires the Appium driver to support the `mobile: lock` execute method. Args: seconds: The duration to lock the device, in seconds. @@ -39,54 +37,44 @@ def lock(self, seconds: Optional[int] = None) -> Self: """ ext_name = 'mobile: lock' args = {'seconds': seconds or 0} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.LOCK, args) + self.execute_script(ext_name, args) return self def unlock(self) -> Self: - """Unlock the device. No changes are made if the device is already locked. + """Unlock the device. No changes are made if the device is already unlocked. + + Requires the Appium driver to support the `mobile: isLocked` and `mobile: unlock` execute methods. Returns: Union['WebDriver', 'HardwareActions']: Self instance """ ext_name = 'mobile: unlock' - try: - if not self.assert_extension_exists(ext_name).execute_script('mobile: isLocked'): - return self - self.execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.UNLOCK) + if not self.execute_script('mobile: isLocked'): + return self + self.execute_script(ext_name) return self def is_locked(self) -> bool: """Checks whether the device is locked. + Requires the Appium driver to support the `mobile: isLocked` execute method. + Returns: `True` if the device is locked """ ext_name = 'mobile: isLocked' - try: - return self.assert_extension_exists(ext_name).execute_script('mobile: isLocked') - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.IS_LOCKED)['value'] + return self.execute_script(ext_name) def shake(self) -> Self: """Shake the device. + Requires the Appium driver to support the `mobile: shake` execute method. + Returns: Union['WebDriver', 'HardwareActions']: Self instance """ ext_name = 'mobile: shake' - try: - self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.SHAKE) + self.execute_script(ext_name) return self def touch_id(self, match: bool) -> Self: @@ -118,32 +106,17 @@ def toggle_touch_id_enrollment(self) -> Self: return self def finger_print(self, finger_id: int) -> Self: - """Authenticate users by using their finger print scans on supported Android emulators. + """Authenticate users using a fingerprint scan on supported Android emulators. + + Requires the Appium driver to support the `mobile: fingerprint` execute method. Args: - finger_id: Finger prints stored in Android Keystore system (from 1 to 10) + finger_id: Fingerprint identifier stored in the Android Keystore system (from 1 to 10) + + Returns: + Union['WebDriver', 'HardwareActions']: Self instance """ ext_name = 'mobile: fingerprint' args = {'fingerprintId': finger_id} - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - self.mark_extension_absence(ext_name).execute(Command.FINGER_PRINT, args) + self.execute_script(ext_name, args) return self - - def _add_commands(self) -> None: - self.command_executor.add_command(Command.LOCK, 'POST', '/session/$sessionId/appium/device/lock') - self.command_executor.add_command(Command.UNLOCK, 'POST', '/session/$sessionId/appium/device/unlock') - self.command_executor.add_command(Command.IS_LOCKED, 'POST', '/session/$sessionId/appium/device/is_locked') - self.command_executor.add_command(Command.SHAKE, 'POST', '/session/$sessionId/appium/device/shake') - self.command_executor.add_command(Command.TOUCH_ID, 'POST', '/session/$sessionId/appium/simulator/touch_id') - self.command_executor.add_command( - Command.TOGGLE_TOUCH_ID_ENROLLMENT, - 'POST', - '/session/$sessionId/appium/simulator/toggle_touch_id_enrollment', - ) - self.command_executor.add_command( - Command.FINGER_PRINT, - 'POST', - '/session/$sessionId/appium/device/finger_print', - ) diff --git a/appium/webdriver/extensions/images_comparison.py b/appium/webdriver/extensions/images_comparison.py index 6f7308157..04b8f1147 100644 --- a/appium/webdriver/extensions/images_comparison.py +++ b/appium/webdriver/extensions/images_comparison.py @@ -18,9 +18,11 @@ from ..mobilecommand import MobileCommand as Command +Base64Payload = Union[str, bytes] + class ImagesComparison(CanExecuteCommands): - def match_images_features(self, base64_image1: bytes, base64_image2: bytes, **opts: Any) -> Dict[str, Any]: + def match_images_features(self, base64_image1: Base64Payload, base64_image2: Base64Payload, **opts: Any) -> Dict[str, Any]: """Performs images matching by features. Read @@ -66,11 +68,16 @@ def match_images_features(self, base64_image1: bytes, base64_image2: bytes, **op rect2 (dict): The bounding rect for the `points2` array or a zero rect if not enough matching points were found. The rect is represented by a dictionary with 'x', 'y', 'width' and 'height' keys """ - options = {'mode': 'matchFeatures', 'firstImage': base64_image1, 'secondImage': base64_image2, 'options': opts} + options = { + 'mode': 'matchFeatures', + 'firstImage': _adjust_image_payload(base64_image1), + 'secondImage': _adjust_image_payload(base64_image2), + 'options': opts, + } return self.execute(Command.COMPARE_IMAGES, options)['value'] def find_image_occurrence( - self, base64_full_image: bytes, base64_partial_image: bytes, **opts: Any + self, base64_full_image: Base64Payload, base64_partial_image: Base64Payload, **opts: Any ) -> Dict[str, Union[bytes, Dict]]: """Performs images matching by template to find possible occurrence of the partial image in the full image. @@ -97,13 +104,15 @@ def find_image_occurrence( """ options = { 'mode': 'matchTemplate', - 'firstImage': base64_full_image, - 'secondImage': base64_partial_image, + 'firstImage': _adjust_image_payload(base64_full_image), + 'secondImage': _adjust_image_payload(base64_partial_image), 'options': opts, } 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: Base64Payload, base64_image2: Base64Payload, **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 @@ -125,8 +134,20 @@ def get_images_similarity(self, base64_image1: bytes, base64_image2: bytes, **op score (float): The similarity score as a float number in range [0.0, 1.0]. 1.0 is the highest score (means both images are totally equal). """ - options = {'mode': 'getSimilarity', 'firstImage': base64_image1, 'secondImage': base64_image2, 'options': opts} + options = { + 'mode': 'getSimilarity', + 'firstImage': _adjust_image_payload(base64_image1), + 'secondImage': _adjust_image_payload(base64_image2), + 'options': opts, + } return self.execute(Command.COMPARE_IMAGES, options)['value'] def _add_commands(self) -> None: self.command_executor.add_command(Command.COMPARE_IMAGES, 'POST', '/session/$sessionId/appium/compare_images') + + +def _adjust_image_payload(payload: Base64Payload) -> str: + try: + return payload if isinstance(payload, str) else payload.decode('utf-8') + except UnicodeDecodeError as e: + raise ValueError('The image payload cannot be serialized to a string. Make sure to base64-encode it first') from e diff --git a/appium/webdriver/extensions/keyboard.py b/appium/webdriver/extensions/keyboard.py index 4640b1163..cae8ee813 100644 --- a/appium/webdriver/extensions/keyboard.py +++ b/appium/webdriver/extensions/keyboard.py @@ -12,62 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Optional +from typing import Optional -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 ..mobilecommand import MobileCommand as Command - -class Keyboard(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class Keyboard(CanExecuteCommands, CanExecuteScripts): 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 - a particular key, or `strategy`. In Android, no parameters are used. + On iOS, use `key_name` or `key` to provide a keyboard key name. + On Android, no parameters are used. `strategy` is retained for compatibility and ignored. + + Requires the Appium driver to support the `mobile: hideKeyboard` execute method. Args: - key_name: key to press - key: - strategy: strategy for closing the keyboard (e.g., `tapOutside`) + key_name: Keyboard key name to use on iOS + key: Alias for `key_name` + strategy: Legacy argument retained for compatibility; ignored by `mobile: hideKeyboard` Returns: Union['WebDriver', 'Keyboard']: Self instance """ ext_name = 'mobile: hideKeyboard' - try: - self.assert_extension_exists(ext_name).execute_script( - ext_name, {**({'keys': [key or key_name]} if key or key_name else {})} - ) - except UnknownMethodException: - # TODO: Remove the fallback - data: Dict[str, Optional[str]] = {} - if key_name is not None: - data['keyName'] = key_name - elif key is not None: - data['key'] = key - elif strategy is None: - strategy = 'tapOutside' - data['strategy'] = strategy - self.mark_extension_absence(ext_name).execute(Command.HIDE_KEYBOARD, data) + self.execute_script(ext_name, {**({'keys': [key or key_name]} if key or key_name else {})}) return self def is_keyboard_shown(self) -> bool: """Attempts to detect whether a software keyboard is present + Requires the Appium driver to support the `mobile: isKeyboardShown` execute method. + Returns: `True` if keyboard is shown """ ext_name = 'mobile: isKeyboardShown' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name) - except UnknownMethodException: - return self.mark_extension_absence(ext_name).execute(Command.IS_KEYBOARD_SHOWN)['value'] + return self.execute_script(ext_name) def keyevent(self, keycode: int, metastate: Optional[int] = None) -> Self: """Sends a keycode to the device. @@ -75,6 +58,8 @@ def keyevent(self, keycode: int, metastate: Optional[int] = None) -> Self: Android only. Possible keycodes can be found in http://developer.android.com/reference/android/view/KeyEvent.html. + Requires the Appium driver to support the `mobile: pressKey` execute method. + Args: keycode: the keycode to be sent to the device metastate: meta information about the keycode being sent @@ -90,6 +75,8 @@ def press_keycode(self, keycode: int, metastate: Optional[int] = None, flags: Op Android only. Possible keycodes can be found in http://developer.android.com/reference/android/view/KeyEvent.html. + Requires the Appium driver to support the `mobile: pressKey` execute method. + Args: keycode: the keycode to be sent to the device metastate: meta information about the keycode being sent @@ -104,11 +91,7 @@ def press_keycode(self, keycode: int, metastate: Optional[int] = None, flags: Op args['metastate'] = metastate if flags is not None: args['flags'] = flags - try: - self.assert_extension_exists(ext_name).execute_script(ext_name, args) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.PRESS_KEYCODE, args) + self.execute_script(ext_name, args) return self def long_press_keycode(self, keycode: int, metastate: Optional[int] = None, flags: Optional[int] = None) -> Self: @@ -117,6 +100,8 @@ def long_press_keycode(self, keycode: int, metastate: Optional[int] = None, flag Android only. Possible keycodes can be found in http://developer.android.com/reference/android/view/KeyEvent.html. + Requires the Appium driver to support the `mobile: pressKey` execute method. + Args: keycode: the keycode to be sent to the device metastate: meta information about the keycode being sent @@ -131,38 +116,11 @@ def long_press_keycode(self, keycode: int, metastate: Optional[int] = None, flag args['metastate'] = metastate if flags is not None: args['flags'] = flags - try: - self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - **args, - 'isLongPress': True, - }, - ) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute(Command.LONG_PRESS_KEYCODE, args) - return self - - def _add_commands(self) -> None: - self.command_executor.add_command( - Command.HIDE_KEYBOARD, - 'POST', - '/session/$sessionId/appium/device/hide_keyboard', - ) - self.command_executor.add_command( - Command.IS_KEYBOARD_SHOWN, - 'GET', - '/session/$sessionId/appium/device/is_keyboard_shown', - ) - self.command_executor.add_command(Command.KEY_EVENT, 'POST', '/session/$sessionId/appium/device/keyevent') - self.command_executor.add_command( - Command.PRESS_KEYCODE, - 'POST', - '/session/$sessionId/appium/device/press_keycode', - ) - self.command_executor.add_command( - Command.LONG_PRESS_KEYCODE, - 'POST', - '/session/$sessionId/appium/device/long_press_keycode', + self.execute_script( + ext_name, + { + **args, + 'isLongPress': True, + }, ) + return self diff --git a/appium/webdriver/extensions/location.py b/appium/webdriver/extensions/location.py index 3141050ae..fc1fcae28 100644 --- a/appium/webdriver/extensions/location.py +++ b/appium/webdriver/extensions/location.py @@ -14,7 +14,6 @@ from typing import Dict, Union -from selenium.common.exceptions import UnknownMethodException from typing_extensions import Self from appium.protocols.webdriver.can_execute_commands import CanExecuteCommands @@ -33,11 +32,7 @@ def toggle_location_services(self) -> Self: Returns: Union['WebDriver', 'Location']: Self instance """ - try: - self.execute_script('mobile: toggleGps') - except UnknownMethodException: - # TODO: Remove the fallback - self.execute(Command.TOGGLE_LOCATION_SERVICES) + self.execute_script('mobile: toggleGps') return self def set_location( @@ -89,10 +84,5 @@ def location(self) -> Dict[str, float]: def _add_commands(self) -> None: """Add location endpoints. They are not int w3c spec.""" - self.command_executor.add_command( - Command.TOGGLE_LOCATION_SERVICES, - 'POST', - '/session/$sessionId/appium/device/toggle_location_services', - ) self.command_executor.add_command(Command.GET_LOCATION, 'GET', '/session/$sessionId/location') self.command_executor.add_command(Command.SET_LOCATION, 'POST', '/session/$sessionId/location') diff --git a/appium/webdriver/extensions/remote_fs.py b/appium/webdriver/extensions/remote_fs.py index 5ccebd37d..9139cd4c3 100644 --- a/appium/webdriver/extensions/remote_fs.py +++ b/appium/webdriver/extensions/remote_fs.py @@ -15,20 +15,19 @@ import base64 from typing import Optional -from selenium.common.exceptions import InvalidArgumentException, UnknownMethodException +from selenium.common.exceptions import InvalidArgumentException 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 ..mobilecommand import MobileCommand as Command - -class RemoteFS(CanExecuteCommands, CanExecuteScripts, CanRememberExtensionPresence): +class RemoteFS(CanExecuteCommands, CanExecuteScripts): def pull_file(self, path: str) -> str: """Retrieves the file at `path`. + Requires the Appium driver to support the `mobile: pullFile` execute method. + Args: path: the path to the file on the device @@ -36,15 +35,13 @@ def pull_file(self, path: str) -> str: The file's contents encoded as Base64. """ ext_name = 'mobile: pullFile' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name, {'remotePath': path}) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.PULL_FILE, {'path': path})['value'] + return self.execute_script(ext_name, {'remotePath': path}) def pull_folder(self, path: str) -> str: """Retrieves a folder at `path`. + Requires the Appium driver to support the `mobile: pullFolder` execute method. + Args: path: the path to the folder on the device @@ -52,21 +49,19 @@ def pull_folder(self, path: str) -> str: The folder's contents zipped and encoded as Base64. """ ext_name = 'mobile: pullFolder' - try: - return self.assert_extension_exists(ext_name).execute_script(ext_name, {'remotePath': path}) - except UnknownMethodException: - # TODO: Remove the fallback - return self.mark_extension_absence(ext_name).execute(Command.PULL_FOLDER, {'path': path})['value'] + return self.execute_script(ext_name, {'remotePath': path}) 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`. + """Puts the data from the file at `source_path`, encoded as Base64, at `destination_path`. - Specify either `base64data` or `source_path`, if both specified default to `source_path` + Specify either `base64data` or `source_path`. If both are provided, `source_path` takes precedence. + + Requires the Appium driver to support the `mobile: pushFile` execute method. Args: destination_path: the location on the device/simulator where the local file contents should be saved base64data: file contents, encoded as Base64, to be written - to the file on the device/simulator + to the file on the device/simulator source_path: local file path for the file to be loaded on device Returns: @@ -85,26 +80,11 @@ def push_file(self, destination_path: str, base64data: Optional[str] = None, sou base64data = base64.b64encode(file_data).decode('utf-8') ext_name = 'mobile: pushFile' - try: - self.assert_extension_exists(ext_name).execute_script( - ext_name, - { - 'remotePath': destination_path, - 'payload': base64data, - }, - ) - except UnknownMethodException: - # TODO: Remove the fallback - self.mark_extension_absence(ext_name).execute( - Command.PUSH_FILE, - { - 'path': destination_path, - 'data': base64data, - }, - ) + self.execute_script( + ext_name, + { + 'remotePath': destination_path, + 'payload': base64data, + }, + ) return self - - def _add_commands(self) -> None: - self.command_executor.add_command(Command.PULL_FILE, 'POST', '/session/$sessionId/appium/device/pull_file') - self.command_executor.add_command(Command.PULL_FOLDER, 'POST', '/session/$sessionId/appium/device/pull_folder') - self.command_executor.add_command(Command.PUSH_FILE, 'POST', '/session/$sessionId/appium/device/push_file') diff --git a/appium/webdriver/extensions/screen_record.py b/appium/webdriver/extensions/screen_record.py index 11e26c414..07c9b2bae 100644 --- a/appium/webdriver/extensions/screen_record.py +++ b/appium/webdriver/extensions/screen_record.py @@ -126,8 +126,8 @@ def start_recording_screen(self, **options: Any) -> Union[bytes, str]: The default value is the device's native display resolution (if supported), 1280x720 if not. For best results, use a size supported by your device's Advanced Video Coding (AVC) encoder. - bitRate (int): [Android] The video bit rate for the video, in megabits per second. - The default value is 4. You can increase the bit rate to improve video quality, + bitRate (int): [Android] The video bit rate for the video, in bits per second. + The default value is 4000000 (4 Mbit/s). You can increase the bit rate to improve video quality, but doing so results in larger movie files. bugReport (str): [Android] Makes the recorder to display an additional information on the video overlay, such as a timestamp, that is helpful in videos captured to illustrate bugs. diff --git a/appium/webdriver/mobilecommand.py b/appium/webdriver/mobilecommand.py index 79ac25e1b..ed8dc6f80 100644 --- a/appium/webdriver/mobilecommand.py +++ b/appium/webdriver/mobilecommand.py @@ -31,7 +31,6 @@ class MobileCommand: SWITCH_TO_CONTEXT = 'switchToContext' BACKGROUND = 'background' - GET_APP_STRINGS = 'getAppStrings' IS_LOCKED = 'isLocked' LOCK = 'lock' @@ -78,13 +77,10 @@ class MobileCommand: GET_AVAILABLE_LOG_TYPES = 'getAvailableLogTypes' # Android - OPEN_NOTIFICATIONS = 'openNotifications' GET_CURRENT_ACTIVITY = 'getCurrentActivity' - GET_CURRENT_PACKAGE = 'getCurrentPackage' GET_SYSTEM_BARS = 'getSystemBars' GET_DISPLAY_DENSITY = 'getDisplayDensity' TOGGLE_WIFI = 'toggleWiFi' - TOGGLE_LOCATION_SERVICES = 'toggleLocationServices' GET_PERFORMANCE_DATA_TYPES = 'getPerformanceDataTypes' GET_PERFORMANCE_DATA = 'getPerformanceData' GET_NETWORK_CONNECTION = 'getNetworkConnection' diff --git a/appium/webdriver/switch_to.py b/appium/webdriver/switch_to.py index 6e538ec9f..ed9db7c76 100644 --- a/appium/webdriver/switch_to.py +++ b/appium/webdriver/switch_to.py @@ -12,21 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Optional, Protocol +from typing import Optional from selenium.webdriver.remote.switch_to import SwitchTo from typing_extensions import Self -from appium.protocols.webdriver.can_execute_commands import CanExecuteCommands - from .mobilecommand import MobileCommand -class HasDriver(Protocol): - _driver: CanExecuteCommands - - -class MobileSwitchTo(SwitchTo, HasDriver): +class MobileSwitchTo(SwitchTo): def context(self, context_name: Optional[str]) -> Self: """Sets the context for the current session. Passing `None` is equal to switching to native context. diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index e54593359..5ae6b9ab1 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -12,23 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union -from selenium import webdriver from selenium.common.exceptions import ( InvalidArgumentException, SessionNotCreatedException, UnknownMethodException, WebDriverException, ) -from selenium.webdriver.common.by import By from selenium.webdriver.remote.command import Command as RemoteCommand from selenium.webdriver.remote.remote_connection import RemoteConnection + +# `selenium.webdriver.Remote` could be used instead, but Pyright wouldn't locate the class properly. +from selenium.webdriver.remote.webdriver import WebDriver as Remote from typing_extensions import Self from appium.common.logger import logger from appium.options.common.base import AppiumOptions -from appium.webdriver.common.appiumby import AppiumBy from .appium_connection import AppiumConnection from .client_config import AppiumClientConfig @@ -210,7 +210,7 @@ def _get_remote_connection_and_client_config( class WebDriver( - webdriver.Remote, + Remote, ActionHelpers, Activities, Applications, @@ -241,7 +241,7 @@ class WebDriver( def __init__( self, command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4723', - extensions: Optional[List['WebDriver']] = None, + extensions: Optional[List[Type['ExtensionBase']]] = None, options: Union[AppiumOptions, List[AppiumOptions], None] = None, client_config: Optional[AppiumClientConfig] = None, ): @@ -250,12 +250,15 @@ def __init__( ) super().__init__( command_executor=command_executor, - options=options, + options=options, # type: ignore[arg-type] locator_converter=AppiumLocatorConverter(), web_element_cls=MobileWebElement, client_config=client_config, ) + # to explicitly set type after the initialization + self.command_executor: RemoteConnection + self._add_commands() self.error_handler = MobileErrorHandler() @@ -263,15 +266,6 @@ def __init__( if client_config and client_config.direct_connection: self._update_command_executor(keep_alive=client_config.keep_alive) - # add new method to the `find_by_*` pantheon - By.IOS_PREDICATE = AppiumBy.IOS_PREDICATE - By.IOS_CLASS_CHAIN = AppiumBy.IOS_CLASS_CHAIN - By.ANDROID_UIAUTOMATOR = AppiumBy.ANDROID_UIAUTOMATOR - By.ANDROID_VIEWTAG = AppiumBy.ANDROID_VIEWTAG - By.ACCESSIBILITY_ID = AppiumBy.ACCESSIBILITY_ID - By.IMAGE = AppiumBy.IMAGE - By.CUSTOM = AppiumBy.CUSTOM - self._absent_extensions: Set[str] = set() self._extensions = extensions or [] @@ -286,6 +280,14 @@ def __init__( method, url_cmd = instance.add_command() self.command_executor.add_command(method_name, method.upper(), url_cmd) + if TYPE_CHECKING: + + def find_element(self, by: str, value: Union[str, Dict, None] = None) -> 'MobileWebElement': # type: ignore[override] + ... + + def find_elements(self, by: str, value: Union[str, Dict, None] = None) -> List['MobileWebElement']: # type: ignore[override] + ... + def delete_extensions(self) -> None: """Delete extensions added in the class with 'setattr'""" for extension in self._extensions: @@ -301,7 +303,8 @@ def _update_command_executor(self, keep_alive: bool) -> None: direct_port = 'directConnectPort' direct_path = 'directConnectPath' - assert self.caps, 'Driver capabilities must be defined' + if not self.caps: + raise ValueError('Driver capabilities must be defined') if not {direct_protocol, direct_host, direct_port, direct_path}.issubset(set(self.caps)): message = 'Direct connect capabilities from server were:\n' for key in [direct_protocol, direct_host, direct_port, direct_path]: @@ -348,8 +351,8 @@ def start_session(self, capabilities: Union[Dict, AppiumOptions], browser_profil # Due to a W3C spec parsing misconception some servers # pack the createSession response stuff into 'value' dictionary and # some other put it to the top level of the response JSON nesting hierarchy - get_response_value: Callable[[str], Optional[Any]] = lambda key: response.get(key) or ( - response['value'].get(key) if isinstance(response.get('value'), dict) else None + get_response_value: Callable[[str], Optional[Any]] = lambda key: ( + response.get(key) or (response['value'].get(key) if isinstance(response.get('value'), dict) else None) ) session_id = get_response_value('sessionId') if not session_id: @@ -400,7 +403,7 @@ def switch_to(self) -> MobileSwitchTo: return MobileSwitchTo(self) # MJSONWP for Selenium v4 - @property + @property # type: ignore[override] def orientation(self) -> str: """ Gets the current orientation of the device diff --git a/appium/webdriver/webelement.py b/appium/webdriver/webelement.py index 52ea4e94f..61076ca37 100644 --- a/appium/webdriver/webelement.py +++ b/appium/webdriver/webelement.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Callable, Dict, Optional, Union +from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Union from selenium.webdriver.common.utils import keys_to_typing from selenium.webdriver.remote.command import Command as RemoteCommand @@ -26,7 +26,15 @@ class WebElement(SeleniumWebElement): _execute: Callable _id: str - def get_attribute(self, name: str) -> Optional[Union[str, Dict]]: + if TYPE_CHECKING: + + def find_element(self, by: str, value: Union[str, Dict, None] = None) -> Self: # type: ignore[override] + ... + + def find_elements(self, by: str, value: Union[str, Dict, None] = None) -> List[Self]: # type: ignore[override] + ... + + def get_attribute(self, name: str) -> Optional[Union[str, Dict]]: # type: ignore[override] """Gets the given attribute or property of the element. Override for Appium @@ -78,7 +86,7 @@ def is_displayed(self) -> bool: """ return self._execute(Command.IS_ELEMENT_DISPLAYED)['value'] - def clear(self) -> Self: + def clear(self) -> Self: # type: ignore[override] """Clears text. Override for Appium @@ -108,7 +116,7 @@ def location_in_view(self) -> Dict[str, int]: return self._execute(Command.LOCATION_IN_VIEW)['value'] # Override - def send_keys(self, *value: str) -> Self: + def send_keys(self, *value: str) -> Self: # type: ignore[override] """Simulates typing into the element. Args: diff --git a/ci.sh b/ci.sh deleted file mode 100755 index be2986f9d..000000000 --- a/ci.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -EXIT_STATUS=0 - -if ! make check-lint ; then - echo "Please run command 'make fix' or 'make fix-lint' on your local and commit the result" - EXIT_STATUS=1 -fi -if ! make check-format ; then - echo "Please run command 'make fix' or 'make fix-format' on your local and commit the result" - EXIT_STATUS=1 -fi -if ! make unittest ARGS=--junitxml=./test/unit/junit.xml ; then - EXIT_STATUS=1 -fi - -exit $EXIT_STATUS diff --git a/docs/Makefile b/docs/Makefile index d4bb2cbb9..3fb41af69 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -4,7 +4,7 @@ # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build +SPHINXBUILD ?= uv run sphinx-build SOURCEDIR = . BUILDDIR = _build diff --git a/docs/README.md b/docs/README.md index d788be7f1..ed9b03f1d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,6 @@ ```bash $cd python-client/docs -$pip install -r requirements.txt $bash generate.sh $cd python-client/docs/_build/html $python -m http.server 1234 diff --git a/docs/generate.sh b/docs/generate.sh index 219b7325d..71131e835 100644 --- a/docs/generate.sh +++ b/docs/generate.sh @@ -1,4 +1,4 @@ #!/bin/sh rm -rf *rst _build -sphinx-apidoc -F -H 'Appium python client' -o . ../appium/webdriver +uv run sphinx-apidoc -F -H 'Appium python client' -o . ../appium/webdriver make html diff --git a/docs/index.rst b/docs/index.rst index b98b63760..9c16ec4db 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,5 @@ .. Appium python client documentation master file, created by - sphinx-quickstart on Sat May 24 20:49:49 2025. + sphinx-quickstart on Mon Aug 11 09:34:52 2025. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index 21bd02829..000000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx >= 4.0, < 9.0 -sphinx_rtd_theme < 4.0 -sphinxcontrib-apidoc < 1.0 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..a279ebd26 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,144 @@ +[project] +name = "Appium-Python-Client" +description = "Python client for Appium" +version = "5.3.1" +readme = "README.md" +license = "Apache-2.0" +license-files = ["LICENSE"] +authors = [ + {name = "Kazuaki Matsuo", email = "kazucocoa1117@gmail.com"}, + {name = "Isaac Murchie"}, +] +maintainers = [ + {name = "Kazuaki Matsuo"}, + {name = "Mykola Mokhnach"}, + {name = "Mori Atsushi"}, +] +keywords = ["appium", "selenium", "python client", "mobile automation"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Environment :: Console", + "Topic :: Software Development :: Testing", +] +requires-python = ">=3.10" +dependencies = [ + "selenium>=4.26,<5.0", + "typing-extensions~=4.13", +] + +[project.urls] +Homepage = "https://appium.io/" +Repository = "https://github.com/appium/python-client" +Issues = "https://github.com/appium/python-client/issues" +Changelog = "https://github.com/appium/python-client/blob/master/CHANGELOG.md" + +[dependency-groups] +dev = [ + "httpretty~=1.1", + "mock~=5.2", + "mypy>=1.17,<3.0", + "pre-commit~=4.2", + "pytest>=8.4,<10.0", + "pytest-cov>=6.2,<8.0", + "pytest-xdist~=3.8", + "python-dateutil~=2.9", + "ruff~=0.15", + "types-python-dateutil~=2.9", + + # for release + "python-semantic-release>=10.3.1,<10.7.0", + + # for documentation + "sphinx>=4.0,<9.0", + "sphinx_rtd_theme~=3.0", + "sphinxcontrib-apidoc~=0.6", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build] +exclude = [ + "test/", + "script/", + "release.sh" +] + +[tool.hatch.build.targets.wheel] +packages = ["appium"] + +[tool.semantic_release] +assets = [] +build_command = """ + uv lock --upgrade-package "$PACKAGE_NAME" + git add uv.lock + uv build +""" +build_command_env = [] +commit_message = "{version}\n\nAutomatically generated by python-semantic-release" +commit_parser = "conventional" +logging_use_named_masks = false +major_on_zero = true +allow_zero_version = false +no_git_verify = false +tag_format = "v{version}" +version_toml = ["pyproject.toml:project.version"] + +[tool.semantic_release.branches.main] +match = "(main|master)" +prerelease_token = "rc" +prerelease = false + +[tool.semantic_release.changelog] +exclude_commit_patterns = [] +mode = "update" +insertion_flag = "" +template_dir = "templates" + +[tool.semantic_release.changelog.default_templates] +changelog_file = "CHANGELOG.md" +output_format = "md" +mask_initial_release = true + +[tool.semantic_release.changelog.environment] +block_start_string = "{%" +block_end_string = "%}" +variable_start_string = "{{" +variable_end_string = "}}" +comment_start_string = "{#" +comment_end_string = "#}" +trim_blocks = false +lstrip_blocks = false +newline_sequence = "\n" +keep_trailing_newline = false +extensions = [] +autoescape = false + +[tool.semantic_release.commit_author] +env = "GIT_COMMIT_AUTHOR" +default = "semantic-release " + +[tool.semantic_release.commit_parser_options] +minor_tags = ["feat"] +patch_tags = ["fix", "perf"] +other_allowed_tags = ["build", "chore", "ci", "docs", "style", "refactor", "test"] +allowed_tags = ["feat", "fix", "perf", "build", "chore", "ci", "docs", "style", "refactor", "test"] +default_bump_level = 0 +parse_squash_commits = true +ignore_merge_commits = true + +[tool.semantic_release.remote] +name = "origin" +type = "github" +ignore_token_for_push = false +insecure = false + +[tool.semantic_release.publish] +dist_glob_patterns = ["dist/*"] +upload_to_vcs_release = true diff --git a/release.sh b/release.sh deleted file mode 100755 index fe7a840f4..000000000 --- a/release.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -if [ -z "$PYTHON_BIN_PATH" ]; then - PYTHON_BIN_PATH=$(which python || true) -fi - -export PYTHON_BIN_PATH - -CONFIGURE_DIR=$(dirname "$0") -"$PYTHON_BIN_PATH" "${CONFIGURE_DIR}/script/release.py" "$@" - -echo "Finish release process" diff --git a/script/release.py b/script/release.py deleted file mode 100644 index 08ccab591..000000000 --- a/script/release.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. -"""Release script to publish release module to pipy.""" - -import glob -import io -import os -import shutil -import subprocess -import sys -from typing import List - -VERSION_FILE_PATH = os.path.join(os.path.dirname('__file__'), 'appium', 'version.py') -CHANGELOG_PATH = os.path.join(os.path.dirname('__file__'), 'CHANGELOG.rst') - -APPIUM_DIR_PATH = os.path.join(os.path.dirname('__file__'), 'appium') -BUILT_APPIUM_DIR_PATH = os.path.join(os.path.dirname('__file__'), 'build', 'lib', 'appium') - -MESSAGE_RED = '\033[1;31m{}\033[0m' -MESSAGE_GREEN = '\033[1;32m{}\033[0m' -MESSAGE_YELLOW = '\033[1;33m{}\033[0m' - - -def get_current_version(): - 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 - - -def get_new_version(): - print(MESSAGE_GREEN.format('new version:')) - for line in sys.stdin: - return line.rstrip() - - -VERSION_FORMAT = "version = '{}'\n" - - -def update_version_file(version): - new_version = VERSION_FORMAT.format(version) - with open(VERSION_FILE_PATH, 'w') as f: - f.write(new_version) - - -def call_bash_script(cmd): - if os.environ.get('DRY_RUN') is not None: - print('{} Calls: {}'.format(MESSAGE_RED.format('[DRY_RUN]'), cmd)) - else: - os.system(cmd) - - -def commit_version_code(new_version_num): - call_bash_script('git commit {} -m "Bump {}"'.format(VERSION_FILE_PATH, new_version_num)) - - -def tag_and_generate_changelog(new_version_num): - call_bash_script('git tag "v{}"'.format(new_version_num)) - call_bash_script('gitchangelog > {}'.format(CHANGELOG_PATH)) - call_bash_script('git commit {} -m "Update changelog for {}"'.format(CHANGELOG_PATH, new_version_num)) - - -def upload_sdist(new_version_num): - push_file = 'dist/appium_python_client-{}.tar.gz'.format(new_version_num) - try: - 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 - ) - ) - - -def push_changes_to_master(new_version_num): - call_bash_script('git push origin master') - call_bash_script('git push origin "v{}"'.format(new_version_num)) - - -def ensure_publication(new_version_num): - if os.environ.get('DRY_RUN') is not None: - print('Run with {} mode.'.format(MESSAGE_RED.format('[DRY_RUN]'))) - - print('Are you sure to release as {}?[y/n]'.format(MESSAGE_YELLOW.format(new_version_num))) - for line in sys.stdin: - if line.rstrip().lower() == 'y': - return - sys.exit('Canceled release process.') - - -def build_sdist(): - call_bash_script('{} setup.py sdist'.format(sys.executable)) - - -def validate_release_env(): - if os.system('which twine') != 0: - sys.exit("Please get twine via 'pip install twine'") - if os.system('which gitchangelog') != 0: - sys.exit( - "Please get twine via 'pip install gitchangelog' or 'pip install git+git://github.com/vaab/gitchangelog.git' for Python 3.7" - ) - - -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: - 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) - ] - - -def assert_files_count_in_package() -> None: - original_files = get_py_files_in_dir(APPIUM_DIR_PATH) - built_files = get_py_files_in_dir(BUILT_APPIUM_DIR_PATH) - - if len(original_files) != len(built_files): - print(f"The count of files in '{APPIUM_DIR_PATH}' and '{BUILT_APPIUM_DIR_PATH}' were different.") - - original_files_set = set(original_files) - built_files_set = set(built_files) - - diff = original_files_set.difference(built_files_set) - if diff: - 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}') - - sys.exit( - f"Python files in '{BUILT_APPIUM_DIR_PATH}' may differ from '{APPIUM_DIR_PATH}'. " - 'Please make sure setup.py is configured properly.' - ) - - -def main(): - validate_release_env() - - get_current_version() - new_version = get_new_version() - - update_version_file(new_version) - - build() - assert_files_count_in_package() - - ensure_publication(new_version) - - commit_version_code(new_version) - build_sdist() - - tag_and_generate_changelog(new_version) - - upload_sdist(new_version) - push_changes_to_master(new_version) - - -if __name__ == '__main__': - main() diff --git a/setup.py b/setup.py deleted file mode 100644 index adf89441d..000000000 --- a/setup.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. -import io -import os - -from setuptools import find_packages, setup - -from appium.common.helper import library_version - -setup( - name='Appium-Python-Client', - version=library_version(), - description='Python client for Appium', - long_description=io.open(os.path.join(os.path.dirname('__file__'), 'README.md'), encoding='utf-8').read(), - long_description_content_type='text/markdown', - keywords=['appium', 'selenium', 'selenium 4', 'python client', 'mobile automation'], - author='Isaac Murchie', - author_email='isaac@saucelabs.com', - maintainer='Kazuaki Matsuo, Mykola Mokhnach, Mori Atsushi', - url='http://appium.io/', - package_data={'appium': ['py.typed']}, - packages=find_packages(include=['appium*']), - license='Apache 2.0', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: 3.13', - 'Environment :: Console', - 'Environment :: MacOS X', - 'Environment :: Win32 (MS Windows)', - 'Intended Audience :: Developers', - 'Intended Audience :: Other Audience', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Topic :: Software Development :: Quality Assurance', - 'Topic :: Software Development :: Testing', - ], - install_requires=['selenium ~= 4.26, < 5.0'], -) diff --git a/test/apps/ApiDemos-debug.apk.zip b/test/apps/ApiDemos-debug.apk.zip deleted file mode 100644 index fcb29ca77..000000000 Binary files a/test/apps/ApiDemos-debug.apk.zip and /dev/null differ diff --git a/test/apps/TestApp.app.zip b/test/apps/TestApp.app.zip deleted file mode 100644 index 19668e47f..000000000 Binary files a/test/apps/TestApp.app.zip and /dev/null differ diff --git a/test/apps/UICatalog.app.zip b/test/apps/UICatalog.app.zip deleted file mode 100644 index 479d92e50..000000000 Binary files a/test/apps/UICatalog.app.zip and /dev/null differ diff --git a/test/functional/android/appium_service_tests.py b/test/functional/android/appium_service_tests.py index 6c346f734..409b80989 100644 --- a/test/functional/android/appium_service_tests.py +++ b/test/functional/android/appium_service_tests.py @@ -22,6 +22,7 @@ @pytest.fixture def appium_service() -> Generator[AppiumService, None, None]: + """Create and configure Appium service for testing.""" service = AppiumService() service.start( args=[ @@ -33,12 +34,13 @@ def appium_service() -> Generator[AppiumService, None, None]: '/wd/hub', ] ) - try: - yield service - finally: - service.stop() + + yield service + + service.stop() def test_appium_service(appium_service: AppiumService) -> None: + """Test that Appium service is running and listening.""" assert appium_service.is_running assert appium_service.is_listening diff --git a/test/functional/android/bidi_tests.py b/test/functional/android/bidi_tests.py new file mode 100644 index 000000000..146f29a55 --- /dev/null +++ b/test/functional/android/bidi_tests.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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, Generator + +import pytest +from selenium.webdriver.common.bidi.common import command_builder + +from appium import webdriver +from appium.webdriver.client_config import AppiumClientConfig +from test.functional.test_helper import is_ci +from test.helpers.constants import SERVER_URL_BASE + +from .options import make_options + +if TYPE_CHECKING: + from appium.webdriver.webdriver import WebDriver + + +class AppiumLogEntry: + """Represents a log entry from Appium BiDi.""" + + event_class = 'log.entryAdded' + + def __init__(self, level, text, timestamp, source, type): + self.level = level + self.text = text + self.timestamp = timestamp + self.source = source + self.type = type + + @property + def json(self): + return dict(type=self.type, level=self.level, text=self.text, timestamp=self.timestamp, source=self.source) + + @classmethod + def from_json(cls, json: dict): + return cls( + level=json['level'], + text=json['text'], + timestamp=json['timestamp'], + source=json['source'], + type=json['type'], + ) + + +@pytest.fixture +def driver() -> Generator['WebDriver', None, None]: + """Create and configure Chrome driver with BiDi support for testing.""" + client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) + client_config.timeout = 600 + options = make_options() + options.web_socket_url = True + driver = webdriver.Remote(SERVER_URL_BASE, options=options, client_config=client_config) + + yield driver + + driver.quit() + + +@pytest.mark.skipif(is_ci(), reason='Flaky on CI') +def test_bidi_log(driver: 'WebDriver') -> None: + """Test BiDi logging functionality with Chrome driver.""" + log_entries = [] + bidi_log_param = {'events': ['log.entryAdded'], 'contexts': ['NATIVE_APP']} + + driver.script.conn.execute(command_builder('session.subscribe', bidi_log_param)) + + def _log(entry: AppiumLogEntry): + # e.g. {'type': 'syslog', 'level': 'info', 'source': {'realm': ''}, 'text': '08-05 13:30:32.617 29677 29709 I appium : channel read: GET /session/d7c38859-8930-4eb0-960a-8f917c9e6a38/source', 'timestamp': 1754368241565} + log_entries.append(entry.json) + + try: + callback_id = driver.script.conn.add_callback(AppiumLogEntry, _log) + driver.page_source + assert len(log_entries) != 0 + driver.script.conn.remove_callback(AppiumLogEntry, callback_id) + finally: + driver.script.conn.execute(command_builder('session.unsubscribe', bidi_log_param)) diff --git a/test/functional/android/chrome_tests.py b/test/functional/android/chrome_tests.py index 000bc5dc3..52f994392 100644 --- a/test/functional/android/chrome_tests.py +++ b/test/functional/android/chrome_tests.py @@ -12,31 +12,39 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import TYPE_CHECKING, Generator + +import pytest + from appium import webdriver -from appium.options.common import AppiumOptions from appium.webdriver.client_config import AppiumClientConfig from appium.webdriver.common.appiumby import AppiumBy from test.helpers.constants import SERVER_URL_BASE -from .helper.desired_capabilities import get_desired_capabilities +from .options import make_options + +if TYPE_CHECKING: + from appium.webdriver.webdriver import WebDriver + + +@pytest.fixture +def driver() -> Generator['WebDriver', None, None]: + """Create and configure Chrome driver for testing.""" + client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) + client_config.timeout = 600 + options = make_options() + options.browser_name = 'Chrome' + driver = webdriver.Remote(SERVER_URL_BASE, options=options, client_config=client_config) + yield driver -class TestChrome(object): - def setup_method(self) -> None: - client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) - client_config.timeout = 600 - caps = get_desired_capabilities() - caps['browserName'] = 'Chrome' - self.driver = webdriver.Remote( - SERVER_URL_BASE, options=AppiumOptions().load_capabilities(caps), client_config=client_config - ) + driver.quit() - def teardown_method(self) -> None: - self.driver.quit() - def test_find_single_element(self) -> None: - e = self.driver.find_element(by=AppiumBy.XPATH, value='//body') - assert e.text == '' +def test_find_single_element(driver: 'WebDriver') -> None: + """Test finding a single element in Chrome browser.""" + e = driver.find_element(by=AppiumBy.XPATH, value='//body') + assert e.text == '' - # Chrome browser's default page - assert '' in self.driver.page_source + # Chrome browser's default page + assert '' in driver.page_source diff --git a/test/functional/android/helper/__init__.py b/test/functional/android/helper/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/functional/android/helper/desired_capabilities.py b/test/functional/android/helper/desired_capabilities.py deleted file mode 100644 index ef400ffff..000000000 --- a/test/functional/android/helper/desired_capabilities.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. - -import os -from typing import Any, Dict, Optional - -# Returns abs path relative to this file and not cwd - - -def PATH(p: str) -> str: - return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', p)) - - -def get_desired_capabilities(app: Optional[str] = None) -> Dict[str, Any]: - desired_caps: Dict[str, Any] = { - 'platformName': 'Android', - 'deviceName': 'Android Emulator', - 'newCommandTimeout': 240, - 'automationName': 'UIAutomator2', - 'uiautomator2ServerInstallTimeout': 120000, - 'adbExecTimeout': 120000, - } - - if app is not None: - desired_caps['app'] = PATH(os.path.join('../..', 'apps', app)) - - return desired_caps diff --git a/test/functional/android/helper/test_helper.py b/test/functional/android/helper/test_helper.py deleted file mode 100644 index 7f113f210..000000000 --- a/test/functional/android/helper/test_helper.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. - - -import base64 -import os - -from appium import webdriver -from appium.options.android import UiAutomator2Options -from appium.webdriver.client_config import AppiumClientConfig -from test.functional.test_helper import is_ci -from test.helpers.constants import SERVER_URL_BASE - -from . import desired_capabilities - -# the emulator is sometimes slow and needs time to think -SLEEPY_TIME = 10 - -# The package name of ApiDemos-debug.apk.zip -APIDEMO_PKG_NAME = 'io.appium.android.apis' - - -class BaseTestCase: - def setup_method(self, method) -> None: # type: ignore - caps = desired_capabilities.get_desired_capabilities('ApiDemos-debug.apk.zip') - client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) - client_config.timeout = 600 - self.driver = webdriver.Remote(options=UiAutomator2Options().load_capabilities(caps), client_config=client_config) - if is_ci(): - self.driver.start_recording_screen() - - def teardown_method(self, method) -> None: # type: ignore - if not hasattr(self, 'driver'): - return - - if is_ci(): - payload = self.driver.stop_recording_screen() - video_path = os.path.join(os.getcwd(), method.__name__ + '.mp4') - with open(video_path, 'wb') as fd: - fd.write(base64.b64decode(payload)) - self.driver.quit() diff --git a/test/functional/android/options.py b/test/functional/android/options.py new file mode 100644 index 000000000..9c8103a75 --- /dev/null +++ b/test/functional/android/options.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +import os +from typing import Optional + +from appium.options.android import UiAutomator2Options +from test.functional.test_helper import get_worker_info + + +def make_options(app: Optional[str] = None) -> UiAutomator2Options: + """Get UiAutomator2 options configured for Android testing with parallel execution support.""" + options = UiAutomator2Options() + + # Set basic Android capabilities + options.device_name = android_device_name() + options.platform_name = 'Android' + options.automation_name = 'UIAutomator2' + options.new_command_timeout = 240 + options.uiautomator2_server_install_timeout = 120000 + options.adb_exec_timeout = 120000 + + if app is not None: + options.app = app + + return options + + +def android_device_name() -> str: + """ + Get a unique device name for the current worker. + Uses the base device name and appends the port number for uniqueness. + """ + prefix = os.getenv('ANDROID_MODEL') or 'Android Emulator' + worker_info = get_worker_info() + + if worker_info.is_parallel: + # For parallel execution, we can use different device names or ports + # This is a simplified approach - in practice you might want to use different emulators + return f'{prefix} - Worker {worker_info.worker_id}' + + return prefix diff --git a/test/functional/flutter_integration/commands_test.py b/test/functional/flutter_integration/commands_test.py index f256222e0..7afe4156e 100644 --- a/test/functional/flutter_integration/commands_test.py +++ b/test/functional/flutter_integration/commands_test.py @@ -13,122 +13,136 @@ # limitations under the License. import os +from typing import TYPE_CHECKING from appium.webdriver.common.appiumby import AppiumBy from appium.webdriver.extensions.flutter_integration.flutter_finder import FlutterFinder from appium.webdriver.extensions.flutter_integration.scroll_directions import ScrollDirection -from test.functional.flutter_integration.helper.test_helper import BaseTestCase +if TYPE_CHECKING: + from appium.webdriver.extensions.flutter_integration.flutter_commands import FlutterCommand + from appium.webdriver.webdriver import WebDriver -class TestFlutterCommands(BaseTestCase): - def test_wait_command(self) -> None: - self.__open_screen('Lazy Loading') - message_field_finder = FlutterFinder.by_key('message_field') - toggle_button_finder = FlutterFinder.by_key('toggle_button') +def _open_screen(driver: 'WebDriver', flutter_command: 'FlutterCommand', screen_name: str) -> None: + """Helper function to open a specific screen in the Flutter app.""" + driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Login').click() + element = flutter_command.scroll_till_visible(FlutterFinder.by_text(screen_name)) + element.click() - message_field = self.driver.find_element(*message_field_finder.as_args()) - toggle_button = self.driver.find_element(*toggle_button_finder.as_args()) - assert message_field.is_displayed() == True - assert message_field.text == 'Hello world' - toggle_button.click() - self.flutter_command.wait_for_invisible(message_field_finder) - assert len(self.driver.find_elements(*message_field_finder.as_args())) == 0 +def test_wait_command(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test Flutter wait commands for element visibility.""" + _open_screen(driver, flutter_command, 'Lazy Loading') - toggle_button.click() - self.flutter_command.wait_for_visible(message_field) - assert len(self.driver.find_elements(*message_field_finder.as_args())) == 1 + message_field_finder = FlutterFinder.by_key('message_field') + toggle_button_finder = FlutterFinder.by_key('toggle_button') - def test_scroll_till_visible_command(self) -> None: - self.__open_screen('Vertical Swiping') + message_field = driver.find_element(*message_field_finder.as_args()) + toggle_button = driver.find_element(*toggle_button_finder.as_args()) + assert message_field.is_displayed() == True + assert message_field.text == 'Hello world' - java_text_finder = FlutterFinder.by_text('Java') - protractor_text_finder = FlutterFinder.by_text('Protractor') + toggle_button.click() + flutter_command.wait_for_invisible(message_field_finder) + assert len(driver.find_elements(*message_field_finder.as_args())) == 0 - first_element = self.flutter_command.scroll_till_visible(java_text_finder) - assert first_element.get_attribute('displayed') == 'true' + toggle_button.click() + flutter_command.wait_for_visible(message_field) + assert len(driver.find_elements(*message_field_finder.as_args())) == 1 - second_element = self.flutter_command.scroll_till_visible(protractor_text_finder) - assert second_element.get_attribute('displayed') == 'true' - assert first_element.get_attribute('displayed') == 'false' - first_element = self.flutter_command.scroll_till_visible(java_text_finder, ScrollDirection.UP) - assert second_element.get_attribute('displayed') == 'false' - assert first_element.get_attribute('displayed') == 'true' +def test_scroll_till_visible_command(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test Flutter scroll till visible command.""" + _open_screen(driver, flutter_command, 'Vertical Swiping') - def test_scroll_till_visible_with_scroll_params_command(self) -> None: - self.__open_screen('Vertical Swiping') + java_text_finder = FlutterFinder.by_text('Java') + protractor_text_finder = FlutterFinder.by_text('Protractor') - scroll_params = { - 'scrollView': FlutterFinder.by_type('Scrollable').to_dict(), - 'delta': 30, - 'maxScrolls': 30, - 'settleBetweenScrollsTimeout': 5000, - 'dragDuration': 35, - } - first_element = self.flutter_command.scroll_till_visible( - FlutterFinder.by_text('Playwright'), scroll_direction=ScrollDirection.DOWN, **scroll_params - ) - assert first_element.get_attribute('displayed') == 'true' + first_element = flutter_command.scroll_till_visible(java_text_finder) + assert first_element.get_attribute('displayed') == 'true' - def test_double_click_command(self) -> None: - self.__open_screen('Double Tap') + second_element = flutter_command.scroll_till_visible(protractor_text_finder) + assert second_element.get_attribute('displayed') == 'true' + assert first_element.get_attribute('displayed') == 'false' - double_tap_button = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'double_tap_button').find_element( - AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Double Tap' - ) - assert double_tap_button.text == 'Double Tap' + first_element = flutter_command.scroll_till_visible(java_text_finder, ScrollDirection.UP) + assert second_element.get_attribute('displayed') == 'false' + assert first_element.get_attribute('displayed') == 'true' - self.flutter_command.perform_double_click(double_tap_button) - assert ( - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING, 'Successful').text == 'Double Tap Successful' - ) - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Ok').click() - self.flutter_command.perform_double_click(double_tap_button, (10, 2)) - assert ( - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING, 'Successful').text == 'Double Tap Successful' - ) +def test_scroll_till_visible_with_scroll_params_command(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test Flutter scroll till visible command with custom scroll parameters.""" + _open_screen(driver, flutter_command, 'Vertical Swiping') - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Ok').click() + scroll_params = { + 'scrollView': FlutterFinder.by_type('Scrollable').to_dict(), + 'delta': 30, + 'maxScrolls': 30, + 'settleBetweenScrollsTimeout': 5000, + 'dragDuration': 35, + } + first_element = flutter_command.scroll_till_visible( + FlutterFinder.by_text('Playwright'), scroll_direction=ScrollDirection.DOWN, **scroll_params + ) + assert first_element.get_attribute('displayed') == 'true' - def test_long_press_command(self) -> None: - self.__open_screen('Long Press') - long_press_button = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'long_press_button') - self.flutter_command.perform_long_press(long_press_button) +def test_double_click_command(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test Flutter double click command.""" + _open_screen(driver, flutter_command, 'Double Tap') - success_pop_up = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'It was a long press') - assert success_pop_up.text == 'It was a long press' - assert success_pop_up.is_displayed() == True + double_tap_button = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'double_tap_button').find_element( + AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Double Tap' + ) + assert double_tap_button.text == 'Double Tap' - def test_drag_and_drop_command(self) -> None: - self.__open_screen('Drag & Drop') + flutter_command.perform_double_click(double_tap_button) + assert driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING, 'Successful').text == 'Double Tap Successful' - drag_element = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'drag_me') - drop_element = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'drop_zone') - self.flutter_command.perform_drag_and_drop(drag_element, drop_element) - assert self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'The box is dropped').is_displayed() == True + driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Ok').click() + flutter_command.perform_double_click(double_tap_button, (10, 2)) + assert driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING, 'Successful').text == 'Double Tap Successful' - def test_camera_mocking(self) -> None: - self.__open_screen('Image Picker') + driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Ok').click() - success_qr_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'file', 'success_qr.png') - second_qr_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'file', 'second_qr.png') - image_id = self.flutter_command.inject_mock_image(success_qr_file_path) - self.flutter_command.inject_mock_image(second_qr_file_path) - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'capture_image').click() - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'PICK').click() - assert self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'SecondInjectedImage').is_displayed() == True - - self.flutter_command.activate_injected_image(image_id) - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'capture_image').click() - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'PICK').click() - assert self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Success!').is_displayed() == True - - def __open_screen(self, screen_name: str) -> None: - self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Login').click() - element = self.flutter_command.scroll_till_visible(FlutterFinder.by_text(screen_name)) - element.click() +def test_long_press_command(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test Flutter long press command.""" + _open_screen(driver, flutter_command, 'Long Press') + + long_press_button = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'long_press_button') + flutter_command.perform_long_press(long_press_button) + + success_pop_up = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'It was a long press') + assert success_pop_up.text == 'It was a long press' + assert success_pop_up.is_displayed() == True + + +def test_drag_and_drop_command(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test Flutter drag and drop command.""" + _open_screen(driver, flutter_command, 'Drag & Drop') + + drag_element = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'drag_me') + drop_element = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'drop_zone') + flutter_command.perform_drag_and_drop(drag_element, drop_element) + assert driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'The box is dropped').is_displayed() == True + + +def test_camera_mocking(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test Flutter camera mocking functionality.""" + _open_screen(driver, flutter_command, 'Image Picker') + + success_qr_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'file', 'success_qr.png') + second_qr_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'file', 'second_qr.png') + + image_id = flutter_command.inject_mock_image(success_qr_file_path) + flutter_command.inject_mock_image(second_qr_file_path) + driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'capture_image').click() + driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'PICK').click() + assert driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'SecondInjectedImage').is_displayed() == True + + flutter_command.activate_injected_image(image_id) + driver.find_element(AppiumBy.FLUTTER_INTEGRATION_KEY, 'capture_image').click() + driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'PICK').click() + assert driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Success!').is_displayed() == True diff --git a/test/functional/flutter_integration/conftest.py b/test/functional/flutter_integration/conftest.py new file mode 100644 index 000000000..128312e83 --- /dev/null +++ b/test/functional/flutter_integration/conftest.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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, Generator + +import pytest + +from appium import webdriver +from appium.webdriver.client_config import AppiumClientConfig +from appium.webdriver.extensions.flutter_integration.flutter_commands import FlutterCommand +from test.helpers.constants import SERVER_URL_BASE + +from .helper.options import make_options + +if TYPE_CHECKING: + from appium.webdriver.webdriver import WebDriver + + +@pytest.fixture +def driver() -> Generator['WebDriver', None, None]: + """Create and configure Flutter driver for testing.""" + options = make_options() + + client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) + client_config.timeout = 600 + + driver = webdriver.Remote(options=options, client_config=client_config) + + yield driver + + driver.quit() + + +@pytest.fixture +def flutter_command(driver: 'WebDriver') -> FlutterCommand: + """Create FlutterCommand instance for the driver.""" + return FlutterCommand(driver) diff --git a/test/functional/flutter_integration/finder_test.py b/test/functional/flutter_integration/finder_test.py index d9bc3f56b..5357fc6f1 100644 --- a/test/functional/flutter_integration/finder_test.py +++ b/test/functional/flutter_integration/finder_test.py @@ -12,45 +12,58 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import TYPE_CHECKING + from appium.webdriver.common.appiumby import AppiumBy from appium.webdriver.extensions.flutter_integration.flutter_finder import FlutterFinder -from test.functional.flutter_integration.helper.test_helper import BaseTestCase + +if TYPE_CHECKING: + from appium.webdriver.extensions.flutter_integration.flutter_commands import FlutterCommand + from appium.webdriver.webdriver import WebDriver LOGIN_BUTTON_FINDER = FlutterFinder.by_text('Login') -class TestFlutterFinders(BaseTestCase): - def test_by_flutter_key(self) -> None: - user_name_field_finder = FlutterFinder.by_key('username_text_field') - user_name_field = self.driver.find_element(*user_name_field_finder.as_args()) - assert user_name_field.text == 'admin' - - user_name_field.clear() - user_name_field = self.driver.find_element(*user_name_field_finder.as_args()).send_keys('admin123') - assert user_name_field.text == 'admin123' - - def test_by_flutter_type(self) -> None: - login_button = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TYPE, 'ElevatedButton') - assert login_button.find_element(AppiumBy.FLUTTER_INTEGRATION_TYPE, 'Text').text == 'Login' - - def test_by_flutter_text(self) -> None: - login_button = self.driver.find_element(*LOGIN_BUTTON_FINDER.as_args()) - assert login_button.text == 'Login' - - login_button.click() - slider = self.driver.find_elements(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Slider') - assert len(slider) == 1 - - def test_by_flutter_text_containing(self) -> None: - login_button = self.driver.find_element(*LOGIN_BUTTON_FINDER.as_args()) - login_button.click() - vertical_swipe_label = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING, 'Vertical') - assert vertical_swipe_label.text == 'Vertical Swiping' - - def test_by_flutter_semantics_label(self) -> None: - login_button = self.driver.find_element(*LOGIN_BUTTON_FINDER.as_args()) - login_button.click() - element = self.flutter_command.scroll_till_visible(FlutterFinder.by_text('Lazy Loading')) - element.click() - message_field = self.driver.find_element(AppiumBy.FLUTTER_INTEGRATION_SEMANTICS_LABEL, 'message_field') - assert message_field.text == 'Hello world' +def test_by_flutter_key(driver: 'WebDriver') -> None: + """Test finding elements by Flutter key.""" + user_name_field_finder = FlutterFinder.by_key('username_text_field') + user_name_field = driver.find_element(*user_name_field_finder.as_args()) + assert user_name_field.text == 'admin' + + user_name_field.clear() + user_name_field = driver.find_element(*user_name_field_finder.as_args()).send_keys('admin123') + assert user_name_field.text == 'admin123' + + +def test_by_flutter_type(driver: 'WebDriver') -> None: + """Test finding elements by Flutter type.""" + login_button = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TYPE, 'ElevatedButton') + assert login_button.find_element(AppiumBy.FLUTTER_INTEGRATION_TYPE, 'Text').text == 'Login' + + +def test_by_flutter_text(driver: 'WebDriver') -> None: + """Test finding elements by Flutter text.""" + login_button = driver.find_element(*LOGIN_BUTTON_FINDER.as_args()) + assert login_button.text == 'Login' + + login_button.click() + slider = driver.find_elements(AppiumBy.FLUTTER_INTEGRATION_TEXT, 'Slider') + assert len(slider) == 1 + + +def test_by_flutter_text_containing(driver: 'WebDriver') -> None: + """Test finding elements by Flutter text containing.""" + login_button = driver.find_element(*LOGIN_BUTTON_FINDER.as_args()) + login_button.click() + vertical_swipe_label = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_TEXT_CONTAINING, 'Vertical') + assert vertical_swipe_label.text == 'Vertical Swiping' + + +def test_by_flutter_semantics_label(driver: 'WebDriver', flutter_command: 'FlutterCommand') -> None: + """Test finding elements by Flutter semantics label.""" + login_button = driver.find_element(*LOGIN_BUTTON_FINDER.as_args()) + login_button.click() + element = flutter_command.scroll_till_visible(FlutterFinder.by_text('Lazy Loading')) + element.click() + message_field = driver.find_element(AppiumBy.FLUTTER_INTEGRATION_SEMANTICS_LABEL, 'message_field') + assert message_field.text == 'Hello world' diff --git a/test/functional/flutter_integration/helper/desired_capabilities.py b/test/functional/flutter_integration/helper/desired_capabilities.py deleted file mode 100644 index b03053418..000000000 --- a/test/functional/flutter_integration/helper/desired_capabilities.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. - -import os -from typing import Any, Dict - - -def get_desired_capabilities(platform_name: str) -> Dict[str, Any]: - desired_caps: Dict[str, Any] = {} - if platform_name == 'android': - desired_caps.update( - { - 'platformName': 'Android', - 'deviceName': 'Android Emulator', - 'newCommandTimeout': 120, - 'uiautomator2ServerInstallTimeout': 120000, - 'adbExecTimeout': 120000, - 'app': os.getenv('FLUTTER_ANDROID_APP'), - 'autoGrantPermissions': True, - } - ) - else: - desired_caps.update( - { - 'deviceName': os.getenv('IPHONE_MODEL'), - 'platformName': 'iOS', - 'platformVersion': os.getenv('IOS_VERSION'), - 'allowTouchIdEnroll': True, - 'wdaLaunchTimeout': 240000, - 'wdaLocalPort': 8100, - 'eventTimings': True, - 'app': os.getenv('FLUTTER_IOS_APP'), - } - ) - - return desired_caps diff --git a/test/functional/flutter_integration/helper/options.py b/test/functional/flutter_integration/helper/options.py new file mode 100644 index 000000000..0a44f372b --- /dev/null +++ b/test/functional/flutter_integration/helper/options.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +import os +from typing import Any, Dict + +from appium.options.flutter_integration.base import FlutterOptions +from test.functional.test_helper import get_wda_port, get_worker_info + + +def is_platform_android() -> bool: + """Check if the current platform is Android.""" + return os.getenv('PLATFORM', 'android').lower() == 'android' + + +def get_flutter_system_port() -> int: + """ + Get a unique Flutter system port for the current worker. + Uses base port 9999 and increments by worker number. + """ + worker_info = get_worker_info() + return 9999 + (worker_info.worker_number or 0) + + +def make_options() -> FlutterOptions: + """Get Flutter options configured for testing with parallel execution support.""" + options = FlutterOptions() + + # Set Flutter-specific capabilities + options.flutter_system_port = get_flutter_system_port() + options.flutter_enable_mock_camera = True + options.flutter_element_wait_timeout = 10000 + options.flutter_server_launch_timeout = 120000 + + caps: Dict[str, Any] = ( + { + 'platformName': 'Android', + 'deviceName': device_name(), + 'newCommandTimeout': 120, + 'uiautomator2ServerInstallTimeout': 120000, + 'adbExecTimeout': 120000, + 'app': os.environ['FLUTTER_ANDROID_APP'], + 'autoGrantPermissions': True, + } + if is_platform_android() + else { + 'deviceName': device_name(), + 'platformName': 'iOS', + 'platformVersion': os.environ['IOS_VERSION'], + 'allowTouchIdEnroll': True, + 'wdaLaunchTimeout': 240000, + 'wdaLocalPort': get_wda_port(), + 'eventTimings': True, + 'app': os.environ['FLUTTER_IOS_APP'], + } + ) + + if local_prebuilt_wda := os.getenv('LOCAL_PREBUILT_WDA'): + caps.update( + { + 'usePreinstalledWDA': True, + 'prebuiltWDAPath': local_prebuilt_wda, + } + ) + + return options.load_capabilities(caps) + + +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'] + + worker_info = get_worker_info() + + if worker_info.is_parallel: + port = get_flutter_system_port() if is_platform_android() else get_wda_port() + return f'{prefix} - {port}' + + return prefix diff --git a/test/functional/flutter_integration/helper/test_helper.py b/test/functional/flutter_integration/helper/test_helper.py deleted file mode 100644 index 19c669754..000000000 --- a/test/functional/flutter_integration/helper/test_helper.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. - -import os - -from appium import webdriver -from appium.options.flutter_integration.base import FlutterOptions -from appium.webdriver.client_config import AppiumClientConfig -from appium.webdriver.extensions.flutter_integration.flutter_commands import FlutterCommand -from test.helpers.constants import SERVER_URL_BASE - -from . import desired_capabilities - - -class BaseTestCase(object): - def setup_method(self) -> None: - platform_name = os.getenv('PLATFORM', 'android').lower() - - # set flutter options - flutterOptions = FlutterOptions() - flutterOptions.flutter_system_port = 9999 - flutterOptions.flutter_enable_mock_camera = True - flutterOptions.flutter_element_wait_timeout = 10000 - flutterOptions.flutter_server_launch_timeout = 120000 - - desired_caps = desired_capabilities.get_desired_capabilities(platform_name) - - client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) - client_config.timeout = 600 - - self.driver = webdriver.Remote(options=flutterOptions.load_capabilities(desired_caps), client_config=client_config) - self.flutter_command = FlutterCommand(self.driver) - - def teardown_method(self) -> None: # type: ignore - if not hasattr(self, 'driver'): - return - self.driver.quit() diff --git a/test/functional/ios/helper/desired_capabilities.py b/test/functional/ios/helper/desired_capabilities.py deleted file mode 100644 index b0687c357..000000000 --- a/test/functional/ios/helper/desired_capabilities.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. -import os -from typing import Any, Dict, Optional - -# Returns abs path relative to this file and not cwd - - -def PATH(p: str) -> str: - return os.path.abspath(os.path.join(os.path.dirname(__file__), p)) - - -BUNDLE_ID = 'com.example.apple-samplecode.UICatalog' - - -def get_desired_capabilities(app: Optional[str] = None) -> Dict[str, Any]: - desired_caps: Dict[str, Any] = { - 'deviceName': iphone_device_name(), - 'platformName': 'iOS', - 'platformVersion': '17.4', - 'automationName': 'XCUITest', - 'allowTouchIdEnroll': True, - 'wdaLocalPort': wda_port(), - 'simpleIsVisibleCheck': True, - } - - if app is not None: - desired_caps['app'] = PATH(os.path.join('../../..', 'apps', app)) - - return desired_caps - - -class PytestXdistWorker: - NUMBER: Optional[str] = os.getenv('PYTEST_XDIST_WORKER') - COUNT: Optional[str] = os.getenv('PYTEST_XDIST_WORKER_COUNT') # Return 2 if `-n 2` is passed - - @staticmethod - def gw(number: int) -> str: - if PytestXdistWorker.COUNT is None: - return '0' - - if number >= int(PytestXdistWorker.COUNT): - return 'gw0' - - return f'gw{number}' - - -# If you run tests with pytest-xdist, you can run tests in parallel. - - -def wda_port() -> int: - if PytestXdistWorker.NUMBER == PytestXdistWorker.gw(1): - return 8101 - - return 8100 - - -# Before running tests, you must have iOS simulators named 'iPhone 12 - 8100' and 'iPhone 12 - 8101' - - -def iphone_device_name() -> str: - prefix = 'iPhone 15 Plus' - if PytestXdistWorker.NUMBER == PytestXdistWorker.gw(0): - return f'{prefix} - 8100' - elif PytestXdistWorker.NUMBER == PytestXdistWorker.gw(1): - return f'{prefix} - 8101' - - return prefix diff --git a/test/functional/ios/helper/options.py b/test/functional/ios/helper/options.py new file mode 100644 index 000000000..a189b741f --- /dev/null +++ b/test/functional/ios/helper/options.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +import os +from typing import Optional + +from appium.options.ios import XCUITestOptions +from test.functional.test_helper import get_wda_port, get_worker_info + + +def make_options(app: Optional[str] = None) -> XCUITestOptions: + """Get XCUITest options configured for iOS testing with parallel execution support.""" + options = XCUITestOptions() + + # Set basic iOS capabilities + options.device_name = iphone_device_name() + options.platform_version = os.getenv('IOS_VERSION') or '17.4' + options.allow_touch_id_enroll = True + options.wda_local_port = get_wda_port() + options.simple_is_visible_check = True + + if app is not None: + options.app = app + + if local_prebuilt_wda := os.getenv('LOCAL_PREBUILT_WDA'): + options.use_preinstalled_wda = True + options.prebuilt_wda_path = local_prebuilt_wda + + return options + + +def iphone_device_name() -> str: + """ + Get a unique device name for the current worker. + Uses the base device name and appends the port number for uniqueness. + """ + prefix = os.getenv('IPHONE_MODEL') or 'iPhone 15 Plus' + worker_info = get_worker_info() + + if worker_info.is_parallel: + port = get_wda_port() + return f'{prefix} - {port}' + + return prefix diff --git a/test/functional/ios/helper/test_helper.py b/test/functional/ios/helper/test_helper.py deleted file mode 100644 index 435ca4b45..000000000 --- a/test/functional/ios/helper/test_helper.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. - -import base64 -import os - -from appium import webdriver -from appium.options.ios import XCUITestOptions -from appium.webdriver.client_config import AppiumClientConfig -from test.functional.test_helper import is_ci -from test.helpers.constants import SERVER_URL_BASE - -from . import desired_capabilities - - -class BaseTestCase(object): - IOS_UICATALOG_APP_NAME = 'UIKitCatalog' - - def setup_method(self) -> None: - desired_caps = desired_capabilities.get_desired_capabilities('UICatalog.app.zip') - client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) - client_config.timeout = 600 - self.driver = webdriver.Remote(options=XCUITestOptions().load_capabilities(desired_caps), client_config=client_config) - if is_ci(): - self.driver.start_recording_screen() - - def teardown_method(self, method) -> None: # type: ignore - if not hasattr(self, 'driver'): - return - - if is_ci(): - payload = self.driver.stop_recording_screen() - video_path = os.path.join(os.getcwd(), method.__name__ + '.mp4') - with open(video_path, 'wb') as fd: - fd.write(base64.b64decode(payload)) - self.driver.quit() diff --git a/test/functional/ios/safari_tests.py b/test/functional/ios/safari_tests.py index c7bd997c1..624979f80 100644 --- a/test/functional/ios/safari_tests.py +++ b/test/functional/ios/safari_tests.py @@ -13,62 +13,67 @@ # limitations under the License. import time +from typing import TYPE_CHECKING, Generator + +import pytest from appium import webdriver -from appium.options.common import AppiumOptions from appium.webdriver.client_config import AppiumClientConfig from test.helpers.constants import SERVER_URL_BASE -from .helper.desired_capabilities import get_desired_capabilities - - -class TestSafari: - def setup_method(self) -> None: - caps = get_desired_capabilities() - caps.update( - { - 'bundleId': 'com.apple.mobilesafari', - 'nativeWebTap': True, - 'safariIgnoreFraudWarning': True, - 'webviewConnectTimeout': 100000, - } - ) - client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) - client_config.timeout = 600 - self.driver = webdriver.Remote(options=AppiumOptions().load_capabilities(caps), client_config=client_config) - - # Fresh iOS 17.4 simulator may not show up the webview context with "safari" - # after a fresh simlator instance creation. - # Re-launch the process could be a workaround in my debugging. - self.driver.terminate_app('com.apple.mobilesafari') - self.driver.activate_app('com.apple.mobilesafari') - - def teardown_method(self) -> None: - self.driver.quit() - - def test_context(self) -> None: - contexts = self.driver.contexts - assert 'NATIVE_APP' == contexts[0] - assert contexts[1].startswith('WEBVIEW_') - self.driver.switch_to.context(contexts[1]) - assert 'WEBVIEW_' in self.driver.current_context - - def test_get(self) -> None: - ok = False - contexts = self.driver.contexts - for context in contexts: - if context.startswith('WEBVIEW_'): - self.driver.switch_to.context(context) - ok = True - break - - if ok is False: - assert False, 'Could not set WEBVIEW context' - - self.driver.get('http://google.com') - for _ in range(5): - time.sleep(0.5) - if 'Google' == self.driver.title: - return - - assert False, 'The title was wrong' +from .helper.options import make_options + +if TYPE_CHECKING: + from appium.webdriver.webdriver import WebDriver + + +@pytest.fixture +def driver() -> Generator['WebDriver', None, None]: + """Create and configure Safari driver for testing.""" + options = make_options() + options.bundle_id = 'com.apple.mobilesafari' + options.native_web_tap = True + options.safari_ignore_fraud_warning = True + options.webview_connect_timeout = 100000 + + client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) + client_config.timeout = 600 + driver = webdriver.Remote(options=options, client_config=client_config) + + # Fresh iOS 17.4 simulator may not show up the webview context with "safari" + # after a fresh simlator instance creation. + # Re-launch the process could be a workaround in my debugging. + driver.terminate_app('com.apple.mobilesafari') + driver.activate_app('com.apple.mobilesafari') + + yield driver + + driver.quit() + + +def test_context(driver: 'WebDriver') -> None: + """Test Safari context switching.""" + contexts = driver.contexts + assert 'NATIVE_APP' == contexts[0] + assert contexts[1].startswith('WEBVIEW_') + driver.switch_to.context(contexts[1]) + assert 'WEBVIEW_' in driver.current_context + + +def test_navigation(driver: 'WebDriver') -> None: + """Test Safari navigation to Google.""" + contexts = driver.contexts + for context in contexts: + if context.startswith('WEBVIEW_'): + driver.switch_to.context(context) + break + else: + pytest.fail('Could not set WEBVIEW context') + + driver.get('http://google.com') + for _ in range(5): + time.sleep(0.5) + if 'Google' == driver.title: + return + + pytest.fail('The title was wrong') diff --git a/test/functional/mac/helper/test_helper.py b/test/functional/mac/helper/test_helper.py index 0b7463dac..edee8395b 100644 --- a/test/functional/mac/helper/test_helper.py +++ b/test/functional/mac/helper/test_helper.py @@ -20,7 +20,7 @@ from .desired_capabilities import get_desired_capabilities -class BaseTestCase(object): +class BaseTestCase: def setup_method(self) -> None: client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE) client_config.timeout = 600 diff --git a/test/functional/test_helper.py b/test/functional/test_helper.py index 817f833ea..90500ea0a 100644 --- a/test/functional/test_helper.py +++ b/test/functional/test_helper.py @@ -1,8 +1,9 @@ import os import socket import time +from dataclasses import dataclass from time import sleep -from typing import TYPE_CHECKING, Any, Callable +from typing import TYPE_CHECKING, Any, Callable, Optional from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @@ -95,3 +96,47 @@ def wait_for_element(driver: 'WebDriver', locator: str, value: str, timeout_sec: The found WebElement """ return WebDriverWait(driver, timeout_sec).until(EC.presence_of_element_located((locator, value))) + + +@dataclass +class WorkerInfo: + """Information about the current test worker in parallel execution.""" + + worker_number: Optional[int] + total_workers: Optional[int] + + @property + def is_parallel(self) -> bool: + """Check if running in parallel mode.""" + return self.worker_number is not None and self.total_workers is not None + + +def get_worker_info() -> WorkerInfo: + """ + Get current worker number and total worker count from pytest-xdist environment variables. + + Returns: + WorkerInfo: Worker information or None values if not running in parallel + """ + worker_number = os.getenv('PYTEST_XDIST_WORKER') + worker_count = os.getenv('PYTEST_XDIST_WORKER_COUNT') + + if worker_number and worker_count: + # Extract number from worker string like 'gw0', 'gw1', etc. + try: + worker_num = int(worker_number.replace('gw', '')) + total_workers = int(worker_count) + return WorkerInfo(worker_number=worker_num, total_workers=total_workers) + except (ValueError, AttributeError): + pass + + return WorkerInfo(worker_number=None, total_workers=None) + + +def get_wda_port() -> int: + """ + Get a unique WDA port for the current worker. + Uses base port 8100 and increments by worker number. + """ + worker_info = get_worker_info() + return 8100 + (worker_info.worker_number or 0) diff --git a/test/helpers/constants.py b/test/helpers/constants.py index 9f453add8..f2cff27db 100644 --- a/test/helpers/constants.py +++ b/test/helpers/constants.py @@ -1 +1,3 @@ -SERVER_URL_BASE = 'http://127.0.0.1:4723' +import os + +SERVER_URL_BASE = f'http://{os.getenv("APPIUM_TEST_SERVER_HOST", "127.0.0.1")}:{os.getenv("APPIUM_TEST_SERVER_PORT", "4723")}' diff --git a/test/unit/webdriver/appium_service_test.py b/test/unit/webdriver/appium_service_test.py index 763a6a374..784c6e549 100644 --- a/test/unit/webdriver/appium_service_test.py +++ b/test/unit/webdriver/appium_service_test.py @@ -15,6 +15,6 @@ from appium.webdriver.appium_service import AppiumService -class TestAppiumService(object): +class TestAppiumService: def test_get_instance(self): assert AppiumService() diff --git a/test/unit/webdriver/context_test.py b/test/unit/webdriver/context_test.py index 80c2c0f78..b83dd82d4 100644 --- a/test/unit/webdriver/context_test.py +++ b/test/unit/webdriver/context_test.py @@ -17,7 +17,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverContext(object): +class TestWebDriverContext: @httpretty.activate def test_current_contexts(self): driver = android_w3c_driver() diff --git a/test/unit/webdriver/device/activities_test.py b/test/unit/webdriver/device/activities_test.py index 2374ba6cc..15df9b783 100644 --- a/test/unit/webdriver/device/activities_test.py +++ b/test/unit/webdriver/device/activities_test.py @@ -17,15 +17,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command -class TestWebDriverActivities(object): +class TestWebDriverActivities: @httpretty.activate def test_current_activity(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.GET, - appium_command('/session/1234567890/appium/device/current_activity'), - body='{"value": ".ExampleActivity"}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -36,11 +31,6 @@ def test_current_activity(self): @httpretty.activate def test_wait_activity(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.GET, - appium_command('/session/1234567890/appium/device/current_activity'), - body='{"value": ".ExampleActivity"}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), diff --git a/test/unit/webdriver/device/clipboard_test.py b/test/unit/webdriver/device/clipboard_test.py index 7e21797a0..d5a33a2ce 100644 --- a/test/unit/webdriver/device/clipboard_test.py +++ b/test/unit/webdriver/device/clipboard_test.py @@ -18,13 +18,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body, ios_w3c_driver -class TestWebDriverClipboard(object): +class TestWebDriverClipboard: @httpretty.activate def test_set_clipboard_with_url(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/set_clipboard'), body='{"value": ""}' - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -40,9 +37,6 @@ def test_set_clipboard_with_url(self): @httpretty.activate def test_set_clipboard_text(self): driver = ios_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/set_clipboard'), body='{"value": ""}' - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), diff --git a/test/unit/webdriver/device/common_test.py b/test/unit/webdriver/device/common_test.py index 43b069a08..465349029 100644 --- a/test/unit/webdriver/device/common_test.py +++ b/test/unit/webdriver/device/common_test.py @@ -18,7 +18,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverCommon(object): +class TestWebDriverCommon: @httpretty.activate def test_open_notifications(self): driver = android_w3c_driver() @@ -29,14 +29,10 @@ def test_open_notifications(self): @httpretty.activate def test_current_package(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.GET, - appium_command('/session/1234567890/appium/device/current_package'), - body='{"value": ".ExamplePackage"}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ".ExamplePackage"}', ) assert driver.current_package == '.ExamplePackage' + assert {'args': [], 'script': 'mobile: getCurrentPackage'} == get_httpretty_request_body(httpretty.last_request()) diff --git a/test/unit/webdriver/device/device_time_test.py b/test/unit/webdriver/device/device_time_test.py index 8c6f5e0b9..98d01336f 100644 --- a/test/unit/webdriver/device/device_time_test.py +++ b/test/unit/webdriver/device/device_time_test.py @@ -17,15 +17,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverDeviceTime(object): +class TestWebDriverDeviceTime: @httpretty.activate def test_device_time(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.GET, - appium_command('/session/1234567890/appium/device/system_time'), - body='{"value": "2019-01-05T14:46:44+09:00"}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -36,11 +31,6 @@ def test_device_time(self): @httpretty.activate def test_get_device_time(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.GET, - appium_command('/session/1234567890/appium/device/system_time'), - body='{"value": "2019-01-05T14:46:44+09:00"}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -51,11 +41,6 @@ def test_get_device_time(self): @httpretty.activate def test_get_formatted_device_time(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/system_time'), - body='{"value": "2019-01-08"}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -64,4 +49,5 @@ def test_get_formatted_device_time(self): assert driver.get_device_time('YYYY-MM-DD') == '2019-01-08' d = get_httpretty_request_body(httpretty.last_request()) - assert d.get('format', d['args'][0]['format']) == 'YYYY-MM-DD' + assert d['script'] == 'mobile: getDeviceTime' + assert d['args'][0]['format'] == 'YYYY-MM-DD' diff --git a/test/unit/webdriver/device/display_test.py b/test/unit/webdriver/device/display_test.py index bce0b4e43..cc93c86a6 100644 --- a/test/unit/webdriver/device/display_test.py +++ b/test/unit/webdriver/device/display_test.py @@ -17,12 +17,9 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command -class TestWebDriverDisplay(object): +class TestWebDriverDisplay: @httpretty.activate def test_get_display_density(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.GET, appium_command('/session/1234567890/appium/device/display_density'), body='{"value": 560}' - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": 560}') assert driver.get_display_density() == 560 diff --git a/test/unit/webdriver/device/fingerprint_test.py b/test/unit/webdriver/device/fingerprint_test.py index e6facf86d..93b027842 100644 --- a/test/unit/webdriver/device/fingerprint_test.py +++ b/test/unit/webdriver/device/fingerprint_test.py @@ -18,15 +18,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverFingerprint(object): +class TestWebDriverFingerprint: @httpretty.activate def test_finger_print(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/finger_print'), - # body is None - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -36,4 +31,5 @@ def test_finger_print(self): assert isinstance(driver.finger_print(1), WebDriver) d = get_httpretty_request_body(httpretty.last_request()) - assert d.get('fingerprintId', d['args'][0]['fingerprintId']) == 1 + assert d['script'] == 'mobile: fingerprint' + assert d['args'][0]['fingerprintId'] == 1 diff --git a/test/unit/webdriver/device/gsm_test.py b/test/unit/webdriver/device/gsm_test.py index cd776a94a..b40f2df5a 100644 --- a/test/unit/webdriver/device/gsm_test.py +++ b/test/unit/webdriver/device/gsm_test.py @@ -19,7 +19,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriveGsm(object): +class TestWebDriveGsm: @httpretty.activate def test_make_gsm_call(self): driver = android_w3c_driver() diff --git a/test/unit/webdriver/device/keyboard_test.py b/test/unit/webdriver/device/keyboard_test.py index 526f1826f..33f31a535 100644 --- a/test/unit/webdriver/device/keyboard_test.py +++ b/test/unit/webdriver/device/keyboard_test.py @@ -14,85 +14,75 @@ import httpretty +from appium.webdriver.extensions.android.nativekey import AndroidKeyMetastate from appium.webdriver.webdriver import WebDriver from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body, ios_w3c_driver -class TestWebDriverKeyboardAndroid(object): +class TestWebDriverKeyboardAndroid: @httpretty.activate def test_hide_keyboard(self): driver = android_w3c_driver() - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/appium/device/hide_keyboard')) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.hide_keyboard(), WebDriver) @httpretty.activate def test_press_keycode(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/press_keycode'), body='{"value": "86"}' - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": "86"}') driver.press_keycode(86) d = get_httpretty_request_body((httpretty.last_request())) - assert d.get('keycode', d['args'][0]['keycode']) == 86 + assert d['script'] == 'mobile: pressKey' + assert d['args'][0]['keycode'] == 86 @httpretty.activate def test_long_press_keycode(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/long_press_keycode'), - body='{"value": "86"}', - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": "86"}') driver.long_press_keycode(86) d = get_httpretty_request_body((httpretty.last_request())) - assert d.get('keycode', d['args'][0]['keycode']) == 86 + assert d['script'] == 'mobile: pressKey' + assert d['args'][0]['keycode'] == 86 + assert d['args'][0]['isLongPress'] is True @httpretty.activate def test_keyevent(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/keyevent'), body='{keycode: 86}' - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": "86"}') assert isinstance(driver.keyevent(86), WebDriver) @httpretty.activate def test_press_keycode_with_flags(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/press_keycode'), - body='{keycode: 86, metastate: 2097153, flags: 44}', - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) # metastate is META_SHIFT_ON and META_NUM_LOCK_ON # flags is CANCELFLAG_CANCELEDED, FLAG_KEEP_TOUCH_MODE, FLAG_FROM_SYSTEM assert isinstance( - driver.press_keycode(86, metastate=0x00000001 | 0x00200000, flags=0x20 | 0x00000004 | 0x00000008), + driver.press_keycode( + 86, + metastate=AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON, + flags=0x20 | 0x00000004 | 0x00000008, + ), WebDriver, ) @httpretty.activate def test_long_press_keycode_with_flags(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/long_press_keycode'), - body='{keycode: 86, metastate: 2097153, flags: 44}', - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) # metastate is META_SHIFT_ON and META_NUM_LOCK_ON # flags is CANCELFLAG_CANCELEDED, FLAG_KEEP_TOUCH_MODE, FLAG_FROM_SYSTEM assert isinstance( - driver.long_press_keycode(86, metastate=0x00000001 | 0x00200000, flags=0x20 | 0x00000004 | 0x00000008), + driver.long_press_keycode( + 86, + metastate=AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON, + flags=0x20 | 0x00000004 | 0x00000008, + ), WebDriver, ) -class TestWebDriverKeyboardIOS(object): +class TestWebDriverKeyboardIOS: @httpretty.activate def test_hide_keyboard(self): driver = ios_w3c_driver() diff --git a/test/unit/webdriver/device/location_test.py b/test/unit/webdriver/device/location_test.py index fb0112bc5..7fd423e3a 100644 --- a/test/unit/webdriver/device/location_test.py +++ b/test/unit/webdriver/device/location_test.py @@ -20,14 +20,16 @@ FLT_EPSILON = 1e-9 -class TestWebDriverLocation(object): +class TestWebDriverLocation: @httpretty.activate def test_toggle_location_services(self): driver = android_w3c_driver() - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/appium/device/toggle_location_services')) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) assert isinstance(driver.toggle_location_services(), WebDriver) + d = get_httpretty_request_body(httpretty.last_request()) + assert d['script'] == 'mobile: toggleGps' + @httpretty.activate def test_set_location_float(self): driver = android_w3c_driver() diff --git a/test/unit/webdriver/device/lock_test.py b/test/unit/webdriver/device/lock_test.py index b54698543..1cd89c41a 100644 --- a/test/unit/webdriver/device/lock_test.py +++ b/test/unit/webdriver/device/lock_test.py @@ -18,98 +18,78 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body, ios_w3c_driver -class TestWebDriverLockAndroid(object): +class TestWebDriverLockAndroid: @httpretty.activate def test_lock(self): driver = android_w3c_driver() - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/appium/device/lock'), body='{"value": ""}') httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') driver.lock(1) d = get_httpretty_request_body(httpretty.last_request()) - assert d.get('seconds', d['args'][0]['seconds']) == 1 + assert d['script'] == 'mobile: lock' + assert d['args'][0]['seconds'] == 1 @httpretty.activate def test_lock_no_args(self): driver = android_w3c_driver() - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/appium/device/lock'), body='{"value": ""}') httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') driver.lock() @httpretty.activate def test_islocked_false(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/is_locked'), body='{"value": false}' - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": false}') assert driver.is_locked() is False @httpretty.activate def test_islocked_true(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/is_locked'), body='{"value": true}' - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": true}') assert driver.is_locked() is True @httpretty.activate def test_unlock(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/unlock'), - ) - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) + httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": true}') assert isinstance(driver.unlock(), WebDriver) + assert get_httpretty_request_body(httpretty.last_request())['script'] == 'mobile: unlock' -class TestWebDriverLockIOS(object): +class TestWebDriverLockIOS: @httpretty.activate def test_lock(self): driver = ios_w3c_driver() - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/appium/device/lock'), body='{"value": ""}') httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') driver.lock(1) d = get_httpretty_request_body(httpretty.last_request()) - assert d.get('seconds', d['args'][0]['seconds']) == 1 + assert d['script'] == 'mobile: lock' + assert d['args'][0]['seconds'] == 1 @httpretty.activate def test_lock_no_args(self): driver = ios_w3c_driver() - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/appium/device/lock'), body='{"value": ""}') httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": ""}') driver.lock() @httpretty.activate def test_islocked_false(self): driver = ios_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/is_locked'), body='{"value": false}' - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": false}') assert driver.is_locked() is False @httpretty.activate def test_islocked_true(self): driver = ios_w3c_driver() - httpretty.register_uri( - httpretty.POST, appium_command('/session/1234567890/appium/device/is_locked'), body='{"value": true}' - ) httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": true}') assert driver.is_locked() is True @httpretty.activate def test_unlock(self): driver = ios_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/unlock'), - ) - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync')) + httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": true}') assert isinstance(driver.unlock(), WebDriver) + assert get_httpretty_request_body(httpretty.last_request())['script'] == 'mobile: unlock' @httpretty.activate def test_touch_id(self): diff --git a/test/unit/webdriver/device/power_test.py b/test/unit/webdriver/device/power_test.py index 2d87a8d4c..ea5fe1dc7 100644 --- a/test/unit/webdriver/device/power_test.py +++ b/test/unit/webdriver/device/power_test.py @@ -19,14 +19,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverPower(object): +class TestWebDriverPower: @httpretty.activate def test_set_power_capacity(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/power_capacity'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -34,15 +30,12 @@ def test_set_power_capacity(self): assert isinstance(driver.set_power_capacity(50), WebDriver) d = get_httpretty_request_body(httpretty.last_request()) + assert d['script'] == 'mobile: powerCapacity' assert d['args'][0]['percent'] == 50 @httpretty.activate def test_set_power_ac(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/power_ac'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -50,4 +43,5 @@ def test_set_power_ac(self): assert isinstance(driver.set_power_ac(Power.AC_ON), WebDriver) d = get_httpretty_request_body(httpretty.last_request()) + assert d['script'] == 'mobile: powerAC' assert d['args'][0]['state'] == Power.AC_ON diff --git a/test/unit/webdriver/device/remote_fs_test.py b/test/unit/webdriver/device/remote_fs_test.py index 4de3a85fe..f1fca0df5 100644 --- a/test/unit/webdriver/device/remote_fs_test.py +++ b/test/unit/webdriver/device/remote_fs_test.py @@ -22,14 +22,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverRemoteFs(object): +class TestWebDriverRemoteFs: @httpretty.activate def test_push_file(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/push_file'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -40,16 +36,13 @@ def test_push_file(self): assert isinstance(driver.push_file(dest_path, data), WebDriver) d = get_httpretty_request_body(httpretty.last_request()) - assert d.get('path', d['args'][0]['remotePath']) == dest_path - assert d.get('data', d['args'][0]['payload']) == str(data) + assert d['script'] == 'mobile: pushFile' + assert d['args'][0]['remotePath'] == dest_path + assert d['args'][0]['payload'] == str(data) @httpretty.activate def test_push_file_invalid_arg_exception_without_src_path_and_base64data(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/push_file'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -62,14 +55,6 @@ def test_push_file_invalid_arg_exception_without_src_path_and_base64data(self): @httpretty.activate def test_push_file_invalid_arg_exception_with_src_file_not_found(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/push_file'), - ) - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/push_file'), - ) dest_path = '/dest_path/to/file.txt' src_path = '/src_path/to/file.txt' @@ -79,11 +64,6 @@ def test_push_file_invalid_arg_exception_with_src_file_not_found(self): @httpretty.activate def test_pull_file(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/pull_file'), - body='{"value": "SGVsbG9Xb3JsZA=="}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -94,16 +74,12 @@ def test_pull_file(self): assert driver.pull_file(dest_path) == str(base64.b64encode(bytes('HelloWorld', 'utf-8')).decode('utf-8')) d = get_httpretty_request_body(httpretty.last_request()) - assert d.get('path', d['args'][0]['remotePath']) == dest_path + assert d['script'] == 'mobile: pullFile' + assert d['args'][0]['remotePath'] == dest_path @httpretty.activate def test_pull_folder(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/pull_folder'), - body='{"value": "base64EncodedZippedFolderData"}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -114,4 +90,5 @@ def test_pull_folder(self): assert driver.pull_folder(dest_path) == 'base64EncodedZippedFolderData' d = get_httpretty_request_body(httpretty.last_request()) - assert d.get('path', d['args'][0]['remotePath']) == dest_path + assert d['script'] == 'mobile: pullFolder' + assert d['args'][0]['remotePath'] == dest_path diff --git a/test/unit/webdriver/device/shake_test.py b/test/unit/webdriver/device/shake_test.py index 0371852f1..8c796255a 100644 --- a/test/unit/webdriver/device/shake_test.py +++ b/test/unit/webdriver/device/shake_test.py @@ -19,14 +19,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command -class TestWebDriverShake(object): +class TestWebDriverShake: @httpretty.activate def test_shake(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/shake'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), diff --git a/test/unit/webdriver/device/sms_test.py b/test/unit/webdriver/device/sms_test.py index 1323f50c4..a7200dca0 100644 --- a/test/unit/webdriver/device/sms_test.py +++ b/test/unit/webdriver/device/sms_test.py @@ -18,14 +18,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverSms(object): +class TestWebDriverSms: @httpretty.activate def test_send_sms(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/send_sms'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -33,5 +29,6 @@ def test_send_sms(self): assert isinstance(driver.send_sms('555-123-4567', 'Hey lol'), WebDriver) d = get_httpretty_request_body(httpretty.last_request()) + assert d['script'] == 'mobile: sendSms' assert d['args'][0]['phoneNumber'] == '555-123-4567' assert d['args'][0]['message'] == 'Hey lol' diff --git a/test/unit/webdriver/device/system_bars_test.py b/test/unit/webdriver/device/system_bars_test.py index 79e7c680c..3592c0059 100644 --- a/test/unit/webdriver/device/system_bars_test.py +++ b/test/unit/webdriver/device/system_bars_test.py @@ -17,7 +17,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command -class TestWebDriverSystemBars(object): +class TestWebDriverSystemBars: @httpretty.activate def test_get_system_bars(self): driver = android_w3c_driver() @@ -26,11 +26,6 @@ def test_get_system_bars(self): {"visible": true, "x": 0, "y": 0, "width": 1080, "height": 1920}, "navigationBar": {"visible": true, "x": 0, "y": 0, "width": 1080, "height": 126}}}""" - httpretty.register_uri( - httpretty.GET, - appium_command('/session/1234567890/appium/device/system_bars'), - body=body, - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), diff --git a/test/unit/webdriver/execute_driver_test.py b/test/unit/webdriver/execute_driver_test.py index 250b8cc84..65cdbbd2b 100644 --- a/test/unit/webdriver/execute_driver_test.py +++ b/test/unit/webdriver/execute_driver_test.py @@ -19,7 +19,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverExecuteDriver(object): +class TestWebDriverExecuteDriver: @httpretty.activate def test_batch(self): driver = android_w3c_driver() diff --git a/test/unit/webdriver/flutter_integration/flutter_actions_test.py b/test/unit/webdriver/flutter_integration/flutter_actions_test.py index 50a42e599..8c54a357c 100644 --- a/test/unit/webdriver/flutter_integration/flutter_actions_test.py +++ b/test/unit/webdriver/flutter_integration/flutter_actions_test.py @@ -24,7 +24,7 @@ from test.unit.helper.test_helper import appium_command, flutter_w3c_driver, get_httpretty_request_body -class TestFlutterActions(object): +class TestFlutterActions: @httpretty.activate def test_double_click(self): driver = flutter_w3c_driver() diff --git a/test/unit/webdriver/flutter_integration/flutter_search_context_test.py b/test/unit/webdriver/flutter_integration/flutter_search_context_test.py index 36e378437..d25c6c5cd 100644 --- a/test/unit/webdriver/flutter_integration/flutter_search_context_test.py +++ b/test/unit/webdriver/flutter_integration/flutter_search_context_test.py @@ -18,7 +18,7 @@ from test.unit.helper.test_helper import appium_command, flutter_w3c_driver, get_httpretty_request_body -class TestFlutterSearchContext(object): +class TestFlutterSearchContext: @httpretty.activate def test_find_element_by_flutter_key(self): driver = flutter_w3c_driver() diff --git a/test/unit/webdriver/flutter_integration/flutter_waits_test.py b/test/unit/webdriver/flutter_integration/flutter_waits_test.py index 62f9f7c1c..a0d5669d4 100644 --- a/test/unit/webdriver/flutter_integration/flutter_waits_test.py +++ b/test/unit/webdriver/flutter_integration/flutter_waits_test.py @@ -20,7 +20,7 @@ from test.unit.helper.test_helper import appium_command, flutter_w3c_driver, get_httpretty_request_body -class TestFlutterWaits(object): +class TestFlutterWaits: @httpretty.activate def test_wait_for_visible_with_finder(self): driver = flutter_w3c_driver() diff --git a/test/unit/webdriver/log_events_test.py b/test/unit/webdriver/log_events_test.py index 14d41442e..244aa8223 100644 --- a/test/unit/webdriver/log_events_test.py +++ b/test/unit/webdriver/log_events_test.py @@ -20,7 +20,7 @@ from test.unit.helper.test_helper import appium_command, get_httpretty_request_body, ios_w3c_driver -class TestWebDriverLogEvents(object): +class TestWebDriverLogEvents: @httpretty.activate def test_get_events(self): driver = ios_w3c_driver() diff --git a/test/unit/webdriver/nativekey_test.py b/test/unit/webdriver/nativekey_test.py index 733f6159b..ba38abe98 100644 --- a/test/unit/webdriver/nativekey_test.py +++ b/test/unit/webdriver/nativekey_test.py @@ -13,7 +13,10 @@ # limitations under the License. -from appium.webdriver.extensions.android.nativekey import AndroidKey +from appium.webdriver.extensions.android.nativekey import ( + AndroidKey, + AndroidKeyMetastate, +) class TestAndroidKey: @@ -23,6 +26,12 @@ def test_has_some_codes(self): assert AndroidKey.CAMERA == 27 assert AndroidKey.SPACE == 62 + def test_has_some_metastates(self): + assert AndroidKeyMetastate.NONE == 0 + assert AndroidKeyMetastate.META_SHIFT_ON == 0x00000001 + assert AndroidKeyMetastate.META_NUM_LOCK_ON == 0x00200000 + assert (AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON) == 0x00000001 | 0x00200000 + def test_is_gamepad_key(self): assert AndroidKey.is_gamepad_button(AndroidKey.BUTTON_8) assert not AndroidKey.is_gamepad_button(250) diff --git a/test/unit/webdriver/network_test.py b/test/unit/webdriver/network_test.py index a9cf7ea9e..cc1938dd3 100644 --- a/test/unit/webdriver/network_test.py +++ b/test/unit/webdriver/network_test.py @@ -20,11 +20,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverNetwork(object): +class TestWebDriverNetwork: @httpretty.activate def test_network_connection(self): driver = android_w3c_driver() - httpretty.register_uri(httpretty.GET, appium_command('/session/1234567890/network_connection'), body='{"value": 2}') httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -35,24 +34,20 @@ def test_network_connection(self): @httpretty.activate def test_set_network_connection(self): driver = android_w3c_driver() - httpretty.register_uri(httpretty.POST, appium_command('/session/1234567890/network_connection'), body='{"value": ""}') httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), body='{"value": {"wifi": true, "data": false, "airplaneMode": false}}', ) - driver.set_network_connection(2) + assert driver.set_network_connection(2) == 2 - d = get_httpretty_request_body(httpretty.last_request()) + d = get_httpretty_request_body(httpretty.latest_requests()[-4]) + assert d['script'] == 'mobile: setConnectivity' assert d['args'][0]['wifi'] is True @httpretty.activate def test_set_network_speed(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/network_speed'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -65,10 +60,6 @@ def test_set_network_speed(self): @httpretty.activate def test_toggle_wifi(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/device/toggle_wifi'), - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), diff --git a/test/unit/webdriver/performance_test.py b/test/unit/webdriver/performance_test.py index d4534c903..c21f720ec 100644 --- a/test/unit/webdriver/performance_test.py +++ b/test/unit/webdriver/performance_test.py @@ -17,15 +17,10 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverPerformance(object): +class TestWebDriverPerformance: @httpretty.activate def test_get_performance_data(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/getPerformanceData'), - body='{"value": [["user", "kernel"], ["2.5", "1.3"]]}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), @@ -34,17 +29,13 @@ def test_get_performance_data(self): assert driver.get_performance_data('my.app.package', 'cpuinfo', 5) == [['user', 'kernel'], ['2.5', '1.3']] d = get_httpretty_request_body(httpretty.last_request()) + assert d['script'] == 'mobile: getPerformanceData' assert d['args'][0]['packageName'] == 'my.app.package' assert d['args'][0]['dataType'] == 'cpuinfo' @httpretty.activate def test_get_performance_data_types(self): driver = android_w3c_driver() - httpretty.register_uri( - httpretty.POST, - appium_command('/session/1234567890/appium/performanceData/types'), - body='{"value": ["cpuinfo", "memoryinfo", "batteryinfo", "networkinfo"]}', - ) httpretty.register_uri( httpretty.POST, appium_command('/session/1234567890/execute/sync'), diff --git a/test/unit/webdriver/screen_record_test.py b/test/unit/webdriver/screen_record_test.py index da470cebf..a8ddee1b2 100644 --- a/test/unit/webdriver/screen_record_test.py +++ b/test/unit/webdriver/screen_record_test.py @@ -12,7 +12,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body, ios_w3c_driver -class TestWebDriverScreenRecordAndroid(object): +class TestWebDriverScreenRecordAndroid: @httpretty.activate def test_start_recording_screen(self): driver = android_w3c_driver() @@ -43,7 +43,7 @@ def test_stop_recording_screen(self): assert 'password' not in d['options'].keys() -class TestWebDriverScreenRecordIOS(object): +class TestWebDriverScreenRecordIOS: @httpretty.activate def test_start_recording_screen(self): driver = ios_w3c_driver() diff --git a/test/unit/webdriver/search_context/android_test.py b/test/unit/webdriver/search_context/android_test.py index 879d78f53..cab932f22 100644 --- a/test/unit/webdriver/search_context/android_test.py +++ b/test/unit/webdriver/search_context/android_test.py @@ -21,7 +21,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverAndroidSearchContext(object): +class TestWebDriverAndroidSearchContext: @httpretty.activate def test_find_element_by_id(self): driver = android_w3c_driver() diff --git a/test/unit/webdriver/search_context/ios_test.py b/test/unit/webdriver/search_context/ios_test.py index d6b288a41..fece30ac2 100644 --- a/test/unit/webdriver/search_context/ios_test.py +++ b/test/unit/webdriver/search_context/ios_test.py @@ -19,7 +19,7 @@ from test.unit.helper.test_helper import appium_command, get_httpretty_request_body, ios_w3c_driver -class TestWebDriverIOSSearchContext(object): +class TestWebDriverIOSSearchContext: @httpretty.activate def test_find_element_by_ios_predicate(self): driver = ios_w3c_driver() diff --git a/test/unit/webdriver/settings_test.py b/test/unit/webdriver/settings_test.py index de9a0e00c..da14fe886 100644 --- a/test/unit/webdriver/settings_test.py +++ b/test/unit/webdriver/settings_test.py @@ -18,7 +18,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebDriverSettings(object): +class TestWebDriverSettings: @httpretty.activate def test_get_settings_bool(self): driver = android_w3c_driver() diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index 443885d54..17db27afc 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -472,7 +472,7 @@ def __init__(self, command_executor, options=None): ) -class TestSubModuleWebDriver(object): +class TestSubModuleWebDriver: def android_w3c_driver(self, driver_class): response_body_json = json.dumps( { diff --git a/test/unit/webdriver/webelement_test.py b/test/unit/webdriver/webelement_test.py index 23268c3ac..a37f229a4 100644 --- a/test/unit/webdriver/webelement_test.py +++ b/test/unit/webdriver/webelement_test.py @@ -21,7 +21,7 @@ from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body -class TestWebElement(object): +class TestWebElement: @httpretty.activate def test_status(self): driver = android_w3c_driver() diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 223cf5094..000000000 --- a/tox.ini +++ /dev/null @@ -1,15 +0,0 @@ -[tox] -skipsdist = True -envlist = - py38, - py39, - py311 - -[testenv] -deps = - pipenv -commands = - pipenv lock --clear - pipenv install --dev - ./ci.sh -allowlist_externals = ./ci.sh diff --git a/uv.lock b/uv.lock new file mode 100644 index 000000000..9215bd800 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1842 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.15'", + "python_full_version >= '3.11' and python_full_version < '3.15'", + "python_full_version < '3.11'", +] + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "appium-python-client" +version = "5.3.1" +source = { editable = "." } +dependencies = [ + { name = "selenium" }, + { name = "typing-extensions" }, +] + +[package.dev-dependencies] +dev = [ + { name = "httpretty" }, + { name = "mock" }, + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-xdist" }, + { name = "python-dateutil" }, + { name = "python-semantic-release" }, + { name = "ruff" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-rtd-theme" }, + { name = "sphinxcontrib-apidoc" }, + { name = "types-python-dateutil" }, +] + +[package.metadata] +requires-dist = [ + { name = "selenium", specifier = ">=4.26,<5.0" }, + { name = "typing-extensions", specifier = "~=4.13" }, +] + +[package.metadata.requires-dev] +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 = "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 = "sphinx", specifier = ">=4.0,<9.0" }, + { name = "sphinx-rtd-theme", specifier = "~=3.0" }, + { name = "sphinxcontrib-apidoc", specifier = "~=0.6" }, + { name = "types-python-dateutil", specifier = "~=2.9" }, +] + +[[package]] +name = "ast-serialize" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/ad/0d70a3a2d6e01968d985415259e8ec7ad3f777903f9b1c1f3c8c44642c60/ast_serialize-0.6.0.tar.gz", hash = "sha256:aadd3ffcf4858c9726bf3515f7b199c7eadbe504f96028e4a87172c0da65a8fe", size = 61489, upload-time = "2026-06-30T20:02:55.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/12/3e5f575f156555547c250a8b0d1347517a3a20fc7f4492e9703a69d4f45e/ast_serialize-0.6.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:a7520b672827885bafeae7501f684d14d47d17e5f45256f9df547686cca52264", size = 1177640, upload-time = "2026-06-30T20:02:06.708Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a4/921a9e27951627983b0f368859ea00f8330a551dc0bf4c2fdcb11855a98b/ast_serialize-0.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a14191beec7e0c078d2fc1f6edc0aee88bcd4db9f18e1bc9f8052b559c22dddc", size = 1168111, upload-time = "2026-06-30T20:02:08.366Z" }, + { url = "https://files.pythonhosted.org/packages/00/69/950cf404de7b8782cf95e5c1237e25e2aa46177b287f39f9eeddf481fd6f/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32ef62ec34cf6be20ad77d4799556638fbdf187f3ae10698dfb20ef9f2c89516", size = 1227656, upload-time = "2026-06-30T20:02:09.843Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a8/46f8f6a6479d9d2273980957bb091a506c55f5b95d3c029ee58518a78407/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13b7769970a39983b0adf2f38917b1cd3b8946f76df045756c3d741bc689f089", size = 1227706, upload-time = "2026-06-30T20:02:11.367Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b9/9ac415bda0a40e49eab8fea3b2741c19c98bb84d57d62c4cfc6230eb67be/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f7a408601bb3edaefb3bc67a4c01f5235e3253653b6a5729a2ee2382b35341c", size = 1431705, upload-time = "2026-06-30T20:02:12.737Z" }, + { url = "https://files.pythonhosted.org/packages/e5/06/8807115d441444879f7561b5eede5ac18fc80392f11826d61ccf31f503b1/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8670bfa51208a2c0c8d138928e40e998fab158f9200d53bb80c088b5b8eda7b8", size = 1249533, upload-time = "2026-06-30T20:02:14.571Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c0/c2ba82ef9618650357d9421a1fdb27ffec862a7f57e8e2de82a3ccd11e12/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4826809eb8597a8cd59fd924b6d7c285b8969a1e0007e2cb652cab62376270f", size = 1252619, upload-time = "2026-06-30T20:02:16.219Z" }, + { url = "https://files.pythonhosted.org/packages/0f/a7/fa31d52dd4102cede29fb9634e98d214129b2783b4f95528c6dc6a8f6587/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:577a6c189068686869f5f1ddc38363f3ae1808a4753b577266f9202071a7bb66", size = 1242983, upload-time = "2026-06-30T20:02:17.813Z" }, + { url = "https://files.pythonhosted.org/packages/b1/20/ddf742b5ad3c4bafd3466f2265037cfd99bc1b9a5ee46a5d58c90d523242/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:085de7f62dc9cc247eb01e965a362707d1d90b1d89a82c5bf78301a60a3c417b", size = 1296148, upload-time = "2026-06-30T20:02:19.146Z" }, + { url = "https://files.pythonhosted.org/packages/24/cb/9f6f217cce8b3b632c5568b478d195a35e79dce4dbe309438cb89ba6ea4f/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9f8a8b78b13173de6a9ec22111d9be674874cd5bdccda04f14ae5ebc2bef403a", size = 1403826, upload-time = "2026-06-30T20:02:20.696Z" }, + { url = "https://files.pythonhosted.org/packages/2d/f8/9d16d4f0107a183924425cc0e7618d8bf76f96b45afa9ff19f924ed1ad57/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f2ff3baffc3a29c1f15bc9098aa0c09763410262d5e6cef42116f7356c184554", size = 1502943, upload-time = "2026-06-30T20:02:22.034Z" }, + { url = "https://files.pythonhosted.org/packages/80/dd/bbc1c38756350dddf7e24acae1c9482ef42051c267417e019aecc1ed4075/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0067b25fce104eaae5b88383de9ab803faeb671831e14ca698b771b356e2600f", size = 1497632, upload-time = "2026-06-30T20:02:23.517Z" }, + { url = "https://files.pythonhosted.org/packages/42/7e/9daffefcf5b97e6bb4c3e0b3c024c1aee9722f23d3cf7cd2ff80d6fb4a40/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c617417f9cbb0cb144f6283c3cbe0d2e0f01beaf9f608f662b21191058a626ec", size = 1448858, upload-time = "2026-06-30T20:02:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1f/f9baaab81a677ea0af7d2458cac2f94ebcc85958f8a3c15ba9d9e5dab653/ast_serialize-0.6.0-cp314-cp314t-win32.whl", hash = "sha256:5337cb256dcea3df9288205213d1601581536526b8f4da44b6974f1180f3252a", size = 1052600, upload-time = "2026-06-30T20:02:26.263Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1f/41b535866519512d8cf6669cb2cff7823b7672bb6279c0333b4ff89d7d9f/ast_serialize-0.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2d947e45cafc4b09bd7528917fa84c517654a43de173c79785574b7b3068ac24", size = 1095570, upload-time = "2026-06-30T20:02:27.639Z" }, + { url = "https://files.pythonhosted.org/packages/50/64/e472fe3e3a2d33d874b987e8518aedf24562919e3b6161a4fa1797e89c0f/ast_serialize-0.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6e15ec740436e1a0d62de848641abe5f3a2f89a7f94907d534795ac91bbacf14", size = 1067267, upload-time = "2026-06-30T20:02:28.949Z" }, + { url = "https://files.pythonhosted.org/packages/52/19/ac8348ae8711c9b5ae834634f635780cab62a0f5e6f988882e048b89c2ae/ast_serialize-0.6.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:093cb8bb91b720d8523580498d031791bb1bbaa048599c3d21085d380e11a596", size = 1185367, upload-time = "2026-06-30T20:02:30.427Z" }, + { url = "https://files.pythonhosted.org/packages/c1/f6/ec7ec652c51db77c2f61d8573338e13e4704303265ccc658cb4031d9f354/ast_serialize-0.6.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e61580a69faf47e3689795367ed211f2a10fd741478cc0f36a0f128793360aad", size = 1178657, upload-time = "2026-06-30T20:02:31.964Z" }, + { url = "https://files.pythonhosted.org/packages/6f/02/613a7534a41d0122f37d1e0c64aa8ac78bfb831f8c92f6db057a311abb3c/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305802f2ce2a7c4e87835078ea85c58b586ddda8095b92fe2ead9364ae19c80a", size = 1238620, upload-time = "2026-06-30T20:02:33.664Z" }, + { url = "https://files.pythonhosted.org/packages/4d/21/087957bba486242afc52f49b2d9e21c9dad00289356cf9efe67084015a9d/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c7b8b8f0c42f752ea00b2b7d7c090b3f80d9c1c5c75cadf16423790a0cc74081", size = 1236075, upload-time = "2026-06-30T20:02:34.936Z" }, + { url = "https://files.pythonhosted.org/packages/82/04/78128bbb170071c2c72a210a181f1c00e11cc1cec60a8beef747b07f9201/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd5b91b9e6f2356ace3a556963b0cd783b395fbbb0bb17b4defc283415466e77", size = 1441348, upload-time = "2026-06-30T20:02:36.245Z" }, + { url = "https://files.pythonhosted.org/packages/64/64/62fb99d6faf199b4c3e5b08a07136e9a0d7664bb249c6de3670e5b63e9b6/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d6ef91590258ada18909b9caea344dac4de2013906b035473cd674a43f4b790", size = 1258580, upload-time = "2026-06-30T20:02:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/ca/87/b4d6c38e0ccd5e85dc54cecdf933a152c60b28fe5d993a6d8a72fa6d5896/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcbed41e9386059fc0261d602445ede0976c2ecec2939688bcbcb9ed0b6f28b7", size = 1261693, upload-time = "2026-06-30T20:02:39.123Z" }, + { url = "https://files.pythonhosted.org/packages/0e/4b/3676ca2191f39bafb75f93f99b2f429ec464586158fece2165f3572805dc/ast_serialize-0.6.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:cdc4e6f930b9090c2f92c9036ad12ffb8e6e44d4a5ba06f1458a05d60f203f7b", size = 1252517, upload-time = "2026-06-30T20:02:40.511Z" }, + { url = "https://files.pythonhosted.org/packages/f3/58/494ef8c4b4acb2f4a265ac934caf45f792a08fe27d6b853de35ad991941a/ast_serialize-0.6.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:897ac47b5637be41c0c07061c8a912fafa967ef1dc73fa115e4bfa70882a093b", size = 1304843, upload-time = "2026-06-30T20:02:41.961Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f2/13736d920ab3d49bbee80ef1a277dd7b7aaf3b3545efd9d2a8114fe05525/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c4af9a1386166e40ed01464991806f89038a2d89782576c7774876fa77034e32", size = 1413698, upload-time = "2026-06-30T20:02:44.179Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5a/e046f3899e2acba4677d7427b76431443a1aa1a0e583dfb05b55b69d55cf/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:c901adbd750029b9ac4ad3d6aa56853e0ad4875119fbf52b7b8298afc223828b", size = 1512209, upload-time = "2026-06-30T20:02:45.584Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c7/e42aaca7bb2d22a7c06d5a8c7930086c5a334e93d716e6fa5e6647a4515f/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae22a366b752ab4496191525b78b097b5b72d531752e3c1dd7e383a8f2c8a1a", size = 1508464, upload-time = "2026-06-30T20:02:46.942Z" }, + { url = "https://files.pythonhosted.org/packages/95/93/5524a3dc6c3f593de3228ed9cbef73afa047625b7000ec21b7f58e6eb4d4/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4ed29121da8b3fdc291002801a1de0f76248fa07dce89157a5f277842cf6126e", size = 1457164, upload-time = "2026-06-30T20:02:48.294Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c0/36a6ffb4d653cf621427b4c4928671f53ad800c453474de2b82564a44ad9/ast_serialize-0.6.0-cp39-abi3-pyemscripten_2026_0_wasm32.whl", hash = "sha256:b1dac4e09d341c1300ba69cdcbe62867b32a8c75d90db9bf4d083bec3b039f0b", size = 863014, upload-time = "2026-06-30T20:02:49.742Z" }, + { url = "https://files.pythonhosted.org/packages/09/c7/7d5ad8b49e1278e1c2a1e0274bd7850560b3f09313aa00c13bc8d5544792/ast_serialize-0.6.0-cp39-abi3-win32.whl", hash = "sha256:82c312a7844d2fdeb4d5c48bd3d215bf940dafd4704e1a9bcf252a99010a99b1", size = 1063165, upload-time = "2026-06-30T20:02:50.98Z" }, + { url = "https://files.pythonhosted.org/packages/47/ae/6710c14ecb276031cf10249f6adf5a59e2d3fdb3b5183bd59f70524067ee/ast_serialize-0.6.0-cp39-abi3-win_amd64.whl", hash = "sha256:113b58346f9ceb664352032770caca817d4a3c86f611c6088e6ef65ddaa70f0e", size = 1101444, upload-time = "2026-06-30T20:02:52.554Z" }, + { url = "https://files.pythonhosted.org/packages/66/40/c53deb2cd0c9b0fb636d24d9f40924cf2e65028e6b20b10cd5c1eeb2c730/ast_serialize-0.6.0-cp39-abi3-win_arm64.whl", hash = "sha256:ccd132fe8db56f61fe743b1f644d01b8d65b83248a8da506f3132bda86d6ed5e", size = 1072965, upload-time = "2026-06-30T20:02:54.097Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "certifi" +version = "2026.6.17" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, +] + +[[package]] +name = "click-option-group" +version = "0.5.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/ff/d291d66595b30b83d1cb9e314b2c9be7cfc7327d4a0d40a15da2416ea97b/click_option_group-0.5.9.tar.gz", hash = "sha256:f94ed2bc4cf69052e0f29592bd1e771a1789bd7bfc482dd0bc482134aff95823", size = 22222, upload-time = "2025-10-09T09:38:01.474Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/45/54bb2d8d4138964a94bef6e9afe48b0be4705ba66ac442ae7d8a8dc4ffef/click_option_group-0.5.9-py3-none-any.whl", hash = "sha256:ad2599248bd373e2e19bec5407967c3eec1d0d4fc4a5e77b08a0481e75991080", size = 11553, upload-time = "2025-10-09T09:38:00.066Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/9a/3742e58fd04b233df95c012ee9f3dfe04708a5e1d32613bd2d47d4e1be0d/coverage-7.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1fa280b3ad78eea5be86f94f461c04943d942697e0dac889fa18fff8f5f9147", size = 218633, upload-time = "2025-12-28T15:40:10.165Z" }, + { url = "https://files.pythonhosted.org/packages/7e/45/7e6bdc94d89cd7c8017ce735cf50478ddfe765d4fbf0c24d71d30ea33d7a/coverage-7.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c3d8c679607220979434f494b139dfb00131ebf70bb406553d69c1ff01a5c33d", size = 219147, upload-time = "2025-12-28T15:40:12.069Z" }, + { url = "https://files.pythonhosted.org/packages/f7/38/0d6a258625fd7f10773fe94097dc16937a5f0e3e0cdf3adef67d3ac6baef/coverage-7.13.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:339dc63b3eba969067b00f41f15ad161bf2946613156fb131266d8debc8e44d0", size = 245894, upload-time = "2025-12-28T15:40:13.556Z" }, + { url = "https://files.pythonhosted.org/packages/27/58/409d15ea487986994cbd4d06376e9860e9b157cfbfd402b1236770ab8dd2/coverage-7.13.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db622b999ffe49cb891f2fff3b340cdc2f9797d01a0a202a0973ba2562501d90", size = 247721, upload-time = "2025-12-28T15:40:15.37Z" }, + { url = "https://files.pythonhosted.org/packages/da/bf/6e8056a83fd7a96c93341f1ffe10df636dd89f26d5e7b9ca511ce3bcf0df/coverage-7.13.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1443ba9acbb593fa7c1c29e011d7c9761545fe35e7652e85ce7f51a16f7e08d", size = 249585, upload-time = "2025-12-28T15:40:17.226Z" }, + { url = "https://files.pythonhosted.org/packages/f4/15/e1daff723f9f5959acb63cbe35b11203a9df77ee4b95b45fffd38b318390/coverage-7.13.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c832ec92c4499ac463186af72f9ed4d8daec15499b16f0a879b0d1c8e5cf4a3b", size = 246597, upload-time = "2025-12-28T15:40:19.028Z" }, + { url = "https://files.pythonhosted.org/packages/74/a6/1efd31c5433743a6ddbc9d37ac30c196bb07c7eab3d74fbb99b924c93174/coverage-7.13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:562ec27dfa3f311e0db1ba243ec6e5f6ab96b1edfcfc6cf86f28038bc4961ce6", size = 247626, upload-time = "2025-12-28T15:40:20.846Z" }, + { url = "https://files.pythonhosted.org/packages/6d/9f/1609267dd3e749f57fdd66ca6752567d1c13b58a20a809dc409b263d0b5f/coverage-7.13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4de84e71173d4dada2897e5a0e1b7877e5eefbfe0d6a44edee6ce31d9b8ec09e", size = 245629, upload-time = "2025-12-28T15:40:22.397Z" }, + { url = "https://files.pythonhosted.org/packages/e2/f6/6815a220d5ec2466383d7cc36131b9fa6ecbe95c50ec52a631ba733f306a/coverage-7.13.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:a5a68357f686f8c4d527a2dc04f52e669c2fc1cbde38f6f7eb6a0e58cbd17cae", size = 245901, upload-time = "2025-12-28T15:40:23.836Z" }, + { url = "https://files.pythonhosted.org/packages/ac/58/40576554cd12e0872faf6d2c0eb3bc85f71d78427946ddd19ad65201e2c0/coverage-7.13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:77cc258aeb29a3417062758975521eae60af6f79e930d6993555eeac6a8eac29", size = 246505, upload-time = "2025-12-28T15:40:25.421Z" }, + { url = "https://files.pythonhosted.org/packages/3b/77/9233a90253fba576b0eee81707b5781d0e21d97478e5377b226c5b096c0f/coverage-7.13.1-cp310-cp310-win32.whl", hash = "sha256:bb4f8c3c9a9f34423dba193f241f617b08ffc63e27f67159f60ae6baf2dcfe0f", size = 221257, upload-time = "2025-12-28T15:40:27.217Z" }, + { url = "https://files.pythonhosted.org/packages/e0/43/e842ff30c1a0a623ec80db89befb84a3a7aad7bfe44a6ea77d5a3e61fedd/coverage-7.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:c8e2706ceb622bc63bac98ebb10ef5da80ed70fbd8a7999a5076de3afaef0fb1", size = 222191, upload-time = "2025-12-28T15:40:28.916Z" }, + { url = "https://files.pythonhosted.org/packages/b4/9b/77baf488516e9ced25fc215a6f75d803493fc3f6a1a1227ac35697910c2a/coverage-7.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a55d509a1dc5a5b708b5dad3b5334e07a16ad4c2185e27b40e4dba796ab7f88", size = 218755, upload-time = "2025-12-28T15:40:30.812Z" }, + { url = "https://files.pythonhosted.org/packages/d7/cd/7ab01154e6eb79ee2fab76bf4d89e94c6648116557307ee4ebbb85e5c1bf/coverage-7.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d010d080c4888371033baab27e47c9df7d6fb28d0b7b7adf85a4a49be9298b3", size = 219257, upload-time = "2025-12-28T15:40:32.333Z" }, + { url = "https://files.pythonhosted.org/packages/01/d5/b11ef7863ffbbdb509da0023fad1e9eda1c0eaea61a6d2ea5b17d4ac706e/coverage-7.13.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d938b4a840fb1523b9dfbbb454f652967f18e197569c32266d4d13f37244c3d9", size = 249657, upload-time = "2025-12-28T15:40:34.1Z" }, + { url = "https://files.pythonhosted.org/packages/f7/7c/347280982982383621d29b8c544cf497ae07ac41e44b1ca4903024131f55/coverage-7.13.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf100a3288f9bb7f919b87eb84f87101e197535b9bd0e2c2b5b3179633324fee", size = 251581, upload-time = "2025-12-28T15:40:36.131Z" }, + { url = "https://files.pythonhosted.org/packages/82/f6/ebcfed11036ade4c0d75fa4453a6282bdd225bc073862766eec184a4c643/coverage-7.13.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef6688db9bf91ba111ae734ba6ef1a063304a881749726e0d3575f5c10a9facf", size = 253691, upload-time = "2025-12-28T15:40:37.626Z" }, + { url = "https://files.pythonhosted.org/packages/02/92/af8f5582787f5d1a8b130b2dcba785fa5e9a7a8e121a0bb2220a6fdbdb8a/coverage-7.13.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b609fc9cdbd1f02e51f67f51e5aee60a841ef58a68d00d5ee2c0faf357481a3", size = 249799, upload-time = "2025-12-28T15:40:39.47Z" }, + { url = "https://files.pythonhosted.org/packages/24/aa/0e39a2a3b16eebf7f193863323edbff38b6daba711abaaf807d4290cf61a/coverage-7.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c43257717611ff5e9a1d79dce8e47566235ebda63328718d9b65dd640bc832ef", size = 251389, upload-time = "2025-12-28T15:40:40.954Z" }, + { url = "https://files.pythonhosted.org/packages/73/46/7f0c13111154dc5b978900c0ccee2e2ca239b910890e674a77f1363d483e/coverage-7.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e09fbecc007f7b6afdfb3b07ce5bd9f8494b6856dd4f577d26c66c391b829851", size = 249450, upload-time = "2025-12-28T15:40:42.489Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ca/e80da6769e8b669ec3695598c58eef7ad98b0e26e66333996aee6316db23/coverage-7.13.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a03a4f3a19a189919c7055098790285cc5c5b0b3976f8d227aea39dbf9f8bfdb", size = 249170, upload-time = "2025-12-28T15:40:44.279Z" }, + { url = "https://files.pythonhosted.org/packages/af/18/9e29baabdec1a8644157f572541079b4658199cfd372a578f84228e860de/coverage-7.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3820778ea1387c2b6a818caec01c63adc5b3750211af6447e8dcfb9b6f08dbba", size = 250081, upload-time = "2025-12-28T15:40:45.748Z" }, + { url = "https://files.pythonhosted.org/packages/00/f8/c3021625a71c3b2f516464d322e41636aea381018319050a8114105872ee/coverage-7.13.1-cp311-cp311-win32.whl", hash = "sha256:ff10896fa55167371960c5908150b434b71c876dfab97b69478f22c8b445ea19", size = 221281, upload-time = "2025-12-28T15:40:47.232Z" }, + { url = "https://files.pythonhosted.org/packages/27/56/c216625f453df6e0559ed666d246fcbaaa93f3aa99eaa5080cea1229aa3d/coverage-7.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:a998cc0aeeea4c6d5622a3754da5a493055d2d95186bad877b0a34ea6e6dbe0a", size = 222215, upload-time = "2025-12-28T15:40:49.19Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9a/be342e76f6e531cae6406dc46af0d350586f24d9b67fdfa6daee02df71af/coverage-7.13.1-cp311-cp311-win_arm64.whl", hash = "sha256:fea07c1a39a22614acb762e3fbbb4011f65eedafcb2948feeef641ac78b4ee5c", size = 220886, upload-time = "2025-12-28T15:40:51.067Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3", size = 218927, upload-time = "2025-12-28T15:40:52.814Z" }, + { url = "https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e", size = 219288, upload-time = "2025-12-28T15:40:54.262Z" }, + { url = "https://files.pythonhosted.org/packages/d0/0a/853a76e03b0f7c4375e2ca025df45c918beb367f3e20a0a8e91967f6e96c/coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c", size = 250786, upload-time = "2025-12-28T15:40:56.059Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62", size = 253543, upload-time = "2025-12-28T15:40:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/96/b2/7f1f0437a5c855f87e17cf5d0dc35920b6440ff2b58b1ba9788c059c26c8/coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968", size = 254635, upload-time = "2025-12-28T15:40:59.443Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d1/73c3fdb8d7d3bddd9473c9c6a2e0682f09fc3dfbcb9c3f36412a7368bcab/coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e", size = 251202, upload-time = "2025-12-28T15:41:01.328Z" }, + { url = "https://files.pythonhosted.org/packages/66/3c/f0edf75dcc152f145d5598329e864bbbe04ab78660fe3e8e395f9fff010f/coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f", size = 252566, upload-time = "2025-12-28T15:41:03.319Z" }, + { url = "https://files.pythonhosted.org/packages/17/b3/e64206d3c5f7dcbceafd14941345a754d3dbc78a823a6ed526e23b9cdaab/coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee", size = 250711, upload-time = "2025-12-28T15:41:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ad/28a3eb970a8ef5b479ee7f0c484a19c34e277479a5b70269dc652b730733/coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf", size = 250278, upload-time = "2025-12-28T15:41:08.285Z" }, + { url = "https://files.pythonhosted.org/packages/54/e3/c8f0f1a93133e3e1291ca76cbb63565bd4b5c5df63b141f539d747fff348/coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c", size = 252154, upload-time = "2025-12-28T15:41:09.969Z" }, + { url = "https://files.pythonhosted.org/packages/d0/bf/9939c5d6859c380e405b19e736321f1c7d402728792f4c752ad1adcce005/coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7", size = 221487, upload-time = "2025-12-28T15:41:11.468Z" }, + { url = "https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6", size = 222299, upload-time = "2025-12-28T15:41:13.386Z" }, + { url = "https://files.pythonhosted.org/packages/10/79/176a11203412c350b3e9578620013af35bcdb79b651eb976f4a4b32044fa/coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c", size = 220941, upload-time = "2025-12-28T15:41:14.975Z" }, + { url = "https://files.pythonhosted.org/packages/a3/a4/e98e689347a1ff1a7f67932ab535cef82eb5e78f32a9e4132e114bbb3a0a/coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78", size = 218951, upload-time = "2025-12-28T15:41:16.653Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/7cbfe2bdc6e2f03d6b240d23dc45fdaf3fd270aaf2d640be77b7f16989ab/coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b", size = 219325, upload-time = "2025-12-28T15:41:18.609Z" }, + { url = "https://files.pythonhosted.org/packages/59/f6/efdabdb4929487baeb7cb2a9f7dac457d9356f6ad1b255be283d58b16316/coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd", size = 250309, upload-time = "2025-12-28T15:41:20.629Z" }, + { url = "https://files.pythonhosted.org/packages/12/da/91a52516e9d5aea87d32d1523f9cdcf7a35a3b298e6be05d6509ba3cfab2/coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992", size = 252907, upload-time = "2025-12-28T15:41:22.257Z" }, + { url = "https://files.pythonhosted.org/packages/75/38/f1ea837e3dc1231e086db1638947e00d264e7e8c41aa8ecacf6e1e0c05f4/coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4", size = 254148, upload-time = "2025-12-28T15:41:23.87Z" }, + { url = "https://files.pythonhosted.org/packages/7f/43/f4f16b881aaa34954ba446318dea6b9ed5405dd725dd8daac2358eda869a/coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a", size = 250515, upload-time = "2025-12-28T15:41:25.437Z" }, + { url = "https://files.pythonhosted.org/packages/84/34/8cba7f00078bd468ea914134e0144263194ce849ec3baad187ffb6203d1c/coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766", size = 252292, upload-time = "2025-12-28T15:41:28.459Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/cffac66c7652d84ee4ac52d3ccb94c015687d3b513f9db04bfcac2ac800d/coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4", size = 250242, upload-time = "2025-12-28T15:41:30.02Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/9a64d462263dde416f3c0067efade7b52b52796f489b1037a95b0dc389c9/coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398", size = 250068, upload-time = "2025-12-28T15:41:32.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/c8/a8994f5fece06db7c4a97c8fc1973684e178599b42e66280dded0524ef00/coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784", size = 251846, upload-time = "2025-12-28T15:41:33.946Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f7/91fa73c4b80305c86598a2d4e54ba22df6bf7d0d97500944af7ef155d9f7/coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461", size = 221512, upload-time = "2025-12-28T15:41:35.519Z" }, + { url = "https://files.pythonhosted.org/packages/45/0b/0768b4231d5a044da8f75e097a8714ae1041246bb765d6b5563bab456735/coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500", size = 222321, upload-time = "2025-12-28T15:41:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b8/bdcb7253b7e85157282450262008f1366aa04663f3e3e4c30436f596c3e2/coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9", size = 220949, upload-time = "2025-12-28T15:41:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/70/52/f2be52cc445ff75ea8397948c96c1b4ee14f7f9086ea62fc929c5ae7b717/coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc", size = 219643, upload-time = "2025-12-28T15:41:41.567Z" }, + { url = "https://files.pythonhosted.org/packages/47/79/c85e378eaa239e2edec0c5523f71542c7793fe3340954eafb0bc3904d32d/coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a", size = 219997, upload-time = "2025-12-28T15:41:43.418Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9b/b1ade8bfb653c0bbce2d6d6e90cc6c254cbb99b7248531cc76253cb4da6d/coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4", size = 261296, upload-time = "2025-12-28T15:41:45.207Z" }, + { url = "https://files.pythonhosted.org/packages/1f/af/ebf91e3e1a2473d523e87e87fd8581e0aa08741b96265730e2d79ce78d8d/coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6", size = 263363, upload-time = "2025-12-28T15:41:47.163Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8b/fb2423526d446596624ac7fde12ea4262e66f86f5120114c3cfd0bb2befa/coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1", size = 265783, upload-time = "2025-12-28T15:41:49.03Z" }, + { url = "https://files.pythonhosted.org/packages/9b/26/ef2adb1e22674913b89f0fe7490ecadcef4a71fa96f5ced90c60ec358789/coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd", size = 260508, upload-time = "2025-12-28T15:41:51.035Z" }, + { url = "https://files.pythonhosted.org/packages/ce/7d/f0f59b3404caf662e7b5346247883887687c074ce67ba453ea08c612b1d5/coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c", size = 263357, upload-time = "2025-12-28T15:41:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b1/29896492b0b1a047604d35d6fa804f12818fa30cdad660763a5f3159e158/coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0", size = 260978, upload-time = "2025-12-28T15:41:54.589Z" }, + { url = "https://files.pythonhosted.org/packages/48/f2/971de1238a62e6f0a4128d37adadc8bb882ee96afbe03ff1570291754629/coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e", size = 259877, upload-time = "2025-12-28T15:41:56.263Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0474efcbb590ff8628830e9aaec5f1831594874360e3251f1fdec31d07a3/coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53", size = 262069, upload-time = "2025-12-28T15:41:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/88/4f/3c159b7953db37a7b44c0eab8a95c37d1aa4257c47b4602c04022d5cb975/coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842", size = 222184, upload-time = "2025-12-28T15:41:59.763Z" }, + { url = "https://files.pythonhosted.org/packages/58/a5/6b57d28f81417f9335774f20679d9d13b9a8fb90cd6160957aa3b54a2379/coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2", size = 223250, upload-time = "2025-12-28T15:42:01.52Z" }, + { url = "https://files.pythonhosted.org/packages/81/7c/160796f3b035acfbb58be80e02e484548595aa67e16a6345e7910ace0a38/coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09", size = 221521, upload-time = "2025-12-28T15:42:03.275Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/ba0e597560c6563fc0adb902fda6526df5d4aa73bb10adf0574d03bd2206/coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894", size = 218996, upload-time = "2025-12-28T15:42:04.978Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8e/764c6e116f4221dc7aa26c4061181ff92edb9c799adae6433d18eeba7a14/coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a", size = 219326, upload-time = "2025-12-28T15:42:06.691Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a6/6130dc6d8da28cdcbb0f2bf8865aeca9b157622f7c0031e48c6cf9a0e591/coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f", size = 250374, upload-time = "2025-12-28T15:42:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/82/2b/783ded568f7cd6b677762f780ad338bf4b4750205860c17c25f7c708995e/coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909", size = 252882, upload-time = "2025-12-28T15:42:10.515Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b2/9808766d082e6a4d59eb0cc881a57fc1600eb2c5882813eefff8254f71b5/coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4", size = 254218, upload-time = "2025-12-28T15:42:12.208Z" }, + { url = "https://files.pythonhosted.org/packages/44/ea/52a985bb447c871cb4d2e376e401116520991b597c85afdde1ea9ef54f2c/coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75", size = 250391, upload-time = "2025-12-28T15:42:14.21Z" }, + { url = "https://files.pythonhosted.org/packages/7f/1d/125b36cc12310718873cfc8209ecfbc1008f14f4f5fa0662aa608e579353/coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9", size = 252239, upload-time = "2025-12-28T15:42:16.292Z" }, + { url = "https://files.pythonhosted.org/packages/6a/16/10c1c164950cade470107f9f14bbac8485f8fb8515f515fca53d337e4a7f/coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465", size = 250196, upload-time = "2025-12-28T15:42:18.54Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c6/cd860fac08780c6fd659732f6ced1b40b79c35977c1356344e44d72ba6c4/coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864", size = 250008, upload-time = "2025-12-28T15:42:20.365Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/a8c58d3d38f82a5711e1e0a67268362af48e1a03df27c03072ac30feefcf/coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9", size = 251671, upload-time = "2025-12-28T15:42:22.114Z" }, + { url = "https://files.pythonhosted.org/packages/f0/bc/fd4c1da651d037a1e3d53e8cb3f8182f4b53271ffa9a95a2e211bacc0349/coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5", size = 221777, upload-time = "2025-12-28T15:42:23.919Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/71acabdc8948464c17e90b5ffd92358579bd0910732c2a1c9537d7536aa6/coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a", size = 222592, upload-time = "2025-12-28T15:42:25.619Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c8/a6fb943081bb0cc926499c7907731a6dc9efc2cbdc76d738c0ab752f1a32/coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0", size = 221169, upload-time = "2025-12-28T15:42:27.629Z" }, + { url = "https://files.pythonhosted.org/packages/16/61/d5b7a0a0e0e40d62e59bc8c7aa1afbd86280d82728ba97f0673b746b78e2/coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a", size = 219730, upload-time = "2025-12-28T15:42:29.306Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2c/8881326445fd071bb49514d1ce97d18a46a980712b51fee84f9ab42845b4/coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6", size = 220001, upload-time = "2025-12-28T15:42:31.319Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d7/50de63af51dfa3a7f91cc37ad8fcc1e244b734232fbc8b9ab0f3c834a5cd/coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673", size = 261370, upload-time = "2025-12-28T15:42:32.992Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2c/d31722f0ec918fd7453b2758312729f645978d212b410cd0f7c2aed88a94/coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5", size = 263485, upload-time = "2025-12-28T15:42:34.759Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7a/2c114fa5c5fc08ba0777e4aec4c97e0b4a1afcb69c75f1f54cff78b073ab/coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d", size = 265890, upload-time = "2025-12-28T15:42:36.517Z" }, + { url = "https://files.pythonhosted.org/packages/65/d9/f0794aa1c74ceabc780fe17f6c338456bbc4e96bd950f2e969f48ac6fb20/coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8", size = 260445, upload-time = "2025-12-28T15:42:38.646Z" }, + { url = "https://files.pythonhosted.org/packages/49/23/184b22a00d9bb97488863ced9454068c79e413cb23f472da6cbddc6cfc52/coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486", size = 263357, upload-time = "2025-12-28T15:42:40.788Z" }, + { url = "https://files.pythonhosted.org/packages/7d/bd/58af54c0c9199ea4190284f389005779d7daf7bf3ce40dcd2d2b2f96da69/coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564", size = 260959, upload-time = "2025-12-28T15:42:42.808Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2a/6839294e8f78a4891bf1df79d69c536880ba2f970d0ff09e7513d6e352e9/coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7", size = 259792, upload-time = "2025-12-28T15:42:44.818Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c3/528674d4623283310ad676c5af7414b9850ab6d55c2300e8aa4b945ec554/coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416", size = 262123, upload-time = "2025-12-28T15:42:47.108Z" }, + { url = "https://files.pythonhosted.org/packages/06/c5/8c0515692fb4c73ac379d8dc09b18eaf0214ecb76ea6e62467ba7a1556ff/coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f", size = 222562, upload-time = "2025-12-28T15:42:49.144Z" }, + { url = "https://files.pythonhosted.org/packages/05/0e/c0a0c4678cb30dac735811db529b321d7e1c9120b79bd728d4f4d6b010e9/coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79", size = 223670, upload-time = "2025-12-28T15:42:51.218Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/b177aa0011f354abf03a8f30a85032686d290fdeed4222b27d36b4372a50/coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4", size = 221707, upload-time = "2025-12-28T15:42:53.034Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "deprecated" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, +] + +[[package]] +name = "dotty-dict" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/ab/88d67f02024700b48cd8232579ad1316aa9df2272c63049c27cc094229d6/dotty_dict-1.3.1.tar.gz", hash = "sha256:4b016e03b8ae265539757a53eba24b9bfda506fb94fbce0bee843c6f05541a15", size = 7699, upload-time = "2022-07-09T18:50:57.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/91/e0d457ee03ec33d79ee2cd8d212debb1bc21dfb99728ae35efdb5832dc22/dotty_dict-1.3.1-py3-none-any.whl", hash = "sha256:5022d234d9922f13aa711b4950372a06a6d64cb6d6db9ba43d0ba133ebfce31f", size = 7014, upload-time = "2022-07-09T18:50:55.058Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, +] + +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, +] + +[[package]] +name = "gitpython" +version = "3.1.54" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/d5/3da0b92033887033f4c27f2dd109a303c4ca62813c7b3bb2511edb4777de/gitpython-3.1.54.tar.gz", hash = "sha256:53f2085e24a2cda300eed7c3fc5f1559ae289634b725e98acaf4791940247aa0", size = 225076, upload-time = "2026-07-22T04:08:51.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/b9/876f442a28df5c068ca69b0122d5c35e65fd2d2fa9992ea5cb5944ea00a6/gitpython-3.1.54-py3-none-any.whl", hash = "sha256:b90d7b3d9bc0238681d24369130826f0dcdb0ceaa45db67cf1d4ffa4c302dedf", size = 216575, upload-time = "2026-07-22T04:08:50.05Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpretty" +version = "1.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/19/850b7ed736319d0c4088581f4fc34f707ef14461947284026664641e16d4/httpretty-1.1.4.tar.gz", hash = "sha256:20de0e5dd5a18292d36d928cc3d6e52f8b2ac73daec40d41eb62dee154933b68", size = 442389, upload-time = "2021-08-16T19:35:31.4Z" } + +[[package]] +name = "identify" +version = "2.6.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360, upload-time = "2026-01-12T18:58:58.201Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202, upload-time = "2026-01-12T18:58:56.627Z" }, +] + +[[package]] +name = "idna" +version = "3.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/77/7b3966d0b9d1d31a36ddf1746926a11dface89a83409bf1483f0237aa758/idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc", size = 199245, upload-time = "2026-05-12T22:45:57.011Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8", size = 72340, upload-time = "2026-05-12T22:45:55.733Z" }, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "librt" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/2f/3908645ddddab7120b46295e541ead308109fa48dbec7d67d7a778870d60/librt-0.13.0.tar.gz", hash = "sha256:1d2a610c14ac0d0750ee0a3ab8548e83155258387891caaca04def4bf7289781", size = 211402, upload-time = "2026-07-08T12:26:29.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/2f/ec5241c38e7fa0fe6c26bfc450e78b9489a6c3c08b394b85d2c10e506975/librt-0.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:34e47058fcc69a313293d6dee94216a4f30c929ae6f2476e58c5ba635aa639d5", size = 148654, upload-time = "2026-07-08T12:24:30.622Z" }, + { url = "https://files.pythonhosted.org/packages/a5/1a/d651e18d3ee7aa2879322368c4f278bb7ecaa6b90caadfdec4ebfa8389f3/librt-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dbdd5b6509d0c2a8fe72cf494c299a61dbd58142a90a4190664ae159e4a7b547", size = 153537, upload-time = "2026-07-08T12:24:31.773Z" }, + { url = "https://files.pythonhosted.org/packages/45/18/10bff2122577246009d9619b6569596daf69b7648812f997ca9ca0426f60/librt-0.13.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e56ea4ee4df77585a6b5c138f6538680886024fa559f5b55bd14b12e98e67b2", size = 494336, upload-time = "2026-07-08T12:24:33.079Z" }, + { url = "https://files.pythonhosted.org/packages/67/69/87dfee871b852970f137fdeae8e2ca356c5ab38e6f21d2a3299535fc3159/librt-0.13.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f1f9cc4d09a46d9cb3c2063ae100629d3f52a6517c3c08c2f4c9828261883929", size = 485393, upload-time = "2026-07-08T12:24:34.324Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d5/625447a8c0441ff5f15f4ac5e1d323fb9d4d256ebfde7a3c8e003f646057/librt-0.13.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f125f5d46b20f89dc5587a55cc416b4ba2a5b2ffda36d048ee120e17598a653a", size = 515382, upload-time = "2026-07-08T12:24:35.575Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d8/1c8c49ea04235960426444deece9092a6b3a9587a850a81bae2335317411/librt-0.13.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2608d3b39f9e0b4a66a130d9150c615cba40a5090d25eeeaa225e0e46de8c0ac", size = 509483, upload-time = "2026-07-08T12:24:36.923Z" }, + { url = "https://files.pythonhosted.org/packages/6f/65/f1760fc48050e215201a03506c32b7270159088d01f64557b53e39e74a45/librt-0.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fd35e95ab5e45c3901d37110263c7db85a961110f5460588fe37f8c131f88a7", size = 532503, upload-time = "2026-07-08T12:24:38.203Z" }, + { url = "https://files.pythonhosted.org/packages/18/1b/793e281dcf494879eff99f642b63ebc9c7c58694a1c2d1e93362a22c7041/librt-0.13.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5f31b0aa13c9b04370d4da6be1ab7779776b3a075cceb6747a39a4be85fe1e40", size = 537027, upload-time = "2026-07-08T12:24:39.34Z" }, + { url = "https://files.pythonhosted.org/packages/69/45/0801bbb40c9eea795d3dd3ce91c4c5f3fe7d42d23ec4be3e8cb283bcc754/librt-0.13.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0b795f5fc70fbbb787ceaf79bb3a0d627bcc33c53de51741755263ec406b775a", size = 517100, upload-time = "2026-07-08T12:24:40.907Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6c/eb5f514f8e29d4924bc0ff4601dd7b4175557e182e7c0721e84cffa39b8a/librt-0.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36b306a623aaad96fe4b378692b54f9c0789fccd833b9851753d5fbf6138cfde", size = 558653, upload-time = "2026-07-08T12:24:42.359Z" }, + { url = "https://files.pythonhosted.org/packages/b4/bf/f140100d1b59fe87ff40b5ecbb4e27924335b189a784e230ee465452f6c2/librt-0.13.0-cp310-cp310-win32.whl", hash = "sha256:a3762e75fcac8c9e4dacaaf438bffd9003e2ca2c531b756f3c0035deefa674c8", size = 104402, upload-time = "2026-07-08T12:24:43.668Z" }, + { url = "https://files.pythonhosted.org/packages/22/7c/57e40fef7cfb61869341cb28bdcefe8a950bebcbecca74a397bae14dce4a/librt-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:d63bae12a8aeb51380be3438e4dc4bd27354d0f8e19166b2f44e3e94d6f552dc", size = 125002, upload-time = "2026-07-08T12:24:44.793Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/a6498964cfeec270c468cffdc118f69c29b412593610d55fa1327ca51ff4/librt-0.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b5a7bbff495baedbd9b916c367d66854008f8f3b575908ded477c499dc60082", size = 148029, upload-time = "2026-07-08T12:24:45.961Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/dc86d1bffd8e0c2818bace29d9f7783cfbb8e0673bf3673b5bbd5bbe0420/librt-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34bc7938b9fdf14fe32a406c19c71faf894c5cee7e7474bd0be2f17200b82d14", size = 153036, upload-time = "2026-07-08T12:24:47.257Z" }, + { url = "https://files.pythonhosted.org/packages/29/3f/b923826660f02f286186cd9303d52bb05ced0a13708edc104dc8480920e3/librt-0.13.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f40e56b61b41be5f7dec938cfeffd660668cf4b5e72c78e7bd671d66b7bc2c79", size = 493062, upload-time = "2026-07-08T12:24:48.483Z" }, + { url = "https://files.pythonhosted.org/packages/88/87/6c0980a9c9b1302cb68d108906697b89eceb55889bb1dcf77c109aa56ca5/librt-0.13.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:9c5d02b89de5acd0379a51ec44a89476fb03df6145442e1c8ecd6bee2f91b176", size = 485510, upload-time = "2026-07-08T12:24:49.727Z" }, + { url = "https://files.pythonhosted.org/packages/32/81/795ae3b9df5dd94079fb807e38191855e023e8c6249014ae6bc3f0d9a490/librt-0.13.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7db9a3ff32ef5f7d1703d93831a3316cdf0b537de6a1cc03cc8fdd09b9194e89", size = 515909, upload-time = "2026-07-08T12:24:51.135Z" }, + { url = "https://files.pythonhosted.org/packages/20/e5/182de15abce8907108a6fdb41487de65beb5099b74dc5841b19b099168db/librt-0.13.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3dbb2a31882456cadc7053378e81ad7ed7693db4ac9f98ab5f81ef034aa8ec9f", size = 508620, upload-time = "2026-07-08T12:24:52.358Z" }, + { url = "https://files.pythonhosted.org/packages/32/03/33978d32db76e1f66377e8f78e42a2ca3c162143331677d1f50bbad36cfb/librt-0.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c6014e3c80f9c1fe268ef8b0e0ef113bac672cc032f2f93866e7ddad4f3e663d", size = 530363, upload-time = "2026-07-08T12:24:53.503Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f5/b291fbd2d00f7d8287bcbf67b5aa0c6afed4bc26cef23e079629c47a2c04/librt-0.13.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:091b60a4d2174fc1ec5c34cdc0b72efb6224753d76b7da61ebeab7a191aec8bd", size = 534209, upload-time = "2026-07-08T12:24:55.138Z" }, + { url = "https://files.pythonhosted.org/packages/3e/03/6f41f17939d191bc21609f220da8509316bc62797f078545fe83be522e78/librt-0.13.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:66cb1138f384a191a6d75f986064841fcfdc0cea98f7bd9c9ab9b38049917588", size = 514254, upload-time = "2026-07-08T12:24:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/af/c2/2e4befa5410a7443019c14abccc94ff619797171f6b72013635fb87f31d7/librt-0.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:17221a7569f8f292aa0014226e48aa25b8c2b08da18088cd230953d0ea0f9cd1", size = 557611, upload-time = "2026-07-08T12:24:57.561Z" }, + { url = "https://files.pythonhosted.org/packages/ab/54/8b69f81448417adbc040a2185f4e2eece1e1994b7dcfaeed4662b30f98a5/librt-0.13.0-cp311-cp311-win32.whl", hash = "sha256:fc67741da44c6eaa90e01eafb586bbba9b51eb5b6ed381ee6f5ae72eb3316d21", size = 104906, upload-time = "2026-07-08T12:24:58.806Z" }, + { url = "https://files.pythonhosted.org/packages/76/5a/f4aaf37b50f2fde12c8c663b83fdd499cdc24f957f19543d7414bfcc9e25/librt-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:cc99dfb62b23c9207c33d0be8a2e2af7a42e21e6ea388b380a0c948c7b88953b", size = 125852, upload-time = "2026-07-08T12:25:00.065Z" }, + { url = "https://files.pythonhosted.org/packages/f2/99/bf1820e6feeabc2f218c24450ec0c995d6a91e8ba0fd3caf042c9e8adb2a/librt-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:40ccd13c252d3fe473ffc8a57be7565abc8b64cf1b108344c859d5164f7f3e0c", size = 111832, upload-time = "2026-07-08T12:25:01.148Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f4/b2933ddae222dac338476abb872641169a5cfed2c2bb5444a5b07b32b0c3/librt-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30536798f4504c0fad0885b1d371b0539abb081e4570c9d7c641cb51141b49f0", size = 150990, upload-time = "2026-07-08T12:25:02.42Z" }, + { url = "https://files.pythonhosted.org/packages/90/ef/db98f744ca50e6efc9c95c70ee49b77aefac31f6a3fc7c83754a42d6a74f/librt-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93d24ebb82aa4420b1409c389e7857bc35bd0b668007ac8172427d5c73cc8cc5", size = 155238, upload-time = "2026-07-08T12:25:03.681Z" }, + { url = "https://files.pythonhosted.org/packages/03/e7/a197e7bc72baf2c61ce7fdc6906a5054dc05bd8da0819aa894e4857bf87e/librt-0.13.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb8a1adce42d8b75485a5d56a9623a50bcab995b6079f1dac59fc44034dd93d9", size = 503073, upload-time = "2026-07-08T12:25:05.049Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e7/7887712e27da7c1ab80fcabb1de6eb24243964f6557cae530d4b70706dbd/librt-0.13.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0763ca2ab66058174f9dee426dc64f5e0a89c24a7df8d3fe3f1836c04e25de4b", size = 496528, upload-time = "2026-07-08T12:25:06.26Z" }, + { url = "https://files.pythonhosted.org/packages/94/f0/f2283385bb6b950b26a1410f4ce51ec27231e0b3a4b925c46366d218b198/librt-0.13.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b222493da6e7b6199db9bd79502436cf5a27da3c1f7fa83c7e285444fc93fd03", size = 531786, upload-time = "2026-07-08T12:25:07.658Z" }, + { url = "https://files.pythonhosted.org/packages/36/11/69ac3b54766ffba5fd7e5acebfb048d66dbe1f9f2d14516c2b3edc59cf87/librt-0.13.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fadc63331f4388c3dc90090448f682a7e9feafc11481391c1e94f2f907a3976e", size = 524393, upload-time = "2026-07-08T12:25:09.121Z" }, + { url = "https://files.pythonhosted.org/packages/61/5f/d72f95fd444a926a3c14b4e24979474116988dd57a45be242077c45d3c22/librt-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:70d9c62a4cffd9f23396cd5ef93fc5d11b31596b9b7d6306074abe3d5fcf09bd", size = 543026, upload-time = "2026-07-08T12:25:10.459Z" }, + { url = "https://files.pythonhosted.org/packages/c4/08/dcd9993ad192737a004ba263d549f8ea605b326b952e7d6205c7d4170b76/librt-0.13.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66c0e7e6b02a155576df2c77ec933a70b72da726e248c494abf690923e624348", size = 546829, upload-time = "2026-07-08T12:25:11.716Z" }, + { url = "https://files.pythonhosted.org/packages/96/d5/6d9bb2f54e4109a956b7128836529653eb9d740f784bc47ed10a02c1000e/librt-0.13.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ac04bcd3328eb91d99dfedf6a60d9c1f15d3434e6f6daf922f0420f7d90b85c7", size = 535700, upload-time = "2026-07-08T12:25:13.144Z" }, + { url = "https://files.pythonhosted.org/packages/8c/f2/10946922503858a359492fa27f13e86228bde702116a740ac7b3cd185f24/librt-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db327e7271e653c32040b85ae6188059c924b57d7e1e29f935523fa017cd4e82", size = 573566, upload-time = "2026-07-08T12:25:14.336Z" }, + { url = "https://files.pythonhosted.org/packages/48/a8/94f00e3c99479a18088af3685ea016c42f3c7d5d1964d8dbb40c08d7f1aa/librt-0.13.0-cp312-cp312-win32.whl", hash = "sha256:860bd1d8ba48456ce08feaf8d343a8aaeb2fa086f2bcaa2a923fa3f7a3ff9aa3", size = 106099, upload-time = "2026-07-08T12:25:16.159Z" }, + { url = "https://files.pythonhosted.org/packages/c9/7b/2da9c74c1ed25a89cc4e1c8e007ea2eb4a0f1fafa3e70d757fe3242c5c5c/librt-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:e54a315caf843c8d77e388cadc56ea9ded569935ee2d2347d7ea94992e5aa6fa", size = 126934, upload-time = "2026-07-08T12:25:17.275Z" }, + { url = "https://files.pythonhosted.org/packages/d0/65/aead61bbf3b5358593f9d4779d2a0e88eaf6ec191a6342dde36dd1df6371/librt-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:c718e99a0992127af84385378460db624103b559ab260435abcfe77a4e4ed1c1", size = 112236, upload-time = "2026-07-08T12:25:18.425Z" }, + { url = "https://files.pythonhosted.org/packages/67/3b/18e7b63255297a2bdc9c25c8d6d4ca8eca9f63aceb1252c0f7427ac7099e/librt-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a468951af16155824e88bdd8326ebe5bdb371f3ec0ac04642994b98201d914f3", size = 151027, upload-time = "2026-07-08T12:25:19.638Z" }, + { url = "https://files.pythonhosted.org/packages/4d/68/e2248452c00d1a03b45fee1752cdc8f790a476efd2402b75181da88a9e61/librt-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ae01d8512cc17079e53425635327dbf3f7ff57a42c00dec348bf79791c56444c", size = 155152, upload-time = "2026-07-08T12:25:20.851Z" }, + { url = "https://files.pythonhosted.org/packages/0e/16/52b1c99bf19057a062aac39c900cbb81499f6f75d6c537c14463d247ba78/librt-0.13.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32c26893cd085c1efe83219e78d866da23fb20a066101b8f68210004361d224c", size = 502499, upload-time = "2026-07-08T12:25:22.055Z" }, + { url = "https://files.pythonhosted.org/packages/9f/54/b811151805c795f55e0dedee6ec687b75f9982a8105d240ea3910737a77b/librt-0.13.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5929da1981a46bcf4b28b1b9499905f0ff58e2419da402a048234e9783acbc4b", size = 496108, upload-time = "2026-07-08T12:25:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f8/094d6b2bd93f3fdaa54db54cc788c4a365333bddad65ab02e04da0b1d004/librt-0.13.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b85d664d777bab6c0d709416cb42938251fda9e221b79e3a2215d85df5f4f9", size = 531576, upload-time = "2026-07-08T12:25:24.648Z" }, + { url = "https://files.pythonhosted.org/packages/2e/40/541733d5755824f968f7ec39d78ffbd75d145964157ae5e69a09ec6d7326/librt-0.13.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:531b2df3e9fe96b1fcf73a6d165921e4656be5f58d631d384ebce344298368db", size = 524390, upload-time = "2026-07-08T12:25:25.898Z" }, + { url = "https://files.pythonhosted.org/packages/c6/b5/255673cfdbf5ba663339d36cd863c897289ab4337577e19f9405ce059f36/librt-0.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:109b84a9edf69ad89dc1f66358659e14a031baca95e3e5b0060bd903ede8efd6", size = 543053, upload-time = "2026-07-08T12:25:27.436Z" }, + { url = "https://files.pythonhosted.org/packages/9e/11/ab5005e9c9850710f21e354201bf090646349d3fabf5f951eaf70235729e/librt-0.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1304368a3e7ffc3e9db986796cc5326fdb5943a3567ecc137cff318e4240c0e7", size = 546387, upload-time = "2026-07-08T12:25:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/a2/04/a5d7ce1d1df1afd15ca283dcdf7530ac073e12d69ae8c40879dda96f7868/librt-0.13.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e4f9b472e7d308d94b62c801982065661158c6ed02790d6c7ddb4337cea0f9c1", size = 535970, upload-time = "2026-07-08T12:25:30.171Z" }, + { url = "https://files.pythonhosted.org/packages/5a/76/927e267a6daa290174ac281b23c9804c8829b042ade9c6f24a065f540958/librt-0.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f836c37478f167a81200d8c8b2c920a22224564bed2c23d7aeec760965c367a", size = 573582, upload-time = "2026-07-08T12:25:31.507Z" }, + { url = "https://files.pythonhosted.org/packages/10/24/b6c5213efe39c19f9e13605644d0cf063b4ddaa33ac2e45b088e23a70e2e/librt-0.13.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:4000d961ff9598ac6ea603c6c836a5ed49bc205ade5fc378b998dfe1e2c36628", size = 82189, upload-time = "2026-07-08T12:25:32.675Z" }, + { url = "https://files.pythonhosted.org/packages/4c/00/d29736be177a906ac0b84a5b04b4fbfa22c776dc2f366de4172b0f968c08/librt-0.13.0-cp313-cp313-win32.whl", hash = "sha256:79e44cff71750d299d61a678e49995b0d5935a9cda238c2574daeca3ba536927", size = 106193, upload-time = "2026-07-08T12:25:33.692Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ac/aff6fb45393cb8912f39dfb156ef6b2d1cadb207ff465fc8f66141054be8/librt-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:54dab44a847d5ad1acd05c8a83fe518ae685516ecf4d3f7cc6e3df2a66767650", size = 126962, upload-time = "2026-07-08T12:25:34.769Z" }, + { url = "https://files.pythonhosted.org/packages/d9/3a/d68cb2b334d53fd30fac81d3a489ce4ba0d9506f4df43fcf676b68352b19/librt-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:d4cb6fbfdf874340ab5e51450753c0f817b6958a3621125ee695bbc3de866566", size = 112127, upload-time = "2026-07-08T12:25:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/7b/66/f49ae0d592bd45b6941e9a8bafcb6a87cddcd501ee7874707e767f01b585/librt-0.13.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:25218d94b1d2cbc0ba1d8a3f9dc9af578d9646e5ed16443a70cde1dfdcce6d71", size = 149818, upload-time = "2026-07-08T12:25:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/3d/50/51c76d74014d04fb95b6506d286808984b78a2f7a41039094e6b2194ac48/librt-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f26629539d4893c2957a16c41bb058e1e135c1f150f6a2e25ed047f64cf3f5c6", size = 154071, upload-time = "2026-07-08T12:25:39.399Z" }, + { url = "https://files.pythonhosted.org/packages/b8/fe/f19b0f5f82d5a1f2da736586bc840abd00ce07d6388136ae80b7333883fc/librt-0.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4517d47b2b8af26975a406fba7d314de9696d864252e0257c6ea90238cfe27f", size = 494168, upload-time = "2026-07-08T12:25:40.641Z" }, + { url = "https://files.pythonhosted.org/packages/94/bc/b8550c75775127fd31a5f20e8775997f7b527ad661fc8ddccd7497c064f7/librt-0.13.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f19e181de5b3a1148bb3420b8c4b0b0ea0fce6950099724ad151d6cea5acc180", size = 491054, upload-time = "2026-07-08T12:25:41.905Z" }, + { url = "https://files.pythonhosted.org/packages/30/14/4d0204867623df3f33f86efd3d3692ba5e01321443f4d6eab35a22697618/librt-0.13.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22034924f5b42d5a56371cf271771bfeaabf235a7a8b6264bef2d20013f786c6", size = 523006, upload-time = "2026-07-08T12:25:43.327Z" }, + { url = "https://files.pythonhosted.org/packages/19/0a/c45fc9a260934696bace1ac5df1e148ac92bd71767aee3bf7cd7a4534f4c/librt-0.13.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7897db4e95e22468bdda33d8e012ceacd0182abf001e6389d763f0def6286b9", size = 515058, upload-time = "2026-07-08T12:25:44.541Z" }, + { url = "https://files.pythonhosted.org/packages/13/0a/50c5ce45b326854ef8fa6ae4c36cf5142e5c55315eaf9e51d0ae73ac4da3/librt-0.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1ce61b3746545029d4f5c17d6bd74b676254ad98433086c846ffb5e8fa73f007", size = 534025, upload-time = "2026-07-08T12:25:45.825Z" }, + { url = "https://files.pythonhosted.org/packages/89/2d/08c413c8f93fc13b8103624fce38e5caa86cd08cbbc8465870ab287af54b/librt-0.13.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:46c330e82565962c761dbce7941be2cff7db674ee807455a8d0cadc5f9b759b0", size = 540557, upload-time = "2026-07-08T12:25:47.059Z" }, + { url = "https://files.pythonhosted.org/packages/b3/c1/93af71fb4a364952210051811dd4e40174e79656b050c89cacac18af3330/librt-0.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:375f5af8f99cbaa99dd293af986e3d57caabc9ba81a5d3f021603764854197a1", size = 523201, upload-time = "2026-07-08T12:25:48.392Z" }, + { url = "https://files.pythonhosted.org/packages/c1/6e/9766f07b676a4889d9f8bc2864e9ba5fff165653143ef4dda7df6aa34d16/librt-0.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9320d34c3376ae204b2cd176e8d4883a013934e0aef822f1aed9c536490c275d", size = 565740, upload-time = "2026-07-08T12:25:49.678Z" }, + { url = "https://files.pythonhosted.org/packages/a2/1e/664e3472ce2b6e10e9b83f29d4a36eb982ff6b5a169ae7567bba3a4c4ff5/librt-0.13.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:9af313c66157a69dc69ea0059a66961692250e0dc95af9c385a48ffb770a0d16", size = 81611, upload-time = "2026-07-08T12:25:50.857Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d4/8582a4d65e2234673685e07309d02c230b28a85724eb0acbf13f019b7f6e/librt-0.13.0-cp314-cp314-win32.whl", hash = "sha256:f2a7253458e34f33543551394ae4fe104b497ec2a65ac266074de64c1df82e37", size = 100106, upload-time = "2026-07-08T12:25:52.03Z" }, + { url = "https://files.pythonhosted.org/packages/63/ce/0cb99efe6086b46cd985dc26672166fae312a239690e75871f7fafbd3fc5/librt-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:a3dfe4edf10e8ed7e55b026a8bfc2c2a8704218b659cd4bffdf604fab966dc39", size = 121209, upload-time = "2026-07-08T12:25:53.166Z" }, + { url = "https://files.pythonhosted.org/packages/26/85/4f3ccb083a3c9b0d42e223acdb3c3f507953324a59cdcab4826e8e2e3b89/librt-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:68a5faee4bba381cb93b5961f684a514cf0053cb92308ff9c792c2fea0b174c6", size = 106404, upload-time = "2026-07-08T12:25:54.253Z" }, + { url = "https://files.pythonhosted.org/packages/b2/77/333191499538c8e8189de7a4cba8e6f49ee949fd6d6e6324b21fd1522466/librt-0.13.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a38fb81d8376dfa2f8963b265fec07637802b0d01e2a127c19c66cb070fb24f5", size = 159231, upload-time = "2026-07-08T12:25:55.432Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9e/2aa83758f22c278b837a1d8025898434ce2b8bff36678d5330ecaef56dff/librt-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d4c8d9bd5abce34b2e75edb3bf37ab0f34e49b1f915a40ae8468eb7c85bc5b46", size = 161300, upload-time = "2026-07-08T12:25:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/bb/c0/86791e936553ca763d6b3c2fb4d31d596cd00e14fa631c283a40ba01559a/librt-0.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:387e2f1d27e89bffe0d3f520f0da0662c973fd607ca16c1808f8a5085419485e", size = 582056, upload-time = "2026-07-08T12:25:58.144Z" }, + { url = "https://files.pythonhosted.org/packages/a8/d3/a9ec15984a185e000c4d2a16ba28bd623124ad4c38a10974c7ff78e3a893/librt-0.13.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:4f6db193d2e5e0ed60359b9a5a682cd67205d0d3b1e459a867dd4b5c4e7eaa7a", size = 562758, upload-time = "2026-07-08T12:25:59.544Z" }, + { url = "https://files.pythonhosted.org/packages/3c/af/dbe36b78b19c06a55097f99305e4ea9458e2273e6ae16a3cbecaad7ee978/librt-0.13.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d38604854e8d22faadf683ec6c02bb0f886e2ba56ef981a1c36ee275f21ea22", size = 602095, upload-time = "2026-07-08T12:26:00.991Z" }, + { url = "https://files.pythonhosted.org/packages/2a/a8/2966891b4dd2830f5203fbee92ac2c4947653a2390ba73dfa44244fad025/librt-0.13.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:371f7ce73026815dafd51c50ce38416e91428b28c4b2ec97cd39271164b0045c", size = 593452, upload-time = "2026-07-08T12:26:02.352Z" }, + { url = "https://files.pythonhosted.org/packages/61/f5/4df8bfc8405ecf8c0d525b4d69636f694bdd8620b313ec8b76e54a5926cc/librt-0.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3aaedf52171bee90860704c560bc798fe83b76247df47568e0197e9b13c735a0", size = 623729, upload-time = "2026-07-08T12:26:04.294Z" }, + { url = "https://files.pythonhosted.org/packages/d6/13/9ac202dffc8db06f75d06c08c2f9f6ff054be67d21272dcc078fa1cc0c57/librt-0.13.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:96bad8725a4f196a798366c25ce075d1f7543a4ec045ffc13e6a7ec095cdab04", size = 617077, upload-time = "2026-07-08T12:26:05.845Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f0/ebe38610716aee5cb28efd95089bb90192096179802779381e1c5dcf239c/librt-0.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6bf6a559ffe4a93bbea6cf31ddf01a7fd9ba342ef51f27beb178e318b74acd61", size = 599561, upload-time = "2026-07-08T12:26:07.21Z" }, + { url = "https://files.pythonhosted.org/packages/4f/5c/c2e72e236fff7abc716d5b1753b8b8cd3ea85ac46fe17d2e7c51d4e1c723/librt-0.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:301067672387902c55f94b51d5022304b36c966ea9fe1f21caab99a9bef487c9", size = 645511, upload-time = "2026-07-08T12:26:08.562Z" }, + { url = "https://files.pythonhosted.org/packages/0c/99/6203ce619dee940d6bfbe099ec3fe4be00a68e9d60f70abf906cf124fe66/librt-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:5fdcf34f86de8fb66d7dc7589f96ba91c4aa46671200d400e6fd6f109a483f18", size = 104357, upload-time = "2026-07-08T12:26:09.828Z" }, + { url = "https://files.pythonhosted.org/packages/52/dd/843b6314087c41657c7036d7914d8f294bdf9b580aa8513ea0588c8e9a3d/librt-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:260c33e92263fa629b4f6d3c51967a1c2158fe6c33237aaa3ebeac586b085259", size = 126998, upload-time = "2026-07-08T12:26:10.975Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/3dcec2884ba1b0806d1408612555c38dd5d68e90156b59f75f6e36435c3a/librt-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2f281549a4c52ac7bb97997f14353f8bd0e53a34ca0dad1c905cfd0b4a58ae99", size = 110771, upload-time = "2026-07-08T12:26:12.303Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mock" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/07/8c/14c2ae915e5f9dca5a22edd68b35be94400719ccfa068a03e0fb63d0f6f6/mock-5.2.0.tar.gz", hash = "sha256:4e460e818629b4b173f32d08bf30d3af8123afbb8e04bb5707a1fd4799e503f0", size = 92796, upload-time = "2025-03-03T12:31:42.911Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/d9/617e6af809bf3a1d468e0d58c3997b1dc219a9a9202e650d30c2fc85d481/mock-5.2.0-py3-none-any.whl", hash = "sha256:7ba87f72ca0e915175596069dbbcc7c75af7b5e9b9bc107ad6349ede0819982f", size = 31617, upload-time = "2025-03-03T12:31:41.518Z" }, +] + +[[package]] +name = "mypy" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ast-serialize" }, + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/af/4e516a05d3ca2eb9283e9ec45b2c02225c1514dd6da49fd3c9eaa6639370/mypy-2.3.0.tar.gz", hash = "sha256:465965d41cd9a2726694e983e8ce7113259327bec798115d1e1dfa2a52fb666e", size = 3988104, upload-time = "2026-07-13T11:34:53.387Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/09/f2f5f45dae0c9a0891e4751a73312730e009395102e5d72a22a976cca41f/mypy-2.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1fa8d916ac3b705af733c4c1e6c9ebe38fd0d52beb15b105c3e8355b55e6ecdc", size = 14927774, upload-time = "2026-07-13T11:28:38.224Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/345367effd3a6877275a94d481614bfca983f45e028c6290e2cc54603811/mypy-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:28e1e2af8cd8fff551fd30f2fe4b03fb76764ac8b1ba6c6a1bd00ad32b412db3", size = 14000127, upload-time = "2026-07-13T11:30:19.57Z" }, + { url = "https://files.pythonhosted.org/packages/99/6c/a10b7a7b9f0a755fb94e27ae834d4cea9ad6c5221f9325eef8f182641feb/mypy-2.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e77244df3843048c3f927182916730e40c124cbaa43905c1fb86cb382aa0805", size = 14229437, upload-time = "2026-07-13T11:28:17.765Z" }, + { url = "https://files.pythonhosted.org/packages/d9/bd/a26a602acb1bbf849fa4bdac4bc657ee2f11c0c2a764a2cc87a5304e865c/mypy-2.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9559ab18a9c9957dfa3004ab57cd4bac5f26a724329a9584e583367f0c2e1117", size = 15171457, upload-time = "2026-07-13T11:29:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/7f/14/124f462bef69bcbc90b9358088460b6091954a3e004852fcd9948db617a5/mypy-2.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:09abd66d8685e73f8f7d17b847c3e104d9a7b164a8706ea87d6c96a3d45816d5", size = 15478281, upload-time = "2026-07-13T11:32:23.413Z" }, + { url = "https://files.pythonhosted.org/packages/db/a4/8bdca6a8ac8d856d82ed049144af2721245a135c2e8001d3890c93975852/mypy-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e91adad1ca81742ac7ef9893959911df867752206b37135185e88dfb3c89494", size = 11148008, upload-time = "2026-07-13T11:34:17.332Z" }, + { url = "https://files.pythonhosted.org/packages/83/41/490eea348e60ba50decec20bc750605444149a5d7a8cc560042f90ba2c75/mypy-2.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:6f99ec626e3c3a2f7c0b22c5b90ddb5dabb1c18729c971e9bdaca1f1766d2cee", size = 10142329, upload-time = "2026-07-13T11:32:52.116Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b9/d75b3082b05f1b3028828aeb18e74ae5ab0a0936051bbf1f32f59f654747/mypy-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3419d00717afbc5265b50dd14b1278f29ea4884dd398ab67873489ac093fd329", size = 14838725, upload-time = "2026-07-13T11:32:44.655Z" }, + { url = "https://files.pythonhosted.org/packages/a9/50/79a65c6ea6e115bc73296038a4543b2d5c91f07912b918a2c616a2514bba/mypy-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cfca8ee88544090f86b6dcce05ec55d66eb48a762412ac2507810ba4bd793b6f", size = 13911128, upload-time = "2026-07-13T11:32:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/90/48/e11ed7716c26953ca321f726e452e374dbf81a6f2b8b212ec02af29b6b8f/mypy-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75cbb4b9ef04a0c84a957f07abc4504fbf64b8dcc145675101f2d3a78a4b1d6a", size = 14146742, upload-time = "2026-07-13T11:33:03.313Z" }, + { url = "https://files.pythonhosted.org/packages/06/72/6807565b1c4861ef66f7fdd98b51c61556356eab80235717b46c53bb8627/mypy-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:982e3d53dd23d0a4cef67dd66791fdbede0cf38f9eb617bf47663554c51e1e36", size = 15081418, upload-time = "2026-07-13T11:31:13.899Z" }, + { url = "https://files.pythonhosted.org/packages/00/80/1ea14c5d80e589e415973db3e47c78c2219a305b808b2b506395342c1d79/mypy-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85c5385b93012ffa3b31479ab579aef5415f4f3a32c6cf1ae07a984d2a0ff461", size = 15328164, upload-time = "2026-07-13T11:31:35.723Z" }, + { url = "https://files.pythonhosted.org/packages/37/28/8223157404a3d51920078459c37f80fbdc590e1d8ea049dc5ce48643022a/mypy-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:13b1b16e2fa39f3b2e33fb1c468abc7a69369fa2e886b4b87b5afc81472325cd", size = 11136472, upload-time = "2026-07-13T11:27:37.018Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cc/ea27e5959c5f258585a756b252031f3b313583d81b5064b2bebc41d3706b/mypy-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5cd2f027a972a4a5f2278a11fac9747f5f81a53a30b714d74950b6807e55568", size = 10135800, upload-time = "2026-07-13T11:30:08.92Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/0e7e592619e2133596a47cdd642534b0456545c218430bd3b9d8fefdd1b1/mypy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d53fc67b9d28a43c6199077f49fea0f05839e36cf6158500331c9549225e5a5", size = 15026523, upload-time = "2026-07-13T11:34:49.206Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d2/1e1731df090a857df2807177a4626863e5ac0f0256513c35780efe53986f/mypy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fbc00cee7bdbb9291979ddc9d08034a29dfcda4932628c9bbc28c1edd589df0c", size = 14032189, upload-time = "2026-07-13T11:33:57.168Z" }, + { url = "https://files.pythonhosted.org/packages/44/95/cab921f4a806e171f34113e6181dd23c55358ccf6a80741269ef594a410e/mypy-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04e617030eca5221909c8b7d8d7fd1c637948199aa2100b2ad9813feb07e1491", size = 14198696, upload-time = "2026-07-13T11:32:12.767Z" }, + { url = "https://files.pythonhosted.org/packages/66/80/e6d008bb19fe446e3662d85e0e2717bf9f2d611a2164fb29d6e067dbf46c/mypy-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56c184d2c20ca6b6378d58d1960270a767f41f5e44acbbd27f05effef4f4e1d7", size = 15286904, upload-time = "2026-07-13T11:34:27.594Z" }, + { url = "https://files.pythonhosted.org/packages/db/83/94397c9293608a364aa03e8084fb34ede4ae976a260384b9b52929308135/mypy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3961a4a34b05f7c74b0f05aa51fbfe99a2d1e126038df40318d15c8f558b7ef3", size = 15528342, upload-time = "2026-07-13T11:34:07.819Z" }, + { url = "https://files.pythonhosted.org/packages/cf/96/d8b37d819adec6cfccfb1fd3afc1735d94717ddeafb45536db9c6943e09b/mypy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b1942b9314d4c784b8ea1dbab4972603290e5dd5630f06675f13aec97526bc4c", size = 11218346, upload-time = "2026-07-13T11:28:27.745Z" }, + { url = "https://files.pythonhosted.org/packages/2b/cd/cd9f725b19b19e5b530a154cf9bcf9e94279c5d55b3c34fb42b3aa48ea1b/mypy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:be51653d7669d7d7955d613b8d0bb57d5b652eaf71a873ddf65ac87254dd2595", size = 10204525, upload-time = "2026-07-13T11:31:02.552Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ae/f7d056eb0294586a572d0d0d89580ec633c064db520f11d37d5a2fb833bd/mypy-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:91ad22a52ae2c7e621c2f67c94d5a17f66b3209a4cff5cf8a573579835c69e97", size = 14947298, upload-time = "2026-07-13T11:27:47.734Z" }, + { url = "https://files.pythonhosted.org/packages/32/d5/db3e7af01e7844d21662c6ddc1f7825ec7cb4053f0391ac02faf3638396f/mypy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:99ac767cc5d3b64c8d0ae226ead10c96694f94e4e7da1668642225dcd4e75aac", size = 13950768, upload-time = "2026-07-13T11:27:57.726Z" }, + { url = "https://files.pythonhosted.org/packages/d9/fb/43c031f0190513d1ec248ed037eceb742ddd2a4d74bbf406658a28173837/mypy-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de6d2c484742a4d7b0ed6d07b143375624d3b899c5749c7b3c947f56261f48a6", size = 14151586, upload-time = "2026-07-13T11:29:18.615Z" }, + { url = "https://files.pythonhosted.org/packages/ec/c3/f8b2ffc60883084da91be51af58e88a7ffd4ff9795acb7d902ff88d31eb1/mypy-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7da939dd335cfd2ad788bdfd081c9f4e47634ab995e5a45eb15fd1e5bc052f8b", size = 15227411, upload-time = "2026-07-13T11:30:29.904Z" }, + { url = "https://files.pythonhosted.org/packages/83/2e/16b917fc7adcf03f1aadddfc93aab804ffb234b1ab09c0ffd6d92a5d34a2/mypy-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7247eb2824f996722a949530183394921ca71deb9680052a338cf53cff7925c2", size = 15478790, upload-time = "2026-07-13T11:33:14.686Z" }, + { url = "https://files.pythonhosted.org/packages/c0/88/aaa65a93c73d0cdae7e42f8adb302bf6885bb281302084f99d0290a35347/mypy-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:75b0984bb3cbd76bb5c9291a8671f7ae66ca3b51c7584c358fc2e923259f0757", size = 11234919, upload-time = "2026-07-13T11:33:39.28Z" }, + { url = "https://files.pythonhosted.org/packages/35/19/b40de63f1a80e63bc2d40f0679a6a8dbd34e95176c8122119bdf406aa552/mypy-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:d78fcf900b59cb7e82cb7e3a235e31b462d9333d92285bd1e4952d355b8ffba1", size = 10201510, upload-time = "2026-07-13T11:31:52.619Z" }, + { url = "https://files.pythonhosted.org/packages/a4/58/fa0ae047da911f540284009b4f44b96fe09d83c076d7c103e9d645f46303/mypy-2.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ea317b060ce83e26050f8f9e4d7d6bf44ed7597c8ff9990bccffbb9d1d8522db", size = 14941909, upload-time = "2026-07-13T11:32:34.332Z" }, + { url = "https://files.pythonhosted.org/packages/15/14/2ba1d61452d7c2a7fe12741e8d374e52b183476b07aa7f9e2a0d02b0720a/mypy-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:094af99f92638aa92852326188b85a89e50f4a472f44827c03362228482f0762", size = 13967581, upload-time = "2026-07-13T11:30:00.587Z" }, + { url = "https://files.pythonhosted.org/packages/ed/5a/483fb9e5ffbbb1a28dccc7b0a13d141b17ac769b6c9f488c0a0c63698962/mypy-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de121747278144fc9ae7caa2e978cf5df12aebc82933182f5b3b86081a30baef", size = 14168807, upload-time = "2026-07-13T11:28:48.6Z" }, + { url = "https://files.pythonhosted.org/packages/ae/77/70d7a10732063beb74ad713682cf871e88f5c5fa39bfc8beff8a524bf9cb/mypy-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37fa4de896a84e2dc9200d91e614c22563b43d1a266789d4bbac7b22ebe6192b", size = 15200144, upload-time = "2026-07-13T11:31:25.283Z" }, + { url = "https://files.pythonhosted.org/packages/56/72/766218ac783be4fdfcd699b90037b63017348a3e86fb2c1fbfb18302637d/mypy-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f1b3a98dfd21058bc759bb3337d5d1f61d0fdf9f3cf9c00f4291790fb5427bff", size = 15460389, upload-time = "2026-07-13T11:29:29.077Z" }, + { url = "https://files.pythonhosted.org/packages/38/4e/8a9db7411ecb8ec0cb1fd05dba432f28bafffcd38b4e887714a4a0506689/mypy-2.3.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:944c665d984157cb96a679dfb7a4a81dd1d36b24b9c284b699514e6e626b82d4", size = 7753664, upload-time = "2026-07-13T11:29:08.147Z" }, + { url = "https://files.pythonhosted.org/packages/65/4c/c3f8bfd6ed0e5e38b5a244403b27f821d433443df5a15a278417c10a3a3c/mypy-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:4359424140d985192c778c1ce2c114a10c1ca58a381ed79cfa70d37df94b299f", size = 11417237, upload-time = "2026-07-13T11:33:47.467Z" }, + { url = "https://files.pythonhosted.org/packages/3c/00/89a32eaf5ccf174bc4f90db0eaea5d70636c01b8d49f384bdab2e8834390/mypy-2.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:3dd0bed92c4bdec57c42505b96416fb9e6a5aa7be84d2809bcd5f2ecec2860d7", size = 10389252, upload-time = "2026-07-13T11:31:43.81Z" }, + { url = "https://files.pythonhosted.org/packages/31/56/104f93d69aa9f339b6b9d3b0a7faa699b8b466c942cf3ae86cc2a2ec0915/mypy-2.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:691fdc37132b1ae628d834f672e74de83462d9fb4aff621835767fb43a8dd373", size = 16385495, upload-time = "2026-07-13T11:29:49.818Z" }, + { url = "https://files.pythonhosted.org/packages/d2/03/f1d2123313f55efafdd27706960f43a771c62f1b68426c76043f3ab9ebf3/mypy-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:aec15d465d477558fd842757b487849007311cf3897849cdda0e3162ac0ac556", size = 15098155, upload-time = "2026-07-13T11:30:40.301Z" }, + { url = "https://files.pythonhosted.org/packages/e5/5d/d5f9200399b445e81726c4f23becee33f233aee81c72680b1ef3a258b641/mypy-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b352b7e49f5e6576009e8df730e1ff4f915cb565b851b396d2ffe2f5a6f5da88", size = 15514155, upload-time = "2026-07-13T11:34:38.569Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ce/69977c555f08faa3190cfde44189b89dbd56861b1ab97aa18fc5f3a2e4a3/mypy-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c6c6bf687b17f90dbfcad95b960d32eaa0154c00da45f03ab50bf8952e047fe", size = 16766351, upload-time = "2026-07-13T11:33:29.195Z" }, + { url = "https://files.pythonhosted.org/packages/bc/92/6648b6caa3ab9e00f9ac0c2a78307805f873dd48139b24a6f6f7c3667bbf/mypy-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f4ed18f111bfe2d599bca7468e7f9251042c1c2118f762c8de2766a56d773c60", size = 17043490, upload-time = "2026-07-13T11:30:53.927Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ab/0dc91d80f3f016634c68d451f294a97320fe903a9b6f90b9e57b3f7f1717/mypy-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0b025a93cffb9781d231f232be07a17912f35f10a313c24f301c81e842870654", size = 12146869, upload-time = "2026-07-13T11:29:38.874Z" }, + { url = "https://files.pythonhosted.org/packages/85/b5/4c964d02634ba81f4d1c84838e5c5b18ab06d13ed568960f5d6318495ccc/mypy-2.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:adebc76aab4f3495a88b41d48aa4aff0c03f2822501da76625afcca5975f19e5", size = 10965113, upload-time = "2026-07-13T11:28:07.056Z" }, + { url = "https://files.pythonhosted.org/packages/2c/fa/fdc54fe583ba3cafbcedfb70eeeaf03849f75b1827a07096c7bd996f582d/mypy-2.3.0-py3-none-any.whl", hash = "sha256:6b1cdb579446b60432432b2b2403a6201b4b475a004d7f488511c9ba177c9e88", size = 2753292, upload-time = "2026-07-13T11:33:18.48Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "outcome" +version = "1.3.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060, upload-time = "2023-10-26T04:26:04.361Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b", size = 10692, upload-time = "2023-10-26T04:26:02.532Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, +] + +[[package]] +name = "pbr" +version = "7.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/ab/1de9a4f730edde1bdbbc2b8d19f8fa326f036b4f18b2f72cfbea7dc53c26/pbr-7.0.3.tar.gz", hash = "sha256:b46004ec30a5324672683ec848aed9e8fc500b0d261d40a3229c2d2bbfcedc29", size = 135625, upload-time = "2025-11-03T17:04:56.274Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/db/61efa0d08a99f897ef98256b03e563092d36cc38dc4ebe4a85020fe40b31/pbr-7.0.3-py2.py3-none-any.whl", hash = "sha256:ff223894eb1cd271a98076b13d3badff3bb36c424074d26334cd25aebeecea6b", size = 131898, upload-time = "2025-11-03T17:04:54.875Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { 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" } +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" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pysocks" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-gitlab" +version = "6.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, + { name = "requests-toolbelt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9a/bd/b30f1d3b303cb5d3c72e2d57a847d699e8573cbdfd67ece5f1795e49da1c/python_gitlab-6.5.0.tar.gz", hash = "sha256:97553652d94b02de343e9ca92782239aa2b5f6594c5482331a9490d9d5e8737d", size = 400591, upload-time = "2025-10-17T21:40:02.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/bd/b0d440685fbcafee462bed793a74aea88541887c4c30556a55ac64914b8d/python_gitlab-6.5.0-py3-none-any.whl", hash = "sha256:494e1e8e5edd15286eaf7c286f3a06652688f1ee20a49e2a0218ddc5cc475e32", size = 144419, upload-time = "2025-10-17T21:40:01.233Z" }, +] + +[[package]] +name = "python-semantic-release" +version = "10.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "click-option-group" }, + { name = "deprecated" }, + { name = "dotty-dict" }, + { name = "gitpython" }, + { name = "importlib-resources" }, + { name = "jinja2" }, + { name = "pydantic" }, + { name = "python-gitlab" }, + { name = "requests" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "tomlkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/f6/06d5aa54b46bb192b00ef3e74234300ea5932dd310d142a3c8070e770e93/python_semantic_release-10.6.1.tar.gz", hash = "sha256:ee6369238f72e75a009b3724481232c8b813416191be099bc0266e375fd02b2b", size = 626453, upload-time = "2026-07-06T06:14:35.507Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/97/be812cd1eb350551d2f3cc38426864cce493a03ed31f4749133bcff8d053/python_semantic_release-10.6.1-py3-none-any.whl", hash = "sha256:36f7319515f218719d0972bc9535813a930f04cd19556767599e9863242efcdc", size = 155674, upload-time = "2026-07-06T06:14:33.575Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "requests" +version = "2.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + +[[package]] +name = "rich" +version = "14.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, +] + +[[package]] +name = "roman-numerals" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, +] + +[[package]] +name = "roman-numerals-py" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "roman-numerals", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/b5/de96fca640f4f656eb79bbee0e79aeec52e3e0e359f8a3e6a0d366378b64/roman_numerals_py-4.1.0.tar.gz", hash = "sha256:f5d7b2b4ca52dd855ef7ab8eb3590f428c0b1ea480736ce32b01fef2a5f8daf9", size = 4274, upload-time = "2025-12-17T18:25:41.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/2c/daca29684cbe9fd4bc711f8246da3c10adca1ccc4d24436b17572eb2590e/roman_numerals_py-4.1.0-py3-none-any.whl", hash = "sha256:553114c1167141c1283a51743759723ecd05604a1b6b507225e91dc1a6df0780", size = 4547, upload-time = "2025-12-17T18:25:40.136Z" }, +] + +[[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" }, +] + +[[package]] +name = "selenium" +version = "4.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "trio" }, + { name = "trio-websocket" }, + { name = "typing-extensions" }, + { name = "urllib3", extra = ["socks"] }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a0/53/053df98ef0c38535a74ea732217eb2dbfddc7ff5442a47a4b315ba577f85/selenium-4.46.0.tar.gz", hash = "sha256:54f7e1a4df5f7508ac8c38ce2ea584db1b27083dd79962b22524219219df5cbe", size = 1006000, upload-time = "2026-07-11T00:38:41.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/f4/365c723a37c7e9ba6a6a19bf0c9e407137703f56a72c6201d0e4cb1432cb/selenium-4.46.0-py3-none-any.whl", hash = "sha256:f03e864770a21ab32009961c9d015cb2c6275eba45c926c272e02d90af423aad", size = 9428587, upload-time = "2026-07-11T00:38:38.84Z" }, +] + +[[package]] +name = "setuptools" +version = "83.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/26/f5d29e25ffdb535afef2d35cdb55b325298f96debd670da4c325e08d70f4/setuptools-83.0.0.tar.gz", hash = "sha256:025bccbbf0fa05b6192bc64ae1e7b16e001fd6d6d4d5de03c97b1c1ade523bef", size = 1154254, upload-time = "2026-07-04T15:31:22.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl", hash = "sha256:29b23c360f22f414dc7336bb39178cc7bcbf6021ed2733cde173f09dba19abb3", size = 1008090, upload-time = "2026-07-04T15:31:20.885Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "smmap" +version = "5.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + +[[package]] +name = "sphinx" +version = "8.1.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "alabaster", marker = "python_full_version < '3.11'" }, + { name = "babel", marker = "python_full_version < '3.11'" }, + { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, + { name = "docutils", marker = "python_full_version < '3.11'" }, + { name = "imagesize", marker = "python_full_version < '3.11'" }, + { name = "jinja2", marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pygments", marker = "python_full_version < '3.11'" }, + { name = "requests", marker = "python_full_version < '3.11'" }, + { name = "snowballstemmer", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.11'" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125, upload-time = "2024-10-13T20:27:10.448Z" }, +] + +[[package]] +name = "sphinx" +version = "8.2.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.15'", + "python_full_version >= '3.11' and python_full_version < '3.15'", +] +dependencies = [ + { name = "alabaster", marker = "python_full_version >= '3.11'" }, + { name = "babel", marker = "python_full_version >= '3.11'" }, + { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, + { name = "docutils", marker = "python_full_version >= '3.11'" }, + { name = "imagesize", marker = "python_full_version >= '3.11'" }, + { name = "jinja2", marker = "python_full_version >= '3.11'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pygments", marker = "python_full_version >= '3.11'" }, + { name = "requests", marker = "python_full_version >= '3.11'" }, + { name = "roman-numerals-py", marker = "python_full_version >= '3.11'" }, + { name = "snowballstemmer", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, +] + +[[package]] +name = "sphinx-rtd-theme" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-jquery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/68/a1bfbf38c0f7bccc9b10bbf76b94606f64acb1552ae394f0b8285bfaea25/sphinx_rtd_theme-3.1.0.tar.gz", hash = "sha256:b44276f2c276e909239a4f6c955aa667aaafeb78597923b1c60babc76db78e4c", size = 7620915, upload-time = "2026-01-12T16:03:31.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/c7/b5c8015d823bfda1a346adb2c634a2101d50bb75d421eb6dcb31acd25ebc/sphinx_rtd_theme-3.1.0-py2.py3-none-any.whl", hash = "sha256:1785824ae8e6632060490f67cf3a72d404a85d2d9fc26bce3619944de5682b89", size = 7655617, upload-time = "2026-01-12T16:03:28.101Z" }, +] + +[[package]] +name = "sphinxcontrib-apidoc" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pbr" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/8d/161842a1c199c1baed5f5bc0765a59a791324f962fea3b604f105c9493e7/sphinxcontrib_apidoc-0.6.0.tar.gz", hash = "sha256:329b9810d66988f48e127a6bd18cc8efbbd1cd20b8deb4691a35738af49ad88d", size = 16790, upload-time = "2025-05-08T12:55:44.463Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/ac/6b94ecdca590ad0596b83d78277f89d897539a6cfdc997d62f27651540bc/sphinxcontrib_apidoc-0.6.0-py3-none-any.whl", hash = "sha256:668592f933eee858f3bc0d0810d56d50dfa0a70f650a2faaaad501b9a3504633", size = 8765, upload-time = "2025-05-08T12:55:42.733Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, + { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, + { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, + { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" }, + { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" }, + { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" }, + { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" }, + { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" }, + { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" }, + { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" }, + { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "tomlkit" +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, +] + +[[package]] +name = "trio" +version = "0.32.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "outcome" }, + { name = "sniffio" }, + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/ce/0041ddd9160aac0031bcf5ab786c7640d795c797e67c438e15cfedf815c8/trio-0.32.0.tar.gz", hash = "sha256:150f29ec923bcd51231e1d4c71c7006e65247d68759dd1c19af4ea815a25806b", size = 605323, upload-time = "2025-10-31T07:18:17.466Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/bf/945d527ff706233636c73880b22c7c953f3faeb9d6c7e2e85bfbfd0134a0/trio-0.32.0-py3-none-any.whl", hash = "sha256:4ab65984ef8370b79a76659ec87aa3a30c5c7c83ff250b4de88c29a8ab6123c5", size = 512030, upload-time = "2025-10-31T07:18:15.885Z" }, +] + +[[package]] +name = "trio-websocket" +version = "0.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "outcome" }, + { name = "trio" }, + { name = "wsproto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/3c/8b4358e81f2f2cfe71b66a267f023a91db20a817b9425dd964873796980a/trio_websocket-0.12.2.tar.gz", hash = "sha256:22c72c436f3d1e264d0910a3951934798dcc5b00ae56fc4ee079d46c7cf20fae", size = 33549, upload-time = "2025-02-25T05:16:58.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/19/eb640a397bba49ba49ef9dbe2e7e5c04202ba045b6ce2ec36e9cadc51e04/trio_websocket-0.12.2-py3-none-any.whl", hash = "sha256:df605665f1db533f4a386c94525870851096a223adcb97f72a07e8b4beba45b6", size = 21221, upload-time = "2025-02-25T05:16:57.545Z" }, +] + +[[package]] +name = "types-python-dateutil" +version = "2.9.0.20260716" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/9a/aefb9f80ff79641d36149352afe66ca835c5e6894deb518418f786f4b8ad/types_python_dateutil-2.9.0.20260716.tar.gz", hash = "sha256:1d55d1c3024bdb4861bb6a6622c9ec800c433d87bdc5b16fb84cdd0eed4ef2cb", size = 17516, upload-time = "2026-07-16T04:48:06.604Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/85/cff97326a81e7e8877803e78e3ea56c840b85bb811934b9c936f7c40f185/types_python_dateutil-2.9.0.20260716-py3-none-any.whl", hash = "sha256:1ae41d51a5c5f6bbeeb7f1f34df7086d55ff1605cf88d2ed71a7a276e1a7794e", size = 18443, upload-time = "2026-07-16T04:48:05.793Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[package.optional-dependencies] +socks = [ + { name = "pysocks" }, +] + +[[package]] +name = "virtualenv" +version = "20.36.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + +[[package]] +name = "wrapt" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481, upload-time = "2025-11-07T00:43:11.103Z" }, + { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692, upload-time = "2025-11-07T00:43:13.697Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574, upload-time = "2025-11-07T00:43:14.967Z" }, + { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688, upload-time = "2025-11-07T00:43:18.275Z" }, + { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698, upload-time = "2025-11-07T00:43:19.407Z" }, + { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096, upload-time = "2025-11-07T00:43:16.5Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878, upload-time = "2025-11-07T00:43:20.81Z" }, + { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298, upload-time = "2025-11-07T00:43:22.229Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361, upload-time = "2025-11-07T00:43:24.301Z" }, + { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035, upload-time = "2025-11-07T00:43:28.96Z" }, + { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383, upload-time = "2025-11-07T00:43:25.804Z" }, + { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894, upload-time = "2025-11-07T00:43:27.074Z" }, + { url = "https://files.pythonhosted.org/packages/98/60/553997acf3939079dab022e37b67b1904b5b0cc235503226898ba573b10c/wrapt-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e17283f533a0d24d6e5429a7d11f250a58d28b4ae5186f8f47853e3e70d2590", size = 77480, upload-time = "2025-11-07T00:43:30.573Z" }, + { url = "https://files.pythonhosted.org/packages/2d/50/e5b3d30895d77c52105c6d5cbf94d5b38e2a3dd4a53d22d246670da98f7c/wrapt-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85df8d92158cb8f3965aecc27cf821461bb5f40b450b03facc5d9f0d4d6ddec6", size = 60690, upload-time = "2025-11-07T00:43:31.594Z" }, + { url = "https://files.pythonhosted.org/packages/f0/40/660b2898703e5cbbb43db10cdefcc294274458c3ca4c68637c2b99371507/wrapt-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1be685ac7700c966b8610ccc63c3187a72e33cab53526a27b2a285a662cd4f7", size = 61578, upload-time = "2025-11-07T00:43:32.918Z" }, + { url = "https://files.pythonhosted.org/packages/5b/36/825b44c8a10556957bc0c1d84c7b29a40e05fcf1873b6c40aa9dbe0bd972/wrapt-2.0.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:df0b6d3b95932809c5b3fecc18fda0f1e07452d05e2662a0b35548985f256e28", size = 114115, upload-time = "2025-11-07T00:43:35.605Z" }, + { url = "https://files.pythonhosted.org/packages/83/73/0a5d14bb1599677304d3c613a55457d34c344e9b60eda8a737c2ead7619e/wrapt-2.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da7384b0e5d4cae05c97cd6f94faaf78cc8b0f791fc63af43436d98c4ab37bb", size = 116157, upload-time = "2025-11-07T00:43:37.058Z" }, + { url = "https://files.pythonhosted.org/packages/01/22/1c158fe763dbf0a119f985d945711d288994fe5514c0646ebe0eb18b016d/wrapt-2.0.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ec65a78fbd9d6f083a15d7613b2800d5663dbb6bb96003899c834beaa68b242c", size = 112535, upload-time = "2025-11-07T00:43:34.138Z" }, + { url = "https://files.pythonhosted.org/packages/5c/28/4f16861af67d6de4eae9927799b559c20ebdd4fe432e89ea7fe6fcd9d709/wrapt-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7de3cc939be0e1174969f943f3b44e0d79b6f9a82198133a5b7fc6cc92882f16", size = 115404, upload-time = "2025-11-07T00:43:39.214Z" }, + { url = "https://files.pythonhosted.org/packages/a0/8b/7960122e625fad908f189b59c4aae2d50916eb4098b0fb2819c5a177414f/wrapt-2.0.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:fb1a5b72cbd751813adc02ef01ada0b0d05d3dcbc32976ce189a1279d80ad4a2", size = 111802, upload-time = "2025-11-07T00:43:40.476Z" }, + { url = "https://files.pythonhosted.org/packages/3e/73/7881eee5ac31132a713ab19a22c9e5f1f7365c8b1df50abba5d45b781312/wrapt-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3fa272ca34332581e00bf7773e993d4f632594eb2d1b0b162a9038df0fd971dd", size = 113837, upload-time = "2025-11-07T00:43:42.921Z" }, + { url = "https://files.pythonhosted.org/packages/45/00/9499a3d14e636d1f7089339f96c4409bbc7544d0889f12264efa25502ae8/wrapt-2.0.1-cp311-cp311-win32.whl", hash = "sha256:fc007fdf480c77301ab1afdbb6ab22a5deee8885f3b1ed7afcb7e5e84a0e27be", size = 58028, upload-time = "2025-11-07T00:43:47.369Z" }, + { url = "https://files.pythonhosted.org/packages/70/5d/8f3d7eea52f22638748f74b102e38fdf88cb57d08ddeb7827c476a20b01b/wrapt-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:47434236c396d04875180171ee1f3815ca1eada05e24a1ee99546320d54d1d1b", size = 60385, upload-time = "2025-11-07T00:43:44.34Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/32195e57a8209003587bbbad44d5922f13e0ced2a493bb46ca882c5b123d/wrapt-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:837e31620e06b16030b1d126ed78e9383815cbac914693f54926d816d35d8edf", size = 58893, upload-time = "2025-11-07T00:43:46.161Z" }, + { url = "https://files.pythonhosted.org/packages/cb/73/8cb252858dc8254baa0ce58ce382858e3a1cf616acebc497cb13374c95c6/wrapt-2.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1fdbb34da15450f2b1d735a0e969c24bdb8d8924892380126e2a293d9902078c", size = 78129, upload-time = "2025-11-07T00:43:48.852Z" }, + { url = "https://files.pythonhosted.org/packages/19/42/44a0db2108526ee6e17a5ab72478061158f34b08b793df251d9fbb9a7eb4/wrapt-2.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3d32794fe940b7000f0519904e247f902f0149edbe6316c710a8562fb6738841", size = 61205, upload-time = "2025-11-07T00:43:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/4d/8a/5b4b1e44b791c22046e90d9b175f9a7581a8cc7a0debbb930f81e6ae8e25/wrapt-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:386fb54d9cd903ee0012c09291336469eb7b244f7183d40dc3e86a16a4bace62", size = 61692, upload-time = "2025-11-07T00:43:51.678Z" }, + { url = "https://files.pythonhosted.org/packages/11/53/3e794346c39f462bcf1f58ac0487ff9bdad02f9b6d5ee2dc84c72e0243b2/wrapt-2.0.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7b219cb2182f230676308cdcacd428fa837987b89e4b7c5c9025088b8a6c9faf", size = 121492, upload-time = "2025-11-07T00:43:55.017Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/10b7b0e8841e684c8ca76b462a9091c45d62e8f2de9c4b1390b690eadf16/wrapt-2.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:641e94e789b5f6b4822bb8d8ebbdfc10f4e4eae7756d648b717d980f657a9eb9", size = 123064, upload-time = "2025-11-07T00:43:56.323Z" }, + { url = "https://files.pythonhosted.org/packages/0e/d1/3c1e4321fc2f5ee7fd866b2d822aa89b84495f28676fd976c47327c5b6aa/wrapt-2.0.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe21b118b9f58859b5ebaa4b130dee18669df4bd111daad082b7beb8799ad16b", size = 117403, upload-time = "2025-11-07T00:43:53.258Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b0/d2f0a413cf201c8c2466de08414a15420a25aa83f53e647b7255cc2fab5d/wrapt-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17fb85fa4abc26a5184d93b3efd2dcc14deb4b09edcdb3535a536ad34f0b4dba", size = 121500, upload-time = "2025-11-07T00:43:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/bd/45/bddb11d28ca39970a41ed48a26d210505120f925918592283369219f83cc/wrapt-2.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b89ef9223d665ab255ae42cc282d27d69704d94be0deffc8b9d919179a609684", size = 116299, upload-time = "2025-11-07T00:43:58.877Z" }, + { url = "https://files.pythonhosted.org/packages/81/af/34ba6dd570ef7a534e7eec0c25e2615c355602c52aba59413411c025a0cb/wrapt-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a453257f19c31b31ba593c30d997d6e5be39e3b5ad9148c2af5a7314061c63eb", size = 120622, upload-time = "2025-11-07T00:43:59.962Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/693a13b4146646fb03254636f8bafd20c621955d27d65b15de07ab886187/wrapt-2.0.1-cp312-cp312-win32.whl", hash = "sha256:3e271346f01e9c8b1130a6a3b0e11908049fe5be2d365a5f402778049147e7e9", size = 58246, upload-time = "2025-11-07T00:44:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/a7/36/715ec5076f925a6be95f37917b66ebbeaa1372d1862c2ccd7a751574b068/wrapt-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:2da620b31a90cdefa9cd0c2b661882329e2e19d1d7b9b920189956b76c564d75", size = 60492, upload-time = "2025-11-07T00:44:01.027Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3e/62451cd7d80f65cc125f2b426b25fbb6c514bf6f7011a0c3904fc8c8df90/wrapt-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:aea9c7224c302bc8bfc892b908537f56c430802560e827b75ecbde81b604598b", size = 58987, upload-time = "2025-11-07T00:44:02.095Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/41af4c46b5e498c90fc87981ab2972fbd9f0bccda597adb99d3d3441b94b/wrapt-2.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:47b0f8bafe90f7736151f61482c583c86b0693d80f075a58701dd1549b0010a9", size = 78132, upload-time = "2025-11-07T00:44:04.628Z" }, + { url = "https://files.pythonhosted.org/packages/1c/92/d68895a984a5ebbbfb175512b0c0aad872354a4a2484fbd5552e9f275316/wrapt-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cbeb0971e13b4bd81d34169ed57a6dda017328d1a22b62fda45e1d21dd06148f", size = 61211, upload-time = "2025-11-07T00:44:05.626Z" }, + { url = "https://files.pythonhosted.org/packages/e8/26/ba83dc5ae7cf5aa2b02364a3d9cf74374b86169906a1f3ade9a2d03cf21c/wrapt-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb7cffe572ad0a141a7886a1d2efa5bef0bf7fe021deeea76b3ab334d2c38218", size = 61689, upload-time = "2025-11-07T00:44:06.719Z" }, + { url = "https://files.pythonhosted.org/packages/cf/67/d7a7c276d874e5d26738c22444d466a3a64ed541f6ef35f740dbd865bab4/wrapt-2.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8d60527d1ecfc131426b10d93ab5d53e08a09c5fa0175f6b21b3252080c70a9", size = 121502, upload-time = "2025-11-07T00:44:09.557Z" }, + { url = "https://files.pythonhosted.org/packages/0f/6b/806dbf6dd9579556aab22fc92908a876636e250f063f71548a8660382184/wrapt-2.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c654eafb01afac55246053d67a4b9a984a3567c3808bb7df2f8de1c1caba2e1c", size = 123110, upload-time = "2025-11-07T00:44:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/e5/08/cdbb965fbe4c02c5233d185d070cabed2ecc1f1e47662854f95d77613f57/wrapt-2.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:98d873ed6c8b4ee2418f7afce666751854d6d03e3c0ec2a399bb039cd2ae89db", size = 117434, upload-time = "2025-11-07T00:44:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/6aae2ce39db4cb5216302fa2e9577ad74424dfbe315bd6669725569e048c/wrapt-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9e850f5b7fc67af856ff054c71690d54fa940c3ef74209ad9f935b4f66a0233", size = 121533, upload-time = "2025-11-07T00:44:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/565abf57559fbe0a9155c29879ff43ce8bd28d2ca61033a3a3dd67b70794/wrapt-2.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e505629359cb5f751e16e30cf3f91a1d3ddb4552480c205947da415d597f7ac2", size = 116324, upload-time = "2025-11-07T00:44:13.28Z" }, + { url = "https://files.pythonhosted.org/packages/e1/e0/53ff5e76587822ee33e560ad55876d858e384158272cd9947abdd4ad42ca/wrapt-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2879af909312d0baf35f08edeea918ee3af7ab57c37fe47cb6a373c9f2749c7b", size = 120627, upload-time = "2025-11-07T00:44:14.431Z" }, + { url = "https://files.pythonhosted.org/packages/7c/7b/38df30fd629fbd7612c407643c63e80e1c60bcc982e30ceeae163a9800e7/wrapt-2.0.1-cp313-cp313-win32.whl", hash = "sha256:d67956c676be5a24102c7407a71f4126d30de2a569a1c7871c9f3cabc94225d7", size = 58252, upload-time = "2025-11-07T00:44:17.814Z" }, + { url = "https://files.pythonhosted.org/packages/85/64/d3954e836ea67c4d3ad5285e5c8fd9d362fd0a189a2db622df457b0f4f6a/wrapt-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9ca66b38dd642bf90c59b6738af8070747b610115a39af2498535f62b5cdc1c3", size = 60500, upload-time = "2025-11-07T00:44:15.561Z" }, + { url = "https://files.pythonhosted.org/packages/89/4e/3c8b99ac93527cfab7f116089db120fef16aac96e5f6cdb724ddf286086d/wrapt-2.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:5a4939eae35db6b6cec8e7aa0e833dcca0acad8231672c26c2a9ab7a0f8ac9c8", size = 58993, upload-time = "2025-11-07T00:44:16.65Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f4/eff2b7d711cae20d220780b9300faa05558660afb93f2ff5db61fe725b9a/wrapt-2.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a52f93d95c8d38fed0669da2ebdb0b0376e895d84596a976c15a9eb45e3eccb3", size = 82028, upload-time = "2025-11-07T00:44:18.944Z" }, + { url = "https://files.pythonhosted.org/packages/0c/67/cb945563f66fd0f61a999339460d950f4735c69f18f0a87ca586319b1778/wrapt-2.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e54bbf554ee29fcceee24fa41c4d091398b911da6e7f5d7bffda963c9aed2e1", size = 62949, upload-time = "2025-11-07T00:44:20.074Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ca/f63e177f0bbe1e5cf5e8d9b74a286537cd709724384ff20860f8f6065904/wrapt-2.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:908f8c6c71557f4deaa280f55d0728c3bca0960e8c3dd5ceeeafb3c19942719d", size = 63681, upload-time = "2025-11-07T00:44:21.345Z" }, + { url = "https://files.pythonhosted.org/packages/39/a1/1b88fcd21fd835dca48b556daef750952e917a2794fa20c025489e2e1f0f/wrapt-2.0.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e2f84e9af2060e3904a32cea9bb6db23ce3f91cfd90c6b426757cf7cc01c45c7", size = 152696, upload-time = "2025-11-07T00:44:24.318Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/d9185500c1960d9f5f77b9c0b890b7fc62282b53af7ad1b6bd779157f714/wrapt-2.0.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3612dc06b436968dfb9142c62e5dfa9eb5924f91120b3c8ff501ad878f90eb3", size = 158859, upload-time = "2025-11-07T00:44:25.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/60/5d796ed0f481ec003220c7878a1d6894652efe089853a208ea0838c13086/wrapt-2.0.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d2d947d266d99a1477cd005b23cbd09465276e302515e122df56bb9511aca1b", size = 146068, upload-time = "2025-11-07T00:44:22.81Z" }, + { url = "https://files.pythonhosted.org/packages/04/f8/75282dd72f102ddbfba137e1e15ecba47b40acff32c08ae97edbf53f469e/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7d539241e87b650cbc4c3ac9f32c8d1ac8a54e510f6dca3f6ab60dcfd48c9b10", size = 155724, upload-time = "2025-11-07T00:44:26.634Z" }, + { url = "https://files.pythonhosted.org/packages/5a/27/fe39c51d1b344caebb4a6a9372157bdb8d25b194b3561b52c8ffc40ac7d1/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4811e15d88ee62dbf5c77f2c3ff3932b1e3ac92323ba3912f51fc4016ce81ecf", size = 144413, upload-time = "2025-11-07T00:44:27.939Z" }, + { url = "https://files.pythonhosted.org/packages/83/2b/9f6b643fe39d4505c7bf926d7c2595b7cb4b607c8c6b500e56c6b36ac238/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c1c91405fcf1d501fa5d55df21e58ea49e6b879ae829f1039faaf7e5e509b41e", size = 150325, upload-time = "2025-11-07T00:44:29.29Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/20ffcf2558596a7f58a2e69c89597128781f0b88e124bf5a4cadc05b8139/wrapt-2.0.1-cp313-cp313t-win32.whl", hash = "sha256:e76e3f91f864e89db8b8d2a8311d57df93f01ad6bb1e9b9976d1f2e83e18315c", size = 59943, upload-time = "2025-11-07T00:44:33.211Z" }, + { url = "https://files.pythonhosted.org/packages/87/6a/0e56111cbb3320151eed5d3821ee1373be13e05b376ea0870711f18810c3/wrapt-2.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:83ce30937f0ba0d28818807b303a412440c4b63e39d3d8fc036a94764b728c92", size = 63240, upload-time = "2025-11-07T00:44:30.935Z" }, + { url = "https://files.pythonhosted.org/packages/1d/54/5ab4c53ea1f7f7e5c3e7c1095db92932cc32fd62359d285486d00c2884c3/wrapt-2.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:4b55cacc57e1dc2d0991dbe74c6419ffd415fb66474a02335cb10efd1aa3f84f", size = 60416, upload-time = "2025-11-07T00:44:32.002Z" }, + { url = "https://files.pythonhosted.org/packages/73/81/d08d83c102709258e7730d3cd25befd114c60e43ef3891d7e6877971c514/wrapt-2.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5e53b428f65ece6d9dad23cb87e64506392b720a0b45076c05354d27a13351a1", size = 78290, upload-time = "2025-11-07T00:44:34.691Z" }, + { url = "https://files.pythonhosted.org/packages/f6/14/393afba2abb65677f313aa680ff0981e829626fed39b6a7e3ec807487790/wrapt-2.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ad3ee9d0f254851c71780966eb417ef8e72117155cff04821ab9b60549694a55", size = 61255, upload-time = "2025-11-07T00:44:35.762Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/a4a1f2fba205a9462e36e708ba37e5ac95f4987a0f1f8fd23f0bf1fc3b0f/wrapt-2.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d7b822c61ed04ee6ad64bc90d13368ad6eb094db54883b5dde2182f67a7f22c0", size = 61797, upload-time = "2025-11-07T00:44:37.22Z" }, + { url = "https://files.pythonhosted.org/packages/12/db/99ba5c37cf1c4fad35349174f1e38bd8d992340afc1ff27f526729b98986/wrapt-2.0.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7164a55f5e83a9a0b031d3ffab4d4e36bbec42e7025db560f225489fa929e509", size = 120470, upload-time = "2025-11-07T00:44:39.425Z" }, + { url = "https://files.pythonhosted.org/packages/30/3f/a1c8d2411eb826d695fc3395a431757331582907a0ec59afce8fe8712473/wrapt-2.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e60690ba71a57424c8d9ff28f8d006b7ad7772c22a4af432188572cd7fa004a1", size = 122851, upload-time = "2025-11-07T00:44:40.582Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8d/72c74a63f201768d6a04a8845c7976f86be6f5ff4d74996c272cefc8dafc/wrapt-2.0.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3cd1a4bd9a7a619922a8557e1318232e7269b5fb69d4ba97b04d20450a6bf970", size = 117433, upload-time = "2025-11-07T00:44:38.313Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5a/df37cf4042cb13b08256f8e27023e2f9b3d471d553376616591bb99bcb31/wrapt-2.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b4c2e3d777e38e913b8ce3a6257af72fb608f86a1df471cb1d4339755d0a807c", size = 121280, upload-time = "2025-11-07T00:44:41.69Z" }, + { url = "https://files.pythonhosted.org/packages/54/34/40d6bc89349f9931e1186ceb3e5fbd61d307fef814f09fbbac98ada6a0c8/wrapt-2.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3d366aa598d69416b5afedf1faa539fac40c1d80a42f6b236c88c73a3c8f2d41", size = 116343, upload-time = "2025-11-07T00:44:43.013Z" }, + { url = "https://files.pythonhosted.org/packages/70/66/81c3461adece09d20781dee17c2366fdf0cb8754738b521d221ca056d596/wrapt-2.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c235095d6d090aa903f1db61f892fffb779c1eaeb2a50e566b52001f7a0f66ed", size = 119650, upload-time = "2025-11-07T00:44:44.523Z" }, + { url = "https://files.pythonhosted.org/packages/46/3a/d0146db8be8761a9e388cc9cc1c312b36d583950ec91696f19bbbb44af5a/wrapt-2.0.1-cp314-cp314-win32.whl", hash = "sha256:bfb5539005259f8127ea9c885bdc231978c06b7a980e63a8a61c8c4c979719d0", size = 58701, upload-time = "2025-11-07T00:44:48.277Z" }, + { url = "https://files.pythonhosted.org/packages/1a/38/5359da9af7d64554be63e9046164bd4d8ff289a2dd365677d25ba3342c08/wrapt-2.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:4ae879acc449caa9ed43fc36ba08392b9412ee67941748d31d94e3cedb36628c", size = 60947, upload-time = "2025-11-07T00:44:46.086Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3f/96db0619276a833842bf36343685fa04f987dd6e3037f314531a1e00492b/wrapt-2.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:8639b843c9efd84675f1e100ed9e99538ebea7297b62c4b45a7042edb84db03e", size = 59359, upload-time = "2025-11-07T00:44:47.164Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/5f5d1e867bf2064bf3933bc6cf36ade23505f3902390e175e392173d36a2/wrapt-2.0.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:9219a1d946a9b32bb23ccae66bdb61e35c62773ce7ca6509ceea70f344656b7b", size = 82031, upload-time = "2025-11-07T00:44:49.4Z" }, + { url = "https://files.pythonhosted.org/packages/2b/89/0009a218d88db66ceb83921e5685e820e2c61b59bbbb1324ba65342668bc/wrapt-2.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fa4184e74197af3adad3c889a1af95b53bb0466bced92ea99a0c014e48323eec", size = 62952, upload-time = "2025-11-07T00:44:50.74Z" }, + { url = "https://files.pythonhosted.org/packages/ae/18/9b968e920dd05d6e44bcc918a046d02afea0fb31b2f1c80ee4020f377cbe/wrapt-2.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c5ef2f2b8a53b7caee2f797ef166a390fef73979b15778a4a153e4b5fedce8fa", size = 63688, upload-time = "2025-11-07T00:44:52.248Z" }, + { url = "https://files.pythonhosted.org/packages/a6/7d/78bdcb75826725885d9ea26c49a03071b10c4c92da93edda612910f150e4/wrapt-2.0.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e042d653a4745be832d5aa190ff80ee4f02c34b21f4b785745eceacd0907b815", size = 152706, upload-time = "2025-11-07T00:44:54.613Z" }, + { url = "https://files.pythonhosted.org/packages/dd/77/cac1d46f47d32084a703df0d2d29d47e7eb2a7d19fa5cbca0e529ef57659/wrapt-2.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2afa23318136709c4b23d87d543b425c399887b4057936cd20386d5b1422b6fa", size = 158866, upload-time = "2025-11-07T00:44:55.79Z" }, + { url = "https://files.pythonhosted.org/packages/8a/11/b521406daa2421508903bf8d5e8b929216ec2af04839db31c0a2c525eee0/wrapt-2.0.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c72328f668cf4c503ffcf9434c2b71fdd624345ced7941bc6693e61bbe36bef", size = 146148, upload-time = "2025-11-07T00:44:53.388Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c0/340b272bed297baa7c9ce0c98ef7017d9c035a17a6a71dce3184b8382da2/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3793ac154afb0e5b45d1233cb94d354ef7a983708cc3bb12563853b1d8d53747", size = 155737, upload-time = "2025-11-07T00:44:56.971Z" }, + { url = "https://files.pythonhosted.org/packages/f3/93/bfcb1fb2bdf186e9c2883a4d1ab45ab099c79cbf8f4e70ea453811fa3ea7/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fec0d993ecba3991645b4857837277469c8cc4c554a7e24d064d1ca291cfb81f", size = 144451, upload-time = "2025-11-07T00:44:58.515Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6b/dca504fb18d971139d232652656180e3bd57120e1193d9a5899c3c0b7cdd/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:949520bccc1fa227274da7d03bf238be15389cd94e32e4297b92337df9b7a349", size = 150353, upload-time = "2025-11-07T00:44:59.753Z" }, + { url = "https://files.pythonhosted.org/packages/1d/f6/a1de4bd3653afdf91d250ca5c721ee51195df2b61a4603d4b373aa804d1d/wrapt-2.0.1-cp314-cp314t-win32.whl", hash = "sha256:be9e84e91d6497ba62594158d3d31ec0486c60055c49179edc51ee43d095f79c", size = 60609, upload-time = "2025-11-07T00:45:03.315Z" }, + { url = "https://files.pythonhosted.org/packages/01/3a/07cd60a9d26fe73efead61c7830af975dfdba8537632d410462672e4432b/wrapt-2.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:61c4956171c7434634401db448371277d07032a81cc21c599c22953374781395", size = 64038, upload-time = "2025-11-07T00:45:00.948Z" }, + { url = "https://files.pythonhosted.org/packages/41/99/8a06b8e17dddbf321325ae4eb12465804120f699cd1b8a355718300c62da/wrapt-2.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:35cdbd478607036fee40273be8ed54a451f5f23121bd9d4be515158f9498f7ad", size = 60634, upload-time = "2025-11-07T00:45:02.087Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, +] + +[[package]] +name = "wsproto" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/79/12135bdf8b9c9367b8701c2c19a14c913c120b882d50b014ca0d38083c2c/wsproto-1.3.2.tar.gz", hash = "sha256:b86885dcf294e15204919950f666e06ffc6c7c114ca900b060d6e16293528294", size = 50116, upload-time = "2025-11-20T18:18:01.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl", hash = "sha256:61eea322cdf56e8cc904bd3ad7573359a242ba65688716b0710a5eb12beab584", size = 24405, upload-time = "2025-11-20T18:18:00.454Z" }, +]