pydeno 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. pydeno-0.4.0/.github/workflows/benchmarks.yml +32 -0
  2. pydeno-0.4.0/.github/workflows/docs.yml +58 -0
  3. pydeno-0.4.0/.github/workflows/test.yml +229 -0
  4. pydeno-0.4.0/.github/workflows/workflow.yaml +127 -0
  5. pydeno-0.4.0/.gitignore +80 -0
  6. pydeno-0.4.0/BENCHMARKS.md +395 -0
  7. pydeno-0.4.0/CLAUDE.md +481 -0
  8. pydeno-0.4.0/Cargo.lock +2609 -0
  9. pydeno-0.4.0/Cargo.toml +77 -0
  10. pydeno-0.4.0/LICENSE +28 -0
  11. pydeno-0.4.0/Makefile +100 -0
  12. pydeno-0.4.0/PKG-INFO +222 -0
  13. pydeno-0.4.0/README.md +192 -0
  14. pydeno-0.4.0/benches/runtime_benches.rs +112 -0
  15. pydeno-0.4.0/benches_py/test_bench_runtime.py +109 -0
  16. pydeno-0.4.0/benchmarks/README.md +70 -0
  17. pydeno-0.4.0/benchmarks/bench_memory.py +105 -0
  18. pydeno-0.4.0/benchmarks/bench_regex.py +86 -0
  19. pydeno-0.4.0/benchmarks/bench_startup.py +56 -0
  20. pydeno-0.4.0/benchmarks/bench_threading.py +71 -0
  21. pydeno-0.4.0/benchmarks/suite.py +102 -0
  22. pydeno-0.4.0/docs/api/config.md +3 -0
  23. pydeno-0.4.0/docs/api/pydeno.md +14 -0
  24. pydeno-0.4.0/docs/api/runtime.md +3 -0
  25. pydeno-0.4.0/docs/api/types.md +17 -0
  26. pydeno-0.4.0/docs/concepts/evaluation.md +345 -0
  27. pydeno-0.4.0/docs/concepts/runtime.md +291 -0
  28. pydeno-0.4.0/docs/concepts/types.md +275 -0
  29. pydeno-0.4.0/docs/contributing/architecture.md +451 -0
  30. pydeno-0.4.0/docs/contributing/development.md +66 -0
  31. pydeno-0.4.0/docs/contributing/upstream-divergence.md +115 -0
  32. pydeno-0.4.0/docs/guides/advanced/arrow-ipc-dataframes.md +200 -0
  33. pydeno-0.4.0/docs/guides/advanced/inspector.md +63 -0
  34. pydeno-0.4.0/docs/guides/advanced/snapshots.md +206 -0
  35. pydeno-0.4.0/docs/guides/advanced/vendored-npm-libraries.md +220 -0
  36. pydeno-0.4.0/docs/guides/advanced/webassembly.md +80 -0
  37. pydeno-0.4.0/docs/guides/bindings.md +498 -0
  38. pydeno-0.4.0/docs/guides/modules.md +270 -0
  39. pydeno-0.4.0/docs/index.md +57 -0
  40. pydeno-0.4.0/docs/quickstart.md +116 -0
  41. pydeno-0.4.0/docs/stable-release-review.md +813 -0
  42. pydeno-0.4.0/docs/stubs/pydeno/__init__.py +68 -0
  43. pydeno-0.4.0/docs/stubs/pydeno/_pydeno.py +1107 -0
  44. pydeno-0.4.0/docs/stylesheets/extra.css +6 -0
  45. pydeno-0.4.0/docs/use-cases/ai-agent.md +227 -0
  46. pydeno-0.4.0/docs/use-cases/playground.md +100 -0
  47. pydeno-0.4.0/docs/use-cases/plugin-system.md +177 -0
  48. pydeno-0.4.0/docs/use-cases/serverless-runtime.md +259 -0
  49. pydeno-0.4.0/docs/use-cases/workflow.md +226 -0
  50. pydeno-0.4.0/examples/README.md +80 -0
  51. pydeno-0.4.0/examples/add.wasm +0 -0
  52. pydeno-0.4.0/examples/arrow_ipc_dataframes.py +255 -0
  53. pydeno-0.4.0/examples/basic_eval.py +57 -0
  54. pydeno-0.4.0/examples/bindings_async.py +121 -0
  55. pydeno-0.4.0/examples/bindings_basic.py +232 -0
  56. pydeno-0.4.0/examples/context_local_api.py +166 -0
  57. pydeno-0.4.0/examples/fastapi_multitenant.py +172 -0
  58. pydeno-0.4.0/examples/fastmcp_tool_bridge.py +124 -0
  59. pydeno-0.4.0/examples/inspector.py +48 -0
  60. pydeno-0.4.0/examples/markdown_parser.py +86 -0
  61. pydeno-0.4.0/examples/modules_basic.py +43 -0
  62. pydeno-0.4.0/examples/modules_wasm.py +41 -0
  63. pydeno-0.4.0/examples/pptxgenjs_presentation.py +435 -0
  64. pydeno-0.4.0/examples/pydantic_ai_agent.py +115 -0
  65. pydeno-0.4.0/examples/resource_limits.py +292 -0
  66. pydeno-0.4.0/examples/snapshot_example.py +245 -0
  67. pydeno-0.4.0/examples/threading_gil.py +81 -0
  68. pydeno-0.4.0/examples/tool_bridge.py +117 -0
  69. pydeno-0.4.0/examples/type_conversion.py +280 -0
  70. pydeno-0.4.0/examples/vendored_npm_libraries.py +185 -0
  71. pydeno-0.4.0/mkdocs.yml +109 -0
  72. pydeno-0.4.0/pyproject.toml +67 -0
  73. pydeno-0.4.0/python/pydeno/__init__.py +273 -0
  74. pydeno-0.4.0/python/pydeno/__main__.py +63 -0
  75. pydeno-0.4.0/python/pydeno/_awaitable.py +30 -0
  76. pydeno-0.4.0/python/pydeno/_pydeno.pyi +1107 -0
  77. pydeno-0.4.0/python/pydeno/_tools.py +345 -0
  78. pydeno-0.4.0/python/pydeno/py.typed +0 -0
  79. pydeno-0.4.0/scripts/check_test_report.py +140 -0
  80. pydeno-0.4.0/src/lib.rs +49 -0
  81. pydeno-0.4.0/src/runtime/config.rs +712 -0
  82. pydeno-0.4.0/src/runtime/conversion.rs +450 -0
  83. pydeno-0.4.0/src/runtime/error.rs +298 -0
  84. pydeno-0.4.0/src/runtime/handle.rs +980 -0
  85. pydeno-0.4.0/src/runtime/inspector.rs +515 -0
  86. pydeno-0.4.0/src/runtime/js_value.rs +623 -0
  87. pydeno-0.4.0/src/runtime/loader.rs +399 -0
  88. pydeno-0.4.0/src/runtime/mod.rs +191 -0
  89. pydeno-0.4.0/src/runtime/ops.rs +841 -0
  90. pydeno-0.4.0/src/runtime/python/bridge.rs +233 -0
  91. pydeno-0.4.0/src/runtime/python/error.rs +101 -0
  92. pydeno-0.4.0/src/runtime/python/mod.rs +82 -0
  93. pydeno-0.4.0/src/runtime/python/runtime.rs +1139 -0
  94. pydeno-0.4.0/src/runtime/python/snapshot.rs +49 -0
  95. pydeno-0.4.0/src/runtime/python/stats.rs +153 -0
  96. pydeno-0.4.0/src/runtime/python/utils.rs +58 -0
  97. pydeno-0.4.0/src/runtime/runner.rs +3723 -0
  98. pydeno-0.4.0/src/runtime/snapshot.rs +115 -0
  99. pydeno-0.4.0/src/runtime/stats.rs +241 -0
  100. pydeno-0.4.0/src/runtime/stream.rs +533 -0
  101. pydeno-0.4.0/tests/test_console_capture.py +303 -0
  102. pydeno-0.4.0/tests/test_dispatcher_step_timeout.py +85 -0
  103. pydeno-0.4.0/tests/test_function.py +243 -0
  104. pydeno-0.4.0/tests/test_fuzz_eval_boundary.py +670 -0
  105. pydeno-0.4.0/tests/test_gil_and_limits.py +255 -0
  106. pydeno-0.4.0/tests/test_guest_globals.py +197 -0
  107. pydeno-0.4.0/tests/test_idle_cpu.py +168 -0
  108. pydeno-0.4.0/tests/test_known_escape_techniques.py +555 -0
  109. pydeno-0.4.0/tests/test_large_script_eval.py +139 -0
  110. pydeno-0.4.0/tests/test_microtask_timeout.py +78 -0
  111. pydeno-0.4.0/tests/test_modules.py +274 -0
  112. pydeno-0.4.0/tests/test_ops.py +645 -0
  113. pydeno-0.4.0/tests/test_parked_termination.py +484 -0
  114. pydeno-0.4.0/tests/test_pydeno_api.py +378 -0
  115. pydeno-0.4.0/tests/test_runtime.py +1891 -0
  116. pydeno-0.4.0/tests/test_serialization_headroom.py +173 -0
  117. pydeno-0.4.0/tests/test_sparse_array_limits.py +69 -0
  118. pydeno-0.4.0/tests/test_stress_concurrency.py +197 -0
  119. pydeno-0.4.0/tests/test_termination_handle.py +132 -0
  120. pydeno-0.4.0/tests/test_thread_stack_size.py +222 -0
  121. pydeno-0.4.0/tests/test_timeout_overhead.py +155 -0
  122. pydeno-0.4.0/tests/test_tool_bridge.py +538 -0
  123. pydeno-0.4.0/tests/test_vendored_bundle_execution.py +697 -0
  124. pydeno-0.4.0/uv.lock +3786 -0
  125. pydeno-0.4.0/vendor/pptxgenjs/LICENSE +21 -0
  126. pydeno-0.4.0/vendor/pptxgenjs/README.md +49 -0
  127. pydeno-0.4.0/vendor/pptxgenjs/polyfills.js +175 -0
  128. pydeno-0.4.0/vendor/pptxgenjs/pptxgen.bundle.js +96 -0
@@ -0,0 +1,32 @@
1
+ name: Benchmarks
2
+
3
+ # Informational only -- reports numbers in the log/summary, never fails the build.
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ benchmarks:
14
+ # macos-latest: the Linux cdylib build currently fails to link V8 (rust-lld
15
+ # TLS relocation vs -shared, tracked separately, pre-existing/unrelated to
16
+ # benchmarking) -- same failure as the v0.1.0 Linux wheel build.
17
+ runs-on: macos-latest
18
+ steps:
19
+ - uses: actions/checkout@v5
20
+
21
+ - uses: astral-sh/setup-uv@v7
22
+
23
+ - name: Rust benchmarks (Criterion)
24
+ run: cargo bench --features bench | tee -a "$GITHUB_STEP_SUMMARY"
25
+
26
+ - name: Build release extension
27
+ run: |
28
+ uv sync --group all
29
+ uv run maturin develop --uv --release
30
+
31
+ - name: Python benchmarks (pytest-benchmark)
32
+ run: uv run pytest benches_py/ --benchmark-only | tee -a "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,58 @@
1
+ name: Documentation
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - "docs/**"
9
+ - "mkdocs.yml"
10
+ - "python/pydeno/**"
11
+ - ".github/workflows/docs.yml"
12
+ workflow_dispatch:
13
+
14
+ # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
15
+ permissions:
16
+ contents: read
17
+ pages: write
18
+ id-token: write
19
+
20
+ # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
21
+ # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
22
+ concurrency:
23
+ group: "pages"
24
+ cancel-in-progress: false
25
+
26
+ jobs:
27
+ build:
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v5
31
+
32
+ - uses: actions/setup-python@v6
33
+ with:
34
+ python-version: "3.x"
35
+
36
+ - uses: astral-sh/setup-uv@v7
37
+
38
+ - name: Install dependencies
39
+ run: uv sync --no-install-project --group docs
40
+
41
+ - name: Build documentation
42
+ run: source .venv/bin/activate && mkdocs build
43
+
44
+ - name: Upload artifact
45
+ uses: actions/upload-pages-artifact@v4
46
+ with:
47
+ path: ./site
48
+
49
+ deploy:
50
+ environment:
51
+ name: github-pages
52
+ url: ${{ steps.deployment.outputs.page_url }}
53
+ runs-on: ubuntu-latest
54
+ needs: build
55
+ steps:
56
+ - name: Deploy to GitHub Pages
57
+ id: deployment
58
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,229 @@
1
+ name: Tests
2
+
3
+ # The first workflow in this repo that actually runs the test suite. Before
4
+ # this, `.github/workflows/` held only publish-on-release, benchmarks and
5
+ # docs, so every "the tests pass" claim was local and unverified.
6
+ on:
7
+ push:
8
+ pull_request:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: tests-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ env:
18
+ # A `>=` floor on the collected test count, not an equality check: adding
19
+ # tests never needs a bump here, only deleting them does. This is the
20
+ # assertion that makes a mass-skip fail the job -- see
21
+ # `scripts/check_test_report.py` for the full rationale.
22
+ MIN_PYTHON_TESTS: "553"
23
+ # Skips are unverified tests, so the budget is zero. The suite has exactly
24
+ # one conditional skip (`tests/test_idle_cpu.py`, skipped above 16 CPUs) and
25
+ # GitHub's macOS runners are well under that, so zero is correct here. Every
26
+ # skip is printed with its reason regardless, so a new one is visible before
27
+ # anyone tolerates it.
28
+ MAX_SKIPPED: "0"
29
+ CARGO_TERM_COLOR: always
30
+
31
+ jobs:
32
+ # Debug and release are separate jobs on purpose. The library's headline
33
+ # invariant -- guest JS gets a result or a catchable exception, never a host
34
+ # crash -- silently depended on `-O` shrinking the recursive serializer's
35
+ # stack frames: `rt.eval("[" * 80 + "]" * 80)` killed the process on a debug
36
+ # build and was refused cleanly on a release build. A release-only CI job
37
+ # cannot see that class of bug at all.
38
+ pytest:
39
+ name: pytest (${{ matrix.profile }})
40
+ # macos-latest, matching `benchmarks.yml`: the Linux cdylib build currently
41
+ # fails to link V8 (rust-lld TLS relocation vs `-shared`), a pre-existing
42
+ # issue tracked separately. Moving these jobs to Linux is a follow-up, and
43
+ # would want a `manylinux: 2_28` container -- the pinned `deno_core`'s V8
44
+ # needs glibc >= 2.27.
45
+ #
46
+ # State this plainly, because it is the largest remaining hole in the
47
+ # verification story: `workflow.yaml` publishes `manylinux_2_28` wheels
48
+ # that **no CI job ever imports, let alone tests**. The wheel is built in
49
+ # maturin-action's container (which does link), so what is missing is not
50
+ # the build but a job that installs the built wheel and runs `pytest`
51
+ # against it. Until that exists, every Linux claim in this repo rests on
52
+ # the container producing a wheel, not on anything having run it.
53
+ runs-on: macos-latest
54
+ strategy:
55
+ fail-fast: false
56
+ matrix:
57
+ include:
58
+ - profile: debug
59
+ maturin_args: ""
60
+ - profile: release
61
+ maturin_args: "--release"
62
+ steps:
63
+ - uses: actions/checkout@v5
64
+
65
+ - uses: astral-sh/setup-uv@v7
66
+ with:
67
+ enable-cache: true
68
+
69
+ - uses: Swatinem/rust-cache@v2
70
+ with:
71
+ key: ${{ matrix.profile }}
72
+
73
+ - name: Build the extension (${{ matrix.profile }})
74
+ run: |
75
+ uv sync --frozen --group all
76
+ uv run maturin develop --uv ${{ matrix.maturin_args }}
77
+
78
+ # Collection is a separate step so a collection error (which removes
79
+ # every test in the offending file) fails the job on its own exit code,
80
+ # before anything has had a chance to look green.
81
+ - name: Collect tests
82
+ run: |
83
+ uv run python -m pytest tests/ --co -q \
84
+ -p no:randomly --strict-markers --strict-config \
85
+ | tee collect-${{ matrix.profile }}.log
86
+
87
+ - name: Run pytest
88
+ # `continue-on-error` is deliberate: a red suite must still reach the
89
+ # report check below, which is what turns "the process died at test 46"
90
+ # into a legible error instead of a bare exit code.
91
+ continue-on-error: true
92
+ id: pytest
93
+ run: |
94
+ uv run python -m pytest tests/ -v \
95
+ -p no:randomly --strict-markers --strict-config \
96
+ --junitxml=junit-${{ matrix.profile }}.xml
97
+
98
+ - name: Check the test report for skipped or unrun tests
99
+ run: |
100
+ uv run python scripts/check_test_report.py \
101
+ --label "pytest ${{ matrix.profile }}" \
102
+ --junit junit-${{ matrix.profile }}.xml \
103
+ --collect-log collect-${{ matrix.profile }}.log \
104
+ --min-tests "$MIN_PYTHON_TESTS" \
105
+ --max-skipped "$MAX_SKIPPED"
106
+
107
+ - name: Fail if pytest itself failed
108
+ if: steps.pytest.outcome != 'success'
109
+ run: |
110
+ echo "::error::pytest exited non-zero in the ${{ matrix.profile }} profile"
111
+ exit 1
112
+
113
+ # Closes the gap the `pytest` job's comment above states plainly:
114
+ # `workflow.yaml` publishes `manylinux_2_28` wheels that no CI job ever
115
+ # imported, let alone tested. This job builds that exact wheel (same
116
+ # `manylinux: 2_28` as `workflow.yaml`) and actually installs + imports +
117
+ # tests it on Linux, instead of resting every Linux claim on "the
118
+ # container produced a wheel".
119
+ pytest-linux-wheel:
120
+ name: pytest (linux wheel)
121
+ runs-on: ubuntu-latest
122
+ steps:
123
+ - uses: actions/checkout@v5
124
+
125
+ - uses: astral-sh/setup-uv@v7
126
+ with:
127
+ enable-cache: true
128
+
129
+ - uses: Swatinem/rust-cache@v2
130
+ with:
131
+ key: linux-wheel
132
+
133
+ - name: Build a manylinux_2_28 wheel
134
+ uses: PyO3/maturin-action@v1
135
+ with:
136
+ args: --release --out dist --find-interpreter
137
+ manylinux: 2_28
138
+
139
+ - name: Install the built wheel (not the editable dev build)
140
+ run: |
141
+ uv venv .wheel-venv
142
+ # `--find-interpreter` builds one wheel per CPython minor found in
143
+ # the manylinux container (cp310..cp313), so `dist/*.whl` expands to
144
+ # several and `uv pip install` refuses them: "Requirements contain
145
+ # conflicting URLs for package `pydeno`". Install only the wheel
146
+ # whose ABI tag matches this venv's interpreter.
147
+ PYTAG=$(.wheel-venv/bin/python -c \
148
+ 'import sys; print("cp%d%d" % sys.version_info[:2])')
149
+ WHEEL=$(ls dist/*-${PYTAG}-${PYTAG}-*.whl)
150
+ echo "Installing $WHEEL into a $PYTAG venv"
151
+ uv pip install --python .wheel-venv/bin/python "$WHEEL"
152
+ # Matches the `testing` dependency group in pyproject.toml -- the
153
+ # test *runner's* deps, deliberately installed on top of the built
154
+ # wheel rather than an editable `maturin develop` install.
155
+ uv pip install --python .wheel-venv/bin/python \
156
+ "pytest>=8.4.0" "pytest-asyncio>=1.2.0" "hypothesis>=6.100.0"
157
+
158
+ # Same collection-first-then-run-then-check shape as the macOS jobs, so
159
+ # a collection error or a mass-skip fails this job exactly as loudly.
160
+ - name: Collect tests
161
+ run: |
162
+ .wheel-venv/bin/python -m pytest tests/ --co -q \
163
+ -p no:randomly --strict-markers --strict-config \
164
+ | tee collect-linux-wheel.log
165
+
166
+ - name: Run pytest against the installed wheel
167
+ continue-on-error: true
168
+ id: pytest
169
+ run: |
170
+ .wheel-venv/bin/python -m pytest tests/ -v \
171
+ -p no:randomly --strict-markers --strict-config \
172
+ --junitxml=junit-linux-wheel.xml
173
+
174
+ - name: Check the test report for skipped or unrun tests
175
+ run: |
176
+ uv run python scripts/check_test_report.py \
177
+ --label "pytest linux-wheel" \
178
+ --junit junit-linux-wheel.xml \
179
+ --collect-log collect-linux-wheel.log \
180
+ --min-tests "$MIN_PYTHON_TESTS" \
181
+ --max-skipped "$MAX_SKIPPED"
182
+
183
+ - name: Fail if pytest itself failed
184
+ if: steps.pytest.outcome != 'success'
185
+ run: |
186
+ echo "::error::pytest exited non-zero against the installed linux wheel"
187
+ exit 1
188
+
189
+ cargo-test:
190
+ name: cargo test
191
+ runs-on: macos-latest
192
+ steps:
193
+ - uses: actions/checkout@v5
194
+ - uses: Swatinem/rust-cache@v2
195
+
196
+ # `--test-threads=1` is this repo's convention: several tests share
197
+ # process-global V8 platform state, and the Rust suite is not safe to
198
+ # interleave.
199
+ - name: cargo test
200
+ run: cargo test --release --features bench -- --test-threads=1
201
+
202
+ lint:
203
+ name: lint
204
+ runs-on: macos-latest
205
+ steps:
206
+ - uses: actions/checkout@v5
207
+ - uses: astral-sh/setup-uv@v7
208
+ with:
209
+ enable-cache: true
210
+ - uses: Swatinem/rust-cache@v2
211
+
212
+ - name: cargo fmt
213
+ run: cargo fmt --all -- --check
214
+
215
+ - name: cargo clippy
216
+ run: cargo clippy --tests -- -D warnings
217
+
218
+ # Pinned. `uv tool run ruff` resolves the newest release at job time, so
219
+ # an unpinned lint step turns every upstream ruff release into a red
220
+ # build that nobody in this repo caused: 0.16 widened the default rule
221
+ # selection and reports 248 findings (I001, PYI048, PIE790, SIM117, ...)
222
+ # against `main` @ 400e3cb, none of them regressions. Bumping the pin is
223
+ # then a deliberate commit that clears the new rules, which is what a
224
+ # lint gate is for.
225
+ - name: ruff check
226
+ run: uv tool run ruff@0.15.10 check python/pydeno tests scripts
227
+
228
+ - name: ruff format
229
+ run: uv tool run ruff@0.15.10 format --check python/pydeno tests scripts
@@ -0,0 +1,127 @@
1
+ name: Publish to PyPI
2
+
3
+ # Runs only when a GitHub Release is published -- never on every push.
4
+ # Actually publishing requires PyPI Trusted Publishing to be configured for
5
+ # this exact repo + workflow on the PyPI project page first (see README).
6
+ on:
7
+ release:
8
+ types: [published]
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ linux:
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ matrix:
18
+ target: [x86_64]
19
+ steps:
20
+ - uses: actions/checkout@v5
21
+ - name: Build manylinux wheels
22
+ uses: PyO3/maturin-action@v1
23
+ with:
24
+ target: ${{ matrix.target }}
25
+ args: --release --out dist --find-interpreter
26
+ # v8 >=150.1 (pulled in via deno_core >=0.409, see Cargo.toml) needs
27
+ # glibc's memfd_create (glibc >=2.27), which manylinux2014's glibc
28
+ # 2.17 lacks ("auto" resolved to manylinux2014 and the resulting
29
+ # wheel failed to import: "undefined symbol: memfd_create").
30
+ # manylinux_2_28 ships glibc 2.28.
31
+ manylinux: 2_28
32
+ - uses: actions/upload-artifact@v4
33
+ with:
34
+ name: wheels-linux-${{ matrix.target }}
35
+ path: dist
36
+
37
+ macos:
38
+ runs-on: macos-latest
39
+ steps:
40
+ - uses: actions/checkout@v5
41
+ - uses: PyO3/maturin-action@v1
42
+ with:
43
+ args: --release --out dist --find-interpreter
44
+ - uses: actions/upload-artifact@v4
45
+ with:
46
+ name: wheels-macos
47
+ path: dist
48
+
49
+ windows:
50
+ runs-on: windows-latest
51
+ steps:
52
+ - uses: actions/checkout@v5
53
+ - uses: PyO3/maturin-action@v1
54
+ with:
55
+ args: --release --out dist --find-interpreter
56
+ - uses: actions/upload-artifact@v4
57
+ with:
58
+ name: wheels-windows
59
+ path: dist
60
+
61
+ sdist:
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - uses: actions/checkout@v5
65
+ - uses: PyO3/maturin-action@v1
66
+ with:
67
+ command: sdist
68
+ args: --out dist
69
+ - uses: actions/upload-artifact@v4
70
+ with:
71
+ name: wheels-sdist
72
+ path: dist
73
+
74
+ # `test.yml`'s `pytest-linux-wheel` job runs this same check on every
75
+ # push/PR, but a `needs:` dependency only works within one workflow file,
76
+ # so a release can't lean on that job directly. This job re-runs the same
77
+ # gate -- install the manylinux_2_28 wheel this release is about to
78
+ # publish and actually `import`+test it -- against the artifact the
79
+ # `linux` job above just built, so `publish` cannot ship a wheel that was
80
+ # never installed anywhere.
81
+ test-linux-wheel:
82
+ name: Test the linux wheel before publishing
83
+ needs: [linux]
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/checkout@v5
87
+ - uses: astral-sh/setup-uv@v7
88
+ with:
89
+ enable-cache: true
90
+ - uses: actions/download-artifact@v6
91
+ with:
92
+ name: wheels-linux-x86_64
93
+ path: dist
94
+ - name: Install the wheel and run the suite against it
95
+ run: |
96
+ uv venv .wheel-venv
97
+ # Same as `test.yml`'s `pytest-linux-wheel`: the `linux` job's
98
+ # `--find-interpreter` produces one wheel per CPython minor, so a
99
+ # bare `dist/*.whl` is a multi-wheel glob that `uv pip install`
100
+ # rejects. Pick the one matching this venv's ABI tag.
101
+ PYTAG=$(.wheel-venv/bin/python -c \
102
+ 'import sys; print("cp%d%d" % sys.version_info[:2])')
103
+ WHEEL=$(ls dist/*-${PYTAG}-${PYTAG}-*.whl)
104
+ echo "Installing $WHEEL into a $PYTAG venv"
105
+ uv pip install --python .wheel-venv/bin/python "$WHEEL"
106
+ uv pip install --python .wheel-venv/bin/python \
107
+ "pytest>=8.4.0" "pytest-asyncio>=1.2.0" "hypothesis>=6.100.0"
108
+ .wheel-venv/bin/python -m pytest tests/ -q \
109
+ -p no:randomly --strict-markers --strict-config
110
+
111
+ publish:
112
+ name: Publish to PyPI (Trusted Publishing)
113
+ needs: [linux, macos, windows, sdist, test-linux-wheel]
114
+ runs-on: ubuntu-latest
115
+ environment:
116
+ name: pypi
117
+ url: https://pypi.org/p/pydeno
118
+ permissions:
119
+ id-token: write # required for PyPI Trusted Publishing (OIDC) -- no API token secret needed
120
+ steps:
121
+ - uses: actions/download-artifact@v6
122
+ with:
123
+ pattern: wheels-*
124
+ path: dist
125
+ merge-multiple: true
126
+ - name: Publish
127
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,80 @@
1
+ /target
2
+
3
+ # Byte-compiled / optimized / DLL files
4
+ __pycache__/
5
+ .pytest_cache/
6
+ *.py[cod]
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ .venv/
14
+ env/
15
+ bin/
16
+ build/
17
+ develop-eggs/
18
+ dist/
19
+ eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ include/
26
+ man/
27
+ venv/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+
32
+ # Installer logs
33
+ pip-log.txt
34
+ pip-delete-this-directory.txt
35
+ pip-selfcheck.json
36
+
37
+ # Unit test / coverage reports
38
+ htmlcov/
39
+ .tox/
40
+ .coverage
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+
45
+ # Translations
46
+ *.mo
47
+
48
+ # Mr Developer
49
+ .mr.developer.cfg
50
+ .project
51
+ .pydevproject
52
+
53
+ # Rope
54
+ .ropeproject
55
+
56
+ # Django stuff:
57
+ *.log
58
+ *.pot
59
+
60
+ .DS_Store
61
+
62
+ # Sphinx documentation
63
+ docs/_build/
64
+
65
+ # mkdocs build output
66
+ site/
67
+
68
+ # Tool caches
69
+ .ruff_cache/
70
+ .hypothesis/
71
+ .benchmarks/
72
+
73
+ # PyCharm
74
+ .idea/
75
+
76
+ # VSCode
77
+ .vscode/
78
+
79
+ # Pyenv
80
+ .python-version