Source code for jitx.property
"""
Property system
===============
This module provides the base Property class. Objects can be assigned properties,
and properties can be retrieved from objects.
"""
from collections.abc import Iterable
from typing import Any, overload
from ._structural import Structural, Proxy
[docs]
class Property:
"""Property base class. To declare a new property, subclass this class. Note that
properties should be immutable, or care should be taken that a mutable
property is not reused across multiple objects (unless intentional, of
course). For example a property holding a list of things to be appended to
per object should be carefully constructed so the same list is not attached
to multiple objects.
>>> @dataclass(frozen=True)
... class MyProperty(Property):
... some_string_value: str
>>> other_object = object() # some object to assign property, such as a Port
>>> MyProperty("abc").assign(other_object)
>>> MyProperty.get(other_object)
MyProperty(some_string_value="abc")
"""
[docs]
def assign(self, *objects: Any):
# bypass proxy forwarding
with Proxy.override():
for obs in objects:
if not isinstance(obs, Iterable) or isinstance(obs, Structural):
obs = (obs,)
for ob in obs:
props = getattr(ob, "_Property__dict", None)
if not props:
props = {}
# bypass frozen checks
object.__setattr__(ob, "_Property__dict", props)
t = type(self)
props[t] = self._set(props.get(t))
# Any|None here to indicate that it will be called with an object of its
# own type or None, but can't use Self here since that would make the type
# signature incompatible.
def _set(self, other: Any | None):
# can be used to make sure a list-property is unique by cloning on set
return self
@overload
@classmethod
def get[T, D](cls: type[T], ob: Any, default: D) -> T | D: ...
@overload
@classmethod
def get[T](cls: type[T], ob: Any) -> T | None: ...
[docs]
@classmethod
def get[T, D](cls: type[T], ob: Any, default: D | None = None) -> T | D:
props = getattr(ob, "_Property__dict", {})
return props.get(cls, default)