diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a1715720..1ddbe74c 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -5,4 +5,10 @@ aae30e864449442cf0b04e94f8a242b1b667de9a 16dc3153b3cb684ca72445ed058babc8f5d97f42 # chore(linting): lint all C++ files -58cd4b45777b046f03a63255c1d93e289e1cab5e \ No newline at end of file +58cd4b45777b046f03a63255c1d93e289e1cab5e + +# chore(linting): lint PyBytesProxyHandler.cc +d540ed6e0edfe9538dc726cf587dfb2cc76dde34 + +# chore(linting): lint PyObjectProxyHandler.cc +1d45ea98e42294cce16deec5454725d4de36f59f \ No newline at end of file diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 99383de8..ad562623 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -5,7 +5,7 @@ on: branches: - main tags: - - '*' + - 'v*' workflow_call: workflow_dispatch: inputs: @@ -15,10 +15,10 @@ on: required: false options: - '' - - 'ubuntu-20.04' - - 'macos-12' + - 'ubuntu-22.04' + - 'macos-15-intel' - 'macos-14' - - 'windows-2019' + - 'windows-2022' debug_enabled_python: type: choice description: Choose a Python version to run the build with SSH debugging on @@ -30,6 +30,8 @@ on: - '3.10' - '3.11' - '3.12' + - '3.13' + - '3.14' build_type: type: choice description: 'Choose the build type to use' @@ -48,55 +50,107 @@ env: # don't upgrade outdated brew packages because the process is too slow HOMEBREW_NO_INSTALL_UPGRADE: 1 HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 + # apt-get should run in noninteractive mode + DEBIAN_FRONTEND: noninteractive defaults: run: # run with Git Bash on Windows shell: bash +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build-spidermonkey-unix: strategy: fail-fast: false matrix: - # Use Ubuntu 20.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-20.04', 'macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares - # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available + # Use Ubuntu 22.04 / macOS 15 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey + os: [ 'ubuntu-22.04', 'macos-15-intel', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares + # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} + container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python_version }} + - name: Read the mozilla-central commit hash to be used + run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV - name: Cache spidermonkey build id: cache-spidermonkey uses: actions/cache@v4 with: path: | ./_spidermonkey_install/* - key: spidermonkey115.8.0-${{ runner.os }}-${{ runner.arch }} - lookup-only: true # skip download + key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} + - name: Setup container + if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + run: | + apt-get update -y + apt-get install -y sudo libnss3-dev libssl-dev + apt-get install -y curl make git build-essential + apt-get install -y zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata + echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 + - name: Setup LLVM + if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + run: | + apt-get install -y llvm clang + apt-get install -y lsb-release wget software-properties-common gnupg + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + ./llvm.sh 18 # install LLVM version 18 + update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-18 18 + update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 18 + update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 18 + clang --version + clang++ --version + - name: Setup Python + if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + run: | + # Use pyenv to install Python version that is not available via `actions/setup-python` + unset PYENV_ROOT + curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash + echo "$HOME/.pyenv/bin" >> $GITHUB_PATH # ~/.bashrc file is not read, so we need to add to GITHUB_PATH manually + echo "$HOME/.pyenv/shims" >> $GITHUB_PATH + echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV + export PATH="$HOME/.pyenv/bin:$PATH" + pyenv install $PYTHON_VERSION + pyenv global $PYTHON_VERSION + env: + PYTHON_VERSION: ${{ matrix.python_version }} + - uses: actions/setup-python@v5 + if: ${{ !startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + with: + python-version: ${{ matrix.python_version }} - name: Setup XCode - if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # SpiderMonkey 115 ESR requires XCode SDK version at least 13.3 - # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks - run: sudo xcode-select -switch /Applications/Xcode_14.3.app + if: ${{ matrix.os == 'macos-15-intel' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + # Xcode 16.x removed the old linker behaviour (-ld64 or -ld_classic) that SpiderMonkey relies on, so we need to switch to an older version + run: sudo xcode-select -switch /Applications/Xcode_16.0.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh + - name: Upload spidermonkey build as CI artifacts + uses: actions/upload-artifact@v4 + with: + name: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} + path: ./_spidermonkey_install/ build-spidermonkey-win: - runs-on: windows-2019 + runs-on: windows-2022 + # SpiderMonkey requires Visual Studio 2022 or newer. + # The Windows 2019 runner only has Visual Studio Enterprise 2019 installed. steps: - uses: actions/checkout@v4 + - name: Read the mozilla-central commit hash to be used + run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV - name: Cache spidermonkey build id: cache-spidermonkey uses: actions/cache@v4 with: path: | ./_spidermonkey_install/* - key: spidermonkey115.8.0-${{ runner.os }}-${{ runner.arch }} - lookup-only: true # skip download + key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} - name: Install dependencies if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} shell: powershell @@ -104,7 +158,7 @@ jobs: # Already installed in Github Actions runner # choco install -y cmake --installargs 'ADD_CMAKE_TO_PATH=System' # add CMake to system PATH # choco install -y llvm gnuwin32-m4 - choco install -y wget make + choco install -y wget make unzip - name: Install MozillaBuild if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | @@ -117,29 +171,61 @@ jobs: # see https://groups.google.com/u/1/a/mozilla.org/g/dev-platform/c/hF51Q3j6ca8 USE_MINTTY: 0 run: /c/mozilla-build/start-shell.bat -use-full-path -here ./setup.sh + - name: Upload spidermonkey build as CI artifacts + uses: actions/upload-artifact@v4 + with: + name: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} + path: ./_spidermonkey_install/ build-and-test: needs: [build-spidermonkey-unix, build-spidermonkey-win] strategy: fail-fast: false matrix: - # The lowest supported version is Ubuntu 20.04 + Python 3.8 or macOS 12 + Python 3.9 - os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2019' ] - python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] - exclude: - # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. - # see https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json - - os: 'macos-14' - python_version: '3.8' - - os: 'macos-14' - python_version: '3.9' + os: [ 'ubuntu-22.04', 'macos-15-intel', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] + python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ] runs-on: ${{ matrix.os }} + container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} steps: + - name: Setup container + if: ${{ startsWith(matrix.os, 'ubuntu') }} + run: | + apt-get update -y + apt-get install -y sudo libnss3-dev libssl-dev + apt-get install -y curl zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv + apt-get install -y git # required for `actions/checkout` + apt-get install -y nodejs npm # required for pminit to build + apt-get install -y build-essential + apt-get install -y strace # required to run JS tests + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here + echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 + git config --global --add safe.directory '*' # silence "git failed because of dubious ownership" + + # CMake 3.25 or higher is required + apt-get install -y ca-certificates gpg wget + wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null + echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null + apt-get update -y && apt-get install -y cmake - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 # fetch all history for all branches and tags # poetry-dynamic-versioning needs git tags to produce the correct version number + - name: Setup Python + if: ${{ startsWith(matrix.os, 'ubuntu') }} + run: | + # Use pyenv to install Python version that is not available via `actions/setup-python` + unset PYENV_ROOT + curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash + echo "$HOME/.pyenv/bin" >> $GITHUB_PATH # ~/.bashrc file is not read, so we need to add to GITHUB_PATH manually + echo "$HOME/.pyenv/shims" >> $GITHUB_PATH + echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV + export PATH="$HOME/.pyenv/bin:$PATH" + pyenv install $PYTHON_VERSION + pyenv global $PYTHON_VERSION + env: + PYTHON_VERSION: ${{ matrix.python_version }} - uses: actions/setup-python@v5 + if: ${{ !startsWith(matrix.os, 'ubuntu') }} with: python-version: ${{ matrix.python_version }} - name: Setup Poetry @@ -154,15 +240,18 @@ jobs: sudo apt-get install -y cmake llvm elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS brew update || true # allow failure - brew install cmake pkg-config wget coreutils # `coreutils` installs the `realpath` command + brew install cmake pkg-config wget unzip coreutils # `coreutils` installs the `realpath` command fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" - poetry env use python3 # use the correct Python version we've set up + echo "Use the correct Python version we've set up" + poetry env use python$PYTHON_VERSION || poetry env use python3 # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" + env: + PYTHON_VERSION: ${{ matrix.python_version }} - name: Build Docs # only build docs once - if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} + if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python_version == '3.11' }} run: | sudo apt-get install -y graphviz # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series @@ -172,17 +261,19 @@ jobs: rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz BUILD_DOCS=1 BUILD_TYPE=None poetry install - name: Upload Doxygen-generated docs as CI artifacts - if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} - uses: actions/upload-artifact@v3 + if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python_version == '3.11' }} + uses: actions/upload-artifact@v4 with: name: docs-${{ github.run_id }}-${{ github.sha }} path: ./build/docs/html/ + - name: Read the mozilla-central commit hash to be used + run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV - name: Use cached spidermonkey build uses: actions/cache@v4 with: path: | ./_spidermonkey_install/* - key: spidermonkey115.8.0-${{ runner.os }}-${{ runner.arch }} + key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} fail-on-cache-miss: true # SpiderMonkey is expected to be cached in its dedicated job - name: Build pminit run: | @@ -197,54 +288,38 @@ jobs: WORKFLOW_BUILD_TYPE=${{ inputs.build_type }} BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry build --format=wheel ls -lah ./dist/ + - name: Make the wheels we build also support lower versions of macOS + if: ${{ matrix.os == 'macos-15-intel' || matrix.os == 'macos-14' }} + # Change the platform tag part of the wheel filename to `macosx_11_0_xxx` (means to support macOS 11.0 and above) + # See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format + # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. + # Otherwise, pip would fallback to compile from the source distribution. + run: | + cd ./dist/ + for file in *.whl; do + mv "$file" "$(echo "$file" | sed -E 's/macosx_[0-9]+_[0-9]+/macosx_11_0/')"; + done - name: Upload wheel as CI artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + name: wheel-${{ github.run_id }}-${{ github.sha }}-${{ runner.os }}_${{ runner.arch }}_Python${{ matrix.python_version }} path: ./dist/ - - name: Set cores to get stored in /cores - if: ${{ matrix.os != 'windows-2019' }} - # TODO (Caleb Aikens) figure out how to get Windows core dumps - run: | - sudo mkdir -p /cores - sudo chmod 777 /cores - # Core filenames will be of the form osname.pythonversion.executable.pid.timestamp: - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - sudo bash -c 'echo "/cores/${OSTYPE}.$(poetry run python --version).%e.%p.%t" > /proc/sys/kernel/core_pattern' - else - sudo sysctl kern.corefile="/cores/${OSTYPE}.$(poetry run python --version).%e.%p.%y" - fi - name: Run Python tests (pytest) run: | - if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]]; then - # TODO (Caleb Aikens) figure out how to get Windows core dumps - ulimit -c unlimited - fi WORKFLOW_BUILD_TYPE=${{ inputs.build_type }} BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry run python -m pip install --force-reinstall --verbose ./dist/* poetry run python -m pytest tests/python - name: Run JS tests (peter-jr) if: ${{ (success() || failure()) }} run: | - if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]]; then - # TODO (Caleb Aikens) figure out how to get Windows core dumps - ulimit -c unlimited - fi poetry run bash ./peter-jr ./tests/js/ - name: SSH debug session if: ${{ (success() || failure()) && github.event_name == 'workflow_dispatch' && inputs.debug_enabled_os == matrix.os && inputs.debug_enabled_python == matrix.python_version}} uses: fawazahmed0/action-debug@main with: credentials: "admin:admin" - - name: Upload core dumps as CI artifacts - uses: actions/upload-artifact@v3 - if: ${{ matrix.os != 'windows-2019' && failure() }} - # TODO (Caleb Aikens) figure out how to get Windows core dumps - with: - name: cores-${{ matrix.os }}-${{ matrix.python_version }} - path: /cores sdist: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: @@ -262,14 +337,14 @@ jobs: poetry build --format=sdist ls -lah ./dist/ - name: Upload sdist as CI artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + name: wheel-${{ github.run_id }}-${{ github.sha }}-sdist path: ./dist/ publish: needs: [build-and-test, sdist] - runs-on: ubuntu-20.04 - if: ${{ success() && github.event_name == 'push' && contains(github.ref, 'refs/tags/') }} + runs-on: ubuntu-22.04 + if: ${{ success() && github.event_name == 'push' && github.ref_type == 'tag' }} steps: # no need to checkout - uses: actions/setup-python@v5 @@ -277,9 +352,10 @@ jobs: python-version: '3.9' - run: pip install twine - name: Download wheels built - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + pattern: wheel-${{ github.run_id }}-${{ github.sha }}-* + merge-multiple: true path: ./dist/ - run: ls -lah ./dist/ - name: Publish package @@ -291,8 +367,8 @@ jobs: # Implement a very basic Python package repository (https://peps.python.org/pep-0503/) # and deploy the static files to GitHub Pages needs: [build-and-test, sdist] - runs-on: ubuntu-20.04 - if: ${{ (success() || failure()) && github.ref_name == 'main' }} # publish nightly builds regardless of tests failure + runs-on: ubuntu-22.04 + if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }} # publish nightly builds regardless of tests failure permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment pages: write id-token: write @@ -302,12 +378,13 @@ jobs: steps: # don't checkout - name: Download wheels built - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + pattern: wheel-${{ github.run_id }}-${{ github.sha }}-* + merge-multiple: true path: ./dist/ - name: Download docs html generated by Doxygen - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: docs-${{ github.run_id }}-${{ github.sha }} path: ./docs/ @@ -341,9 +418,52 @@ jobs: html+="
  • pminit
  • " html+="" echo "$html" > ./index.html - - uses: actions/upload-pages-artifact@v1 + - uses: actions/upload-pages-artifact@v3 with: path: ./ - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 + publish-archive: + # Publish to ⊇istributive's archive server (https://archive.distributed.computer/releases/pythonmonkey/) + needs: [build-and-test, sdist] + runs-on: ubuntu-22.04 + if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }} + environment: + name: archive + url: https://archive.distributed.computer/releases/pythonmonkey/${{ steps.get_path.outputs.ARCHIVE_PATH }} + steps: + # no need to checkout + - name: Download wheels built + uses: actions/download-artifact@v4 + with: + pattern: wheel-${{ github.run_id }}-${{ github.sha }}-* + merge-multiple: true + path: ./ + - name: Download docs html generated by Doxygen + uses: actions/download-artifact@v4 + with: + name: docs-${{ github.run_id }}-${{ github.sha }} + path: ./docs/ + - name: Get the pythonmonkey/pminit version number + run: | + file=$(ls ./pminit*.tar.gz | head -1) + pm_version=$(basename "${file%.tar.gz}" | cut -d- -f2) # match /pminit-([^-]+).tar.gz/ + echo "PM_VERSION=$pm_version" >> $GITHUB_ENV + - name: Get the archive type (nightly or releases) and path + id: get_path + run: | + path="$ARCHIVE_TYPE/$PM_VERSION/" + echo "$path" + echo "ARCHIVE_PATH=$path" >> $GITHUB_OUTPUT + env: + ARCHIVE_TYPE: ${{ (github.ref_type == 'tag' && 'releases') || 'nightly' }} + - name: SCP to the archive server + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.ARCHIVE_HOST }} + username: pythonmonkey + key: ${{ secrets.ARCHIVE_KEY }} + source: ./* + target: archive/${{ steps.get_path.outputs.ARCHIVE_PATH }} + overwrite: true diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml new file mode 100644 index 00000000..ec3c6a41 --- /dev/null +++ b/.github/workflows/update-mozcentral-version.yaml @@ -0,0 +1,43 @@ +name: 'Create pull requests to update mozilla-central version to the latest' + +on: + # schedule: + # - cron: "00 14 */100,1-7 * 1" # run on the first Monday of each month at 14:00 UTC (10:00 Eastern Daylight Time) + # See https://blog.healthchecks.io/2022/09/schedule-cron-job-the-funky-way/ + workflow_call: + workflow_dispatch: # or you can run it manually + +defaults: + run: + shell: bash + +jobs: + update: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - name: Check Version + # Check the latest changes on mozilla-central via the Mercurial pushlog HTTP API + # See https://mozilla-version-control-tools.readthedocs.io/en/latest/hgmo/pushlog.html#hgweb-commands + run: | + COMMIT_HASH=$( + curl -L -s "https://hg.mozilla.org/mozilla-central/json-pushes?tipsonly=1&version=2" |\ + jq --join-output '(.lastpushid | tostring) as $pushid | empty, .pushes[$pushid].changesets[0]' + ) + echo "MOZCENTRAL_VERSION=$COMMIT_HASH" >> $GITHUB_ENV + echo "MOZCENTRAL_VERSION_SHORT=${COMMIT_HASH:0:7}" >> $GITHUB_ENV + - name: Update `mozcentral.version` File + run: echo -n $MOZCENTRAL_VERSION > mozcentral.version + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6 + with: + add-paths: mozcentral.version + commit-message: | + chore(deps): upgrade SpiderMonkey to `${{ env.MOZCENTRAL_VERSION }}` + author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + branch: chore/upgrade-spidermonkey-to-${{ env.MOZCENTRAL_VERSION_SHORT }} + title: Upgrade SpiderMonkey to mozilla-central commit `${{ env.MOZCENTRAL_VERSION }}` + body: | + Changeset: https://hg.mozilla.org/mozilla-central/rev/${{ env.MOZCENTRAL_VERSION }} + labels: dependencies + assignees: Xmader diff --git a/.gitignore b/.gitignore index 00be16f6..8f796a40 100644 --- a/.gitignore +++ b/.gitignore @@ -7,13 +7,16 @@ lib/* .pytest_cache .DS_Store firefox-*.tar.xz +firefox-*.zip firefox-*/ +mozilla-central-* __pycache__ Testing/Temporary -_spidermonkey_install +_spidermonkey_install* uncrustify-*.tar.gz uncrustify-*/ uncrustify +uncrustify.exe *.uncrustify __pycache__/* dist diff --git a/Makefile b/Makefile index a15c4035..5eece9f1 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ else ifeq ($(BUILD),Debug) PYTHON_BUILD_ENV += BUILD_TYPE=Debug else ifeq ($(BUILD),DRelease) PYTHON_BUILD_ENV += BUILD_TYPE=DRelease -else ifeq($(BUILD), None) +else ifeq ($(BUILD), None) PYTHON_BUILD_ENV += BUILD_TYPE=None else # Release build PYTHON_BUILD_ENV += BUILD_TYPE=Release diff --git a/README.md b/README.md index 1b799f0c..31e6efac 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PythonMonkey -![Testing Suite](https://github.com/Kings-Distributed-Systems/PythonMonkey/actions/workflows/tests.yaml/badge.svg) +[![Test and Publish Suite](https://github.com/Distributive-Network/PythonMonkey/actions/workflows/test-and-publish.yaml/badge.svg)](https://github.com/Distributive-Network/PythonMonkey/actions/workflows/test-and-publish.yaml) ## About [PythonMonkey](https://pythonmonkey.io) is a Mozilla [SpiderMonkey](https://firefox-source-docs.mozilla.org/js/index.html) JavaScript engine embedded into the Python Runtime, @@ -8,7 +8,7 @@ using the Python engine to provide the Javascript host environment. We feature JavaScript Array and Object methods implemented on Python List and Dictionaries using the cPython C API, and the inverse using the Mozilla Firefox Spidermonkey JavaScript C++ API. -This product is in an advanced stage, approximately 95% to MVP as of March 2024. It is under active development by [Distributive](https://distributive.network/). +This project has reached MVP as of September 2024. It is under maintenance by [Distributive](https://distributive.network/). External contributions and feedback are welcome and encouraged. @@ -59,7 +59,7 @@ js_eval("console.log")('hello, world') - [done] JS TypedArrays coerce to Python TypeArrays - [done] Python lists coerce to JS Arrays - [done] JS arrays coerce to Python lists -- [90%] PythonMonkey can run the dcp-client npm package from Distributive. +- [done] PythonMonkey can run the dcp-client npm package from Distributive. ## Build Instructions @@ -73,7 +73,7 @@ Read this if you want to build a local version. - llvm - rust - python3.8 or later with header files (python3-dev) - - spidermonkey 115.1.0 or later + - spidermonkey latest from mozilla-central - npm (nodejs) - [Poetry](https://python-poetry.org/docs/#installation) - [poetry-dynamic-versioning](https://github.com/mtkennerly/poetry-dynamic-versioning) @@ -136,6 +136,15 @@ $ poetry build --format=wheel ``` and install them by `pip install ./dist/*`. +## Uninstallation + +Installing `pythonmonkey` will also install the `pminit` package as a dependency. However, `pip uninstall`ing a package won't automatically remove its dependencies. +If you want to cleanly remove `pythonmonkey` from your system, do the following: + +```bash +$ pip uninstall pythonmonkey pminit +``` + ## Debugging Steps 1. [build the project locally](#build-instructions) @@ -164,11 +173,11 @@ They are largely based on SpiderMonkey's `CompileOptions`. The supported option - `filename`: set the filename of this code for the purposes of generating stack traces etc. - `lineno`: set the line number offset of this code for the purposes of generating stack traces etc. - `column`: set the column number offset of this code for the purposes of generating stack traces etc. -- `mutedErrors`: experimental -- `noScriptRval`: experimental -- `selfHosting`: experimental -- `strict`: experimental -- `module`: experimental +- `mutedErrors`: if set to `True`, eval errors or unhandled rejections are ignored ("muted"). Default `False`. +- `noScriptRval`: if `False`, return the last expression value of the script as the result value to the caller. Default `False`. +- `selfHosting`: *experimental* +- `strict`: forcibly evaluate in strict mode (`"use strict"`). Default `False`. +- `module`: indicate the file is an ECMAScript module (always strict mode code and disallow HTML comments). Default `False`. - `fromPythonFrame`: generate the equivalent of filename, lineno, and column based on the location of the Python call to eval. This makes it possible to evaluate Python multiline string literals and generate stack traces in JS pointing to the error in the Python source file. @@ -462,7 +471,7 @@ List of commands: ```console $ pmjs -Welcome to PythonMonkey v0.4.0. +Welcome to PythonMonkey v1.0.0. Type ".help" for more information. > .python import sys > .python sys.path diff --git a/cmake/modules/FindSpiderMonkey.cmake b/cmake/modules/FindSpiderMonkey.cmake index ab5ae2a2..84fca1ca 100644 --- a/cmake/modules/FindSpiderMonkey.cmake +++ b/cmake/modules/FindSpiderMonkey.cmake @@ -24,8 +24,6 @@ # SPIDERMONKEY_FOUND - True if SpiderMonkey found. # SPIDERMONKEY_THREADSAFE - True if SpiderMonkey is compiled with multi threading support. -#Last Change: 2022-10-03 (Caleb Aikens) - include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) @@ -36,11 +34,26 @@ if(SPIDERMONKEY_FOUND) set(SPIDERMONKEY_FIND_QUIETLY TRUE) endif() +# Get the SpiderMonkey major version number +# See https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/old-configure.in#l1081 +file(GLOB LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install") +execute_process(COMMAND + "sh" "-c" "./js*-config --version" # Run "_spidermonkey_install/bin/js*-config --version" to print the full version number + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/bin" + OUTPUT_VARIABLE MOZILLA_VERSION +) +string(STRIP ${MOZILLA_VERSION} MOZILLA_VERSION) +string(REGEX REPLACE "^([0-9]+)(\\.[0-9]+)*([ab][0-9]|)?" # Only the MAJOR and the "a1" (indicator of nightly build) part is needed + "\\1\\3" # see https://hg.mozilla.org/releases/mozilla-esr102/file/tip/build/moz.configure/init.configure#l959 + MOZILLA_SYMBOLVERSION + ${MOZILLA_VERSION} +) + # SpiderMonkey search paths set(SPIDERMONKEY_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install" "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/lib" - "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/include/mozjs-115" + "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/include/mozjs-${MOZILLA_SYMBOLVERSION}" ${SPIDERMONKEY_ROOT} $ENV{SPIDERMONKEY_ROOT} ~/Library/Frameworks @@ -60,7 +73,7 @@ set(SPIDERMONKEY_PATHS set(SPIDERMONKEY_HEADERS jsapi.h js/RequiredDefines.h) # SpiderMonkey include suffix paths -set(SPIDERMONKEY_INCLUDE_SUFFIX_PATHS include/mozjs-115/) +set(SPIDERMONKEY_INCLUDE_SUFFIX_PATHS include/mozjs-${MOZILLA_SYMBOLVERSION}/) # Find SpiderMonkey include path find_path(SPIDERMONKEY_INCLUDE_DIR ${SPIDERMONKEY_HEADERS} @@ -71,7 +84,7 @@ find_path(SPIDERMONKEY_INCLUDE_DIR ${SPIDERMONKEY_HEADERS} ) # SpiderMonkey libs -set(SPIDERMONKEY_LIBRARY_NAMES libmozjs-115.so libmozjs-115.dylib mozjs-115.lib) +set(SPIDERMONKEY_LIBRARY_NAMES libmozjs-${MOZILLA_SYMBOLVERSION}.so libmozjs-${MOZILLA_SYMBOLVERSION}.dylib mozjs-${MOZILLA_SYMBOLVERSION}.lib) set(SPIDERMONKEY_LIB_SUFFIX_PATHS js/src/build lib) diff --git a/include/JSArrayProxy.hh b/include/JSArrayProxy.hh index 6cf98ea0..0f452708 100644 --- a/include/JSArrayProxy.hh +++ b/include/JSArrayProxy.hh @@ -251,11 +251,10 @@ public: * * @param self - The JSArrayProxy * @param args - arguments to the sort method (not used) - * @param nargs - number of arguments to the sort method - * @param kwnames - keyword arguments to the sort method (reverse=True|False, key=keyfunction) + * @param kwargs - keyword arguments to the sort method (reverse=True|False, key=keyfunction) * @return PyObject* NULL on exception, None otherwise */ - static PyObject *JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames); + static PyObject *JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs); /** * @brief tp_traverse @@ -404,7 +403,7 @@ static PyMethodDef JSArrayProxy_methods[] = { {"index", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_index, METH_FASTCALL, list_index__doc__}, {"count", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_count, METH_O, list_count__doc__}, {"reverse", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_reverse, METH_NOARGS, list_reverse__doc__}, - {"sort", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_sort, METH_FASTCALL|METH_KEYWORDS, list_sort__doc__}, + {"sort", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_sort, METH_VARARGS|METH_KEYWORDS, list_sort__doc__}, {NULL, NULL} /* sentinel */ }; diff --git a/include/JSObjectItemsProxy.hh b/include/JSObjectItemsProxy.hh index f71e297e..59d16517 100644 --- a/include/JSObjectItemsProxy.hh +++ b/include/JSObjectItemsProxy.hh @@ -14,6 +14,7 @@ #include #include +#include "include/pyshim.hh" /** diff --git a/include/JSObjectKeysProxy.hh b/include/JSObjectKeysProxy.hh index bffdb18b..e2a8beef 100644 --- a/include/JSObjectKeysProxy.hh +++ b/include/JSObjectKeysProxy.hh @@ -14,6 +14,7 @@ #include #include +#include "include/pyshim.hh" /** diff --git a/include/JSObjectValuesProxy.hh b/include/JSObjectValuesProxy.hh index 8cb40034..17c2af23 100644 --- a/include/JSObjectValuesProxy.hh +++ b/include/JSObjectValuesProxy.hh @@ -14,6 +14,7 @@ #include #include +#include "include/pyshim.hh" /** diff --git a/include/JSStringProxy.hh b/include/JSStringProxy.hh index 8c82374c..ed696c19 100644 --- a/include/JSStringProxy.hh +++ b/include/JSStringProxy.hh @@ -15,15 +15,62 @@ #include +#include + /** * @brief The typedef for the backing store that will be used by JSStringProxy objects. All it contains is a pointer to the JSString * */ typedef struct { PyUnicodeObject str; - JS::PersistentRootedValue jsString; + JS::PersistentRootedValue *jsString; } JSStringProxy; +extern std::unordered_set jsStringProxies; // a collection of all JSStringProxy objects, used during a GCCallback to ensure they continue to point to the correct char buffer + +/** + * @brief This struct is a bundle of methods used by the JSStringProxy type + * + */ +struct JSStringProxyMethodDefinitions { +public: + /** + * @brief Deallocation method (.tp_dealloc), removes the reference to the underlying JSString before freeing the JSStringProxy + * + * @param self - The JSStringProxy to be free'd + */ + static void JSStringProxy_dealloc(JSStringProxy *self); + + /** + * @brief copy protocol method for both copy and deepcopy + * + * @param self - The JSObjectProxy + * @return a copy of the string + */ + static PyObject *JSStringProxy_copy_method(JSStringProxy *self); +}; + +// docs for methods, copied from cpython +PyDoc_STRVAR(stringproxy_deepcopy__doc__, + "__deepcopy__($self, memo, /)\n" + "--\n" + "\n"); + +PyDoc_STRVAR(stringproxy_copy__doc__, + "__copy__($self, /)\n" + "--\n" + "\n"); + +/** + * @brief Struct for the other methods + * + */ +static PyMethodDef JSStringProxy_methods[] = { + {"__deepcopy__", (PyCFunction)JSStringProxyMethodDefinitions::JSStringProxy_copy_method, METH_O, stringproxy_deepcopy__doc__}, // ignores any memo argument + {"__copy__", (PyCFunction)JSStringProxyMethodDefinitions::JSStringProxy_copy_method, METH_NOARGS, stringproxy_copy__doc__}, + {NULL, NULL} /* sentinel */ +}; + /** * @brief Struct for the JSStringProxyType, used by all JSStringProxy objects */ diff --git a/include/JobQueue.hh b/include/JobQueue.hh index c8bf1a95..36734f92 100644 --- a/include/JobQueue.hh +++ b/include/JobQueue.hh @@ -35,13 +35,21 @@ explicit JobQueue(JSContext *cx); bool init(JSContext *cx); /** - * @brief Ask the embedding for the incumbent global. + * @brief Ask the embedding for the host defined data. * - * SpiderMonkey doesn't itself have a notion of incumbent globals as defined + * SpiderMonkey doesn't itself have a notion of host defined data as defined * by the HTML spec, so we need the embedding to provide this. See * dom/script/ScriptSettings.h for details. + * + * If the embedding has the host defined data, this method should return the + * host defined data via the `data` out parameter and return `true`. + * The object in the `data` out parameter can belong to any compartment. + * If the embedding doesn't need the host defined data, this method should + * set the `data` out parameter to `nullptr` and return `true`. + * If any error happens while generating the host defined data, this method + * should set a pending exception to `cx` and return `false`. */ -JSObject *getIncumbentGlobal(JSContext *cx) override; +bool getHostDefinedData(JSContext *cx, JS::MutableHandle data) const override; /** * @brief Enqueue a reaction job `job` for `promise`, which was allocated at @@ -78,6 +86,11 @@ void runJobs(JSContext *cx) override; */ bool empty() const override; +/** + * @return true if the job queue stopped draining, which results in `empty()` being false after `runJobs()`. + */ +bool isDrainingStopped() const override; + /** * @brief Appends a callback to the queue of FinalizationRegistry callbacks * @@ -120,6 +133,20 @@ js::UniquePtr saveJobQueue(JSContext *) override; */ static bool dispatchToEventLoop(void *closure, JS::Dispatchable *dispatchable); +/** + * @brief The callback that gets invoked whenever a Promise is rejected without a rejection handler (uncaught/unhandled exception) + * see https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/public/Promise.h#l268 + * https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/Runtime.cpp#l600 + * @param promise - The Promise object + * @param state - Is the Promise unhandled? + * @param mutedErrors - When the `mutedErrors` option in `pm.eval` is set to true, unhandled rejections are ignored ("muted"). + * See also https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/public/CompileOptions.h#l129 + * @param privateData - unused + */ +static void promiseRejectionTracker(JSContext *cx, bool mutedErrors, + JS::HandleObject promise, JS::PromiseRejectionHandlingState state, + void *privateData); + }; // class /** diff --git a/include/PyBaseProxyHandler.hh b/include/PyBaseProxyHandler.hh index 0634728a..637a0300 100644 --- a/include/PyBaseProxyHandler.hh +++ b/include/PyBaseProxyHandler.hh @@ -30,7 +30,7 @@ public: bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible) const override final; }; -enum ProxySlots {PyObjectSlot}; +enum ProxySlots {PyObjectSlot, OtherSlot}; typedef struct { const char *name; /* The name of the method */ diff --git a/include/PyBytesProxyHandler.hh b/include/PyBytesProxyHandler.hh new file mode 100644 index 00000000..1c7126f9 --- /dev/null +++ b/include/PyBytesProxyHandler.hh @@ -0,0 +1,57 @@ +/** + * @file PyBytesProxyHandler.hh + * @author Philippe Laporte (philippe@distributive.network) + * @brief Struct for creating JS Uint8Array-like proxy objects for immutable bytes objects + * @date 2024-07-23 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + +#ifndef PythonMonkey_PyBytesProxy_ +#define PythonMonkey_PyBytesProxy_ + + +#include "include/PyObjectProxyHandler.hh" + + +/** + * @brief This struct is the ProxyHandler for JS Proxy Iterable pythonmonkey creates to handle coercion from python iterables to JS Objects + * + */ +struct PyBytesProxyHandler : public PyObjectProxyHandler { +public: + PyBytesProxyHandler() : PyObjectProxyHandler(&family) {}; + static const char family; + + /** + * @brief [[Set]] + * + * @param cx pointer to JSContext + * @param proxy The proxy object who's property we wish to set + * @param id Key of the property we wish to set + * @param v Value that we wish to set the property to + * @param receiver The `this` value to use when executing any code + * @param result whether or not the call succeeded + * @return true call succeed + * @return false call failed and an exception has been raised + */ + bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::HandleValue v, JS::HandleValue receiver, + JS::ObjectOpResult &result) const override; + + bool getOwnPropertyDescriptor( + JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle> desc + ) const override; + + /** + * @brief Handles python object reference count when JS Proxy object is finalized + * + * @param gcx pointer to JS::GCContext + * @param proxy the proxy object being finalized + */ + void finalize(JS::GCContext *gcx, JSObject *proxy) const override; +}; + +#endif \ No newline at end of file diff --git a/include/PyEventLoop.hh b/include/PyEventLoop.hh index 3097dbc9..a4c643f2 100644 --- a/include/PyEventLoop.hh +++ b/include/PyEventLoop.hh @@ -83,6 +83,12 @@ public: } } + /** + * @brief Cancel all pending event-loop jobs. + * @return success + */ + static bool cancelAll(); + /** * @brief Get the underlying `asyncio.Handle` Python object */ diff --git a/include/PyIterableProxyHandler.hh b/include/PyIterableProxyHandler.hh index ff631b3a..8a11706f 100644 --- a/include/PyIterableProxyHandler.hh +++ b/include/PyIterableProxyHandler.hh @@ -28,12 +28,6 @@ public: JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle> desc ) const override; - - /** - * @brief An array of method definitions for Iterable prototype methods - * - */ - static JSMethodDef iterable_methods[]; }; #endif \ No newline at end of file diff --git a/include/PyObjectProxyHandler.hh b/include/PyObjectProxyHandler.hh index 78cf1f37..38f6f970 100644 --- a/include/PyObjectProxyHandler.hh +++ b/include/PyObjectProxyHandler.hh @@ -190,12 +190,6 @@ public: JS::ObjectOpResult &result) const override; bool getBuiltinClass(JSContext *cx, JS::HandleObject proxy, js::ESClass *cls) const override; - - /** - * @brief An array of method definitions for Object prototype methods - * - */ - static JSMethodDef object_methods[]; }; #endif \ No newline at end of file diff --git a/include/StrType.hh b/include/StrType.hh index 7d516485..d8199bc4 100644 --- a/include/StrType.hh +++ b/include/StrType.hh @@ -34,9 +34,9 @@ public: * * @returns PyObject* pointer to the resulting PyObject */ - static PyObject *getPyObject(JSContext *cx, JSString *str); + static PyObject *getPyObject(JSContext *cx, JS::HandleValue str); - static const char *getValue(JSContext *cx, JSString *str); + static PyObject *proxifyString(JSContext *cx, JS::HandleValue str); }; #endif \ No newline at end of file diff --git a/include/jsTypeFactory.hh b/include/jsTypeFactory.hh index f791a257..479ef938 100644 --- a/include/jsTypeFactory.hh +++ b/include/jsTypeFactory.hh @@ -16,7 +16,29 @@ #include -struct PythonExternalString; +struct PythonExternalString : public JSExternalStringCallbacks { +public: + /** + * @brief Get the PyObject using the given char buffer + * + * @param chars - the char buffer of the PyObject + * @return PyObject* - the PyObject string + */ + static PyObject *getPyString(const char16_t *chars); + static PyObject *getPyString(const JS::Latin1Char *chars); + + /** + * @brief decrefs the underlying PyObject string when the JSString is finalized + * + * @param chars - The char buffer of the string + */ + void finalize(char16_t *chars) const override; + void finalize(JS::Latin1Char *chars) const override; + + size_t sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const override; + size_t sizeOfBuffer(const JS::Latin1Char *chars, mozilla::MallocSizeOf mallocSizeOf) const override; +}; +extern PythonExternalString PythonExternalStringCallbacks; /** * @brief Function that makes a UTF16-encoded copy of a UCS4 string diff --git a/include/pyshim.hh b/include/pyshim.hh new file mode 100644 index 00000000..1e43d86f --- /dev/null +++ b/include/pyshim.hh @@ -0,0 +1,145 @@ +/** + * @file pyshim.hh + * @author Tom Tang (xmader@distributive.network) + * @brief Python's C APIs are constantly changing in different versions of CPython. + * PythonMonkey has a wide variety of CPython versions' support. (Currently Python 3.8-3.13) + * This file helps our Python API calls work with different Python versions in the same code base. + * @date 2024-09-20 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + +#ifndef PythonMonkey_py_version_shim_ +#define PythonMonkey_py_version_shim_ + +#include + +/** + * @brief `_Py_IsFinalizing` becomes a stable API in Python 3.13, + * and renames to `Py_IsFinalizing` + */ +#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 + #define Py_IsFinalizing Py_IsFinalizing +#else + #define Py_IsFinalizing _Py_IsFinalizing +#endif + +/** + * @brief `_PyDictViewObject` type definition moved from Python's public API + * to the **internal** header file `internal/pycore_dict.h` in Python 3.13. + * + * @see https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_dict.h#L64-L72 + */ +#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 +typedef struct { + PyObject_HEAD + PyDictObject *dv_dict; +} _PyDictViewObject; +#endif + +/** + * @brief Shim for `_PyArg_CheckPositional`. + * Since Python 3.13, `_PyArg_CheckPositional` function became an internal API. + * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2738-L2780 + */ +#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 +inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { + if (!name) { // _PyArg_CheckPositional may also be when unpacking a tuple + name = "unpacked tuple"; // https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2746 + } + + if (nargs < min) { + PyErr_Format( + PyExc_TypeError, + "%.200s expected %s%zd argument%s, got %zd", + name, (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs); + return 0; + } + + if (nargs == 0) { + return 1; + } + + if (nargs > max) { + PyErr_Format( + PyExc_TypeError, + "%.200s expected %s%zd argument%s, got %zd", + name, (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs); + return 0; + } + + return 1; +} +#endif + +/** + * @brief Shim for `_PyDictView_New`. + * Since Python 3.13, `_PyDictView_New` function became an internal API. + * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827 + */ +inline PyObject *PyDictView_New(PyObject *dict, PyTypeObject *type) { +#if PY_VERSION_HEX < 0x030d0000 // Python version is lower than 3.13 + return _PyDictView_New(dict, type); +#else + _PyDictViewObject *dv; + dv = PyObject_GC_New(_PyDictViewObject, type); + if (dv == NULL) + return NULL; + Py_INCREF(dict); + dv->dv_dict = (PyDictObject *)dict; + PyObject_GC_Track(dv); + return (PyObject *)dv; +#endif +} + +/** + * @brief Shim for `_PyErr_SetKeyError`. + * Since Python 3.13, `_PyErr_SetKeyError` function became an internal API. + */ +inline void PyErr_SetKeyError(PyObject *key) { + // Use the provided API when possible, as `PyErr_SetObject`'s behaviour is more complex than originally thought + // see also: https://github.com/python/cpython/issues/101578 +#if PY_VERSION_HEX < 0x030d0000 // Python version is lower than 3.13 + return _PyErr_SetKeyError(key); +#else + return PyErr_SetObject(PyExc_KeyError, key); +#endif +} + +/** + * @brief Shim for `Py_SET_SIZE`. + * `Py_SET_SIZE` is not available in Python < 3.9 + */ +#ifndef Py_SET_SIZE +static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { + ob->ob_size = size; +} +#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject *)(ob), size) +#endif + +/** + * @brief Shim for `PyObject_CallOneArg`. + * `PyObject_CallOneArg` is not available in Python < 3.9 + */ +#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9 +inline PyObject *PyObject_CallOneArg(PyObject *func, PyObject *arg) { + return PyObject_CallFunction(func, "O", arg); +} +#endif + +/** + * @brief Shim for `_PyLong_AsByteArray`. + * Python 3.13.0a4 added a new public API `PyLong_AsNativeBytes()` to replace the private `_PyLong_AsByteArray()`. + * But this change also modified the function signature of `_PyLong_AsByteArray()`. + * @see https://github.com/python/cpython/issues/111140 + */ +inline int PyLong_AsByteArray(PyLongObject *v, unsigned char *bytes, size_t n, bool little_endian, bool is_signed) { +#if PY_VERSION_HEX >= 0x030d0000 // Python version is 3.13 or higher + return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed, /*with_exceptions*/ false); +#else + return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed); +#endif +} + +#endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/mozcentral.version b/mozcentral.version new file mode 100644 index 00000000..55aeecbf --- /dev/null +++ b/mozcentral.version @@ -0,0 +1 @@ +6bca861985ba51920c1cacc21986af01c51bd690 diff --git a/poetry.lock b/poetry.lock index 5c5912ae..6bf2a192 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,117 +1,144 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiodns" -version = "3.1.1" +version = "3.2.0" description = "Simple DNS resolver for asyncio" optional = false python-versions = "*" files = [ - {file = "aiodns-3.1.1-py3-none-any.whl", hash = "sha256:a387b63da4ced6aad35b1dda2d09620ad608a1c7c0fb71efa07ebb4cd511928d"}, - {file = "aiodns-3.1.1.tar.gz", hash = "sha256:1073eac48185f7a4150cad7f96a5192d6911f12b4fb894de80a088508c9b3a99"}, + {file = "aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5"}, + {file = "aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72"}, ] [package.dependencies] pycares = ">=4.0.0" +[[package]] +name = "aiohappyeyeballs" +version = "2.4.4" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, + {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, +] + [[package]] name = "aiohttp" -version = "3.9.5" +version = "3.10.11" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, - {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, - {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, - {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, - {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, - {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, - {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, - {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, - {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, - {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5077b1a5f40ffa3ba1f40d537d3bec4383988ee51fbba6b74aa8fb1bc466599e"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d6a14a4d93b5b3c2891fca94fa9d41b2322a68194422bef0dd5ec1e57d7d298"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffbfde2443696345e23a3c597049b1dd43049bb65337837574205e7368472177"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20b3d9e416774d41813bc02fdc0663379c01817b0874b932b81c7f777f67b217"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b943011b45ee6bf74b22245c6faab736363678e910504dd7531a58c76c9015a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48bc1d924490f0d0b3658fe5c4b081a4d56ebb58af80a6729d4bd13ea569797a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e12eb3f4b1f72aaaf6acd27d045753b18101524f72ae071ae1c91c1cd44ef115"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f14ebc419a568c2eff3c1ed35f634435c24ead2fe19c07426af41e7adb68713a"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:72b191cdf35a518bfc7ca87d770d30941decc5aaf897ec8b484eb5cc8c7706f3"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ab2328a61fdc86424ee540d0aeb8b73bbcad7351fb7cf7a6546fc0bcffa0038"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa93063d4af05c49276cf14e419550a3f45258b6b9d1f16403e777f1addf4519"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:30283f9d0ce420363c24c5c2421e71a738a2155f10adbb1a11a4d4d6d2715cfc"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e5358addc8044ee49143c546d2182c15b4ac3a60be01c3209374ace05af5733d"}, + {file = "aiohttp-3.10.11-cp310-cp310-win32.whl", hash = "sha256:e1ffa713d3ea7cdcd4aea9cddccab41edf6882fa9552940344c44e59652e1120"}, + {file = "aiohttp-3.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:778cbd01f18ff78b5dd23c77eb82987ee4ba23408cbed233009fd570dda7e674"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:80ff08556c7f59a7972b1e8919f62e9c069c33566a6d28586771711e0eea4f07"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c8f96e9ee19f04c4914e4e7a42a60861066d3e1abf05c726f38d9d0a466e695"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fb8601394d537da9221947b5d6e62b064c9a43e88a1ecd7414d21a1a6fba9c24"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea224cf7bc2d8856d6971cea73b1d50c9c51d36971faf1abc169a0d5f85a382"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db9503f79e12d5d80b3efd4d01312853565c05367493379df76d2674af881caa"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0f449a50cc33f0384f633894d8d3cd020e3ccef81879c6e6245c3c375c448625"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82052be3e6d9e0c123499127782a01a2b224b8af8c62ab46b3f6197035ad94e9"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20063c7acf1eec550c8eb098deb5ed9e1bb0521613b03bb93644b810986027ac"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:489cced07a4c11488f47aab1f00d0c572506883f877af100a38f1fedaa884c3a"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ea9b3bab329aeaa603ed3bf605f1e2a6f36496ad7e0e1aa42025f368ee2dc07b"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ca117819d8ad113413016cb29774b3f6d99ad23c220069789fc050267b786c16"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2dfb612dcbe70fb7cdcf3499e8d483079b89749c857a8f6e80263b021745c730"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9b615d3da0d60e7d53c62e22b4fd1c70f4ae5993a44687b011ea3a2e49051b8"}, + {file = "aiohttp-3.10.11-cp311-cp311-win32.whl", hash = "sha256:29103f9099b6068bbdf44d6a3d090e0a0b2be6d3c9f16a070dd9d0d910ec08f9"}, + {file = "aiohttp-3.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:236b28ceb79532da85d59aa9b9bf873b364e27a0acb2ceaba475dc61cffb6f3f"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7480519f70e32bfb101d71fb9a1f330fbd291655a4c1c922232a48c458c52710"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f65267266c9aeb2287a6622ee2bb39490292552f9fbf851baabc04c9f84e048d"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7400a93d629a0608dc1d6c55f1e3d6e07f7375745aaa8bd7f085571e4d1cee97"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f34b97e4b11b8d4eb2c3a4f975be626cc8af99ff479da7de49ac2c6d02d35725"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e7b825da878464a252ccff2958838f9caa82f32a8dbc334eb9b34a026e2c636"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f92a344c50b9667827da308473005f34767b6a2a60d9acff56ae94f895f385"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f1ab987a27b83c5268a17218463c2ec08dbb754195113867a27b166cd6087"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1dc0f4ca54842173d03322793ebcf2c8cc2d34ae91cc762478e295d8e361e03f"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7ce6a51469bfaacff146e59e7fb61c9c23006495d11cc24c514a455032bcfa03"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aad3cd91d484d065ede16f3cf15408254e2469e3f613b241a1db552c5eb7ab7d"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f4df4b8ca97f658c880fb4b90b1d1ec528315d4030af1ec763247ebfd33d8b9a"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2e4e18a0a2d03531edbc06c366954e40a3f8d2a88d2b936bbe78a0c75a3aab3e"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ce66780fa1a20e45bc753cda2a149daa6dbf1561fc1289fa0c308391c7bc0a4"}, + {file = "aiohttp-3.10.11-cp312-cp312-win32.whl", hash = "sha256:a919c8957695ea4c0e7a3e8d16494e3477b86f33067478f43106921c2fef15bb"}, + {file = "aiohttp-3.10.11-cp312-cp312-win_amd64.whl", hash = "sha256:b5e29706e6389a2283a91611c91bf24f218962717c8f3b4e528ef529d112ee27"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:703938e22434d7d14ec22f9f310559331f455018389222eed132808cd8f44127"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9bc50b63648840854e00084c2b43035a62e033cb9b06d8c22b409d56eb098413"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f0463bf8b0754bc744e1feb61590706823795041e63edf30118a6f0bf577461"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6c6dec398ac5a87cb3a407b068e1106b20ef001c344e34154616183fe684288"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcaf2d79104d53d4dcf934f7ce76d3d155302d07dae24dff6c9fffd217568067"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25fd5470922091b5a9aeeb7e75be609e16b4fba81cdeaf12981393fb240dd10e"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbde2ca67230923a42161b1f408c3992ae6e0be782dca0c44cb3206bf330dee1"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:249c8ff8d26a8b41a0f12f9df804e7c685ca35a207e2410adbd3e924217b9006"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:878ca6a931ee8c486a8f7b432b65431d095c522cbeb34892bee5be97b3481d0f"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8663f7777ce775f0413324be0d96d9730959b2ca73d9b7e2c2c90539139cbdd6"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6cd3f10b01f0c31481fba8d302b61603a2acb37b9d30e1d14e0f5a58b7b18a31"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e8d8aad9402d3aa02fdc5ca2fe68bcb9fdfe1f77b40b10410a94c7f408b664d"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:38e3c4f80196b4f6c3a85d134a534a56f52da9cb8d8e7af1b79a32eefee73a00"}, + {file = "aiohttp-3.10.11-cp313-cp313-win32.whl", hash = "sha256:fc31820cfc3b2863c6e95e14fcf815dc7afe52480b4dc03393c4873bb5599f71"}, + {file = "aiohttp-3.10.11-cp313-cp313-win_amd64.whl", hash = "sha256:4996ff1345704ffdd6d75fb06ed175938c133425af616142e7187f28dc75f14e"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74baf1a7d948b3d640badeac333af581a367ab916b37e44cf90a0334157cdfd2"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:473aebc3b871646e1940c05268d451f2543a1d209f47035b594b9d4e91ce8339"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c2f746a6968c54ab2186574e15c3f14f3e7f67aef12b761e043b33b89c5b5f95"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d110cabad8360ffa0dec8f6ec60e43286e9d251e77db4763a87dcfe55b4adb92"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0099c7d5d7afff4202a0c670e5b723f7718810000b4abcbc96b064129e64bc7"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0316e624b754dbbf8c872b62fe6dcb395ef20c70e59890dfa0de9eafccd2849d"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a5f7ab8baf13314e6b2485965cbacb94afff1e93466ac4d06a47a81c50f9cca"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c891011e76041e6508cbfc469dd1a8ea09bc24e87e4c204e05f150c4c455a5fa"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9208299251370ee815473270c52cd3f7069ee9ed348d941d574d1457d2c73e8b"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:459f0f32c8356e8125f45eeff0ecf2b1cb6db1551304972702f34cd9e6c44658"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:14cdc8c1810bbd4b4b9f142eeee23cda528ae4e57ea0923551a9af4820980e39"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:971aa438a29701d4b34e4943e91b5e984c3ae6ccbf80dd9efaffb01bd0b243a9"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9a309c5de392dfe0f32ee57fa43ed8fc6ddf9985425e84bd51ed66bb16bce3a7"}, + {file = "aiohttp-3.10.11-cp38-cp38-win32.whl", hash = "sha256:9ec1628180241d906a0840b38f162a3215114b14541f1a8711c368a8739a9be4"}, + {file = "aiohttp-3.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:9c6e0ffd52c929f985c7258f83185d17c76d4275ad22e90aa29f38e211aacbec"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc493a2e5d8dc79b2df5bec9558425bcd39aff59fc949810cbd0832e294b106"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3e70f24e7d0405be2348da9d5a7836936bf3a9b4fd210f8c37e8d48bc32eca6"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968b8fb2a5eee2770eda9c7b5581587ef9b96fbdf8dcabc6b446d35ccc69df01"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deef4362af9493d1382ef86732ee2e4cbc0d7c005947bd54ad1a9a16dd59298e"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:686b03196976e327412a1b094f4120778c7c4b9cff9bce8d2fdfeca386b89829"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3bf6d027d9d1d34e1c2e1645f18a6498c98d634f8e373395221121f1c258ace8"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:099fd126bf960f96d34a760e747a629c27fb3634da5d05c7ef4d35ef4ea519fc"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c73c4d3dae0b4644bc21e3de546530531d6cdc88659cdeb6579cd627d3c206aa"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c5580f3c51eea91559db3facd45d72e7ec970b04528b4709b1f9c2555bd6d0b"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fdf6429f0caabfd8a30c4e2eaecb547b3c340e4730ebfe25139779b9815ba138"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d97187de3c276263db3564bb9d9fad9e15b51ea10a371ffa5947a5ba93ad6777"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0acafb350cfb2eba70eb5d271f55e08bd4502ec35e964e18ad3e7d34d71f7261"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c13ed0c779911c7998a58e7848954bd4d63df3e3575f591e321b19a2aec8df9f"}, + {file = "aiohttp-3.10.11-cp39-cp39-win32.whl", hash = "sha256:22b7c540c55909140f63ab4f54ec2c20d2635c0289cdd8006da46f3327f971b9"}, + {file = "aiohttp-3.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:7b26b1551e481012575dab8e3727b16fe7dd27eb2711d2e63ced7368756268fb"}, + {file = "aiohttp-3.10.11.tar.gz", hash = "sha256:9dc2b8f3dcab2e39e0fa309c8da50c3b55e6f34ab25f1a71d3288f24924d33a7"}, ] [package.dependencies] -aiodns = {version = "*", optional = true, markers = "(sys_platform == \"linux\" or sys_platform == \"darwin\") and extra == \"speedups\""} +aiodns = {version = ">=3.2.0", optional = true, markers = "(sys_platform == \"linux\" or sys_platform == \"darwin\") and extra == \"speedups\""} +aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" Brotli = {version = "*", optional = true, markers = "platform_python_implementation == \"CPython\" and extra == \"speedups\""} brotlicffi = {version = "*", optional = true, markers = "platform_python_implementation != \"CPython\" and extra == \"speedups\""} frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +yarl = ">=1.12.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns", "brotlicffi"] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" @@ -129,33 +156,33 @@ frozenlist = ">=1.1.0" [[package]] name = "async-timeout" -version = "4.0.3" +version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] [[package]] name = "attrs" -version = "23.2.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "brotli" @@ -290,63 +317,78 @@ cffi = ">=1.0.0" [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -365,225 +407,251 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] [[package]] name = "frozenlist" -version = "1.4.1" +version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, ] [[package]] name = "idna" -version = "3.6" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] name = "multidict" -version = "6.0.5" +version = "6.1.0" description = "multidict implementation" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "numpy" version = "1.24.4" @@ -623,58 +691,214 @@ files = [ [[package]] name = "numpy" -version = "1.26.4" +version = "2.0.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, - {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, - {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, + {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, + {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, + {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, + {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, + {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, + {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, + {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, + {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, + {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, +] + +[[package]] +name = "numpy" +version = "2.2.6" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289"}, + {file = "numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d"}, + {file = "numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab"}, + {file = "numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47"}, + {file = "numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de"}, + {file = "numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4"}, + {file = "numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d"}, + {file = "numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd"}, + {file = "numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1"}, + {file = "numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff"}, + {file = "numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00"}, + {file = "numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd"}, +] + +[[package]] +name = "numpy" +version = "2.3.3" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.11" +files = [ + {file = "numpy-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ffc4f5caba7dfcbe944ed674b7eef683c7e94874046454bb79ed7ee0236f59d"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7e946c7170858a0295f79a60214424caac2ffdb0063d4d79cb681f9aa0aa569"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:cd4260f64bc794c3390a63bf0728220dd1a68170c169088a1e0dfa2fde1be12f"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f0ddb4b96a87b6728df9362135e764eac3cfa674499943ebc44ce96c478ab125"}, + {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:afd07d377f478344ec6ca2b8d4ca08ae8bd44706763d1efb56397de606393f48"}, + {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc92a5dedcc53857249ca51ef29f5e5f2f8c513e22cfb90faeb20343b8c6f7a6"}, + {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7af05ed4dc19f308e1d9fc759f36f21921eb7bbfc82843eeec6b2a2863a0aefa"}, + {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:433bf137e338677cebdd5beac0199ac84712ad9d630b74eceeb759eaa45ddf30"}, + {file = "numpy-2.3.3-cp311-cp311-win32.whl", hash = "sha256:eb63d443d7b4ffd1e873f8155260d7f58e7e4b095961b01c91062935c2491e57"}, + {file = "numpy-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:ec9d249840f6a565f58d8f913bccac2444235025bbb13e9a4681783572ee3caa"}, + {file = "numpy-2.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:74c2a948d02f88c11a3c075d9733f1ae67d97c6bdb97f2bb542f980458b257e7"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b"}, + {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8"}, + {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20"}, + {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea"}, + {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7"}, + {file = "numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf"}, + {file = "numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb"}, + {file = "numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7"}, + {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c"}, + {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93"}, + {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae"}, + {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86"}, + {file = "numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8"}, + {file = "numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf"}, + {file = "numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19"}, + {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30"}, + {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e"}, + {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3"}, + {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea"}, + {file = "numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd"}, + {file = "numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d"}, + {file = "numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a"}, + {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe"}, + {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421"}, + {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021"}, + {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf"}, + {file = "numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0"}, + {file = "numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8"}, + {file = "numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a"}, + {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54"}, + {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e"}, + {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097"}, + {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970"}, + {file = "numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5"}, + {file = "numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f"}, + {file = "numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1e02c7159791cd481e1e6d5ddd766b62a4d5acf8df4d4d1afe35ee9c5c33a41e"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:dca2d0fc80b3893ae72197b39f69d55a3cd8b17ea1b50aa4c62de82419936150"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:99683cbe0658f8271b333a1b1b4bb3173750ad59c0c61f5bbdc5b318918fffe3"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d9d537a39cc9de668e5cd0e25affb17aec17b577c6b3ae8a3d866b479fbe88d0"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8596ba2f8af5f93b01d97563832686d20206d303024777f6dfc2e7c7c3f1850e"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1ec5615b05369925bd1125f27df33f3b6c8bc10d788d5999ecd8769a1fa04db"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2e267c7da5bf7309670523896df97f93f6e469fb931161f483cd6882b3b1a5dc"}, + {file = "numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029"}, ] [[package]] name = "packaging" -version = "23.2" +version = "25.0" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -690,19 +914,126 @@ files = [ [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "pycares" version = "4.4.0" @@ -771,26 +1102,29 @@ idna = ["idna (>=2.1)"] [[package]] name = "pycparser" -version = "2.21" +version = "2.23" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, + {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, ] [[package]] name = "pyreadline3" -version = "3.4.1" +version = "3.5.4" description = "A python implementation of GNU readline." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, - {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, + {file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"}, + {file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"}, ] +[package.extras] +dev = ["build", "flake8", "mypy", "pytest", "twine"] + [[package]] name = "pytest" version = "7.4.4" @@ -815,119 +1149,169 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "typing-extensions" +version = "4.13.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] [[package]] name = "yarl" -version = "1.9.4" +version = "1.15.2" description = "Yet another URL library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e4ee8b8639070ff246ad3649294336b06db37a94bdea0d09ea491603e0be73b8"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a7cf963a357c5f00cb55b1955df8bbe68d2f2f65de065160a1c26b85a1e44172"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43ebdcc120e2ca679dba01a779333a8ea76b50547b55e812b8b92818d604662c"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3433da95b51a75692dcf6cc8117a31410447c75a9a8187888f02ad45c0a86c50"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38d0124fa992dbacd0c48b1b755d3ee0a9f924f427f95b0ef376556a24debf01"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ded1b1803151dd0f20a8945508786d57c2f97a50289b16f2629f85433e546d47"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace4cad790f3bf872c082366c9edd7f8f8f77afe3992b134cfc810332206884f"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c77494a2f2282d9bbbbcab7c227a4d1b4bb829875c96251f66fb5f3bae4fb053"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b7f227ca6db5a9fda0a2b935a2ea34a7267589ffc63c8045f0e4edb8d8dcf956"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:31561a5b4d8dbef1559b3600b045607cf804bae040f64b5f5bca77da38084a8a"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3e52474256a7db9dcf3c5f4ca0b300fdea6c21cca0148c8891d03a025649d935"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1af74a9529a1137c67c887ed9cde62cff53aa4d84a3adbec329f9ec47a3936"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:15c87339490100c63472a76d87fe7097a0835c705eb5ae79fd96e343473629ed"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:74abb8709ea54cc483c4fb57fb17bb66f8e0f04438cff6ded322074dbd17c7ec"}, + {file = "yarl-1.15.2-cp310-cp310-win32.whl", hash = "sha256:ffd591e22b22f9cb48e472529db6a47203c41c2c5911ff0a52e85723196c0d75"}, + {file = "yarl-1.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:1695497bb2a02a6de60064c9f077a4ae9c25c73624e0d43e3aa9d16d983073c2"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9fcda20b2de7042cc35cf911702fa3d8311bd40055a14446c1e62403684afdc5"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0545de8c688fbbf3088f9e8b801157923be4bf8e7b03e97c2ecd4dfa39e48e0e"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbda058a9a68bec347962595f50546a8a4a34fd7b0654a7b9697917dc2bf810d"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ac2bc069f4a458634c26b101c2341b18da85cb96afe0015990507efec2e417"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd126498171f752dd85737ab1544329a4520c53eed3997f9b08aefbafb1cc53b"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3db817b4e95eb05c362e3b45dafe7144b18603e1211f4a5b36eb9522ecc62bcf"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:076b1ed2ac819933895b1a000904f62d615fe4533a5cf3e052ff9a1da560575c"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8cfd847e6b9ecf9f2f2531c8427035f291ec286c0a4944b0a9fce58c6446046"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:32b66be100ac5739065496c74c4b7f3015cef792c3174982809274d7e51b3e04"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34a2d76a1984cac04ff8b1bfc939ec9dc0914821264d4a9c8fd0ed6aa8d4cfd2"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0afad2cd484908f472c8fe2e8ef499facee54a0a6978be0e0cff67b1254fd747"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c68e820879ff39992c7f148113b46efcd6ec765a4865581f2902b3c43a5f4bbb"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:98f68df80ec6ca3015186b2677c208c096d646ef37bbf8b49764ab4a38183931"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56ec1eacd0a5d35b8a29f468659c47f4fe61b2cab948ca756c39b7617f0aa5"}, + {file = "yarl-1.15.2-cp311-cp311-win32.whl", hash = "sha256:eedc3f247ee7b3808ea07205f3e7d7879bc19ad3e6222195cd5fbf9988853e4d"}, + {file = "yarl-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:0ccaa1bc98751fbfcf53dc8dfdb90d96e98838010fc254180dd6707a6e8bb179"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:82d5161e8cb8f36ec778fd7ac4d740415d84030f5b9ef8fe4da54784a1f46c94"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa2bea05ff0a8fb4d8124498e00e02398f06d23cdadd0fe027d84a3f7afde31e"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99e12d2bf587b44deb74e0d6170fec37adb489964dbca656ec41a7cd8f2ff178"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:243fbbbf003754fe41b5bdf10ce1e7f80bcc70732b5b54222c124d6b4c2ab31c"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:856b7f1a7b98a8c31823285786bd566cf06226ac4f38b3ef462f593c608a9bd6"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:553dad9af802a9ad1a6525e7528152a015b85fb8dbf764ebfc755c695f488367"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30c3ff305f6e06650a761c4393666f77384f1cc6c5c0251965d6bfa5fbc88f7f"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:353665775be69bbfc6d54c8d134bfc533e332149faeddd631b0bc79df0897f46"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f4fe99ce44128c71233d0d72152db31ca119711dfc5f2c82385ad611d8d7f897"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9c1e3ff4b89cdd2e1a24c214f141e848b9e0451f08d7d4963cb4108d4d798f1f"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:711bdfae4e699a6d4f371137cbe9e740dc958530cb920eb6f43ff9551e17cfbc"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4388c72174868884f76affcdd3656544c426407e0043c89b684d22fb265e04a5"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f0e1844ad47c7bd5d6fa784f1d4accc5f4168b48999303a868fe0f8597bde715"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a5cafb02cf097a82d74403f7e0b6b9df3ffbfe8edf9415ea816314711764a27b"}, + {file = "yarl-1.15.2-cp312-cp312-win32.whl", hash = "sha256:156ececdf636143f508770bf8a3a0498de64da5abd890c7dbb42ca9e3b6c05b8"}, + {file = "yarl-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:435aca062444a7f0c884861d2e3ea79883bd1cd19d0a381928b69ae1b85bc51d"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:416f2e3beaeae81e2f7a45dc711258be5bdc79c940a9a270b266c0bec038fb84"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:173563f3696124372831007e3d4b9821746964a95968628f7075d9231ac6bb33"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ce2e0f6123a60bd1a7f5ae3b2c49b240c12c132847f17aa990b841a417598a2"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaea112aed589131f73d50d570a6864728bd7c0c66ef6c9154ed7b59f24da611"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4ca3b9f370f218cc2a0309542cab8d0acdfd66667e7c37d04d617012485f904"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23ec1d3c31882b2a8a69c801ef58ebf7bae2553211ebbddf04235be275a38548"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75119badf45f7183e10e348edff5a76a94dc19ba9287d94001ff05e81475967b"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e6fdc976ec966b99e4daa3812fac0274cc28cd2b24b0d92462e2e5ef90d368"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8657d3f37f781d987037f9cc20bbc8b40425fa14380c87da0cb8dfce7c92d0fb"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:93bed8a8084544c6efe8856c362af08a23e959340c87a95687fdbe9c9f280c8b"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:69d5856d526802cbda768d3e6246cd0d77450fa2a4bc2ea0ea14f0d972c2894b"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ccad2800dfdff34392448c4bf834be124f10a5bc102f254521d931c1c53c455a"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a880372e2e5dbb9258a4e8ff43f13888039abb9dd6d515f28611c54361bc5644"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c998d0558805860503bc3a595994895ca0f7835e00668dadc673bbf7f5fbfcbe"}, + {file = "yarl-1.15.2-cp313-cp313-win32.whl", hash = "sha256:533a28754e7f7439f217550a497bb026c54072dbe16402b183fdbca2431935a9"}, + {file = "yarl-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:5838f2b79dc8f96fdc44077c9e4e2e33d7089b10788464609df788eb97d03aad"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fbbb63bed5fcd70cd3dd23a087cd78e4675fb5a2963b8af53f945cbbca79ae16"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2e93b88ecc8f74074012e18d679fb2e9c746f2a56f79cd5e2b1afcf2a8a786b"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af8ff8d7dc07ce873f643de6dfbcd45dc3db2c87462e5c387267197f59e6d776"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66f629632220a4e7858b58e4857927dd01a850a4cef2fb4044c8662787165cf7"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:833547179c31f9bec39b49601d282d6f0ea1633620701288934c5f66d88c3e50"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2aa738e0282be54eede1e3f36b81f1e46aee7ec7602aa563e81e0e8d7b67963f"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a13a07532e8e1c4a5a3afff0ca4553da23409fad65def1b71186fb867eeae8d"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c45817e3e6972109d1a2c65091504a537e257bc3c885b4e78a95baa96df6a3f8"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:670eb11325ed3a6209339974b276811867defe52f4188fe18dc49855774fa9cf"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:d417a4f6943112fae3924bae2af7112562285848d9bcee737fc4ff7cbd450e6c"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bc8936d06cd53fddd4892677d65e98af514c8d78c79864f418bbf78a4a2edde4"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:954dde77c404084c2544e572f342aef384240b3e434e06cecc71597e95fd1ce7"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5bc0df728e4def5e15a754521e8882ba5a5121bd6b5a3a0ff7efda5d6558ab3d"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b71862a652f50babab4a43a487f157d26b464b1dedbcc0afda02fd64f3809d04"}, + {file = "yarl-1.15.2-cp38-cp38-win32.whl", hash = "sha256:63eab904f8630aed5a68f2d0aeab565dcfc595dc1bf0b91b71d9ddd43dea3aea"}, + {file = "yarl-1.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:2cf441c4b6e538ba0d2591574f95d3fdd33f1efafa864faa077d9636ecc0c4e9"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a32d58f4b521bb98b2c0aa9da407f8bd57ca81f34362bcb090e4a79e9924fefc"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:766dcc00b943c089349d4060b935c76281f6be225e39994c2ccec3a2a36ad627"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bed1b5dbf90bad3bfc19439258c97873eab453c71d8b6869c136346acfe497e7"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed20a4bdc635f36cb19e630bfc644181dd075839b6fc84cac51c0f381ac472e2"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d538df442c0d9665664ab6dd5fccd0110fa3b364914f9c85b3ef9b7b2e157980"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c6cf1d92edf936ceedc7afa61b07e9d78a27b15244aa46bbcd534c7458ee1b"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce44217ad99ffad8027d2fde0269ae368c86db66ea0571c62a000798d69401fb"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47a6000a7e833ebfe5886b56a31cb2ff12120b1efd4578a6fcc38df16cc77bd"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e52f77a0cd246086afde8815039f3e16f8d2be51786c0a39b57104c563c5cbb0"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:f9ca0e6ce7774dc7830dc0cc4bb6b3eec769db667f230e7c770a628c1aa5681b"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:136f9db0f53c0206db38b8cd0c985c78ded5fd596c9a86ce5c0b92afb91c3a19"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:173866d9f7409c0fb514cf6e78952e65816600cb888c68b37b41147349fe0057"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:6e840553c9c494a35e449a987ca2c4f8372668ee954a03a9a9685075228e5036"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:458c0c65802d816a6b955cf3603186de79e8fdb46d4f19abaec4ef0a906f50a7"}, + {file = "yarl-1.15.2-cp39-cp39-win32.whl", hash = "sha256:5b48388ded01f6f2429a8c55012bdbd1c2a0c3735b3e73e221649e524c34a58d"}, + {file = "yarl-1.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:81dadafb3aa124f86dc267a2168f71bbd2bfb163663661ab0038f6e4b8edb810"}, + {file = "yarl-1.15.2-py3-none-any.whl", hash = "sha256:0d3105efab7c5c091609abacad33afff33bdff0035bece164c98bcf5a85ef90a"}, + {file = "yarl-1.15.2.tar.gz", hash = "sha256:a39c36f4218a5bb668b4f06874d676d35a035ee668e6e7e3538835c703634b84"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "11d3704623455cf65a35174a88b275bb80ab36ae0dc95074b1a943ef0be3c08d" +content-hash = "e4f32f4286c2558ea80fcba84acb74bb0a6d10ff33f02edaa7a36330ea25e07b" diff --git a/pyproject.toml b/pyproject.toml index b2bc612f..78edc0ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,20 +1,24 @@ [tool.poetry] name = "pythonmonkey" version = "0" # automatically set by poetry-dynamic-versioning -description = "" -authors = ["Caleb Aikens ", "Tom Tang ", "Wes Garland ", "Hamada Gasmallah ", "Philippe Laporte "] +description = "Seamless interop between Python and JavaScript." +authors = ["Distributive Corp. "] +license = "MIT" +homepage = "https://pythonmonkey.io/" +documentation = "https://docs.pythonmonkey.io/" +repository = "https://github.com/Distributive-Network/PythonMonkey" readme = "README.md" packages = [ { include = "pythonmonkey", from = "python" }, ] include = [ # Linux and macOS - "python/pythonmonkey/pythonmonkey.so", - "python/pythonmonkey/libmozjs*", + { path = "python/pythonmonkey/pythonmonkey.so", format = ["sdist", "wheel"] }, + { path = "python/pythonmonkey/libmozjs*", format = ["sdist", "wheel"] }, # Windows - "python/pythonmonkey/pythonmonkey.pyd", - "python/pythonmonkey/mozjs-*.dll", + { path = "python/pythonmonkey/pythonmonkey.pyd", format = ["sdist", "wheel"] }, + { path = "python/pythonmonkey/mozjs-*.dll", format = ["sdist", "wheel"] }, # include all files for source distribution { path = "src", format = "sdist" }, @@ -23,13 +27,17 @@ include = [ { path = "tests", format = "sdist" }, { path = "CMakeLists.txt", format = "sdist" }, { path = "*.sh", format = "sdist" }, + { path = "mozcentral.version", format = "sdist" }, + + # Add marker file for pep561 + { path = "python/pythonmonkey/py.typed", format = ["sdist", "wheel"] }, ] [tool.poetry.dependencies] python = "^3.8" pyreadline3 = { version = "^3.4.1", platform = "win32" } -aiohttp = { version = "^3.9.5", extras = ["speedups"] } +aiohttp = { version = "^3.9.5" } pminit = { version = ">=0.4.0", allow-prereleases = true } @@ -57,8 +65,10 @@ pmjs = "pythonmonkey.cli.pmjs:main" pytest = "^7.3.1" pip = "^23.1.2" numpy = [ - {version = "^1.26.1", python = ">=3.9,<3.13"}, - {version = "^1.24.3", python = "3.8.*"}, + {version = "^2.3.0", python = ">=3.11"}, + {version = "^2.1.0", python = ">=3.10,<3.11"}, # NumPy 2.3.0 drops support for Python 3.10 + {version = "^2.0.1", python = ">=3.9,<3.10"}, # NumPy 2.1.0 drops support for Python 3.9 + {version = "^1.24.3", python = ">=3.8,<3.9"}, # NumPy 1.25.0 drops support for Python 3.8 ] pminit = { path = "./python/pminit", develop = true } @@ -73,4 +83,4 @@ ignore="E111,E114,E121" # allow 2-space indents verbose=true indent-size=2 aggressive=3 -exit-code=true \ No newline at end of file +exit-code=true diff --git a/python/pminit/pminit/cli.py b/python/pminit/pminit/cli.py index 700ba00c..f7a005a2 100644 --- a/python/pminit/pminit/cli.py +++ b/python/pminit/pminit/cli.py @@ -11,8 +11,8 @@ def execute(cmd: str, cwd: str): popen.stdout.close() return_code = popen.wait() - if return_code: - raise subprocess.CalledProcessError(return_code, cmd) + if return_code != 0: + sys.exit(return_code) def commandType(value: str): if value != "npm": @@ -34,7 +34,3 @@ def main(): ) execute(' '.join( args.executable + args.args ), pythonmonkey_path) - - - - diff --git a/python/pminit/pyproject.toml b/python/pminit/pyproject.toml index 9910cc72..09d28174 100644 --- a/python/pminit/pyproject.toml +++ b/python/pminit/pyproject.toml @@ -3,11 +3,13 @@ name = "pminit" version = "0" description = "Post-install hook for PythonMonkey" authors = [ - "Tom Tang ", - "Caleb Aikens ", - "Wes Garland ", - "Hamada Gasmallah " + "Distributive Corp. " ] +license = "MIT" +homepage = "https://pythonmonkey.io/" +documentation = "https://docs.pythonmonkey.io/" +repository = "https://github.com/Distributive-Network/PythonMonkey" + include = [ # Install extra files into the pythonmonkey package "pythonmonkey/package*.json", diff --git a/python/pminit/pythonmonkey/package-lock.json b/python/pminit/pythonmonkey/package-lock.json index 54aca4dd..6533b355 100644 --- a/python/pminit/pythonmonkey/package-lock.json +++ b/python/pminit/pythonmonkey/package-lock.json @@ -10,24 +10,26 @@ "license": "MIT", "dependencies": { "core-js": "^3.35.1", - "ctx-module": "^1.0.14" + "ctx-module": "^1.0.15", + "events": "^3.3.0" } }, "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" + "minimalistic-assert": "^1.0.0" } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -51,17 +53,20 @@ "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "license": "MIT" }, "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" }, "node_modules/browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "license": "MIT", "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -75,6 +80,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "license": "MIT", "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -85,6 +91,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -93,31 +100,38 @@ } }, "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "license": "MIT", "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/browserify-sign": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", - "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "license": "ISC", "dependencies": { "bn.js": "^5.2.1", "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.4", + "elliptic": "^6.5.5", + "hash-base": "~3.0", "inherits": "^2.0.4", - "parse-asn1": "^5.1.6", - "readable-stream": "^3.6.2", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 4" + "node": ">= 0.12" } }, "node_modules/buffer": { @@ -146,15 +160,20 @@ "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "license": "MIT" }, "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/core-js": { @@ -167,24 +186,33 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -197,6 +225,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -207,39 +236,64 @@ } }, "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "license": "MIT", "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" }, "engines": { - "node": "*" + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/ctx-module": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/ctx-module/-/ctx-module-1.0.14.tgz", - "integrity": "sha512-eH4h/bv64YuzCHMUZs93j57/4zNJHyQWOIz5CPAs1gJ/4yznPD9HoCLCXjQlST2AxOLOKNvV67n+A8dALtLA+Q==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/ctx-module/-/ctx-module-1.0.15.tgz", + "integrity": "sha512-+/L9CMH/5cjNW+ddPmqGoxF4/xOns3jdTZFbvi683zjxB/FEACGKpBLfVVWvLsyJsdQCKLVibUlM7Ui/BtMS/A==", + "license": "MIT", "dependencies": { "buffer": "^6.0.3", - "crypto-browserify": "^3.12.0" + "crypto-browserify": "^3.12.1", + "debug": "^4.3.4" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/des.js": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -249,6 +303,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -256,14 +311,16 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -275,36 +332,44 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "license": "MIT", "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "license": "MIT", "dependencies": { "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=4" + "node": ">= 0.10" } }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -314,6 +379,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -342,12 +408,20 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -358,6 +432,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -367,36 +442,51 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "license": "MIT", "dependencies": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -408,10 +498,17 @@ "node": ">=0.12" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -422,14 +519,16 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -438,28 +537,38 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "license": "MIT", "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "license": "MIT", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -482,17 +591,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + ], + "license": "MIT" }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "license": "(MIT AND BSD-3-Clause)", "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -502,17 +608,25 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" } } } diff --git a/python/pminit/pythonmonkey/package.json b/python/pminit/pythonmonkey/package.json index b2afffeb..af323dd0 100644 --- a/python/pminit/pythonmonkey/package.json +++ b/python/pminit/pythonmonkey/package.json @@ -22,6 +22,7 @@ "homepage": "https://github.com/Distributive-Network/PythonMonkey#readme", "dependencies": { "core-js": "^3.35.1", - "ctx-module": "^1.0.14" + "ctx-module": "^1.0.15", + "events": "^3.3.0" } } diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts index bdb159b0..2d8c4495 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts @@ -46,6 +46,9 @@ export declare function request( // callbacks for known exceptions onTimeoutError: (err: Error) => void, onNetworkError: (err: Error) => void, + // the debug logging function + /** See `pm.bootstrap.require("debug")` */ + debug: (selector: string) => ((...args: string[]) => void), ): Promise; /** diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py index 19c5a0d6..ca716d88 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py @@ -12,6 +12,8 @@ import pythonmonkey as pm from typing import Union, ByteString, Callable, TypedDict +keepAliveConnector: Union[aiohttp.TCPConnector, None] = None + class XHRResponse(TypedDict, total=True): """ @@ -42,9 +44,16 @@ async def request( # callbacks for known exceptions onTimeoutError: Callable[[asyncio.TimeoutError], None], onNetworkError: Callable[[aiohttp.ClientError], None], + # the debug logging function, see `pm.bootstrap.require("debug")` + debug: Callable[[str], Callable[..., None]], / ): - debug = pm.bootstrap.require("debug") + + # to support HTTP-Keep-Alive + global keepAliveConnector + if (not keepAliveConnector): + # seconds before closing Keep-Alive connection. + keepAliveConnector = aiohttp.TCPConnector(keepalive_timeout=5) # 5s is the default for Node.js's `http.globalAgent` class BytesPayloadWithProgress(aiohttp.BytesPayload): _chunkMaxLength = 2**16 # aiohttp default @@ -80,6 +89,7 @@ async def write(self, writer) -> None: headers=headers, data=BytesPayloadWithProgress(body) if body else None, timeout=timeoutOptions, + connector=keepAliveConnector, ) as res: debug('xhr:aiohttp')('got', res.content_type, 'result') diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js index 82dc4a99..3cbacfc1 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js @@ -20,7 +20,7 @@ const debug = globalThis.python.eval('__import__("pythonmonkey").bootstrap.requi * @param {any} what The thing to truncate; must have a slice method and index property. * Works with string, array, typedarray, etc. * @param {number} maxlen The maximum length for truncation - * @param {boolean} coerce Not false = coerce to printable character codes + * @param {boolean=} coerce Not false = coerce to printable character codes * @returns {string} */ function trunc(what, maxlen, coerce) @@ -49,7 +49,7 @@ class ProgressEvent extends Event { /** * @param {string} type - * @param {{ lengthComputable?: boolean; loaded?: number; total?: number; }} eventInitDict + * @param {{ lengthComputable?: boolean; loaded?: number; total?: number; error?: Error; }} eventInitDict */ constructor (type, eventInitDict = {}) { @@ -57,6 +57,7 @@ class ProgressEvent extends Event this.lengthComputable = eventInitDict.lengthComputable ?? false; this.loaded = eventInitDict.loaded ?? 0; this.total = eventInitDict.total ?? 0; + this.error = eventInitDict.error ?? null; this.debugTag = 'xhr:'; } } @@ -103,6 +104,34 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget /** @type {EventListenerFn} */ onreadystatechange = null; + // + // debugging + // + /** The unique connection id to identify each XHR connection when debugging */ + #connectionId = Math.random().toString(16).slice(2, 9); // random 7-character hex string + + /** + * Wrapper to print debug logs with connection id information + * @param {string} selector + */ + #debug(selector) + { + return (...args) => debug(selector)(`Conn<${this.#connectionId}>:`, ...args); + } + + /** + * Allowing others to inspect the internal properties + */ + get _requestMetadata() + { + return { + method: this.#requestMethod, + url: this.#requestURL.toString(), + headers: this.#requestHeaders, + body: this.#requestBody, + }; + } + // // states // @@ -141,7 +170,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ open(method, url, async = true, username = null, password = null) { - debug('xhr:open')('open start, method=' + method); + this.#debug('xhr:open')('open start, method=' + method); // Normalize the method. // @ts-expect-error method = method.toString().toUpperCase(); @@ -155,7 +184,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget parsedURL.username = username; if (password) parsedURL.password = password; - debug('xhr:open')('url is ' + parsedURL.href); + this.#debug('xhr:open')('url is ' + parsedURL.href); // step 11 this.#sendFlag = false; @@ -175,7 +204,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget this.#state = XMLHttpRequest.OPENED; this.dispatchEvent(new Event('readystatechange')); } - debug('xhr:open')('finished open, state is ' + this.#state); + this.#debug('xhr:open')('finished open, state is ' + this.#state); } /** @@ -185,7 +214,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ setRequestHeader(name, value) { - debug('xhr:headers')(`set header ${name}=${value}`); + this.#debug('xhr:headers')(`set header ${name}=${value}`); if (this.#state !== XMLHttpRequest.OPENED) throw new DOMException('setRequestHeader can only be called when state is OPEN', 'InvalidStateError'); if (this.#sendFlag) @@ -251,7 +280,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ send(body = null) { - debug('xhr:send')(`sending; body length=${body?.length}`); + this.#debug('xhr:send')(`sending; body length=${body?.length} «${body ? trunc(body, 100) : ''}»`); if (this.#state !== XMLHttpRequest.OPENED) // step 1 throw new DOMException('connection must be opened before send() is called', 'InvalidStateError'); if (this.#sendFlag) // step 2 @@ -284,7 +313,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget if (!originalAuthorContentType && extractedContentType) this.#requestHeaders['content-type'] = extractedContentType; } - debug('xhr:send')(`content-type=${this.#requestHeaders['content-type']}`); + this.#debug('xhr:send')(`content-type=${this.#requestHeaders['content-type']}`); // step 5 if (this.#uploadObject._hasAnyListeners()) @@ -309,7 +338,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ #sendAsync() { - debug('xhr:send')('sending in async mode'); + this.#debug('xhr:send')('sending in async mode'); this.dispatchEvent(new ProgressEvent('loadstart', { loaded:0, total:0 })); // step 11.1 let requestBodyTransmitted = 0; // step 11.2 @@ -342,7 +371,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget let responseLength = 0; const processResponse = (response) => { - debug('xhr:response')(`response headers ----\n${response.getAllResponseHeaders()}`); + this.#debug('xhr:response')(`response headers ----\n${response.getAllResponseHeaders()}`); this.#response = response; // step 11.9.1 this.#state = XMLHttpRequest.HEADERS_RECEIVED; // step 11.9.4 this.dispatchEvent(new Event('readystatechange')); // step 11.9.5 @@ -353,7 +382,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget const processBodyChunk = (/** @type {Uint8Array} */ bytes) => { - debug('xhr:response')(`recv chunk, ${bytes.length} bytes (${trunc(bytes, 100)})`); + this.#debug('xhr:response')(`recv chunk, ${bytes.length} bytes «${trunc(bytes, 100)}»`); this.#receivedBytes.push(bytes); if (this.#state === XMLHttpRequest.HEADERS_RECEIVED) this.#state = XMLHttpRequest.LOADING; @@ -366,7 +395,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ const processEndOfBody = () => { - debug('xhr:response')(`end of body, received ${this.#receivedLength} bytes`); + this.#debug('xhr:response')(`end of body, received ${this.#receivedLength} bytes`); const transmitted = this.#receivedLength; // step 3 const length = responseLength || 0; // step 4 @@ -379,8 +408,8 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget this.dispatchEvent(new ProgressEvent(eventType, { loaded:transmitted, total:length })); }; - debug('xhr:send')(`${this.#requestMethod} ${this.#requestURL.href}`); - debug('xhr:headers')('headers=' + Object.entries(this.#requestHeaders)); + this.#debug('xhr:send')(`${this.#requestMethod} ${this.#requestURL.href}`); + this.#debug('xhr:headers')('headers=' + Object.entries(this.#requestHeaders)); // send() step 6 request( @@ -396,6 +425,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget processEndOfBody, () => (this.#timedOutFlag = true), // onTimeoutError () => (this.#response = null /* network error */), // onNetworkError + this.#debug.bind(this), ).catch((e) => this.#handleErrors(e)); } @@ -446,12 +476,12 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget this.#uploadCompleteFlag = true; if (this.#uploadListenerFlag) { - this.#uploadObject.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0 })); + this.#uploadObject.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0, error: exception })); this.#uploadObject.dispatchEvent(new ProgressEvent('loadend', { loaded:0, total:0 })); } } - this.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0 })); // step 7 + this.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0, error: exception })); // step 7 this.dispatchEvent(new ProgressEvent('loadend', { loaded:0, total:0 })); // step 8 } diff --git a/python/pythonmonkey/builtin_modules/base64.py b/python/pythonmonkey/builtin_modules/base64.py index 12ca25a0..97e29ade 100644 --- a/python/pythonmonkey/builtin_modules/base64.py +++ b/python/pythonmonkey/builtin_modules/base64.py @@ -8,7 +8,8 @@ def atob(b64): - return str(base64.standard_b64decode(b64), 'latin1') + padding = '=' * (4 - (len(b64) & 3)) + return str(base64.standard_b64decode(b64 + padding), 'latin1') def btoa(data): diff --git a/python/pythonmonkey/builtin_modules/console.js b/python/pythonmonkey/builtin_modules/console.js index bae4fc62..a2024d8c 100644 --- a/python/pythonmonkey/builtin_modules/console.js +++ b/python/pythonmonkey/builtin_modules/console.js @@ -98,11 +98,14 @@ class Console const header = args.length > 0 ? `Trace: ${format(...args)}\n` : 'Trace\n'; - const stacks = new Error().stack - .split('\n') - .filter(s => s !== '') // filter out empty lines - .map(s => ' '+s) // add indent - .join('\n'); + + let stacks = new Error().stack + .split('\n') + stacks.shift(); // skip the first line which is this.trace itself + stacks = stacks + .filter(s => s !== '') // filter out empty lines + .map(s => ' '+s) // add indent + .join('\n'); return this.debug(header + stacks); }; diff --git a/python/pythonmonkey/builtin_modules/util.js b/python/pythonmonkey/builtin_modules/util.js index 91aba2f5..358bfcf6 100644 --- a/python/pythonmonkey/builtin_modules/util.js +++ b/python/pythonmonkey/builtin_modules/util.js @@ -629,9 +629,9 @@ function formatValue(ctx, value, recurseTimes, ln) else if (isError(value)) { // Make error with message first say the error - if (keyLength === 0 || keys.every(k => k === 'stack')) // There's only a 'stack' property + if (keyLength === 0 || keys.every(k => k === 'stack' || k === 'name')) // There's only a 'stack' or 'name' property return formatError(ctx, value); - keys = keys.filter(k => k !== 'stack'); // When changing the 'stack' property in SpiderMonkey, it becomes enumerable. + keys = keys.filter(k => k !== 'stack' && k !== 'name'); // When changing the 'stack' or the 'name' property in SpiderMonkey, it becomes enumerable. base = ` ${formatError(ctx, value)}\n`; braces.length=0; } @@ -773,10 +773,12 @@ function formatError(ctx, error) .split('\n') .filter(a => a.length > 0) .map(a => ` ${a}`); - const retstr - = `${error.name}: ${error.message}\n` - + stackEls[0] + '\n' - + style(stackEls.slice(1).join('\n')); + let retstr = `${error.name}: ${error.message}\n`; + if (stackEls.length) + { + retstr += stackEls[0] + '\n'; + if (stackEls.length > 1) retstr += style(stackEls.slice(1).join('\n')); + } return retstr; } diff --git a/python/pythonmonkey/cli/pmjs.py b/python/pythonmonkey/cli/pmjs.py index a7a50070..1e48f83e 100755 --- a/python/pythonmonkey/cli/pmjs.py +++ b/python/pythonmonkey/cli/pmjs.py @@ -378,9 +378,37 @@ async def runEvalPrint(): if (len(args) > 0): async def runJS(): - globalInitModule.patchGlobalRequire() - pm.runProgramModule(args[0], args, requirePath) - await pm.wait() # blocks until all asynchronous calls finish + hasUncaughtException = False + loop = asyncio.get_running_loop() + + def exceptionHandler(loop, context): + "See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api" + error = context["exception"] + try: + globalInitModule.uncaughtExceptionHandler(error) + except SystemExit: # the "exception" raised by `sys.exit()` call + pass + finally: + pm.stop() # unblock `await pm.wait()` to gracefully exit the program + nonlocal hasUncaughtException + hasUncaughtException = True + loop.set_exception_handler(exceptionHandler) + + def cleanupExit(code=0): + pm.stop() + realExit(code) + realExit = globalThis.python.exit + globalThis.python.exit = cleanupExit + + try: + globalInitModule.patchGlobalRequire() + pm.runProgramModule(args[0], args, requirePath) + await pm.wait() # blocks until all asynchronous calls finish + if hasUncaughtException: + sys.exit(1) + except Exception as error: + print(error, file=sys.stderr) + sys.exit(1) try: asyncio.run(runJS()) except KeyboardInterrupt: diff --git a/python/pythonmonkey/helpers.py b/python/pythonmonkey/helpers.py index 5a1c718f..76970edc 100644 --- a/python/pythonmonkey/helpers.py +++ b/python/pythonmonkey/helpers.py @@ -43,8 +43,19 @@ def new(ctor): return (lambda *args: newCtor(list(args))) +def simpleUncaughtExceptionHandler(loop, context): + """ + A simple exception handler for uncaught JS Promise rejections sent to the Python event-loop + + See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api + """ + error = context["exception"] + pm.eval("(err) => console.error('Uncaught', err)")(error) + pm.stop() # unblock `await pm.wait()` to gracefully exit the program + + # List which symbols are exposed to the pythonmonkey module. -__all__ = ["new", "typeof"] +__all__ = ["new", "typeof", "simpleUncaughtExceptionHandler"] # Add the non-enumerable properties of globalThis which don't collide with pythonmonkey.so as exports: globalThis = pm.eval('globalThis') diff --git a/python/pythonmonkey/lib/pmdb.py b/python/pythonmonkey/lib/pmdb.py index 9f5ffcab..f7afdc30 100644 --- a/python/pythonmonkey/lib/pmdb.py +++ b/python/pythonmonkey/lib/pmdb.py @@ -22,7 +22,7 @@ def enable(debuggerGlobalObject=pm.eval("debuggerGlobal")): return # already enabled, skipping debuggerGlobalObject._pmdbEnabled = True - debuggerGlobalObject.eval("""(debuggerInput, _pythonPrint, _pythonExit) => { + pm.eval("debuggerGlobal.eval")("""(mainGlobal, debuggerInput, _pythonPrint, _pythonExit) => { const dbg = new Debugger() const mainDebuggee = dbg.addDebuggee(mainGlobal) dbg.uncaughtExceptionHook = (e) => { @@ -177,4 +177,4 @@ def enable(debuggerGlobalObject=pm.eval("debuggerGlobal")): // Enter debugger on `debugger;` statement dbg.onDebuggerStatement = (frame) => enterDebuggerLoop(frame) - }""")(debuggerInput, print, lambda status: exit(int(status))) + }""")(pm.globalThis, debuggerInput, print, lambda status: exit(int(status))) diff --git a/python/pythonmonkey/lib/pmjs/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js index d1ac6ee8..87f3a5be 100644 --- a/python/pythonmonkey/lib/pmjs/global-init.js +++ b/python/pythonmonkey/lib/pmjs/global-init.js @@ -17,6 +17,21 @@ for (let mid in require.cache) delete require.cache[mid]; +/* Recreate the python object as an EventEmitter */ +const { EventEmitter } = require('events'); +const originalPython = globalThis.python; +const python = globalThis.python = new EventEmitter('python'); +Object.assign(python, originalPython); + +/* Emulate node's process.on('error') behaviour with python.on('error'). */ +python.on('error', function unhandledError(error) +{ + if (python.listenerCount('error') > 1) + return; + if (python.listenerCount('error') === 0 || python.listeners('error')[0] === unhandledError) + python.emit('unhandledException', error); +}); + /** * runProgramModule wants to include the require.cache from the pre-program loads (e.g. via -r or -e), but * due to current bugs in PythonMonkey, we can't access the cache property of require because it is a JS @@ -34,4 +49,33 @@ exports.patchGlobalRequire = function pmjs$$patchGlobalRequire() exports.initReplLibs = function pmjs$$initReplLibs() { globalThis.util = require('util'); + globalThis.events = require('events'); +}; + +/** + * Temporary API until we get EventEmitters working. Replace this export with a custom handler. + */ +exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler(error) +{ + if (python._events && python._events['uncaughtException']) + python.emit('uncaughtException', error); + else + { + console.error('Uncaught', error); + python.exit(1); + } +}; + +/** + * Temporary API until we get EventEmitters working. Replace this export with a custom handler. + */ +exports.unhandledRejectionHandler = function globalInit$$unhandledRejectionHandler(error) +{ + if (python._events && python._events['uncaughtRejection']) + python.emit('unhandledRejection', error); + else + { + console.error(error); + python.exit(1); + } }; diff --git a/python/pythonmonkey/py.typed b/python/pythonmonkey/py.typed new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/python/pythonmonkey/py.typed @@ -0,0 +1 @@ + diff --git a/python/pythonmonkey/pythonmonkey.pyi b/python/pythonmonkey/pythonmonkey.pyi index 95595373..b6e81761 100644 --- a/python/pythonmonkey/pythonmonkey.pyi +++ b/python/pythonmonkey/pythonmonkey.pyi @@ -1,4 +1,5 @@ """ +stub file for type hints & documentations for the native module @see https://typing.readthedocs.io/en/latest/source/stubs.html """ @@ -25,6 +26,25 @@ def eval(code: str, evalOpts: EvalOptions = {}, /) -> _typing.Any: """ +def require(moduleIdentifier: str, /) -> JSObjectProxy: + """ + Return the exports of a CommonJS module identified by `moduleIdentifier`, using standard CommonJS semantics + """ + + +def new(ctor: JSFunctionProxy) -> _typing.Callable[..., _typing.Any]: + """ + Wrap the JS new operator, emitting a lambda which constructs a new + JS object upon invocation + """ + + +def typeof(jsval: _typing.Any, /): + """ + This is the JS `typeof` operator, wrapped in a function so that it can be used easily from Python. + """ + + def wait() -> _typing.Awaitable[None]: """ Block until all asynchronous jobs (Promise/setTimeout/etc.) finish. @@ -37,6 +57,18 @@ def wait() -> _typing.Awaitable[None]: """ +def stop() -> None: + """ + Stop all pending asynchronous jobs, and unblock `await pm.wait()` + """ + + +def runProgramModule(filename: str, argv: _typing.List[str], extraPaths: _typing.List[str] = []) -> None: + """ + Load and evaluate a program (main) module. Program modules must be written in JavaScript. + """ + + def isCompilableUnit(code: str) -> bool: """ Hint if a string might be compilable Javascript without actual evaluation @@ -49,6 +81,14 @@ def collect() -> None: """ +def internalBinding(namespace: str) -> JSObjectProxy: + """ + INTERNAL USE ONLY + + See function declarations in ./builtin_modules/internal-binding.d.ts + """ + + class JSFunctionProxy(): """ JavaScript Function proxy @@ -75,13 +115,60 @@ class JSMethodProxy(JSFunctionProxy, object): print(myObject.value) # 42.0 """ - def __init__(self) -> None: - """ - PythonMonkey init function - """ + def __init__(self) -> None: "deleted" + + +class JSObjectProxy(dict): + """ + JavaScript Object proxy dict + """ + + def __init__(self) -> None: "deleted" + + +class JSArrayProxy(list): + """ + JavaScript Array proxy + """ + + def __init__(self) -> None: "deleted" + + +class JSArrayIterProxy(_typing.Iterator): + """ + JavaScript Array Iterator proxy + """ + + def __init__(self) -> None: "deleted" + + +class JSStringProxy(str): + """ + JavaScript String proxy + """ + + def __init__(self) -> None: "deleted" + + +class bigint(int): + """ + Representing JavaScript BigInt in Python + """ + + +class SpiderMonkeyError(Exception): + """ + Representing a corresponding JS Error in Python + """ null = _typing.Annotated[ - _typing.NewType("pythonmonkey.null", object), - "Representing the JS null type in Python using a singleton object", + _typing.NewType("pythonmonkey.null", object), + "Representing the JS null type in Python using a singleton object", +] + + +globalThis = _typing.Annotated[ + JSObjectProxy, + "A Python Dict which is equivalent to the globalThis object in JavaScript", ] diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index 957dd585..696a4fbb 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -82,8 +82,10 @@ globalThis.python.stderr.write = lambda s: sys.stderr.write(s) globalThis.python.stdout.read = lambda n: sys.stdout.read(n) globalThis.python.stderr.read = lambda n: sys.stderr.read(n) -globalThis.python.eval = eval -globalThis.python.exec = exec +# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works +# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals +globalThis.python.eval = lambda x: eval(str(x)[:], None, sys._getframe(1).f_locals) +globalThis.python.exec = lambda x: exec(str(x)[:], None, sys._getframe(1).f_locals) globalThis.python.getenv = os.getenv globalThis.python.paths = sys.path @@ -409,7 +411,8 @@ def runProgramModule(filename, argv, extraPaths=[]): globalThis.__filename = fullFilename globalThis.__dirname = os.path.dirname(fullFilename) with open(fullFilename, encoding="utf-8", mode="r") as mainModuleSource: - pm.eval(mainModuleSource.read(), {'filename': fullFilename}) + pm.eval(mainModuleSource.read(), {'filename': fullFilename, 'noScriptRval': True}) + # forcibly run in file mode. We shouldn't be getting the last expression of the script as the result value. # The pythonmonkey require export. Every time it is used, the stack is inspected so that the filename # passed to createRequire is correct. This is necessary so that relative requires work. If the filename diff --git a/setup.sh b/setup.sh index e07bd680..c4033863 100755 --- a/setup.sh +++ b/setup.sh @@ -2,28 +2,23 @@ set -euo pipefail IFS=$'\n\t' -# set git hooks -ln -s -f ../../githooks/pre-commit .git/hooks/pre-commit -# set blame ignore file -git config blame.ignorerevsfile .git-blame-ignore-revs - # Get number of CPU cores CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1) echo "Installing dependencies" if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux - sudo apt-get update --yes - sudo apt-get install --yes cmake graphviz llvm clang pkg-config m4 \ - wget curl python3-distutils python3-dev - # Install Doxygen - # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series - wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz - tar xf doxygen-1.9.7.linux.bin.tar.gz - cd doxygen-1.9.7 && sudo make install && cd - - rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz + SUDO='' + if command -v sudo >/dev/null; then + # sudo is present on the system, so use it + SUDO='sudo' + fi + echo "Installing apt packages" + $SUDO apt-get install --yes cmake llvm clang pkg-config m4 unzip \ + wget curl python3-dev elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS brew update || true # allow failure - brew install cmake doxygen pkg-config wget coreutils # `coreutils` installs the `realpath` command + brew install cmake pkg-config wget unzip coreutils # `coreutils` installs the `realpath` command + brew install lld elif [[ "$OSTYPE" == "msys"* ]]; then # Windows echo "Dependencies are not going to be installed automatically on Windows." else @@ -31,61 +26,63 @@ else exit 1 fi # Install rust compiler -curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.69 # force to use Rust 1.69 because 1.70 has linking issues on Windows +echo "Installing rust compiler" +curl --proto '=https' --tlsv1.2 https://raw.githubusercontent.com/rust-lang/rustup/refs/tags/1.28.2/rustup-init.sh -sSf | sh -s -- -y --default-host "$(clang --print-target-triple)" --default-toolchain 1.85 +CARGO_BIN="$HOME/.cargo/bin/cargo" # also works for Windows. On Windows this equals to %USERPROFILE%\.cargo\bin\cargo +$CARGO_BIN install cbindgen # Setup Poetry +echo "Installing poetry" curl -sSL https://install.python-poetry.org | python3 - --version "1.7.1" if [[ "$OSTYPE" == "msys"* ]]; then # Windows POETRY_BIN="$APPDATA/Python/Scripts/poetry" else - POETRY_BIN=`echo ~/.local/bin/poetry` # expand tilde + POETRY_BIN="$HOME/.local/bin/poetry" fi $POETRY_BIN self add 'poetry-dynamic-versioning[plugin]' -$POETRY_BIN run pip install autopep8 echo "Done installing dependencies" -echo "Downloading uncrustify source code" -wget -c -q https://github.com/uncrustify/uncrustify/archive/refs/tags/uncrustify-0.78.1.tar.gz -mkdir -p uncrustify-source -tar -xzvf uncrustify-0.78.1.tar.gz -C uncrustify-source --strip-components=1 # strip the root folder -echo "Done downloading uncrustify source code" - -echo "Building uncrustify" -cd uncrustify-source -mkdir -p build -cd build -cmake ../ -make -j4 -cp uncrustify ../../uncrustify -cd ../.. -echo "Done building uncrustify" - echo "Downloading spidermonkey source code" -wget -c -q https://ftp.mozilla.org/pub/firefox/releases/115.8.0esr/source/firefox-115.8.0esr.source.tar.xz -mkdir -p firefox-source -tar xf firefox-115.8.0esr.source.tar.xz -C firefox-source --strip-components=1 # strip the root folder +# Read the commit hash for mozilla-central from the `mozcentral.version` file +MOZCENTRAL_VERSION=$(cat mozcentral.version) +wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://github.com/mozilla-firefox/firefox/archive/${MOZCENTRAL_VERSION}.zip +unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv firefox-${MOZCENTRAL_VERSION} firefox-source echo "Done downloading spidermonkey source code" echo "Building spidermonkey" cd firefox-source + +# Apply patching # making it work for both GNU and BSD (macOS) versions of sed sed -i'' -e 's/os not in ("WINNT", "OSX", "Android")/os not in ("WINNT", "Android")/' ./build/moz.configure/pkg.configure # use pkg-config on macOS -sed -i'' -e '/"WindowsDllMain.cpp"/d' ./mozglue/misc/moz.build # https://discourse.mozilla.org/t/105671, https://bugzilla.mozilla.org/show_bug.cgi?id=1751561 -sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mozilla.org/show_bug.cgi?id=1802675 -sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `install-name-tool` does not exist, but we have `install_name_tool` sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here +sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py # would generate a Makefile to install the binary files from an invalid path prefix +sed -i'' -e 's/% self._pretty_path(libdef.import_path, backend_file)/% libdef.import_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py # same as above. Shall we file a bug in bugzilla? +sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the required version is not available on Github Actions runner +sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable FinalizationRegistry +sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers +sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction +sed -i'' -e '/MOZ_ASSERT(stackRootPtr == nullptr);/d' ./js/src/vm/JSContext.cpp # would assert false in Debug Build since we extensively use `new JS::Rooted` +sed -i'' -e 's/"-fuse-ld=ld"/"-ld64" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking +sed -i'' -e 's/defined(XP_WIN)/defined(_WIN32)/' ./mozglue/baseprofiler/public/BaseProfilerUtils.h # this header file is introduced to js/Debug.h in https://phabricator.services.mozilla.com/D221102, but it would be compiled without XP_WIN in this building configuration + cd js/src mkdir -p _build cd _build mkdir -p ../../../../_spidermonkey_install/ -../configure \ +../configure --target=$(clang --print-target-triple) \ --prefix=$(realpath $PWD/../../../../_spidermonkey_install) \ --with-intl-api \ - --without-system-zlib \ + $(if [[ "$OSTYPE" != "msys"* ]]; then echo "--without-system-zlib"; fi) \ --disable-debug-symbols \ --disable-jemalloc \ --disable-tests \ - --enable-optimize + $(if [[ "$OSTYPE" == "darwin"* ]]; then echo "--enable-linker=ld64"; fi) \ + --enable-optimize \ + --disable-explicit-resource-management +# disable-explicit-resource-management: Disable the `using` syntax that is enabled by default in SpiderMonkey nightly, otherwise the header files will disagree with the compiled lib .so file +# when it's using a `IF_EXPLICIT_RESOURCE_MANAGEMENT` macro, e.g., the `enum JSProtoKey` index would be off by 1 (header `JSProto_Uint8Array` 27 will be interpreted as `JSProto_Int8Array` in lib as lib has an extra element) +# https://bugzilla.mozilla.org/show_bug.cgi?id=1940342 make -j$CPUS echo "Done building spidermonkey" @@ -99,3 +96,35 @@ if [[ "$OSTYPE" == "darwin"* ]]; then # macOS install_name_tool -id @rpath/$(basename ./libmozjs*) ./libmozjs* # making it work for whatever name the libmozjs dylib is called fi echo "Done installing spidermonkey" + +# if this is being ran in the root directory of the PythonMonkey repo, then include dev configurations +if test -f .git/hooks/pre-commit; then + # set git hooks + ln -s -f ../../githooks/pre-commit .git/hooks/pre-commit + # set blame ignore file + git config blame.ignorerevsfile .git-blame-ignore-revs + # install autopep8 + $POETRY_BIN run pip install autopep8 + # install uncrustify + echo "Downloading uncrustify source code" + wget -c -q https://github.com/uncrustify/uncrustify/archive/refs/tags/uncrustify-0.78.1.tar.gz + mkdir -p uncrustify-source + tar -xzf uncrustify-0.78.1.tar.gz -C uncrustify-source --strip-components=1 # strip the root folder + echo "Done downloading uncrustify source code" + + echo "Building uncrustify" + cd uncrustify-source + mkdir -p build + cd build + if [[ "$OSTYPE" == "msys"* ]]; then # Windows + cmake ../ + cmake --build . -j$CPUS --config Release + cp Release/uncrustify.exe ../../uncrustify.exe + else + cmake ../ + make -j$CPUS + cp uncrustify ../../uncrustify + fi + cd ../.. + echo "Done building uncrustify" +fi diff --git a/src/BufferType.cc b/src/BufferType.cc index a97b9aa0..f0726bce 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -9,13 +9,56 @@ */ #include "include/BufferType.hh" - +#include "include/PyBytesProxyHandler.hh" #include #include #include #include +#include + +// JS to Python + +/* static */ +const char *BufferType::_toPyBufferFormatCode(JS::Scalar::Type subtype) { + // floating point types + switch (subtype) { + case JS::Scalar::Float16: + return "e"; + case JS::Scalar::Float32: + return "f"; + case JS::Scalar::Float64: + return "d"; + } + + // integer types + bool isSigned = JS::Scalar::isSignedIntType(subtype); + uint8_t byteSize = JS::Scalar::byteSize(subtype); + // Python `array` type codes are strictly mapped to basic C types (e.g., `int`), widths may vary on different architectures, + // but JS TypedArray uses fixed-width integer types (e.g., `uint32_t`) + switch (byteSize) { + case sizeof(char): + return isSigned ? "b" : "B"; + case sizeof(short): + return isSigned ? "h" : "H"; + case sizeof(int): + return isSigned ? "i" : "I"; + // case sizeof(long): // compile error: duplicate case value + // // And this is usually where the bit widths on 32/64-bit systems don't agree, + // // see https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models + // return isSigned ? "l" : "L"; + case sizeof(long long): + return isSigned ? "q" : "Q"; + default: // invalid + return "x"; // type code for pad bytes, no value + } +} + +/* static */ +bool BufferType::isSupportedJsTypes(JSObject *obj) { + return JS::IsArrayBufferObject(obj) || JS_IsTypedArrayObject(obj); +} PyObject *BufferType::getPyObject(JSContext *cx, JS::HandleObject bufObj) { PyObject *pyObject; @@ -32,11 +75,6 @@ PyObject *BufferType::getPyObject(JSContext *cx, JS::HandleObject bufObj) { return pyObject; } -/* static */ -bool BufferType::isSupportedJsTypes(JSObject *obj) { - return JS::IsArrayBufferObject(obj) || JS_IsTypedArrayObject(obj); -} - /* static */ PyObject *BufferType::fromJsTypedArray(JSContext *cx, JS::HandleObject typedArray) { JS::Scalar::Type subtype = JS_GetArrayBufferViewType(typedArray); @@ -90,15 +128,29 @@ PyObject *BufferType::fromJsArrayBuffer(JSContext *cx, JS::HandleObject arrayBuf return PyMemoryView_FromBuffer(&bufInfo); } + +// Python to JS + +static PyBytesProxyHandler pyBytesProxyHandler; + + JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { Py_INCREF(pyObject); // Get the pyObject's underlying buffer pointer and size Py_buffer *view = new Py_buffer{}; + bool immutable = false; if (PyObject_GetBuffer(pyObject, view, PyBUF_ND | PyBUF_WRITABLE /* C-contiguous and writable */ | PyBUF_FORMAT) < 0) { // the buffer is immutable (e.g., Python `bytes` type is read-only) - return nullptr; // raises a PyExc_BufferError + PyErr_Clear(); // a PyExc_BufferError was raised + + if (PyObject_GetBuffer(pyObject, view, PyBUF_ND /* C-contiguous */ | PyBUF_FORMAT) < 0) { + return nullptr; // a PyExc_BufferError was raised again + } + + immutable = true; } + if (view->ndim != 1) { PyErr_SetString(PyExc_BufferError, "multidimensional arrays are not allowed"); BufferType::_releasePyBuffer(view); @@ -108,22 +160,38 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { // Determine the TypedArray's subtype (Uint8Array, Float64Array, ...) JS::Scalar::Type subtype = _getPyBufferType(view); - JSObject *arrayBuffer = nullptr; + JSObject *arrayBuffer; if (view->len > 0) { // Create a new ExternalArrayBuffer object // Note: data will be copied instead of transferring the ownership when this external ArrayBuffer is "transferred" to a worker thread. // see https://hg.mozilla.org/releases/mozilla-esr102/file/a03fde6/js/public/ArrayBuffer.h#l86 + mozilla::UniquePtr dataPtr( + view->buf /* data pointer */, + {BufferType::_releasePyBuffer, view /* the `bufView` argument to `_releasePyBuffer` */} + ); + arrayBuffer = JS::NewExternalArrayBuffer(cx, - view->len /* byteLength */, view->buf /* data pointer */, - BufferType::_releasePyBuffer, view /* the `bufView` argument to `_releasePyBuffer` */ + view->len /* byteLength */, std::move(dataPtr) ); } else { // empty buffer arrayBuffer = JS::NewArrayBuffer(cx, 0); BufferType::_releasePyBuffer(view); // the buffer is no longer needed since we are creating a brand new empty ArrayBuffer } - JS::RootedObject arrayBufferRooted(cx, arrayBuffer); - return _newTypedArrayWithBuffer(cx, subtype, arrayBufferRooted); + if (!immutable) { + JS::RootedObject arrayBufferRooted(cx, arrayBuffer); + return _newTypedArrayWithBuffer(cx, subtype, arrayBufferRooted); + } else { + JS::RootedValue v(cx); + JS::RootedObject uint8ArrayPrototype(cx); + JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype); // so that instanceof will work, not that prototype methods will + JSObject *proxy = js::NewProxyObject(cx, &pyBytesProxyHandler, v, uint8ArrayPrototype.get()); + JS::SetReservedSlot(proxy, PyObjectSlot, JS::PrivateValue(pyObject)); + JS::PersistentRootedObject *arrayBufferPointer = new JS::PersistentRootedObject(cx); + arrayBufferPointer->set(arrayBuffer); + JS::SetReservedSlot(proxy, OtherSlot, JS::PrivateValue(arrayBufferPointer)); + return proxy; + } } /* static */ @@ -152,8 +220,11 @@ JS::Scalar::Type BufferType::_getPyBufferType(Py_buffer *bufView) { return JS::Scalar::Float32; } else if (typeCode == 'd') { return JS::Scalar::Float64; + } else if (typeCode == 'e') { + return JS::Scalar::Float16; } + // integer types // We can't rely on the type codes alone since the typecodes are mapped to C types and would have different sizes on different architectures // see https://docs.python.org/3.9/library/array.html#module-array @@ -175,38 +246,6 @@ JS::Scalar::Type BufferType::_getPyBufferType(Py_buffer *bufView) { } } -/* static */ -const char *BufferType::_toPyBufferFormatCode(JS::Scalar::Type subtype) { - // floating point types - if (subtype == JS::Scalar::Float32) { - return "f"; - } else if (subtype == JS::Scalar::Float64) { - return "d"; - } - - // integer types - bool isSigned = JS::Scalar::isSignedIntType(subtype); - uint8_t byteSize = JS::Scalar::byteSize(subtype); - // Python `array` type codes are strictly mapped to basic C types (e.g., `int`), widths may vary on different architectures, - // but JS TypedArray uses fixed-width integer types (e.g., `uint32_t`) - switch (byteSize) { - case sizeof(char): - return isSigned ? "b" : "B"; - case sizeof(short): - return isSigned ? "h" : "H"; - case sizeof(int): - return isSigned ? "i" : "I"; - // case sizeof(long): // compile error: duplicate case value - // // And this is usually where the bit widths on 32/64-bit systems don't agree, - // // see https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models - // return isSigned ? "l" : "L"; - case sizeof(long long): - return isSigned ? "q" : "Q"; - default: // invalid - return "x"; // type code for pad bytes, no value - } -} - JSObject *BufferType::_newTypedArrayWithBuffer(JSContext *cx, JS::Scalar::Type subtype, JS::HandleObject arrayBuffer) { switch (subtype) { #define NEW_TYPED_ARRAY_WITH_BUFFER(ExternalType, NativeType, Name) \ diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 6c2d8ee7..620643f9 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -13,15 +13,17 @@ #include "include/ExceptionType.hh" #include "include/StrType.hh" +#include "include/DictType.hh" +#include "include/JSObjectProxy.hh" #include #include +#include #include +#include "include/pyshim.hh" -// TODO (Tom Tang): preserve the original Python exception object somewhere in the JS obj for lossless two-way conversion - PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { // Convert the JS Error object to a Python string JS::RootedValue errValue(cx, JS::ObjectValue(*error)); // err @@ -29,13 +31,13 @@ PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { PyObject *errStr = getExceptionString(cx, JS::ExceptionStack(cx, errValue, errStack), true); // Construct a new SpiderMonkeyError python object - #if PY_VERSION_HEX >= 0x03090000 PyObject *pyObject = PyObject_CallOneArg(SpiderMonkeyError, errStr); // _PyErr_CreateException, https://github.com/python/cpython/blob/3.9/Python/errors.c#L100 - #else - PyObject *pyObject = PyObject_CallFunction(SpiderMonkeyError, "O", errStr); // PyObject_CallOneArg is not available in Python < 3.9 - #endif Py_XDECREF(errStr); + // Preserve the original JS Error object as the Python Exception's `jsError` attribute for lossless two-way conversion + PyObject *originalJsErrCapsule = DictType::getPyObject(cx, errValue); + PyObject_SetAttrString(pyObject, "jsError", originalJsErrCapsule); + return pyObject; } @@ -79,6 +81,13 @@ tb_print_line_repeated(_PyUnicodeWriter *writer, long cnt) JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyObject *traceBack) { assert(exceptionValue != NULL); + if (PyObject_HasAttrString(exceptionValue, "jsError")) { + PyObject *originalJsErrCapsule = PyObject_GetAttrString(exceptionValue, "jsError"); + if (originalJsErrCapsule && PyObject_TypeCheck(originalJsErrCapsule, &JSObjectProxyType)) { + return *((JSObjectProxy *)originalJsErrCapsule)->jsObject; + } + } + // Gather JS context #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-zero-length" @@ -96,7 +105,8 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb if (stackObj.get()) { JS::RootedString stackStr(cx); JS::BuildStackString(cx, nullptr, stackObj, &stackStr, 2, js::StackFormat::SpiderMonkey); - stackStream << "\nJS Stack Trace:\n" << StrType::getValue(cx, stackStr); + JS::UniqueChars stackStrUtf8 = JS_EncodeStringToUTF8(cx, stackStr); + stackStream << "\nJS Stack Trace:\n" << stackStrUtf8.get(); } @@ -264,7 +274,7 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb JS::RootedString filename(cx, JS_NewStringCopyZ(cx, PyUnicode_AsUTF8(fileName))); JS::RootedString message(cx, JS_NewStringCopyZ(cx, msgStream.str().c_str())); // stack argument cannot be passed in as a string anymore (deprecated), and could not find a proper example using the new argument type - if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, lineno, 0, nullptr, message, JS::NothingHandleValue, &rval)) { + if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, lineno, JS::ColumnNumberOneOrigin(1), nullptr, message, JS::NothingHandleValue, &rval)) { return NULL; } @@ -294,7 +304,7 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb JS::RootedString filename(cx, JS_NewStringCopyZ(cx, "")); // cannot be null or omitted, but is overriden by the errorReport JS::RootedString message(cx, JS_NewStringCopyZ(cx, msgStream.str().c_str())); // filename cannot be null - if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, 0, 0, errorReport, message, JS::NothingHandleValue, &rval)) { + if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, 0, JS::ColumnNumberOneOrigin(1), errorReport, message, JS::NothingHandleValue, &rval)) { return NULL; } diff --git a/src/IntType.cc b/src/IntType.cc index c7a5cae5..26a7ea1e 100644 --- a/src/IntType.cc +++ b/src/IntType.cc @@ -14,6 +14,9 @@ #include #include +#include +#include "include/pyshim.hh" + #include #define SIGN_BIT_MASK 0b1000 // https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/BigIntType.h#l40 @@ -44,11 +47,7 @@ static inline void PythonLong_SetSign(PyLongObject *op, int sign) { #else // Python version is less than 3.12 // see https://github.com/python/cpython/blob/v3.9.16/Objects/longobject.c#L956 Py_ssize_t pyDigitCount = Py_SIZE(op); - #if PY_VERSION_HEX >= 0x03090000 Py_SET_SIZE(op, sign * std::abs(pyDigitCount)); - #else - ((PyVarObject *)op)->ob_size = sign * std::abs(pyDigitCount); // Py_SET_SIZE is not available in Python < 3.9 - #endif #endif } @@ -102,11 +101,7 @@ PyObject *IntType::getPyObject(JSContext *cx, JS::BigInt *bigint) { // Cast to a pythonmonkey.bigint to differentiate it from a normal Python int, // allowing Py<->JS two-way BigInt conversion. // We don't do `Py_SET_TYPE` because `_PyLong_FromByteArray` may cache and reuse objects for small ints - #if PY_VERSION_HEX >= 0x03090000 PyObject *pyObject = PyObject_CallOneArg(getPythonMonkeyBigInt(), pyIntObj); // pyObject = pythonmonkey.bigint(pyIntObj) - #else - PyObject *pyObject = PyObject_CallFunction(getPythonMonkeyBigInt(), "O", pyIntObj); // PyObject_CallOneArg is not available in Python < 3.9 - #endif Py_DECREF(pyIntObj); // Set the sign bit @@ -139,7 +134,7 @@ JS::BigInt *IntType::toJsBigInt(JSContext *cx, PyObject *pyObject) { // Convert to bytes of 8-bit "digits" in **big-endian** order size_t byteCount = (size_t)JS_DIGIT_BYTE * jsDigitCount; uint8_t *bytes = (uint8_t *)PyMem_Malloc(byteCount); - _PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false); + PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false); // Convert pm.bigint to JS::BigInt through hex strings (no public API to convert directly through bytes) // TODO (Tom Tang): We could manually allocate the memory, https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/BigIntType.cpp#l162, but still no public API diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 6fbdf465..869e1503 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -23,6 +23,7 @@ #include #include +#include "include/pyshim.hh" void JSArrayProxyMethodDefinitions::JSArrayProxy_dealloc(JSArrayProxy *self) @@ -1179,60 +1180,15 @@ static bool sort_compare_default(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } -PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = {&_Py_ID(key), &_Py_ID(reverse), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - +PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs) { static const char *const _keywords[] = {"key", "reverse", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "sort", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *keyfunc = Py_None; int reverse = 0; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); - if (!args) { - return NULL; - } - - if (!noptargs) { - goto skip_optional_kwonly; - } - - if (args[0]) { - keyfunc = args[0]; - if (!--noptargs) { - goto skip_optional_kwonly; - } - } - - reverse = PyObject_IsTrue(args[1]); - if (reverse < 0) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$Op:sort", (char **)_keywords, &keyfunc, &reverse)) { return NULL; } -skip_optional_kwonly: if (JSArrayProxy_length(self) > 1) { JS::RootedValue jReturnedArray(GLOBAL_CX); if (keyfunc != Py_None) { diff --git a/src/JSFunctionProxy.cc b/src/JSFunctionProxy.cc index d545f739..99a32552 100644 --- a/src/JSFunctionProxy.cc +++ b/src/JSFunctionProxy.cc @@ -36,7 +36,7 @@ PyObject *JSFunctionProxyMethodDefinitions::JSFunctionProxy_call(PyObject *self, JSContext *cx = GLOBAL_CX; JS::RootedValue jsFunc(GLOBAL_CX, JS::ObjectValue(**((JSFunctionProxy *)self)->jsFunc)); JSObject *jsFuncObj = jsFunc.toObjectOrNull(); - JS::RootedObject thisObj(GLOBAL_CX, JS::GetNonCCWObjectGlobal(jsFuncObj)); // if jsFunc is not bound, assume `this` is `globalThis` + JS::RootedObject thisObj(GLOBAL_CX, JS::CurrentGlobalOrNull(GLOBAL_CX)); // if jsFunc is not bound, assume `this` is `globalThis` JS::RootedVector jsArgsVector(cx); Py_ssize_t nargs = PyTuple_Size(args); diff --git a/src/JSObjectIterProxy.cc b/src/JSObjectIterProxy.cc index eb7c9fc6..0163e713 100644 --- a/src/JSObjectIterProxy.cc +++ b/src/JSObjectIterProxy.cc @@ -78,11 +78,11 @@ PyObject *JSObjectIterProxyMethodDefinitions::JSObjectIterProxy_nextkey(JSObject ret = key; } + Py_INCREF(ret); if (self->it.kind != KIND_KEYS) { Py_DECREF(value); } - Py_INCREF(ret); return ret; } } else { @@ -108,11 +108,11 @@ PyObject *JSObjectIterProxyMethodDefinitions::JSObjectIterProxy_nextkey(JSObject ret = key; } + Py_INCREF(ret); if (self->it.kind != KIND_KEYS) { Py_DECREF(value); } - Py_INCREF(ret); return ret; } } diff --git a/src/JSObjectKeysProxy.cc b/src/JSObjectKeysProxy.cc index e5d6be19..4c4e54ce 100644 --- a/src/JSObjectKeysProxy.cc +++ b/src/JSObjectKeysProxy.cc @@ -22,8 +22,7 @@ #include #include - - +#include "include/pyshim.hh" void JSObjectKeysProxyMethodDefinitions::JSObjectKeysProxy_dealloc(JSObjectKeysProxy *self) { diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 83546f37..e983335b 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -27,6 +27,7 @@ #include #include +#include "include/pyshim.hh" #include @@ -35,9 +36,10 @@ JSContext *GLOBAL_CX; /**< pointer to PythonMonkey's JSContext */ bool keyToId(PyObject *key, JS::MutableHandleId idp) { if (PyUnicode_Check(key)) { // key is str type JS::RootedString idString(GLOBAL_CX); - const char *keyStr = PyUnicode_AsUTF8(key); - JS::ConstUTF8CharsZ utf8Chars(keyStr, strlen(keyStr)); - idString.set(JS_NewStringCopyUTF8Z(GLOBAL_CX, utf8Chars)); + Py_ssize_t length; + const char *keyStr = PyUnicode_AsUTF8AndSize(key, &length); + JS::UTF8Chars utf8Chars(keyStr, length); + idString.set(JS_NewStringCopyUTF8N(GLOBAL_CX, utf8Chars)); return JS_StringToId(GLOBAL_CX, idString, idp); } else if (PyLong_Check(key)) { // key is int type uint32_t keyAsInt = PyLong_AsUnsignedLong(key); // TODO raise OverflowError if the value of pylong is out of range for a unsigned long @@ -245,7 +247,7 @@ bool JSObjectProxyMethodDefinitions::JSObjectProxy_richcompare_helper(JSObjectPr if (!js::GetPropertyKeys(GLOBAL_CX, *(self->jsObject), JSITER_OWNONLY, &props)) { PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSObjectProxyType.tp_name); - return NULL; + return false; } // iterate recursively through members of self and check for equality @@ -320,6 +322,9 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_iter_next(JSObjectProxy PyObject *retVal = JSFunctionProxyMethodDefinitions::JSFunctionProxy_call(nextFunction, PyTuple_New(0), NULL); Py_DECREF(nextFunction); + if (retVal == NULL) { + return NULL; + } // check if end of iteration key = PyUnicode_FromString("done"); @@ -338,7 +343,14 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_iter_next(JSObjectProxy } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self) { - Py_ssize_t i = Py_ReprEnter((PyObject *)self); + // Detect cyclic objects + PyObject *objPtr = PyLong_FromVoidPtr(self->jsObject->get()); + // For `Py_ReprEnter`, we must get a same PyObject when visiting the same JSObject. + // We cannot simply use the object returned by `PyLong_FromVoidPtr` because it won't reuse the PyLongObjects for ints not between -5 and 256. + // Instead, we store this PyLongObject in a global dict, using itself as the hashable key, effectively interning the PyLongObject. + PyObject *tsDict = PyThreadState_GetDict(); + PyObject *cyclicKey = PyDict_SetDefault(tsDict, /*key*/ objPtr, /*value*/ objPtr); // cyclicKey = (tsDict[objPtr] ??= objPtr) + int i = Py_ReprEnter(cyclicKey); if (i != 0) { return i > 0 ? PyUnicode_FromString("{...}") : NULL; } @@ -346,7 +358,8 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self Py_ssize_t selfLength = JSObjectProxy_length(self); if (selfLength == 0) { - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); return PyUnicode_FromString("{}"); } @@ -417,15 +430,26 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self value = pyTypeFactory(GLOBAL_CX, elementVal); } - s = PyObject_Repr(value); - if (s == NULL) { - goto error; - } + if (value != NULL) { + s = PyObject_Repr(value); + if (s == NULL) { + goto error; + } - res = _PyUnicodeWriter_WriteStr(&writer, s); - Py_DECREF(s); - if (res < 0) { - goto error; + res = _PyUnicodeWriter_WriteStr(&writer, s); + Py_DECREF(s); + if (res < 0) { + goto error; + } + } else { + // clear any exception that was just set + if (PyErr_Occurred()) { + PyErr_Clear(); + } + + if (_PyUnicodeWriter_WriteASCIIString(&writer, "", 19) < 0) { + goto error; + } } Py_CLEAR(key); @@ -437,11 +461,13 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self goto error; } - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); return _PyUnicodeWriter_Finish(&writer); error: - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); _PyUnicodeWriter_Dealloc(&writer); Py_XDECREF(key); Py_XDECREF(value); @@ -612,6 +638,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_get_method(JSObjectProxy PyObject *value = JSObjectProxy_get(self, key); if (value == Py_None) { + Py_INCREF(default_value); value = default_value; } @@ -677,7 +704,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy Py_INCREF(default_value); return default_value; } - _PyErr_SetKeyError(key); + PyErr_SetKeyError(key); return NULL; } else { @@ -756,13 +783,13 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_update_method(JSObjectPr } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_keys_method(JSObjectProxy *self) { - return _PyDictView_New((PyObject *)self, &JSObjectKeysProxyType); + return PyDictView_New((PyObject *)self, &JSObjectKeysProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_values_method(JSObjectProxy *self) { - return _PyDictView_New((PyObject *)self, &JSObjectValuesProxyType); + return PyDictView_New((PyObject *)self, &JSObjectValuesProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_items_method(JSObjectProxy *self) { - return _PyDictView_New((PyObject *)self, &JSObjectItemsProxyType); + return PyDictView_New((PyObject *)self, &JSObjectItemsProxyType); } \ No newline at end of file diff --git a/src/JSObjectValuesProxy.cc b/src/JSObjectValuesProxy.cc index f5b0a1b2..ead71b66 100644 --- a/src/JSObjectValuesProxy.cc +++ b/src/JSObjectValuesProxy.cc @@ -22,8 +22,7 @@ #include #include - - +#include "include/pyshim.hh" void JSObjectValuesProxyMethodDefinitions::JSObjectValuesProxy_dealloc(JSObjectValuesProxy *self) { diff --git a/src/JSStringProxy.cc b/src/JSStringProxy.cc new file mode 100644 index 00000000..2b68f6bb --- /dev/null +++ b/src/JSStringProxy.cc @@ -0,0 +1,29 @@ +/** + * @file JSStringProxy.cc + * @author Caleb Aikens (caleb@distributive.network) and Philippe Laporte (plaporte@distributive.network) + * @brief JSStringProxy is a custom C-implemented python type that derives from str. It acts as a proxy for JSStrings from Spidermonkey, and behaves like a str would. + * @date 2024-05-15 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + +#include "include/JSStringProxy.hh" + +#include "include/StrType.hh" + +std::unordered_set jsStringProxies; +extern JSContext *GLOBAL_CX; + + +void JSStringProxyMethodDefinitions::JSStringProxy_dealloc(JSStringProxy *self) +{ + jsStringProxies.erase(self); + delete self->jsString; +} + +PyObject *JSStringProxyMethodDefinitions::JSStringProxy_copy_method(JSStringProxy *self) { + JS::RootedString selfString(GLOBAL_CX, ((JSStringProxy *)self)->jsString->toString()); + JS::RootedValue selfStringValue(GLOBAL_CX, JS::StringValue(selfString)); + return StrType::proxifyString(GLOBAL_CX, selfStringValue); +} \ No newline at end of file diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 9a79789f..928746fd 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -9,9 +9,11 @@ */ #include "include/JobQueue.hh" +#include "include/modules/pythonmonkey/pythonmonkey.hh" #include "include/PyEventLoop.hh" #include "include/pyTypeFactory.hh" +#include "include/PromiseType.hh" #include @@ -24,8 +26,9 @@ JobQueue::JobQueue(JSContext *cx) { finalizationRegistryCallbacks = new JS::PersistentRooted(cx); // Leaks but it's OK since freed at process exit } -JSObject *JobQueue::getIncumbentGlobal(JSContext *cx) { - return JS::CurrentGlobalOrNull(cx); +bool JobQueue::getHostDefinedData(JSContext *cx, JS::MutableHandle data) const { + data.set(nullptr); // We don't need the host defined data + return true; // `true` indicates no error } bool JobQueue::enqueuePromiseJob(JSContext *cx, @@ -57,7 +60,12 @@ void JobQueue::runJobs(JSContext *cx) { bool JobQueue::empty() const { // TODO (Tom Tang): implement using `get_running_loop` and getting job count on loop??? - throw std::logic_error("JobQueue::empty is not implemented\n"); + return true; // see https://hg.mozilla.org/releases/mozilla-esr128/file/tip/js/src/builtin/Promise.cpp#l6946 +} + +bool JobQueue::isDrainingStopped() const { + // TODO (Tom Tang): implement this by detecting if the Python event-loop is still running + return false; } js::UniquePtr JobQueue::saveJobQueue(JSContext *cx) { @@ -72,6 +80,7 @@ js::UniquePtr JobQueue::saveJobQueue(JSContext *cx) bool JobQueue::init(JSContext *cx) { JS::SetJobQueue(cx, this); JS::InitDispatchToEventLoop(cx, dispatchToEventLoop, cx); + JS::SetPromiseRejectionTrackerCallback(cx, promiseRejectionTracker); return true; } @@ -113,10 +122,48 @@ bool sendJobToMainLoop(PyObject *pyFunc) { } loop.enqueue(pyFunc); + loop._loop = nullptr; // the `Py_XDECREF` Python API call in `PyEventLoop`'s destructor will not be accessible once we hand over the GIL by `PyGILState_Release` PyGILState_Release(gstate); return true; } +void JobQueue::promiseRejectionTracker(JSContext *cx, + bool mutedErrors, + JS::HandleObject promise, + JS::PromiseRejectionHandlingState state, + [[maybe_unused]] void *privateData) { + + // We only care about unhandled Promises + if (state != JS::PromiseRejectionHandlingState::Unhandled) { + return; + } + // If the `mutedErrors` option is set to True in `pm.eval`, eval errors or unhandled rejections should be ignored. + if (mutedErrors) { + return; + } + + // Test if there's no user-defined (or pmjs defined) exception handler on the Python event-loop + PyEventLoop loop = PyEventLoop::getRunningLoop(); + if (!loop.initialized()) return; + PyObject *customHandler = PyObject_GetAttrString(loop._loop, "_exception_handler"); // see https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/base_events.py#L1782 + if (customHandler == Py_None) { // we only have the default exception handler + // Set an exception handler to the event-loop + PyObject *pmModule = PyImport_ImportModule("pythonmonkey"); + PyObject *exceptionHandler = PyObject_GetAttrString(pmModule, "simpleUncaughtExceptionHandler"); + PyObject_CallMethod(loop._loop, "set_exception_handler", "O", exceptionHandler); + Py_DECREF(pmModule); + Py_DECREF(exceptionHandler); + } + Py_DECREF(customHandler); + + // Go ahead and send this unhandled Promise rejection to the exception handler on the Python event-loop + PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 + // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) + // See https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/futures.py#L108 + // or https://github.com/python/cpython/blob/v3.9.16/Modules/_asynciomodule.c#L1457-L1467 (It will actually use the C module by default, see futures.py#L417-L423) + Py_DECREF(pyFuture); // decreasing the reference count from 2 to 1, leaving one for the `onResolved` callback in `PromiseType::getPyObject`, which will be called very soon and clean up the reference +} + void JobQueue::queueFinalizationRegistryCallback(JSFunction *callback) { mozilla::Unused << finalizationRegistryCallbacks->append(callback); } diff --git a/src/PromiseType.cc b/src/PromiseType.cc index 18cd872b..5a3f94b3 100644 --- a/src/PromiseType.cc +++ b/src/PromiseType.cc @@ -10,6 +10,7 @@ #include "include/modules/pythonmonkey/pythonmonkey.hh" #include "include/PromiseType.hh" +#include "include/DictType.hh" #include "include/PyEventLoop.hh" #include "include/pyTypeFactory.hh" #include "include/jsTypeFactory.hh" @@ -18,6 +19,9 @@ #include #include +#include +#include "include/pyshim.hh" + // slot ids to access the python object in JS callbacks #define PY_FUTURE_OBJ_SLOT 0 #define PROMISE_OBJ_SLOT 1 @@ -37,11 +41,10 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { if (state == JS::PromiseState::Rejected && !PyExceptionInstance_Check(result)) { // Wrap the result object into a SpiderMonkeyError object // because only *Exception objects can be thrown in Python `raise` statement and alike - #if PY_VERSION_HEX >= 0x03090000 PyObject *wrapped = PyObject_CallOneArg(SpiderMonkeyError, result); // wrapped = SpiderMonkeyError(result) - #else - PyObject *wrapped = PyObject_CallFunction(SpiderMonkeyError, "O", result); // PyObject_CallOneArg is not available in Python < 3.9 - #endif + // Preserve the original JS value as the `jsError` attribute for lossless conversion back + PyObject *originalJsErrCapsule = DictType::getPyObject(cx, resultArg); + PyObject_SetAttrString(wrapped, "jsError", originalJsErrCapsule); Py_DECREF(result); result = wrapped; } @@ -51,7 +54,7 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { PyObject *futureObj = (PyObject *)(futureObjVal.toPrivate()); // Settle the Python asyncio.Future by the Promise's result - PyEventLoop::Future future = PyEventLoop::Future(futureObj); + PyEventLoop::Future future = PyEventLoop::Future(futureObj); // will decrease the reference count of `futureObj` in its destructor when the `onResolvedCb` function ends if (state == JS::PromiseState::Fulfilled) { future.setResult(result); } else { // state == JS::PromiseState::Rejected @@ -59,6 +62,7 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { } Py_DECREF(result); + // Py_DECREF(futureObj) // the destructor for the `PyEventLoop::Future` above already does this return true; } @@ -66,15 +70,17 @@ PyObject *PromiseType::getPyObject(JSContext *cx, JS::HandleObject promise) { // Create a python asyncio.Future on the running python event-loop PyEventLoop loop = PyEventLoop::getRunningLoop(); if (!loop.initialized()) return NULL; - PyEventLoop::Future future = loop.createFuture(); + PyEventLoop::Future future = loop.createFuture(); // ref count == 1 // Callbacks to settle the Python asyncio.Future once the JS Promise is resolved JS::RootedObject onResolved = JS::RootedObject(cx, (JSObject *)js::NewFunctionWithReserved(cx, onResolvedCb, 1, 0, NULL)); - js::SetFunctionNativeReserved(onResolved, PY_FUTURE_OBJ_SLOT, JS::PrivateValue(future.getFutureObject())); + js::SetFunctionNativeReserved(onResolved, PY_FUTURE_OBJ_SLOT, JS::PrivateValue(future.getFutureObject())); // ref count == 2 js::SetFunctionNativeReserved(onResolved, PROMISE_OBJ_SLOT, JS::ObjectValue(*promise)); - AddPromiseReactions(cx, promise, onResolved, onResolved); + JS::AddPromiseReactions(cx, promise, onResolved, onResolved); - return future.getFutureObject(); // must be a new reference + return future.getFutureObject(); // must be a new reference, ref count == 3 + // Here the ref count for the `future` object is 3, but will immediately decrease to 2 in `PyEventLoop::Future`'s destructor when the `PromiseType::getPyObject` function ends + // Leaving one reference for the returned Python object, and another one for the `onResolved` callback function } // Callback to resolve or reject the JS Promise when the Future is done diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc new file mode 100644 index 00000000..304c37c9 --- /dev/null +++ b/src/PyBytesProxyHandler.cc @@ -0,0 +1,430 @@ +/** + * @file PyBytesProxyHandler.cc + * @author Philippe Laporte (philippe@distributive.network) + * @brief Struct for creating JS Uint8Array-like proxy objects for immutable bytes objects + * @date 2024-07-23 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + + +#include "include/PyBytesProxyHandler.hh" + +#include +#include + + +const char PyBytesProxyHandler::family = 0; + + +static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); + if (!proxy) { + return false; + } + + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + auto byteLength = JS::GetArrayBufferByteLength(rootedArrayBuffer); + + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + size_t numberOfDigits = 0; + for (size_t i = 0; i < byteLength; i++) { + numberOfDigits += data[i] < 10 ? 1 : data[i] < 100 ? 2 : 3; + } + + const size_t STRING_LENGTH = byteLength + numberOfDigits; + JS::Latin1Char *buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); + + if (snprintf((char *)&buffer[0], 3 + 1, "%hu", data[0]) < 0) { + return false; + } + size_t charIndex = data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; + + for (size_t dataIndex = 1; dataIndex < byteLength; dataIndex++) { + buffer[charIndex] = ','; + charIndex++; + if (snprintf((char *)&buffer[charIndex], 3 + 1, "%hu", data[dataIndex]) < 0) { + return false; + } + charIndex += data[dataIndex] < 10 ? 1 : data[dataIndex] < 100 ? 2 : 3; + } + + JS::UniqueLatin1Chars str(buffer); + args.rval().setString(JS_NewLatin1String(cx, std::move(str), STRING_LENGTH - 1)); // don't include the null terminating byte + return true; +} + +static bool array_toString(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_valueOf(cx, argc, vp); +} + + +// BytesIterator + + +#define ITEM_KIND_KEY 0 +#define ITEM_KIND_VALUE 1 +#define ITEM_KIND_KEY_AND_VALUE 2 + +enum { + BytesIteratorSlotIteratedObject, + BytesIteratorSlotNextIndex, + BytesIteratorSlotItemKind, + BytesIteratorSlotCount +}; + +static JSClass bytesIteratorClass = {"BytesIterator", JSCLASS_HAS_RESERVED_SLOTS(BytesIteratorSlotCount)}; + +static bool iterator_next(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject thisObj(cx); + if (!args.computeThis(cx, &thisObj)) return false; + + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(thisObj, BytesIteratorSlotIteratedObject); + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + JS::RootedValue rootedNextIndex(cx, JS::GetReservedSlot(thisObj, BytesIteratorSlotNextIndex)); + JS::RootedValue rootedItemKind(cx, JS::GetReservedSlot(thisObj, BytesIteratorSlotItemKind)); + + int32_t nextIndex; + int32_t itemKind; + if (!JS::ToInt32(cx, rootedNextIndex, &nextIndex) || !JS::ToInt32(cx, rootedItemKind, &itemKind)) return false; + + JS::RootedObject result(cx, JS_NewPlainObject(cx)); + + Py_ssize_t len = JS::GetArrayBufferByteLength(rootedArrayBuffer); + + if (nextIndex >= len) { + // UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null); // TODO lose ref + JS::RootedValue done(cx, JS::BooleanValue(true)); + if (!JS_SetProperty(cx, result, "done", done)) return false; + args.rval().setObject(*result); + return result; + } + + JS::SetReservedSlot(thisObj, BytesIteratorSlotNextIndex, JS::Int32Value(nextIndex + 1)); + + JS::RootedValue done(cx, JS::BooleanValue(false)); + if (!JS_SetProperty(cx, result, "done", done)) return false; + + if (itemKind == ITEM_KIND_VALUE) { + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + JS::RootedValue value(cx, JS::Int32Value(data[nextIndex])); + if (!JS_SetProperty(cx, result, "value", value)) return false; + } + else if (itemKind == ITEM_KIND_KEY_AND_VALUE) { + JS::Rooted> items(cx); + + JS::RootedValue rootedNextIndex(cx, JS::Int32Value(nextIndex)); + items[0].set(rootedNextIndex); + + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + JS::RootedValue value(cx, JS::Int32Value(data[nextIndex])); + items[1].set(value); + + JS::RootedValue pair(cx); + JSObject *array = JS::NewArrayObject(cx, items); + pair.setObject(*array); + if (!JS_SetProperty(cx, result, "value", pair)) return false; + } + else { // itemKind == ITEM_KIND_KEY + JS::RootedValue value(cx, JS::Int32Value(nextIndex)); + if (!JS_SetProperty(cx, result, "value", value)) return false; + } + + args.rval().setObject(*result); + return true; +} + +static JSFunctionSpec bytes_iterator_methods[] = { + JS_FN("next", iterator_next, 0, JSPROP_ENUMERATE), + JS_FS_END +}; + +static bool BytesIteratorConstructor(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + if (!args.isConstructing()) { + JS_ReportErrorASCII(cx, "You must call this constructor with 'new'"); + return false; + } + + JS::RootedObject thisObj(cx, JS_NewObjectForConstructor(cx, &bytesIteratorClass, args)); + if (!thisObj) { + return false; + } + + args.rval().setObject(*thisObj); + return true; +} + +static bool DefineBytesIterator(JSContext *cx, JS::HandleObject global) { + JS::RootedObject iteratorPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Iterator, &iteratorPrototype)) { + return false; + } + + JS::RootedObject protoObj(cx, + JS_InitClass(cx, global, + nullptr, iteratorPrototype, + "BytesIterator", + BytesIteratorConstructor, 0, + nullptr, bytes_iterator_methods, + nullptr, nullptr) + ); + + return protoObj; // != nullptr +} + +/// private util +static bool array_iterator_func(JSContext *cx, unsigned argc, JS::Value *vp, int itemKind) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); + if (!proxy) { + return false; + } + + JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); + + JS::RootedValue constructor_val(cx); + if (!JS_GetProperty(cx, global, "BytesIterator", &constructor_val)) return false; + if (!constructor_val.isObject()) { + if (!DefineBytesIterator(cx, global)) { + return false; + } + + if (!JS_GetProperty(cx, global, "BytesIterator", &constructor_val)) return false; + if (!constructor_val.isObject()) { + JS_ReportErrorASCII(cx, "BytesIterator is not a constructor"); + return false; + } + } + JS::RootedObject constructor(cx, &constructor_val.toObject()); + + JS::RootedObject obj(cx); + if (!JS::Construct(cx, constructor_val, JS::HandleValueArray::empty(), &obj)) return false; + if (!obj) return false; + + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + + JS::SetReservedSlot(obj, BytesIteratorSlotIteratedObject, JS::PrivateValue(arrayBuffer)); + JS::SetReservedSlot(obj, BytesIteratorSlotNextIndex, JS::Int32Value(0)); + JS::SetReservedSlot(obj, BytesIteratorSlotItemKind, JS::Int32Value(itemKind)); + + args.rval().setObject(*obj); + return true; +} + +static bool array_entries(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_iterator_func(cx, argc, vp, ITEM_KIND_KEY_AND_VALUE); +} + +static bool array_keys(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_iterator_func(cx, argc, vp, ITEM_KIND_KEY); +} + +static bool array_values(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_iterator_func(cx, argc, vp, ITEM_KIND_VALUE); +} + + +static JSMethodDef array_methods[] = { + {"toString", array_toString, 0}, + {"valueOf", array_valueOf, 0}, + {"entries", array_entries, 0}, + {"keys", array_keys, 0}, + {"values", array_values, 0}, + {NULL, NULL, 0} +}; + + +bool PyBytesProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::HandleValue v, JS::HandleValue receiver, + JS::ObjectOpResult &result) const { + + // block all modifications + + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); + + PyErr_Format(PyExc_TypeError, + "'%.100s' object has only read-only attributes", + Py_TYPE(self)->tp_name); + + return result.failReadOnly(); +} + +bool PyBytesProxyHandler::getOwnPropertyDescriptor( + JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle> desc +) const { + // see if we're calling a function + if (id.isString()) { + for (size_t index = 0;; index++) { + bool isThatFunction; + const char *methodName = array_methods[index].name; + if (methodName == NULL) { + break; + } + else if (JS_StringEqualsAscii(cx, id.toString(), methodName, &isThatFunction) && isThatFunction) { + JSFunction *newFunction = JS_NewFunction(cx, array_methods[index].call, array_methods[index].nargs, 0, NULL); + if (!newFunction) return false; + JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*funObj), + {JS::PropertyAttribute::Enumerable} + ) + )); + return true; + } + } + } + + if (id.isString()) { + bool isProperty; + + JSString *idString = id.toString(); + + // "length" and "byteLength" properties have the same value + if ((JS_StringEqualsLiteral(cx, idString, "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty)) { + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + auto byteLength = JS::GetArrayBufferByteLength(rootedArrayBuffer); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(byteLength) + ) + )); + return true; + } + + // "buffer" property + if (JS_StringEqualsLiteral(cx, idString, "buffer", &isProperty) && isProperty) { + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*(arrayBuffer->get())) + ) + )); + return true; + } + + // "BYTES_PER_ELEMENT" property + if (JS_StringEqualsLiteral(cx, idString, "BYTES_PER_ELEMENT", &isProperty) && isProperty) { + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(1) + ) + )); + return true; + } + + // "byteOffset" property + if (JS_StringEqualsLiteral(cx, idString, "byteOffset", &isProperty) && isProperty) { + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(0) + ) + )); + return true; + } + + // "constructor" property + if (JS_StringEqualsLiteral(cx, idString, "constructor", &isProperty) && isProperty) { + JS::RootedObject uint8ArrayPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype)) { + return false; + } + + JS::RootedValue Uint8Array_Prototype_Constructor(cx); + if (!JS_GetProperty(cx, uint8ArrayPrototype, "constructor", &Uint8Array_Prototype_Constructor)) { + return false; + } + + JS::RootedObject rootedUint8ArrayPrototypeConstructor(cx, Uint8Array_Prototype_Constructor.toObjectOrNull()); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*rootedUint8ArrayPrototypeConstructor), + {JS::PropertyAttribute::Enumerable} + ) + )); + + return true; + } + } + + if (id.isSymbol()) { + JS::RootedSymbol rootedSymbol(cx, id.toSymbol()); + + if (JS::GetSymbolCode(rootedSymbol) == JS::SymbolCode::iterator) { + JSFunction *newFunction = JS_NewFunction(cx, array_values, 0, 0, NULL); + if (!newFunction) return false; + JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*funObj), + {JS::PropertyAttribute::Enumerable} + ) + )); + } else { + desc.set(mozilla::Nothing()); + } + + return true; + } + + // item + Py_ssize_t index; + if (idToIndex(cx, id, &index)) { + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(data[index]) + ) + )); + + return true; + } + + PyObject *attrName = idToKey(cx, id); + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); + PyObject *item = PyObject_GetAttr(self, attrName); + if (!item && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); // clear error, we will be returning undefined in this case + } + + return handleGetOwnPropertyDescriptor(cx, id, desc, item); +} + +void PyBytesProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { + PyObjectProxyHandler::finalize(gcx, proxy); + + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + delete arrayBuffer; +} \ No newline at end of file diff --git a/src/PyDictProxyHandler.cc b/src/PyDictProxyHandler.cc index 72d2decf..4295d2c4 100644 --- a/src/PyDictProxyHandler.cc +++ b/src/PyDictProxyHandler.cc @@ -56,7 +56,7 @@ bool PyDictProxyHandler::getOwnPropertyDescriptor( ) const { PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - PyObject *item = PyDict_GetItemWithError(self, attrName); + PyObject *item = PyDict_GetItemWithError(self, attrName); // returns NULL without an exception set if the key wasn’t present. return handleGetOwnPropertyDescriptor(cx, id, desc, item); } diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index 46904ce6..14b6f003 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -19,7 +19,12 @@ static PyObject *eventLoopJobWrapper(PyObject *jobFn, PyObject *Py_UNUSED(_)) { PyObject *ret = PyObject_CallObject(jobFn, NULL); Py_XDECREF(ret); // don't care about its return value + + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); // Protects `decCounter()`. If the error indicator is set, Python cannot make further function calls. PyEventLoop::_locker->decCounter(); + PyErr_Restore(type, value, traceback); + if (PyErr_Occurred()) { return NULL; } else { @@ -135,10 +140,44 @@ PyEventLoop PyEventLoop::_loopNotFound() { /* static */ PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { // Modified from Python 3.9 `get_running_loop` https://github.com/python/cpython/blob/7cb3a44/Modules/_asynciomodule.c#L241-L278 - #if PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 - PyObject *ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference + + PyObject *ts_dict; + #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 + // The private `_PyThreadState_GetDict(tstate)` API gets removed in Python 3.13. + // However, simply replacing it with `PyThreadState_GetDict()` does not work, + // since the public `PyThreadState_GetDict()` API can only get from the current thread. + // We need to somehow get the thread dictionary on the main thread instead of the current thread. + // + // UPDATE: We don't need the thread dictionary anymore. + // To get the thread's running event-loop in Python 3.13 is as simple as `thread_state->asyncio_running_loop` + { + // Every `PyThreadState` is actually allocated with extra fields as a `_PyThreadStateImpl` struct + // See https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_tstate.h#L17-L24 + using PyThreadStateHolder = struct { // _PyThreadStateImpl + PyThreadState base; + #if PY_VERSION_HEX >= 0x030e0000 // Python version is greater than 3.14 + // the struct is changed with more additional fields, see https://github.com/python/cpython/blob/v3.14.0rc3/Include/internal/pycore_tstate.h#L24-L40 + Py_ssize_t refcount; + uintptr_t c_stack_top; + uintptr_t c_stack_soft_limit; + uintptr_t c_stack_hard_limit; + #endif + PyObject *asyncio_running_loop; // we only need the first few fields of `_PyThreadStateImpl` + }; + + // Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Modules/_asynciomodule.c#L3205-L3210 + PyObject *loop = ((PyThreadStateHolder *)tstate)->asyncio_running_loop; + if (loop == NULL) { + return _loopNotFound(); + } + + Py_INCREF(loop); + return PyEventLoop(loop); + } + #elif PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 + ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference #else // Python 3.8 - PyObject *ts_dict = tstate->dict; // see https://github.com/python/cpython/blob/v3.8.17/Modules/_asynciomodule.c#L244-L245 + ts_dict = tstate->dict; // see https://github.com/python/cpython/blob/v3.8.17/Modules/_asynciomodule.c#L244-L245 #endif if (ts_dict == NULL) { return _loopNotFound(); @@ -210,6 +249,14 @@ void PyEventLoop::AsyncHandle::cancel() { Py_XDECREF(ret); } +/* static */ +bool PyEventLoop::AsyncHandle::cancelAll() { + for (AsyncHandle &handle: _timeoutIdMap) { + handle.cancel(); + } + return true; +} + bool PyEventLoop::AsyncHandle::cancelled() { // https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Handle.cancelled PyObject *ret = PyObject_CallMethod(_handle, "cancelled", NULL); // returns Python bool diff --git a/src/PyIterableProxyHandler.cc b/src/PyIterableProxyHandler.cc index 178dbde4..0a95603f 100644 --- a/src/PyIterableProxyHandler.cc +++ b/src/PyIterableProxyHandler.cc @@ -66,8 +66,48 @@ static bool iterable_next(JSContext *cx, unsigned argc, JS::Value *vp) { return iter_next(cx, args, it); } -JSMethodDef PyIterableProxyHandler::iterable_methods[] = { +static bool toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); + if (!proxy) { + return false; + } + + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); + + _PyUnicodeWriter writer; + + _PyUnicodeWriter_Init(&writer); + + PyObject *s = PyObject_Repr(self); + + if (s == nullptr) { + args.rval().setString(JS_NewStringCopyZ(cx, "")); + return true; + } + + int res = _PyUnicodeWriter_WriteStr(&writer, s); + Py_DECREF(s); + + if (res < 0) { + args.rval().setString(JS_NewStringCopyZ(cx, "")); + return true; + } + + PyObject *repr = _PyUnicodeWriter_Finish(&writer); + + args.rval().set(jsTypeFactory(cx, repr)); + return true; +} + +static bool iterable_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { + return toPrimitive(cx, argc, vp); +} + +static JSMethodDef iterable_methods[] = { {"next", iterable_next, 0}, + {"valueOf", iterable_valueOf, 0}, {NULL, NULL, 0} }; @@ -172,7 +212,6 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle> desc ) const { - // see if we're calling a function if (id.isString()) { for (size_t index = 0;; index++) { @@ -196,11 +235,36 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( } } + // "constructor" property + bool isConstructorProperty; + if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { + JS::RootedObject rootedObjectPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Object, &rootedObjectPrototype)) { + return false; + } + + JS::RootedValue Object_Prototype_Constructor(cx); + if (!JS_GetProperty(cx, rootedObjectPrototype, "constructor", &Object_Prototype_Constructor)) { + return false; + } + + JS::RootedObject rootedObjectPrototypeConstructor(cx, Object_Prototype_Constructor.toObjectOrNull()); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*rootedObjectPrototypeConstructor), + {JS::PropertyAttribute::Enumerable} + ) + )); + return true; + } + // symbol property if (id.isSymbol()) { JS::RootedSymbol rootedSymbol(cx, id.toSymbol()); + JS::SymbolCode symbolCode = JS::GetSymbolCode(rootedSymbol); - if (JS::GetSymbolCode(rootedSymbol) == JS::SymbolCode::iterator) { + if (symbolCode == JS::SymbolCode::iterator) { JSFunction *newFunction = JS_NewFunction(cx, iterable_values, 0, 0, NULL); if (!newFunction) return false; JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); @@ -212,11 +276,26 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( )); return true; } + else if (symbolCode == JS::SymbolCode::toPrimitive) { + JSFunction *newFunction = JS_NewFunction(cx, toPrimitive, 0, 0, nullptr); + if (!newFunction) return false; + JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*funObj), + {JS::PropertyAttribute::Enumerable} + ) + )); + return true; + } } PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - PyObject *item = PyDict_GetItemWithError(self, attrName); + PyObject *item = PyObject_GetAttr(self, attrName); + if (!item && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); // clear error, we will be returning undefined in this case + } return handleGetOwnPropertyDescriptor(cx, id, desc, item); } \ No newline at end of file diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index 2b6f9573..72da8d4e 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -24,7 +24,7 @@ #include #include - +#include "include/pyshim.hh" const char PyListProxyHandler::family = 0; @@ -428,17 +428,16 @@ static bool array_fill(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedValue fillValue(cx, args[0].get()); PyObject *fillValueItem = pyTypeFactory(cx, fillValue); - bool setItemCalled = false; for (int index = actualStart; index < actualEnd; index++) { - setItemCalled = true; + // Since each call of `PyList_SetItem` steals a reference (even if its to the same object), + // We need multiple references to it for it to steal. + Py_INCREF(fillValueItem); if (PyList_SetItem(self, index, fillValueItem) < 0) { return false; } } - if (!setItemCalled) { - Py_DECREF(fillValueItem); - } + Py_DECREF(fillValueItem); // return ref to self args.rval().set(jsTypeFactory(cx, self)); @@ -550,12 +549,7 @@ static bool array_concat(JSContext *cx, unsigned argc, JS::Value *vp) { PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_ssize_t selfSize = PyList_GET_SIZE(self); - - PyObject *result = PyList_New(selfSize); - - for (Py_ssize_t index = 0; index < selfSize; index++) { - PyList_SetItem(result, index, PyList_GetItem(self, index)); - } + PyObject *result = PyList_GetSlice(self, 0, selfSize); unsigned numArgs = args.length(); JS::RootedValue elementVal(cx); @@ -2040,8 +2034,6 @@ bool PyListProxyHandler::getOwnPropertyDescriptor( // "constructor" property bool isConstructorProperty; if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { - JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); - JS::RootedObject rootedArrayPrototype(cx); if (!JS_GetClassPrototype(cx, JSProto_Array, &rootedArrayPrototype)) { return false; @@ -2101,8 +2093,8 @@ void PyListProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - if (Py_REFCNT(self) > 1) { + if (!Py_IsFinalizing()) { + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_DECREF(self); } } diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 12bfef78..0671774c 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -21,41 +21,10 @@ #include #include +#include "include/pyshim.hh" const char PyObjectProxyHandler::family = 0; -bool PyObjectProxyHandler::object_toString(JSContext *cx, unsigned argc, JS::Value *vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - - args.rval().setString(JS_NewStringCopyZ(cx, "[object Object]")); - return true; -} - -bool PyObjectProxyHandler::object_toLocaleString(JSContext *cx, unsigned argc, JS::Value *vp) { - return object_toString(cx, argc, vp); -} - -bool PyObjectProxyHandler::object_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - - JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); - if (!proxy) { - return false; - } - PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - - // return ref to self - args.rval().set(jsTypeFactory(cx, self)); - return true; -} - -JSMethodDef PyObjectProxyHandler::object_methods[] = { - {"toString", PyObjectProxyHandler::object_toString, 0}, - {"toLocaleString", PyObjectProxyHandler::object_toLocaleString, 0}, - {"valueOf", PyObjectProxyHandler::object_valueOf, 0}, - {NULL, NULL, 0} -}; - bool PyObjectProxyHandler::handleOwnPropertyKeys(JSContext *cx, PyObject *keys, size_t length, JS::MutableHandleIdVector props) { if (!props.reserve(length)) { return false; // out of memory @@ -76,24 +45,30 @@ bool PyObjectProxyHandler::handleGetOwnPropertyDescriptor(JSContext *cx, JS::Han JS::MutableHandle> desc, PyObject *item) { // see if we're calling a function if (id.isString()) { - for (size_t index = 0;; index++) { - bool isThatFunction; - const char *methodName = object_methods[index].name; - if (methodName == NULL) { - break; + JS::UniqueChars idString = JS_EncodeStringToUTF8(cx, JS::RootedString(cx, id.toString())); + const char *methodName = idString.get(); + + if (!strcmp(methodName, "toString") || !strcmp(methodName, "toLocaleString") || !strcmp(methodName, "valueOf")) { + JS::RootedObject objectPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Object, &objectPrototype)) { + return false; } - else if (JS_StringEqualsAscii(cx, id.toString(), methodName, &isThatFunction) && isThatFunction) { - JSFunction *newFunction = JS_NewFunction(cx, object_methods[index].call, object_methods[index].nargs, 0, NULL); - if (!newFunction) return false; - JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); - desc.set(mozilla::Some( - JS::PropertyDescriptor::Data( - JS::ObjectValue(*funObj), - {JS::PropertyAttribute::Enumerable} - ) - )); - return true; + + JS::RootedValue Object_Prototype_Method(cx); + if (!JS_GetProperty(cx, objectPrototype, methodName, &Object_Prototype_Method)) { + return false; } + + JS::RootedObject rootedObjectPrototypeConstructor(cx, Object_Prototype_Method.toObjectOrNull()); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*rootedObjectPrototypeConstructor), + {JS::PropertyAttribute::Enumerable} + ) + )); + + return true; } } @@ -114,8 +89,8 @@ void PyObjectProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - if (Py_REFCNT(self) > 1) { + if (!Py_IsFinalizing()) { + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_DECREF(self); } } @@ -123,19 +98,27 @@ void PyObjectProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { bool PyObjectProxyHandler::ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleIdVector props) const { PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); PyObject *keys = PyObject_Dir(self); - size_t keysLength = PyList_Size(keys); - PyObject *nonDunderKeys = PyList_New(0); - for (size_t i = 0; i < keysLength; i++) { - PyObject *key = PyList_GetItem(keys, i); - if (PyObject_CallMethod(key, "startswith", "(s)", "__") == Py_False) { // if key starts with "__", ignore it - PyList_Append(nonDunderKeys, key); + if (keys != nullptr) { + size_t keysLength = PyList_Size(keys); + + PyObject *nonDunderKeys = PyList_New(0); + for (size_t i = 0; i < keysLength; i++) { + PyObject *key = PyList_GetItem(keys, i); + if (PyObject_CallMethod(key, "startswith", "(s)", "__") == Py_False) { // if key starts with "__", ignore it + PyList_Append(nonDunderKeys, key); + } } - } - size_t length = PyList_Size(nonDunderKeys); + return handleOwnPropertyKeys(cx, nonDunderKeys, PyList_Size(nonDunderKeys), props); + } + else { + if (PyErr_Occurred()) { + PyErr_Clear(); + } - return handleOwnPropertyKeys(cx, nonDunderKeys, length, props); + return handleOwnPropertyKeys(cx, PyList_New(0), 0, props); + } } bool PyObjectProxyHandler::delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, @@ -160,8 +143,8 @@ bool PyObjectProxyHandler::getOwnPropertyDescriptor( PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); PyObject *item = PyObject_GetAttr(self, attrName); - if (!item) { // clear error, we will be returning undefined in this case - PyErr_Clear(); + if (!item && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); // clear error, we will be returning undefined in this case } return handleGetOwnPropertyDescriptor(cx, id, desc, item); diff --git a/src/StrType.cc b/src/StrType.cc index 546e6979..a5c65788 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -10,6 +10,7 @@ #include "include/StrType.hh" #include "include/JSStringProxy.hh" +#include "include/jsTypeFactory.hh" #include #include @@ -52,21 +53,31 @@ static bool containsSurrogatePair(const char16_t *chars, size_t length) { return false; } +/** + * @brief check if the Latin-1 encoded `chars` only contain ascii characters + */ +static bool containsOnlyAscii(const JS::Latin1Char *chars, size_t length) { + for (size_t i = 0; i < length; i++) { + if (chars[i] >= 128) return false; + } + return true; +} + /** * @brief creates new UCS4-encoded pyObject string. This must be called by the user if the original JSString contains any surrogate pairs * * @return PyObject* - the UCS4-encoding of the pyObject string * */ -static PyObject *asUCS4(PyObject *pyObject) { - if (PyUnicode_KIND(pyObject) != PyUnicode_2BYTE_KIND) { +static PyObject *asUCS4(PyObject *pyString) { + if (PyUnicode_KIND(pyString) != PyUnicode_2BYTE_KIND) { // return a new reference to match the behaviour of `PyUnicode_FromKindAndData` - Py_INCREF(pyObject); - return pyObject; + Py_INCREF(pyString); + return pyString; } - uint16_t *chars = PY_UNICODE_OBJECT_DATA_UCS2(pyObject); - size_t length = PY_UNICODE_OBJECT_LENGTH(pyObject); + uint16_t *chars = PY_UNICODE_OBJECT_DATA_UCS2(pyString); + size_t length = PY_UNICODE_OBJECT_LENGTH(pyString); uint32_t *ucs4String = new uint32_t[length]; size_t ucs4Length = 0; @@ -94,45 +105,70 @@ static PyObject *asUCS4(PyObject *pyObject) { return ret; } -static PyObject *processString(JSContext *cx, JSString *str) { +PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { + JS::RootedString str(cx, strVal.toString()); JSLinearString *lstr = JS_EnsureLinearString(cx, str); JS::AutoCheckCannotGC nogc; PyObject *p; size_t length = JS::GetLinearStringLength(lstr); - PyObject *pyObject = (PyObject *)PyObject_New(JSStringProxy, &JSStringProxyType); // new reference - Py_INCREF(pyObject); + JSStringProxy *pyString = PyObject_New(JSStringProxy, &JSStringProxyType); // new reference + + if (pyString == NULL) { + return NULL; + } - ((JSStringProxy *)pyObject)->jsString.setString((JSString *)lstr); + JS::RootedObject obj(cx); + pyString->jsString = new JS::PersistentRootedValue(cx); + pyString->jsString->setString((JSString *)lstr); + jsStringProxies.insert(pyString); // Initialize as legacy string (https://github.com/python/cpython/blob/v3.12.0b1/Include/cpython/unicodeobject.h#L78-L93) // see https://github.com/python/cpython/blob/v3.11.3/Objects/unicodeobject.c#L1230-L1245 - PY_UNICODE_OBJECT_HASH(pyObject) = -1; - PY_UNICODE_OBJECT_STATE(pyObject).interned = 0; - PY_UNICODE_OBJECT_STATE(pyObject).compact = 0; - PY_UNICODE_OBJECT_STATE(pyObject).ascii = 0; - PY_UNICODE_OBJECT_UTF8(pyObject) = NULL; - PY_UNICODE_OBJECT_UTF8_LENGTH(pyObject) = 0; + PY_UNICODE_OBJECT_HASH(pyString) = -1; + PY_UNICODE_OBJECT_STATE(pyString).interned = 0; + PY_UNICODE_OBJECT_STATE(pyString).compact = 0; + PY_UNICODE_OBJECT_STATE(pyString).ascii = 0; + PY_UNICODE_OBJECT_UTF8(pyString) = NULL; + PY_UNICODE_OBJECT_UTF8_LENGTH(pyString) = 0; if (JS::LinearStringHasLatin1Chars(lstr)) { // latin1 spidermonkey, latin1 python const JS::Latin1Char *chars = JS::GetLatin1LinearStringChars(nogc, lstr); + if ((PY_VERSION_HEX) >= 0x030d0000) { // Python version is greater than 3.13 + // Short path to temporarily fix the issue with Python 3.13+ compact unicode representation. + // It would error with `ValueError: embedded null character`, which is caused by the fact that + // most Python C APIs assume the string buffer is null-terminated, so we need to create a copy. + PyObject *copied = PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, chars, length); + Py_DECREF(pyString); + return copied; + } - PY_UNICODE_OBJECT_DATA_ANY(pyObject) = (void *)chars; - PY_UNICODE_OBJECT_KIND(pyObject) = PyUnicode_1BYTE_KIND; - PY_UNICODE_OBJECT_LENGTH(pyObject) = length; + PY_UNICODE_OBJECT_DATA_ANY(pyString) = (void *)chars; + PY_UNICODE_OBJECT_KIND(pyString) = PyUnicode_1BYTE_KIND; + PY_UNICODE_OBJECT_LENGTH(pyString) = length; #if PY_UNICODE_HAS_WSTR - PY_UNICODE_OBJECT_WSTR(pyObject) = NULL; - PY_UNICODE_OBJECT_WSTR_LENGTH(pyObject) = 0; - PY_UNICODE_OBJECT_READY(pyObject) = 1; + PY_UNICODE_OBJECT_WSTR(pyString) = NULL; + PY_UNICODE_OBJECT_WSTR_LENGTH(pyString) = 0; + PY_UNICODE_OBJECT_READY(pyString) = 1; + #endif + + #ifdef Py_DEBUG + // In a debug build of CPython, it needs to be a well-formed PyUnicodeObject, otherwise a `_PyObject_AssertFailed` error will be raised. + // See: `_PyUnicode_CheckConsistency` https://github.com/python/cpython/blob/v3.11.3/Objects/unicodeobject.c#L594-L600, #L552-L553 + if (containsOnlyAscii(chars, length)) { + PY_UNICODE_OBJECT_STATE(pyString).ascii = 1; + PY_UNICODE_OBJECT_UTF8(pyString) = (char *)chars; // XXX: most APIs (e.g. PyUnicode_AsUTF8) assume this is a \0 terminated string + PY_UNICODE_OBJECT_UTF8_LENGTH(pyString) = length; + } #endif } else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); - PY_UNICODE_OBJECT_DATA_ANY(pyObject) = (void *)chars; - PY_UNICODE_OBJECT_KIND(pyObject) = PyUnicode_2BYTE_KIND; - PY_UNICODE_OBJECT_LENGTH(pyObject) = length; + PY_UNICODE_OBJECT_DATA_ANY(pyString) = (void *)chars; + PY_UNICODE_OBJECT_KIND(pyString) = PyUnicode_2BYTE_KIND; + PY_UNICODE_OBJECT_LENGTH(pyString) = length; #if PY_UNICODE_HAS_WSTR // python unicode objects take advantage of a possible performance gain on systems where @@ -141,38 +177,51 @@ static PyObject *processString(JSContext *cx, JSString *str) { // On systems where sizeof(wchar_t) == 4, i.e. Unixy systems, a similar performance gain happens if the // string is using UCS4 encoding [this is automatically handled by asUCS4()] if (sizeof(wchar_t) == 2) { - PY_UNICODE_OBJECT_WSTR(pyObject) = (wchar_t *)chars; - PY_UNICODE_OBJECT_WSTR_LENGTH(pyObject) = length; + PY_UNICODE_OBJECT_WSTR(pyString) = (wchar_t *)chars; + PY_UNICODE_OBJECT_WSTR_LENGTH(pyString) = length; } else { - PY_UNICODE_OBJECT_WSTR(pyObject) = NULL; - PY_UNICODE_OBJECT_WSTR_LENGTH(pyObject) = 0; + PY_UNICODE_OBJECT_WSTR(pyString) = NULL; + PY_UNICODE_OBJECT_WSTR_LENGTH(pyString) = 0; } - PY_UNICODE_OBJECT_READY(pyObject) = 1; + PY_UNICODE_OBJECT_READY(pyString) = 1; #endif if (containsSurrogatePair(chars, length)) { // We must convert to UCS4 here because Python does not support decoding string containing surrogate pairs to bytes - PyObject *ucs4Obj = asUCS4(pyObject); // convert to a new PyUnicodeObject with UCS4 data + PyObject *ucs4Obj = asUCS4((PyObject *)pyString); // convert to a new PyUnicodeObject with UCS4 data if (!ucs4Obj) { - // conversion fails, keep the original `pyObject` - return pyObject; + // conversion fails, keep the original `pyString` + return (PyObject *)pyString; } - Py_DECREF(pyObject); + Py_DECREF(pyString); return ucs4Obj; } + if ((PY_VERSION_HEX) >= 0x030d0000) { // Python 3.13+, fix `ValueError: embedded null character` + PyObject *copied = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, chars, length); // create a copy of the string buffer + Py_DECREF(pyString); + return copied; + } } - return pyObject; + return (PyObject *)pyString; } -PyObject *StrType::getPyObject(JSContext *cx, JSString *str) { - return processString(cx, str); -} +PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { + const PythonExternalString *callbacks; + const char16_t *ucs2Buffer{}; + const JS::Latin1Char *latin1Buffer{}; + + if ( + JS::IsExternalUCString(str.toString(), (const JSExternalStringCallbacks **)&callbacks, &ucs2Buffer) || + JS::IsExternalStringLatin1(str.toString(), (const JSExternalStringCallbacks **)&callbacks, &latin1Buffer) + ) { + if (callbacks == &PythonExternalStringCallbacks) { + PyObject *pyString = ucs2Buffer ? callbacks->getPyString(ucs2Buffer) : callbacks->getPyString(latin1Buffer); + Py_INCREF(pyString); + return pyString; + } + } -const char *StrType::getValue(JSContext *cx, JSString *str) { - PyObject *pyObject = processString(cx, str); - const char *value = PyUnicode_AsUTF8(pyObject); - Py_DECREF(pyObject); - return value; -} \ No newline at end of file + return proxifyString(cx, str); +} diff --git a/src/internalBinding/timers.cc b/src/internalBinding/timers.cc index f7adabf5..567df548 100644 --- a/src/internalBinding/timers.cc +++ b/src/internalBinding/timers.cc @@ -23,6 +23,11 @@ using AsyncHandle = PyEventLoop::AsyncHandle; */ static bool enqueueWithDelay(JSContext *cx, unsigned argc, JS::Value *vp) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) { + // quit, exit or sys.exit was called (and raised SystemExit) + return false; + } + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::HandleValue jobArgVal = args.get(0); double delaySeconds = args.get(1).toNumber(); diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index d00860d0..d1fcfb60 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -36,6 +36,7 @@ #include #include +#include "include/pyshim.hh" #include @@ -49,24 +50,66 @@ static PyObjectProxyHandler pyObjectProxyHandler; static PyListProxyHandler pyListProxyHandler; static PyIterableProxyHandler pyIterableProxyHandler; -std::unordered_map charToPyObjectMap; // a map of char16_t buffers to their corresponding PyObjects, used when finalizing JSExternalStrings +std::unordered_map externalStringObjToRefCountMap; // a map of python string objects to the number of JSExternalStrings that depend on it, used when finalizing JSExternalStrings -struct PythonExternalString : public JSExternalStringCallbacks { - void finalize(char16_t *chars) const override { - // We cannot call Py_DECREF here when shutting down as the thread state is gone. - // Then, when shutting down, there is only on reference left, and we don't need - // to free the object since the entire process memory is being released. - PyObject *object = charToPyObjectMap[chars]; - if (Py_REFCNT(object) > 1) { - Py_DECREF(object); +PyObject *PythonExternalString::getPyString(const char16_t *chars) +{ + for (auto it: externalStringObjToRefCountMap) { + if (PyUnicode_DATA(it.first) == (void *)chars) { // PyUnicode_<2/1>BYTE_DATA are just type casts of PyUnicode_DATA + return it.first; } } - size_t sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const override { - return 0; + + return NULL; // this shouldn't be reachable +} + +PyObject *PythonExternalString::getPyString(const JS::Latin1Char *chars) +{ + return PythonExternalString::getPyString((const char16_t *)chars); +} + +void PythonExternalString::finalize(char16_t *chars) const +{ + // We cannot call Py_DECREF here when shutting down as the thread state is gone. + // Then, when shutting down, there is only on reference left, and we don't need + // to free the object since the entire process memory is being released. + if (Py_IsFinalizing()) { return; } + + for (auto it = externalStringObjToRefCountMap.cbegin(), next_it = it; it != externalStringObjToRefCountMap.cend(); it = next_it) { + next_it++; + if (PyUnicode_DATA(it->first) == (void *)chars) { + Py_DECREF(it->first); + externalStringObjToRefCountMap[it->first] = externalStringObjToRefCountMap[it->first] - 1; + + if (externalStringObjToRefCountMap[it->first] == 0) { + externalStringObjToRefCountMap.erase(it); + } + } } -}; +} + +void PythonExternalString::finalize(JS::Latin1Char *chars) const +{ + PythonExternalString::finalize((char16_t *)chars); +} -static constexpr PythonExternalString PythonExternalStringCallbacks; +size_t PythonExternalString::sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const +{ + for (auto it: externalStringObjToRefCountMap) { + if (PyUnicode_DATA(it.first) == (void *)chars) { + return PyUnicode_GetLength(it.first); + } + } + + return 0; // // this shouldn't be reachable +} + +size_t PythonExternalString::sizeOfBuffer(const JS::Latin1Char *chars, mozilla::MallocSizeOf mallocSizeOf) const +{ + return PythonExternalString::sizeOfBuffer((const char16_t *)chars, mallocSizeOf); +} + +PythonExternalString PythonExternalStringCallbacks = {}; size_t UCS4ToUTF16(const uint32_t *chars, size_t length, uint16_t **outStr) { uint16_t *utf16String = (uint16_t *)malloc(sizeof(uint16_t) * length*2); @@ -112,7 +155,7 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) { returnType.setNumber(PyFloat_AsDouble(object)); } else if (PyObject_TypeCheck(object, &JSStringProxyType)) { - returnType.setString(((JSStringProxy *)object)->jsString.toString()); + returnType.setString(((JSStringProxy *)object)->jsString->toString()); } else if (PyUnicode_Check(object)) { switch (PyUnicode_KIND(object)) { @@ -126,27 +169,22 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) { break; } case (PyUnicode_2BYTE_KIND): { - charToPyObjectMap[(char16_t *)PyUnicode_2BYTE_DATA(object)] = object; - JSString *str = JS_NewExternalString(cx, (char16_t *)PyUnicode_2BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); + externalStringObjToRefCountMap[object] = externalStringObjToRefCountMap[object] + 1; + Py_INCREF(object); + JSString *str = JS_NewExternalUCString(cx, (char16_t *)PyUnicode_2BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); returnType.setString(str); break; } case (PyUnicode_1BYTE_KIND): { - charToPyObjectMap[(char16_t *)PyUnicode_2BYTE_DATA(object)] = object; - JSString *str = JS_NewExternalString(cx, (char16_t *)PyUnicode_1BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); - /* TODO (Caleb Aikens): this is a hack to set the JSString::LATIN1_CHARS_BIT, because there isnt an API for latin1 JSExternalStrings. - * Ideally we submit a patch to Spidermonkey to make this part of their API with the following signature: - * JS_NewExternalString(JSContext *cx, const char *chars, size_t length, const JSExternalStringCallbacks *callbacks) - */ - // FIXME: JSExternalString are all treated as two-byte strings when GCed - // see https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/StringType-inl.h#l514 - // https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/StringType.h#l1808 - *(std::atomic *)str |= 512; + externalStringObjToRefCountMap[object] = externalStringObjToRefCountMap[object] + 1; + Py_INCREF(object); + JSString *str = JS_NewExternalStringLatin1(cx, (JS::Latin1Char *)PyUnicode_1BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); + // JSExternalString can now be properly treated as either one-byte or two-byte strings when GCed + // see https://hg.mozilla.org/releases/mozilla-esr128/file/tip/js/src/vm/StringType-inl.h#l785 returnType.setString(str); break; } } - Py_INCREF(object); } else if (PyMethod_Check(object) || PyFunction_Check(object) || PyCFunction_Check(object)) { // can't determine number of arguments for PyCFunctions, so just assume potentially unbounded @@ -288,11 +326,11 @@ JS::Value jsTypeFactorySafe(JSContext *cx, PyObject *object) { return v; } -void setPyException(JSContext *cx) { +bool setPyException(JSContext *cx) { // Python `exit` and `sys.exit` only raise a SystemExit exception to end the program // We definitely don't want to catch it in JS if (PyErr_ExceptionMatches(PyExc_SystemExit)) { - return; + return false; } PyObject *type, *value, *traceback; @@ -308,52 +346,107 @@ void setPyException(JSContext *cx) { JS::RootedValue jsExceptionValue(cx, JS::ObjectValue(*jsException)); JS_SetPendingException(cx, jsExceptionValue); } + return true; } bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) { JS::CallArgs callargs = JS::CallArgsFromVp(argc, vp); // get the python function from the 0th reserved slot - JS::Value pyFuncVal = js::GetFunctionNativeReserved(&(callargs.callee()), 0); - PyObject *pyFunc = (PyObject *)(pyFuncVal.toPrivate()); - - unsigned int callArgsLength = callargs.length(); - - if (!callArgsLength) { - #if PY_VERSION_HEX >= 0x03090000 - PyObject *pyRval = PyObject_CallNoArgs(pyFunc); - #else - PyObject *pyRval = _PyObject_CallNoArg(pyFunc); // in Python 3.8, the API is only available under the name with a leading underscore - #endif - if (PyErr_Occurred()) { // Check if an exception has already been set in Python error stack - setPyException(cx); - return false; + PyObject *pyFunc = (PyObject *)js::GetFunctionNativeReserved(&(callargs.callee()), 0).toPrivate(); + Py_INCREF(pyFunc); + PyObject *pyRval = NULL; + PyObject *pyArgs = NULL; + Py_ssize_t nNormalArgs = 0; // number of positional non-default arguments + Py_ssize_t nDefaultArgs = 0; // number of positional default arguments + bool varargs = false; + bool unknownNargs = false; + + if (PyCFunction_Check(pyFunc)) { + const int funcFlags = ((PyCFunctionObject *)pyFunc)->m_ml->ml_flags; + if (funcFlags & METH_NOARGS) { // 0 arguments + nNormalArgs = 0; + } + else if (funcFlags & METH_O) { // 1 argument + nNormalArgs = 1; + } + else { // unknown number of arguments + nNormalArgs = 0; + unknownNargs = true; + varargs = true; + } + } + else { + nNormalArgs = 1; + PyObject *f = pyFunc; + if (PyMethod_Check(pyFunc)) { + f = PyMethod_Function(pyFunc); // borrowed reference + nNormalArgs -= 1; // don't include the implicit `self` of the method as an argument + } + PyCodeObject *bytecode = (PyCodeObject *)PyFunction_GetCode(f); // borrowed reference + PyObject *defaults = PyFunction_GetDefaults(f); // borrowed reference + nDefaultArgs = defaults ? PyTuple_Size(defaults) : 0; + nNormalArgs += bytecode->co_argcount - nDefaultArgs - 1; + if (bytecode->co_flags & CO_VARARGS) { + varargs = true; } - callargs.rval().set(jsTypeFactory(cx, pyRval)); - return true; + } + + // use faster calling if no arguments are needed + if (((nNormalArgs + nDefaultArgs) <= 0 && !varargs)) { + pyRval = PyObject_CallObject(pyFunc, NULL); + if (PyErr_Occurred() && setPyException(cx)) { // Check if an exception has already been set in Python error stack + goto failure; + } + goto success; } // populate python args tuple - PyObject *pyArgs = PyTuple_New(callArgsLength); - for (size_t i = 0; i < callArgsLength; i++) { + Py_ssize_t argTupleLength; + if (unknownNargs) { // pass all passed arguments + argTupleLength = callargs.length(); + } + else if (varargs) { // if passed arguments is less than number of non-default positionals, rest will be set to `None` + argTupleLength = std::max((Py_ssize_t)callargs.length(), nNormalArgs); + } + else if (nNormalArgs > callargs.length()) { // if passed arguments is less than number of non-default positionals, rest will be set to `None` + argTupleLength = nNormalArgs; + } + else { // passed arguments greater than non-default positionals, so we may be replacing default positional arguments + argTupleLength = std::min((Py_ssize_t)callargs.length(), nNormalArgs+nDefaultArgs); + } + pyArgs = PyTuple_New(argTupleLength); + + for (size_t i = 0; i < callargs.length() && i < argTupleLength; i++) { JS::RootedValue jsArg(cx, callargs[i]); PyObject *pyArgObj = pyTypeFactory(cx, jsArg); if (!pyArgObj) return false; // error occurred PyTuple_SetItem(pyArgs, i, pyArgObj); } - PyObject *pyRval = PyObject_Call(pyFunc, pyArgs, NULL); - if (PyErr_Occurred()) { - setPyException(cx); - return false; + // set unspecified args to None, to match JS behaviour of setting unspecified args to undefined + for (Py_ssize_t i = callargs.length(); i < argTupleLength; i++) { + PyTuple_SetItem(pyArgs, i, Py_None); } - callargs.rval().set(jsTypeFactory(cx, pyRval)); - if (PyErr_Occurred()) { - Py_DECREF(pyRval); - setPyException(cx); - return false; + + pyRval = PyObject_Call(pyFunc, pyArgs, NULL); + if (PyErr_Occurred() && setPyException(cx)) { + goto failure; } + goto success; - Py_DECREF(pyRval); +success: + if (pyRval) { // can be NULL if SystemExit was raised + callargs.rval().set(jsTypeFactory(cx, pyRval)); + Py_DECREF(pyRval); + } + Py_DECREF(pyFunc); + Py_XDECREF(pyArgs); return true; + +failure: + Py_XDECREF(pyRval); + Py_DECREF(pyFunc); + Py_XDECREF(pyArgs); + return false; } \ No newline at end of file diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 600a986d..8408b594 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -41,6 +41,7 @@ #include #include +#include "include/pyshim.hh" #include #include @@ -48,10 +49,39 @@ JS::PersistentRootedObject jsFunctionRegistry; -void finalizationRegistryGCCallback(JSContext *cx, JSGCStatus status, JS::GCReason reason, void *data) { +/** + * @brief During a GC, string buffers may have moved, so we need to re-point our JSStringProxies + * The char buffer pointer obtained by previous `JS::Get{Latin1,TwoByte}LinearStringChars` calls remains valid only as long as no GC occurs. + */ +void updateCharBufferPointers() { + if (Py_IsFinalizing()) { + return; // do not move char pointers around if python is finalizing + } + + JS::AutoCheckCannotGC nogc; + for (const JSStringProxy *jsStringProxy: jsStringProxies) { + JSLinearString *str = JS_ASSERT_STRING_IS_LINEAR(jsStringProxy->jsString->toString()); + void *updatedCharBufPtr; // pointer to the moved char buffer after a GC + if (JS::LinearStringHasLatin1Chars(str)) { + updatedCharBufPtr = (void *)JS::GetLatin1LinearStringChars(nogc, str); + } else { // utf16 / ucs2 string + updatedCharBufPtr = (void *)JS::GetTwoByteLinearStringChars(nogc, str); + } + ((PyUnicodeObject *)(jsStringProxy))->data.any = updatedCharBufPtr; + } +} + +void pythonmonkeyGCCallback(JSContext *cx, JSGCStatus status, JS::GCReason reason, void *data) { if (status == JSGCStatus::JSGC_END) { JS::ClearKeptObjects(GLOBAL_CX); while (JOB_QUEUE->runFinalizationRegistryCallbacks(GLOBAL_CX)); + updateCharBufferPointers(); + } +} + +void nurseryCollectionCallback(JSContext *cx, JS::GCNurseryProgress progress, JS::GCReason reason, void *data) { + if (progress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_END) { + updateCharBufferPointers(); } } @@ -128,8 +158,10 @@ PyTypeObject JSObjectProxyType = { PyTypeObject JSStringProxyType = { .tp_name = PyUnicode_Type.tp_name, .tp_basicsize = sizeof(JSStringProxy), + .tp_dealloc = (destructor)JSStringProxyMethodDefinitions::JSStringProxy_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_UNICODE_SUBCLASS, - .tp_doc = PyDoc_STR("Javascript String value"), + .tp_doc = PyDoc_STR("Javascript String proxy"), + .tp_methods = JSStringProxy_methods, .tp_base = &PyUnicode_Type }; @@ -271,14 +303,23 @@ PyTypeObject JSObjectItemsProxyType = { }; static void cleanup() { + // Clean up the PythonMonkey module Py_XDECREF(PythonMonkey_Null); Py_XDECREF(PythonMonkey_BigInt); + + // Clean up SpiderMonkey delete autoRealm; delete global; - if (GLOBAL_CX) JS_DestroyContext(GLOBAL_CX); + if (GLOBAL_CX) { + JS_DestroyContext(GLOBAL_CX); + GLOBAL_CX = nullptr; + } delete JOB_QUEUE; JS_ShutDown(); } +static void cleanup(PyObject *) { + cleanup(); +} static PyObject *collect(PyObject *self, PyObject *args) { JS_GC(GLOBAL_CX); @@ -293,7 +334,7 @@ static bool getEvalOption(PyObject *evalOptions, const char *optionName, const c value = PyDict_GetItemString(evalOptions, optionName); } if (value && value != Py_None) { - *s_p = PyUnicode_AsUTF8(value); + *s_p = PyUnicode_AsUTF8(PyUnicode_FromObject(value)); } return value != NULL && value != Py_None; } @@ -388,7 +429,7 @@ static PyObject *eval(PyObject *self, PyObject *args) { if (getEvalOption(evalOptions, "filename", &s)) options.setFile(s); if (getEvalOption(evalOptions, "lineno", &l)) options.setLine(l); - if (getEvalOption(evalOptions, "column", &l)) options.setColumn(l); + if (getEvalOption(evalOptions, "column", &l)) options.setColumn(JS::ColumnNumberOneOrigin(l)); if (getEvalOption(evalOptions, "mutedErrors", &b)) options.setMutedErrors(b); if (getEvalOption(evalOptions, "noScriptRval", &b)) options.setNoScriptRval(b); if (getEvalOption(evalOptions, "selfHosting", &b)) options.setSelfHostingMode(b); @@ -411,7 +452,8 @@ static PyObject *eval(PyObject *self, PyObject *args) { #endif if (!getEvalOption(evalOptions, "filename", &s)) { if (filename && PyUnicode_Check(filename)) { - options.setFile(PyUnicode_AsUTF8(filename)); + PyObject *filenameStr = PyUnicode_FromObject(filename); // needs a strict Python str object (not a subtype) + options.setFile(PyUnicode_AsUTF8(filenameStr)); } } /* filename */ } /* fromPythonFrame */ @@ -419,11 +461,12 @@ static PyObject *eval(PyObject *self, PyObject *args) { // compile the code to execute JS::RootedScript script(GLOBAL_CX); - JS::Rooted *rval = new JS::Rooted(GLOBAL_CX); + JS::Rooted rval(GLOBAL_CX); if (code) { JS::SourceText source; - const char *codeChars = PyUnicode_AsUTF8(code); - if (!source.init(GLOBAL_CX, codeChars, strlen(codeChars), JS::SourceOwnership::Borrowed)) { + Py_ssize_t codeLength; + const char *codeChars = PyUnicode_AsUTF8AndSize(code, &codeLength); + if (!source.init(GLOBAL_CX, codeChars, codeLength, JS::SourceOwnership::Borrowed)) { setSpiderMonkeyException(GLOBAL_CX); return NULL; } @@ -440,27 +483,17 @@ static PyObject *eval(PyObject *self, PyObject *args) { } // execute the compiled code; last expr goes to rval - if (!JS_ExecuteScript(GLOBAL_CX, script, rval)) { + if (!JS_ExecuteScript(GLOBAL_CX, script, &rval)) { setSpiderMonkeyException(GLOBAL_CX); return NULL; } // translate to the proper python type - PyObject *returnValue = pyTypeFactory(GLOBAL_CX, *rval); + PyObject *returnValue = pyTypeFactory(GLOBAL_CX, rval); if (PyErr_Occurred()) { return NULL; } - // TODO: Find a way to root strings for the lifetime of a proxying python string - js::ESClass cls = js::ESClass::Other; // placeholder if `rval` is not a JSObject - if (rval->isObject()) { - JS::GetBuiltinClass(GLOBAL_CX, JS::RootedObject(GLOBAL_CX, &rval->toObject()), &cls); - } - - if (!(rval->isString() || cls == js::ESClass::String)) { // rval may be a string which must be kept alive. - delete rval; - } - if (returnValue) { return returnValue; } @@ -480,6 +513,11 @@ static PyObject *waitForEventLoop(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED return PyObject_CallMethod(waiter, "wait", NULL); } +static PyObject *closeAllPending(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(_)) { + if (!PyEventLoop::AsyncHandle::cancelAll()) return NULL; + Py_RETURN_NONE; +} + static PyObject *isCompilableUnit(PyObject *self, PyObject *args) { PyObject *item = PyTuple_GetItem(args, 0); if (!PyUnicode_Check(item)) { @@ -487,17 +525,20 @@ static PyObject *isCompilableUnit(PyObject *self, PyObject *args) { return NULL; } - const char *bufferUtf8 = PyUnicode_AsUTF8(item); + Py_ssize_t bufferLength; + const char *bufferUtf8 = PyUnicode_AsUTF8AndSize(item, &bufferLength); - if (JS_Utf8BufferIsCompilableUnit(GLOBAL_CX, *global, bufferUtf8, strlen(bufferUtf8))) + if (JS_Utf8BufferIsCompilableUnit(GLOBAL_CX, *global, bufferUtf8, bufferLength)) { Py_RETURN_TRUE; - else + } else { Py_RETURN_FALSE; + } } PyMethodDef PythonMonkeyMethods[] = { {"eval", eval, METH_VARARGS, "Javascript evaluator in Python"}, {"wait", waitForEventLoop, METH_NOARGS, "The event-loop shield. Blocks until all asynchronous jobs finish."}, + {"stop", closeAllPending, METH_NOARGS, "Cancel all pending event-loop jobs."}, {"isCompilableUnit", isCompilableUnit, METH_VARARGS, "Hint if a string might be compilable Javascript"}, {"collect", collect, METH_VARARGS, "Calls the Spidermonkey garbage collector"}, {NULL, NULL, 0, NULL} @@ -523,7 +564,6 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) PyErr_SetString(SpiderMonkeyError, "Spidermonkey could not be initialized."); return NULL; } - Py_AtExit(cleanup); GLOBAL_CX = JS_NewContext(JS::DefaultHeapMaxBytes); if (!GLOBAL_CX) { @@ -548,12 +588,13 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) return NULL; } - JS_SetGCCallback(GLOBAL_CX, finalizationRegistryGCCallback, NULL); + JS_SetGCParameter(GLOBAL_CX, JSGC_MAX_BYTES, (uint32_t)-1); + + JS_SetGCCallback(GLOBAL_CX, pythonmonkeyGCCallback, NULL); + JS::AddGCNurseryCollectionCallback(GLOBAL_CX, nurseryCollectionCallback, NULL); JS::RealmCreationOptions creationOptions = JS::RealmCreationOptions(); JS::RealmBehaviors behaviours = JS::RealmBehaviors(); - creationOptions.setWeakRefsEnabled(JS::WeakRefSpecifier::EnabledWithoutCleanupSome); // enable FinalizationRegistry - creationOptions.setIteratorHelpersEnabled(true); JS::RealmOptions options = JS::RealmOptions(creationOptions, behaviours); static JSClass globalClass = {"global", JSCLASS_GLOBAL_FLAGS, &JS::DefaultGlobalClassOps}; global = new JS::RootedObject(GLOBAL_CX, JS_NewGlobalObject(GLOBAL_CX, &globalClass, nullptr, JS::FireOnNewGlobalHook, options)); @@ -565,14 +606,19 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) JS::RootedObject debuggerGlobal(GLOBAL_CX, JS_NewGlobalObject(GLOBAL_CX, &globalClass, nullptr, JS::FireOnNewGlobalHook, options)); { JSAutoRealm r(GLOBAL_CX, debuggerGlobal); - JS_DefineProperty(GLOBAL_CX, debuggerGlobal, "mainGlobal", *global, JSPROP_READONLY); JS_DefineDebuggerObject(GLOBAL_CX, debuggerGlobal); } + { + JSAutoRealm r(GLOBAL_CX, *global); + JS::Rooted desc(GLOBAL_CX, JS::PropertyDescriptor::Data( + JS::ObjectValue(*debuggerGlobal) + )); + JS_WrapPropertyDescriptor(GLOBAL_CX, &desc); + JS_DefineUCProperty(GLOBAL_CX, *global, u"debuggerGlobal", 14, desc); + } autoRealm = new JSAutoRealm(GLOBAL_CX, *global); - JS_DefineProperty(GLOBAL_CX, *global, "debuggerGlobal", debuggerGlobal, JSPROP_READONLY); - // XXX: SpiderMonkey bug??? // In https://hg.mozilla.org/releases/mozilla-esr102/file/3b574e1/js/src/jit/CacheIR.cpp#l317, trying to use the callback returned by `js::GetDOMProxyShadowsCheck()` even it's unset (nullptr) // Temporarily solved by explicitly setting the `domProxyShadowsCheck` callback here @@ -610,6 +656,16 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) if (pyModule == NULL) return NULL; + // Clean up SpiderMonkey when the PythonMonkey module gets destroyed (module.___cleanup is GCed) + // The `cleanup` function will be called automatically when this PyCapsule gets GCed + // We cannot use `Py_AtExit(cleanup);` because the GIL is unavailable after Python finalization, no more Python APIs can be called. + PyObject *autoDestructor = PyCapsule_New(&pythonmonkey, NULL, cleanup); + if (PyModule_AddObject(pyModule, "___cleanup", autoDestructor) < 0) { + Py_DECREF(autoDestructor); + Py_DECREF(pyModule); + return NULL; + } + Py_INCREF(&NullType); if (PyModule_AddObject(pyModule, "null", (PyObject *)&NullType) < 0) { Py_DECREF(&NullType); diff --git a/src/pyTypeFactory.cc b/src/pyTypeFactory.cc index fbe42b11..c11f0c1f 100644 --- a/src/pyTypeFactory.cc +++ b/src/pyTypeFactory.cc @@ -27,6 +27,7 @@ #include "include/PyListProxyHandler.hh" #include "include/PyObjectProxyHandler.hh" #include "include/PyIterableProxyHandler.hh" +#include "include/PyBytesProxyHandler.hh" #include "include/setSpiderMonkeyException.hh" #include "include/StrType.hh" #include "include/modules/pythonmonkey/pythonmonkey.hh" @@ -37,6 +38,8 @@ #include PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { + std::string errorString; + if (rval.isUndefined()) { return NoneType::getPyObject(); } @@ -50,10 +53,10 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { return FloatType::getPyObject(rval.toNumber()); } else if (rval.isString()) { - return StrType::getPyObject(cx, rval.toString()); + return StrType::getPyObject(cx, rval); } else if (rval.isSymbol()) { - printf("symbol type is not handled by PythonMonkey yet"); + errorString = "symbol type is not handled by PythonMonkey yet.\n"; } else if (rval.isBigInt()) { return IntType::getPyObject(cx, rval.toBigInt()); @@ -66,7 +69,8 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { if (js::GetProxyHandler(obj)->family() == &PyDictProxyHandler::family || // this is one of our proxies for python dicts js::GetProxyHandler(obj)->family() == &PyListProxyHandler::family || // this is one of our proxies for python lists js::GetProxyHandler(obj)->family() == &PyIterableProxyHandler::family || // this is one of our proxies for python iterables - js::GetProxyHandler(obj)->family() == &PyObjectProxyHandler::family) { // this is one of our proxies for python objects + js::GetProxyHandler(obj)->family() == &PyObjectProxyHandler::family || // this is one of our proxies for python iterables + js::GetProxyHandler(obj)->family() == &PyBytesProxyHandler::family) { // this is one of our proxies for python bytes objects PyObject *pyObject = JS::GetMaybePtrFromReservedSlot(obj, PyObjectSlot); Py_INCREF(pyObject); @@ -117,12 +121,17 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { return DictType::getPyObject(cx, rval); } else if (rval.isMagic()) { - printf("magic type is not handled by PythonMonkey yet\n"); + errorString = "magic type is not handled by PythonMonkey yet.\n"; } - std::string errorString("pythonmonkey cannot yet convert Javascript value of: "); - JS::RootedString str(cx, JS::ToString(cx, rval)); - errorString += JS_EncodeStringToUTF8(cx, str).get(); + errorString += "pythonmonkey cannot yet convert Javascript value of: "; + JSString *valToStr = JS::ToString(cx, rval); + if (!valToStr) { // `JS::ToString` returns `nullptr` for JS symbols, see https://hg.mozilla.org/releases/mozilla-esr102/file/3b574e1/js/src/vm/StringType.cpp#l2208 + // TODO (Tom Tang): Revisit this once we have Symbol coercion support + valToStr = JS_ValueToSource(cx, rval); + } + JS::RootedString valToStrRooted(cx, valToStr); + errorString += JS_EncodeStringToUTF8(cx, valToStrRooted).get(); PyErr_SetString(PyExc_TypeError, errorString.c_str()); return NULL; } \ No newline at end of file diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index 96d4c830..6d9d10fa 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -11,6 +11,7 @@ #include "include/modules/pythonmonkey/pythonmonkey.hh" #include "include/setSpiderMonkeyException.hh" #include "include/StrType.hh" +#include "include/DictType.hh" #include #include @@ -37,11 +38,15 @@ PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionS std::stringstream outStrStream; JSErrorReport *errorReport = reportBuilder.report(); - if (errorReport && errorReport->filename) { // `errorReport->filename` (the source file name) can be null + if (errorReport && !!errorReport->filename) { // `errorReport->filename` (the source file name) can be null std::string offsetSpaces(errorReport->tokenOffset(), ' '); // number of spaces equal to tokenOffset std::string linebuf; // the offending JS line of code (can be empty) - outStrStream << "Error in file " << errorReport->filename << ", on line " << errorReport->lineno << ", column " << errorReport->column << ":\n"; + /* *INDENT-OFF* */ + outStrStream << "Error in file " << errorReport->filename.c_str() + << ", on line " << errorReport->lineno + << ", column " << errorReport->column.oneOriginValue() << ":\n"; + /* *INDENT-ON* */ if (errorReport->linebuf()) { std::wstring_convert, char16_t> convert; std::u16string u16linebuf(errorReport->linebuf()); @@ -61,7 +66,8 @@ PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionS if (stackObj.get()) { JS::RootedString stackStr(cx); BuildStackString(cx, nullptr, stackObj, &stackStr, 2, js::StackFormat::SpiderMonkey); - outStrStream << "Stack Trace:\n" << StrType::getValue(cx, stackStr); + JS::UniqueChars stackStrUtf8 = JS_EncodeStringToUTF8(cx, stackStr); + outStrStream << "Stack Trace:\n" << stackStrUtf8.get(); } } @@ -102,6 +108,14 @@ void setSpiderMonkeyException(JSContext *cx) { // `PyErr_SetString` uses `PyErr_SetObject` with `PyUnicode_FromString` under the hood // see https://github.com/python/cpython/blob/3.9/Python/errors.c#L234-L236 PyObject *errStr = getExceptionString(cx, exceptionStack, printStack); - PyErr_SetObject(SpiderMonkeyError, errStr); + PyObject *errObj = PyObject_CallFunction(SpiderMonkeyError, "O", errStr); // errObj = SpiderMonkeyError(errStr) Py_XDECREF(errStr); + // Preserve the original JS value as the `jsError` attribute for lossless back conversion + PyObject *originalJsErrCapsule = DictType::getPyObject(cx, exn); + PyObject_SetAttrString(errObj, "jsError", originalJsErrCapsule); + Py_XDECREF(originalJsErrCapsule); + // `PyErr_SetObject` can accept either an already created Exception instance or the containing exception value as the second argument + // see https://github.com/python/cpython/blob/v3.9.16/Python/errors.c#L134-L150 + PyErr_SetObject(SpiderMonkeyError, errObj); + Py_XDECREF(errObj); } diff --git a/tests/js/commonjs-modules.bash b/tests/js/commonjs-modules.bash index abd6c411..0bc36f86 100755 --- a/tests/js/commonjs-modules.bash +++ b/tests/js/commonjs-modules.bash @@ -5,6 +5,8 @@ # suite causes this test to fail. # @author Wes Garland, wes@distributive.network # @date June 2023 +# +# timeout: 40 panic() { diff --git a/tests/js/console-methods.simple b/tests/js/console-methods.simple index 4c52923e..6c9a4f14 100644 --- a/tests/js/console-methods.simple +++ b/tests/js/console-methods.simple @@ -73,6 +73,7 @@ expectOutput('stderr', /^Assertion failed: abc undefined$/m, (console) => consol expectOutput('stdout', /^Trace\n/, (console) => console.trace()); expectOutput('stdout', /^Trace: \x1b\[90mundefined\x1b\[39m\n/, (console) => console.trace(undefined)); expectOutput('stdout', /^Trace: \x1b\[33m123\x1b\[39m\n/, (console) => console.trace(123)); +expectOutput('stdout', /^((?!console\.js)[\s\S])*$/, (console) => console.trace()); // implementation details should not show up in the trace // console.count() let keptConsole; diff --git a/tests/js/program-exit.bash b/tests/js/program-exit.bash new file mode 100755 index 00000000..70eb4987 --- /dev/null +++ b/tests/js/program-exit.bash @@ -0,0 +1,35 @@ +#! /bin/bash +# +# @file program-exit.bash +# A peter-jr test which shows that python.exit can cause a program to exit without +# reporting errors, even if there are pending timers. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 5 + +set -u + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./program-exit.js 2>&1 \ +| while read line + do + panic "Unexpected output '$line'" + done +exitCode="$?" +[ "$exitCode" = 0 ] || exit "$exitCode" + +"${PMJS:-../../pmjs}" ./program-exit.js +exitCode="$?" + +[ "$exitCode" = "99" ] || panic "exit code should have been 99 but was $exitCode" + +exit 0 diff --git a/tests/js/program-exit.js b/tests/js/program-exit.js new file mode 100644 index 00000000..b88b0ed2 --- /dev/null +++ b/tests/js/program-exit.js @@ -0,0 +1,8 @@ +/** + * @file program-exit.js + * Support code program-exit.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ +setTimeout(()=>console.log('hey'), 10400) +python.exit(99) diff --git a/tests/js/program-throw.bash b/tests/js/program-throw.bash new file mode 100755 index 00000000..2f4d848c --- /dev/null +++ b/tests/js/program-throw.bash @@ -0,0 +1,28 @@ +#! /bin/bash +# +# @file program-throw.bash +# A peter-jr test which shows that uncaught exceptions in the program throw, get shown +# on stderr, cause a non-zero exit code, and aren't delayed because of pending events. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 5 + +set -u + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./program-throw.js 2>&1 1>/dev/null \ +| egrep 'hello|goodbye' \ +| while read line + do + [[ "$line" =~ goodbye ]] && panic "found goodbye - timer fired when it shouldn't have!" + [[ "$line" =~ hello ]] && echo "found expected '$line'" && exit 0 + done diff --git a/tests/js/program-throw.js b/tests/js/program-throw.js new file mode 100644 index 00000000..dd842f3e --- /dev/null +++ b/tests/js/program-throw.js @@ -0,0 +1,9 @@ +/** + * @file program-throw.js + * Support code program-throw.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(() => console.error('goodbye'), 6000) +throw new Error('hello') diff --git a/tests/js/timer-reject.bash b/tests/js/timer-reject.bash new file mode 100755 index 00000000..6cc3c89e --- /dev/null +++ b/tests/js/timer-reject.bash @@ -0,0 +1,47 @@ +#! /bin/bash +# +# @file timer-reject.bash +# A peter-jr test which shows that unhandled rejections in timers get shown on stderr, +# exit with status 1, and aren't delayed because of pending events. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 10 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./timer-reject.js 2>&1 1>/dev/null \ +| egrep 'hello|goodbye|fire' \ +| ( + read line + if [[ "$line" =~ hello ]]; then + echo "found expected '$line'" + else + panic "expected hello, found '${line}'" + fi + + read line + if [[ "$line" =~ Error:.goodbye ]]; then + echo "found expected '$line'" + else + panic "expected Error: goodbye, found '${line}'" + fi + ) +exitCode="$?" + +if [ "${exitCode}" = "1" ]; then + echo pass + exit 0 +fi + +[ "$exitCode" = 2 ] || panic "Exit code was $exitCode" diff --git a/tests/js/timer-reject.js b/tests/js/timer-reject.js new file mode 100644 index 00000000..b756cd34 --- /dev/null +++ b/tests/js/timer-reject.js @@ -0,0 +1,10 @@ +/** + * @file timer-reject.js + * Support code timer-reject.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(async () => { throw new Error('goodbye') }, 600); +setTimeout(async () => { console.warn('this should not fire') }, 2000); +console.error('hello'); diff --git a/tests/js/timer-throw.bash b/tests/js/timer-throw.bash new file mode 100755 index 00000000..a3d87804 --- /dev/null +++ b/tests/js/timer-throw.bash @@ -0,0 +1,38 @@ +#! /bin/bash +# +# @file program-throw.bash +# A peter-jr test which shows that uncaught exceptions in the program throw, get shown +# on stderr, cause a non-zero exit code, and aren't delayed because of pending events. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 5 + +set -u + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./timer-throw.js 2>&1 1>/dev/null \ +| egrep 'hello|goodbye' \ +| ( + read line + if [[ "$line" =~ hello ]]; then + echo "found expected '$line'" + else + panic "expected hello, found '${line}'" + fi + + read line + if [[ "$line" =~ Error:.goodbye ]]; then + echo "found expected '$line'" + else + panic "expected Error: goodbye, found '${line}'" + fi + ) diff --git a/tests/js/timer-throw.js b/tests/js/timer-throw.js new file mode 100644 index 00000000..c9901890 --- /dev/null +++ b/tests/js/timer-throw.js @@ -0,0 +1,9 @@ +/** + * @file timer-throw.js + * Support code timer-throw.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(() => { throw new Error('goodbye') }, 600); +console.error('hello'); diff --git a/tests/js/timers-force-exit.simple b/tests/js/timers-force-exit.simple new file mode 100644 index 00000000..a18f63b5 --- /dev/null +++ b/tests/js/timers-force-exit.simple @@ -0,0 +1,13 @@ +/** + * @file timers-force-exit.simple + * ensure we can use python.exit() even though there are timers pending + * @author Wes Garland, wes@distributive.network + * @date July 2023 + * + * timeout: 4 + */ + +setTimeout(()=>console.log('fired timer'), 500000); +setTimeout(()=>console.error('should not have fired timer!'), 0); +console.log('about to exit even though timers are pending'); +python.exit(0); diff --git a/tests/js/timers-natural-exit.bash b/tests/js/timers-natural-exit.bash new file mode 100755 index 00000000..00c5532b --- /dev/null +++ b/tests/js/timers-natural-exit.bash @@ -0,0 +1,27 @@ +#! /bin/bash +# +# @file timers-natural-exit.bash +# A peter-jr test which show that programs exit when the event loop becomes empty. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./timers-natural-exit.js \ +| egrep 'end of program|fired timer' \ +| ( + read line + [ "$line" = "end of program" ] || panic "first line read was '$line', not 'end of program'" + read line + [ "$line" = "fired timer" ] || panic "second line read was '$line', not 'fired timer'" + ) diff --git a/tests/js/timers-natural-exit.js b/tests/js/timers-natural-exit.js new file mode 100644 index 00000000..178e3cae --- /dev/null +++ b/tests/js/timers-natural-exit.js @@ -0,0 +1,9 @@ +/** + * @file timers-natural-exit.js + * Support code timers-natural-exit.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(()=>console.log('fired timer'), 500); +console.log('end of program') diff --git a/tests/js/timers-segfault.simple b/tests/js/timers-segfault.simple new file mode 100644 index 00000000..afe42df3 --- /dev/null +++ b/tests/js/timers-segfault.simple @@ -0,0 +1,13 @@ +/** + * @file timers-segfault.simple + * Test using the builtin_modules/timers.js module. + * @author Wes Garland, wes@distributive.network + * @date July 2023 + * + * timeout: 10 + */ +/* eslint-disable brace-style */ + +setTimeout(() => { console.log(0); }); +const interval = setInterval(() => { console.log(1); }, 500); +setTimeout(() => { clearInterval(interval); console.log(2); }, 1000); diff --git a/tests/js/uncaught-rejection-handler.bash b/tests/js/uncaught-rejection-handler.bash new file mode 100644 index 00000000..837d286c --- /dev/null +++ b/tests/js/uncaught-rejection-handler.bash @@ -0,0 +1,53 @@ +#! /bin/bash +# +# @file uncaught-rejection-handler.bash +# For testing if the actual JS error gets printed out for uncaught Promise rejections, +# instead of printing out a Python `Future exception was never retrieved` error message when not in pmjs +# +# @author Tom Tang (xmader@distributive.network) +# @date June 2024 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +code=' +import asyncio +import pythonmonkey as pm + +async def pythonmonkey_main(): + pm.eval("""void Promise.reject(new TypeError("abc"));""") + await pm.wait() + +asyncio.run(pythonmonkey_main()) +' + +OUTPUT=$(python -c "$code" \ + < /dev/null 2>&1 +) + +echo "$OUTPUT" \ +| tr -d '\r' \ +| (grep -c 'Future exception was never retrieved' || true) \ +| while read qty + do + echo "$OUTPUT" + [ "$qty" != "0" ] && panic "There shouldn't be a 'Future exception was never retrieved' error massage" + break + done || exit $? + +echo "$OUTPUT" \ +| tr -d '\r' \ +| grep -c 'Uncaught TypeError: abc' \ +| while read qty + do + [ "$qty" != "1" ] && panic "It should print out 'Uncaught TypeError' directly" + break + done || exit $? diff --git a/tests/js/xhr-http-keep-alive.bash b/tests/js/xhr-http-keep-alive.bash new file mode 100644 index 00000000..3ac6a421 --- /dev/null +++ b/tests/js/xhr-http-keep-alive.bash @@ -0,0 +1,72 @@ +#! /bin/bash +# +# @file xhr-http-keep-alive.bash +# For testing HTTP-Keep-Alive automatically in the CI. +# +# We use `strace` to track system calls within the process that open a TCP connection. +# If HTTP-Keep-Alive is working, the total number of TCP connections opened should be 1 for a single remote host. +# +# @author Tom Tang (xmader@distributive.network) +# @date May 2024 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +if [[ "$OSTYPE" != "linux-gnu"* ]]; then + exit 0 + # Skip non-Linux for this test + # TODO: add tests on Windows and macOS. What's the equivalence of `strace`? +fi + +code=' +function newRequest(url) { + return new Promise(function (resolve, reject) + { + let xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onload = function () + { + if (this.status >= 200 && this.status < 300) resolve(this.response); + else reject(new Error(this.status)); + }; + xhr.onerror = (ev) => reject(ev.error); + xhr.send(); + }); +} + +async function main() { + await newRequest("http://www.example.org/"); + await newRequest("http://www.example.org/"); + await newRequest("http://http.badssl.com/"); +} + +main(); +' + +# Trace the `socket` system call https://man.archlinux.org/man/socket.2 +# AF_INET: IPv4, IPPROTO_TCP: TCP connection +TRACE=$(strace -f -e socket \ + "${PMJS:-pmjs}" -e "$code" \ + < /dev/null 2>&1 +) + +# We have 3 HTTP requests, but we should only have 2 TCP connections open, +# as HTTP-Keep-Alive reuses the socket for a single remote host. +echo "$TRACE" \ +| tr -d '\r' \ +| grep -c -E 'socket\(AF_INET, \w*(\|\w*)+, IPPROTO_TCP\)' \ +| while read qty + do + echo "$TRACE" + echo "TCP connections opened: $qty" + [ "$qty" != "2" ] && panic qty should not be $qty + break + done || exit $? diff --git a/tests/js/xhr.simple b/tests/js/xhr.simple deleted file mode 100644 index 2afddb55..00000000 --- a/tests/js/xhr.simple +++ /dev/null @@ -1,142 +0,0 @@ -/** - * @file xhr.simple - * - * Simple smoke test which ensures that XMLHttpRequest is initialized, that the - * constructor works, and that it can send requests and receive responses. - * - * @author Caleb Aikens, caleb@distributive.network - * @date September 2023 - */ - -const expectedBody = ` - - - Example Domain - - - - - - - - -
    -

    Example Domain

    -

    This domain is for use in illustrative examples in documents. You may use this - domain in literature without prior coordination or asking for permission.

    -

    More information...

    -
    - - -`; - -new Promise(function (resolve, reject) -{ - let xhr = new XMLHttpRequest(); - xhr.open('GET', 'http://www.example.org/'); - - xhr.onload = function () - { - if (this.status >= 200 && this.status < 300) - { - resolve(this.response); - } - else - { - reject(new Error({ - status: this.status, - statusText: this.statusText - })); - } - }; - - xhr.onerror = function () - { - reject(new Error({ - status: this.status, - statusText: this.statusText - })); - }; - - xhr.send(); -}).then((value) => -{ - if (value !== expectedBody) - { - console.error('expected ', expectedBody, ' but got ', value); - throw new Error('Test failed'); - } - console.log('Test passed'); -}).catch((error) => -{ - throw error; -}); - - -new Promise(function (resolve, reject) -{ - let xhr = new XMLHttpRequest(); - xhr.open('POST', 'http://httpbin.org/post'); - - xhr.onload = function () - { - if (this.status >= 200 && this.status < 300) - { - resolve(this.response); - } - else - { - reject(new Error({ - status: this.status, - statusText: this.statusText - })); - } - }; - - xhr.onerror = function () - { - reject(new Error({ - status: this.status, - statusText: this.statusText - })); - }; - - xhr.send(); -}).then((value) => -{ - value = JSON.parse(value); - if (!value['headers']['User-Agent'].startsWith('Python/')) - { - console.error('expected Python/* User-Agent, but got ', value.headers['User-Agent']); - } - console.log('Test passed'); -}).catch((error) => -{ - throw error; -}); \ No newline at end of file diff --git a/tests/python/test_arrays.py b/tests/python/test_arrays.py index 2f340ea5..c91b95e5 100644 --- a/tests/python/test_arrays.py +++ b/tests/python/test_arrays.py @@ -894,33 +894,6 @@ def myFunc(e, f): assert "@evaluate:1:27" in str(e) -def test_sort_with_one_arg_keyfunc(): - items = ['Four', 'Three', 'One'] - - def myFunc(e): - return len(e) - try: - pm.eval("(arr, compareFun) => {arr.sort(compareFun)}")(items, myFunc) - assert (False) - except Exception as e: - assert str(type(e)) == "" - assert "takes 1 positional argument but 2 were given" in str(e) - assert "JS Stack Trace" in str(e) - assert "@evaluate:1:27" in str(e) - - -def test_sort_with_builtin_keyfunc(): - items = ['Four', 'Three', 'One'] - try: - pm.eval("(arr, compareFun) => {arr.sort(compareFun)}")(items, len) - assert (False) - except Exception as e: - assert str(type(e)) == "" - assert "len() takes exactly one argument (2 given)" in str(e) - assert "JS Stack Trace" in str(e) - assert "@evaluate:1:27" in str(e) - - def test_sort_with_js_func(): items = ['Four', 'Three', 'One'] result = [None] @@ -1125,7 +1098,8 @@ class Counter { assert (False) except Exception as e: assert str(type(e)) == "" - assert str(e).__contains__("TypeError: this is null") + assert "TypeError:" in str(e) + assert "this is null" in str(e) def test_forEach_too_few_args(): diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index dabc8c61..0eab66d5 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -4,6 +4,8 @@ import numpy import array import struct +from io import StringIO +import sys def test_py_buffer_to_js_typed_array(): @@ -48,6 +50,7 @@ def assert_js_to_py_memoryview(buf: memoryview): assert pm.eval("(arr)=>arr instanceof Int16Array")(numpy.array([1], dtype=numpy.int16)) assert pm.eval("(arr)=>arr instanceof Int32Array")(numpy.array([1], dtype=numpy.int32)) assert pm.eval("(arr)=>arr instanceof BigInt64Array")(numpy.array([1], dtype=numpy.int64)) + assert pm.eval("(arr)=>arr instanceof Float16Array")(numpy.array([1], dtype=numpy.float16)) assert pm.eval("(arr)=>arr instanceof Float32Array")(numpy.array([1], dtype=numpy.float32)) assert pm.eval("(arr)=>arr instanceof Float64Array")(numpy.array([1], dtype=numpy.float64)) assert pm.eval("new Uint8Array([1])").format == "B" @@ -58,6 +61,7 @@ def assert_js_to_py_memoryview(buf: memoryview): assert pm.eval("new Int16Array([1])").format == "h" assert pm.eval("new Int32Array([1])").format == "i" assert pm.eval("new BigInt64Array([1n])").format == "q" + assert pm.eval("new Float16Array([1])").format == "e" assert pm.eval("new Float32Array([1])").format == "f" assert pm.eval("new Float64Array([1])").format == "d" @@ -189,16 +193,6 @@ def assert_empty_arraybuffer(buf): # TODO (Tom Tang): error for detached ArrayBuffer, or should it be considered as empty? - # should error on immutable Python buffers - # Note: Python `bytes` type must be converted to a (mutable) `bytearray` - # because there's no such a concept of read-only ArrayBuffer in JS - with pytest.raises(BufferError, match="Object is not writable."): - pm.eval("(typedArray) => {}")(b'') - immutable_numpy_array = numpy.arange(10) - immutable_numpy_array.setflags(write=False) - with pytest.raises(ValueError, match="buffer source array is read-only"): - pm.eval("(typedArray) => {}")(immutable_numpy_array) - # buffer should be in C order (row major) # 1-D array is always considered C-contiguous because it doesn't matter if it's row or column major in 1-D fortran_order_arr = numpy.array([[1, 2], [3, 4]], order="F") @@ -209,3 +203,195 @@ def assert_empty_arraybuffer(buf): numpy_2d_array = numpy.array([[1, 2], [3, 4]], order="C") with pytest.raises(BufferError, match="multidimensional arrays are not allowed"): pm.eval("(typedArray) => {}")(numpy_2d_array) + + + +def test_bytes_proxy_write(): + with pytest.raises(TypeError, match="'bytes' object has only read-only attributes"): + pm.eval('(bytes) => bytes[0] = 5')(bytes("hello world", "ascii")) + + +def test_bytes_get_index_python(): + b = pm.eval('(bytes) => bytes')(bytes("hello world", "ascii")) + assert b[0] == 104 + + +def test_bytes_get_index_js(): + b = pm.eval('(bytes) => bytes[1]')(bytes("hello world", "ascii")) + assert b == 101.0 + + +def test_bytes_bytes_per_element(): + b = pm.eval('(bytes) => bytes.BYTES_PER_ELEMENT')(bytes("hello world", "ascii")) + assert b == 1.0 + + +def test_bytes_buffer(): + b = pm.eval('(bytes) => bytes.buffer')(bytes("hello world", "ascii")) + assert repr(b).__contains__("memory at") + assert b[2] == 108 + + +def test_bytes_length(): + b = pm.eval('(bytes) => bytes.length')(bytes("hello world", "ascii")) + assert b == 11.0 + +def test_bytes_bytelength(): + b = pm.eval('(bytes) => bytes.byteLength')(bytes("hello world", "ascii")) + assert b == 11.0 + + +def test_bytes_byteoffset(): + b = pm.eval('(bytes) => bytes.byteOffset')(bytes("hello world", "ascii")) + assert b == 0.0 + + +def test_bytes_instanceof(): + result = [None] + pm.eval("(result, bytes) => {result[0] = bytes instanceof Uint8Array}")(result, bytes("hello world", "ascii")) + assert result[0] + + +def test_constructor_creates_typedarray(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { result[0] = arr.constructor; result[0] = new result[0]; result[0] = result[0] instanceof Uint8Array}")(result, items) + assert result[0] == True + + +def test_bytes_valueOf(): + a = pm.eval('(bytes) => bytes.valueOf()')(bytes("hello world", "ascii")) + assert a == "104,101,108,108,111,32,119,111,114,108,100" + + +def test_bytes_toString(): + a = pm.eval('(bytes) => bytes.toString()')(bytes("hello world", "ascii")) + assert a == "104,101,108,108,111,32,119,111,114,108,100" + + +def test_bytes_console(): + temp_out = StringIO() + sys.stdout = temp_out + pm.eval('console.log')(bytes("hello world", "ascii")) + assert temp_out.getvalue().__contains__('104,101,108,108,111,32,119,111,114,108,100') + + +# iterator symbol property + +def test_iterator_type_function(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { result[0] = typeof arr[Symbol.iterator]}")(result, items) + assert result[0] == 'function' + + +def test_iterator_first_next(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { result[0] = arr[Symbol.iterator]().next()}")(result, items) + assert result[0].value == 104.0 + assert not result[0].done + + +def test_iterator_second_next(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { let iterator = arr[Symbol.iterator](); iterator.next(); result[0] = iterator.next()}")( + result, items) + assert result[0].value == 101.0 + assert not result[0].done + + +def test_iterator_last_next(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval(""" + (result, arr) => { + let iterator = arr[Symbol.iterator](); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + result[0] = iterator.next(); + } + """)(result, items) + assert result[0].value is None + assert result[0].done + + +def test_iterator_iterator(): + items = bytes("hell", "ascii") + result = [0] + pm.eval("(result, arr) => {let iter = arr[Symbol.iterator](); let head = iter.next().value; result[0] = [...iter] }")( + result, items) + assert result[0] == [101.0, 108.0, 108.0] + + +# entries + +def test_entries_next(): + items = bytes("abc", "ascii") + result = [0] + pm.eval("(result, arr) => {result[0] = arr.entries(); result[0] = result[0].next().value}")(result, items) + assert items == bytes("abc", "ascii") + assert result[0] == [0, 97.0] + + +def test_entries_next_next(): + items = bytes("abc", "ascii") + result = [0] + pm.eval("(result, arr) => {result[0] = arr.entries(); result[0].next(); result[0] = result[0].next().value}")( + result, items) + assert result[0] == [1, 98.0] + + +def test_entries_next_next_undefined(): + items = bytes("a", "ascii") + result = [0] + pm.eval("(result, arr) => {result[0] = arr.entries(); result[0].next(); result[0] = result[0].next().value}")( + result, items) + assert result[0] is None + + +# keys + +def test_keys_iterator(): + items = bytes("abc", "ascii") + result = [7, 8, 9] + pm.eval(""" + (result, arr) => { + index = 0; + iterator = arr.keys(); + for (const key of iterator) { + result[index] = key; + index++; + } + } + """)(result, items) + assert result == [0, 1, 2] + + +# values + +def test_values_iterator(): + items = bytes("abc", "ascii") + result = [7, 8, 9] + pm.eval(""" + (result, arr) => { + index = 0; + iterator = arr.values(); + for (const value of iterator) { + result[index] = value; + index++; + } + } + """)(result, items) + assert result == [97.0, 98.0, 99.0] + assert result is not items \ No newline at end of file diff --git a/tests/python/test_dict_methods.py b/tests/python/test_dict_methods.py index a303f73a..d0fccba9 100644 --- a/tests/python/test_dict_methods.py +++ b/tests/python/test_dict_methods.py @@ -555,3 +555,19 @@ def test_next_operator(): assert (True) fourth = next(myit, 'default') assert fourth == 'default' + + +def test_next_operator_non_iterator(): + make_js_generator = pm.eval(""" + function* sliceGenerator(pyIter) + { + yield python.eval('lambda x: next(x)')(pyIter); + } + sliceGenerator; + """) + + try: + next(make_js_generator(range(0,5))) + assert (False) + except pm.SpiderMonkeyError as e: + assert "'range' object is not an iterator" in str(e) \ No newline at end of file diff --git a/tests/python/test_dicts.py b/tests/python/test_dicts.py index 99959926..b3f481fa 100644 --- a/tests/python/test_dicts.py +++ b/tests/python/test_dicts.py @@ -367,14 +367,6 @@ def test_toLocaleString(): pm.eval("(result, obj) => {result[0] = obj.toLocaleString()}")(result, items) assert result[0] == '[object Object]' -# repr - - -def test_repr_max_recursion_depth(): - subprocess.check_call('npm install crypto-js', shell=True) - CryptoJS = pm.require('crypto-js') - assert str(CryptoJS).__contains__("{'lib': {'Base': {'extend':") - # __class__ def test___class__attribute(): diff --git a/tests/python/test_event_loop.py b/tests/python/test_event_loop.py index 3f3adf6b..2e4215ea 100644 --- a/tests/python/test_event_loop.py +++ b/tests/python/test_event_loop.py @@ -273,7 +273,8 @@ async def c(): assert "nested" == await pm.eval("(promise) => promise")(c()) assert "nested" == await pm.eval("(promise) => promise")(await c()) assert "nested" == await pm.eval("(promise) => promise")(await (await c())) - with pytest.raises(TypeError, match="object str can't be used in 'await' expression"): + with pytest.raises(TypeError, match="(object str can't be used in 'await' expression)|('str' object can't be awaited)"): + # Python 3.14 changed the error message format await pm.eval("(promise) => promise")(await (await (await c()))) # Python awaitable throwing exceptions @@ -312,7 +313,7 @@ async def coro_to_throw1(): # # await pm.eval("Promise.resolve().then(()=>{ throw {a:1,toString(){return'anything'}} })") # not going through the conversion - with pytest.raises(pm.SpiderMonkeyError, match="on line 1, column 31:\nTypeError: undefined has no properties"): + with pytest.raises(pm.SpiderMonkeyError, match="on line 1, column 31:\nTypeError: can\'t access property \"prop\" of undefined"): await pm.eval("Promise.resolve().then(()=>{ (undefined).prop })") # TODO (Tom Tang): Modify this testcase once we support ES2020-style dynamic import @@ -350,10 +351,68 @@ def py_sleep(seconds): # asyncio.sleep has issues on Python 3.8 match="PythonMonkey cannot find a running Python event-loop to make asynchronous calls."): pm.eval("new Promise(() => { })") -# off-thread promises + +def test_errors_thrown_in_promise(): + async def async_fn(): + loop = asyncio.get_running_loop() + future = loop.create_future() + + def exceptionHandler(loop, context): + future.set_exception(context["exception"]) + loop.set_exception_handler(exceptionHandler) + + pm.eval(""" + new Promise(function (resolve, reject) + { + reject(new Error('in Promise')); + }); + + new Promise(function (resolve, reject) + { + console.log('ok'); + }); + """) + with pytest.raises(pm.SpiderMonkeyError, match="Error: in Promise"): + await asyncio.wait_for(future, timeout=0.1) + + loop.set_exception_handler(None) + return True + assert asyncio.run(async_fn()) + + +def test_errors_thrown_in_async_function(): + async def async_fn(): + loop = asyncio.get_running_loop() + future = loop.create_future() + + def exceptionHandler(loop, context): + future.set_exception(context["exception"]) + loop.set_exception_handler(exceptionHandler) + + pm.eval(""" + async function aba() { + throw new Error('in async function'); + } + + async function abb() { + console.log('ok'); + } + + aba(); + abb(); + """) + with pytest.raises(pm.SpiderMonkeyError, match="Error: in async function"): + await asyncio.wait_for(future, timeout=0.1) + + loop.set_exception_handler(None) + return True + assert asyncio.run(async_fn()) def test_webassembly(): + """ + Tests for off-thread promises + """ async def async_fn(): # off-thread promises can run assert 'instantiated' == await pm.eval(""" diff --git a/tests/python/test_functions.py b/tests/python/test_functions.py new file mode 100644 index 00000000..5b61acb8 --- /dev/null +++ b/tests/python/test_functions.py @@ -0,0 +1,121 @@ +import pythonmonkey as pm + + +def test_func_no_args(): + def f(): + return 42 + assert 42 == pm.eval("(f) => f()")(f) + + +def test_func_too_many_args(): + def f(a, b): + return [a, b] + assert [1, 2] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_func_equal_args(): + def f(a, b): + return [a, b] + assert [1, 2] == pm.eval("(f) => f(1, 2)")(f) + + +def test_func_too_few_args(): + def f(a, b): + return [a, b] + assert [1, None] == pm.eval("(f) => f(1)")(f) + + +def test_default_func_no_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [None, None, 42, 43] == pm.eval("(f) => f()")(f) + + +def test_default_func_too_many_default_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 3, 4] == pm.eval("(f) => f(1, 2, 3, 4, 5)")(f) + + +def test_default_func_equal_default_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 3, 4] == pm.eval("(f) => f(1, 2, 3, 4)")(f) + + +def test_default_func_too_few_default_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 3, 43] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_default_func_equal_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 42, 43] == pm.eval("(f) => f(1, 2)")(f) + + +def test_default_func_too_few_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, None, 42, 43] == pm.eval("(f) => f(1)")(f) + + +def test_vararg_func_no_args(): + def f(a, b, *args): + return [a, b, *args] + assert [None, None] == pm.eval("(f) => f()")(f) + + +def test_vararg_func_too_many_args(): + def f(a, b, *args): + return [a, b, *args] + assert [1, 2, 3] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_vararg_func_equal_args(): + def f(a, b, *args): + return [a, b, *args] + assert [1, 2] == pm.eval("(f) => f(1, 2)")(f) + + +def test_vararg_func_too_few_args(): + def f(a, b, *args): + return [a, b, *args] + assert [1, None] == pm.eval("(f) => f(1)")(f) + + +def test_default_vararg_func_no_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [None, None, 42, 43] == pm.eval("(f) => f()")(f) + + +def test_default_vararg_func_too_many_default_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, 2, 3, 4, 5] == pm.eval("(f) => f(1, 2, 3, 4, 5)")(f) + + +def test_default_vararg_func_equal_default_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, 2, 3, 4] == pm.eval("(f) => f(1, 2, 3, 4)")(f) + + +def test_default_vararg_func_too_few_default_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, 2, 3, 43] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_default_vararg_func_equal_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, 2, 42, 43] == pm.eval("(f) => f(1, 2)")(f) + + +def test_default_vararg_func_too_few_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, None, 42, 43] == pm.eval("(f) => f(1)")(f) diff --git a/tests/python/test_functions_this.py b/tests/python/test_functions_this.py index dc20f416..52838781 100644 --- a/tests/python/test_functions_this.py +++ b/tests/python/test_functions_this.py @@ -126,14 +126,6 @@ class Class: # require -def test_require_correct_this(): - subprocess.check_call('npm install crypto-js', shell=True) - CryptoJS = pm.require('crypto-js') - cipher = CryptoJS.SHA256("Hello, World!").toString() - assert cipher == "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f" - subprocess.check_call('npm uninstall crypto-js', shell=True) - - def test_require_correct_this_old_style_class(): example = pm.eval(""" () => { @@ -202,3 +194,17 @@ def pyFunc(): pm.collect() # this should collect the JS proxy to pyFunc, which should decref pyFunc # pyFunc should be collected by now assert ref[0]() is None + + +def test_method_no_self(): + class What: + def some_method(): + return 3 + + obj = What() + + try: + pm.eval('x => x.some_method()')(obj) + assert (False) + except pm.SpiderMonkeyError as e: + assert 'takes 0 positional arguments but 1 was given' in str(e) diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index a56ba529..b40f25b1 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -1,4 +1,5 @@ import pythonmonkey as pm +import sys def test_eval_pyobjects(): @@ -148,3 +149,40 @@ def __init__(self): o = MyClass() assert '[object Object]' == pm.eval("(obj) => { return obj.toLocaleString(); }")(o) + + +def test_toPrimitive_iterable(): + iterable = iter([1,2]) + toPrimitive = pm.eval("(obj) => { return obj[Symbol.toPrimitive]; }")(iterable) + assert repr(toPrimitive).__contains__(" { return obj.constructor; }")(iterable) + assert repr(constructor).__contains__(" { return obj[Symbol.toPrimitive]; }")(sys.stdin) + assert repr(toPrimitive).__contains__(" { return obj.constructor; }")(sys.stdin) + assert repr(constructor).__contains__(" x.toString === Object.prototype.toString") + assert is_to_string_correct({}) + + +def test_toString_is_prototype_toLocaleString(): + is_to_locale_string_correct = pm.eval("x => x.toLocaleString === Object.prototype.toLocaleString") + assert is_to_locale_string_correct({}) + + +def test_valueof_is_prototype_valueof(): + is_valueof_correct = pm.eval("x => x.valueOf === Object.prototype.valueOf") + assert is_valueof_correct({}) \ No newline at end of file diff --git a/tests/python/test_pythonmonkey_eval.py b/tests/python/test_pythonmonkey_eval.py index e21cdbe2..cb2366c4 100644 --- a/tests/python/test_pythonmonkey_eval.py +++ b/tests/python/test_pythonmonkey_eval.py @@ -5,6 +5,7 @@ import math from io import StringIO import sys +import asyncio def test_passes(): @@ -138,6 +139,7 @@ def test_eval_exceptions(): def test_eval_exceptions_nested_py_js_py(): def c(): raise Exception('this is an exception') + err_line_number = sys._getframe().f_lineno - 1 b = pm.eval('''(x) => { try { x() @@ -145,10 +147,11 @@ def c(): return "Caught in JS " + e; } }''') - assert str(b(c)).__contains__("Caught in JS Error: Python Exception: this is an exception") - assert str(b(c)).__contains__("test_pythonmonkey_eval.py") - assert str(b(c)).__contains__("line 140") - assert str(b(c)).__contains__("in c") + err = b(c) + assert "Caught in JS Error: Python Exception: this is an exception" in str(err) + assert "test_pythonmonkey_eval.py" in str(err) + assert "line {}".format(err_line_number) in str(err) + assert "in c" in str(err) def test_eval_exceptions_nested_js_py_js(): @@ -164,6 +167,55 @@ def b(x): assert ("Caught in Py Error in" in ret) and ("TypeError: this is an exception" in ret) +def test_eval_exceptions_preserve_js_py_js(): + # Tests for https://github.com/Distributive-Network/PythonMonkey/blob/d9a8ebe/src/ExceptionType.cc#L39-L41 + # and https://github.com/Distributive-Network/PythonMonkey/blob/d9a8ebe/src/ExceptionType.cc#L86-L91 + obj = pm.eval("({ err: new TypeError('JS Error') })") + py_err = obj.err + assert type(py_err) is pm.SpiderMonkeyError + assert pm.eval("(e) => e instanceof TypeError")(py_err) + assert pm.eval("(e) => e.message == 'JS Error'")(py_err) + assert pm.eval("(e, obj) => Object.is(e, obj.err)")(py_err, obj) + + +def test_eval_exceptions_preserve_promise_rejection(): + # Tests for https://github.com/Distributive-Network/PythonMonkey/blob/d9a8ebe/src/PromiseType.cc#L46-L48 + async def async_fn(): + try: + await pm.eval("Promise.reject(Number(123))", {'mutedErrors': True}) + # The mutedErrors option is required to avoid sending this to uncaughtExceptionHandler prematurely + except Exception as py_err: + assert type(py_err) is pm.SpiderMonkeyError + assert repr(py_err) == "SpiderMonkeyError(123.0)" + assert pm.eval("(e) => e instanceof Number")(py_err) + assert pm.eval("(e) => e == 123")(py_err) + try: + await pm.eval("Promise.reject(new TypeError('Promise rejection'))", {'mutedErrors': True}) + except Exception as py_err: + assert type(py_err) is pm.SpiderMonkeyError + assert pm.eval("(e) => e instanceof TypeError")(py_err) + assert pm.eval("(e) => e.message == 'Promise rejection'")(py_err) + return True + assert asyncio.run(async_fn()) + + +def test_eval_exceptions_preserve_original_js_error_object(): + # Test for https://github.com/Distributive-Network/PythonMonkey/blob/dc753a0/src/setSpiderMonkeyException.cc#L108-L111 + obj = pm.eval("({ err: new TypeError('JS Error') })") + c = pm.eval("(obj) => { throw obj.err; }") + + def b(fn): + try: + fn(obj) + except Exception as e: + return e + + py_err = b(c) + assert pm.eval("(err) => err instanceof TypeError")(py_err) + assert pm.eval("(e) => e.message == 'JS Error'")(py_err) + assert pm.eval("(e, obj) => Object.is(e, obj.err)")(py_err, obj) + + def test_eval_undefined(): x = pm.eval("undefined") assert x is None @@ -388,3 +440,14 @@ def test_console_array(): items = [1, 2, 3] pm.eval('console.log')(items) assert temp_out.getvalue() == "[ \x1b[33m1\x1b[39m, \x1b[33m2\x1b[39m, \x1b[33m3\x1b[39m ]\n" + + +def test_iterable_attribute_console_printing(): + temp_out = StringIO() + sys.stdout = temp_out + obj = {} + obj['stdin'] = sys.stdin # sys.stdin is iterable + assert hasattr(sys.stdin, '__iter__') == True + obj['stdin'].isTTY = sys.stdin.isatty() + pm.eval('''(function iife(obj){console.log(obj['stdin'].isTTY);})''')(obj) + assert temp_out.getvalue() == "\x1b[33mfalse\x1b[39m\n" \ No newline at end of file diff --git a/tests/python/test_strings.py b/tests/python/test_strings.py index 694de79f..01a22b97 100644 --- a/tests/python/test_strings.py +++ b/tests/python/test_strings.py @@ -1,6 +1,13 @@ import pythonmonkey as pm import gc import random +import copy + + +def test_identity(): + py_string = "abc" + js_string = pm.eval("(str) => str")(py_string) + assert py_string is js_string def test_eval_ascii_string_matches_evaluated_string(): @@ -265,3 +272,21 @@ def test_eval_boxed_ucs4_string_fuzztest(): string1 = string2 assert INITIAL_STRING == string1 # strings should still match after a bunch of iterations through JS + + +def test_string_proxy_copy(): + world = pm.eval('(function() {return "World"})') + say = pm.eval('(function(who) { return `Hello ${who}`})') + who = world() + hello_world = say(copy.copy(who)) + assert hello_world == "Hello World" + assert hello_world is not who + +def test_string_proxy_deepcopy(): + world = pm.eval('(function() {return "World"})') + say = pm.eval('(function(who) { return `Hello ${who}`})') + who = world() + hello_world = say(copy.deepcopy(who)) + assert hello_world == "Hello World" + assert hello_world is not who + \ No newline at end of file diff --git a/tests/python/test_xhr.py b/tests/python/test_xhr.py new file mode 100644 index 00000000..990193eb --- /dev/null +++ b/tests/python/test_xhr.py @@ -0,0 +1,97 @@ +from http.server import HTTPServer, BaseHTTPRequestHandler +import pythonmonkey as pm +import threading +import asyncio +import json + +def test_xhr(): + class TestHTTPRequestHandler(BaseHTTPRequestHandler): + def log_request(self, *args) -> None: + return + + def do_GET(self): + self.send_response(200) + self.end_headers() + self.wfile.write(b"get response") + + def do_POST(self): + self.send_response(200) + self.send_header('Content-Type', 'application/json') + self.end_headers() + length = int(self.headers.get('Content-Length')) + json_string = self.rfile.read(length).decode("utf-8") + parameter_dict = json.loads(json_string) + parameter_dict["User-Agent"] = self.headers['User-Agent'] + data = json.dumps(parameter_dict).encode("utf-8") + self.wfile.write(data) + + httpd = HTTPServer(('localhost', 4001), TestHTTPRequestHandler) + thread = threading.Thread(target = httpd.serve_forever) + thread.daemon = True + thread.start() + + async def async_fn(): + assert "get response" == await pm.eval(""" + new Promise(function (resolve, reject) { + let xhr = new XMLHttpRequest(); + xhr.open('GET', 'http://localhost:4001'); + + xhr.onload = function () + { + if (this.status >= 200 && this.status < 300) + { + resolve(this.response); + } + else + { + reject(new Error(JSON.stringify({ + status: this.status, + statusText: this.statusText + }))); + } + }; + + xhr.onerror = function (ev) + { + reject(ev.error); + }; + xhr.send(); + }); + """) + + post_result = await pm.eval(""" + new Promise(function (resolve, reject) + { + let xhr = new XMLHttpRequest(); + xhr.open('POST', 'http://localhost:4001'); + + xhr.onload = function () + { + if (this.status >= 200 && this.status < 300) + { + resolve(this.response); + } + else + { + reject(new Error(JSON.stringify({ + status: this.status, + statusText: this.statusText + }))); + } + }; + + xhr.onerror = function (ev) + { + console.log(ev) + reject(ev.error); + }; + + xhr.send(JSON.stringify({fromPM: "snakesandmonkeys"})); + }) + """) + + result_json = json.loads(post_result) + assert result_json["fromPM"] == "snakesandmonkeys" + assert result_json["User-Agent"].startswith("Python/") + httpd.shutdown() + asyncio.run(async_fn()) \ No newline at end of file