localqueue 1.1.0__tar.gz → 1.1.1__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 (59) hide show
  1. {localqueue-1.1.0 → localqueue-1.1.1}/.github/workflows/ci.yml +104 -3
  2. localqueue-1.1.1/.github/workflows/docs.yml +68 -0
  3. localqueue-1.1.1/.github/workflows/release.yml +91 -0
  4. localqueue-1.1.1/.github/workflows/wheels.yml +298 -0
  5. {localqueue-1.1.0 → localqueue-1.1.1}/.gitignore +5 -0
  6. localqueue-1.1.1/.pre-commit-config.yaml +31 -0
  7. {localqueue-1.1.0 → localqueue-1.1.1}/CHANGELOG.md +21 -0
  8. {localqueue-1.1.0 → localqueue-1.1.1}/Cargo.lock +1 -1
  9. {localqueue-1.1.0 → localqueue-1.1.1}/Cargo.toml +1 -1
  10. {localqueue-1.1.0 → localqueue-1.1.1}/PKG-INFO +28 -11
  11. {localqueue-1.1.0 → localqueue-1.1.1}/README.md +19 -9
  12. {localqueue-1.1.0 → localqueue-1.1.1}/benchmarks/queue_bench.py +10 -7
  13. localqueue-1.1.1/deny.toml +19 -0
  14. localqueue-1.1.1/docs/getting-started.md +75 -0
  15. localqueue-1.1.1/docs/index.md +52 -0
  16. {localqueue-1.1.0 → localqueue-1.1.1}/docs/internal/initial_idea.md +0 -1
  17. {localqueue-1.1.0 → localqueue-1.1.1}/pyproject.toml +46 -2
  18. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/bus/bus.py +2 -3
  19. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/bus/topology.py +2 -5
  20. localqueue-1.1.1/scripts/check_release_version.py +56 -0
  21. {localqueue-1.1.0 → localqueue-1.1.1}/stress/run_soak.py +4 -4
  22. localqueue-1.1.1/tasks/plan.md +663 -0
  23. localqueue-1.1.1/tasks/todo.md +83 -0
  24. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_batch.py +2 -7
  25. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_bus.py +24 -30
  26. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_bus_static_topology.py +9 -28
  27. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_bus_topology.py +0 -1
  28. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_concurrency.py +0 -1
  29. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_contract.py +3 -7
  30. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_core.py +1 -2
  31. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_maintenance.py +0 -1
  32. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_worker.py +0 -3
  33. localqueue-1.1.1/uv.lock +1253 -0
  34. localqueue-1.1.1/zensical.toml +30 -0
  35. localqueue-1.1.0/.github/workflows/wheels.yml +0 -173
  36. {localqueue-1.1.0 → localqueue-1.1.1}/.github/workflows/stress.yml +0 -0
  37. {localqueue-1.1.0 → localqueue-1.1.1}/LICENSE +0 -0
  38. {localqueue-1.1.0 → localqueue-1.1.1}/benchmarks/README.md +0 -0
  39. {localqueue-1.1.0 → localqueue-1.1.1}/docs/event-bus.md +0 -0
  40. {localqueue-1.1.0 → localqueue-1.1.1}/docs/guarantees.md +0 -0
  41. {localqueue-1.1.0 → localqueue-1.1.1}/examples/basic.py +0 -0
  42. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/__init__.py +0 -0
  43. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/bus/__init__.py +0 -0
  44. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/bus/consumer.py +0 -0
  45. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/bus/event.py +0 -0
  46. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/bus/registry.py +0 -0
  47. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/bus/subscription.py +0 -0
  48. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/core.py +0 -0
  49. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/exceptions.py +0 -0
  50. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/job.py +0 -0
  51. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/localqueue.pyi +0 -0
  52. {localqueue-1.1.0 → localqueue-1.1.1}/python/localqueue/worker.py +0 -0
  53. {localqueue-1.1.0 → localqueue-1.1.1}/src/error.rs +0 -0
  54. {localqueue-1.1.0 → localqueue-1.1.1}/src/lib.rs +0 -0
  55. {localqueue-1.1.0 → localqueue-1.1.1}/src/queue.rs +0 -0
  56. {localqueue-1.1.0 → localqueue-1.1.1}/src/schema.rs +0 -0
  57. {localqueue-1.1.0 → localqueue-1.1.1}/src/storage.rs +0 -0
  58. {localqueue-1.1.0 → localqueue-1.1.1}/tests/__init__.py +0 -0
  59. {localqueue-1.1.0 → localqueue-1.1.1}/tests/test_gil.py +0 -0
@@ -14,6 +14,52 @@ concurrency:
14
14
  cancel-in-progress: true
15
15
 
16
16
  jobs:
17
+ python-quality:
18
+ name: Python lint and types
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Check out repository
22
+ uses: actions/checkout@v6
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v6
26
+ with:
27
+ python-version: '3.14'
28
+ cache: pip
29
+
30
+ - name: Install Python quality tools
31
+ run: |
32
+ python -m pip install --upgrade \
33
+ "pydantic>=2,<3" \
34
+ "ruff>=0.15,<1" \
35
+ "pyrefly>=1.1,<2"
36
+
37
+ - name: Run Ruff
38
+ run: |
39
+ ruff check .
40
+ ruff format --check .
41
+
42
+ - name: Run Pyrefly
43
+ env:
44
+ PYTHONPATH: python
45
+ run: pyrefly check --preset default --progress-bar no python/localqueue
46
+
47
+ secrets:
48
+ name: Secret scan
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - name: Check out repository
52
+ uses: actions/checkout@v6
53
+ with:
54
+ fetch-depth: 0
55
+
56
+ - name: Run Gitleaks
57
+ uses: gitleaks/gitleaks-action@v2
58
+ env:
59
+ # The CLI result is the quality gate. Keep SARIF uploads opt-in so
60
+ # a transient Actions artifact quota cannot hide scan results.
61
+ GITLEAKS_ENABLE_UPLOAD_ARTIFACT: "false"
62
+
17
63
  rust-quality:
18
64
  name: Rust format and Clippy
19
65
  runs-on: ubuntu-latest
@@ -43,6 +89,18 @@ jobs:
43
89
  - name: Run Clippy
44
90
  run: cargo clippy --locked --all-targets --all-features -- -D warnings
45
91
 
92
+ rust-dependencies:
93
+ name: Rust dependencies
94
+ runs-on: ubuntu-latest
95
+ steps:
96
+ - name: Check out repository
97
+ uses: actions/checkout@v6
98
+
99
+ - name: Run cargo-deny
100
+ uses: EmbarkStudios/cargo-deny-action@v2
101
+ with:
102
+ command: check
103
+
46
104
  msrv:
47
105
  name: Rust MSRV 1.83
48
106
  runs-on: ubuntu-latest
@@ -81,7 +139,19 @@ jobs:
81
139
  python-version: ${{ matrix.python }}
82
140
  cache: pip
83
141
 
84
- - name: Build extension and run tests in a virtual environment
142
+ - name: Cache Cargo dependencies and build outputs
143
+ uses: actions/cache@v4
144
+ with:
145
+ path: |
146
+ ~/.cargo/registry
147
+ ~/.cargo/git
148
+ target
149
+ key: ${{ runner.os }}-cargo-py${{ matrix.python }}-${{ hashFiles('Cargo.toml', 'Cargo.lock') }}
150
+ restore-keys: |
151
+ ${{ runner.os }}-cargo-py${{ matrix.python }}-
152
+ ${{ runner.os }}-cargo-
153
+
154
+ - name: Build extension in a virtual environment
85
155
  shell: bash
86
156
  run: |
87
157
  python -m venv .venv
@@ -93,13 +163,44 @@ jobs:
93
163
  python -m pip install --upgrade \
94
164
  "maturin>=1.14,<2" \
95
165
  "pytest>=8,<10" \
166
+ "pytest-cov>=7,<8" \
96
167
  "pydantic>=2,<3"
97
- maturin develop --release --locked
168
+ maturin develop --locked
169
+
170
+ - name: Run tests
171
+ if: matrix.os != 'ubuntu-latest' || matrix.python != '3.14'
172
+ shell: bash
173
+ run: |
174
+ if [ "$RUNNER_OS" = "Windows" ]; then
175
+ source .venv/Scripts/activate
176
+ else
177
+ source .venv/bin/activate
178
+ fi
98
179
  pytest -ra
99
180
 
181
+ - name: Run tests with branch coverage
182
+ if: matrix.os == 'ubuntu-latest' && matrix.python == '3.14'
183
+ shell: bash
184
+ run: |
185
+ source .venv/bin/activate
186
+ pytest -ra \
187
+ --cov=localqueue \
188
+ --cov-branch \
189
+ --cov-report=term-missing \
190
+ --cov-report=xml \
191
+ --cov-fail-under=80
192
+
193
+ - name: Upload coverage to Codecov
194
+ if: matrix.os == 'ubuntu-latest' && matrix.python == '3.14'
195
+ uses: codecov/codecov-action@v5
196
+ with:
197
+ token: ${{ secrets.CODECOV_TOKEN }}
198
+ files: coverage.xml
199
+ fail_ci_if_error: false
200
+
100
201
  wheel-smoke:
101
202
  name: Build and smoke-test wheel
102
- needs: [rust-quality, python-tests]
203
+ needs: [python-quality, secrets, rust-quality, rust-dependencies, python-tests]
103
204
  runs-on: ubuntu-latest
104
205
  steps:
105
206
  - name: Check out repository
@@ -0,0 +1,68 @@
1
+ name: Documentation
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - "docs/**"
7
+ - "zensical.toml"
8
+ - ".github/workflows/docs.yml"
9
+ - "pyproject.toml"
10
+ - "uv.lock"
11
+ push:
12
+ branches: [main]
13
+ paths:
14
+ - "docs/**"
15
+ - "zensical.toml"
16
+ - ".github/workflows/docs.yml"
17
+ - "pyproject.toml"
18
+ - "uv.lock"
19
+ workflow_dispatch:
20
+
21
+ permissions:
22
+ contents: read
23
+
24
+ concurrency:
25
+ group: docs-${{ github.workflow }}-${{ github.ref }}
26
+ cancel-in-progress: true
27
+
28
+ jobs:
29
+ build:
30
+ name: Build documentation
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - name: Check out repository
34
+ uses: actions/checkout@v6
35
+
36
+ - name: Set up Python
37
+ uses: actions/setup-python@v6
38
+ with:
39
+ python-version: '3.14'
40
+ cache: pip
41
+
42
+ - name: Install Zensical
43
+ run: python -m pip install --upgrade "zensical>=0.0.51,<0.1"
44
+
45
+ - name: Build site
46
+ run: zensical build --clean
47
+
48
+ - name: Upload Pages artifact
49
+ if: github.event_name != 'pull_request'
50
+ uses: actions/upload-pages-artifact@v5
51
+ with:
52
+ path: site
53
+
54
+ deploy:
55
+ name: Deploy documentation
56
+ if: github.event_name != 'pull_request'
57
+ needs: build
58
+ runs-on: ubuntu-latest
59
+ permissions:
60
+ pages: write
61
+ id-token: write
62
+ environment:
63
+ name: github-pages
64
+ url: ${{ steps.deployment.outputs.page_url }}
65
+ steps:
66
+ - name: Deploy to GitHub Pages
67
+ id: deployment
68
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,91 @@
1
+ name: Create release tag
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ dry_run:
7
+ description: Calculate the next version without writing, tagging, or pushing
8
+ required: true
9
+ default: true
10
+ type: boolean
11
+
12
+ permissions:
13
+ contents: write
14
+
15
+ concurrency:
16
+ group: release
17
+ cancel-in-progress: false
18
+
19
+ jobs:
20
+ release:
21
+ name: Calculate and tag release
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - name: Check out main with full history
25
+ uses: actions/checkout@v6
26
+ with:
27
+ ref: main
28
+ fetch-depth: 0
29
+
30
+ - name: Confirm main is current
31
+ run: |
32
+ git fetch origin main --tags
33
+ test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
34
+
35
+ - name: Set up Python
36
+ uses: actions/setup-python@v6
37
+ with:
38
+ python-version: '3.14'
39
+
40
+ - name: Set up Rust
41
+ uses: dtolnay/rust-toolchain@stable
42
+
43
+ - name: Install release and test tooling
44
+ run: |
45
+ python -m pip install --upgrade \
46
+ "python-semantic-release>=10.6,<11" \
47
+ "maturin>=1.14,<2" \
48
+ "pytest>=8,<10" \
49
+ "pydantic>=2,<3"
50
+
51
+ - name: Validate release history
52
+ run: |
53
+ current_version=$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
54
+ last_released=$(semantic-release version --print-last-released)
55
+ test "$current_version" = "$last_released" || {
56
+ echo "pyproject.toml is $current_version but Semantic Release sees $last_released." >&2
57
+ echo "Reconcile the published release tag with main before automating the next release." >&2
58
+ exit 1
59
+ }
60
+
61
+ - name: Calculate next version
62
+ id: version
63
+ run: |
64
+ version=$(semantic-release version --print)
65
+ echo "version=$version" >> "$GITHUB_OUTPUT"
66
+ echo "tag=v$version" >> "$GITHUB_OUTPUT"
67
+
68
+ - name: Report dry run
69
+ if: inputs.dry_run
70
+ run: |
71
+ echo "Next release would be ${{ steps.version.outputs.tag }}"
72
+
73
+ - name: Create local release commit and tag
74
+ if: inputs.dry_run == false
75
+ env:
76
+ GH_TOKEN: ${{ github.token }}
77
+ run: semantic-release version --no-push --no-vcs-release
78
+
79
+ - name: Validate versioned tree
80
+ if: inputs.dry_run == false
81
+ run: |
82
+ python scripts/check_release_version.py --tag "${{ steps.version.outputs.tag }}"
83
+ cargo fmt --all --check
84
+ cargo check --locked
85
+ maturin develop --release --locked
86
+ pytest -ra
87
+
88
+ - name: Push release commit and tag atomically
89
+ if: inputs.dry_run == false
90
+ run: |
91
+ git push --atomic origin HEAD:main "${{ steps.version.outputs.tag }}"
@@ -0,0 +1,298 @@
1
+ name: Wheels
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ release_ref:
7
+ description: Existing v* tag to publish; leave empty for a build-only run
8
+ required: false
9
+ type: string
10
+ push:
11
+ tags: ['v*']
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ prepare-release:
18
+ name: Prepare release
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ contents: write
22
+ outputs:
23
+ release_mode: ${{ steps.release.outputs.release_mode }}
24
+ release_ref: ${{ steps.release.outputs.release_ref }}
25
+ steps:
26
+ - name: Resolve release mode
27
+ id: release
28
+ env:
29
+ INPUT_RELEASE_REF: ${{ inputs.release_ref }}
30
+ REF_NAME: ${{ github.ref_name }}
31
+ REF_TYPE: ${{ github.ref_type }}
32
+ shell: bash
33
+ run: |
34
+ if [[ -n "$INPUT_RELEASE_REF" ]]; then
35
+ release_ref="$INPUT_RELEASE_REF"
36
+ release_mode=true
37
+ elif [[ "$REF_TYPE" == "tag" && "$REF_NAME" == v* ]]; then
38
+ release_ref="$REF_NAME"
39
+ release_mode=true
40
+ else
41
+ release_ref="$REF_NAME"
42
+ release_mode=false
43
+ fi
44
+
45
+ if [[ "$release_mode" == true && "$release_ref" != v* ]]; then
46
+ echo "release_ref must start with v" >&2
47
+ exit 1
48
+ fi
49
+
50
+ echo "release_mode=$release_mode" >> "$GITHUB_OUTPUT"
51
+ echo "release_ref=$release_ref" >> "$GITHUB_OUTPUT"
52
+
53
+ - name: Create draft GitHub release
54
+ if: steps.release.outputs.release_mode == 'true'
55
+ env:
56
+ GH_TOKEN: ${{ github.token }}
57
+ RELEASE_REF: ${{ steps.release.outputs.release_ref }}
58
+ run: |
59
+ gh release view "$RELEASE_REF" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 || \
60
+ gh release create "$RELEASE_REF" \
61
+ --repo "$GITHUB_REPOSITORY" \
62
+ --verify-tag \
63
+ --draft \
64
+ --generate-notes \
65
+ --title "$RELEASE_REF"
66
+
67
+ - name: Refuse to rebuild an already published release
68
+ if: steps.release.outputs.release_mode == 'true'
69
+ env:
70
+ GH_TOKEN: ${{ github.token }}
71
+ RELEASE_REF: ${{ steps.release.outputs.release_ref }}
72
+ run: |
73
+ if gh release view "$RELEASE_REF" --repo "$GITHUB_REPOSITORY" \
74
+ --json isDraft --jq '.isDraft == false' | grep -qx true; then
75
+ echo "release $RELEASE_REF is already published" >&2
76
+ exit 1
77
+ fi
78
+
79
+ validate-release:
80
+ name: Validate release version
81
+ needs: prepare-release
82
+ runs-on: ubuntu-latest
83
+ steps:
84
+ - name: Check out release source
85
+ uses: actions/checkout@v6
86
+ with:
87
+ ref: ${{ needs.prepare-release.outputs.release_ref }}
88
+
89
+ - name: Validate tag and package metadata
90
+ if: needs.prepare-release.outputs.release_mode == 'true'
91
+ run: python scripts/check_release_version.py --tag "${{ needs.prepare-release.outputs.release_ref }}"
92
+
93
+ build:
94
+ name: ${{ matrix.name }}
95
+ needs: [prepare-release, validate-release]
96
+ permissions:
97
+ contents: write
98
+ strategy:
99
+ fail-fast: false
100
+ matrix:
101
+ include:
102
+ - name: linux-x86_64
103
+ os: ubuntu-latest
104
+ target: x86_64-unknown-linux-gnu
105
+ manylinux: '2_17'
106
+ - name: linux-aarch64
107
+ os: ubuntu-latest
108
+ target: aarch64-unknown-linux-gnu
109
+ manylinux: '2_17'
110
+ - name: macos-x86_64
111
+ os: macos-15-intel
112
+ target: x86_64-apple-darwin
113
+ manylinux: off
114
+ - name: macos-arm64
115
+ os: macos-15
116
+ target: aarch64-apple-darwin
117
+ manylinux: off
118
+ - name: windows-x86_64
119
+ os: windows-latest
120
+ target: x86_64-pc-windows-msvc
121
+ manylinux: off
122
+ runs-on: ${{ matrix.os }}
123
+ steps:
124
+ - name: Check out repository
125
+ uses: actions/checkout@v6
126
+ with:
127
+ ref: ${{ needs.prepare-release.outputs.release_ref }}
128
+
129
+ - name: Set up QEMU for Linux ARM64
130
+ if: matrix.name == 'linux-aarch64'
131
+ uses: docker/setup-qemu-action@v3
132
+
133
+ - name: Set up Python interpreters
134
+ uses: actions/setup-python@v6
135
+ with:
136
+ python-version: |
137
+ 3.10
138
+ 3.11
139
+ 3.12
140
+ 3.13
141
+ 3.14
142
+
143
+ - name: Build wheels with maturin
144
+ uses: PyO3/maturin-action@v1
145
+ with:
146
+ command: build
147
+ target: ${{ matrix.target }}
148
+ manylinux: ${{ matrix.manylinux }}
149
+ args: --release --locked --find-interpreter --compatibility pypi
150
+ maturin-version: v1.14.1
151
+
152
+ - name: Set up smoke-test Python
153
+ uses: actions/setup-python@v6
154
+ with:
155
+ python-version: '3.13'
156
+
157
+ - name: Install one wheel for smoke testing
158
+ if: matrix.name != 'linux-aarch64'
159
+ shell: bash
160
+ run: |
161
+ python -m pip install --upgrade "pydantic>=2,<3"
162
+ python -m pip install --force-reinstall --no-index target/wheels/*cp313*.whl
163
+
164
+ - name: Smoke-test installed wheel outside the checkout
165
+ if: matrix.name != 'linux-aarch64'
166
+ shell: bash
167
+ run: |
168
+ cd "$RUNNER_TEMP"
169
+ python - <<'PY'
170
+ import tempfile
171
+
172
+ from localqueue import EnqueueItem, SimpleQueue
173
+ from localqueue.bus import BaseEvent, BusTopology, EventBus
174
+
175
+ class WheelEvent(BaseEvent):
176
+ value: int
177
+
178
+ with tempfile.TemporaryDirectory() as path:
179
+ queue = SimpleQueue(path)
180
+ queue.put_many([
181
+ {"platform": "wheel"},
182
+ EnqueueItem({"platform": "batch"}, job_id="batch-1"),
183
+ ])
184
+ job = queue.get(block=False)
185
+ queue.ack(job)
186
+ job = queue.get(block=False)
187
+ queue.ack(job)
188
+ assert queue.stats()["acked"] == 2
189
+ queue.close()
190
+
191
+ topology = BusTopology({"smoke": [WheelEvent]})
192
+ bus = EventBus(path, topology=topology)
193
+ smoke = bus.subscription("smoke")
194
+
195
+ @smoke.handler(WheelEvent)
196
+ def handle(event: WheelEvent) -> None:
197
+ assert event.value == 1
198
+
199
+ receipt = bus.dispatch(WheelEvent(value=1))
200
+ assert receipt.subscriptions == ("smoke",)
201
+ bus.close()
202
+ PY
203
+
204
+ - name: Validate Linux ARM64 wheel artifact
205
+ if: matrix.name == 'linux-aarch64'
206
+ shell: bash
207
+ run: test -n "$(find target/wheels -name '*cp313*.whl' -print -quit)"
208
+
209
+ - name: Build source distribution
210
+ if: matrix.name == 'linux-x86_64'
211
+ uses: PyO3/maturin-action@v1
212
+ with:
213
+ command: sdist
214
+ args: --out target/dist
215
+ maturin-version: v1.14.1
216
+
217
+ - name: Upload wheels
218
+ if: needs.prepare-release.outputs.release_mode != 'true'
219
+ uses: actions/upload-artifact@v4
220
+ with:
221
+ name: wheels-${{ matrix.name }}
222
+ path: target/wheels/*.whl
223
+ if-no-files-found: error
224
+
225
+ - name: Upload source distribution
226
+ if: matrix.name == 'linux-x86_64' && needs.prepare-release.outputs.release_mode != 'true'
227
+ uses: actions/upload-artifact@v4
228
+ with:
229
+ name: source-distribution
230
+ path: target/dist/*.tar.gz
231
+ if-no-files-found: error
232
+
233
+ - name: Upload distributions to draft GitHub release
234
+ if: needs.prepare-release.outputs.release_mode == 'true'
235
+ shell: bash
236
+ env:
237
+ GH_TOKEN: ${{ github.token }}
238
+ RELEASE_REF: ${{ needs.prepare-release.outputs.release_ref }}
239
+ run: |
240
+ gh release upload "$RELEASE_REF" target/wheels/*.whl \
241
+ --repo "$GITHUB_REPOSITORY" \
242
+ --clobber
243
+
244
+ if [[ "${{ matrix.name }}" == "linux-x86_64" ]]; then
245
+ gh release upload "$RELEASE_REF" target/dist/*.tar.gz \
246
+ --repo "$GITHUB_REPOSITORY" \
247
+ --clobber
248
+ fi
249
+
250
+ publish:
251
+ name: Publish complete release to PyPI
252
+ if: needs.prepare-release.outputs.release_mode == 'true'
253
+ needs: [prepare-release, build]
254
+ runs-on: ubuntu-latest
255
+ environment: pypi
256
+ permissions:
257
+ contents: write
258
+ id-token: write
259
+ steps:
260
+ - name: Download distributions from draft GitHub release
261
+ env:
262
+ GH_TOKEN: ${{ github.token }}
263
+ RELEASE_REF: ${{ needs.prepare-release.outputs.release_ref }}
264
+ run: |
265
+ mkdir -p target/dist
266
+ gh release download "$RELEASE_REF" \
267
+ --repo "$GITHUB_REPOSITORY" \
268
+ --dir target/dist
269
+
270
+ for python_tag in cp310 cp311 cp312 cp313 cp314; do
271
+ wheel_count=$(find target/dist -name "*-${python_tag}-${python_tag}-*.whl" | wc -l)
272
+ if [[ "$wheel_count" -ne 5 ]]; then
273
+ echo "expected 5 wheels for $python_tag, found $wheel_count" >&2
274
+ exit 1
275
+ fi
276
+ done
277
+
278
+ test "$(find target/dist -name '*.tar.gz' | wc -l)" -eq 1
279
+
280
+ - name: Install uv
281
+ uses: astral-sh/setup-uv@v8.3.2
282
+
283
+ - name: Publish all artifacts
284
+ run: |
285
+ uv publish \
286
+ --trusted-publishing always \
287
+ --check-url https://pypi.org/simple/ \
288
+ target/dist/*
289
+
290
+ - name: Publish GitHub release
291
+ env:
292
+ GH_TOKEN: ${{ github.token }}
293
+ RELEASE_REF: ${{ needs.prepare-release.outputs.release_ref }}
294
+ run: |
295
+ gh release edit "$RELEASE_REF" \
296
+ --repo "$GITHUB_REPOSITORY" \
297
+ --draft=false \
298
+ --latest
@@ -5,11 +5,16 @@ __pycache__/
5
5
  .pytest_cache/
6
6
  .mypy_cache/
7
7
  .ruff_cache/
8
+ .pyrefly/
9
+ .coverage
10
+ coverage.xml
11
+ htmlcov/
8
12
  *.db
9
13
  *.wal
10
14
  *.shm
11
15
  data/
12
16
  dist/
13
17
  build/
18
+ site/
14
19
  target/
15
20
  *.so
@@ -0,0 +1,31 @@
1
+ default_language_version:
2
+ python: python3.10
3
+
4
+ repos:
5
+ - repo: https://github.com/pre-commit/pre-commit-hooks
6
+ rev: v5.0.0
7
+ hooks:
8
+ - id: check-toml
9
+ - id: check-yaml
10
+ - id: end-of-file-fixer
11
+ - id: trailing-whitespace
12
+
13
+ - repo: https://github.com/astral-sh/ruff-pre-commit
14
+ rev: v0.15.22
15
+ hooks:
16
+ - id: ruff-check
17
+ args: [--fix]
18
+ - id: ruff-format
19
+
20
+ - repo: https://github.com/gitleaks/gitleaks
21
+ rev: v8.30.1
22
+ hooks:
23
+ - id: gitleaks
24
+
25
+ - repo: local
26
+ hooks:
27
+ - id: cargo-fmt
28
+ name: cargo fmt
29
+ entry: cargo fmt --all --check
30
+ language: system
31
+ pass_filenames: false
@@ -2,6 +2,26 @@
2
2
 
3
3
  All notable changes to `localqueue` are documented here.
4
4
 
5
+ <!-- version list -->
6
+
7
+ ## [1.1.1] - 2026-07-21
8
+
9
+ ### Added
10
+
11
+ - Zensical documentation site with a durable, two-process getting-started
12
+ guide and GitHub Pages deployment workflow.
13
+ - Python branch-coverage reporting, Ruff, Pyrefly, pre-commit, Gitleaks, and
14
+ cargo-deny quality gates.
15
+ - Manual Conventional Commits release workflow with Python, Cargo, lockfile,
16
+ tag, and wheel-release consistency checks.
17
+
18
+ ### Changed
19
+
20
+ - The README quickstart now demonstrates a producer persisting a job before a
21
+ later worker process consumes it.
22
+ - CI caches Rust build outputs and uses debug builds for test jobs while wheel
23
+ builds remain optimized release builds.
24
+
5
25
  ## [1.1.0] - 2026-07-21
6
26
 
7
27
  ### Added
@@ -80,6 +100,7 @@ storage migration:
80
100
  leases, bounded retries, dead-letter handling, receipt fencing, and
81
101
  multiprocess safety on one machine.
82
102
 
103
+ [1.1.1]: https://github.com/brunoportis/localqueue/compare/v1.1.0...v1.1.1
83
104
  [1.1.0]: https://github.com/brunoportis/localqueue/compare/v1.0.1...v1.1.0
84
105
  [1.0.1]: https://github.com/brunoportis/localqueue/compare/v1.0.0...v1.0.1
85
106
  [1.0.0]: https://github.com/brunoportis/localqueue/releases/tag/v1.0.0
@@ -97,7 +97,7 @@ dependencies = [
97
97
 
98
98
  [[package]]
99
99
  name = "localqueue"
100
- version = "1.1.0"
100
+ version = "1.1.1"
101
101
  dependencies = [
102
102
  "pyo3",
103
103
  "rusqlite",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "localqueue"
3
- version = "1.1.0"
3
+ version = "1.1.1"
4
4
  edition = "2021"
5
5
  rust-version = "1.83"
6
6
  description = "A persistent, multiprocess-safe local queue for Python, backed by SQLite and Rust."