pydocket 0.6.3__tar.gz → 0.15.3__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.

Potentially problematic release.


This version of pydocket might be problematic. Click here for more details.

Files changed (117) hide show
  1. pydocket-0.15.3/.coveragerc-memory +11 -0
  2. {pydocket-0.6.3 → pydocket-0.15.3}/.cursor/rules/general.mdc +1 -1
  3. {pydocket-0.6.3 → pydocket-0.15.3}/.github/workflows/chaos.yml +24 -1
  4. pydocket-0.15.3/.github/workflows/ci.yml +100 -0
  5. pydocket-0.15.3/.github/workflows/claude-code-review.yml +40 -0
  6. pydocket-0.15.3/.github/workflows/claude.yml +42 -0
  7. pydocket-0.15.3/.github/workflows/docs.yml +84 -0
  8. {pydocket-0.6.3 → pydocket-0.15.3}/.github/workflows/publish.yml +9 -4
  9. {pydocket-0.6.3 → pydocket-0.15.3}/.gitignore +8 -8
  10. {pydocket-0.6.3 → pydocket-0.15.3}/.pre-commit-config.yaml +8 -2
  11. pydocket-0.15.3/CLAUDE.md +125 -0
  12. pydocket-0.15.3/PKG-INFO +160 -0
  13. pydocket-0.15.3/README.md +118 -0
  14. {pydocket-0.6.3 → pydocket-0.15.3}/chaos/driver.py +142 -46
  15. pydocket-0.15.3/chaos/redis.py +46 -0
  16. pydocket-0.15.3/chaos/signals.py +347 -0
  17. {pydocket-0.6.3 → pydocket-0.15.3}/chaos/tasks.py +8 -1
  18. pydocket-0.15.3/docs/advanced-patterns.md +1101 -0
  19. pydocket-0.15.3/docs/api-reference.md +3 -0
  20. pydocket-0.15.3/docs/dependencies.md +535 -0
  21. pydocket-0.15.3/docs/getting-started.md +253 -0
  22. pydocket-0.15.3/docs/index.md +71 -0
  23. pydocket-0.15.3/docs/production.md +551 -0
  24. pydocket-0.15.3/docs/testing.md +426 -0
  25. pydocket-0.15.3/examples/agenda_scatter.py +128 -0
  26. {pydocket-0.6.3 → pydocket-0.15.3}/examples/common.py +1 -1
  27. pydocket-0.15.3/examples/concurrency_control.py +114 -0
  28. pydocket-0.15.3/examples/fastapi_background_tasks.py +204 -0
  29. pydocket-0.15.3/examples/local_development.py +98 -0
  30. pydocket-0.15.3/examples/task_progress.py +109 -0
  31. pydocket-0.15.3/mkdocs.yml +64 -0
  32. {pydocket-0.6.3 → pydocket-0.15.3}/pyproject.toml +39 -10
  33. pydocket-0.15.3/sitecustomize.py +7 -0
  34. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/__init__.py +10 -1
  35. pydocket-0.15.3/src/docket/_uuid7.py +99 -0
  36. pydocket-0.15.3/src/docket/agenda.py +202 -0
  37. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/annotations.py +30 -2
  38. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/cli.py +465 -19
  39. pydocket-0.15.3/src/docket/dependencies.py +808 -0
  40. pydocket-0.15.3/src/docket/docket.py +1062 -0
  41. pydocket-0.15.3/src/docket/execution.py +1370 -0
  42. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/instrumentation.py +50 -5
  43. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/tasks.py +2 -2
  44. pydocket-0.15.3/src/docket/testing.py +235 -0
  45. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/worker.py +410 -87
  46. pydocket-0.15.3/tests/_key_leak_checker.py +199 -0
  47. pydocket-0.15.3/tests/cli/run.py +53 -0
  48. pydocket-0.15.3/tests/cli/test_clear.py +202 -0
  49. pydocket-0.15.3/tests/cli/test_module.py +10 -0
  50. {pydocket-0.6.3 → pydocket-0.15.3}/tests/cli/test_parsing.py +7 -0
  51. pydocket-0.15.3/tests/cli/test_snapshot.py +375 -0
  52. {pydocket-0.6.3 → pydocket-0.15.3}/tests/cli/test_striking.py +78 -108
  53. {pydocket-0.6.3 → pydocket-0.15.3}/tests/cli/test_tasks.py +32 -45
  54. pydocket-0.15.3/tests/cli/test_url_validation.py +59 -0
  55. {pydocket-0.6.3 → pydocket-0.15.3}/tests/cli/test_version.py +5 -6
  56. pydocket-0.15.3/tests/cli/test_watch.py +450 -0
  57. pydocket-0.15.3/tests/cli/test_worker.py +240 -0
  58. {pydocket-0.6.3 → pydocket-0.15.3}/tests/cli/test_workers.py +27 -29
  59. pydocket-0.15.3/tests/cli/waiting.py +174 -0
  60. pydocket-0.15.3/tests/concurrency_limits/__init__.py +1 -0
  61. pydocket-0.15.3/tests/concurrency_limits/test_basic.py +369 -0
  62. pydocket-0.15.3/tests/concurrency_limits/test_errors_and_resilience.py +238 -0
  63. pydocket-0.15.3/tests/concurrency_limits/test_execution_patterns.py +220 -0
  64. pydocket-0.15.3/tests/concurrency_limits/test_redelivery.py +321 -0
  65. pydocket-0.15.3/tests/concurrency_limits/test_worker_mechanics.py +288 -0
  66. pydocket-0.15.3/tests/conftest.py +243 -0
  67. pydocket-0.15.3/tests/test_agenda.py +404 -0
  68. pydocket-0.15.3/tests/test_cli.py +104 -0
  69. pydocket-0.15.3/tests/test_dependencies.py +666 -0
  70. pydocket-0.15.3/tests/test_docket.py +750 -0
  71. pydocket-0.15.3/tests/test_execution.py +145 -0
  72. pydocket-0.15.3/tests/test_execution_progress.py +817 -0
  73. {pydocket-0.6.3 → pydocket-0.15.3}/tests/test_fundamentals.py +483 -15
  74. {pydocket-0.6.3 → pydocket-0.15.3}/tests/test_instrumentation.py +232 -5
  75. pydocket-0.15.3/tests/test_key_leak_protection.py +198 -0
  76. pydocket-0.15.3/tests/test_memory_backend.py +113 -0
  77. pydocket-0.15.3/tests/test_perpetual_state.py +179 -0
  78. pydocket-0.15.3/tests/test_results.py +500 -0
  79. {pydocket-0.6.3 → pydocket-0.15.3}/tests/test_striking.py +2 -0
  80. pydocket-0.15.3/tests/test_testing.py +315 -0
  81. pydocket-0.15.3/tests/test_ttl_zero.py +166 -0
  82. pydocket-0.15.3/tests/test_uuid7.py +134 -0
  83. pydocket-0.15.3/tests/test_worker.py +1156 -0
  84. pydocket-0.15.3/uv.lock +2260 -0
  85. pydocket-0.6.3/.github/workflows/ci.yml +0 -65
  86. pydocket-0.6.3/PKG-INFO +0 -389
  87. pydocket-0.6.3/README.md +0 -353
  88. pydocket-0.6.3/src/docket/dependencies.py +0 -413
  89. pydocket-0.6.3/src/docket/docket.py +0 -645
  90. pydocket-0.6.3/src/docket/execution.py +0 -436
  91. pydocket-0.6.3/tests/cli/conftest.py +0 -8
  92. pydocket-0.6.3/tests/cli/test_module.py +0 -22
  93. pydocket-0.6.3/tests/cli/test_snapshot.py +0 -175
  94. pydocket-0.6.3/tests/cli/test_worker.py +0 -179
  95. pydocket-0.6.3/tests/conftest.py +0 -176
  96. pydocket-0.6.3/tests/test_dependencies.py +0 -140
  97. pydocket-0.6.3/tests/test_docket.py +0 -14
  98. pydocket-0.6.3/tests/test_execution.py +0 -63
  99. pydocket-0.6.3/tests/test_worker.py +0 -515
  100. pydocket-0.6.3/uv.lock +0 -1115
  101. {pydocket-0.6.3 → pydocket-0.15.3}/.cursor/rules/python-style.mdc +0 -0
  102. {pydocket-0.6.3 → pydocket-0.15.3}/.github/codecov.yml +0 -0
  103. {pydocket-0.6.3 → pydocket-0.15.3}/LICENSE +0 -0
  104. {pydocket-0.6.3 → pydocket-0.15.3}/chaos/README.md +0 -0
  105. {pydocket-0.6.3 → pydocket-0.15.3}/chaos/__init__.py +0 -0
  106. {pydocket-0.6.3 → pydocket-0.15.3}/chaos/producer.py +0 -0
  107. {pydocket-0.6.3 → pydocket-0.15.3}/chaos/run +0 -0
  108. {pydocket-0.6.3 → pydocket-0.15.3}/examples/__init__.py +0 -0
  109. {pydocket-0.6.3 → pydocket-0.15.3}/examples/find_and_flood.py +0 -0
  110. {pydocket-0.6.3 → pydocket-0.15.3}/examples/self_perpetuating.py +0 -0
  111. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/__main__.py +0 -0
  112. {pydocket-0.6.3 → pydocket-0.15.3}/src/docket/py.typed +0 -0
  113. {pydocket-0.6.3 → pydocket-0.15.3}/telemetry/.gitignore +0 -0
  114. {pydocket-0.6.3 → pydocket-0.15.3}/telemetry/start +0 -0
  115. {pydocket-0.6.3 → pydocket-0.15.3}/telemetry/stop +0 -0
  116. {pydocket-0.6.3 → pydocket-0.15.3}/tests/__init__.py +0 -0
  117. {pydocket-0.6.3 → pydocket-0.15.3}/tests/cli/__init__.py +0 -0
@@ -0,0 +1,11 @@
1
+ # Coverage configuration for memory backend testing
2
+ # CLI tests are skipped with memory:// URLs, so exclude CLI from coverage
3
+
4
+ [run]
5
+ branch = true
6
+ parallel = true
7
+ omit =
8
+ src/docket/__main__.py
9
+ src/docket/_uuid7.py
10
+ src/docket/cli.py
11
+ tests/cli/test_*.py
@@ -6,7 +6,7 @@ alwaysApply: true
6
6
 
7
7
  # about docket
8
8
  docket is a distributed background task system for Python functions with a focus
9
- on the scheduling of future work as seamlessly and efficiency as immediate work.
9
+ on the scheduling of future work as seamlessly and efficiently as immediate work.
10
10
 
11
11
  docket is built in Python and uses Redis as the message broker and storage system.
12
12
 
@@ -8,13 +8,15 @@ on:
8
8
  workflow_call:
9
9
 
10
10
  jobs:
11
- test:
11
+ chaos:
12
12
  name: Chaos tests
13
13
  runs-on: ubuntu-latest
14
14
  timeout-minutes: 2
15
15
 
16
16
  steps:
17
17
  - uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 0
18
20
 
19
21
  - name: Install uv and set Python version
20
22
  uses: astral-sh/setup-uv@v5
@@ -28,3 +30,24 @@ jobs:
28
30
 
29
31
  - name: Run chaos tests
30
32
  run: python -m chaos.driver
33
+
34
+ signals:
35
+ name: Signal handling tests
36
+ runs-on: ubuntu-latest
37
+ timeout-minutes: 2
38
+
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+
42
+ - name: Install uv and set Python version
43
+ uses: astral-sh/setup-uv@v5
44
+ with:
45
+ python-version: 3.12
46
+ enable-cache: true
47
+ cache-dependency-glob: "pyproject.toml"
48
+
49
+ - name: Install dependencies
50
+ run: uv sync --dev
51
+
52
+ - name: Run signal handling tests
53
+ run: python -m chaos.signals
@@ -0,0 +1,100 @@
1
+ name: Docket CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_call:
8
+
9
+ jobs:
10
+ test:
11
+ name: Test Python ${{ matrix.python-version }}, ${{ matrix.backend.name }}
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
17
+ backend:
18
+ - name: "Redis 6.2, redis-py <5"
19
+ redis-version: "6.2"
20
+ redis-py-version: ">=5,<6"
21
+ - name: "Redis 7.4, redis-py >=5"
22
+ redis-version: "7.4"
23
+ redis-py-version: ">=5"
24
+ - name: "Redis 8.0, redis-py >=5"
25
+ redis-version: "8.0"
26
+ redis-py-version: ">=5"
27
+ - name: "Valkey 8.0, redis-py >=5"
28
+ redis-version: "valkey-8.0"
29
+ redis-py-version: ">=5"
30
+ - name: "Memory (in-memory backend)"
31
+ redis-version: "memory"
32
+ redis-py-version: ">=5"
33
+ include:
34
+ - python-version: "3.10"
35
+ cov-threshold: 100
36
+ pytest-args: ""
37
+ # Python 3.11 coverage reporting is unstable, so use 98% threshold
38
+ - python-version: "3.11"
39
+ cov-threshold: 98
40
+ pytest-args: ""
41
+ - python-version: "3.12"
42
+ cov-threshold: 100
43
+ pytest-args: ""
44
+ - python-version: "3.13"
45
+ cov-threshold: 100
46
+ pytest-args: ""
47
+ - python-version: "3.14"
48
+ cov-threshold: 100
49
+ pytest-args: ""
50
+ # Memory backend: CLI tests are skipped via pytest skip markers because
51
+ # CLI rejects memory:// URLs. Use separate coverage config to exclude CLI.
52
+ - backend:
53
+ name: "Memory (in-memory backend)"
54
+ redis-version: "memory"
55
+ redis-py-version: ">=5"
56
+ cov-threshold: 98 # CLI tests are excluded from coverage and some lines are only covered by CLI tests
57
+ pytest-args: "--cov-config=.coveragerc-memory"
58
+
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+
62
+ - name: Install uv and set Python version
63
+ uses: astral-sh/setup-uv@v5
64
+ with:
65
+ python-version: ${{ matrix.python-version }}
66
+ enable-cache: true
67
+ cache-dependency-glob: "pyproject.toml"
68
+
69
+ - name: Install dependencies
70
+ run: uv sync --upgrade-package 'redis${{ matrix.backend.redis-py-version }}'
71
+
72
+ - name: Run tests
73
+ env:
74
+ REDIS_VERSION: ${{ matrix.backend.redis-version }}
75
+ run: uv run pytest --cov-branch --cov-fail-under=${{ matrix.cov-threshold }} --cov-report=xml --cov-report=term-missing:skip-covered ${{ matrix.pytest-args }}
76
+
77
+ - name: Upload coverage reports to Codecov
78
+ uses: codecov/codecov-action@v5
79
+ with:
80
+ token: ${{ secrets.CODECOV_TOKEN }}
81
+ flags: python-${{ matrix.python-version }}
82
+
83
+ prek:
84
+ name: Prek checks
85
+ runs-on: ubuntu-latest
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+
89
+ - name: Install uv and set Python version
90
+ uses: astral-sh/setup-uv@v5
91
+ with:
92
+ python-version: "3.10"
93
+ enable-cache: true
94
+ cache-dependency-glob: "pyproject.toml"
95
+
96
+ - name: Install dependencies
97
+ run: uv sync
98
+
99
+ - name: Run prek
100
+ uses: j178/prek-action@v1
@@ -0,0 +1,40 @@
1
+ name: Claude Code Review
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize]
6
+
7
+ jobs:
8
+ claude-review:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: read
12
+ pull-requests: read
13
+ issues: read
14
+ id-token: write
15
+
16
+ steps:
17
+ - name: Checkout repository
18
+ uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 1
21
+
22
+ - name: Run Claude Code Review
23
+ id: claude-review
24
+ uses: anthropics/claude-code-action@beta
25
+ with:
26
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
27
+ model: "claude-opus-4-1-20250805"
28
+
29
+ # Direct prompt for automated review (no @claude mention needed)
30
+ direct_prompt: |
31
+ Please review this pull request and provide feedback on:
32
+ - Code quality and best practices
33
+ - Potential bugs or issues
34
+ - Performance considerations
35
+ - Security concerns
36
+ - Test coverage, which must be maintained at 100% for this project
37
+
38
+ Be constructive and helpful in your feedback.
39
+
40
+ use_sticky_comment: true
@@ -0,0 +1,42 @@
1
+ name: Claude Code
2
+
3
+ on:
4
+ issue_comment:
5
+ types: [created]
6
+ pull_request_review_comment:
7
+ types: [created]
8
+ issues:
9
+ types: [opened, assigned]
10
+ pull_request_review:
11
+ types: [submitted]
12
+
13
+ jobs:
14
+ claude:
15
+ if: |
16
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17
+ (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18
+ (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19
+ (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ contents: read
23
+ pull-requests: read
24
+ issues: read
25
+ id-token: write
26
+ actions: read # Required for Claude to read CI results on PRs
27
+ steps:
28
+ - name: Checkout repository
29
+ uses: actions/checkout@v4
30
+ with:
31
+ fetch-depth: 1
32
+
33
+ - name: Run Claude Code
34
+ id: claude
35
+ uses: anthropics/claude-code-action@beta
36
+ with:
37
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
38
+
39
+ additional_permissions: |
40
+ actions: read
41
+
42
+ model: "claude-opus-4-1-20250805"
@@ -0,0 +1,84 @@
1
+ name: Documentation
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ permissions:
12
+ contents: read
13
+ pages: write
14
+ id-token: write
15
+ pull-requests: write
16
+
17
+ concurrency:
18
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
19
+ cancel-in-progress: true
20
+
21
+ jobs:
22
+ build:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - name: Install uv and set Python version
30
+ uses: astral-sh/setup-uv@v5
31
+ with:
32
+ python-version: "3.12"
33
+ enable-cache: true
34
+ cache-dependency-glob: "pyproject.toml"
35
+
36
+ - name: Install dependencies
37
+ run: uv sync --group docs
38
+
39
+ - name: Build documentation
40
+ run: uv run mkdocs build
41
+
42
+ - name: Upload artifact
43
+ uses: actions/upload-artifact@v4
44
+ id: docs-artifact
45
+ with:
46
+ name: documentation
47
+ path: site/
48
+
49
+ - name: Add or Update Comment
50
+ if: github.event_name == 'pull_request'
51
+ uses: marocchino/sticky-pull-request-comment@v2
52
+ with:
53
+ header: preview
54
+ message: |
55
+ 📚 Documentation has been built for this PR!
56
+
57
+ You can download the documentation directly here:
58
+ ${{ steps.docs-artifact.outputs.artifact-url }}
59
+
60
+ publish:
61
+ needs: build
62
+ if: github.ref == 'refs/heads/main'
63
+ runs-on: ubuntu-latest
64
+ environment:
65
+ name: github-pages
66
+ url: ${{ steps.deployment.outputs.page_url }}
67
+ steps:
68
+ - name: Download artifact
69
+ uses: actions/download-artifact@v4
70
+ with:
71
+ name: documentation
72
+ path: site
73
+
74
+ - name: Setup Pages
75
+ uses: actions/configure-pages@v4
76
+
77
+ - name: Upload Pages artifact
78
+ uses: actions/upload-pages-artifact@v3
79
+ with:
80
+ path: site
81
+
82
+ - name: Deploy to GitHub Pages
83
+ id: deployment
84
+ uses: actions/deploy-pages@v4
@@ -13,8 +13,11 @@ jobs:
13
13
  name: Build and publish to PyPI
14
14
  runs-on: ubuntu-latest
15
15
  needs: ci
16
+ environment:
17
+ name: pypi
18
+ url: https://pypi.org/p/pydocket
16
19
  permissions:
17
- id-token: write
20
+ id-token: write # Required for trusted publishing and PEP 740 attestations
18
21
  contents: read
19
22
 
20
23
  steps:
@@ -31,10 +34,12 @@ jobs:
31
34
  cache-dependency-glob: "pyproject.toml"
32
35
 
33
36
  - name: Install build dependencies
34
- run: uv pip install build hatchling hatch-vcs
37
+ run: uv pip install hatchling hatch-vcs
35
38
 
36
39
  - name: Build package
37
40
  run: uv build
38
41
 
39
- - name: Publish to PyPI
40
- run: uv publish
42
+ - name: Publish to PyPI with PEP 740 attestations
43
+ uses: pypa/gh-action-pypi-publish@release/v1
44
+ with:
45
+ packages-dir: dist/
@@ -1,13 +1,13 @@
1
- # Python-generated files
2
- __pycache__/
1
+ *.egg-info
3
2
  *.py[oc]
3
+ .coverage
4
+ .envrc
5
+ .python-version
6
+ .venv
7
+ .worktrees/
8
+ __pycache__/
4
9
  build/
5
10
  dist/
6
11
  wheels/
7
- *.egg-info
8
12
 
9
- # Virtual environments
10
- .venv
11
- .coverage
12
- .envrc
13
- .python-version
13
+ .coverage.*
@@ -24,13 +24,19 @@ repos:
24
24
  hooks:
25
25
  - id: pyright
26
26
  name: pyright (docket package)
27
- entry: pyright --verifytypes docket --ignoreexternal
27
+ entry: uv run pyright --verifytypes docket --ignoreexternal
28
28
  language: system
29
29
  types: [python]
30
30
  pass_filenames: false
31
31
  - id: pyright
32
32
  name: pyright (source and tests)
33
- entry: pyright tests
33
+ entry: uv run pyright tests
34
+ language: system
35
+ types: [python]
36
+ pass_filenames: false
37
+ - id: pyright
38
+ name: pyright (chaos tests)
39
+ entry: uv run pyright chaos
34
40
  language: system
35
41
  types: [python]
36
42
  pass_filenames: false
@@ -0,0 +1,125 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ **Docket** (`pydocket` on PyPI) is a distributed background task system for Python functions with Redis-backed persistence. It enables scheduling both immediate and future work with comprehensive dependency injection, retry mechanisms, and fault tolerance.
8
+
9
+ **Key Requirements**: Python 3.10+, Redis 6.2+ or Valkey 8.0+
10
+
11
+ ## Development Commands
12
+
13
+ ### Testing
14
+
15
+ ```bash
16
+ # Run full test suite with coverage and parallel execution
17
+ pytest
18
+
19
+ # Run specific test
20
+ pytest tests/test_docket.py::test_specific_function
21
+
22
+ ```
23
+
24
+ The project REQUIRES 100% test coverage
25
+
26
+ ### Code Quality
27
+
28
+ ```bash
29
+ # Lint and format code
30
+ ruff check
31
+ ruff format
32
+
33
+ # Type checking
34
+ pyright
35
+ pyright tests
36
+
37
+ # Run all prek hooks
38
+ uv run prek run --all-files
39
+ ```
40
+
41
+ ### Development Setup
42
+
43
+ ```bash
44
+ # Install development dependencies
45
+ uv sync --group dev
46
+
47
+ # Install prek hooks
48
+ uv run prek install
49
+ ```
50
+
51
+ ### Git Workflow
52
+
53
+ - This project uses Github for issue tracking
54
+ - This project can use git worktrees under .worktrees/
55
+
56
+ ## Core Architecture
57
+
58
+ ### Key Classes
59
+
60
+ - **`Docket`** (`src/docket/docket.py`): Central task registry and scheduler
61
+ - `add()`: Schedule tasks for execution
62
+ - `replace()`: Replace existing scheduled tasks
63
+ - `cancel()`: Cancel pending tasks
64
+ - `strike()`/`restore()`: Conditionally block/unblock tasks
65
+ - `snapshot()`: Get current state for observability
66
+
67
+ - **`Worker`** (`src/docket/worker.py`): Task execution engine
68
+ - `run_forever()`/`run_until_finished()`: Main execution loops
69
+ - Handles concurrency, retries, and dependency injection
70
+ - Maintains heartbeat for liveness tracking
71
+
72
+ - **`Execution`** (`src/docket/execution.py`): Task execution context with metadata
73
+
74
+ ### Dependencies System (`src/docket/dependencies.py`)
75
+
76
+ Rich dependency injection supporting:
77
+
78
+ - Context access: `CurrentDocket`, `CurrentWorker`, `CurrentExecution`
79
+ - Retry strategies: `Retry`, `ExponentialRetry`
80
+ - Special behaviors: `Perpetual` (self-rescheduling), `Timeout`
81
+ - Custom injection: `Depends()`
82
+ - Contextual logging: `TaskLogger`
83
+
84
+ ### Redis Data Model
85
+
86
+ - **Streams**: `{docket}:stream` (ready tasks), `{docket}:strikes` (commands)
87
+ - **Sorted Sets**: `{docket}:queue` (scheduled tasks), `{docket}:workers` (heartbeats)
88
+ - **Hashes**: `{docket}:{key}` (parked task data)
89
+ - **Sets**: `{docket}:worker-tasks:{worker}` (worker capabilities)
90
+
91
+ ### Task Lifecycle
92
+
93
+ 1. Registration with `Docket.register()` or `@docket.task`
94
+ 2. Scheduling: immediate → Redis stream, future → Redis sorted set
95
+ 3. Worker processing: scheduler moves due tasks, workers consume via consumer groups
96
+ 4. Execution: dependency injection, retry logic, acknowledgment
97
+
98
+ ## Project Structure
99
+
100
+ ### Source Code
101
+
102
+ - `src/docket/` - Main package
103
+ - `__init__.py` - Public API exports
104
+ - `docket.py` - Core Docket class
105
+ - `worker.py` - Worker implementation
106
+ - `execution.py` - Task execution context
107
+ - `dependencies.py` - Dependency injection system
108
+ - `tasks.py` - Built-in utility tasks
109
+ - `cli.py` - Command-line interface
110
+
111
+ ### Testing and Examples
112
+
113
+ - `tests/` - Comprehensive test suite
114
+ - `examples/` - Usage examples
115
+ - `chaos/` - Chaos testing framework
116
+
117
+ ## CLI Usage
118
+
119
+ ```bash
120
+ # Run a worker
121
+ docket worker --url redis://localhost:6379/0 --tasks your.module --concurrency 4
122
+
123
+ # See all commands
124
+ docket --help
125
+ ```
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.4
2
+ Name: pydocket
3
+ Version: 0.15.3
4
+ Summary: A distributed background task system for Python functions
5
+ Project-URL: Homepage, https://github.com/chrisguidry/docket
6
+ Project-URL: Bug Tracker, https://github.com/chrisguidry/docket/issues
7
+ Author-email: Chris Guidry <guid@omg.lol>
8
+ License: # Released under MIT License
9
+
10
+ Copyright (c) 2025 Chris Guidry.
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ License-File: LICENSE
18
+ Classifier: Development Status :: 4 - Beta
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: 3.14
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.10
29
+ Requires-Dist: cloudpickle>=3.1.1
30
+ Requires-Dist: exceptiongroup>=1.2.0; python_version < '3.11'
31
+ Requires-Dist: fakeredis[lua]>=2.32.1
32
+ Requires-Dist: opentelemetry-api>=1.30.0
33
+ Requires-Dist: opentelemetry-exporter-prometheus>=0.51b0
34
+ Requires-Dist: prometheus-client>=0.21.1
35
+ Requires-Dist: py-key-value-aio[memory,redis]>=0.3.0
36
+ Requires-Dist: python-json-logger>=2.0.7
37
+ Requires-Dist: redis>=5
38
+ Requires-Dist: rich>=13.9.4
39
+ Requires-Dist: typer>=0.15.1
40
+ Requires-Dist: typing-extensions>=4.12.0
41
+ Description-Content-Type: text/markdown
42
+
43
+ Docket is a distributed background task system for Python functions with a focus
44
+ on the scheduling of future work as seamlessly and efficiently as immediate work.
45
+
46
+ [![PyPI - Version](https://img.shields.io/pypi/v/pydocket)](https://pypi.org/project/pydocket/)
47
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pydocket)](https://pypi.org/project/pydocket/)
48
+ [![GitHub main checks](https://img.shields.io/github/check-runs/chrisguidry/docket/main)](https://github.com/chrisguidry/docket/actions/workflows/ci.yml)
49
+ [![Codecov](https://img.shields.io/codecov/c/github/chrisguidry/docket)](https://app.codecov.io/gh/chrisguidry/docket)
50
+ [![PyPI - License](https://img.shields.io/pypi/l/pydocket)](https://github.com/chrisguidry/docket/blob/main/LICENSE)
51
+ [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://chrisguidry.github.io/docket/)
52
+
53
+ ## At a glance
54
+
55
+ ```python
56
+ from datetime import datetime, timedelta, timezone
57
+
58
+ from docket import Docket
59
+
60
+
61
+ async def greet(name: str, greeting="Hello") -> None:
62
+ print(f"{greeting}, {name} at {datetime.now()}!")
63
+
64
+
65
+ async with Docket() as docket:
66
+ await docket.add(greet)("Jane")
67
+
68
+ now = datetime.now(timezone.utc)
69
+ soon = now + timedelta(seconds=3)
70
+ await docket.add(greet, when=soon)("John", greeting="Howdy")
71
+ ```
72
+
73
+ ```python
74
+ from docket import Docket, Worker
75
+
76
+ async with Docket() as docket:
77
+ async with Worker(docket) as worker:
78
+ worker.register(greet)
79
+ await worker.run_until_finished()
80
+ ```
81
+
82
+ ```
83
+ Hello, Jane at 2025-03-05 13:58:21.552644!
84
+ Howdy, John at 2025-03-05 13:58:24.550773!
85
+ ```
86
+
87
+ Check out our docs for more [details](http://chrisguidry.github.io/docket/),
88
+ [examples](https://chrisguidry.github.io/docket/getting-started/), and the [API
89
+ reference](https://chrisguidry.github.io/docket/api-reference/).
90
+
91
+ ## Why `docket`?
92
+
93
+ ⚡️ Snappy one-way background task processing without any bloat
94
+
95
+ 📅 Schedule immediate or future work seamlessly with the same interface
96
+
97
+ ⏭️ Skip problematic tasks or parameters without redeploying
98
+
99
+ 🌊 Purpose-built for Redis streams
100
+
101
+ 🧩 Fully type-complete and type-aware for your background task functions
102
+
103
+ 💉 Dependency injection like FastAPI, Typer, and FastMCP for reusable resources
104
+
105
+ ## Installing `docket`
106
+
107
+ Docket is [available on PyPI](https://pypi.org/project/pydocket/) under the package name
108
+ `pydocket`. It targets Python 3.10 or above.
109
+
110
+ With [`uv`](https://docs.astral.sh/uv/):
111
+
112
+ ```bash
113
+ uv pip install pydocket
114
+
115
+ or
116
+
117
+ uv add pydocket
118
+ ```
119
+
120
+ With `pip`:
121
+
122
+ ```bash
123
+ pip install pydocket
124
+ ```
125
+
126
+ Docket requires a [Redis](http://redis.io/) server with Streams support (which was
127
+ introduced in Redis 5.0.0). Docket is tested with Redis 6, 7, and 8.
128
+
129
+ For testing without Redis, Docket includes [fakeredis](https://github.com/cunla/fakeredis-py) for in-memory operation:
130
+
131
+ ```python
132
+ from docket import Docket
133
+
134
+ async with Docket(name="my-docket", url="memory://my-docket") as docket:
135
+ # Use docket normally - all operations are in-memory
136
+ ...
137
+ ```
138
+
139
+ See [Testing with Docket](https://chrisguidry.github.io/docket/testing/#using-in-memory-backend-no-redis-required) for more details.
140
+
141
+ # Hacking on `docket`
142
+
143
+ We use [`uv`](https://docs.astral.sh/uv/) for project management, so getting set up
144
+ should be as simple as cloning the repo and running:
145
+
146
+ ```bash
147
+ uv sync
148
+ ```
149
+
150
+ The to run the test suite:
151
+
152
+ ```bash
153
+ pytest
154
+ ```
155
+
156
+ We aim to maintain 100% test coverage, which is required for all PRs to `docket`. We
157
+ believe that `docket` should stay small, simple, understandable, and reliable, and that
158
+ begins with testing all the dusty branches and corners. This will give us the
159
+ confidence to upgrade dependencies quickly and to adapt to new versions of Redis over
160
+ time.