@@ -10,27 +10,23 @@ In certain situations, you might want to deviate from this behavior and use alte
1010
1111For example, consider the following ` Point ` class describing points in 2D space, which offers two ` classmethod ` s for alternative creation:
1212
13- ``` {doctest}
14- >>> from __future__ import annotations
15-
13+ ``` {doctest} point_group
1614>>> import math
17-
1815>>> from attrs import define
1916
20-
2117>>> @define
2218... class Point:
2319... """A point in 2D space."""
2420... x: float
2521... y: float
2622...
2723... @classmethod
28- ... def from_tuple(cls, coordinates: tuple[float, float]) -> Point:
24+ ... def from_tuple(cls, coordinates: tuple[float, float]) -> " Point" :
2925... """Create a point from a tuple of Cartesian coordinates."""
3026... return Point(*coordinates)
3127...
3228... @classmethod
33- ... def from_polar(cls, radius: float, angle: float) -> Point:
29+ ... def from_polar(cls, radius: float, angle: float) -> " Point" :
3430... """Create a point from its polar coordinates."""
3531... return Point(radius * math.cos(angle), radius * math.sin(angle))
3632```
@@ -40,17 +36,18 @@ For example, consider the following `Point` class describing points in 2D space,
4036
4137A simple way to _ statically_ set one of the ` classmethod ` s as initializer is to register a structuring hook that holds a reference to the respective callable:
4238
43- ``` {doctest}
39+ ``` {doctest} point_group
4440>>> from inspect import signature
4541>>> from typing import Callable, TypedDict
4642
4743>>> from cattrs import Converter
4844>>> from cattrs.dispatch import StructureHook
4945
5046>>> def signature_to_typed_dict(fn: Callable) -> type[TypedDict]:
51- ... """Create a TypedDict reflecting a callable's signature."""
47+ ... """Create a TypedDict reflecting a callable's signature."""
5248... params = {p: t.annotation for p, t in signature(fn).parameters.items()}
5349... return TypedDict(f"{fn.__name__}_args", params)
50+ ...
5451
5552>>> def make_initializer_from(fn: Callable, conv: Converter) -> StructureHook:
5653... """Return a structuring hook from a given callable."""
@@ -61,7 +58,7 @@ A simple way to _statically_ set one of the `classmethod`s as initializer is to
6158
6259Now, you can easily structure ` Point ` s from the specified alternative representation:
6360
64- ``` {doctest}
61+ ``` {doctest} point_group
6562>>> c = Converter()
6663>>> c.register_structure_hook(Point, make_initializer_from(Point.from_polar, c))
6764
@@ -78,7 +75,7 @@ A typical scenario would be when object structuring happens behind an API and yo
7875
7976In such situations, the following hook factory can help you achieve your goal:
8077
81- ``` {doctest}
78+ ``` {doctest} point_group
8279>>> from inspect import signature
8380>>> from typing import Callable, TypedDict
8481
@@ -90,6 +87,7 @@ In such situations, the following hook factory can help you achieve your goal:
9087... params = {p: t.annotation for p, t in signature(fn).parameters.items()}
9188... return TypedDict(f"{fn.__name__}_args", params)
9289
90+ >>> T = TypeVar("T")
9391>>> def make_initializer_selection_hook(
9492... initializer_key: str,
9593... converter: Converter,
@@ -116,7 +114,7 @@ In such situations, the following hook factory can help you achieve your goal:
116114
117115Specifying the key that determines the initializer to be used now lets you dynamically select the ` classmethod ` as part of the object specification itself:
118116
119- ``` {doctest}
117+ ``` {doctest} point_group
120118>>> c = Converter()
121119>>> c.register_structure_hook(Point, make_initializer_selection_hook("initializer", c))
122120
0 commit comments