Skip to content

Commit 53f2f32

Browse files
committed
Improve performance
1 parent 01774eb commit 53f2f32

File tree

2 files changed

+36
-12
lines changed

2 files changed

+36
-12
lines changed

dacite/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def _build_value(type_: Type, data: Any, config: Config) -> Any:
103103
data = _build_value_for_collection(collection=type_, data=data, config=config)
104104
elif cache(is_dataclass)(type_) and isinstance(data, Mapping):
105105
data = from_dict(data_class=type_, data=data, config=config)
106-
elif is_generic_subclass(type_) and is_dataclass(get_origin(type_)):
106+
elif is_generic_subclass(type_) and cache(is_dataclass)(get_origin(type_)):
107107
origin = get_origin(type_)
108108
assert origin is not None
109109
data = from_dict(data_class=origin, data=data, config=config)

dacite/types.py

+35-11
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,13 @@ def is_valid_generic_class(value: Any, type_: Type) -> bool:
102102
origin = get_origin(type_)
103103
if not (origin and isinstance(value, origin)):
104104
return False
105-
type_hints = get_type_hints(type(value))
105+
type_hints = cache(get_type_hints)(type(value))
106106
for field_name, field_type in type_hints.items():
107107
if isinstance(field_type, TypeVar):
108-
return (
109-
any(isinstance(getattr(value, field_name), arg) for arg in get_args(type_)) if get_args(type_) else True
110-
)
108+
args = get_args(type_)
109+
return True if not args else any(isinstance(getattr(value, field_name, None), arg) for arg in args)
111110
else:
112-
return is_instance(value, type_)
111+
return isinstance(value, type_)
113112
return True
114113

115114

@@ -121,6 +120,31 @@ def extract_init_var(type_: Type) -> Union[Type, Any]:
121120
return Any
122121

123122

123+
@cache
124+
def get_constraints(type_: TypeVar) -> Optional[Any]:
125+
return type_.__constraints__
126+
127+
128+
@cache
129+
def is_constrained(type_: TypeVar) -> bool:
130+
return hasattr(type_, "__constraints__") and get_constraints(type_)
131+
132+
133+
@cache
134+
def get_bound(type_: TypeVar) -> Optional[Any]:
135+
return type_.__bound__
136+
137+
138+
@cache
139+
def is_bound(type_: TypeVar) -> bool:
140+
return hasattr(type_, "__bound__") and get_bound(type_)
141+
142+
143+
@cache
144+
def is_generic_bound(type_: TypeVar) -> bool:
145+
return is_bound(type_) and get_bound(type_) is not None and is_generic(get_bound(type_))
146+
147+
124148
def is_instance(value: Any, type_: Type) -> bool:
125149
try:
126150
# As described in PEP 484 - section: "The numeric tower"
@@ -164,13 +188,13 @@ def is_instance(value: Any, type_: Type) -> bool:
164188
elif isclass(type(type_)) and is_generic_alias(type(type_)):
165189
return is_valid_generic_class(value, type_)
166190
elif isinstance(type_, TypeVar):
167-
if hasattr(type_, "__constraints__") and type_.__constraints__:
191+
if is_constrained(type_):
168192
return any(is_instance(value, t) for t in type_.__constraints__)
169-
if hasattr(type_, "__bound__") and type_.__bound__:
170-
if isinstance(type_.__bound__, tuple):
171-
return any(is_instance(value, t) for t in type_.__bound__)
172-
if type_.__bound__ is not None and is_generic(type_.__bound__):
173-
return isinstance(value, extract_generic(type_.__bound__))
193+
if is_bound(type_):
194+
if isinstance(get_bound(type_), tuple):
195+
return any(isinstance(value, t) for t in get_bound(type_))
196+
if is_generic_bound(type_):
197+
return isinstance(value, extract_generic(get_bound(type_)))
174198
return True
175199
elif is_type_generic(type_):
176200
return is_subclass(value, extract_generic(type_)[0])

0 commit comments

Comments
 (0)