1616from collections .abc import Callable
1717import types
1818from inspect import isclass
19+ from functools import lru_cache
1920from dataclasses import dataclass , InitVar
2021from .parsers .json import JSONContent
2122from .converters import encoders , parse_basic
@@ -155,7 +156,25 @@ class ModelMeta(type):
155156 __aliases__ : Dict
156157 __primary_keys__ : List
157158 # Class-level cache
158- _base_class_cache = {}
159+ _base_class_cache = OrderedDict ()
160+ _MAX_CACHE_SIZE = 512 # size limit
161+
162+ @classmethod
163+ def _cache_get (cls , key ):
164+ """Get item from cache with LRU behavior."""
165+ if key not in cls ._base_class_cache :
166+ return None
167+ value = cls ._base_class_cache .pop (key )
168+ cls ._base_class_cache [key ] = value
169+ return value
170+
171+ @classmethod
172+ def _cache_set (cls , key , value ):
173+ """Set item in cache with LRU eviction."""
174+ # If cache is full, remove oldest item (first in OrderedDict)
175+ if len (cls ._base_class_cache ) >= cls ._MAX_CACHE_SIZE :
176+ cls ._base_class_cache .popitem (last = False )
177+ cls ._base_class_cache [key ] = value
159178
160179 @staticmethod
161180 def _initialize_fields (attrs , annotations , strict ):
@@ -206,7 +225,7 @@ def _initialize_fields(attrs, annotations, strict):
206225 df .type = _type
207226
208227 # Check for primary_key in field metadata
209- if df .metadata .get ("primary_key " , False ):
228+ if df .metadata .get ("primary " , False ) or df . primary_key is True :
210229 primary_keys .append (field )
211230
212231 # Cache reflection info so we DON’T need to call
@@ -292,20 +311,27 @@ def _initialize_fields(attrs, annotations, strict):
292311
293312 def __new__ (cls , name , bases , attrs , ** kwargs ): # noqa
294313 annotations = attrs .get ('__annotations__' , {})
295- base_key = (tuple (bases ), tuple (sorted (annotations .items ())))
296- strict = getattr (attrs .get ('Meta' , Meta ), 'strict' , False )
314+ _strict_ = False
315+ cols = OrderedDict ()
316+
317+ # Base class constructor
318+ base_key = (name , tuple (bases ), tuple (sorted (annotations .items ())))
319+ with contextlib .suppress (TypeError , AttributeError , KeyError ):
320+ _strict_ = attrs ['Meta' ].strict
297321
298- if base_key in cls ._base_class_cache :
322+ # Use LRU get method
323+ cached = cls ._cache_get (base_key )
324+ if cached :
325+ # if base_key in cls._base_class_cache:
299326 # Check the Cache First:
300- cached = cls ._base_class_cache [base_key ]
327+ # cached = cls._base_class_cache[base_key]
301328 cols = cached ['cols' ].copy ()
302329 _types = cached ['types' ].copy ()
303330 _typing_args = cached ['_typing_args' ].copy ()
304331 aliases = cached ['aliases' ].copy ()
305332 primary_keys = cached ['primary_keys' ].copy ()
306333 else :
307334 # Compute field from Bases:
308- cols = OrderedDict ()
309335 _types = {}
310336 _typing_args = {}
311337 aliases = {}
@@ -325,7 +351,7 @@ def __new__(cls, name, bases, attrs, **kwargs): # noqa
325351
326352 # Now initialize subclass-specific fields
327353 new_cols , new_types , new_typing_args , new_aliases , nw_primary_keys = cls ._initialize_fields ( # noqa
328- attrs , annotations , strict
354+ attrs , annotations , _strict_
329355 )
330356
331357 # Merge new fields with inherited fields
@@ -336,13 +362,21 @@ def __new__(cls, name, bases, attrs, **kwargs): # noqa
336362 primary_keys .extend (nw_primary_keys )
337363
338364 # Store computed results in cache
339- cls ._base_class_cache [base_key ] = {
365+ # cls._base_class_cache[base_key] = {
366+ # 'cols': cols.copy(),
367+ # 'types': _types.copy(),
368+ # '_typing_args': _typing_args.copy(),
369+ # 'aliases': aliases.copy(),
370+ # 'primary_keys': primary_keys.copy(),
371+ # }
372+ cache_entry = {
340373 'cols' : cols .copy (),
341374 'types' : _types .copy (),
342375 '_typing_args' : _typing_args .copy (),
343376 'aliases' : aliases .copy (),
344377 'primary_keys' : primary_keys .copy (),
345378 }
379+ cls ._cache_set (base_key , cache_entry )
346380
347381 _columns = cols .keys ()
348382 cls .__slots__ = tuple (_columns )
@@ -388,7 +422,7 @@ def __new__(cls, name, bases, attrs, **kwargs): # noqa
388422
389423 # Now that fields are in attrs, decorate the class as a dataclass
390424 dc = dataclass (
391- unsafe_hash = strict ,
425+ unsafe_hash = _strict_ ,
392426 repr = False ,
393427 init = True ,
394428 order = False ,
@@ -402,7 +436,7 @@ def __new__(cls, name, bases, attrs, **kwargs): # noqa
402436 dc .__valid__ = False
403437 dc .__errors__ = {}
404438 dc .__values__ = {}
405- dc .__frozen__ = strict
439+ dc .__frozen__ = _strict_
406440 dc .__initialised__ = False
407441 dc .__field_types__ = _types
408442 dc .__aliases__ = aliases
0 commit comments