Skip to content

Commit afedb11

Browse files
committed
ensure_type: cache the type adaptors
for a much more efficient type checking of complex types (using pydantic) at runtime: before: 124 μs ± 82.5 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each) after: 1.81 μs ± 4.74 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each) for comparison, when using isinstance: 629 ns ± 9.26 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each) Signed-off-by: Gaëtan Lehmann <[email protected]>
1 parent 1efb579 commit afedb11

File tree

1 file changed

+7
-1
lines changed

1 file changed

+7
-1
lines changed

lib/common.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def expand_scope_relative_nodeid(scoped_nodeid, scope, ref_nodeid):
7272
def callable_marker(value, request):
7373
T = TypeVar("T")
7474

75+
_ensure_type_cache: Dict[type, TypeAdapter] = {}
76+
7577
def ensure_type(typ: Type[T], value: Any) -> T:
7678
"""
7779
Converts a value to the specified type.
@@ -85,7 +87,11 @@ def ensure_type(typ: Type[T], value: Any) -> T:
8587
except TypeError:
8688
# not just a simple type, lets try with pydantic
8789
with suppress(ValidationError):
88-
TypeAdapter(typ).validate_python(value)
90+
if typ in _ensure_type_cache:
91+
ta = _ensure_type_cache[typ]
92+
else:
93+
ta = _ensure_type_cache.setdefault(typ, TypeAdapter(typ))
94+
ta.validate_python(value)
8995
ok = True
9096
if not ok:
9197
raise TypeError(f"'{type(value).__name__}' object is not of the expected type '{typ.__name__}'")

0 commit comments

Comments
 (0)