Skip to content

Commit 8447125

Browse files
authored
Fix converter type hints (#579)
Fix converter type hints
1 parent 3cb6707 commit 8447125

File tree

4 files changed

+76
-23
lines changed

4 files changed

+76
-23
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
name: coverage-data-${{ matrix.python-version }}
3939
path: .coverage.*
4040
if-no-files-found: ignore
41+
include-hidden-files: true
4142

4243
coverage:
4344
name: "Combine & check coverage."

HISTORY.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ The third number is for emergencies when we need to start branches for older rel
99

1010
Our backwards-compatibility policy can be found [here](https://github.com/python-attrs/cattrs/blob/main/.github/SECURITY.md).
1111

12+
## 24.1.1 (UNRELEASED)
13+
14+
- Fix {meth}`BaseConverter.register_structure_hook_factory` and {meth}`BaseConverter.register_unstructure_hook_factory` type hints.
15+
([#578](https://github.com/python-attrs/cattrs/issues/578) [#579](https://github.com/python-attrs/cattrs/pull/579))
16+
1217
## 24.1.0 (2024-08-28)
1318

1419
- **Potentially breaking**: Unstructuring hooks for `typing.Any` are consistent now: values are unstructured using their runtime type.

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ _cattrs_ works best with [_attrs_](https://www.attrs.org/) classes, and [datacla
3737
C(a=1, b=['x', 'y'])
3838
>>> unstructure(instance)
3939
{'a': 1, 'b': ['x', 'y']}
40-
4140
```
4241

4342
<!-- end-teaser -->

src/cattrs/converters.py

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,35 @@
102102
)
103103

104104
# The Extended factory also takes a converter.
105-
ExtendedUnstructureHookFactory = TypeVar(
106-
"ExtendedUnstructureHookFactory",
107-
bound=Callable[[TargetType, "BaseConverter"], UnstructureHook],
105+
ExtendedUnstructureHookFactory: TypeAlias = Callable[[TargetType, T], UnstructureHook]
106+
107+
# This typevar for the BaseConverter.
108+
AnyUnstructureHookFactoryBase = TypeVar(
109+
"AnyUnstructureHookFactoryBase",
110+
bound="HookFactory[UnstructureHook] | ExtendedUnstructureHookFactory[BaseConverter]",
111+
)
112+
113+
# This typevar for the Converter.
114+
AnyUnstructureHookFactory = TypeVar(
115+
"AnyUnstructureHookFactory",
116+
bound="HookFactory[UnstructureHook] | ExtendedUnstructureHookFactory[Converter]",
108117
)
109118

110119
StructureHookFactory = TypeVar("StructureHookFactory", bound=HookFactory[StructureHook])
111120

112121
# The Extended factory also takes a converter.
113-
ExtendedStructureHookFactory = TypeVar(
114-
"ExtendedStructureHookFactory",
115-
bound=Callable[[TargetType, "BaseConverter"], StructureHook],
122+
ExtendedStructureHookFactory: TypeAlias = Callable[[TargetType, T], StructureHook]
123+
124+
# This typevar for the BaseConverter.
125+
AnyStructureHookFactoryBase = TypeVar(
126+
"AnyStructureHookFactoryBase",
127+
bound="HookFactory[StructureHook] | ExtendedStructureHookFactory[BaseConverter]",
128+
)
129+
130+
# This typevar for the Converter.
131+
AnyStructureHookFactory = TypeVar(
132+
"AnyStructureHookFactory",
133+
bound="HookFactory[StructureHook] | ExtendedStructureHookFactory[Converter]",
116134
)
117135

118136

@@ -341,12 +359,7 @@ def register_unstructure_hook_func(
341359
@overload
342360
def register_unstructure_hook_factory(
343361
self, predicate: Predicate
344-
) -> Callable[[UnstructureHookFactory], UnstructureHookFactory]: ...
345-
346-
@overload
347-
def register_unstructure_hook_factory(
348-
self, predicate: Predicate
349-
) -> Callable[[ExtendedUnstructureHookFactory], ExtendedUnstructureHookFactory]: ...
362+
) -> Callable[[AnyUnstructureHookFactoryBase], AnyUnstructureHookFactoryBase]: ...
350363

351364
@overload
352365
def register_unstructure_hook_factory(
@@ -355,8 +368,10 @@ def register_unstructure_hook_factory(
355368

356369
@overload
357370
def register_unstructure_hook_factory(
358-
self, predicate: Predicate, factory: ExtendedUnstructureHookFactory
359-
) -> ExtendedUnstructureHookFactory: ...
371+
self,
372+
predicate: Predicate,
373+
factory: ExtendedUnstructureHookFactory[BaseConverter],
374+
) -> ExtendedUnstructureHookFactory[BaseConverter]: ...
360375

361376
def register_unstructure_hook_factory(self, predicate, factory=None):
362377
"""
@@ -478,12 +493,7 @@ def register_structure_hook_func(
478493
@overload
479494
def register_structure_hook_factory(
480495
self, predicate: Predicate
481-
) -> Callable[[StructureHookFactory, StructureHookFactory]]: ...
482-
483-
@overload
484-
def register_structure_hook_factory(
485-
self, predicate: Predicate
486-
) -> Callable[[ExtendedStructureHookFactory, ExtendedStructureHookFactory]]: ...
496+
) -> Callable[[AnyStructureHookFactoryBase], AnyStructureHookFactoryBase]: ...
487497

488498
@overload
489499
def register_structure_hook_factory(
@@ -492,8 +502,8 @@ def register_structure_hook_factory(
492502

493503
@overload
494504
def register_structure_hook_factory(
495-
self, predicate: Predicate, factory: ExtendedStructureHookFactory
496-
) -> ExtendedStructureHookFactory: ...
505+
self, predicate: Predicate, factory: ExtendedStructureHookFactory[BaseConverter]
506+
) -> ExtendedStructureHookFactory[BaseConverter]: ...
497507

498508
def register_structure_hook_factory(self, predicate, factory=None):
499509
"""
@@ -1159,6 +1169,44 @@ def __init__(
11591169
self._struct_copy_skip = self._structure_func.get_num_fns()
11601170
self._unstruct_copy_skip = self._unstructure_func.get_num_fns()
11611171

1172+
@overload
1173+
def register_unstructure_hook_factory(
1174+
self, predicate: Predicate
1175+
) -> Callable[[AnyUnstructureHookFactory], AnyUnstructureHookFactory]: ...
1176+
1177+
@overload
1178+
def register_unstructure_hook_factory(
1179+
self, predicate: Predicate, factory: UnstructureHookFactory
1180+
) -> UnstructureHookFactory: ...
1181+
1182+
@overload
1183+
def register_unstructure_hook_factory(
1184+
self, predicate: Predicate, factory: ExtendedUnstructureHookFactory[Converter]
1185+
) -> ExtendedUnstructureHookFactory[Converter]: ...
1186+
1187+
def register_unstructure_hook_factory(self, predicate, factory=None):
1188+
# This dummy wrapper is required due to how `@overload` works.
1189+
return super().register_unstructure_hook_factory(predicate, factory)
1190+
1191+
@overload
1192+
def register_structure_hook_factory(
1193+
self, predicate: Predicate
1194+
) -> Callable[[AnyStructureHookFactory], AnyStructureHookFactory]: ...
1195+
1196+
@overload
1197+
def register_structure_hook_factory(
1198+
self, predicate: Predicate, factory: StructureHookFactory
1199+
) -> StructureHookFactory: ...
1200+
1201+
@overload
1202+
def register_structure_hook_factory(
1203+
self, predicate: Predicate, factory: ExtendedStructureHookFactory[Converter]
1204+
) -> ExtendedStructureHookFactory[Converter]: ...
1205+
1206+
def register_structure_hook_factory(self, predicate, factory=None):
1207+
# This dummy wrapper is required due to how `@overload` works.
1208+
return super().register_structure_hook_factory(predicate, factory)
1209+
11621210
def get_structure_newtype(self, type: type[T]) -> Callable[[Any, Any], T]:
11631211
base = get_newtype_base(type)
11641212
handler = self.get_structure_hook(base)

0 commit comments

Comments
 (0)