diff --git a/.github/workflows/release-wheels.yml b/.github/workflows/release-wheels.yml index 195fcbb8..a370eb98 100644 --- a/.github/workflows/release-wheels.yml +++ b/.github/workflows/release-wheels.yml @@ -18,7 +18,7 @@ concurrency: cancel-in-progress: true jobs: - py-wheels-matrix: + py-generate-matrix: name: "generate build matrix" runs-on: ubuntu-latest if: > @@ -34,59 +34,29 @@ jobs: contains(github.event.pull_request.labels.*.name, 'check-wheels') ) outputs: - matrix: ${{ steps.make-matrix.outputs.matrix }} + wheels: ${{ steps.make-matrix-wheels.outputs.matrix }} + tests: ${{ steps.make-matrix-tests.outputs.matrix }} steps: - - id: make-matrix - shell: python - name: generate matrix + - id: download-matrix-scripts + name: retrieve matrix scripts run: | - import itertools - import json - import os - import pprint - - builder = { - ('linux', 'x86_64'): 'ubuntu-latest', - ('linux', 'aarch64'): 'ubuntu-24.04-arm', - ('musllinux', 'x86_64'): 'ubuntu-latest', - ('musllinux', 'aarch64'): 'ubuntu-24.04-arm', - ('macos', 'x86_64'): 'macos-15-intel', - ('macos', 'aarch64'): 'macos-latest', - ('windows', 'x86_64'): 'windows-latest', - ('windows', 'aarch64'): 'windows-11-arm', - } - - matrix = [ - d - for d in map(dict, itertools.product( - (('python-version', v) for v in ["3.x", "3.14t", "pypy-3.11", "graalpy-25"]), - (('arch', a) for a in ["x86_64", "aarch64"]), - (('platform', p) for p in ["linux", "musllinux", "windows", "macos"]) - )) - # on windows, only cpython has arm builds (?) - if d['python-version'].startswith('3.') \ - or d['platform'] != 'windows' \ - or d['arch'] != 'aarch64' - ] - for job in matrix: - match job['platform']: - case 'linux': - job['manylinux'] = 'auto' - job['args'] = ' --zig' # use zig instead of docker for manylinux cross-builds (see #315) - case 'mussllinux': - job['manylinux'] = 'musllinux_1_2' - - job['runs'] = builder[job['platform'], job['arch']] - - with open(os.environ['GITHUB_OUTPUT'], 'w') as f: - f.write("matrix=") - json.dump({'include': matrix}, f) - f.flush() - + curl -fsSL \ + -O https://raw.githubusercontent.com/${{ github.repository }}/${{ github.sha }}/scripts/matrix-wheels.py \ + -O https://raw.githubusercontent.com/${{ github.repository }}/${{ github.sha }}/scripts/matrix-tests.py + - id: make-matrix-wheels + name: generate wheels matrix + run: | + echo -n "matrix=" >> $GITHUB_OUTPUT + python3 matrix-wheels.py | tee -a $GITHUB_OUTPUT | jq "." + - id: make-matrix-tests + name: generate tests matrix + run: | + echo -n "matrix=" >> $GITHUB_OUTPUT + python3 matrix-tests.py | tee -a $GITHUB_OUTPUT | jq "." py-release-wheels: - needs: [py-wheels-matrix] + needs: [py-generate-matrix] strategy: - matrix: ${{fromJson(needs.py-wheels-matrix.outputs.matrix)}} + matrix: ${{ fromJson(needs.py-generate-matrix.outputs.wheels) }} runs-on: ${{ matrix.runs }} @@ -97,8 +67,7 @@ jobs: - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ matrix.python-version }} - # windows/arm doesn't have a rust toolchain by default - - if: matrix.platform == 'windows' && matrix.arch == 'aarch64' + - if: (matrix.setup-rust) uses: actions-rust-lang/setup-rust-toolchain@ecabd13d1c56bd1345c230e542e9144811ad706f # v2.0.0 - name: Build wheels uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 @@ -109,7 +78,7 @@ jobs: - name: Upload wheels uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ua-parser-rs-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.python-version }} + name: ua-parser-rs-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.python-version }}.whl path: dist/* retention-days: 1 compression-level: 0 @@ -132,64 +101,9 @@ jobs: path: dist py-release-tests: - needs: py-release-wheels - + needs: [py-generate-matrix, py-release-wheels] strategy: - matrix: - python-version: - - "3.10" - - "3.11" - - "3.12" - - "3.13" - - "3.14" - - "3.14t" - - "pypy-3.11" - - "graalpy-25" - platform: - - linux - # probably requires a custom image of some sort - # - musllinux - - windows - - macos - arch: - - x86_64 - - aarch64 - - exclude: - - platform: windows - python-version: 3.10 - arch: aarch64 - - platform: windows - arch: aarch64 - python-version: pypy-3.11 - - platform: windows - python-version: graalpy-25 - - include: - - wheel: "3.x" - - python-version: "3.14t" - wheel: "3.14t" - - python-version: "pypy-3.11" - wheel: "pypy-3.11" - - python-version: "graalpy-25" - wheel: "graalpy-25" - - - runner: ubuntu-latest - - arch: aarch64 - runner: ubuntu-24.04-arm - - platform: windows - runner: windows-latest - - platform: windows - arch: aarch64 - runner: windows-11-arm - - platform: macos - runner: macos-latest - - platform: macos - arch: x86_64 - runner: macos-15-intel - - opts: "" - - python-version: graalpy-25 - opts: "--experimental-options --engine.CompileOnly='~tregex re'" + matrix: ${{ fromJson(needs.py-generate-matrix.outputs.tests) }} runs-on: ${{ matrix.runner }} @@ -204,10 +118,11 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true + freethreaded: ${{ endsWith(matrix.python-version, 't') }} - name: Retrieve wheel uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # 8.0.1 with: - name: ua-parser-rs-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.wheel }} + name: ua-parser-rs-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.wheel }}.whl path: dist - name: Update pip run: python -mpip install --upgrade pip diff --git a/pyproject.toml b/pyproject.toml index 42a5a144..0ead22f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,12 +30,12 @@ classifiers = [ "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries :: Python Modules", - "Programming Language :: Python", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: GraalPy", diff --git a/scripts/matrix-tests.py b/scripts/matrix-tests.py new file mode 100644 index 00000000..2260dddd --- /dev/null +++ b/scripts/matrix-tests.py @@ -0,0 +1,51 @@ +import itertools +import json + +# fmt: off +PYTHON_VERSIONS = [ + "3.10", "3.11", "3.12", "3.13", "3.14", "3.15", + "3.14t", "3.15t", + "pypy-3.11", "pypy-3.12", + "graalpy-25", +] +matrix = [ + d + for d in map(dict, itertools.product( + (("python-version", v) for v in PYTHON_VERSIONS), + (("arch", a) for a in ["x86_64", "aarch64"]), + (("platform", p) for p in ["linux", "windows", "macos"]), + )) + # on windows, only cpython has arm builds (?) + if (d["python-version"].startswith("3.") and d["python-version"] != "3.10") + or d["platform"] != "windows" + or d["arch"] != "aarch64" +] +# fmt: on + +RUNNERS = { + ("linux", "x86_64"): "ubuntu-latest", + ("linux", "aarch64"): "ubuntu-24.04-arm", + ("musllinux", "x86_64"): "ubuntu-latest", + ("musllinux", "aarch64"): "ubuntu-24.04-arm", + ("macos", "x86_64"): "macos-15-intel", + ("macos", "aarch64"): "macos-latest", + ("windows", "x86_64"): "windows-latest", + ("windows", "aarch64"): "windows-11-arm", +} +for job in matrix: + job["opts"] = "" + job["runner"] = RUNNERS[job["platform"], job["arch"]] + + match job["python-version"]: + case "3.14t": + job["wheel"] = "3.14t" + case "3.15t": + job["wheel"] = "3.15" + case v if v.startswith("3."): + job["wheel"] = "3.14" + case v: # pypy, graal only do single-version wheels + job["wheel"] = v + if v.startswith("graal"): + job["opts"] = "--experimental-options --engine.CompileOnly='~tregex re'" + +print(json.dumps({"include": matrix})) diff --git a/scripts/matrix-wheels.py b/scripts/matrix-wheels.py new file mode 100644 index 00000000..04871b4a --- /dev/null +++ b/scripts/matrix-wheels.py @@ -0,0 +1,44 @@ +import itertools +import json + +builder = { + ("linux", "x86_64"): "ubuntu-latest", + ("linux", "aarch64"): "ubuntu-24.04-arm", + ("musllinux", "x86_64"): "ubuntu-latest", + ("musllinux", "aarch64"): "ubuntu-24.04-arm", + ("macos", "x86_64"): "macos-15-intel", + ("macos", "aarch64"): "macos-latest", + ("windows", "x86_64"): "windows-latest", + ("windows", "aarch64"): "windows-11-arm", +} + +# fmt: off +matrix = [ + d + for d in map(dict, itertools.product( + (("python-version", v) for v in ["3.14", "3.14t", "3.15", "pypy-3.11", "pypy-3.12", "graalpy-25"]), + (("arch", a) for a in ["x86_64", "aarch64"]), + (("platform", p) for p in ["linux", "musllinux", "windows", "macos"]), + )) + # on windows, only cpython has arm builds (?) + if d["python-version"].startswith("3.") + or d["platform"] != "windows" + or d["arch"] != "aarch64" +] +# fmt: on +# platform-specific fixups +for job in matrix: + match job["platform"]: + case "linux": + job["manylinux"] = "auto" + # use zig instead of docker for manylinux cross-builds (see #315) + job["args"] = " --zig" + case "mussllinux": + job["manylinux"] = "musllinux_1_2" + # windows/arm doesn't have a rust toolchain by default + case "windows" if job["arch"] == "aarch64": + job["setup-rust"] = True + + job["runs"] = builder[job["platform"], job["arch"]] + +print(json.dumps({"include": matrix})) diff --git a/tox.ini b/tox.ini index 37621d9f..94123347 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,8 @@ [tox] min_version = 4.0 -env_list = py3{10,11,12,13,14,14t} - pypy{311} - graalpy3{11,12} +env_list = py3{10,11,12,13,14,14t,15,15t} + pypy{311,312} + graalpy313 check, format, typecheck [testenv] @@ -22,6 +22,7 @@ deps = commands = pytest -Werror --doctest-glob="*.rst" {posargs} +# versions with re2 support [testenv:py3{10,11,12,13,14}] labels = test, cpy deps = diff --git a/ua-parser-builtins/pyproject.toml b/ua-parser-builtins/pyproject.toml index 6fc800dc..d4059adc 100644 --- a/ua-parser-builtins/pyproject.toml +++ b/ua-parser-builtins/pyproject.toml @@ -24,12 +24,12 @@ classifiers = [ "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries :: Python Modules", - "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: GraalPy", diff --git a/ua-parser-rs/Cargo.lock b/ua-parser-rs/Cargo.lock index 167440ef..c68231c0 100644 --- a/ua-parser-rs/Cargo.lock +++ b/ua-parser-rs/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - [[package]] name = "either" version = "1.15.0" @@ -29,15 +23,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - [[package]] name = "itertools" version = "0.14.0" @@ -59,15 +44,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.21.4" @@ -91,35 +67,32 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.27.2" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d" +checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4" dependencies = [ - "indoc", "libc", - "memoffset", "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", - "unindent", ] [[package]] name = "pyo3-build-config" -version = "0.27.2" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6" +checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700" dependencies = [ "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.27.2" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089" +checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4" dependencies = [ "libc", "pyo3-build-config", @@ -127,27 +100,26 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.27.2" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02" +checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "pyo3-macros-backend" -version = "0.27.2" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9" +checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b" dependencies = [ "heck", "proc-macro2", - "pyo3-build-config", "quote", - "syn", + "syn 3.0.9", ] [[package]] @@ -200,12 +172,6 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - [[package]] name = "serde" version = "1.0.228" @@ -233,7 +199,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -247,6 +213,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "target-lexicon" version = "0.13.5" @@ -266,7 +243,7 @@ dependencies = [ [[package]] name = "ua-parser-rs" -version = "0.1.4" +version = "0.1.5" dependencies = [ "pyo3", "ua-parser", @@ -277,9 +254,3 @@ name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unindent" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" diff --git a/ua-parser-rs/Cargo.toml b/ua-parser-rs/Cargo.toml index 273e9035..b5641334 100644 --- a/ua-parser-rs/Cargo.toml +++ b/ua-parser-rs/Cargo.toml @@ -14,5 +14,5 @@ name = "ua_parser_rs" crate-type = ["cdylib"] [dependencies] -pyo3 = { version = "0.27", features = ["extension-module", "abi3", "abi3-py310"] } +pyo3 = { version = "0.30.1", features = ["extension-module", "abi3", "abi3-py310", "abi3t", "abi3t-py315"] } ua-parser = "0.2.2" diff --git a/ua-parser-rs/pyproject.toml b/ua-parser-rs/pyproject.toml index 555cbec4..2fd99564 100644 --- a/ua-parser-rs/pyproject.toml +++ b/ua-parser-rs/pyproject.toml @@ -14,6 +14,8 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", + "Programming Language :: Python :: Free Threading :: 4 - Resilient", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: GraalPy",