Skip to content

Commit 92ddf76

Browse files
📝 Add docstrings.
1 parent 0fdd3a9 commit 92ddf76

File tree

5 files changed

+111
-16
lines changed

5 files changed

+111
-16
lines changed

src/lapidary/runtime/annotations.py

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,51 @@
1010

1111

1212
class WebArg(abc.ABC):
13-
pass
13+
"""Base class for web-processed parameters."""
1414

1515

1616
@dc.dataclass
1717
class Body(WebArg):
18+
"""
19+
Link content type headers with a python type.
20+
When used with a method parameter, it tells lapidary what content-type header to send for a given body type.
21+
When used in return annotation, it tells lapidary the type to process the response body as.
22+
23+
Example use with parameter:
24+
25+
```python
26+
body: Body({'application/json': BodyModel})
27+
```
28+
"""
29+
1830
content: Mapping[MimeType, type]
1931

2032

2133
class Metadata(WebArg):
22-
"""Annotation for models that hold other WebArg fields"""
34+
"""
35+
Annotation for models that hold other WebArg fields.
36+
Can be used to group request parameters as an alternative to passing parameters directly.
37+
38+
Example:
39+
```python
40+
class RequestMetadata(pydantic.BaseModel):
41+
my_header: typing.Annotated[
42+
str,
43+
Header('my-header'),
44+
]
45+
46+
class Client(ApiClient):
47+
@get(...)
48+
async def my_method(
49+
headers: Annotated[RequestMetadata, Metadata]
50+
):
51+
```
52+
"""
2353

2454

2555
class Param(WebArg, abc.ABC):
56+
"""Base class for web parameters (headers, query and path parameters, including cookies)"""
57+
2658
style: typing.Any
2759
alias: typing.Optional[str]
2860

@@ -31,13 +63,19 @@ def __init__(self, alias: typing.Optional[str], /) -> None:
3163

3264

3365
class Header(Param):
66+
"""Mark parameter as HTTP Header"""
67+
3468
def __init__(
3569
self,
3670
alias: typing.Optional[str] = None,
3771
/,
3872
*,
3973
style: type[MultimapSerializationStyle] = SimpleMultimap,
4074
) -> None:
75+
"""
76+
:param alias: Header name, if different than the name of the annotated parameter
77+
:param style: Serialization style
78+
"""
4179
super().__init__(alias)
4280
self.style = style
4381

@@ -50,6 +88,10 @@ def __init__(
5088
*,
5189
style: type[MultimapSerializationStyle] = FormExplode,
5290
) -> None:
91+
"""
92+
:param alias: Cookie name, if different than the name of the annotated parameter
93+
:param style: Serialization style
94+
"""
5395
super().__init__(alias)
5496
self.style = style
5597

@@ -62,6 +104,10 @@ def __init__(
62104
*,
63105
style: type[StringSerializationStyle] = SimpleString,
64106
) -> None:
107+
"""
108+
:param alias: Path parameter name, if different than the name of the annotated parameter
109+
:param style: Serialization style
110+
"""
65111
super().__init__(alias)
66112
self.style = style
67113

@@ -74,6 +120,10 @@ def __init__(
74120
*,
75121
style: type[MultimapSerializationStyle] = FormExplode,
76122
) -> None:
123+
"""
124+
:param alias: Query parameter name, if different than the name of the annotated parameter
125+
:param style: Serialization style
126+
"""
77127
super().__init__(alias)
78128
self.style = style
79129

@@ -95,4 +145,28 @@ class Response:
95145

96146
@dc.dataclass
97147
class Responses(WebArg):
148+
"""
149+
Mapping between response code, headers, media type and body type.
150+
The simplified structure is:
151+
152+
response code => (
153+
body: content type => body model type
154+
headers model
155+
)
156+
157+
The structure follows OpenAPI 3.
158+
"""
159+
98160
responses: Mapping[StatusCodeRange, Response]
161+
"""
162+
Map of status code match to Response.
163+
Key may be:
164+
165+
- any HTTP status code
166+
- HTTP status code range, i.e. 1XX, 2XX, etc
167+
- "default"
168+
169+
The most specific value takes precedence.
170+
171+
Value is [Body][lapidary.runtime.Body]
172+
"""

src/lapidary/runtime/client_base.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,21 @@ def lapidary_user_agent() -> str:
2626

2727

2828
class ClientBase(abc.ABC):
29+
"""Base for Client classes"""
30+
2931
def __init__(
3032
self,
3133
security: Iterable[SecurityRequirements] | None = None,
3234
session_factory: SessionFactory = httpx.AsyncClient,
3335
middlewares: Sequence[HttpxMiddleware] = (),
3436
**httpx_kwargs: typing.Unpack[ClientArgs],
3537
) -> None:
38+
"""
39+
:param security: Security requirements as a mapping of name => list of scopes
40+
:param session_factory: `httpx.AsyncClient` or a subclass type
41+
:param middlewares: list of middlewares to process HTTP requests and responses
42+
:param httpx_kwargs: keyword arguments to pass to session_factory
43+
"""
3644
self._client = session_factory(**httpx_kwargs)
3745
if USER_AGENT not in self._client.headers:
3846
self._client.headers[USER_AGENT] = lapidary_user_agent()
@@ -53,7 +61,10 @@ async def __aexit__(
5361
return await self._client.__aexit__(exc_type, exc_value, traceback)
5462

5563
def lapidary_authenticate(self, *auth_args: NamedAuth, **auth_kwargs: httpx.Auth) -> None:
56-
"""Register named Auth instances for future use with methods that require authentication."""
64+
"""
65+
Register named Auth instances for future use with methods that require authentication.
66+
Accepts named [`Auth`][httpx.Auth] as tuples name, auth or as named arguments
67+
"""
5768
if auth_args:
5869
# make python complain about duplicate names
5970
self.lapidary_authenticate(**dict(auth_args), **auth_kwargs)

src/lapidary/runtime/middleware.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,19 @@
77

88

99
class HttpxMiddleware(Generic[State]):
10+
"""
11+
Base class for HTTP middleware.
12+
"""
13+
1014
@abc.abstractmethod
1115
async def handle_request(self, request: httpx.Request) -> State:
12-
pass
16+
"""Called for each request after it's generated for a method call but before it's sent to the remote server.
17+
Any returned value will be passed back to handle_response.
18+
"""
1319

1420
async def handle_response(self, response: httpx.Response, request: httpx.Request, state: State) -> None:
15-
pass
21+
"""Called for each response after it's been received from the remote server and before it's converted to the return type as defined
22+
in the python method.
23+
24+
state is the value returned by handle_request
25+
"""

src/lapidary/runtime/model/error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def __init__(self, status_code: int, headers: Headers, body: Body):
3737

3838

3939
class UnexpectedResponse(LapidaryResponseError):
40-
"""Base error class for undeclared responses"""
40+
"""Raised when the remote server responded with code and content-type pair that wasn't declared in the method return annotation"""
4141

4242
def __init__(self, response: httpx.Response):
4343
self.response = response

src/lapidary/runtime/paging.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def iter_pages(
1414
get_cursor: Callable[[R], Optional[C]],
1515
) -> Callable[P, AsyncIterable[R]]:
1616
"""
17-
Create a function that returns an async iterator over pages from the async operation function :param:`fn`.
17+
Take a function that returns a pageg response and return a function that returns an async iterator that iterates over the pages.
1818
1919
The returned function can be called with the same parameters as :param:`fn` (except for the cursor parameter),
2020
and returns an async iterator that yields results from :param:`fn`, handling pagination automatically.
@@ -24,19 +24,19 @@ def iter_pages(
2424
2525
**Example:**
2626
27-
.. code:: python
28-
29-
async for page in iter_pages(client.fn, 'cursor', extractor_fn)(parameter=value):
30-
# Process page
27+
```python
28+
async for page in iter_pages(client.fn, 'cursor', extractor_fn)(parameter=value):
29+
# Process page
30+
```
3131
3232
Typically, an API will use the same paging pattern for all operations supporting it, so it's a good idea to write a shortcut function:
3333
34-
.. code:: python
35-
36-
from lapidary.runtime import iter_pages as _iter_pages
34+
```python
35+
from lapidary.runtime import iter_pages as _iter_pages
3736
38-
def iter_pages[P, R](fn: Callable[P, Awaitable[R]]) -> Callable[P, AsyncIterable[R]]:
39-
return _iter_pages(fn, 'cursor', lambda result: ...)
37+
def iter_pages[P, R](fn: Callable[P, Awaitable[R]]) -> Callable[P, AsyncIterable[R]]:
38+
return _iter_pages(fn, 'cursor', lambda result: ...)
39+
```
4040
4141
:param fn: An async function that retrieves a page of data.
4242
:param cursor_param_name: The name of the cursor parameter in :param:`fn`.

0 commit comments

Comments
 (0)