pypiron 0.0.2__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 (95) hide show
  1. pypiron-0.0.2/.dockerignore +28 -0
  2. pypiron-0.0.2/.github/stamp-version.sh +21 -0
  3. pypiron-0.0.2/.github/workflows/ci.yml +373 -0
  4. pypiron-0.0.2/.github/workflows/docker.yml +166 -0
  5. pypiron-0.0.2/.gitignore +35 -0
  6. pypiron-0.0.2/AGENTS.md +44 -0
  7. pypiron-0.0.2/CLAUDE.md +1 -0
  8. pypiron-0.0.2/Cargo.lock +3553 -0
  9. pypiron-0.0.2/Cargo.toml +58 -0
  10. pypiron-0.0.2/Dockerfile +39 -0
  11. pypiron-0.0.2/LICENSE +9 -0
  12. pypiron-0.0.2/Makefile +77 -0
  13. pypiron-0.0.2/PKG-INFO +197 -0
  14. pypiron-0.0.2/README.md +172 -0
  15. pypiron-0.0.2/RELEASE.md +52 -0
  16. pypiron-0.0.2/bench/aws-down.sh +39 -0
  17. pypiron-0.0.2/bench/aws-up.sh +114 -0
  18. pypiron-0.0.2/bench/deploy.sh +83 -0
  19. pypiron-0.0.2/bench/meter.py +587 -0
  20. pypiron-0.0.2/bench/msync.sh +71 -0
  21. pypiron-0.0.2/bench/phase3.py +143 -0
  22. pypiron-0.0.2/bench/run-baseline.sh +34 -0
  23. pypiron-0.0.2/bench/s3_cas_validate.py +233 -0
  24. pypiron-0.0.2/bench/s3_scale_measure.py +276 -0
  25. pypiron-0.0.2/bench/s3_upload_during_steady.py +114 -0
  26. pypiron-0.0.2/bench/scale.py +349 -0
  27. pypiron-0.0.2/bench/seed_s3.py +98 -0
  28. pypiron-0.0.2/bench/server-ctl.sh +60 -0
  29. pypiron-0.0.2/bench/tier2.py +147 -0
  30. pypiron-0.0.2/docs/BENCHMARKS.md +198 -0
  31. pypiron-0.0.2/docs/BENCHMARK_RESULTS.md +493 -0
  32. pypiron-0.0.2/docs/COMPATIBILITY.md +32 -0
  33. pypiron-0.0.2/docs/CONFIGURATION.md +188 -0
  34. pypiron-0.0.2/docs/DESIGN.md +336 -0
  35. pypiron-0.0.2/docs/ROADMAP.md +113 -0
  36. pypiron-0.0.2/docs/SECURITY_AUDIT.md +149 -0
  37. pypiron-0.0.2/docs/STANDARDS.md +58 -0
  38. pypiron-0.0.2/docs/TESTING.md +91 -0
  39. pypiron-0.0.2/docs/VISION.md +15 -0
  40. pypiron-0.0.2/docs/pypiron-logo-256.png +0 -0
  41. pypiron-0.0.2/docs/pypiron-logo.png +0 -0
  42. pypiron-0.0.2/pyproject.toml +64 -0
  43. pypiron-0.0.2/scripts/transform_readme.py +78 -0
  44. pypiron-0.0.2/src/cache.rs +527 -0
  45. pypiron-0.0.2/src/config.rs +117 -0
  46. pypiron-0.0.2/src/corpus_check.rs +290 -0
  47. pypiron-0.0.2/src/lease.rs +185 -0
  48. pypiron-0.0.2/src/main.rs +1884 -0
  49. pypiron-0.0.2/src/metrics.rs +306 -0
  50. pypiron-0.0.2/src/names.rs +277 -0
  51. pypiron-0.0.2/src/origin.rs +75 -0
  52. pypiron-0.0.2/src/proxy.rs +689 -0
  53. pypiron-0.0.2/src/render.rs +326 -0
  54. pypiron-0.0.2/src/sidecar.rs +96 -0
  55. pypiron-0.0.2/src/storage.rs +1445 -0
  56. pypiron-0.0.2/src/sync.rs +948 -0
  57. pypiron-0.0.2/src/upload.rs +125 -0
  58. pypiron-0.0.2/src/verify.rs +263 -0
  59. pypiron-0.0.2/src/wheel.rs +100 -0
  60. pypiron-0.0.2/src/worker.rs +1217 -0
  61. pypiron-0.0.2/tests/__init__.py +0 -0
  62. pypiron-0.0.2/tests/conftest.py +631 -0
  63. pypiron-0.0.2/tests/helpers.py +547 -0
  64. pypiron-0.0.2/tests/test_auth.py +119 -0
  65. pypiron-0.0.2/tests/test_caching.py +99 -0
  66. pypiron-0.0.2/tests/test_compat_pdm.py +144 -0
  67. pypiron-0.0.2/tests/test_compat_pip.py +119 -0
  68. pypiron-0.0.2/tests/test_compat_poetry.py +167 -0
  69. pypiron-0.0.2/tests/test_compat_publishers.py +89 -0
  70. pypiron-0.0.2/tests/test_crash_consistency.py +639 -0
  71. pypiron-0.0.2/tests/test_dirty_markers.py +62 -0
  72. pypiron-0.0.2/tests/test_exclude_newer.py +93 -0
  73. pypiron-0.0.2/tests/test_immutability.py +31 -0
  74. pypiron-0.0.2/tests/test_leader.py +61 -0
  75. pypiron-0.0.2/tests/test_observability.py +128 -0
  76. pypiron-0.0.2/tests/test_origin.py +127 -0
  77. pypiron-0.0.2/tests/test_pep658.py +99 -0
  78. pypiron-0.0.2/tests/test_perf.py +50 -0
  79. pypiron-0.0.2/tests/test_presigned.py +152 -0
  80. pypiron-0.0.2/tests/test_proxy.py +153 -0
  81. pypiron-0.0.2/tests/test_read_auth.py +113 -0
  82. pypiron-0.0.2/tests/test_reconciler.py +76 -0
  83. pypiron-0.0.2/tests/test_redirects.py +40 -0
  84. pypiron-0.0.2/tests/test_roundtrip.py +85 -0
  85. pypiron-0.0.2/tests/test_scale.py +71 -0
  86. pypiron-0.0.2/tests/test_sidecars.py +152 -0
  87. pypiron-0.0.2/tests/test_standards.py +116 -0
  88. pypiron-0.0.2/tests/test_sync.py +159 -0
  89. pypiron-0.0.2/tests/test_sync_filters.py +263 -0
  90. pypiron-0.0.2/tests/test_sync_http.py +210 -0
  91. pypiron-0.0.2/tests/test_sync_retry.py +117 -0
  92. pypiron-0.0.2/tests/test_sync_uploads.py +50 -0
  93. pypiron-0.0.2/tests/test_tools.py +58 -0
  94. pypiron-0.0.2/tests/test_yank_delete.py +154 -0
  95. pypiron-0.0.2/uv.lock +1234 -0
@@ -0,0 +1,28 @@
1
+ # Keep the build context tiny: only Rust sources feed `cargo build`.
2
+ # Everything here is either rebuilt, irrelevant to the binary, or bulky.
3
+ target/
4
+ .git/
5
+ .github/
6
+ docs/
7
+ tests/
8
+ bench/
9
+ fuzz/
10
+ data/
11
+ dist/
12
+ downloaded/
13
+ pypiron-data/
14
+ .venv/
15
+ .test-venv/
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .claude/
19
+ .cargo/
20
+ *.whl
21
+ *.tar.gz
22
+ **/__pycache__/
23
+ *.pyc
24
+ .DS_Store
25
+ pyproject.toml
26
+ uv.lock
27
+ README.md
28
+ RELEASE.md
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ # Stamp a release-tag version (vX.Y.Z) into Cargo.toml and Cargo.lock.
3
+ # The repo permanently carries version 0.0.0; CI runs this before building wheels.
4
+ set -euo pipefail
5
+
6
+ TAG="${1:?usage: stamp-version.sh vX.Y.Z}"
7
+ [[ "$TAG" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]] || {
8
+ echo "release tag must be vX.Y.Z, got: $TAG" >&2
9
+ exit 1
10
+ }
11
+ V="${BASH_REMATCH[1]}"
12
+
13
+ # No trailing $ anchors: tolerate CRLF checkouts on Windows runners.
14
+ sed -i.bak "s/^version = \"0.0.0\"/version = \"$V\"/" Cargo.toml
15
+ # Cargo.lock pins pypiron's own version; stamp it too so --locked builds (e.g. from sdist) work.
16
+ sed -i.bak -e '/^name = "pypiron"/{' -e n -e "s/^version = \"0.0.0\"/version = \"$V\"/" -e '}' Cargo.lock
17
+ rm -f Cargo.toml.bak Cargo.lock.bak
18
+
19
+ grep -q "^version = \"$V\"" Cargo.toml || { echo "failed to stamp Cargo.toml" >&2; exit 1; }
20
+ grep -A1 '^name = "pypiron"' Cargo.lock | grep -q "^version = \"$V\"" || { echo "failed to stamp Cargo.lock" >&2; exit 1; }
21
+ echo "stamped version $V"
@@ -0,0 +1,373 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - main
8
+ tags:
9
+ - 'v*'
10
+ pull_request:
11
+ branches:
12
+ - master
13
+ - main
14
+ workflow_dispatch:
15
+
16
+ env:
17
+ CARGO_TERM_COLOR: always
18
+
19
+ permissions:
20
+ contents: read
21
+
22
+ concurrency:
23
+ group: ${{ github.workflow }}-${{ github.ref }}
24
+ cancel-in-progress: true
25
+
26
+ jobs:
27
+ fmt:
28
+ name: rustfmt
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
32
+ with:
33
+ persist-credentials: false
34
+ - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
35
+ with:
36
+ components: rustfmt, clippy
37
+ - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
38
+ - name: Check formatting
39
+ run: cargo fmt --all -- --check
40
+
41
+ clippy:
42
+ name: clippy (lint)
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
46
+ with:
47
+ persist-credentials: false
48
+ - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
49
+ with:
50
+ components: clippy, rustfmt
51
+ - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
52
+ - name: Clippy (fail on warnings)
53
+ run: cargo clippy --workspace --all-targets --all-features -- -D warnings
54
+
55
+ test:
56
+ name: tests
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
60
+ with:
61
+ persist-credentials: false
62
+ - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
63
+ with:
64
+ components: clippy, rustfmt
65
+ - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
66
+ - name: Unit tests
67
+ run: cargo test --workspace --all-features --locked
68
+
69
+ integration:
70
+ name: blackbox integration
71
+ runs-on: ubuntu-latest
72
+ timeout-minutes: 25
73
+ steps:
74
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
75
+ with:
76
+ persist-credentials: false
77
+ - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
78
+ - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
79
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
80
+ - name: Sync dev dependencies
81
+ run: uv sync
82
+ # The product's center of gravity is the blackbox suite (docs/TESTING.md):
83
+ # the real binary driven over HTTP by real uv/pip clients. S3/MinIO tests
84
+ # skip without Docker; the multi-client compat matrix (poetry/pdm/flit/
85
+ # hatch via uvx) stays a local `make compat` concern, not a merge gate.
86
+ - name: Blackbox suite (disk mode)
87
+ run: uv run -- pytest tests -m "not perf and not stress and not compat"
88
+
89
+ fuzz-build:
90
+ name: fuzz build (smoke)
91
+ runs-on: ubuntu-latest
92
+ timeout-minutes: 20
93
+ steps:
94
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
95
+ with:
96
+ persist-credentials: false
97
+ - uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
98
+ - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
99
+ - uses: taiki-e/install-action@b8cecb83565409bcc297b2df6e77f030b2a468d5 # v2.82.0
100
+ with:
101
+ tool: cargo-fuzz
102
+ # Keep the fuzz targets compiling. Coverage-guided runs stay manual
103
+ # (`make fuzz`); this only guards against bitrot in the harness.
104
+ - name: Compile all fuzz targets
105
+ # Pin the gnu host target: recent cargo-fuzz defaults to musl even on a
106
+ # gnu host, and musl's static libc is incompatible with ASan.
107
+ # https://github.com/rust-fuzz/cargo-fuzz/issues/398
108
+ run: cargo fuzz build --target x86_64-unknown-linux-gnu
109
+
110
+ build-release:
111
+ # Build release binaries on pushes to master/main (not on PRs)
112
+ if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main')
113
+ name: build release (${{ matrix.os }})
114
+ runs-on: ${{ matrix.os }}
115
+ needs: [fmt, clippy, test]
116
+ strategy:
117
+ fail-fast: false
118
+ matrix:
119
+ os: [ ubuntu-latest, macos-latest, windows-latest ]
120
+ steps:
121
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
122
+ with:
123
+ persist-credentials: false
124
+ - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
125
+ - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
126
+
127
+ - name: Build (release)
128
+ run: cargo build --release --locked
129
+
130
+ # Upload the built binary as an artifact per-OS.
131
+ - name: Upload artifact (Linux/macOS)
132
+ if: runner.os != 'Windows'
133
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
134
+ with:
135
+ name: pypiron-${{ runner.os }}-${{ github.sha }}
136
+ path: target/release/pypiron
137
+ retention-days: 14
138
+
139
+ - name: Upload artifact (Windows)
140
+ if: runner.os == 'Windows'
141
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
142
+ with:
143
+ name: pypiron-${{ runner.os }}-${{ github.sha }}
144
+ path: target\release\pypiron.exe
145
+ retention-days: 14
146
+
147
+ # Wheel builds run only for release tags (and manual dispatch for testing the
148
+ # pipeline). The version is stamped from the tag; the repo itself stays at 0.0.0.
149
+ linux:
150
+ if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
151
+ runs-on: ${{ matrix.platform.runner }}
152
+ strategy:
153
+ matrix:
154
+ platform:
155
+ - runner: ubuntu-22.04
156
+ target: x86_64
157
+ - runner: ubuntu-22.04
158
+ target: x86
159
+ - runner: ubuntu-22.04
160
+ target: aarch64
161
+ - runner: ubuntu-22.04
162
+ target: armv7
163
+ - runner: ubuntu-22.04
164
+ target: s390x
165
+ - runner: ubuntu-22.04
166
+ target: ppc64le
167
+ - runner: ubuntu-22.04
168
+ target: riscv64
169
+ steps:
170
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
171
+ with:
172
+ persist-credentials: false
173
+ - name: Stamp version from tag
174
+ if: startsWith(github.ref, 'refs/tags/')
175
+ shell: bash
176
+ run: ./.github/stamp-version.sh "$GITHUB_REF_NAME"
177
+ # Make the README baked into the wheel/sdist metadata render on PyPI:
178
+ # rewrite its repo-relative links/logo to absolute URLs (pinned to the
179
+ # stamped tag). The committed file stays GitHub-relative.
180
+ - name: Rewrite README links to absolute URLs for PyPI
181
+ shell: bash
182
+ run: command -v python3 >/dev/null 2>&1 && python3 scripts/transform_readme.py --target pypi || python scripts/transform_readme.py --target pypi
183
+ - name: Build wheels
184
+ uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
185
+ with:
186
+ target: ${{ matrix.platform.target }}
187
+ args: --release --locked --out dist
188
+ sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
189
+ manylinux: auto
190
+ env:
191
+ CFLAGS_aarch64_unknown_linux_gnu: "-D__ARM_ARCH=8"
192
+ - name: Upload wheels
193
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
194
+ with:
195
+ name: wheels-linux-${{ matrix.platform.target }}
196
+ path: dist
197
+
198
+ musllinux:
199
+ if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
200
+ runs-on: ${{ matrix.platform.runner }}
201
+ strategy:
202
+ matrix:
203
+ platform:
204
+ - runner: ubuntu-22.04
205
+ target: x86_64
206
+ - runner: ubuntu-22.04
207
+ target: x86
208
+ - runner: ubuntu-22.04
209
+ target: aarch64
210
+ - runner: ubuntu-22.04
211
+ target: armv7
212
+ steps:
213
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
214
+ with:
215
+ persist-credentials: false
216
+ - name: Stamp version from tag
217
+ if: startsWith(github.ref, 'refs/tags/')
218
+ shell: bash
219
+ run: ./.github/stamp-version.sh "$GITHUB_REF_NAME"
220
+ # Make the README baked into the wheel/sdist metadata render on PyPI:
221
+ # rewrite its repo-relative links/logo to absolute URLs (pinned to the
222
+ # stamped tag). The committed file stays GitHub-relative.
223
+ - name: Rewrite README links to absolute URLs for PyPI
224
+ shell: bash
225
+ run: command -v python3 >/dev/null 2>&1 && python3 scripts/transform_readme.py --target pypi || python scripts/transform_readme.py --target pypi
226
+ - name: Build wheels
227
+ uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
228
+ with:
229
+ target: ${{ matrix.platform.target }}
230
+ args: --release --locked --out dist
231
+ sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
232
+ manylinux: musllinux_1_2
233
+ env:
234
+ CFLAGS_aarch64_unknown_linux_gnu: "-D__ARM_ARCH=8"
235
+ - name: Upload wheels
236
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
237
+ with:
238
+ name: wheels-musllinux-${{ matrix.platform.target }}
239
+ path: dist
240
+
241
+ windows:
242
+ if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
243
+ runs-on: ${{ matrix.platform.runner }}
244
+ strategy:
245
+ matrix:
246
+ platform:
247
+ - runner: windows-latest
248
+ target: x64
249
+ - runner: windows-latest
250
+ target: x86
251
+ - runner: windows-latest
252
+ target: aarch64
253
+ steps:
254
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
255
+ with:
256
+ persist-credentials: false
257
+ - name: Stamp version from tag
258
+ if: startsWith(github.ref, 'refs/tags/')
259
+ shell: bash
260
+ run: ./.github/stamp-version.sh "$GITHUB_REF_NAME"
261
+ # Make the README baked into the wheel/sdist metadata render on PyPI:
262
+ # rewrite its repo-relative links/logo to absolute URLs (pinned to the
263
+ # stamped tag). The committed file stays GitHub-relative.
264
+ - name: Rewrite README links to absolute URLs for PyPI
265
+ shell: bash
266
+ run: command -v python3 >/dev/null 2>&1 && python3 scripts/transform_readme.py --target pypi || python scripts/transform_readme.py --target pypi
267
+ - name: Build wheels
268
+ uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
269
+ with:
270
+ target: ${{ matrix.platform.target }}
271
+ args: --release --locked --out dist
272
+ sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
273
+ - name: Upload wheels
274
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
275
+ with:
276
+ name: wheels-windows-${{ matrix.platform.target }}
277
+ path: dist
278
+
279
+ macos:
280
+ if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
281
+ runs-on: ${{ matrix.platform.runner }}
282
+ strategy:
283
+ matrix:
284
+ platform:
285
+ # GitHub retired the macos-13 (Intel) image on 2025-12-04; macos-15-intel
286
+ # is its standard x86_64 replacement (last Intel image, supported to ~2027-08).
287
+ - runner: macos-15-intel
288
+ target: x86_64
289
+ - runner: macos-14
290
+ target: aarch64
291
+ steps:
292
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
293
+ with:
294
+ persist-credentials: false
295
+ - name: Stamp version from tag
296
+ if: startsWith(github.ref, 'refs/tags/')
297
+ shell: bash
298
+ run: ./.github/stamp-version.sh "$GITHUB_REF_NAME"
299
+ # Make the README baked into the wheel/sdist metadata render on PyPI:
300
+ # rewrite its repo-relative links/logo to absolute URLs (pinned to the
301
+ # stamped tag). The committed file stays GitHub-relative.
302
+ - name: Rewrite README links to absolute URLs for PyPI
303
+ shell: bash
304
+ run: command -v python3 >/dev/null 2>&1 && python3 scripts/transform_readme.py --target pypi || python scripts/transform_readme.py --target pypi
305
+ - name: Build wheels
306
+ uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
307
+ with:
308
+ target: ${{ matrix.platform.target }}
309
+ args: --release --locked --out dist
310
+ sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
311
+ - name: Upload wheels
312
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
313
+ with:
314
+ name: wheels-macos-${{ matrix.platform.target }}
315
+ path: dist
316
+
317
+ sdist:
318
+ if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
319
+ runs-on: ubuntu-latest
320
+ steps:
321
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
322
+ with:
323
+ persist-credentials: false
324
+ - name: Stamp version from tag
325
+ if: startsWith(github.ref, 'refs/tags/')
326
+ shell: bash
327
+ run: ./.github/stamp-version.sh "$GITHUB_REF_NAME"
328
+ # Make the README baked into the wheel/sdist metadata render on PyPI:
329
+ # rewrite its repo-relative links/logo to absolute URLs (pinned to the
330
+ # stamped tag). The committed file stays GitHub-relative.
331
+ - name: Rewrite README links to absolute URLs for PyPI
332
+ shell: bash
333
+ run: command -v python3 >/dev/null 2>&1 && python3 scripts/transform_readme.py --target pypi || python scripts/transform_readme.py --target pypi
334
+ - name: Build sdist
335
+ uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
336
+ with:
337
+ command: sdist
338
+ args: --out dist
339
+ - name: Upload sdist
340
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
341
+ with:
342
+ name: wheels-sdist
343
+ path: dist
344
+
345
+ release:
346
+ name: Release
347
+ runs-on: ubuntu-latest
348
+ if: startsWith(github.ref, 'refs/tags/')
349
+ needs: [fmt, clippy, test, linux, musllinux, windows, macos, sdist]
350
+ permissions:
351
+ # Used for PyPI trusted publishing and to sign the release artifacts
352
+ id-token: write
353
+ # Used to upload release artifacts
354
+ contents: write
355
+ # Used to generate artifact attestation
356
+ attestations: write
357
+ steps:
358
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
359
+ with:
360
+ pattern: wheels-*
361
+ merge-multiple: true
362
+ path: dist
363
+ # Build-provenance attestation is a public-repo-only feature; skip it while
364
+ # the repo is private (it reactivates automatically once the repo is public).
365
+ - name: Generate artifact attestation
366
+ if: ${{ !github.event.repository.private }}
367
+ uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
368
+ with:
369
+ subject-path: 'dist/*'
370
+ - name: Publish to PyPI
371
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
372
+ with:
373
+ skip-existing: true
@@ -0,0 +1,166 @@
1
+ name: Docker
2
+
3
+ # Publishes multi-arch images to GHCR:
4
+ # ghcr.io/<owner>/pypiron:<branch> on pushes to master/main
5
+ # ghcr.io/<owner>/pypiron:X.Y.Z + :X.Y + :latest on vX.Y.Z tags
6
+ # plus a :sha-<short> tag on every push.
7
+ # Pull requests build (both arches) but never push, so the Dockerfile stays
8
+ # green without leaking images.
9
+ #
10
+ # Multi-arch is built one arch per native runner (amd64 + arm64), then stitched
11
+ # into a single manifest list with `imagetools create` — no QEMU, which would
12
+ # crawl for a from-scratch Rust release build. This is Docker's documented
13
+ # split-runner pattern: https://docs.docker.com/build/ci/github-actions/multi-platform/
14
+
15
+ on:
16
+ push:
17
+ branches: [master, main]
18
+ tags: ['v*']
19
+ pull_request:
20
+ branches: [master, main]
21
+ workflow_dispatch:
22
+
23
+ env:
24
+ REGISTRY: ghcr.io
25
+ IMAGE_NAME: ${{ github.repository }}
26
+
27
+ concurrency:
28
+ group: docker-${{ github.ref }}
29
+ cancel-in-progress: true
30
+
31
+ jobs:
32
+ build:
33
+ name: build (${{ matrix.platform.arch }})
34
+ runs-on: ${{ matrix.platform.runner }}
35
+ permissions:
36
+ contents: read
37
+ packages: write
38
+ strategy:
39
+ fail-fast: false
40
+ matrix:
41
+ platform:
42
+ - arch: amd64
43
+ runner: ubuntu-latest
44
+ - arch: arm64
45
+ runner: ubuntu-24.04-arm
46
+ steps:
47
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
48
+ with:
49
+ persist-credentials: false
50
+
51
+ # Tagged builds stamp the version so the binary's --version is correct.
52
+ - name: Stamp version from tag
53
+ if: startsWith(github.ref, 'refs/tags/')
54
+ shell: bash
55
+ run: ./.github/stamp-version.sh "$GITHUB_REF_NAME"
56
+
57
+ - name: Docker metadata (labels)
58
+ id: meta
59
+ uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
60
+ with:
61
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
62
+
63
+ - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
64
+
65
+ - name: Log in to ${{ env.REGISTRY }}
66
+ if: github.event_name != 'pull_request'
67
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
68
+ with:
69
+ registry: ${{ env.REGISTRY }}
70
+ username: ${{ github.actor }}
71
+ password: ${{ secrets.GITHUB_TOKEN }}
72
+
73
+ - name: Build and push by digest
74
+ id: build
75
+ uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
76
+ with:
77
+ context: .
78
+ platforms: linux/${{ matrix.platform.arch }}
79
+ labels: ${{ steps.meta.outputs.labels }}
80
+ cache-from: type=gha,scope=docker-${{ matrix.platform.arch }}
81
+ cache-to: type=gha,scope=docker-${{ matrix.platform.arch }},mode=max
82
+ # On PRs build only (push=false); the merge job is skipped there.
83
+ # Provenance off so each arch is a clean single manifest — the merge
84
+ # job re-attests the final manifest list.
85
+ provenance: false
86
+ outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
87
+
88
+ - name: Export digest
89
+ if: github.event_name != 'pull_request'
90
+ run: |
91
+ mkdir -p "${{ runner.temp }}/digests"
92
+ digest="${{ steps.build.outputs.digest }}"
93
+ touch "${{ runner.temp }}/digests/${digest#sha256:}"
94
+
95
+ - name: Upload digest
96
+ if: github.event_name != 'pull_request'
97
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
98
+ with:
99
+ name: digest-${{ matrix.platform.arch }}
100
+ path: ${{ runner.temp }}/digests/*
101
+ if-no-files-found: error
102
+ retention-days: 1
103
+
104
+ # merge:
105
+ # name: merge manifest & push tags
106
+ # if: github.event_name != 'pull_request'
107
+ # needs: build
108
+ # runs-on: ubuntu-latest
109
+ # permissions:
110
+ # contents: read
111
+ # packages: write
112
+ # id-token: write # provenance attestation
113
+ # attestations: write
114
+ # steps:
115
+ # - name: Download digests
116
+ # uses: actions/download-artifact@v4
117
+ # with:
118
+ # path: ${{ runner.temp }}/digests
119
+ # pattern: digest-*
120
+ # merge-multiple: true
121
+
122
+ # - uses: docker/setup-buildx-action@v3
123
+
124
+ # - name: Docker metadata (tags)
125
+ # id: meta
126
+ # uses: docker/metadata-action@v5
127
+ # with:
128
+ # images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
129
+ # tags: |
130
+ # type=semver,pattern={{version}}
131
+ # type=semver,pattern={{major}}.{{minor}}
132
+ # type=ref,event=branch
133
+ # type=sha,prefix=sha-
134
+ # flavor: |
135
+ # latest=auto
136
+
137
+ # - name: Log in to ${{ env.REGISTRY }}
138
+ # uses: docker/login-action@v3
139
+ # with:
140
+ # registry: ${{ env.REGISTRY }}
141
+ # username: ${{ github.actor }}
142
+ # password: ${{ secrets.GITHUB_TOKEN }}
143
+
144
+ # - name: Create manifest list and push
145
+ # id: manifest
146
+ # working-directory: ${{ runner.temp }}/digests
147
+ # run: |
148
+ # docker buildx imagetools create \
149
+ # $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
150
+ # $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
151
+ # digest=$(docker buildx imagetools inspect \
152
+ # "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}" \
153
+ # --format '{{json .Manifest.Digest}}' | tr -d '"')
154
+ # echo "digest=$digest" >> "$GITHUB_OUTPUT"
155
+
156
+ # - name: Inspect image
157
+ # run: |
158
+ # docker buildx imagetools inspect \
159
+ # "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}"
160
+
161
+ # - name: Attest provenance
162
+ # uses: actions/attest-build-provenance@v2
163
+ # with:
164
+ # subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
165
+ # subject-digest: ${{ steps.manifest.outputs.digest }}
166
+ # push-to-registry: true
@@ -0,0 +1,35 @@
1
+ # Rust
2
+ /target
3
+ .cargo/
4
+
5
+ # Python
6
+ /downloaded
7
+ /dist
8
+ .test-venv
9
+ *.pyc
10
+ __pycache__/
11
+ *.egg-info/
12
+ .eggs/
13
+ *.whl
14
+ *.tar.gz
15
+
16
+ # Build artifacts
17
+ build/
18
+
19
+ # IDE
20
+ .vscode/
21
+ .idea/
22
+ *.swp
23
+ *.swo
24
+
25
+ # macOS
26
+ .DS_Store
27
+ pypiron-data/
28
+ # Bench harness local state
29
+ bench/.keys/
30
+ bench/.server-env
31
+ bench/.rig.env
32
+ bench/results/
33
+ /data/
34
+ # Bulk PyPI corpus downloads (95MB+, see src/corpus_check.rs)
35
+ bench/corpus/
@@ -0,0 +1,44 @@
1
+ # Working in this repo
2
+
3
+ pypiron is a single-crate Rust PyPI server (index, upload, mirror, on-demand
4
+ proxy). Truth is files on disk/S3; indexes are regenerable views. One binary, no
5
+ database. The guiding bias is against complexity: the best code is no code.
6
+
7
+ ## Before you finish
8
+ - Run `make check` (format, `cargo check`, clippy `-D warnings`, Rust unit tests)
9
+ and fix everything it reports. A change isn't done until it passes.
10
+ - Run `make test` for the full suite (Rust unit + Python blackbox) when you touch
11
+ HTTP, storage, the worker, sync, or the proxy. `make help` lists every target.
12
+
13
+ ## Testing (see [docs/TESTING.md](docs/TESTING.md))
14
+ - Blackbox-first: the real binary, driven over HTTP by real `uv`/`pip`/`twine`.
15
+ Add a blackbox test (`tests/*.py`) for any changed user-visible behavior.
16
+ - Rust unit tests (`#[cfg(test)]`) are for pure functions only — parsing,
17
+ rendering, normalization. Anything touching I/O is tested blackbox.
18
+ - Prefer real clients and real packages over mocks; don't add a mock layer.
19
+ - S3 tests need Docker/MinIO and skip cleanly without it; the poetry/pdm/flit/
20
+ hatch compat matrix runs via `make compat`, not on every change.
21
+
22
+ ## Conventions
23
+ - Architecture and the storage-layout contract: [docs/DESIGN.md](docs/DESIGN.md)
24
+ ([docs/VISION.md](docs/VISION.md) is the one-pager). Don't invent storage-tree
25
+ or sidecar variants.
26
+ - Standards support is behavior verified against real clients, not spec-shaped
27
+ output: [docs/STANDARDS.md](docs/STANDARDS.md).
28
+ - Every `--flag` is also a `PYPIRON_FLAG` env var; document new knobs in
29
+ [docs/CONFIGURATION.md](docs/CONFIGURATION.md).
30
+ - Check [docs/ROADMAP.md](docs/ROADMAP.md) before adding features — respect the
31
+ "rejected" list; don't re-litigate it.
32
+ - No `unwrap`/`expect`/`panic!` on a request or worker path; return errors with
33
+ `anyhow` context. Catch specific errors, never a blanket match.
34
+ - Security is fail-closed: a half-configured credential refuses startup, secrets
35
+ compare in constant time, private names never fall through to upstream.
36
+ - Storage mutations are write-to-tmp-then-rename on the same filesystem; keep
37
+ them crash-safe.
38
+ - Don't add a dependency to avoid a few lines of code.
39
+
40
+ ## Commits & releases
41
+ - Conventional commits; spell out `feature` (not `feat`). Bug-fix messages state
42
+ the root cause and how it was addressed.
43
+ - The repo version stays `0.0.0`; real versions come from `vX.Y.Z` git tags and
44
+ are stamped by CI. See [RELEASE.md](RELEASE.md).
@@ -0,0 +1 @@
1
+ @AGENTS.md