interlock-cb 1.0.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 (103) hide show
  1. interlock_cb-1.0.0/.claude/settings.json +5 -0
  2. interlock_cb-1.0.0/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
  3. interlock_cb-1.0.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. interlock_cb-1.0.0/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  5. interlock_cb-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  6. interlock_cb-1.0.0/.github/dependabot.yml +15 -0
  7. interlock_cb-1.0.0/.github/workflows/ci.yml +45 -0
  8. interlock_cb-1.0.0/.github/workflows/docs.yml +47 -0
  9. interlock_cb-1.0.0/.github/workflows/release.yml +51 -0
  10. interlock_cb-1.0.0/.gitignore +39 -0
  11. interlock_cb-1.0.0/.hypothesis/.gitignore +9 -0
  12. interlock_cb-1.0.0/.hypothesis/constants/06a4b260de5060ee +4 -0
  13. interlock_cb-1.0.0/.hypothesis/constants/089c843b9bbadf6f +4 -0
  14. interlock_cb-1.0.0/.hypothesis/constants/0ded8d2e102de102 +4 -0
  15. interlock_cb-1.0.0/.hypothesis/constants/0e433060b82d8622 +4 -0
  16. interlock_cb-1.0.0/.hypothesis/constants/19a9ca7724cb2cc3 +4 -0
  17. interlock_cb-1.0.0/.hypothesis/constants/206bebd6662412a7 +4 -0
  18. interlock_cb-1.0.0/.hypothesis/constants/426ccac79ef394c0 +4 -0
  19. interlock_cb-1.0.0/.hypothesis/constants/5090f2d8008d86a7 +4 -0
  20. interlock_cb-1.0.0/.hypothesis/constants/53bef2a567a6bbac +4 -0
  21. interlock_cb-1.0.0/.hypothesis/constants/653425710aa90c9c +4 -0
  22. interlock_cb-1.0.0/.hypothesis/constants/656cbb32ddaa52e9 +4 -0
  23. interlock_cb-1.0.0/.hypothesis/constants/67b0a8ccf18bf5d2 +4 -0
  24. interlock_cb-1.0.0/.hypothesis/constants/6c2108f77b1357cf +4 -0
  25. interlock_cb-1.0.0/.hypothesis/constants/6dbf5957cd1b3627 +4 -0
  26. interlock_cb-1.0.0/.hypothesis/constants/6f2e032b5988ca14 +4 -0
  27. interlock_cb-1.0.0/.hypothesis/constants/8341443ac143cf7e +4 -0
  28. interlock_cb-1.0.0/.hypothesis/constants/9c26eabcd1227abe +4 -0
  29. interlock_cb-1.0.0/.hypothesis/constants/ad8f434ace58570d +4 -0
  30. interlock_cb-1.0.0/.hypothesis/constants/c357a4ad29caa583 +4 -0
  31. interlock_cb-1.0.0/.hypothesis/constants/d56313e8a47d81c2 +4 -0
  32. interlock_cb-1.0.0/.hypothesis/constants/d5a94da48926492c +4 -0
  33. interlock_cb-1.0.0/.hypothesis/constants/fadb156b26650b6f +4 -0
  34. interlock_cb-1.0.0/.hypothesis/constants/ffd8d4d32246fbfc +4 -0
  35. interlock_cb-1.0.0/.pre-commit-config.yaml +64 -0
  36. interlock_cb-1.0.0/CHANGELOG.md +43 -0
  37. interlock_cb-1.0.0/CODE_OF_CONDUCT.md +65 -0
  38. interlock_cb-1.0.0/CONTRIBUTING.md +62 -0
  39. interlock_cb-1.0.0/LICENSE +21 -0
  40. interlock_cb-1.0.0/PKG-INFO +153 -0
  41. interlock_cb-1.0.0/README.md +126 -0
  42. interlock_cb-1.0.0/SECURITY.md +23 -0
  43. interlock_cb-1.0.0/docs/getting-started.md +112 -0
  44. interlock_cb-1.0.0/docs/guides/configuration.md +76 -0
  45. interlock_cb-1.0.0/docs/guides/failure-classification.md +62 -0
  46. interlock_cb-1.0.0/docs/guides/observability.md +88 -0
  47. interlock_cb-1.0.0/docs/guides/states.md +54 -0
  48. interlock_cb-1.0.0/docs/guides/timeout.md +42 -0
  49. interlock_cb-1.0.0/docs/index.md +30 -0
  50. interlock_cb-1.0.0/docs/integrations/httpx2.md +74 -0
  51. interlock_cb-1.0.0/docs/llms-full.txt +653 -0
  52. interlock_cb-1.0.0/docs/llms.txt +39 -0
  53. interlock_cb-1.0.0/docs/reference.md +94 -0
  54. interlock_cb-1.0.0/interlock/__init__.py +53 -0
  55. interlock_cb-1.0.0/interlock/_classify.py +24 -0
  56. interlock_cb-1.0.0/interlock/_clock.py +18 -0
  57. interlock_cb-1.0.0/interlock/_detect.py +34 -0
  58. interlock_cb-1.0.0/interlock/_engine.py +232 -0
  59. interlock_cb-1.0.0/interlock/_state_machine.py +197 -0
  60. interlock_cb-1.0.0/interlock/_typing.py +35 -0
  61. interlock_cb-1.0.0/interlock/_windows.py +118 -0
  62. interlock_cb-1.0.0/interlock/breaker.py +169 -0
  63. interlock_cb-1.0.0/interlock/config.py +69 -0
  64. interlock_cb-1.0.0/interlock/errors.py +72 -0
  65. interlock_cb-1.0.0/interlock/httpx2.py +158 -0
  66. interlock_cb-1.0.0/interlock/listeners.py +38 -0
  67. interlock_cb-1.0.0/interlock/otel.py +64 -0
  68. interlock_cb-1.0.0/interlock/outcome.py +30 -0
  69. interlock_cb-1.0.0/interlock/protocols.py +89 -0
  70. interlock_cb-1.0.0/interlock/py.typed +0 -0
  71. interlock_cb-1.0.0/interlock/registry.py +69 -0
  72. interlock_cb-1.0.0/interlock/state.py +28 -0
  73. interlock_cb-1.0.0/interlock/timeout.py +33 -0
  74. interlock_cb-1.0.0/interlock/version.py +15 -0
  75. interlock_cb-1.0.0/interlock/window.py +47 -0
  76. interlock_cb-1.0.0/pyproject.toml +171 -0
  77. interlock_cb-1.0.0/scripts/build_llms_full.py +57 -0
  78. interlock_cb-1.0.0/tests/conftest.py +126 -0
  79. interlock_cb-1.0.0/tests/test_breaker.py +178 -0
  80. interlock_cb-1.0.0/tests/test_clock.py +13 -0
  81. interlock_cb-1.0.0/tests/test_config.py +57 -0
  82. interlock_cb-1.0.0/tests/test_detect.py +74 -0
  83. interlock_cb-1.0.0/tests/test_e2e.py +194 -0
  84. interlock_cb-1.0.0/tests/test_engine.py +217 -0
  85. interlock_cb-1.0.0/tests/test_errors.py +27 -0
  86. interlock_cb-1.0.0/tests/test_httpx2.py +170 -0
  87. interlock_cb-1.0.0/tests/test_httpx2_e2e.py +204 -0
  88. interlock_cb-1.0.0/tests/test_listeners.py +51 -0
  89. interlock_cb-1.0.0/tests/test_observability.py +183 -0
  90. interlock_cb-1.0.0/tests/test_otel.py +64 -0
  91. interlock_cb-1.0.0/tests/test_outcome.py +38 -0
  92. interlock_cb-1.0.0/tests/test_protocols.py +9 -0
  93. interlock_cb-1.0.0/tests/test_registry.py +53 -0
  94. interlock_cb-1.0.0/tests/test_state.py +23 -0
  95. interlock_cb-1.0.0/tests/test_state_machine.py +292 -0
  96. interlock_cb-1.0.0/tests/test_state_machine_properties.py +91 -0
  97. interlock_cb-1.0.0/tests/test_timeout.py +60 -0
  98. interlock_cb-1.0.0/tests/test_typing.py +18 -0
  99. interlock_cb-1.0.0/tests/test_version.py +10 -0
  100. interlock_cb-1.0.0/tests/test_window.py +32 -0
  101. interlock_cb-1.0.0/tests/test_windows.py +141 -0
  102. interlock_cb-1.0.0/uv.lock +953 -0
  103. interlock_cb-1.0.0/zensical.toml +63 -0
@@ -0,0 +1,5 @@
1
+ {
2
+ "worktree": {
3
+ "bgIsolation": "none"
4
+ }
5
+ }
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report incorrect behaviour
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ **What happened**
10
+ A clear description of the bug.
11
+
12
+ **Expected behaviour**
13
+ What you expected instead.
14
+
15
+ **Minimal reproduction**
16
+ ```python
17
+ # the smallest snippet that triggers the issue
18
+ ```
19
+
20
+ **Environment**
21
+ - interlock version:
22
+ - Python version:
23
+ - OS:
24
+ - Extras in use (otel / httpx2):
25
+
26
+ **Additional context**
27
+ Anything else that helps — config used, traceback, etc.
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/bagowix/interlock/security/advisories/new
5
+ about: Please report security issues privately, not as public issues.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea or improvement
4
+ title: ''
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ **Problem**
10
+ What are you trying to do that interlock makes hard or impossible today?
11
+
12
+ **Proposed solution**
13
+ What you'd like to see. API sketches welcome.
14
+
15
+ **Alternatives considered**
16
+ Other approaches you weighed.
17
+
18
+ **Scope check**
19
+ interlock v1 is deliberately a focused circuit breaker (see `planning/PLAN.md`).
20
+ Does this fit the v1 core, or a later milestone (timeout/retry/pipeline,
21
+ distributed state, more integrations)?
@@ -0,0 +1,16 @@
1
+ ## Summary
2
+
3
+ <!-- What does this change and why? -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] Tests added or updated (suite stays at 100% coverage)
8
+ - [ ] `uv run ruff format --check` and `uv run ruff check` pass
9
+ - [ ] `uv run mypy` and `uv run pyright` pass
10
+ - [ ] Docs updated (`docs/`) for user-facing changes
11
+ - [ ] `CHANGELOG.md` `[Unreleased]` updated
12
+ - [ ] Commits follow Conventional Commits
13
+
14
+ ## Related issues
15
+
16
+ <!-- e.g. Closes #123 -->
@@ -0,0 +1,15 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ commit-message:
8
+ prefix: "ci"
9
+
10
+ - package-ecosystem: "uv"
11
+ directory: "/"
12
+ schedule:
13
+ interval: "weekly"
14
+ commit-message:
15
+ prefix: "chore"
@@ -0,0 +1,45 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ quality:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ['3.11', '3.12', '3.13', '3.14']
19
+ env:
20
+ UV_PYTHON: ${{ matrix.python-version }}
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v5
26
+ with:
27
+ enable-cache: true
28
+
29
+ - name: Install dependencies
30
+ run: uv sync --frozen
31
+
32
+ - name: Ruff format
33
+ run: uv run ruff format --check
34
+
35
+ - name: Ruff lint
36
+ run: uv run ruff check
37
+
38
+ - name: Mypy
39
+ run: uv run mypy --num-workers 2
40
+
41
+ - name: Pyright
42
+ run: uv run pyright
43
+
44
+ - name: Tests
45
+ run: uv run pytest --cov
@@ -0,0 +1,47 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: read
9
+ pages: write
10
+ id-token: write
11
+
12
+ concurrency:
13
+ group: pages
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v5
24
+ with:
25
+ enable-cache: true
26
+
27
+ - name: Install dependencies
28
+ run: uv sync --frozen
29
+
30
+ - name: Build site
31
+ run: uv run zensical build
32
+
33
+ - name: Upload Pages artifact
34
+ uses: actions/upload-pages-artifact@v3
35
+ with:
36
+ path: site
37
+
38
+ deploy:
39
+ needs: build
40
+ runs-on: ubuntu-latest
41
+ environment:
42
+ name: github-pages
43
+ url: ${{ steps.deployment.outputs.page_url }}
44
+ steps:
45
+ - name: Deploy to GitHub Pages
46
+ id: deployment
47
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,51 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v5
19
+ with:
20
+ enable-cache: true
21
+
22
+ - name: Install dependencies
23
+ run: uv sync --frozen
24
+
25
+ - name: Tests
26
+ run: uv run pytest
27
+
28
+ - name: Build sdist and wheel
29
+ run: uv build
30
+
31
+ - name: Upload artifacts
32
+ uses: actions/upload-artifact@v4
33
+ with:
34
+ name: dist
35
+ path: dist/
36
+
37
+ publish:
38
+ needs: build
39
+ runs-on: ubuntu-latest
40
+ environment: pypi
41
+ permissions:
42
+ id-token: write
43
+ steps:
44
+ - name: Download artifacts
45
+ uses: actions/download-artifact@v4
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+
50
+ - name: Publish to PyPI
51
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,39 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ .idea/
13
+ .vscode/
14
+ .vim/
15
+
16
+ .venv/
17
+ venv/
18
+ .coverage
19
+ .mypy_cache/
20
+ .pytest_cache/
21
+ .pytype/
22
+ *.pyc
23
+ .env
24
+ .local/
25
+
26
+ .DS_Store
27
+ .python-version
28
+ .ruff_cache
29
+ *.npy
30
+ script.py
31
+ requests.http
32
+
33
+ tmp/
34
+ *egg-info/
35
+ reports/
36
+ scratch/
37
+
38
+ # Zensical docs build output
39
+ site/
@@ -0,0 +1,9 @@
1
+ # This .gitignore file was automatically created by Hypothesis. Hypothesis gitignores
2
+ # .hypothesis by default, because we generally recommend that .hypothesis not be checked
3
+ # into version control.
4
+ #
5
+ # If you *would* like to check .hypothesis into version control, you should delete this
6
+ # file. Hypothesis will not re-create this .gitignore unless .hypothesis is deleted (and
7
+ # if it does, that's a bug - please report it!)
8
+
9
+ *
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/config.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ [0.0, 0.5, 1.0, 60.0, 100, 'Config']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/httpx2.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['HttpStatusClassifier', 'Response']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/errors.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['CallTimeoutError', 'CircuitOpenError', 'InterlockError']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/protocols.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['Clock', 'EventListener', 'FailureClassifier', 'SlidingWindow', 'Storage']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/window.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ [0.0, 'WindowSnapshot', 'WindowType']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/_state_machine.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ [0.0, 'StateMachine']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/_windows.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['build_window']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/otel.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['OTelEventListener', 'breaker', 'from', 'interlock', 'interlock.reset', 'outcome', 's', 'to']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/breaker.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['AsyncCallable[P, R]', 'CircuitBreaker', 'SyncCallable[P, R]']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/_typing.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['AsyncCallable', 'Call', 'P', 'R', 'SyncCallable']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/_engine.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['AsyncCallable[P, R]', 'Engine', 'SyncCallable[P, R]']
@@ -0,0 +1,4 @@
1
+ # file: /usr/lib/python3.12/sitecustomize.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ []
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/listeners.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['LoggingEventListener', 'circuit %r: reset', 'interlock']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/_clock.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['SystemClock']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/_classify.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ []
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/version.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['1.0.0', 'VERSION']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/.venv/bin/pytest
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['-script.pyw', '.exe', '__main__']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/timeout.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['timeout']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/state.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['State']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/_detect.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['__call__', 'is_async_callable']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/__init__.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['AsyncCallable', 'Call', 'CallTimeoutError', 'CircuitBreaker', 'CircuitOpenError', 'Clock', 'Config', 'EventListener', 'FailureClassifier', 'InterlockError', 'LoggingEventListener', 'Outcome', 'Registry', 'SlidingWindow', 'State', 'Storage', 'SyncCallable', 'VERSION', 'WindowSnapshot', 'WindowType', '__version__', 'timeout']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/registry.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['Registry']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/interlock/interlock/interlock/outcome.py
2
+ # hypothesis_version: 6.155.7
3
+
4
+ ['Outcome']
@@ -0,0 +1,64 @@
1
+ default_install_hook_types:
2
+ - pre-commit
3
+ - commit-msg
4
+
5
+ default_stages: [pre-commit, pre-push]
6
+
7
+ repos:
8
+ - repo: https://github.com/astral-sh/ruff-pre-commit
9
+ rev: v0.15.18
10
+ hooks:
11
+ - id: ruff-format
12
+ - id: ruff-check
13
+ name: ruff-check
14
+
15
+ - repo: https://github.com/pre-commit/pre-commit-hooks
16
+ rev: v6.0.0
17
+ hooks:
18
+ - id: check-docstring-first
19
+ exclude: ^interlock/version\.py$
20
+ - id: check-ast
21
+ - id: check-toml
22
+ - id: check-yaml
23
+ - id: check-merge-conflict
24
+ - id: check-case-conflict
25
+ - id: debug-statements
26
+ - id: end-of-file-fixer
27
+ - id: mixed-line-ending
28
+ - id: trailing-whitespace
29
+ - id: detect-private-key
30
+ - id: no-commit-to-branch
31
+ args: [ --branch, main ]
32
+
33
+ - repo: local
34
+ hooks:
35
+ - id: mypy
36
+ name: mypy
37
+ entry: uv run mypy --num-workers 2
38
+ language: system
39
+ types: [python]
40
+ pass_filenames: false
41
+ args: [--config-file=./pyproject.toml]
42
+
43
+ - id: pyright
44
+ name: pyright
45
+ entry: uv run pyright
46
+ language: system
47
+ types: [python]
48
+ pass_filenames: false
49
+
50
+ - repo: https://github.com/jackdewinter/pymarkdown
51
+ rev: v0.9.38
52
+ hooks:
53
+ - id: pymarkdown
54
+ name: pymarkdown
55
+ files: \.md$
56
+ pass_filenames: true
57
+ exclude: (CHANGELOG\.md|^\.github/)
58
+
59
+ - repo: https://github.com/compilerla/conventional-pre-commit
60
+ rev: v4.4.0
61
+ hooks:
62
+ - id: conventional-pre-commit
63
+ stages: [commit-msg]
64
+ args: []
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2026-06-27
10
+
11
+ ### Added
12
+
13
+ - Core state machine: `CLOSED` / `OPEN` / `HALF_OPEN` plus the operator
14
+ overrides `FORCED_OPEN`, `DISABLED` and `METRICS_ONLY` (shadow mode).
15
+ - Sliding windows behind a `SlidingWindow` protocol, with count-based and
16
+ time-based implementations selected via `Config.window_type`.
17
+ - Failure-rate trigger with `failure_rate_threshold` and
18
+ `minimum_number_of_calls`, and **slow-call detection** via
19
+ `slow_call_duration_threshold` and `slow_call_rate_threshold`.
20
+ - Lazy `OPEN → HALF_OPEN` transition with a probe limit and a concurrency cap.
21
+ - Single public `CircuitBreaker` for sync and async, usable as a decorator, a
22
+ sync/async context manager, and `breaker.call(fn, ...)`. Decorators preserve
23
+ the signature and sync/async nature via `ParamSpec` + `@overload`.
24
+ - Manual control: `reset()`, `force_open()`, `disable()`, `metrics_only()`.
25
+ - `Registry` of named breakers with a shared default config and per-name
26
+ overrides.
27
+ - Immutable `Config` (frozen dataclass) with eager validation.
28
+ - `FailureClassifier` protocol with a default policy (any raised exception is a
29
+ failure); classification by result is supported by custom classifiers.
30
+ - `CircuitOpenError` carrying the breaker name, an estimated `retry_after`, and
31
+ the last recorded failure.
32
+ - Async-first `timeout` primitive that turns a hang into `CallTimeoutError`.
33
+ - Observability: `EventListener` protocol, a zero-dependency
34
+ `LoggingEventListener`, and an `OTelEventListener` (extra `interlock-cb[otel]`).
35
+ - httpx2 transport integration (extra `interlock-cb[httpx2]`):
36
+ `CircuitBreakerTransport` and `AsyncCircuitBreakerTransport` apply a breaker
37
+ per host, with an `HttpStatusClassifier` treating `429, 500, 502, 503, 504`
38
+ and transport exceptions as failures.
39
+ - `InterlockDeprecationWarning` (subclasses `UserWarning`, visible by default).
40
+ - `py.typed`; strict mypy and pyright; 100% test coverage.
41
+
42
+ [Unreleased]: https://github.com/bagowix/interlock/compare/v1.0.0...HEAD
43
+ [1.0.0]: https://github.com/bagowix/interlock/releases/tag/v1.0.0
@@ -0,0 +1,65 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment include:
18
+
19
+ - Demonstrating empathy and kindness toward other people
20
+ - Being respectful of differing opinions, viewpoints, and experiences
21
+ - Giving and gracefully accepting constructive feedback
22
+ - Accepting responsibility and apologizing to those affected by our mistakes,
23
+ and learning from the experience
24
+ - Focusing on what is best for the overall community
25
+
26
+ Examples of unacceptable behavior include:
27
+
28
+ - The use of sexualized language or imagery, and sexual attention or advances of
29
+ any kind
30
+ - Trolling, insulting or derogatory comments, and personal or political attacks
31
+ - Public or private harassment
32
+ - Publishing others' private information, such as a physical or email address,
33
+ without their explicit permission
34
+ - Other conduct which could reasonably be considered inappropriate in a
35
+ professional setting
36
+
37
+ ## Enforcement Responsibilities
38
+
39
+ Community leaders are responsible for clarifying and enforcing our standards of
40
+ acceptable behavior and will take appropriate and fair corrective action in
41
+ response to any behavior that they deem inappropriate, threatening, offensive,
42
+ or harmful.
43
+
44
+ ## Scope
45
+
46
+ This Code of Conduct applies within all community spaces, and also applies when
47
+ an individual is officially representing the community in public spaces.
48
+
49
+ ## Enforcement
50
+
51
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
52
+ reported to the community leaders responsible for enforcement at
53
+ **galushko355@gmail.com**. All complaints will be reviewed and investigated
54
+ promptly and fairly.
55
+
56
+ All community leaders are obligated to respect the privacy and security of the
57
+ reporter of any incident.
58
+
59
+ ## Attribution
60
+
61
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
62
+ version 2.1, available at
63
+ <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
64
+
65
+ [homepage]: https://www.contributor-covenant.org