1
1
import copy
2
2
import dataclasses
3
- import inspect
4
3
import sys
5
4
from typing import (
6
5
Dict ,
11
10
TypeVar ,
12
11
Union ,
13
12
)
14
-
15
13
import typing_inspect
14
+ import warnings
16
15
17
16
if sys .version_info >= (3 , 9 ):
18
17
from typing import Annotated , get_args , get_origin
18
+ from types import GenericAlias
19
19
else :
20
20
from typing_extensions import Annotated , get_args , get_origin
21
21
22
+ GenericAlias = type (list )
23
+
24
+
22
25
if sys .version_info >= (3 , 13 ):
23
26
from typing import NoDefault
24
27
else :
@@ -194,25 +197,27 @@ def _resolve_typevars(clazz: type) -> Dict[type, Dict[TypeVar, _Future]]:
194
197
def _replace_typevars (
195
198
clazz : type , resolved_generics : Optional [Dict [TypeVar , _Future ]] = None
196
199
) -> type :
197
- if (
198
- not resolved_generics
199
- or inspect .isclass (clazz )
200
- or not may_contain_typevars (clazz )
201
- ):
200
+ if not resolved_generics or not may_contain_typevars (clazz ):
202
201
return clazz
203
202
204
- return clazz .copy_with ( # type: ignore
205
- tuple (
206
- (
207
- _replace_typevars (arg , resolved_generics )
208
- if may_contain_typevars (arg )
209
- else (
210
- resolved_generics [arg ].result () if arg in resolved_generics else arg
211
- )
212
- )
213
- for arg in get_args (clazz )
203
+ new_args = tuple (
204
+ (
205
+ _replace_typevars (arg , resolved_generics )
206
+ if may_contain_typevars (arg )
207
+ else (resolved_generics [arg ].result () if arg in resolved_generics else arg )
214
208
)
209
+ for arg in get_args (clazz )
215
210
)
211
+ # i.e.: typing.List, typing.Dict, but not list, and dict
212
+ if hasattr (clazz , "copy_with" ):
213
+ return clazz .copy_with (new_args )
214
+ # i.e.: list, dict - inspired by typing._strip_annotations
215
+ if sys .version_info >= (3 , 9 ) and isinstance (clazz , GenericAlias ):
216
+ return GenericAlias (clazz .__origin__ , new_args ) # type:ignore[return-value]
217
+
218
+ # I'm not sure how we'd end up here. But raise a warnings so people can create an issue
219
+ warnings .warn (f"Unable to replace typevars in { clazz } " )
220
+ return clazz
216
221
217
222
218
223
def get_generic_dataclass_fields (clazz : type ) -> Tuple [dataclasses .Field , ...]:
@@ -237,7 +242,7 @@ def get_generic_dataclass_fields(clazz: type) -> Tuple[dataclasses.Field, ...]:
237
242
# If it's a class we handle it later as a Nested. Nothing to resolve now.
238
243
new_field = field
239
244
field_type : type = field .type # type: ignore[assignment]
240
- if not inspect . isclass ( field_type ) and may_contain_typevars (field_type ):
245
+ if may_contain_typevars (field_type ):
241
246
new_field = copy .copy (field )
242
247
new_field .type = _replace_typevars (
243
248
field_type , resolved_typevars [subclass ]
0 commit comments