Coverage for / home / runner / work / viur-core / viur-core / viur / src / viur / core / skeleton / utils.py: 15%
60 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-25 14:23 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-25 14:23 +0000
1import typing as t
3from .meta import MetaBaseSkel
5if t.TYPE_CHECKING: 5 ↛ 6line 5 didn't jump to line 6 because the condition on line 5 was never true
6 from . import RefSkel, Skeleton, SkeletonInstance
9def skeletonByKind(kindName: str) -> t.Type["Skeleton"]:
10 """
11 Returns the Skeleton-Class for the given kindName. That skeleton must exist, otherwise an exception is raised.
12 :param kindName: The kindname to retreive the skeleton for
13 :return: The skeleton-class for that kind
14 """
15 assert kindName in MetaBaseSkel._skelCache, f"Unknown skeleton {kindName=}"
16 return MetaBaseSkel._skelCache[kindName]
19def listKnownSkeletons() -> list[str]:
20 """
21 :return: A list of all known kindnames (all kindnames for which a skeleton is defined)
22 """
23 return sorted(MetaBaseSkel._skelCache.keys())
26def iterAllSkelClasses() -> t.Iterable["Skeleton"]:
27 """
28 :return: An iterator that yields each Skeleton-Class once. (Only top-level skeletons are returned, so no
29 RefSkel classes will be included)
30 """
31 for cls in list(MetaBaseSkel._allSkelClasses): # We'll add new classes here during setSystemInitialized()
32 yield cls
35class SkelList(list):
36 """
37 This class is used to hold multiple skeletons together with other, commonly used information.
39 SkelLists are returned by Skel().all()...fetch()-constructs and provide additional information
40 about the data base query, for fetching additional entries.
42 :ivar cursor: Holds the cursor within a query.
43 :vartype cursor: str
44 """
46 __slots__ = (
47 "baseSkel",
48 "customQueryInfo",
49 "getCursor",
50 "get_orders",
51 "renderPreparation",
52 )
54 def __init__(self, skel, *items):
55 """
56 :param baseSkel: The baseclass for all entries in this list
57 """
58 super().__init__()
59 self.baseSkel = skel or {}
60 self.getCursor = lambda: None
61 self.get_orders = lambda: None
62 self.renderPreparation = None
63 self.customQueryInfo = {}
65 self.extend(items)
68# FIXME: REMOVE WITH VIUR4
69def remove_render_preparation_deep(skel: t.Any) -> t.Any:
70 """Remove renderPreparation of nested skeletons
72 _refSkelCache can have renderPreparation too.
73 """
74 from .instance import SkeletonInstance
76 if isinstance(skel, SkeletonInstance):
77 skel.renderPreparation = None
78 for _, value in skel.items(yieldBoneValues=True):
79 remove_render_preparation_deep(value)
80 elif isinstance(skel, dict):
81 for value in skel.values():
82 remove_render_preparation_deep(value)
83 elif isinstance(skel, (list, tuple, set)):
84 for value in skel:
85 remove_render_preparation_deep(value)
87 return skel
90def without_render_preparation(skel: "SkeletonInstance", full_clone: bool = False) -> "SkeletonInstance":
91 """Return the SkeletonInstance without renderPreparation.
93 This method is useful (and unfortunately necessary due to the ViUR design)
94 if you call python methods from the jinja template that should work on the
95 `SkeletonInstance.accessedValues` and not on the `SkeletonInstance.renderAccessedValues`.
97 If the SkeletonInstance does not have renderPreparation, it will be returned as is.
98 If renderPreparation is enabled, a new SkeletonInstance is created.
99 However, unless `full_clone` is True, the SkeletonInstance will use the
100 identical objects as the source skeleton. It just "removes" the
101 "renderPreparation mode" and keep it for the source skel enabled.
102 """
103 from . import SkeletonInstance
104 if skel.renderPreparation is not None:
105 if full_clone:
106 skel = skel.clone()
107 else:
108 src_skel = skel
109 # Create a new SkeletonInstance with the same object,
110 # but without enabled renderPreparation
111 skel = SkeletonInstance(src_skel.skeletonCls, bone_map=src_skel.boneMap)
112 skel.accessedValues = src_skel.accessedValues
113 skel.dbEntity = src_skel.dbEntity
114 skel.errors = src_skel.errors
115 skel.is_cloned = src_skel.is_cloned
116 assert skel.renderPreparation is None
117 skel = remove_render_preparation_deep(skel)
118 return skel
121def is_skeletoninstance_of(
122 obj: t.Any,
123 skel_cls: type["Skeleton"],
124 *,
125 accept_ref_skel: bool = True,
126) -> bool:
127 """
128 Checks whether an object is an SkeletonInstance that belongs to a specific Skeleton class.
130 :param obj: The object to check.
131 :param skel_cls: The skeleton class that will be checked against ``obj``.
132 :param accept_ref_skel: If True, ``obj`` can also be just a RefSkelFor``skel_cls``.
133 If False, no ``RefSkel`` is accepted.
134 """
135 from . import RefSkel, Skeleton, SkeletonInstance
137 if not issubclass(skel_cls, Skeleton):
138 raise TypeError(f"{skel_cls=} is not a Skeleton.")
140 if not isinstance(obj, SkeletonInstance):
141 return False
142 if issubclass(obj.skeletonCls, skel_cls):
143 return True
144 if accept_ref_skel and issubclass(obj.skeletonCls, RefSkel) and issubclass(obj.skeletonCls.skeletonCls, skel_cls):
145 return True
146 return False