Skip to content

Instantly share code, notes, and snippets.

@JelleZijlstra
Forked from AlexWaygood/annotations-demo.py
Last active June 19, 2024 02:03
Show Gist options
  • Save JelleZijlstra/f9589daadb0d73f64a88f3292d76c808 to your computer and use it in GitHub Desktop.
Save JelleZijlstra/f9589daadb0d73f64a88f3292d76c808 to your computer and use it in GitHub Desktop.
Demo for an `__annotations__` solution
from collections.abc import Mapping
class _AnnotationsDescriptor(Mapping):
def __init__(self, owner: type, name: str):
self._annotations_cache = None
self._owner = owner
self._name = name
# Must act as a descriptor if accessed via `.`
def _materialize_annotations(self) -> None:
if self._annotations_cache is None:
self._annotations_cache = self._owner.__annotate__(1)
def __get__(self, obj, cls=None) -> dict:
if obj is not None:
raise AttributeError(
f"{type(obj).__name__!r} object has no attribute {self._name!r}"
)
assert cls is self._owner
self._materialize_annotations()
return self._annotations_cache
# Must act as a mapping if accessed via `__dict__`:
def __getitem__(self, key: str):
self._materialize_annotations()
return self._annotations_cache[key]
def __iter__(self):
self._materialize_annotations()
yield from self._annotations_cache
def __len__(self) -> int:
self._materialize_annotations()
return len(self._annotations_cache)
class Object:
"""Pretend this is how builtins.object would work"""
def __init_subclass__(cls):
cls.annotations = _AnnotationsDescriptor(cls, "annotations")
class Meta(Object, type):
x: int
class Foo(Object, metaclass=Meta):
y: str
class Bar(Object, metaclass=Meta):
pass
def test():
assert Meta.annotations == {"x": int}
assert Meta.annotations["x"] is int
assert Meta.annotations.get("x", bytes) is int
assert Foo.annotations == {"y": str}
assert Bar.annotations == {}
try:
Foo().annotations
except AttributeError:
pass
else:
assert False, "AttributeError should have been raised"
print("Tests all passed")
if __name__ == "__main__":
test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment