Skip to content

Commit 8a8f7cf

Browse files
committed
Add example for base_http_client
1 parent 225399d commit 8a8f7cf

File tree

11 files changed

+173
-25
lines changed

11 files changed

+173
-25
lines changed

.pre-commit-config.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ default_language_version:
33

44
repos:
55
- repo: https://github.com/pre-commit/pre-commit-hooks
6-
rev: v4.6.0
6+
rev: v5.0.0
77
hooks:
88
- id: check-added-large-files
99
- id: check-ast
@@ -23,7 +23,7 @@ repos:
2323
- id: trailing-whitespace
2424

2525
- repo: https://github.com/astral-sh/ruff-pre-commit
26-
rev: v0.4.10
26+
rev: v0.7.2
2727
hooks:
2828
- id: ruff
2929
args: [--fix]

Makefile

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PROJECT_NAME = base_http_client
22

3-
develop:
3+
develop: clean_dev
44
python3.10 -m venv .venv
55
.venv/bin/pip install -U pip poetry
66
.venv/bin/poetry config virtualenvs.create false
@@ -21,4 +21,7 @@ mypy-ci: ##@Linting Run mypy
2121
mypy ./$(PROJECT_NAME) --config-file ./pyproject.toml
2222

2323
rst-ci: ##@Linting Run rst-lint
24-
rst-lint --encoding utf-8 README.rst
24+
rst-lint --encoding utf-8 README.rst
25+
26+
clean_dev:
27+
rm -rf .venv

README.rst

+50-14
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ Installing from PyPI_:
2626

2727
.. code-block:: bash
2828
29-
pip3 install base-http-client
29+
pip install base-http-client
3030
3131
Installing from github.com:
3232

3333
.. code-block:: bash
3434
35-
pip3 install git+https://github.com/andy-takker/base_http_client
35+
pip install git+https://github.com/andy-takker/base_http_client
3636
3737
The package contains several extras and you can install additional dependencies
3838
if you specify them in this way.
@@ -45,18 +45,52 @@ For example, with msgspec_:
4545
4646
Complete table of extras below:
4747

48-
+-----------------------------------------------+----------------------------------+
49-
| example | description |
50-
+===============================================+==================================+
51-
| ``pip3 install "base-http-client[msgspec]"`` | For using msgspec_ structs |
52-
+-----------------------------------------------+----------------------------------+
53-
| ``pip3 install "base-http-client[orjson]"`` | For fast parsing json by orjson_ |
54-
+-----------------------------------------------+----------------------------------+
55-
| ``pip3 install "base-http-client[pydantic]"`` | For using pydantic_ models |
56-
+-----------------------------------------------+----------------------------------+
48+
+----------------------------------------------+----------------------------------+
49+
| example | description |
50+
+==============================================+==================================+
51+
| ``pip install "base-http-client[msgspec]"`` | For using msgspec_ structs |
52+
+----------------------------------------------+----------------------------------+
53+
| ``pip install "base-http-client[orjson]"`` | For fast parsing json by orjson_ |
54+
+----------------------------------------------+----------------------------------+
55+
| ``pip install "base-http-client[pydantic]"`` | For using pydantic_ models |
56+
+----------------------------------------------+----------------------------------+
5757

58-
Using
59-
~~~~~
58+
Quick start guide
59+
-----------------
60+
61+
BaseHttpClient
62+
~~~~~~~~~~~~~~
63+
64+
Simple HTTP Client for `https://catfact.ninja`. See full example in `examples/base_http_client.py`_
65+
66+
.. code-block:: python
67+
68+
from base_http_client.client import (
69+
DEFAULT_TIMEOUT,
70+
BaseHttpClient,
71+
ResponseHandlersType,
72+
)
73+
from base_http_client.handlers.pydantic import parse_model
74+
from base_http_client.timeout import TimeoutType
75+
76+
77+
class CatfactClient(BaseHttpClient):
78+
RANDOM_CATFACT_HANDLERS: ResponseHandlersType = MappingProxyType(
79+
{
80+
HTTPStatus.OK: parse_model(CatfactSchema),
81+
}
82+
)
83+
84+
async def fetch_random_cat_fact(
85+
self,
86+
timeout: TimeoutType = DEFAULT_TIMEOUT,
87+
) -> CatfactSchema:
88+
return await self._make_req(
89+
method=hdrs.METH_GET,
90+
url=self._url / "fact",
91+
handlers=self.RANDOM_CATFACT_HANDLERS,
92+
timeout=timeout,
93+
)
6094
6195
6296
@@ -65,4 +99,6 @@ Using
6599
.. _aiohttp: https://pypi.org/project/aiohttp/
66100
.. _msgspec: https://github.com/jcrist/msgspec
67101
.. _orjson: https://github.com/ijl/orjson
68-
.. _pydantic: https://github.com/pydantic/pydantic
102+
.. _pydantic: https://github.com/pydantic/pydantic
103+
104+
.. _examples/base_http_client.py: https://github.com/andy-takker/base_http_client/blob/master/examples/base_http_client.py

base_http_client/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from base_http_client.client import BaseHttpClient
2-
from base_http_client.timeout import TimeoutType
32
from base_http_client.handlers.base import ResponseHandlersType
3+
from base_http_client.timeout import TimeoutType
44

55
__all__ = ("BaseHttpClient", "TimeoutType", "ResponseHandlersType")

base_http_client/client.py

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
ResponseHandlersType,
99
apply_handler,
1010
)
11+
1112
from .timeout import TimeoutType, get_timeout
1213

1314

base_http_client/handlers/json.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44

55
from aiohttp import ClientResponse
66

7-
87
try:
98
import orjson as json
109
except ImportError:
1110
import json # type: ignore
1211

1312

14-
def json_parser(
13+
def parse_json(
1514
parser: Callable,
1615
loads: Callable = json.loads,
1716
) -> Callable[[ClientResponse], Awaitable[Any]]:

base_http_client/handlers/msgspec.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
T = TypeVar("T", bound=Struct)
99

1010

11-
def struct_parser(struct: type[T]) -> Callable[[ClientResponse], Awaitable[T]]:
11+
def parse_struct(struct: type[T]) -> Callable[[ClientResponse], Awaitable[T]]:
1212
async def _parse(response: ClientResponse) -> T:
1313
return decode(await response.read(), type=struct)
1414

base_http_client/handlers/pydantic.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
T = TypeVar("T", bound=BaseModel)
88

99

10-
def model_parser(model: type[T]) -> Callable[[ClientResponse], Awaitable[T]]:
10+
def parse_model(model: type[T]) -> Callable[[ClientResponse], Awaitable[T]]:
1111
async def _parse(response: ClientResponse) -> T:
1212
return model.model_validate_json(await response.read())
1313

examples/base_http_client.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import asyncio
2+
from http import HTTPStatus
3+
from types import MappingProxyType
4+
5+
from aiohttp import ClientSession, hdrs
6+
from pydantic import BaseModel
7+
8+
from base_http_client.client import (
9+
DEFAULT_TIMEOUT,
10+
BaseHttpClient,
11+
ResponseHandlersType,
12+
)
13+
from base_http_client.handlers.pydantic import parse_model
14+
from base_http_client.timeout import TimeoutType
15+
16+
17+
class CatfactSchema(BaseModel):
18+
fact: str
19+
length: int
20+
21+
22+
class CatfactClient(BaseHttpClient):
23+
RANDOM_CATFACT_HANDLERS: ResponseHandlersType = MappingProxyType(
24+
{
25+
HTTPStatus.OK: parse_model(CatfactSchema),
26+
}
27+
)
28+
29+
async def fetch_random_cat_fact(
30+
self,
31+
timeout: TimeoutType = DEFAULT_TIMEOUT,
32+
) -> CatfactSchema:
33+
return await self._make_req(
34+
method=hdrs.METH_GET,
35+
url=self._url / "fact",
36+
handlers=self.RANDOM_CATFACT_HANDLERS,
37+
timeout=timeout,
38+
)
39+
40+
41+
async def main() -> None:
42+
async with ClientSession() as session:
43+
client = CatfactClient(session=session, url="https://catfact.ninja")
44+
fact = await client.fetch_random_cat_fact()
45+
print(fact) # noqa: T201
46+
47+
48+
if __name__ == "__main__":
49+
asyncio.run(main())

pyproject.toml

+61-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "base-http-client"
3-
version = "0.2.5"
3+
version = "0.2.6"
44
description = "Typical HTTP Client based on aiohttp"
55
authors = ["Sergey Natalenko <[email protected]>"]
66
license = "MIT"
@@ -35,6 +35,7 @@ packages = [
3535

3636
[tool.poetry.urls]
3737
"Source" = "https://github.com/andy-takker/base_http_client"
38+
"Bug Tracker" = "https://github.com/andy-takker/base_http_client/issues"
3839

3940
[tool.poetry.dependencies]
4041
python = "^3.10"
@@ -60,6 +61,65 @@ pytest = "^8.3.3"
6061
requires = ["poetry-core"]
6162
build-backend = "poetry.core.masonry.api"
6263

64+
[tool.pytest.ini_options]
65+
asyncio_mode = "auto"
66+
python_files = "test_*"
67+
python_functions = "test_*"
68+
python_classes = "TestSuite*"
69+
addopts = "-p no:cacheprovider"
70+
71+
[tool.coverage.run]
72+
branch = true
73+
source = ["base_http_client", "test_http_service"]
74+
command_line = "-m pytest"
75+
76+
[tool.coverage.report]
77+
show_missing = true
78+
79+
[tool.coverage.xml]
80+
output = "coverage.xml"
81+
82+
[tool.ruff]
83+
line-length = 88
84+
exclude = [
85+
".git",
86+
".mypy_cache",
87+
".ruff_cache",
88+
".venv",
89+
]
90+
indent-width = 4
91+
target-version = "py310"
92+
93+
[tool.ruff.format]
94+
quote-style = "double"
95+
indent-style = "space"
96+
97+
[tool.ruff.lint]
98+
select = [
99+
"BLE",
100+
"C90",
101+
"E",
102+
"F",
103+
"G",
104+
"I",
105+
"ICN",
106+
"ISC",
107+
"PLE",
108+
"Q",
109+
"RUF006",
110+
"RUF100",
111+
"T10",
112+
"T20",
113+
"TID",
114+
"UP",
115+
"W",
116+
]
117+
ignore = ["ISC001"]
118+
fixable = ["ALL"]
119+
120+
[tool.ruff.lint.isort]
121+
known-first-party = ["base_http_client", "test_http_service", "tests"]
122+
63123
[tool.mypy]
64124
plugins = ["pydantic.mypy"]
65125
check_untyped_defs = true

test_http_service/service.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
from aiohttp.test_utils import TestServer
66
from aiohttp.web_app import Application
77

8-
from test_http_service.models import MockRoute, MockService
98
from test_http_service.handlers import get_default_handler
9+
from test_http_service.models import MockRoute, MockService
1010

1111

1212
@asynccontextmanager

0 commit comments

Comments
 (0)