diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a6bb5e70bc4..a10fb79b56f 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -280,6 +280,58 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} + test-mobile: + permissions: + contents: read # to fetch code (actions/checkout) + + name: Test (${{ matrix.config.platform }}, ${{ matrix.pyver }}, ${{ matrix.config.os }}) + runs-on: ${{ matrix.config.os }} + needs: gen_llhttp + strategy: + matrix: + pyver: ["cp313", "cp314"] + config: + - os: ubuntu-latest + platform: android + archs: x86_64 + - os: macos-14 + platform: ios + archs: arm64_iphonesimulator + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + submodules: true + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: 3.x + - name: Update pip, wheel, setuptools, build, twine + run: | + python -m pip install -U pip wheel setuptools build twine + - name: Install cython + run: >- + python -m + pip install -r requirements/cython.in -c requirements/cython.txt + - name: Restore llhttp generated files + uses: actions/download-artifact@v8 + with: + name: llhttp + path: vendor/llhttp/build/ + - name: Cythonize + run: | + make cythonize + - name: Build wheels and test + uses: pypa/cibuildwheel@v3.4.0 + env: + CIBW_BUILD: ${{ matrix.pyver }}-* + CIBW_PLATFORM: ${{ matrix.config.platform }} + CIBW_ARCHS: ${{ matrix.config.archs }} + CIBW_TEST_REQUIRES: -r requirements/test.txt + CIBW_TEST_SOURCES: setup.cfg tests + CIBW_TEST_COMMAND: >- + python -m pytest -o 'addopts='-v -ra --showlocals -m 'not dev_mode and not autobahn' + autobahn: permissions: contents: read # to fetch code (actions/checkout) @@ -422,6 +474,7 @@ jobs: needs: - lint - test + - test-mobile - autobahn runs-on: ubuntu-latest @@ -492,7 +545,7 @@ jobs: permissions: contents: read # to fetch code (actions/checkout) - name: Build wheels on ${{ matrix.os }} ${{ matrix.qemu }} ${{ matrix.musl }} + name: Build wheels on ${{ matrix.os }} ${{ matrix.qemu }} ${{ matrix.musl }} ${{ matrix.platform }} runs-on: ${{ matrix.os }} needs: pre-deploy strategy: @@ -500,6 +553,7 @@ jobs: os: ["ubuntu-latest", "windows-latest", "windows-11-arm", "macos-latest", "ubuntu-24.04-arm"] qemu: [''] musl: [""] + platform: [""] include: # Split ubuntu/musl jobs for the sake of speed-up - os: ubuntu-latest @@ -530,6 +584,10 @@ jobs: musl: musllinux - os: ubuntu-24.04-arm musl: musllinux + - os: ubuntu-latest + platform: android + - os: macos-14 + platform: ios steps: - name: Checkout uses: actions/checkout@v6 @@ -575,14 +633,19 @@ jobs: - name: Build wheels uses: pypa/cibuildwheel@v3.4.0 env: + CIBW_PLATFORM: ${{ matrix.platform || 'auto' }} CIBW_SKIP: pp* ${{ matrix.musl == 'musllinux' && '*manylinux*' || '*musllinux*' }} CIBW_ARCHS_MACOS: x86_64 arm64 universal2 + CIBW_ARCHS_IOS: arm64_iphoneos arm64_iphonesimulator x86_64_iphonesimulator + CIBW_ARCHS_ANDROID: arm64_v8a x86_64 - name: Upload wheels uses: actions/upload-artifact@v6 with: name: >- dist-${{ matrix.os }}-${{ matrix.musl }}-${{ - matrix.qemu + matrix.platform + && matrix.platform + || matrix.qemu && matrix.qemu || 'native' }} diff --git a/CHANGES/11750.feature.rst b/CHANGES/11750.feature.rst new file mode 100644 index 00000000000..2af5e11cf45 --- /dev/null +++ b/CHANGES/11750.feature.rst @@ -0,0 +1 @@ +Added wheels for Android and iOS platforms -- by :user:`timrid`. diff --git a/pyproject.toml b/pyproject.toml index 7ad4f54b0c3..d1d9e782f42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,10 +48,10 @@ dynamic = [ [project.optional-dependencies] speedups = [ - "aiodns >= 3.3.0", - "Brotli >= 1.2; platform_python_implementation == 'CPython'", + "aiodns >= 3.3.0; sys_platform != 'android' and sys_platform != 'ios'", + "Brotli >= 1.2; platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios'", "brotlicffi >= 1.2; platform_python_implementation != 'CPython'", - "backports.zstd; platform_python_implementation == 'CPython' and python_version < '3.14'", + "backports.zstd; platform_python_implementation == 'CPython' and python_version < '3.14' and sys_platform != 'android' and sys_platform != 'ios'", ] [[project.maintainers]] diff --git a/requirements/base-ft.txt b/requirements/base-ft.txt index f28172ab3c3..1bd397a85d3 100644 --- a/requirements/base-ft.txt +++ b/requirements/base-ft.txt @@ -4,7 +4,7 @@ # # pip-compile --allow-unsafe --output-file=requirements/base-ft.txt --strip-extras requirements/base-ft.in # -aiodns==4.0.0 +aiodns==4.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in aiohappyeyeballs==2.6.1 # via -r requirements/runtime-deps.in @@ -12,9 +12,9 @@ aiosignal==1.4.0 # via -r requirements/runtime-deps.in async-timeout==5.0.1 ; python_version < "3.11" # via -r requirements/runtime-deps.in -backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" +backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in -brotli==1.2.0 ; platform_python_implementation == "CPython" +brotli==1.2.0 ; platform_python_implementation == "CPython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in cffi==2.0.0 # via pycares diff --git a/requirements/base.in b/requirements/base.in index 816a4e84026..f4cb3743528 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,5 +1,5 @@ -r runtime-deps.in gunicorn -uvloop; platform_system != "Windows" and implementation_name == "cpython" # MagicStack/uvloop#14 +uvloop; platform_system != "Windows" and implementation_name == "cpython" and sys_platform != 'android' and sys_platform != 'ios' # MagicStack/uvloop#14 winloop; platform_system == "Windows" and implementation_name == "cpython" diff --git a/requirements/base.txt b/requirements/base.txt index d637bda2d6d..f491760e616 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -4,7 +4,7 @@ # # pip-compile --allow-unsafe --output-file=requirements/base.txt --strip-extras requirements/base.in # -aiodns==4.0.0 +aiodns==4.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in aiohappyeyeballs==2.6.1 # via -r requirements/runtime-deps.in @@ -12,9 +12,9 @@ aiosignal==1.4.0 # via -r requirements/runtime-deps.in async-timeout==5.0.1 ; python_version < "3.11" # via -r requirements/runtime-deps.in -backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" +backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in -brotli==1.2.0 ; platform_python_implementation == "CPython" +brotli==1.2.0 ; platform_python_implementation == "CPython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in cffi==2.0.0 # via pycares @@ -45,7 +45,7 @@ typing-extensions==4.15.0 ; python_version < "3.13" # -r requirements/runtime-deps.in # aiosignal # multidict -uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpython" +uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/base.in yarl==1.22.0 # via -r requirements/runtime-deps.in diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 940be5cb67b..08838feef82 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -4,7 +4,7 @@ # # pip-compile --allow-unsafe --output-file=requirements/constraints.txt --strip-extras requirements/constraints.in # -aiodns==4.0.0 +aiodns==4.0.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/runtime-deps.in @@ -28,18 +28,19 @@ backports-zstd==1.3.0 ; implementation_name == "cpython" # via # -r requirements/lint.in # -r requirements/runtime-deps.in -blockbuster==1.5.26 +blockbuster==1.5.26 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in -brotli==1.2.0 ; platform_python_implementation == "CPython" +brotli==1.2.0 ; platform_python_implementation == "CPython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in build==1.4.0 # via pip-tools certifi==2026.2.25 # via requests -cffi==2.0.0 +cffi==2.0.0 ; sys_platform != "android" and sys_platform != "ios" # via + # -r requirements/test-common.in # cryptography # pycares # pytest-codspeed @@ -54,11 +55,11 @@ click==8.3.1 # towncrier # wait-for-it coverage==7.13.4 + # via pytest-cov +cryptography==46.0.5 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/test-common.in - # pytest-cov -cryptography==46.0.5 - # via trustme + # trustme cython==3.2.4 # via -r requirements/cython.in distlib==0.4.0 @@ -73,8 +74,10 @@ filelock==3.25.2 # via # python-discovery # virtualenv -forbiddenfruit==0.1.4 - # via blockbuster +forbiddenfruit==0.1.4 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # blockbuster freezegun==1.5.5 # via # -r requirements/lint.in @@ -96,7 +99,7 @@ imagesize==2.0.0 # via sphinx iniconfig==2.3.0 # via pytest -isal==1.7.2 ; python_version < "3.14" +isal==1.7.2 ; python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -104,8 +107,10 @@ jinja2==3.1.6 # via # sphinx # towncrier -librt==0.8.0 - # via mypy +librt==0.8.0 ; platform_python_implementation != "PyPy" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy markdown-it-py==4.0.0 # via rich markupsafe==3.0.3 @@ -121,8 +126,10 @@ mypy==1.19.1 ; implementation_name == "cpython" # via # -r requirements/lint.in # -r requirements/test-common.in -mypy-extensions==1.1.0 - # via mypy +mypy-extensions==1.1.0 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy nodeenv==1.10.0 # via pre-commit packaging==26.0 @@ -156,14 +163,20 @@ proxy-py==2.4.10 # via # -r requirements/lint.in # -r requirements/test-common.in -pycares==5.0.1 - # via aiodns +pycares==5.0.1 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # aiodns pycparser==3.0 # via cffi -pydantic==2.12.5 - # via python-on-whales -pydantic-core==2.41.5 - # via pydantic +pydantic==2.12.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # python-on-whales +pydantic-core==2.41.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # pydantic pyenchant==3.3.0 # via sphinxcontrib-spelling pygments==2.19.2 @@ -183,7 +196,7 @@ pytest==9.0.2 # pytest-cov # pytest-mock # pytest-xdist -pytest-codspeed==4.3.0 +pytest-codspeed==4.3.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -193,13 +206,13 @@ pytest-mock==3.15.1 # via # -r requirements/lint.in # -r requirements/test-common.in -pytest-xdist==3.8.0 +pytest-xdist==3.8.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in python-dateutil==2.9.0.post0 # via freezegun python-discovery==1.1.3 # via virtualenv -python-on-whales==0.81.0 +python-on-whales==0.81.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -254,7 +267,7 @@ towncrier==25.8.0 # via # -r requirements/doc.in # sphinxcontrib-towncrier -trustme==1.2.1 ; platform_machine != "i686" +trustme==1.2.1 ; platform_machine != "i686" and sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -289,7 +302,7 @@ wheel==0.46.3 # via pip-tools yarl==1.22.0 # via -r requirements/runtime-deps.in -zlib-ng==1.0.0 +zlib-ng==1.0.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in diff --git a/requirements/dev.txt b/requirements/dev.txt index aee60f854e5..055e44c0cd7 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -4,7 +4,7 @@ # # pip-compile --allow-unsafe --output-file=requirements/dev.txt --strip-extras requirements/dev.in # -aiodns==4.0.0 +aiodns==4.0.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/runtime-deps.in @@ -24,22 +24,23 @@ async-timeout==5.0.1 ; python_version < "3.11" # valkey babel==2.18.0 # via sphinx -backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" +backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/runtime-deps.in -blockbuster==1.5.26 +blockbuster==1.5.26 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in -brotli==1.2.0 ; platform_python_implementation == "CPython" +brotli==1.2.0 ; platform_python_implementation == "CPython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in build==1.4.0 # via pip-tools certifi==2026.2.25 # via requests -cffi==2.0.0 +cffi==2.0.0 ; sys_platform != "android" and sys_platform != "ios" # via + # -r requirements/test-common.in # cryptography # pycares # pytest-codspeed @@ -54,11 +55,11 @@ click==8.3.1 # towncrier # wait-for-it coverage==7.13.4 + # via pytest-cov +cryptography==46.0.5 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/test-common.in - # pytest-cov -cryptography==46.0.5 - # via trustme + # trustme distlib==0.4.0 # via virtualenv docutils==0.21.2 @@ -71,8 +72,10 @@ filelock==3.25.2 # via # python-discovery # virtualenv -forbiddenfruit==0.1.4 - # via blockbuster +forbiddenfruit==0.1.4 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # blockbuster freezegun==1.5.5 # via # -r requirements/lint.in @@ -94,7 +97,7 @@ imagesize==2.0.0 # via sphinx iniconfig==2.3.0 # via pytest -isal==1.7.2 ; python_version < "3.14" +isal==1.7.2 ; python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -102,8 +105,10 @@ jinja2==3.1.6 # via # sphinx # towncrier -librt==0.8.0 - # via mypy +librt==0.8.0 ; platform_python_implementation != "PyPy" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy markdown-it-py==4.0.0 # via rich markupsafe==3.0.3 @@ -114,12 +119,14 @@ multidict==6.7.1 # via # -r requirements/runtime-deps.in # yarl -mypy==1.19.1 ; implementation_name == "cpython" +mypy==1.19.1 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in -mypy-extensions==1.1.0 - # via mypy +mypy-extensions==1.1.0 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy nodeenv==1.10.0 # via pre-commit packaging==26.0 @@ -153,14 +160,20 @@ proxy-py==2.4.10 # via # -r requirements/lint.in # -r requirements/test-common.in -pycares==5.0.1 - # via aiodns +pycares==5.0.1 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # aiodns pycparser==3.0 # via cffi -pydantic==2.12.5 - # via python-on-whales -pydantic-core==2.41.5 - # via pydantic +pydantic==2.12.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # python-on-whales +pydantic-core==2.41.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # pydantic pygments==2.19.2 # via # pytest @@ -178,7 +191,7 @@ pytest==9.0.2 # pytest-cov # pytest-mock # pytest-xdist -pytest-codspeed==4.3.0 +pytest-codspeed==4.3.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -188,13 +201,13 @@ pytest-mock==3.15.1 # via # -r requirements/lint.in # -r requirements/test-common.in -pytest-xdist==3.8.0 +pytest-xdist==3.8.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in python-dateutil==2.9.0.post0 # via freezegun python-discovery==1.1.3 # via virtualenv -python-on-whales==0.81.0 +python-on-whales==0.81.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -244,7 +257,7 @@ towncrier==25.8.0 # via # -r requirements/doc.in # sphinxcontrib-towncrier -trustme==1.2.1 ; platform_machine != "i686" +trustme==1.2.1 ; platform_machine != "i686" and sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in @@ -265,7 +278,7 @@ typing-inspection==0.4.2 # via pydantic urllib3==2.6.3 # via requests -uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpython" +uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" # via # -r requirements/base.in # -r requirements/lint.in @@ -279,7 +292,7 @@ wheel==0.46.3 # via pip-tools yarl==1.22.0 # via -r requirements/runtime-deps.in -zlib-ng==1.0.0 +zlib-ng==1.0.0 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/lint.in # -r requirements/test-common.in diff --git a/requirements/runtime-deps.in b/requirements/runtime-deps.in index 3e3c4d05313..d70fc5a9dbc 100644 --- a/requirements/runtime-deps.in +++ b/requirements/runtime-deps.in @@ -1,11 +1,11 @@ # Extracted from `pyproject.toml` via `make sync-direct-runtime-deps` -aiodns >= 3.3.0 +aiodns >= 3.3.0; sys_platform != 'android' and sys_platform != 'ios' aiohappyeyeballs >= 2.5.0 aiosignal >= 1.4.0 async-timeout >= 4.0, < 6.0 ; python_version < '3.11' -backports.zstd; platform_python_implementation == 'CPython' and python_version < '3.14' -Brotli >= 1.2; platform_python_implementation == 'CPython' +backports.zstd; platform_python_implementation == 'CPython' and python_version < '3.14' and sys_platform != 'android' and sys_platform != 'ios' +Brotli >= 1.2; platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios' brotlicffi >= 1.2; platform_python_implementation != 'CPython' frozenlist >= 1.1.1 multidict >=4.5, < 7.0 diff --git a/requirements/runtime-deps.txt b/requirements/runtime-deps.txt index 7b6983e8467..80ef7bf9ab3 100644 --- a/requirements/runtime-deps.txt +++ b/requirements/runtime-deps.txt @@ -4,7 +4,7 @@ # # pip-compile --allow-unsafe --output-file=requirements/runtime-deps.txt --strip-extras requirements/runtime-deps.in # -aiodns==4.0.0 +aiodns==4.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in aiohappyeyeballs==2.6.1 # via -r requirements/runtime-deps.in @@ -12,9 +12,9 @@ aiosignal==1.4.0 # via -r requirements/runtime-deps.in async-timeout==5.0.1 ; python_version < "3.11" # via -r requirements/runtime-deps.in -backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" +backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in -brotli==1.2.0 ; platform_python_implementation == "CPython" +brotli==1.2.0 ; platform_python_implementation == "CPython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in cffi==2.0.0 # via pycares diff --git a/requirements/test-common.in b/requirements/test-common.in index c010f61fa8a..e11815259e7 100644 --- a/requirements/test-common.in +++ b/requirements/test-common.in @@ -1,17 +1,24 @@ -blockbuster -coverage +blockbuster; sys_platform != 'android' and sys_platform != 'ios' +cffi; sys_platform != 'android' and sys_platform != 'ios' # used by cryptography, pycares and pytest-codspeedcoverage +cryptography; sys_platform != 'android' and sys_platform != 'ios' # used by trustme +forbiddenfruit; implementation_name == "cpython" and sys_platform != 'android' and sys_platform != 'ios' # used by blockbuster freezegun -isal; python_version < "3.14" # no wheel for 3.14 -mypy; implementation_name == "cpython" +isal; python_version < "3.14" and sys_platform != 'android' and sys_platform != 'ios' # no wheel for 3.14 +librt; platform_python_implementation != 'PyPy' and sys_platform != 'android' and sys_platform != 'ios' # used by mypy +mypy; implementation_name == "cpython" and sys_platform != 'android' and sys_platform != 'ios' +mypy-extensions; sys_platform != 'android' and sys_platform != 'ios' # used by mypy pkgconfig proxy.py >= 2.4.4rc5 +pycares; sys_platform != 'android' and sys_platform != 'ios' # used by aiodns +pydantic; sys_platform != 'android' and sys_platform != 'ios' # used by python-on-whales +pydantic-core; sys_platform != 'android' and sys_platform != 'ios' # used by pydantic pytest pytest-cov pytest-mock -pytest-xdist -pytest_codspeed -python-on-whales +pytest-xdist; sys_platform != 'android' and sys_platform != 'ios' +pytest_codspeed; sys_platform != 'android' and sys_platform != 'ios' +python-on-whales; sys_platform != 'android' and sys_platform != 'ios' setuptools-git -trustme; platform_machine != "i686" # no 32-bit wheels +trustme; platform_machine != "i686" and sys_platform != 'android' and sys_platform != 'ios' # no 32-bit and android and ios wheels wait-for-it -zlib_ng +zlib_ng; sys_platform != 'android' and sys_platform != 'ios' diff --git a/requirements/test-common.txt b/requirements/test-common.txt index 12adefe0296..182d4001fd4 100644 --- a/requirements/test-common.txt +++ b/requirements/test-common.txt @@ -6,44 +6,52 @@ # annotated-types==0.7.0 # via pydantic -blockbuster==1.5.26 +blockbuster==1.5.26 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -cffi==2.0.0 +cffi==2.0.0 ; sys_platform != "android" and sys_platform != "ios" # via + # -r requirements/test-common.in # cryptography + # pycares # pytest-codspeed click==8.3.1 # via wait-for-it coverage==7.13.4 + # via pytest-cov +cryptography==46.0.5 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/test-common.in - # pytest-cov -cryptography==46.0.5 - # via trustme + # trustme exceptiongroup==1.3.1 # via pytest execnet==2.1.2 # via pytest-xdist -forbiddenfruit==0.1.4 - # via blockbuster +forbiddenfruit==0.1.4 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # blockbuster freezegun==1.5.5 # via -r requirements/test-common.in idna==3.11 # via trustme iniconfig==2.3.0 # via pytest -isal==1.8.0 ; python_version < "3.14" +isal==1.8.0 ; python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -librt==0.8.0 - # via mypy +librt==0.8.0 ; platform_python_implementation != "PyPy" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy markdown-it-py==4.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -mypy==1.19.1 ; implementation_name == "cpython" +mypy==1.19.1 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -mypy-extensions==1.1.0 - # via mypy +mypy-extensions==1.1.0 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy packaging==26.0 # via pytest pathspec==1.0.4 @@ -56,12 +64,18 @@ pluggy==1.6.0 # pytest-cov proxy-py==2.4.10 # via -r requirements/test-common.in +pycares==5.0.1 ; sys_platform != "android" and sys_platform != "ios" + # via -r requirements/test-common.in pycparser==3.0 # via cffi -pydantic==2.12.5 - # via python-on-whales -pydantic-core==2.41.5 - # via pydantic +pydantic==2.12.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # python-on-whales +pydantic-core==2.41.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # pydantic pygments==2.19.2 # via # pytest @@ -73,17 +87,17 @@ pytest==9.0.2 # pytest-cov # pytest-mock # pytest-xdist -pytest-codspeed==4.3.0 +pytest-codspeed==4.3.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in pytest-cov==7.0.0 # via -r requirements/test-common.in pytest-mock==3.15.1 # via -r requirements/test-common.in -pytest-xdist==3.8.0 +pytest-xdist==3.8.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in python-dateutil==2.9.0.post0 # via freezegun -python-on-whales==0.81.0 +python-on-whales==0.81.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in rich==14.3.3 # via pytest-codspeed @@ -96,7 +110,7 @@ tomli==2.4.0 # coverage # mypy # pytest -trustme==1.2.1 ; platform_machine != "i686" +trustme==1.2.1 ; platform_machine != "i686" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in typing-extensions==4.15.0 # via @@ -111,5 +125,5 @@ typing-inspection==0.4.2 # via pydantic wait-for-it==2.3.0 # via -r requirements/test-common.in -zlib-ng==1.0.0 +zlib-ng==1.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in diff --git a/requirements/test-ft.txt b/requirements/test-ft.txt index de5fcba25db..ba3c76b88f0 100644 --- a/requirements/test-ft.txt +++ b/requirements/test-ft.txt @@ -4,7 +4,7 @@ # # pip-compile --allow-unsafe --output-file=requirements/test-ft.txt --strip-extras requirements/test-ft.in # -aiodns==4.0.0 +aiodns==4.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in aiohappyeyeballs==2.6.1 # via -r requirements/runtime-deps.in @@ -14,31 +14,34 @@ annotated-types==0.7.0 # via pydantic async-timeout==5.0.1 ; python_version < "3.11" # via -r requirements/runtime-deps.in -backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" +backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in -blockbuster==1.5.26 +blockbuster==1.5.26 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -brotli==1.2.0 ; platform_python_implementation == "CPython" +brotli==1.2.0 ; platform_python_implementation == "CPython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in -cffi==2.0.0 +cffi==2.0.0 ; sys_platform != "android" and sys_platform != "ios" # via + # -r requirements/test-common.in # cryptography # pycares # pytest-codspeed click==8.3.1 # via wait-for-it coverage==7.13.4 + # via pytest-cov +cryptography==46.0.5 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/test-common.in - # pytest-cov -cryptography==46.0.5 - # via trustme + # trustme exceptiongroup==1.3.1 # via pytest execnet==2.1.2 # via pytest-xdist -forbiddenfruit==0.1.4 - # via blockbuster +forbiddenfruit==0.1.4 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # blockbuster freezegun==1.5.5 # via -r requirements/test-common.in frozenlist==1.8.0 @@ -53,10 +56,12 @@ idna==3.11 # yarl iniconfig==2.3.0 # via pytest -isal==1.8.0 ; python_version < "3.14" +isal==1.8.0 ; python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -librt==0.8.0 - # via mypy +librt==0.8.0 ; platform_python_implementation != "PyPy" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy markdown-it-py==4.0.0 # via rich mdurl==0.1.2 @@ -65,10 +70,12 @@ multidict==6.7.1 # via # -r requirements/runtime-deps.in # yarl -mypy==1.19.1 ; implementation_name == "cpython" +mypy==1.19.1 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -mypy-extensions==1.1.0 - # via mypy +mypy-extensions==1.1.0 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy packaging==26.0 # via # gunicorn @@ -87,14 +94,20 @@ propcache==0.4.1 # yarl proxy-py==2.4.10 # via -r requirements/test-common.in -pycares==5.0.1 - # via aiodns +pycares==5.0.1 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # aiodns pycparser==3.0 # via cffi -pydantic==2.12.5 - # via python-on-whales -pydantic-core==2.41.5 - # via pydantic +pydantic==2.12.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # python-on-whales +pydantic-core==2.41.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # pydantic pygments==2.19.2 # via # pytest @@ -106,17 +119,17 @@ pytest==9.0.2 # pytest-cov # pytest-mock # pytest-xdist -pytest-codspeed==4.3.0 +pytest-codspeed==4.3.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in pytest-cov==7.0.0 # via -r requirements/test-common.in pytest-mock==3.15.1 # via -r requirements/test-common.in -pytest-xdist==3.8.0 +pytest-xdist==3.8.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in python-dateutil==2.9.0.post0 # via freezegun -python-on-whales==0.81.0 +python-on-whales==0.81.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in rich==14.3.3 # via pytest-codspeed @@ -129,7 +142,7 @@ tomli==2.4.0 # coverage # mypy # pytest -trustme==1.2.1 ; platform_machine != "i686" +trustme==1.2.1 ; platform_machine != "i686" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in typing-extensions==4.15.0 ; python_version < "3.13" # via @@ -149,5 +162,5 @@ wait-for-it==2.3.0 # via -r requirements/test-common.in yarl==1.22.0 # via -r requirements/runtime-deps.in -zlib-ng==1.0.0 +zlib-ng==1.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in diff --git a/requirements/test.txt b/requirements/test.txt index b2c2968d976..96a56959bc4 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -4,7 +4,7 @@ # # pip-compile --allow-unsafe --output-file=requirements/test.txt --strip-extras requirements/test.in # -aiodns==4.0.0 +aiodns==4.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in aiohappyeyeballs==2.6.1 # via -r requirements/runtime-deps.in @@ -14,31 +14,34 @@ annotated-types==0.7.0 # via pydantic async-timeout==5.0.1 ; python_version < "3.11" # via -r requirements/runtime-deps.in -backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" +backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in -blockbuster==1.5.26 +blockbuster==1.5.26 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -brotli==1.2.0 ; platform_python_implementation == "CPython" +brotli==1.2.0 ; platform_python_implementation == "CPython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/runtime-deps.in -cffi==2.0.0 +cffi==2.0.0 ; sys_platform != "android" and sys_platform != "ios" # via + # -r requirements/test-common.in # cryptography # pycares # pytest-codspeed click==8.3.1 # via wait-for-it coverage==7.13.4 + # via pytest-cov +cryptography==46.0.5 ; sys_platform != "android" and sys_platform != "ios" # via # -r requirements/test-common.in - # pytest-cov -cryptography==46.0.5 - # via trustme + # trustme exceptiongroup==1.3.1 # via pytest execnet==2.1.2 # via pytest-xdist -forbiddenfruit==0.1.4 - # via blockbuster +forbiddenfruit==0.1.4 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # blockbuster freezegun==1.5.5 # via -r requirements/test-common.in frozenlist==1.8.0 @@ -53,10 +56,12 @@ idna==3.11 # yarl iniconfig==2.3.0 # via pytest -isal==1.7.2 ; python_version < "3.14" +isal==1.7.2 ; python_version < "3.14" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -librt==0.8.0 - # via mypy +librt==0.8.0 ; platform_python_implementation != "PyPy" and sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy markdown-it-py==4.0.0 # via rich mdurl==0.1.2 @@ -65,10 +70,12 @@ multidict==6.7.1 # via # -r requirements/runtime-deps.in # yarl -mypy==1.19.1 ; implementation_name == "cpython" +mypy==1.19.1 ; implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in -mypy-extensions==1.1.0 - # via mypy +mypy-extensions==1.1.0 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # mypy packaging==26.0 # via # gunicorn @@ -87,14 +94,20 @@ propcache==0.4.1 # yarl proxy-py==2.4.10 # via -r requirements/test-common.in -pycares==5.0.1 - # via aiodns +pycares==5.0.1 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # aiodns pycparser==3.0 # via cffi -pydantic==2.12.5 - # via python-on-whales -pydantic-core==2.41.5 - # via pydantic +pydantic==2.12.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # python-on-whales +pydantic-core==2.41.5 ; sys_platform != "android" and sys_platform != "ios" + # via + # -r requirements/test-common.in + # pydantic pygments==2.19.2 # via # pytest @@ -106,17 +119,17 @@ pytest==9.0.2 # pytest-cov # pytest-mock # pytest-xdist -pytest-codspeed==4.3.0 +pytest-codspeed==4.3.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in pytest-cov==7.0.0 # via -r requirements/test-common.in pytest-mock==3.15.1 # via -r requirements/test-common.in -pytest-xdist==3.8.0 +pytest-xdist==3.8.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in python-dateutil==2.9.0.post0 # via freezegun -python-on-whales==0.81.0 +python-on-whales==0.81.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in rich==14.3.3 # via pytest-codspeed @@ -129,7 +142,7 @@ tomli==2.4.0 # coverage # mypy # pytest -trustme==1.2.1 ; platform_machine != "i686" +trustme==1.2.1 ; platform_machine != "i686" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in typing-extensions==4.15.0 ; python_version < "3.13" # via @@ -145,11 +158,11 @@ typing-extensions==4.15.0 ; python_version < "3.13" # typing-inspection typing-inspection==0.4.2 # via pydantic -uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpython" +uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpython" and sys_platform != "android" and sys_platform != "ios" # via -r requirements/base.in wait-for-it==2.3.0 # via -r requirements/test-common.in yarl==1.22.0 # via -r requirements/runtime-deps.in -zlib-ng==1.0.0 +zlib-ng==1.0.0 ; sys_platform != "android" and sys_platform != "ios" # via -r requirements/test-common.in diff --git a/setup.cfg b/setup.cfg index 2d7e24b0374..7e50e3fc490 100644 --- a/setup.cfg +++ b/setup.cfg @@ -88,6 +88,8 @@ filterwarnings = # https://github.com/spulec/freezegun/issues/508 # https://github.com/spulec/freezegun/pull/511 ignore:datetime.*utcnow\(\) is deprecated and scheduled for removal:DeprecationWarning:freezegun.api + # coverage's C tracer is not available on iOS/Android (pure-Python fallback is used instead) + ignore:Couldn't import C tracer:coverage.exceptions.CoverageWarning junit_suite_name = aiohttp_test_suite norecursedirs = dist docs build .tox .eggs minversion = 3.8.2 diff --git a/tests/conftest.py b/tests/conftest.py index 336c0e14d40..28535b9e072 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,10 +19,14 @@ from uuid import uuid4 import pytest -import trustme from multidict import CIMultiDict from yarl import URL +try: + import trustme +except ImportError: # pragma: no cover + pass + try: from blockbuster import blockbuster_ctx @@ -113,7 +117,8 @@ def blockbuster(request: pytest.FixtureRequest) -> Iterator[None]: @pytest.fixture def tls_certificate_authority() -> trustme.CA: - return trustme.CA() + trustme = pytest.importorskip("trustme") + return trustme.CA() # type: ignore[no-any-return] @pytest.fixture diff --git a/tests/test_benchmarks_client.py b/tests/test_benchmarks_client.py index 5e205549e9c..5beea505db8 100644 --- a/tests/test_benchmarks_client.py +++ b/tests/test_benchmarks_client.py @@ -3,6 +3,8 @@ import asyncio import pytest + +pytest.importorskip("pytest_codspeed") from pytest_codspeed import BenchmarkFixture from yarl import URL diff --git a/tests/test_benchmarks_client_request.py b/tests/test_benchmarks_client_request.py index 0a37087380f..5d71153e281 100644 --- a/tests/test_benchmarks_client_request.py +++ b/tests/test_benchmarks_client_request.py @@ -2,6 +2,10 @@ import asyncio import sys + +import pytest + +pytest.importorskip("pytest_codspeed") from collections.abc import Callable from http.cookies import BaseCookie from typing import Any diff --git a/tests/test_benchmarks_client_ws.py b/tests/test_benchmarks_client_ws.py index 0338b52fb9d..72b40e92bf9 100644 --- a/tests/test_benchmarks_client_ws.py +++ b/tests/test_benchmarks_client_ws.py @@ -3,6 +3,8 @@ import asyncio import pytest + +pytest.importorskip("pytest_codspeed") from pytest_codspeed import BenchmarkFixture from aiohttp import web diff --git a/tests/test_benchmarks_cookiejar.py b/tests/test_benchmarks_cookiejar.py index 78566151ef4..c2dd294fd03 100644 --- a/tests/test_benchmarks_cookiejar.py +++ b/tests/test_benchmarks_cookiejar.py @@ -2,6 +2,9 @@ from http.cookies import BaseCookie +import pytest + +pytest.importorskip("pytest_codspeed") from pytest_codspeed import BenchmarkFixture from yarl import URL diff --git a/tests/test_benchmarks_http_websocket.py b/tests/test_benchmarks_http_websocket.py index 2aa9b8294bd..61630d14fda 100644 --- a/tests/test_benchmarks_http_websocket.py +++ b/tests/test_benchmarks_http_websocket.py @@ -3,6 +3,8 @@ import asyncio import pytest + +pytest.importorskip("pytest_codspeed") from pytest_codspeed import BenchmarkFixture from aiohttp._websocket.helpers import MSG_SIZE, PACK_LEN3 diff --git a/tests/test_benchmarks_http_writer.py b/tests/test_benchmarks_http_writer.py index 0d52ca875e6..617f02efdba 100644 --- a/tests/test_benchmarks_http_writer.py +++ b/tests/test_benchmarks_http_writer.py @@ -1,5 +1,8 @@ """codspeed benchmarks for http writer.""" +import pytest + +pytest.importorskip("pytest_codspeed") from multidict import CIMultiDict from pytest_codspeed import BenchmarkFixture diff --git a/tests/test_benchmarks_web_fileresponse.py b/tests/test_benchmarks_web_fileresponse.py index 01aa7448c86..4d42cef9c37 100644 --- a/tests/test_benchmarks_web_fileresponse.py +++ b/tests/test_benchmarks_web_fileresponse.py @@ -3,6 +3,9 @@ import asyncio import pathlib +import pytest + +pytest.importorskip("pytest_codspeed") from multidict import CIMultiDict from pytest_codspeed import BenchmarkFixture diff --git a/tests/test_benchmarks_web_middleware.py b/tests/test_benchmarks_web_middleware.py index 497da1819c9..c08a33cc7ea 100644 --- a/tests/test_benchmarks_web_middleware.py +++ b/tests/test_benchmarks_web_middleware.py @@ -2,6 +2,9 @@ import asyncio +import pytest + +pytest.importorskip("pytest_codspeed") from pytest_codspeed import BenchmarkFixture from aiohttp import web diff --git a/tests/test_benchmarks_web_response.py b/tests/test_benchmarks_web_response.py index fbf1fadf1e1..d80e4d3cf64 100644 --- a/tests/test_benchmarks_web_response.py +++ b/tests/test_benchmarks_web_response.py @@ -1,5 +1,8 @@ """codspeed benchmarks for the web responses.""" +import pytest + +pytest.importorskip("pytest_codspeed") from pytest_codspeed import BenchmarkFixture from aiohttp import web diff --git a/tests/test_benchmarks_web_urldispatcher.py b/tests/test_benchmarks_web_urldispatcher.py index 339eaef8a0e..627a92bcc98 100644 --- a/tests/test_benchmarks_web_urldispatcher.py +++ b/tests/test_benchmarks_web_urldispatcher.py @@ -10,6 +10,8 @@ from unittest import mock import pytest + +pytest.importorskip("pytest_codspeed") from multidict import CIMultiDict, CIMultiDictProxy from pytest_codspeed import BenchmarkFixture from yarl import URL diff --git a/tests/test_circular_imports.py b/tests/test_circular_imports.py index 9b5d7ed2697..227da10e53b 100644 --- a/tests/test_circular_imports.py +++ b/tests/test_circular_imports.py @@ -85,6 +85,9 @@ def _discover_path_importables( ) +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="subprocess not supported" +) @pytest.mark.parametrize( "import_path", _mark_aiohttp_worker_for_skipping(_find_all_importables(aiohttp)), diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index 971e7576d52..706487957a0 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -1,4 +1,5 @@ # HTTP client functional tests against aiohttp.web server +from __future__ import annotations # TODO(PY311): Remove import asyncio import datetime @@ -19,6 +20,11 @@ from typing import Any, NoReturn from unittest import mock +try: + import trustme +except ImportError: # pragma: no cover + pass + try: try: import brotlicffi as brotli @@ -33,7 +39,6 @@ ZstdCompressor = None # type: ignore[assignment,misc] # pragma: no cover import pytest -import trustme from multidict import MultiDict from pytest_mock import MockerFixture from yarl import URL, Query diff --git a/tests/test_cookiejar.py b/tests/test_cookiejar.py index 24c1f73284c..f267104d34c 100644 --- a/tests/test_cookiejar.py +++ b/tests/test_cookiejar.py @@ -1569,6 +1569,9 @@ async def test_shared_cookie_with_multiple_domains() -> None: # === Security tests for restricted unpickler and JSON save/load === +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="os.system not supported" +) def test_load_rejects_malicious_pickle(tmp_path: Path) -> None: """Verify CookieJar.load() blocks arbitrary code execution via pickle. diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py index b20be7434a4..7be1e86d7f6 100644 --- a/tests/test_http_parser.py +++ b/tests/test_http_parser.py @@ -2050,6 +2050,9 @@ async def test_feed_eof_no_err_gzip(self, protocol: BaseProtocol) -> None: dbuf.feed_eof() assert [b"line"] == list(buf._buffer) + @pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="brotli not available" + ) async def test_feed_eof_no_err_brotli(self, protocol: BaseProtocol) -> None: buf = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) dbuf = DeflateBuffer(buf, "br") diff --git a/tests/test_leaks.py b/tests/test_leaks.py index 07b506bdb99..742d6f9aa65 100644 --- a/tests/test_leaks.py +++ b/tests/test_leaks.py @@ -8,6 +8,9 @@ IS_PYPY = platform.python_implementation() == "PyPy" +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="subprocess not supported" +) @pytest.mark.skipif(IS_PYPY, reason="gc.DEBUG_LEAK not available on PyPy") @pytest.mark.parametrize( ("script", "message"), diff --git a/tests/test_loop.py b/tests/test_loop.py index 0feaf5ce1a5..ef1a67b854e 100644 --- a/tests/test_loop.py +++ b/tests/test_loop.py @@ -1,5 +1,6 @@ import asyncio import platform +import sys import threading import pytest @@ -8,6 +9,9 @@ from aiohttp.test_utils import AioHTTPTestCase, loop_context +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="subprocess not available" +) @pytest.mark.skipif( platform.system() == "Windows", reason="the test is not valid for Windows" ) @@ -40,6 +44,9 @@ def test_default_loop(loop: asyncio.AbstractEventLoop) -> None: assert asyncio.get_event_loop() is loop +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="subprocess not available" +) def test_setup_loop_non_main_thread() -> None: child_exc = None diff --git a/tests/test_multipart.py b/tests/test_multipart.py index 52e97a993a3..b2489f15d84 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -122,7 +122,7 @@ async def read(self, size: int | None = None) -> bytes: class TestMultipartResponseWrapper: - def test_at_eof(self) -> None: + async def test_at_eof(self) -> None: m_resp = mock.create_autospec(aiohttp.ClientResponse, spec_set=True) m_stream = mock.create_autospec(MultipartReader, spec_set=True) wrapper = MultipartResponseWrapper(m_resp, m_stream) diff --git a/tests/test_proxy_functional.py b/tests/test_proxy_functional.py index 7c92b840790..dfab406cbcf 100644 --- a/tests/test_proxy_functional.py +++ b/tests/test_proxy_functional.py @@ -11,8 +11,10 @@ from unittest import mock from uuid import uuid4 -import proxy import pytest + +pytest.importorskip("proxy") +import proxy from pytest_mock import MockerFixture from yarl import URL diff --git a/tests/test_run_app.py b/tests/test_run_app.py index 9e1fdb63176..e3b6a3fed53 100644 --- a/tests/test_run_app.py +++ b/tests/test_run_app.py @@ -688,6 +688,9 @@ def test_run_app_multiple_preexisting_sockets( """ +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="subprocess not supported" +) def test_sigint() -> None: skip_if_on_windows() @@ -700,6 +703,9 @@ def test_sigint() -> None: assert proc.wait() == 0 +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="subprocess not supported" +) def test_sigterm() -> None: skip_if_on_windows() diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py index 6603389f16d..33ee6d8f894 100644 --- a/tests/test_urldispatch.py +++ b/tests/test_urldispatch.py @@ -1063,7 +1063,7 @@ def test_static_route_user_home(router: web.UrlDispatcher) -> None: except ValueError: pytest.skip("aiohttp folder is not placed in user's HOME") route = router.add_static("/st", str(static_dir)) - assert here == route.get_info()["directory"] + assert here.resolve() == route.get_info()["directory"] def test_static_route_points_to_file(router: web.UrlDispatcher) -> None: @@ -1087,7 +1087,7 @@ async def test_405_for_resource_adapter(router: web.UrlDispatcher) -> None: @pytest.mark.skipif(platform.system() == "Windows", reason="Different path formats") async def test_static_resource_outside_traversal(router: web.UrlDispatcher) -> None: """Test relative path traversing outside root does not resolve.""" - static_file = pathlib.Path(aiohttp.__file__) + static_file = pathlib.Path(aiohttp.__file__).resolve() request_path = "/st" + "/.." * (len(static_file.parts) - 2) + str(static_file) assert pathlib.Path(request_path).resolve() == static_file diff --git a/tests/test_web_functional.py b/tests/test_web_functional.py index 730d662ced4..81da4969c80 100644 --- a/tests/test_web_functional.py +++ b/tests/test_web_functional.py @@ -33,7 +33,10 @@ try: import brotlicffi as brotli except ImportError: - import brotli + try: + import brotli + except ImportError: + brotli = None try: import ssl @@ -1132,9 +1135,12 @@ async def handler(request: web.Request) -> web.Response: resp.release() +@pytest.mark.skipif(brotli is None, reason="brotli not available") async def test_response_with_precompressed_body_brotli( aiohttp_client: AiohttpClient, ) -> None: + assert brotli is not None + async def handler(request: web.Request) -> web.Response: headers = {"Content-Encoding": "br"} return web.Response(body=brotli.compress(b"mydata"), headers=headers) diff --git a/tests/test_web_sendfile_functional.py b/tests/test_web_sendfile_functional.py index 87be2db182b..901da56cf35 100644 --- a/tests/test_web_sendfile_functional.py +++ b/tests/test_web_sendfile_functional.py @@ -3,6 +3,7 @@ import gzip import pathlib import socket +import sys from collections.abc import Iterable, Iterator from typing import Protocol from unittest import mock @@ -19,7 +20,10 @@ try: import brotlicffi as brotli except ImportError: - import brotli + try: + import brotli + except ImportError: + brotli = None try: import ssl @@ -54,9 +58,12 @@ def hello_txt( } # Uncompressed file is not actually written to test it is not required. hello["gzip"].write_bytes(gzip.compress(HELLO_AIOHTTP)) - hello["br"].write_bytes(brotli.compress(HELLO_AIOHTTP)) + if brotli is not None: + hello["br"].write_bytes(brotli.compress(HELLO_AIOHTTP)) hello["bzip2"].write_bytes(bz2.compress(HELLO_AIOHTTP)) encoding = getattr(request, "param", None) + if encoding == "br" and brotli is None: + pytest.skip("brotli not available") return hello[encoding] @@ -275,6 +282,9 @@ async def test_static_file_custom_content_type_compress( ) -> None: """Test that custom type with encoding is returned for unencoded requests.""" + if expect_encoding == "br" and brotli is None: + pytest.skip("brotli not available") + async def handler(request: web.Request) -> web.FileResponse: resp = sender(hello_txt, chunk_size=16) resp.content_type = "application/pdf" @@ -309,6 +319,8 @@ async def test_static_file_with_encoding_and_enable_compression( forced_compression: web.ContentCoding | None, ) -> None: """Test that enable_compression does not double compress when an encoded file is also present.""" + if expect_encoding == "br" and brotli is None: + pytest.skip("brotli not available") async def handler(request: web.Request) -> web.FileResponse: resp = sender(hello_txt) @@ -614,6 +626,9 @@ async def test_static_file_ssl( await conn.close() +@pytest.mark.skipif( + sys.platform in ("android", "ios"), reason="README.md not supported" +) async def test_static_file_directory_traversal_attack( aiohttp_client: AiohttpClient, ) -> None: