Skip to content

Commit 937c1c2

Browse files
committed
Make the generated @property really act like a @cached_property
It seemed to be getting called anyway! May as well! This made it pretty pointless to generate a `__getattr__`, so I've removed `_make_cached_property_getattr`
1 parent 393c804 commit 937c1c2

1 file changed

Lines changed: 14 additions & 63 deletions

File tree

src/attr/_make.py

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -495,64 +495,6 @@ def _transform_attrs(
495495

496496
return _Attributes(AttrsClass(attrs), base_attrs, base_attr_map)
497497

498-
499-
def _make_cached_property_getattr(cached_properties, original_getattr, cls):
500-
lines = [
501-
# Wrapped to get `__class__` into closure cell for super()
502-
# (It will be replaced with the newly constructed class after construction).
503-
"def wrapper(_cls):",
504-
" __class__ = _cls",
505-
" def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):",
506-
" func = cached_properties.get(item)",
507-
" if func is not None:",
508-
" cache = item + '_cache'",
509-
" cached = _cls.__dict__[cache]",
510-
" try:",
511-
" return cached.__get__(self, _cls)",
512-
" except AttributeError:",
513-
" pass",
514-
" result = func(self)",
515-
" cached.__set__(self, result)",
516-
" return result",
517-
]
518-
if original_getattr is not None:
519-
lines.append(
520-
" return original_getattr(self, item)",
521-
)
522-
else:
523-
lines.extend(
524-
[
525-
" try:",
526-
" return super().__getattribute__(item)",
527-
" except AttributeError:",
528-
" if not hasattr(super(), '__getattr__'):",
529-
" raise",
530-
" return super().__getattr__(item)",
531-
" original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"",
532-
" raise AttributeError(original_error)",
533-
]
534-
)
535-
536-
lines.extend(
537-
[
538-
" return __getattr__",
539-
"__getattr__ = wrapper(_cls)",
540-
]
541-
)
542-
543-
unique_filename = _generate_unique_filename(cls, "getattr")
544-
545-
glob = {
546-
"cached_properties": cached_properties,
547-
"_cached_setattr_get": _OBJ_SETATTR.__get__,
548-
"original_getattr": original_getattr,
549-
}
550-
551-
return _linecache_and_compile(
552-
"\n".join(lines), unique_filename, glob, locals={"_cls": cls}
553-
)["__getattr__"]
554-
555-
556498
def _make_cached_property_uncached(original_cached_property_func, cls):
557499
"""Make an ordinary :deco:`property` to replace a :deco:`cached_property`
558500
@@ -585,6 +527,7 @@ def _make_cached_property_uncached(original_cached_property_func, cls):
585527
annotation = inspect.signature(
586528
original_cached_property_func
587529
).return_annotation
530+
name = original_cached_property_func.__name__
588531
if annotation is inspect.Parameter.empty:
589532
defline = f"def {name}(self):"
590533
elif isinstance(
@@ -601,7 +544,19 @@ def _make_cached_property_uncached(original_cached_property_func, cls):
601544
"@property",
602545
defline,
603546
*doc_lines,
604-
" raise AttributeError('Use __getattr__ instead')",
547+
" for entry in type.__dict__['__mro__'].__get__(self.__class__):",
548+
f" if '{name}_cache' in entry.__dict__:",
549+
f" descriptor = entry.__dict__['{name}_cache']",
550+
" break",
551+
" else:",
552+
" raise AttributeError('No descriptor')",
553+
" try:",
554+
" return descriptor.__get__(self, self.__class__)",
555+
" except AttributeError:",
556+
" pass",
557+
" result = original_cached_property(self)",
558+
" descriptor.__set__(self, result)",
559+
" return result",
605560
]
606561
unique_filename = _generate_unique_filename(
607562
cls, original_cached_property_func
@@ -992,10 +947,6 @@ def _create_slots_class(self):
992947
if original_getattr is not None:
993948
additional_closure_functions_to_update.append(original_getattr)
994949

995-
cd["__getattr__"] = _make_cached_property_getattr(
996-
cached_properties, original_getattr, self._cls
997-
)
998-
999950
# We only add the names of attributes that aren't inherited.
1000951
# Setting __slots__ to inherited attributes wastes memory.
1001952
slot_names = [name for name in names if name not in base_names]

0 commit comments

Comments
 (0)