Skip to content

Commit 2d2f98a

Browse files
authored
🚚 Rename Root annotation to FullPayload (#217)
2 parents b5deaac + de9b806 commit 2d2f98a

8 files changed

Lines changed: 37 additions & 37 deletions

File tree

docs/integrations/fastapi_and_pydantic.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ As long as Pydantic is installed in your environment, Repid will automatically s
5252
`PydanticConverter`. This means any type hints you use in your actor signature will be strictly
5353
validated, and you can use `pydantic.Field` for defaults and aliases.
5454

55-
For detailed examples on defining actors with Pydantic validation and using the `Root()` dependency
55+
For detailed examples on defining actors with Pydantic validation and using the `FullPayload()` dependency
5656
annotation, see the [Actors guide](../user_guide/actors/parsing.md#parsing-with-pydantic).
5757

5858
## Integration with FastAPI

docs/user_guide/actors/parsing.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,29 +78,29 @@ async def process_order(
7878
pass
7979
```
8080

81-
### The `Root()` Annotation
81+
### The `FullPayload()` Annotation
8282

8383
Sometimes you don't want your JSON payload's keys scattered as individual arguments. If you want to
84-
accept an entire Pydantic model representing the exact root JSON payload, you can use the `Root`
84+
accept an entire Pydantic model representing the exact root JSON payload, you can use the `FullPayload`
8585
annotation:
8686

8787
```python
8888
from typing import Annotated
8989
from pydantic import BaseModel
90-
from repid import Root
90+
from repid import FullPayload
9191

9292
class UserPayload(BaseModel):
9393
user_id: int
9494
is_active: bool
9595

9696
@router.actor
97-
async def process_user(user: Annotated[UserPayload, Root()]):
97+
async def process_user(user: Annotated[UserPayload, FullPayload()]):
9898
# `user` contains the fully validated payload model
9999
print(user.user_id)
100100
```
101101

102102
!!! tip
103-
`Root()` is only available when Pydantic is installed.
103+
`FullPayload()` is only available when Pydantic is installed.
104104

105105
## Extracting Headers
106106

repid/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
from .converter import PydanticConverter as PydanticConverter
99
from .data import * # noqa: F403
1010
from .dependencies import Depends as Depends
11+
from .dependencies import FullPayload as FullPayload
1112
from .dependencies import Header as Header
1213
from .dependencies import Message as Message
1314
from .dependencies import MessageDependency as MessageDependency
14-
from .dependencies import Root as Root
1515
from .health_check_server import HealthCheckServer as HealthCheckServer
1616
from .health_check_server import HealthCheckServerSettings as HealthCheckServerSettings
1717
from .health_check_server import HealthCheckStatus as HealthCheckStatus

repid/converter.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from repid._utils import is_installed
1111
from repid.data import ConverterInputSchema
12-
from repid.dependencies._utils import DependencyContext, get_dependency, get_root_marker
12+
from repid.dependencies._utils import DependencyContext, get_dependency, get_full_payload_marker
1313
from repid.dependencies.depends import Depends as DependsClass
1414
from repid.dependencies.header_dependency import Header
1515

@@ -154,8 +154,8 @@ def __init__(
154154
inspect.Parameter.POSITIONAL_OR_KEYWORD,
155155
inspect.Parameter.KEYWORD_ONLY,
156156
):
157-
if get_root_marker(p.annotation) is not None:
158-
raise ValueError("Root() requires PydanticConverter.")
157+
if get_full_payload_marker(p.annotation) is not None:
158+
raise ValueError("FullPayload() requires PydanticConverter.")
159159
if (dep := get_dependency(p.annotation)) is not None:
160160
self.dependency_kwargs[p.name] = dep
161161
continue
@@ -306,9 +306,9 @@ def _parse_signature(
306306
if p.kind in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
307307
if (dep := get_dependency(p.annotation)) is not None:
308308
dependency_kwargs[p.name] = dep
309-
elif get_root_marker(p.annotation) is not None:
309+
elif get_full_payload_marker(p.annotation) is not None:
310310
if root_arg is not None:
311-
raise ValueError("Only one Root() marker is allowed per actor.")
311+
raise ValueError("Only one FullPayload() marker is allowed per actor.")
312312
root_arg = (p.name, get_args(p.annotation)[0])
313313
else:
314314
kwargs.append(p.name)

repid/dependencies/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from ._utils import DependencyContext as DependencyContext
22
from ._utils import DependencyT as DependencyT
33
from ._utils import get_dependency as get_dependency
4-
from ._utils import get_root_marker as get_root_marker
4+
from ._utils import get_full_payload_marker as get_full_payload_marker
55
from .depends import Depends as Depends
6+
from .full_payload import FullPayload as FullPayload
67
from .header_dependency import Header as Header
78
from .message_dependency import Message as Message
89
from .message_dependency import MessageDependency as MessageDependency
9-
from .root import Root as Root

repid/dependencies/_utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from dataclasses import dataclass
66
from typing import TYPE_CHECKING, Annotated, Any, Protocol, get_origin, runtime_checkable
77

8+
from repid.dependencies.full_payload import FullPayload
89
from repid.dependencies.header_dependency import Header
910
from repid.dependencies.message_dependency import MessageDependency
10-
from repid.dependencies.root import Root
1111

1212
if TYPE_CHECKING:
1313
from repid.connections.abc import ReceivedMessageT, ServerT
@@ -45,12 +45,12 @@ def get_dependency(t: Any) -> DependencyT | None:
4545
return None
4646

4747

48-
def get_root_marker(t: Any) -> Root | None:
49-
"""Return the `Root` instance from a type annotation if present."""
48+
def get_full_payload_marker(t: Any) -> FullPayload | None:
49+
"""Return the `FullPayload` instance from a type annotation if present."""
5050
if get_origin(t) is not Annotated:
5151
return None
5252
for metadata in t.__metadata__:
53-
if isinstance(metadata, Root):
53+
if isinstance(metadata, FullPayload):
5454
return metadata
5555
return None
5656

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from __future__ import annotations
22

33

4-
class Root:
4+
class FullPayload:
55
"""Annotation marker designating a Pydantic model as the root payload.
66
7-
When applied as ``Annotated[MyModel, Root()]``, the model's fields are
7+
When applied as ``Annotated[MyModel, FullPayload()]``, the model's fields are
88
read directly from the top level of the incoming JSON rather than being
9-
nested under the argument name. Only one ``Root()`` marker is allowed
9+
nested under the argument name. Only one ``FullPayload()`` marker is allowed
1010
per actor.
1111
"""
1212

tests/unit/test_converter.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pytest
77
from pydantic import BaseModel, ValidationError
88

9-
from repid import Header, Root
9+
from repid import FullPayload, Header
1010
from repid.converter import BasicConverter, ConverterT, PydanticConverter
1111
from repid.data import MessageData
1212
from repid.dependencies import Depends
@@ -773,12 +773,12 @@ async def _fn_with_shared_header_in_two_depends(
773773
}
774774

775775

776-
async def test_pydantic_converter_root_model_parse() -> None:
776+
async def test_pydantic_converter_full_payload_model_parse() -> None:
777777
class MyModel(BaseModel):
778778
a: int
779779
b: float
780780

781-
async def fn(model: Annotated[MyModel, Root()]) -> None: ...
781+
async def fn(model: Annotated[MyModel, FullPayload()]) -> None: ...
782782

783783
conv = PydanticConverter(fn, fn_locals=locals(), correlation_id=None)
784784
args, kwargs = await conv.convert_inputs(
@@ -795,12 +795,12 @@ async def fn(model: Annotated[MyModel, Root()]) -> None: ...
795795
assert kwargs == {"model": MyModel(a=1, b=2.5)}
796796

797797

798-
async def test_pydantic_converter_root_model_schema() -> None:
798+
async def test_pydantic_converter_full_payload_model_schema() -> None:
799799
class MyModel(BaseModel):
800800
a: int
801801
b: float
802802

803-
async def fn(model: Annotated[MyModel, Root()]) -> None: ...
803+
async def fn(model: Annotated[MyModel, FullPayload()]) -> None: ...
804804

805805
conv = PydanticConverter(fn, fn_locals=locals(), correlation_id=None)
806806
schema = conv.get_input_schema()
@@ -817,12 +817,12 @@ async def fn(model: Annotated[MyModel, Root()]) -> None: ...
817817
assert schema.content_type == "application/json"
818818

819819

820-
async def test_pydantic_converter_root_model_with_extra_kwargs() -> None:
820+
async def test_pydantic_converter_full_payload_model_with_extra_kwargs() -> None:
821821
class MyModel(BaseModel):
822822
a: int
823823
b: float
824824

825-
async def fn(model: Annotated[MyModel, Root()], extra: str = "default") -> None: ...
825+
async def fn(model: Annotated[MyModel, FullPayload()], extra: str = "default") -> None: ...
826826

827827
conv = PydanticConverter(fn, fn_locals=locals(), correlation_id=None)
828828
args, kwargs = await conv.convert_inputs(
@@ -842,11 +842,11 @@ async def fn(model: Annotated[MyModel, Root()], extra: str = "default") -> None:
842842
assert kwargs["model"].b == 2.5
843843

844844

845-
async def test_pydantic_converter_root_model_with_extra_kwargs_schema() -> None:
845+
async def test_pydantic_converter_full_payload_model_with_extra_kwargs_schema() -> None:
846846
class MyModel(BaseModel):
847847
a: int
848848

849-
async def fn(model: Annotated[MyModel, Root()], extra: str = "default") -> None: ...
849+
async def fn(model: Annotated[MyModel, FullPayload()], extra: str = "default") -> None: ...
850850

851851
conv = PydanticConverter(fn, fn_locals=locals(), correlation_id=None)
852852
schema = conv.get_input_schema()
@@ -857,27 +857,27 @@ async def fn(model: Annotated[MyModel, Root()], extra: str = "default") -> None:
857857
assert "extra" in props
858858

859859

860-
def test_pydantic_converter_root_model_multiple_raises() -> None:
860+
def test_pydantic_converter_full_payload_model_multiple_raises() -> None:
861861
class M1(BaseModel):
862862
a: int
863863

864864
class M2(BaseModel):
865865
b: int
866866

867867
async def fn(
868-
m1: Annotated[M1, Root()],
869-
m2: Annotated[M2, Root()],
868+
m1: Annotated[M1, FullPayload()],
869+
m2: Annotated[M2, FullPayload()],
870870
) -> None: ...
871871

872-
with pytest.raises(ValueError, match="Only one Root\\(\\) marker is allowed per actor"):
872+
with pytest.raises(ValueError, match="Only one FullPayload\\(\\) marker is allowed per actor"):
873873
PydanticConverter(fn, fn_locals=locals(), correlation_id=None)
874874

875875

876-
def test_basic_converter_root_model_raises() -> None:
876+
def test_basic_converter_full_payload_model_raises() -> None:
877877
class MyModel(BaseModel):
878878
a: int
879879

880-
async def fn(model: Annotated[MyModel, Root()]) -> None: ...
880+
async def fn(model: Annotated[MyModel, FullPayload()]) -> None: ...
881881

882-
with pytest.raises(ValueError, match="Root\\(\\) requires PydanticConverter"):
882+
with pytest.raises(ValueError, match="FullPayload\\(\\) requires PydanticConverter"):
883883
BasicConverter(fn, fn_locals=locals(), correlation_id=None)

0 commit comments

Comments
 (0)