Skip to content

Commit 87a56f8

Browse files
committed
Add sdbus.utils.parse_get_managed_objects
Parses data from ObjectsManager's `get_managed_objects` calls. It is similar to existing `parse_interfaces_added` function. Also reduce code duplication in sdbus.utils using extra functions.
1 parent 04d14b0 commit 87a56f8

File tree

3 files changed

+259
-79
lines changed

3 files changed

+259
-79
lines changed

docs/utils.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,22 @@ Parsing utilities
5959
of interface class.
6060
:rtype: Tuple[str, Optional[Type[DbusInterfaceBaseAsync]]]
6161
:returns: Path of removed object and object's class (or ``None``).
62+
63+
.. py:function:: parse_get_managed_objects(interfaces, managed_objects_data, on_unknown_interface='error', on_unknown_member='error')
64+
65+
Parse data from :py:meth:`get_managed_objects <sdbus.DbusObjectManagerInterfaceAsync.get_managed_objects>` call.
66+
67+
Takes an iterable of D-Bus interface classes (or a single class) and the method returned data.
68+
Returns a dictionary where keys a paths of the managed objects and value is a tuple of class of the object
69+
and dictionary of its python named properties and their values.
70+
71+
:param Iterable[DbusInterfaceBaseAsync] interfaces: Possible interfaces of the managed objects.
72+
Can accept classes with multiple interfaces defined.
73+
:param Dict interfaces_added_data: Data returned by ``get_managed_objects`` call.
74+
:param str on_unknown_member: If an unknown D-Bus interface was encountered
75+
either raise an ``"error"`` (default) or return ``"none"`` instead
76+
of interface class.
77+
:rtype: Dict[str, Tuple[Optional[Type[DbusInterfaceBaseAsync], Dict[str, Any]]]]
78+
:returns: Dictionary where keys are paths and values are tuples of managed objects classes and their properties data.
79+
80+
*New in version 0.12.0.*

src/sdbus/utils.py

Lines changed: 141 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,27 @@
4444

4545
from .dbus_proxy_async_interfaces import DBUS_PROPERTIES_CHANGED_TYPING
4646

47+
InterfacesInputElements = Union[
48+
DbusInterfaceBaseAsync,
49+
Type[DbusInterfaceBaseAsync],
50+
]
51+
InterfacesInput = Union[
52+
InterfacesInputElements,
53+
Iterable[InterfacesInputElements],
54+
]
55+
InterfacesToClassMap = Dict[FrozenSet[str], Type[DbusInterfaceBaseAsync]]
56+
OnUnknownMember = Literal['error', 'ignore', 'reuse']
57+
OnUnknownInterface = Literal['error', 'none']
58+
ParseGetManaged = Dict[
59+
str,
60+
Tuple[Optional[Type[DbusInterfaceBaseAsync]], Dict[str, Any]],
61+
]
62+
4763

4864
def parse_properties_changed(
49-
interface: Union[DbusInterfaceBaseAsync, Type[DbusInterfaceBaseAsync]],
65+
interface: InterfacesInputElements,
5066
properties_changed_data: DBUS_PROPERTIES_CHANGED_TYPING,
51-
on_unknown_member: Literal['error', 'ignore', 'reuse'] = 'error',
67+
on_unknown_member: OnUnknownMember = 'error',
5268
) -> Dict[str, Any]:
5369
interface_name, changed_properties, invalidated_properties = (
5470
properties_changed_data
@@ -75,17 +91,16 @@ def parse_properties_changed(
7591

7692

7793
def _create_interfaces_map(
78-
interfaces_iter: Iterable[
79-
Union[
80-
DbusInterfaceBaseAsync,
81-
Type[DbusInterfaceBaseAsync],
82-
]
83-
]
84-
) -> Dict[FrozenSet[str], Type[DbusInterfaceBaseAsync]]:
85-
interfaces_to_class_map: Dict[
86-
FrozenSet[str],
87-
Type[DbusInterfaceBaseAsync],
88-
] = {}
94+
interfaces: InterfacesInput,
95+
) -> InterfacesToClassMap:
96+
97+
if isinstance(interfaces,
98+
(DbusInterfaceBaseAsync, type)):
99+
interfaces_iter = iter((interfaces, ))
100+
else:
101+
interfaces_iter = iter(interfaces)
102+
103+
interfaces_to_class_map: InterfacesToClassMap = {}
89104

90105
for interface in interfaces_iter:
91106
interface_names_set = frozenset(
@@ -101,51 +116,74 @@ def _create_interfaces_map(
101116
return interfaces_to_class_map
102117

103118

119+
def _get_class_from_interfaces(
120+
interfaces_to_class_map: InterfacesToClassMap,
121+
interface_names_iter: Iterable[str],
122+
raise_key_error: bool,
123+
) -> Optional[Type[DbusInterfaceBaseAsync]]:
124+
class_set = frozenset(interface_names_iter) - SKIP_INTERFACES
125+
try:
126+
return interfaces_to_class_map[class_set]
127+
except KeyError:
128+
if raise_key_error:
129+
raise
130+
131+
return None
132+
133+
134+
def _get_member_map_from_class(
135+
python_class: Optional[Type[DbusInterfaceBaseAsync]],
136+
) -> Dict[str, Dict[str, str]]:
137+
if python_class is None:
138+
return {}
139+
else:
140+
return {
141+
interface_name: meta.dbus_member_to_python_attr
142+
for interface_name, meta in
143+
python_class._dbus_iter_interfaces_meta()
144+
}
145+
146+
147+
def _translate_and_merge_members(
148+
properties_data: Dict[str, Dict[str, Any]],
149+
dbus_to_python_map: Dict[str, Dict[str, str]],
150+
on_unknown_member: OnUnknownMember,
151+
) -> Dict[str, Any]:
152+
python_properties: Dict[str, Any] = {}
153+
for interface_name, properties in properties_data.items():
154+
interface_member_map = dbus_to_python_map.get(
155+
interface_name, {},
156+
)
157+
python_properties.update(
158+
_parse_properties_vardict(
159+
interface_member_map,
160+
properties,
161+
on_unknown_member,
162+
)
163+
)
164+
165+
return python_properties
166+
167+
104168
def parse_interfaces_added(
105-
interfaces: Union[
106-
Union[
107-
DbusInterfaceBaseAsync,
108-
Type[DbusInterfaceBaseAsync],
109-
],
110-
Iterable[
111-
Union[
112-
DbusInterfaceBaseAsync,
113-
Type[DbusInterfaceBaseAsync],
114-
],
115-
],
116-
],
169+
interfaces: InterfacesInput,
117170
interfaces_added_data: Tuple[str, Dict[str, Dict[str, Any]]],
118-
on_unknown_interface: Literal['error', 'none'] = 'error',
119-
on_unknown_member: Literal['error', 'ignore', 'reuse'] = 'error',
171+
on_unknown_interface: OnUnknownInterface = 'error',
172+
on_unknown_member: OnUnknownMember = 'error',
120173
) -> Tuple[str, Optional[Type[DbusInterfaceBaseAsync]], Dict[str, Any]]:
121174

122-
if isinstance(interfaces,
123-
(DbusInterfaceBaseAsync, type)):
124-
interfaces_iter = iter((interfaces, ))
125-
else:
126-
interfaces_iter = iter(interfaces)
127-
128-
interfaces_to_class_map = _create_interfaces_map(interfaces_iter)
175+
interfaces_to_class_map = _create_interfaces_map(interfaces)
129176

130177
path, properties_data = interfaces_added_data
131178

132-
class_set = frozenset(properties_data.keys()) - SKIP_INTERFACES
133-
try:
134-
python_class = interfaces_to_class_map[class_set]
135-
dbus_to_python_member_map: Dict[str, Dict[str, str]] = (
136-
{
137-
interface_name: meta.dbus_member_to_python_attr
138-
for interface_name, meta in
139-
python_class._dbus_iter_interfaces_meta()
140-
}
179+
python_class = (
180+
_get_class_from_interfaces(
181+
interfaces_to_class_map,
182+
properties_data.keys(),
183+
on_unknown_interface == "error",
141184
)
142-
except KeyError:
143-
if on_unknown_interface == 'error':
144-
raise
145-
146-
python_class = None
147-
dbus_to_python_member_map = {}
148-
185+
)
186+
dbus_to_python_member_map = _get_member_map_from_class(python_class)
149187
python_properties: Dict[str, Any] = {}
150188
for interface_name, properties in properties_data.items():
151189
interface_member_map = dbus_to_python_member_map.get(
@@ -159,49 +197,74 @@ def parse_interfaces_added(
159197
)
160198
)
161199

162-
return path, python_class, python_properties
200+
return (
201+
path,
202+
python_class,
203+
_translate_and_merge_members(
204+
properties_data,
205+
dbus_to_python_member_map,
206+
on_unknown_member,
207+
),
208+
)
163209

164210

165211
def parse_interfaces_removed(
166-
interfaces: Union[
167-
Union[
168-
DbusInterfaceBaseAsync,
169-
Type[DbusInterfaceBaseAsync],
170-
],
171-
Iterable[
172-
Union[
173-
DbusInterfaceBaseAsync,
174-
Type[DbusInterfaceBaseAsync],
175-
],
176-
],
177-
],
212+
interfaces: InterfacesInput,
178213
interfaces_removed_data: Tuple[str, List[str]],
179-
on_unknown_interface: Literal['error', 'none'] = 'error',
214+
on_unknown_interface: OnUnknownInterface = 'error',
180215
) -> Tuple[str, Optional[Type[DbusInterfaceBaseAsync]]]:
181-
if isinstance(interfaces,
182-
(DbusInterfaceBaseAsync, type)):
183-
interfaces_iter = iter((interfaces, ))
184-
else:
185-
interfaces_iter = iter(interfaces)
186216

187-
interfaces_to_class_map = _create_interfaces_map(interfaces_iter)
217+
interfaces_to_class_map = _create_interfaces_map(interfaces)
188218

189219
path, interfaces_removed = interfaces_removed_data
190220

191-
class_set = frozenset(interfaces_removed) - SKIP_INTERFACES
192-
try:
193-
python_class = interfaces_to_class_map[class_set]
194-
except KeyError:
195-
if on_unknown_interface == 'error':
196-
raise
197-
198-
python_class = None
221+
python_class = (
222+
_get_class_from_interfaces(
223+
interfaces_to_class_map,
224+
interfaces_removed,
225+
on_unknown_interface == "error",
226+
)
227+
)
199228

200229
return path, python_class
201230

202231

232+
def parse_get_managed_objects(
233+
interfaces: InterfacesInput,
234+
managed_objects_data: Dict[str, Dict[str, Dict[str, Any]]],
235+
on_unknown_interface: OnUnknownInterface = 'error',
236+
on_unknown_member: OnUnknownMember = 'error',
237+
) -> ParseGetManaged:
238+
239+
interfaces_to_class_map = _create_interfaces_map(interfaces)
240+
241+
managed_objects_map: ParseGetManaged = {}
242+
243+
for path, properties_data in managed_objects_data.items():
244+
python_class = (
245+
_get_class_from_interfaces(
246+
interfaces_to_class_map,
247+
properties_data.keys(),
248+
on_unknown_interface == "error",
249+
)
250+
)
251+
dbus_to_python_member_map = _get_member_map_from_class(python_class)
252+
253+
managed_objects_map[path] = (
254+
python_class,
255+
_translate_and_merge_members(
256+
properties_data,
257+
dbus_to_python_member_map,
258+
on_unknown_member,
259+
),
260+
)
261+
262+
return managed_objects_map
263+
264+
203265
__all__ = (
204266
'parse_properties_changed',
205267
'parse_interfaces_added',
206268
'parse_interfaces_removed',
269+
'parse_get_managed_objects',
207270
)

0 commit comments

Comments
 (0)