Skip to content

Commit 1d93cc8

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 203fc77 commit 1d93cc8

File tree

1 file changed

+4
-2
lines changed

1 file changed

+4
-2
lines changed

lib/common.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import traceback
1010
from enum import Enum
1111
from pydantic import TypeAdapter, ValidationError
12-
from typing import Any, Dict, Literal, Optional, Type, TypeVar, overload, TYPE_CHECKING, Union
12+
from typing import Any, Dict, Literal, Optional, Type, TypeVar, cast, overload, TYPE_CHECKING, Union
1313
from uuid import UUID
1414

1515
import pytest
@@ -71,6 +71,8 @@ def expand_scope_relative_nodeid(scoped_nodeid, scope, ref_nodeid):
7171

7272
T = TypeVar("T")
7373

74+
_ensure_type_cache: Dict[type, TypeAdapter] = {}
75+
7476
def ensure_type(typ: Type[T], value: Any) -> T:
7577
"""
7678
Converts a value to the specified type.
@@ -84,7 +86,7 @@ def ensure_type(typ: Type[T], value: Any) -> T:
8486
except TypeError:
8587
# not just a simple type, lets try with pydantic
8688
with suppress(ValidationError):
87-
ta = TypeAdapter(typ)
89+
ta = cast(TypeAdapter[T], _ensure_type_cache.setdefault(typ, TypeAdapter(typ)))
8890
return ta.validate_python(value)
8991
raise TypeError(f"'{type(value).__name__}' object is not of the expected type '{typ.__name__}'")
9092

0 commit comments

Comments
 (0)