From 33cc7e8ce6a1a127e6e81ece10c0d8af3edd34d6 Mon Sep 17 00:00:00 2001 From: Roman Snegirev Date: Sat, 13 Nov 2021 15:14:10 +0300 Subject: [PATCH] Cache __getitem__ of BaseCollectionModelMeta --- pydantic_collections/__init__.py | 2 +- .../_base_collection_model.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pydantic_collections/__init__.py b/pydantic_collections/__init__.py index 5d157cc..39583f4 100644 --- a/pydantic_collections/__init__.py +++ b/pydantic_collections/__init__.py @@ -1,5 +1,5 @@ __title__ = 'pydantic-collections' -__version__ = '0.1.1' +__version__ = '0.2.0' from ._base_collection_model import BaseCollectionModel diff --git a/pydantic_collections/_base_collection_model.py b/pydantic_collections/_base_collection_model.py index 1fbf51a..29101c2 100644 --- a/pydantic_collections/_base_collection_model.py +++ b/pydantic_collections/_base_collection_model.py @@ -1,3 +1,4 @@ +import functools import warnings from typing import Optional, List, MutableSequence, Type, TypeVar, Any, Callable @@ -14,7 +15,25 @@ class CollectionModelConfig(BaseConfig): validate_assignment_strict = False +def tp_cache(func): + """Internal wrapper caching __getitem__ of generic types with a fallback to + original function for non-hashable arguments. + """ + cached = functools.lru_cache(maxsize=None, typed=True)(func) + + @functools.wraps(func) + def inner(*args, **kwargs): + try: + return cached(*args, **kwargs) + except TypeError: # pragma: no cover + pass # All real errors (not unhashable args) are raised below. + return func(*args, **kwargs) # pragma: no cover + + return inner + + class BaseCollectionModelMeta(ModelMetaclass): + @tp_cache def __getitem__(cls: Type['BaseCollectionModel'], el_type): if not issubclass(cls, BaseCollectionModel): raise TypeError('{!r} is not a BaseCollectionModel'.format(cls)) # pragma: no cover