httpware 0.1.0__tar.gz → 0.3.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.
- httpware-0.3.0/PKG-INFO +84 -0
- httpware-0.3.0/README.md +53 -0
- {httpware-0.1.0 → httpware-0.3.0}/pyproject.toml +6 -16
- {httpware-0.1.0 → httpware-0.3.0}/src/httpware/__init__.py +1 -18
- {httpware-0.1.0 → httpware-0.3.0}/src/httpware/_internal/import_checker.py +1 -0
- httpware-0.3.0/src/httpware/client.py +675 -0
- httpware-0.3.0/src/httpware/decoders/pydantic.py +44 -0
- httpware-0.3.0/src/httpware/errors.py +138 -0
- httpware-0.3.0/src/httpware/middleware/__init__.py +77 -0
- httpware-0.3.0/src/httpware/middleware/chain.py +31 -0
- httpware-0.1.0/PKG-INFO +0 -94
- httpware-0.1.0/README.md +0 -62
- httpware-0.1.0/src/httpware/_internal/chain.py +0 -39
- httpware-0.1.0/src/httpware/client.py +0 -620
- httpware-0.1.0/src/httpware/config.py +0 -40
- httpware-0.1.0/src/httpware/decoders/pydantic.py +0 -29
- httpware-0.1.0/src/httpware/errors.py +0 -194
- httpware-0.1.0/src/httpware/middleware/__init__.py +0 -89
- httpware-0.1.0/src/httpware/request.py +0 -55
- httpware-0.1.0/src/httpware/response.py +0 -69
- httpware-0.1.0/src/httpware/transports/__init__.py +0 -27
- httpware-0.1.0/src/httpware/transports/httpx2.py +0 -180
- httpware-0.1.0/src/httpware/transports/recorded.py +0 -84
- {httpware-0.1.0 → httpware-0.3.0}/src/httpware/_internal/__init__.py +0 -0
- {httpware-0.1.0 → httpware-0.3.0}/src/httpware/decoders/__init__.py +0 -0
- {httpware-0.1.0 → httpware-0.3.0}/src/httpware/decoders/msgspec.py +0 -0
- {httpware-0.1.0 → httpware-0.3.0}/src/httpware/py.typed +0 -0
httpware-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: httpware
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Resilience-first async HTTP client framework for Python
|
|
5
|
+
Keywords: http,async,client,resilience,retry,circuit-breaker,middleware,httpx,pydantic
|
|
6
|
+
Author: Artur Shiriev
|
|
7
|
+
Author-email: Artur Shiriev <me@shiriev.ru>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
16
|
+
Classifier: Framework :: AsyncIO
|
|
17
|
+
Requires-Dist: httpx2>=2.0.0,<3.0
|
|
18
|
+
Requires-Dist: httpware[pydantic,msgspec,otel] ; extra == 'all'
|
|
19
|
+
Requires-Dist: msgspec>=0.18 ; extra == 'msgspec'
|
|
20
|
+
Requires-Dist: opentelemetry-api>=1.20 ; extra == 'otel'
|
|
21
|
+
Requires-Dist: opentelemetry-sdk>=1.20 ; extra == 'otel'
|
|
22
|
+
Requires-Dist: pydantic>=2.0,<3.0 ; extra == 'pydantic'
|
|
23
|
+
Requires-Python: >=3.11, <4
|
|
24
|
+
Project-URL: repository, https://github.com/modern-python/httpware
|
|
25
|
+
Project-URL: docs, https://httpware.readthedocs.io
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Provides-Extra: msgspec
|
|
28
|
+
Provides-Extra: otel
|
|
29
|
+
Provides-Extra: pydantic
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# httpware
|
|
33
|
+
|
|
34
|
+
[](https://github.com/modern-python/httpware/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/httpware/)
|
|
36
|
+
[](https://pypi.org/project/httpware/)
|
|
37
|
+
[](https://opensource.org/licenses/MIT)
|
|
38
|
+
|
|
39
|
+
**Async HTTP client framework for Python.**
|
|
40
|
+
|
|
41
|
+
`httpware` is a thin opinionated wrapper around `httpx2`. It re-exports `httpx2.Request`/`httpx2.Response`, adds a middleware chain composed at client construction, supports opt-in typed response decoding (pydantic and msgspec are both extras), and raises a status-keyed exception tree automatically on 4xx/5xx.
|
|
42
|
+
|
|
43
|
+
> **Status:** Pre-1.0 (0.3.0). Public API is subject to change between minor releases until v1.0. Resilience middleware (retry / timeout / bulkhead), streaming, and observability are not yet shipped.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install httpware # core only — no decoder
|
|
49
|
+
pip install httpware[pydantic] # + PydanticDecoder (the default-decoder path)
|
|
50
|
+
pip install httpware[msgspec] # + MsgspecDecoder
|
|
51
|
+
pip install httpware[all] # everything declared above (pydantic, msgspec, otel)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`AsyncClient()` with no `decoder=` argument defaults to constructing a `PydanticDecoder`; that path requires the `pydantic` extra and raises `ImportError` at `AsyncClient.__init__` if it is missing. The `otel` extra is declared but the OpenTelemetry middleware (Epic 5) has not shipped yet.
|
|
55
|
+
|
|
56
|
+
## Quickstart
|
|
57
|
+
|
|
58
|
+
> Requires: `pip install httpware[pydantic]`
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from httpware import AsyncClient
|
|
62
|
+
from pydantic import BaseModel
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class User(BaseModel):
|
|
66
|
+
id: int
|
|
67
|
+
name: str
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
async def main() -> None:
|
|
71
|
+
async with AsyncClient(base_url="https://api.example.com") as client:
|
|
72
|
+
user = await client.get("/users/1", response_model=User)
|
|
73
|
+
print(user.name)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 📚 [Documentation](https://httpware.readthedocs.io)
|
|
77
|
+
|
|
78
|
+
## 📦 [PyPI](https://pypi.org/project/httpware)
|
|
79
|
+
|
|
80
|
+
## 📝 [License](./LICENSE)
|
|
81
|
+
|
|
82
|
+
## Part of `modern-python`
|
|
83
|
+
|
|
84
|
+
Browse the full list of templates and libraries in [`modern-python`](https://github.com/modern-python) — see the org profile for the categorized index.
|
httpware-0.3.0/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# httpware
|
|
2
|
+
|
|
3
|
+
[](https://github.com/modern-python/httpware/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/httpware/)
|
|
5
|
+
[](https://pypi.org/project/httpware/)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
**Async HTTP client framework for Python.**
|
|
9
|
+
|
|
10
|
+
`httpware` is a thin opinionated wrapper around `httpx2`. It re-exports `httpx2.Request`/`httpx2.Response`, adds a middleware chain composed at client construction, supports opt-in typed response decoding (pydantic and msgspec are both extras), and raises a status-keyed exception tree automatically on 4xx/5xx.
|
|
11
|
+
|
|
12
|
+
> **Status:** Pre-1.0 (0.3.0). Public API is subject to change between minor releases until v1.0. Resilience middleware (retry / timeout / bulkhead), streaming, and observability are not yet shipped.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install httpware # core only — no decoder
|
|
18
|
+
pip install httpware[pydantic] # + PydanticDecoder (the default-decoder path)
|
|
19
|
+
pip install httpware[msgspec] # + MsgspecDecoder
|
|
20
|
+
pip install httpware[all] # everything declared above (pydantic, msgspec, otel)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`AsyncClient()` with no `decoder=` argument defaults to constructing a `PydanticDecoder`; that path requires the `pydantic` extra and raises `ImportError` at `AsyncClient.__init__` if it is missing. The `otel` extra is declared but the OpenTelemetry middleware (Epic 5) has not shipped yet.
|
|
24
|
+
|
|
25
|
+
## Quickstart
|
|
26
|
+
|
|
27
|
+
> Requires: `pip install httpware[pydantic]`
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from httpware import AsyncClient
|
|
31
|
+
from pydantic import BaseModel
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class User(BaseModel):
|
|
35
|
+
id: int
|
|
36
|
+
name: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def main() -> None:
|
|
40
|
+
async with AsyncClient(base_url="https://api.example.com") as client:
|
|
41
|
+
user = await client.get("/users/1", response_model=User)
|
|
42
|
+
print(user.name)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 📚 [Documentation](https://httpware.readthedocs.io)
|
|
46
|
+
|
|
47
|
+
## 📦 [PyPI](https://pypi.org/project/httpware)
|
|
48
|
+
|
|
49
|
+
## 📝 [License](./LICENSE)
|
|
50
|
+
|
|
51
|
+
## Part of `modern-python`
|
|
52
|
+
|
|
53
|
+
Browse the full list of templates and libraries in [`modern-python`](https://github.com/modern-python) — see the org profile for the categorized index.
|
|
@@ -26,27 +26,26 @@ classifiers = [
|
|
|
26
26
|
"Topic :: Internet :: WWW/HTTP",
|
|
27
27
|
"Framework :: AsyncIO",
|
|
28
28
|
]
|
|
29
|
-
version = "0.
|
|
29
|
+
version = "0.3.0"
|
|
30
30
|
dependencies = [
|
|
31
31
|
"httpx2>=2.0.0,<3.0",
|
|
32
|
-
"pydantic>=2.0,<3.0",
|
|
33
32
|
]
|
|
34
33
|
|
|
35
34
|
[project.optional-dependencies]
|
|
35
|
+
pydantic = ["pydantic>=2.0,<3.0"]
|
|
36
36
|
msgspec = ["msgspec>=0.18"]
|
|
37
37
|
otel = [
|
|
38
38
|
"opentelemetry-api>=1.20",
|
|
39
39
|
"opentelemetry-sdk>=1.20",
|
|
40
40
|
]
|
|
41
|
-
|
|
42
|
-
all = ["httpware[msgspec,otel,niquests]"]
|
|
41
|
+
all = ["httpware[pydantic,msgspec,otel]"]
|
|
43
42
|
|
|
44
43
|
[project.urls]
|
|
45
44
|
repository = "https://github.com/modern-python/httpware"
|
|
46
45
|
docs = "https://httpware.readthedocs.io"
|
|
47
46
|
|
|
48
47
|
[build-system]
|
|
49
|
-
requires = ["uv_build>=0.11,<0
|
|
48
|
+
requires = ["uv_build>=0.11,<1.0"]
|
|
50
49
|
build-backend = "uv_build"
|
|
51
50
|
|
|
52
51
|
[tool.uv.build-backend]
|
|
@@ -74,7 +73,6 @@ fix = true
|
|
|
74
73
|
unsafe-fixes = true
|
|
75
74
|
line-length = 120
|
|
76
75
|
target-version = "py311"
|
|
77
|
-
extend-exclude = ["docs"]
|
|
78
76
|
|
|
79
77
|
[tool.ruff.lint]
|
|
80
78
|
select = ["ALL"]
|
|
@@ -90,24 +88,16 @@ ignore = [
|
|
|
90
88
|
]
|
|
91
89
|
isort.lines-after-imports = 2
|
|
92
90
|
isort.no-lines-before = ["standard-library", "local-folder"]
|
|
93
|
-
pylint.max-args = 10 # HTTP-method APIs are kwarg-rich (headers, params, cookies, timeout, json, content, response_model, …); default 5 is too strict.
|
|
94
91
|
|
|
95
92
|
[tool.ruff.lint.per-file-ignores]
|
|
96
|
-
|
|
97
|
-
# not asyncio.timeout territory. The rule fires on 24+ method signatures in this one file with
|
|
98
|
-
# the same false-positive justification; per-file disable is cleaner than 24 per-line noqa.
|
|
99
|
-
"src/httpware/client.py" = ["ASYNC109"]
|
|
93
|
+
"src/httpware/client.py" = ["ASYNC109", "ANN401"]
|
|
100
94
|
|
|
101
95
|
[tool.pytest.ini_options]
|
|
102
|
-
addopts = "--cov
|
|
96
|
+
addopts = "--cov=. --cov-report term-missing --cov-fail-under=100"
|
|
103
97
|
asyncio_mode = "auto"
|
|
104
98
|
pythonpath = ["src"]
|
|
105
99
|
asyncio_default_fixture_loop_scope = "function"
|
|
106
|
-
markers = [
|
|
107
|
-
"perf: assertive performance tests (skipped by default; run with `pytest -m perf`)",
|
|
108
|
-
]
|
|
109
100
|
|
|
110
101
|
[tool.coverage]
|
|
111
102
|
run.concurrency = ["thread"]
|
|
112
|
-
run.omit = ["benchmarks/*"]
|
|
113
103
|
report.exclude_also = ["if typing.TYPE_CHECKING:"]
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
"""httpware —
|
|
1
|
+
"""httpware — thin async HTTP client wrapper over httpx2."""
|
|
2
2
|
|
|
3
3
|
from httpware.client import AsyncClient
|
|
4
|
-
from httpware.config import ClientConfig, Limits, Timeout
|
|
5
4
|
from httpware.decoders import ResponseDecoder
|
|
6
|
-
from httpware.decoders.pydantic import PydanticDecoder
|
|
7
5
|
from httpware.errors import (
|
|
8
6
|
STATUS_TO_EXCEPTION,
|
|
9
7
|
BadRequestError,
|
|
@@ -23,41 +21,26 @@ from httpware.errors import (
|
|
|
23
21
|
UnprocessableEntityError,
|
|
24
22
|
)
|
|
25
23
|
from httpware.middleware import Middleware, Next, after_response, before_request, on_error
|
|
26
|
-
from httpware.request import Request
|
|
27
|
-
from httpware.response import Response, StreamResponse
|
|
28
|
-
from httpware.transports import Transport
|
|
29
|
-
from httpware.transports.httpx2 import Httpx2Transport
|
|
30
|
-
from httpware.transports.recorded import RecordedTransport
|
|
31
24
|
|
|
32
25
|
|
|
33
26
|
__all__ = [
|
|
34
27
|
"STATUS_TO_EXCEPTION",
|
|
35
28
|
"AsyncClient",
|
|
36
29
|
"BadRequestError",
|
|
37
|
-
"ClientConfig",
|
|
38
30
|
"ClientError",
|
|
39
31
|
"ClientStatusError",
|
|
40
32
|
"ConflictError",
|
|
41
33
|
"ForbiddenError",
|
|
42
|
-
"Httpx2Transport",
|
|
43
34
|
"InternalServerError",
|
|
44
|
-
"Limits",
|
|
45
35
|
"Middleware",
|
|
46
36
|
"Next",
|
|
47
37
|
"NotFoundError",
|
|
48
|
-
"PydanticDecoder",
|
|
49
38
|
"RateLimitedError",
|
|
50
|
-
"RecordedTransport",
|
|
51
|
-
"Request",
|
|
52
|
-
"Response",
|
|
53
39
|
"ResponseDecoder",
|
|
54
40
|
"ServerStatusError",
|
|
55
41
|
"ServiceUnavailableError",
|
|
56
42
|
"StatusError",
|
|
57
|
-
"StreamResponse",
|
|
58
|
-
"Timeout",
|
|
59
43
|
"TimeoutError",
|
|
60
|
-
"Transport",
|
|
61
44
|
"TransportError",
|
|
62
45
|
"UnauthorizedError",
|
|
63
46
|
"UnprocessableEntityError",
|