Coverage for lynceus/utils/lynceus_dict.py: 100%
27 statements
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-29 08:46 +0000
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-29 08:46 +0000
1class LynceusDict(dict):
2 """
3 Little dict enhancement allowing [.] attribute access, in addition to usual [key] ones.
4 """
6 def __getattr__(self, key):
7 """
8 Enable attribute-style access to dictionary keys.
10 Allows accessing dictionary items using dot notation (e.g., obj.key)
11 in addition to standard bracket notation (e.g., obj['key']).
13 Parameters
14 ----------
15 key : str
16 The dictionary key to access as an attribute.
18 Returns
19 -------
20 Any
21 The value associated with the key.
23 Raises
24 ------
25 AttributeError
26 If the key does not exist in the dictionary.
27 """
28 try:
29 return self[key]
30 except KeyError as key_error:
31 raise AttributeError from key_error
33 def __setattr__(self, key, value):
34 """
35 Enable attribute-style assignment to dictionary keys.
37 Allows setting dictionary items using dot notation (e.g., obj.key = value)
38 in addition to standard bracket notation (e.g., obj['key'] = value).
40 Parameters
41 ----------
42 key : str
43 The dictionary key to set as an attribute.
44 value : Any
45 The value to assign to the key.
46 """
47 self[key] = value
49 def __delattr__(self, key):
50 """
51 Enable attribute-style deletion of dictionary keys.
53 Allows deleting dictionary items using dot notation (e.g., del obj.key)
54 in addition to standard bracket notation (e.g., del obj['key']).
56 Parameters
57 ----------
58 key : str
59 The dictionary key to delete as an attribute.
61 Raises
62 ------
63 AttributeError
64 If the key does not exist in the dictionary.
65 """
66 try:
67 del self[key]
68 except KeyError as key_error:
69 raise AttributeError from key_error
71 @staticmethod
72 def _do_to_lynceus_dict(obj, *, max_depth: int, depth: int = 0):
73 """
74 Internal recursive method to convert nested objects to LynceusDict instances.
76 Recursively traverses an object structure and converts dictionaries and
77 objects with __dict__ attributes to LynceusDict instances up to a specified
78 maximum depth to prevent infinite recursion.
80 Parameters
81 ----------
82 obj : Any
83 The object to convert.
84 max_depth : int
85 Maximum recursion depth allowed.
86 depth : int, optional
87 Current recursion depth. Defaults to 0.
89 Returns
90 -------
91 Any
92 The converted object with nested dictionaries as LynceusDict instances,
93 or the original object if max_depth is reached or no conversion is needed.
94 """
95 if depth >= max_depth:
96 return obj
98 if isinstance(obj, dict):
99 return LynceusDict(
100 {
101 k: LynceusDict._do_to_lynceus_dict(
102 v, max_depth=max_depth, depth=depth + 1
103 )
104 for k, v in obj.items()
105 }
106 )
108 if hasattr(obj, "__dict__"):
109 return LynceusDict(
110 {
111 k: LynceusDict._do_to_lynceus_dict(
112 v, max_depth=max_depth, depth=depth + 1
113 )
114 for k, v in obj.__dict__.items()
115 }
116 )
118 if isinstance(obj, list):
119 return [
120 LynceusDict._do_to_lynceus_dict(
121 elem, max_depth=max_depth, depth=depth + 1
122 )
123 for elem in obj
124 ]
126 return obj
128 @staticmethod
129 def to_lynceus_dict(obj, *, max_depth: int = 4):
130 """
131 Convert an object to a LynceusDict with nested dictionary conversion.
133 Converts dictionaries, objects with __dict__ attributes, and lists containing
134 such objects to LynceusDict instances recursively up to the specified depth.
135 This enables dot notation access throughout the nested structure.
137 Parameters
138 ----------
139 obj : Any
140 The object to convert to LynceusDict.
141 max_depth : int, optional
142 Maximum recursion depth to prevent infinite
143 recursion. Defaults to 4.
145 Returns
146 -------
147 LynceusDict | Any
148 A LynceusDict instance if the object is convertible,
149 otherwise returns the original object.
151 Examples
152 --------
153 >>> data = {'user': {'name': 'John', 'age': 30}}
154 >>> lynceus_data = LynceusDict.to_lynceus_dict(data)
155 >>> lynceus_data.user.name # Access using dot notation
156 'John'
157 """
158 return LynceusDict._do_to_lynceus_dict(obj, max_depth=max_depth)