pyresilience 0.1.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.
@@ -0,0 +1,81 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ *.manifest
29
+ *.spec
30
+
31
+ # Installer logs
32
+ pip-log.txt
33
+ pip-delete-this-directory.txt
34
+
35
+ # Unit test / coverage reports
36
+ htmlcov/
37
+ .tox/
38
+ .nox/
39
+ .coverage
40
+ .coverage.*
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+ *.cover
45
+ *.py,cover
46
+ .hypothesis/
47
+ .pytest_cache/
48
+ junit.xml
49
+
50
+ # Translations
51
+ *.mo
52
+ *.pot
53
+
54
+ # Environments
55
+ .env
56
+ .venv
57
+ env/
58
+ venv/
59
+ ENV/
60
+
61
+ # IDE
62
+ .vscode/
63
+ .idea/
64
+ *.swp
65
+ *.swo
66
+ *~
67
+
68
+ # mypy
69
+ .mypy_cache/
70
+ dmypy.json
71
+ dmypy.txt
72
+
73
+ # ruff
74
+ .ruff_cache/
75
+
76
+ # mkdocs
77
+ site/
78
+
79
+ # OS
80
+ .DS_Store
81
+ Thumbs.db
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-03-18
9
+
10
+ ### Added
11
+ - `@resilient()` decorator combining retry, timeout, circuit breaker, fallback, and bulkhead
12
+ - Full sync and async support
13
+ - `RetryConfig` with exponential backoff and jitter
14
+ - `TimeoutConfig` for per-call timeouts
15
+ - `CircuitBreakerConfig` with half-open recovery
16
+ - `FallbackConfig` with static values or callable fallbacks
17
+ - `BulkheadConfig` for concurrency limiting
18
+ - Structured event system via `ResilienceEvent` and `ResilienceListener`
19
+ - Type-safe configuration dataclasses
20
+ - Zero runtime dependencies
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ahsan Sheraz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyresilience
3
+ Version: 0.1.0
4
+ Summary: Unified resilience patterns for Python — retry, circuit breaker, timeout, fallback, and bulkhead in one decorator.
5
+ Project-URL: Homepage, https://github.com/AhsanSheraz/pyresilience
6
+ Project-URL: Repository, https://github.com/AhsanSheraz/pyresilience
7
+ Project-URL: Issues, https://github.com/AhsanSheraz/pyresilience/issues
8
+ Project-URL: Documentation, https://pyresilience.readthedocs.io/
9
+ Project-URL: Changelog, https://github.com/AhsanSheraz/pyresilience/blob/main/CHANGELOG.md
10
+ Author-email: Ahsan Sheraz <ahsansheraz@gmail.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: async,bulkhead,circuit-breaker,decorator,distributed-systems,fallback,fault-tolerance,microservices,python,reliability,resilience,retry,timeout
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Topic :: System :: Networking
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.9
30
+ Provides-Extra: dev
31
+ Requires-Dist: mypy>=1.0; extra == 'dev'
32
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
33
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
34
+ Requires-Dist: pytest>=7.0; extra == 'dev'
35
+ Requires-Dist: ruff>=0.11.0; extra == 'dev'
36
+ Provides-Extra: fast
37
+ Requires-Dist: orjson>=3.9.0; extra == 'fast'
38
+ Requires-Dist: uvloop>=0.17.0; (sys_platform != 'win32') and extra == 'fast'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # pyresilience
42
+
43
+ [![CI](https://github.com/AhsanSheraz/pyresilience/actions/workflows/ci.yml/badge.svg)](https://github.com/AhsanSheraz/pyresilience/actions/workflows/ci.yml)
44
+ [![PyPI](https://img.shields.io/pypi/v/pyresilience)](https://pypi.org/project/pyresilience/)
45
+ [![Python](https://img.shields.io/pypi/pyversions/pyresilience)](https://pypi.org/project/pyresilience/)
46
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
47
+
48
+ **Unified resilience patterns for Python** — retry, circuit breaker, timeout, fallback, bulkhead, rate limiter, and cache in one decorator. Python's [Resilience4j](https://resilience4j.readme.io/).
49
+
50
+ ## Why?
51
+
52
+ Python has `tenacity` for retry, `pybreaker` for circuit breaking, and `wrapt_timeout_decorator` for timeouts. But combining them means stacking decorators, managing separate configs, and losing visibility across patterns. **pyresilience** unifies everything into a single `@resilient()` decorator with zero dependencies.
53
+
54
+ ## Resilience4j Feature Parity
55
+
56
+ | Resilience4j Module | pyresilience | Status |
57
+ |---------------------|-------------|--------|
58
+ | CircuitBreaker | `CircuitBreakerConfig` | Complete |
59
+ | Retry | `RetryConfig` | Complete |
60
+ | Bulkhead | `BulkheadConfig` | Complete |
61
+ | TimeLimiter | `TimeoutConfig` | Complete |
62
+ | RateLimiter | `RateLimiterConfig` | Complete |
63
+ | Cache | `CacheConfig` | Complete |
64
+ | Registry | `ResilienceRegistry` | Complete |
65
+
66
+ ## Install
67
+
68
+ ```bash
69
+ pip install pyresilience
70
+
71
+ # Optional: faster event loop + JSON serialization
72
+ pip install pyresilience[fast]
73
+ ```
74
+
75
+ ## Quick Start
76
+
77
+ ```python
78
+ from pyresilience import resilient, RetryConfig, TimeoutConfig, CircuitBreakerConfig, FallbackConfig
79
+
80
+ @resilient(
81
+ retry=RetryConfig(max_attempts=3, delay=1.0, backoff_factor=2.0),
82
+ timeout=TimeoutConfig(seconds=10),
83
+ circuit_breaker=CircuitBreakerConfig(failure_threshold=5, recovery_timeout=30),
84
+ fallback=FallbackConfig(handler=lambda e: {"error": str(e), "cached": True}),
85
+ )
86
+ def call_api(endpoint: str) -> dict:
87
+ return requests.get(endpoint).json()
88
+
89
+ # Works with async too
90
+ @resilient(
91
+ retry=RetryConfig(max_attempts=3),
92
+ timeout=TimeoutConfig(seconds=5),
93
+ )
94
+ async def async_call(url: str) -> dict:
95
+ async with aiohttp.ClientSession() as session:
96
+ async with session.get(url) as resp:
97
+ return await resp.json()
98
+ ```
99
+
100
+ ## Features
101
+
102
+ | Pattern | What it does |
103
+ |---------|-------------|
104
+ | **Retry** | Exponential backoff with jitter, configurable exceptions |
105
+ | **Timeout** | Per-call time limits (thread-based sync, native async) |
106
+ | **Circuit Breaker** | Stop calling failing services, auto-recover via half-open |
107
+ | **Fallback** | Graceful degradation with static values or callables |
108
+ | **Bulkhead** | Concurrency limiting to prevent resource exhaustion |
109
+ | **Rate Limiter** | Token bucket rate limiting (calls per time window) |
110
+ | **Cache** | LRU result caching with TTL to avoid redundant calls |
111
+
112
+ Plus:
113
+ - **Registry** for centralized management of named resilience instances
114
+ - **Event system** for observability (`ResilienceListener`)
115
+ - **Opinionated presets** — `http_policy()`, `db_policy()`, `queue_policy()`, `strict_policy()`
116
+ - **Structured logging** — `JsonEventLogger` and `MetricsCollector`
117
+ - **Zero dependencies** — pure Python stdlib
118
+ - **Optional performance backends** — `uvloop` + `orjson` via `pip install pyresilience[fast]`
119
+ - **Full async support** — auto-detects sync vs async
120
+ - **Type-safe** — strict mypy compatible, `py.typed` marker
121
+ - **Python 3.9+**
122
+
123
+ ## Rate Limiter
124
+
125
+ Limit call rate using a token bucket algorithm:
126
+
127
+ ```python
128
+ from pyresilience import resilient, RateLimiterConfig
129
+
130
+ @resilient(rate_limiter=RateLimiterConfig(max_calls=10, period=1.0))
131
+ def call_api(endpoint: str) -> dict:
132
+ return requests.get(endpoint).json()
133
+
134
+ # With waiting instead of immediate rejection:
135
+ @resilient(rate_limiter=RateLimiterConfig(max_calls=10, period=1.0, max_wait=5.0))
136
+ async def rate_limited_call() -> dict:
137
+ ...
138
+ ```
139
+
140
+ ## Cache
141
+
142
+ Cache function results with TTL and LRU eviction:
143
+
144
+ ```python
145
+ from pyresilience import resilient, CacheConfig
146
+
147
+ @resilient(cache=CacheConfig(max_size=256, ttl=300.0))
148
+ def get_user(user_id: int) -> dict:
149
+ return db.query(f"SELECT * FROM users WHERE id = {user_id}")
150
+
151
+ # Second call with same args returns cached result
152
+ get_user(42) # hits DB
153
+ get_user(42) # returns cached, DB not called
154
+ ```
155
+
156
+ ## Registry
157
+
158
+ Share resilience state (circuit breakers, rate limiters) across functions:
159
+
160
+ ```python
161
+ from pyresilience import ResilienceRegistry, ResilienceConfig, RetryConfig, CircuitBreakerConfig
162
+
163
+ registry = ResilienceRegistry()
164
+ registry.register("payment-api", ResilienceConfig(
165
+ retry=RetryConfig(max_attempts=3),
166
+ circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
167
+ ))
168
+
169
+ @registry.decorator("payment-api")
170
+ async def charge_card(amount: float) -> dict:
171
+ ...
172
+
173
+ @registry.decorator("payment-api")
174
+ async def refund_card(amount: float) -> dict:
175
+ ...
176
+
177
+ # Both functions share the same circuit breaker —
178
+ # if charge_card trips the circuit, refund_card is also blocked
179
+ ```
180
+
181
+ ## Presets
182
+
183
+ Opinionated defaults for common integration patterns:
184
+
185
+ ```python
186
+ from pyresilience import resilient
187
+ from pyresilience.presets import http_policy, db_policy, queue_policy
188
+
189
+ @resilient(**http_policy())
190
+ def call_api(url: str) -> dict:
191
+ return requests.get(url).json()
192
+
193
+ @resilient(**db_policy())
194
+ def query_db(sql: str) -> list:
195
+ return cursor.execute(sql).fetchall()
196
+
197
+ @resilient(**queue_policy())
198
+ async def publish_message(msg: dict) -> None:
199
+ await producer.send(msg)
200
+ ```
201
+
202
+ ## Observability
203
+
204
+ ```python
205
+ from pyresilience import resilient, RetryConfig, JsonEventLogger, MetricsCollector
206
+
207
+ logger = JsonEventLogger()
208
+ metrics = MetricsCollector()
209
+
210
+ @resilient(retry=RetryConfig(max_attempts=3), listeners=[logger, metrics])
211
+ def monitored_call():
212
+ return do_work()
213
+
214
+ # After calls:
215
+ print(metrics.summary())
216
+ # {'total_events': 5, 'success_rate': 0.8, 'p99_latency': 1.23, ...}
217
+ ```
218
+
219
+ ## Documentation
220
+
221
+ Full docs at [pyresilience.readthedocs.io](https://pyresilience.readthedocs.io/)
222
+
223
+ ## License
224
+
225
+ MIT
@@ -0,0 +1,185 @@
1
+ # pyresilience
2
+
3
+ [![CI](https://github.com/AhsanSheraz/pyresilience/actions/workflows/ci.yml/badge.svg)](https://github.com/AhsanSheraz/pyresilience/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/pyresilience)](https://pypi.org/project/pyresilience/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/pyresilience)](https://pypi.org/project/pyresilience/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ **Unified resilience patterns for Python** — retry, circuit breaker, timeout, fallback, bulkhead, rate limiter, and cache in one decorator. Python's [Resilience4j](https://resilience4j.readme.io/).
9
+
10
+ ## Why?
11
+
12
+ Python has `tenacity` for retry, `pybreaker` for circuit breaking, and `wrapt_timeout_decorator` for timeouts. But combining them means stacking decorators, managing separate configs, and losing visibility across patterns. **pyresilience** unifies everything into a single `@resilient()` decorator with zero dependencies.
13
+
14
+ ## Resilience4j Feature Parity
15
+
16
+ | Resilience4j Module | pyresilience | Status |
17
+ |---------------------|-------------|--------|
18
+ | CircuitBreaker | `CircuitBreakerConfig` | Complete |
19
+ | Retry | `RetryConfig` | Complete |
20
+ | Bulkhead | `BulkheadConfig` | Complete |
21
+ | TimeLimiter | `TimeoutConfig` | Complete |
22
+ | RateLimiter | `RateLimiterConfig` | Complete |
23
+ | Cache | `CacheConfig` | Complete |
24
+ | Registry | `ResilienceRegistry` | Complete |
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pip install pyresilience
30
+
31
+ # Optional: faster event loop + JSON serialization
32
+ pip install pyresilience[fast]
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ```python
38
+ from pyresilience import resilient, RetryConfig, TimeoutConfig, CircuitBreakerConfig, FallbackConfig
39
+
40
+ @resilient(
41
+ retry=RetryConfig(max_attempts=3, delay=1.0, backoff_factor=2.0),
42
+ timeout=TimeoutConfig(seconds=10),
43
+ circuit_breaker=CircuitBreakerConfig(failure_threshold=5, recovery_timeout=30),
44
+ fallback=FallbackConfig(handler=lambda e: {"error": str(e), "cached": True}),
45
+ )
46
+ def call_api(endpoint: str) -> dict:
47
+ return requests.get(endpoint).json()
48
+
49
+ # Works with async too
50
+ @resilient(
51
+ retry=RetryConfig(max_attempts=3),
52
+ timeout=TimeoutConfig(seconds=5),
53
+ )
54
+ async def async_call(url: str) -> dict:
55
+ async with aiohttp.ClientSession() as session:
56
+ async with session.get(url) as resp:
57
+ return await resp.json()
58
+ ```
59
+
60
+ ## Features
61
+
62
+ | Pattern | What it does |
63
+ |---------|-------------|
64
+ | **Retry** | Exponential backoff with jitter, configurable exceptions |
65
+ | **Timeout** | Per-call time limits (thread-based sync, native async) |
66
+ | **Circuit Breaker** | Stop calling failing services, auto-recover via half-open |
67
+ | **Fallback** | Graceful degradation with static values or callables |
68
+ | **Bulkhead** | Concurrency limiting to prevent resource exhaustion |
69
+ | **Rate Limiter** | Token bucket rate limiting (calls per time window) |
70
+ | **Cache** | LRU result caching with TTL to avoid redundant calls |
71
+
72
+ Plus:
73
+ - **Registry** for centralized management of named resilience instances
74
+ - **Event system** for observability (`ResilienceListener`)
75
+ - **Opinionated presets** — `http_policy()`, `db_policy()`, `queue_policy()`, `strict_policy()`
76
+ - **Structured logging** — `JsonEventLogger` and `MetricsCollector`
77
+ - **Zero dependencies** — pure Python stdlib
78
+ - **Optional performance backends** — `uvloop` + `orjson` via `pip install pyresilience[fast]`
79
+ - **Full async support** — auto-detects sync vs async
80
+ - **Type-safe** — strict mypy compatible, `py.typed` marker
81
+ - **Python 3.9+**
82
+
83
+ ## Rate Limiter
84
+
85
+ Limit call rate using a token bucket algorithm:
86
+
87
+ ```python
88
+ from pyresilience import resilient, RateLimiterConfig
89
+
90
+ @resilient(rate_limiter=RateLimiterConfig(max_calls=10, period=1.0))
91
+ def call_api(endpoint: str) -> dict:
92
+ return requests.get(endpoint).json()
93
+
94
+ # With waiting instead of immediate rejection:
95
+ @resilient(rate_limiter=RateLimiterConfig(max_calls=10, period=1.0, max_wait=5.0))
96
+ async def rate_limited_call() -> dict:
97
+ ...
98
+ ```
99
+
100
+ ## Cache
101
+
102
+ Cache function results with TTL and LRU eviction:
103
+
104
+ ```python
105
+ from pyresilience import resilient, CacheConfig
106
+
107
+ @resilient(cache=CacheConfig(max_size=256, ttl=300.0))
108
+ def get_user(user_id: int) -> dict:
109
+ return db.query(f"SELECT * FROM users WHERE id = {user_id}")
110
+
111
+ # Second call with same args returns cached result
112
+ get_user(42) # hits DB
113
+ get_user(42) # returns cached, DB not called
114
+ ```
115
+
116
+ ## Registry
117
+
118
+ Share resilience state (circuit breakers, rate limiters) across functions:
119
+
120
+ ```python
121
+ from pyresilience import ResilienceRegistry, ResilienceConfig, RetryConfig, CircuitBreakerConfig
122
+
123
+ registry = ResilienceRegistry()
124
+ registry.register("payment-api", ResilienceConfig(
125
+ retry=RetryConfig(max_attempts=3),
126
+ circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
127
+ ))
128
+
129
+ @registry.decorator("payment-api")
130
+ async def charge_card(amount: float) -> dict:
131
+ ...
132
+
133
+ @registry.decorator("payment-api")
134
+ async def refund_card(amount: float) -> dict:
135
+ ...
136
+
137
+ # Both functions share the same circuit breaker —
138
+ # if charge_card trips the circuit, refund_card is also blocked
139
+ ```
140
+
141
+ ## Presets
142
+
143
+ Opinionated defaults for common integration patterns:
144
+
145
+ ```python
146
+ from pyresilience import resilient
147
+ from pyresilience.presets import http_policy, db_policy, queue_policy
148
+
149
+ @resilient(**http_policy())
150
+ def call_api(url: str) -> dict:
151
+ return requests.get(url).json()
152
+
153
+ @resilient(**db_policy())
154
+ def query_db(sql: str) -> list:
155
+ return cursor.execute(sql).fetchall()
156
+
157
+ @resilient(**queue_policy())
158
+ async def publish_message(msg: dict) -> None:
159
+ await producer.send(msg)
160
+ ```
161
+
162
+ ## Observability
163
+
164
+ ```python
165
+ from pyresilience import resilient, RetryConfig, JsonEventLogger, MetricsCollector
166
+
167
+ logger = JsonEventLogger()
168
+ metrics = MetricsCollector()
169
+
170
+ @resilient(retry=RetryConfig(max_attempts=3), listeners=[logger, metrics])
171
+ def monitored_call():
172
+ return do_work()
173
+
174
+ # After calls:
175
+ print(metrics.summary())
176
+ # {'total_events': 5, 'success_rate': 0.8, 'p99_latency': 1.23, ...}
177
+ ```
178
+
179
+ ## Documentation
180
+
181
+ Full docs at [pyresilience.readthedocs.io](https://pyresilience.readthedocs.io/)
182
+
183
+ ## License
184
+
185
+ MIT
@@ -0,0 +1,96 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pyresilience"
7
+ version = "0.1.0"
8
+ description = "Unified resilience patterns for Python — retry, circuit breaker, timeout, fallback, and bulkhead in one decorator."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ { name = "Ahsan Sheraz", email = "ahsansheraz@gmail.com" },
14
+ ]
15
+ keywords = [
16
+ "python", "resilience", "retry", "circuit-breaker", "timeout",
17
+ "fallback", "bulkhead", "fault-tolerance", "decorator", "async",
18
+ "reliability", "microservices", "distributed-systems",
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 3 - Alpha",
22
+ "Environment :: Console",
23
+ "Intended Audience :: Developers",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Operating System :: OS Independent",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Programming Language :: Python :: 3.13",
32
+ "Programming Language :: Python :: 3.14",
33
+ "Topic :: Software Development :: Libraries :: Python Modules",
34
+ "Topic :: System :: Networking",
35
+ "Typing :: Typed",
36
+ ]
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/AhsanSheraz/pyresilience"
40
+ Repository = "https://github.com/AhsanSheraz/pyresilience"
41
+ Issues = "https://github.com/AhsanSheraz/pyresilience/issues"
42
+ Documentation = "https://pyresilience.readthedocs.io/"
43
+ Changelog = "https://github.com/AhsanSheraz/pyresilience/blob/main/CHANGELOG.md"
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = ["src/pyresilience"]
47
+
48
+ [tool.hatch.build.targets.sdist]
49
+ include = ["src/pyresilience", "README.md", "LICENSE", "CHANGELOG.md"]
50
+
51
+ [project.optional-dependencies]
52
+ fast = [
53
+ "uvloop>=0.17.0; sys_platform != 'win32'",
54
+ "orjson>=3.9.0",
55
+ ]
56
+ dev = [
57
+ "pytest>=7.0",
58
+ "pytest-cov>=4.0",
59
+ "pytest-asyncio>=0.21.0",
60
+ "mypy>=1.0",
61
+ "ruff>=0.11.0",
62
+ ]
63
+
64
+ [tool.pytest.ini_options]
65
+ testpaths = ["tests"]
66
+ asyncio_mode = "auto"
67
+
68
+ [tool.mypy]
69
+ python_version = "3.9"
70
+ strict = true
71
+
72
+ [tool.ruff]
73
+ target-version = "py39"
74
+ line-length = 100
75
+ src = ["src", "tests"]
76
+
77
+ [tool.ruff.lint]
78
+ select = [
79
+ "E", # pycodestyle errors
80
+ "W", # pycodestyle warnings
81
+ "F", # pyflakes
82
+ "I", # isort
83
+ "UP", # pyupgrade
84
+ "B", # flake8-bugbear
85
+ "SIM", # flake8-simplify
86
+ "TCH", # flake8-type-checking
87
+ ]
88
+ ignore = [
89
+ "UP006", # Use `type` instead of `Type` (3.9 compat)
90
+ "UP007", # Use X | Y for union types (3.9 compat)
91
+ "UP035", # Import from `collections.abc` (3.9 compat)
92
+ "UP045", # Use X | None instead of Optional (3.9 compat)
93
+ ]
94
+
95
+ [tool.ruff.lint.isort]
96
+ known-first-party = ["pyresilience"]
@@ -0,0 +1,64 @@
1
+ """pyresilience — Unified resilience patterns for Python.
2
+
3
+ One decorator to combine retry, timeout, circuit breaker, fallback, and bulkhead.
4
+ Defines the full safety policy for a dependency, not just retries.
5
+ """
6
+
7
+ from pyresilience._bulkhead import BulkheadFullError
8
+ from pyresilience._cache import AsyncResultCache, ResultCache
9
+ from pyresilience._circuit_breaker import CircuitBreaker
10
+ from pyresilience._compat import has_orjson, has_uvloop, install_uvloop
11
+ from pyresilience._decorator import resilient
12
+ from pyresilience._logging import JsonEventLogger, MetricsCollector
13
+ from pyresilience._presets import db_policy, http_policy, queue_policy, strict_policy
14
+ from pyresilience._rate_limiter import AsyncRateLimiter, RateLimiter, RateLimitExceededError
15
+ from pyresilience._registry import ResilienceRegistry
16
+ from pyresilience._types import (
17
+ BulkheadConfig,
18
+ CacheConfig,
19
+ CircuitBreakerConfig,
20
+ CircuitState,
21
+ EventType,
22
+ FallbackConfig,
23
+ RateLimiterConfig,
24
+ ResilienceConfig,
25
+ ResilienceEvent,
26
+ ResilienceListener,
27
+ RetryConfig,
28
+ TimeoutConfig,
29
+ )
30
+
31
+ __version__ = "0.1.0"
32
+
33
+ __all__ = [
34
+ "AsyncRateLimiter",
35
+ "AsyncResultCache",
36
+ "BulkheadConfig",
37
+ "BulkheadFullError",
38
+ "CacheConfig",
39
+ "CircuitBreaker",
40
+ "CircuitBreakerConfig",
41
+ "CircuitState",
42
+ "EventType",
43
+ "FallbackConfig",
44
+ "JsonEventLogger",
45
+ "MetricsCollector",
46
+ "RateLimitExceededError",
47
+ "RateLimiter",
48
+ "RateLimiterConfig",
49
+ "ResilienceConfig",
50
+ "ResilienceEvent",
51
+ "ResilienceListener",
52
+ "ResilienceRegistry",
53
+ "ResultCache",
54
+ "RetryConfig",
55
+ "TimeoutConfig",
56
+ "db_policy",
57
+ "has_orjson",
58
+ "has_uvloop",
59
+ "http_policy",
60
+ "install_uvloop",
61
+ "queue_policy",
62
+ "resilient",
63
+ "strict_policy",
64
+ ]