Coverage for flogin/flow/base.py: 100%
28 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 22:51 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 22:51 +0000
1from __future__ import annotations
3from collections.abc import Callable
4from inspect import getmembers
5from typing import Any
7from ..utils import MISSING
9ValidCls = Callable[[Any], Any]
12def _convert_cls(orig: ValidCls, is_list: bool) -> ValidCls:
13 if orig is MISSING:
14 return lambda x: x
15 if orig is not MISSING and is_list is True:
16 return lambda item: [orig(x) for x in item]
17 return orig
20def _get_prop_func(
21 cls: ValidCls, name: str, *, default: Any = MISSING
22) -> Callable[[Any], Any]:
23 if default is MISSING:
25 def func(self: Any) -> Any:
26 return cls(self._data[name])
28 else:
30 def func(self: Any) -> Any:
31 return cls(self._data.get(name, default))
33 return func
36def add_prop(
37 name: str,
38 *,
39 default: Any = MISSING,
40 cls: ValidCls = MISSING,
41 is_list: bool = False,
42) -> Any:
43 cls = _convert_cls(cls, is_list)
44 func = _get_prop_func(cls, name, default=default)
46 return property(func)
49class Base:
50 __slots__ = ("__repr_attributes__", "_data")
52 def __init__(self, data: dict[str, Any]) -> None:
53 self._data = data
54 self.__repr_attributes__ = [
55 entry[0]
56 for entry in getmembers(
57 self.__class__, lambda other: isinstance(other, property)
58 )
59 ]
61 def __repr__(self) -> str:
62 args = [f"{item}={getattr(self, item)!r}" for item in self.__repr_attributes__]
63 return f"<{self.__class__.__name__} {' '.join(args)}>"