From 38779470a6d1e818eabf27c7f7cdb3fc6099e344 Mon Sep 17 00:00:00 2001 From: David C Ellis Date: Fri, 12 Jul 2024 19:43:54 +0100 Subject: [PATCH] Add private parameter to `attribute` to make it easier to create cached values. --- src/ducktools/classbuilder/prefab.py | 11 +++++++++++ src/ducktools/classbuilder/prefab.pyi | 1 + tests/prefab/dynamic/test_private.py | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/prefab/dynamic/test_private.py diff --git a/src/ducktools/classbuilder/prefab.py b/src/ducktools/classbuilder/prefab.py index 61c73aa..5ca1e31 100644 --- a/src/ducktools/classbuilder/prefab.py +++ b/src/ducktools/classbuilder/prefab.py @@ -294,6 +294,7 @@ def attribute( kw_only=False, serialize=True, exclude_field=False, + private=False, doc=None, type=NOTHING, ): @@ -310,6 +311,7 @@ def attribute( :param kw_only: Make this argument keyword only in init :param serialize: Include this attribute in methods that serialize to dict :param exclude_field: Shorthand for setting repr, compare, iter and serialize to False + :param private: Short for init, repr, compare, iter, serialize = False, must have default or factory :param doc: Parameter documentation for slotted classes :param type: Type of this attribute (for slotted classes) @@ -321,6 +323,15 @@ def attribute( iter = False serialize = False + if private: + if default is NOTHING and default_factory is NOTHING: + raise AttributeError("Private attributes must have defaults or factories.") + init = False + repr = False + compare = False + iter = False + serialize = False + return Attribute( default=default, default_factory=default_factory, diff --git a/src/ducktools/classbuilder/prefab.pyi b/src/ducktools/classbuilder/prefab.pyi index da9718e..4d7073b 100644 --- a/src/ducktools/classbuilder/prefab.pyi +++ b/src/ducktools/classbuilder/prefab.pyi @@ -81,6 +81,7 @@ def attribute( kw_only: bool = False, serialize: bool = True, exclude_field: bool = False, + private: bool = False, ) -> Attribute: ... def prefab_gatherer(cls_or_ns: type | MappingProxyType) -> tuple[dict[str, Attribute], dict[str, typing.Any]]: ... diff --git a/tests/prefab/dynamic/test_private.py b/tests/prefab/dynamic/test_private.py new file mode 100644 index 0000000..26e1375 --- /dev/null +++ b/tests/prefab/dynamic/test_private.py @@ -0,0 +1,24 @@ +from ducktools.classbuilder.prefab import Prefab, attribute, get_attributes + + +def test_private_attribute(): + class Ex(Prefab): + _internal: str | None = attribute(default=None, private=True) + a: int + b: str + + + ex = Ex(1, "Hello") + + assert ex.a == 1 + assert ex.b == "Hello" + + assert ex._internal is None + + _internal_attrib = get_attributes(Ex)["_internal"] + + assert _internal_attrib.init is False + assert _internal_attrib.repr is False + assert _internal_attrib.iter is False + assert _internal_attrib.compare is False + assert _internal_attrib.serialize is False