dbus-fast 2.45.1__cp311-cp311-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dbus-fast might be problematic. Click here for more details.

Files changed (51) hide show
  1. dbus_fast/__init__.py +82 -0
  2. dbus_fast/__version__.py +10 -0
  3. dbus_fast/_private/__init__.py +1 -0
  4. dbus_fast/_private/_cython_compat.py +14 -0
  5. dbus_fast/_private/address.cpython-311-darwin.so +0 -0
  6. dbus_fast/_private/address.pxd +15 -0
  7. dbus_fast/_private/address.py +117 -0
  8. dbus_fast/_private/constants.py +20 -0
  9. dbus_fast/_private/marshaller.cpython-311-darwin.so +0 -0
  10. dbus_fast/_private/marshaller.pxd +110 -0
  11. dbus_fast/_private/marshaller.py +228 -0
  12. dbus_fast/_private/unmarshaller.cpython-311-darwin.so +0 -0
  13. dbus_fast/_private/unmarshaller.pxd +261 -0
  14. dbus_fast/_private/unmarshaller.py +902 -0
  15. dbus_fast/_private/util.py +176 -0
  16. dbus_fast/aio/__init__.py +5 -0
  17. dbus_fast/aio/message_bus.py +578 -0
  18. dbus_fast/aio/message_reader.cpython-311-darwin.so +0 -0
  19. dbus_fast/aio/message_reader.pxd +13 -0
  20. dbus_fast/aio/message_reader.py +49 -0
  21. dbus_fast/aio/proxy_object.py +207 -0
  22. dbus_fast/auth.py +126 -0
  23. dbus_fast/constants.py +152 -0
  24. dbus_fast/errors.py +84 -0
  25. dbus_fast/glib/__init__.py +3 -0
  26. dbus_fast/glib/message_bus.py +515 -0
  27. dbus_fast/glib/proxy_object.py +319 -0
  28. dbus_fast/introspection.py +683 -0
  29. dbus_fast/message.cpython-311-darwin.so +0 -0
  30. dbus_fast/message.pxd +76 -0
  31. dbus_fast/message.py +387 -0
  32. dbus_fast/message_bus.cpython-311-darwin.so +0 -0
  33. dbus_fast/message_bus.pxd +75 -0
  34. dbus_fast/message_bus.py +1310 -0
  35. dbus_fast/proxy_object.py +358 -0
  36. dbus_fast/py.typed +0 -0
  37. dbus_fast/send_reply.py +61 -0
  38. dbus_fast/service.cpython-311-darwin.so +0 -0
  39. dbus_fast/service.pxd +50 -0
  40. dbus_fast/service.py +686 -0
  41. dbus_fast/signature.cpython-311-darwin.so +0 -0
  42. dbus_fast/signature.pxd +31 -0
  43. dbus_fast/signature.py +481 -0
  44. dbus_fast/unpack.cpython-311-darwin.so +0 -0
  45. dbus_fast/unpack.pxd +13 -0
  46. dbus_fast/unpack.py +24 -0
  47. dbus_fast/validators.py +199 -0
  48. dbus_fast-2.45.1.dist-info/METADATA +263 -0
  49. dbus_fast-2.45.1.dist-info/RECORD +51 -0
  50. dbus_fast-2.45.1.dist-info/WHEEL +6 -0
  51. dbus_fast-2.45.1.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,683 @@
1
+ import xml.etree.ElementTree as ET
2
+ from typing import Optional, Union
3
+
4
+ from .constants import ArgDirection, PropertyAccess
5
+ from .errors import InvalidIntrospectionError
6
+ from .signature import SignatureType, get_signature_tree
7
+ from .validators import assert_interface_name_valid, assert_member_name_valid
8
+
9
+ # https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
10
+
11
+
12
+ def _fetch_annotations(element: ET.Element) -> dict[str, str]:
13
+ annotations: dict[str, str] = {}
14
+
15
+ for child in element:
16
+ if child.tag != "annotation":
17
+ continue
18
+ annotation_name = child.attrib["name"]
19
+ annotation_value = child.attrib["value"]
20
+ annotations[annotation_name] = annotation_value
21
+
22
+ return annotations
23
+
24
+
25
+ def _extract_annotations(element: ET.Element, annotations: dict[str, str]) -> None:
26
+ for key, value in annotations.items():
27
+ annotation = ET.Element("annotation", {"name": key, "value": value})
28
+ element.append(annotation)
29
+
30
+
31
+ class Arg:
32
+ """A class that represents an input or output argument to a signal or a method.
33
+
34
+ :ivar name: The name of this arg.
35
+ :vartype name: str
36
+ :ivar direction: Whether this is an input or an output argument.
37
+ :vartype direction: :class:`ArgDirection <dbus_fast.ArgDirection>`
38
+ :ivar type: The parsed signature type of this argument.
39
+ :vartype type: :class:`SignatureType <dbus_fast.SignatureType>`
40
+ :ivar signature: The signature string of this argument.
41
+ :vartype signature: str
42
+ :ivar annotations: The annotations of this arg.
43
+ :vartype annotations: dict[str, str]
44
+
45
+ :raises:
46
+ - :class:`InvalidMemberNameError <dbus_fast.InvalidMemberNameError>` - If the name of the arg is not valid.
47
+ - :class:`InvalidSignatureError <dbus_fast.InvalidSignatureError>` - If the signature is not valid.
48
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the signature is not a single complete type.
49
+ """
50
+
51
+ def __init__(
52
+ self,
53
+ signature: Union[SignatureType, str],
54
+ direction: Optional[ArgDirection] = None,
55
+ name: Optional[str] = None,
56
+ annotations: Optional[dict[str, str]] = None,
57
+ ):
58
+ type_ = None
59
+ if type(signature) is SignatureType:
60
+ type_ = signature
61
+ signature = signature.signature
62
+ else:
63
+ tree = get_signature_tree(signature)
64
+ if len(tree.types) != 1:
65
+ raise InvalidIntrospectionError(
66
+ f"an argument must have a single complete type. (has {len(tree.types)} types)"
67
+ )
68
+ type_ = tree.types[0]
69
+
70
+ self.type = type_
71
+ self.signature = signature
72
+ self.name = name
73
+ self.direction = direction
74
+ self.annotations = annotations or {}
75
+
76
+ def from_xml(element: ET.Element, direction: ArgDirection) -> "Arg":
77
+ """Convert a :class:`xml.etree.ElementTree.Element` into a
78
+ :class:`Arg`.
79
+
80
+ The element must be valid DBus introspection XML for an ``arg``.
81
+
82
+ :param element: The parsed XML element.
83
+ :type element: :class:`xml.etree.ElementTree.Element`
84
+ :param direction: The direction of this arg. Must be specified because it can default to different values depending on if it's in a method or signal.
85
+ :type direction: :class:`ArgDirection <dbus_fast.ArgDirection>`
86
+
87
+ :raises:
88
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
89
+ """
90
+ name = element.attrib.get("name")
91
+ signature = element.attrib.get("type")
92
+
93
+ if not signature:
94
+ raise InvalidIntrospectionError(
95
+ 'a method argument must have a "type" attribute'
96
+ )
97
+
98
+ annotations = _fetch_annotations(element)
99
+
100
+ return Arg(signature, direction, name, annotations)
101
+
102
+ def to_xml(self) -> ET.Element:
103
+ """Convert this :class:`Arg` into an :class:`xml.etree.ElementTree.Element`."""
104
+ element = ET.Element("arg")
105
+ if self.name:
106
+ element.set("name", self.name)
107
+
108
+ if self.direction:
109
+ element.set("direction", self.direction.value)
110
+ element.set("type", self.signature)
111
+
112
+ _extract_annotations(element, self.annotations)
113
+
114
+ return element
115
+
116
+
117
+ class Signal:
118
+ """A class that represents a signal exposed on an interface.
119
+
120
+ :ivar name: The name of this signal
121
+ :vartype name: str
122
+ :ivar args: A list of output arguments for this signal.
123
+ :vartype args: list(Arg)
124
+ :ivar signature: The collected signature of the output arguments.
125
+ :vartype signature: str
126
+ :ivar annotations: The annotations of this signal.
127
+ :vartype annotations: dict[str, str]
128
+
129
+ :raises:
130
+ - :class:`InvalidMemberNameError <dbus_fast.InvalidMemberNameError>` - If the name of the signal is not a valid member name.
131
+ """
132
+
133
+ def __init__(
134
+ self,
135
+ name: str,
136
+ args: Optional[list[Arg]] = None,
137
+ annotations: Optional[dict[str, str]] = None,
138
+ ):
139
+ if name is not None:
140
+ assert_member_name_valid(name)
141
+
142
+ self.name = name
143
+ self.args = args or []
144
+ self.signature = "".join(arg.signature for arg in self.args)
145
+ self.annotations = annotations or {}
146
+
147
+ def from_xml(element):
148
+ """Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Signal`.
149
+
150
+ The element must be valid DBus introspection XML for a ``signal``.
151
+
152
+ :param element: The parsed XML element.
153
+ :type element: :class:`xml.etree.ElementTree.Element`
154
+ :param is_root: Whether this is the root node
155
+ :type is_root: bool
156
+
157
+ :raises:
158
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
159
+ """
160
+ name = element.attrib.get("name")
161
+ if not name:
162
+ raise InvalidIntrospectionError('signals must have a "name" attribute')
163
+
164
+ args = []
165
+ for child in element:
166
+ if child.tag == "arg":
167
+ args.append(Arg.from_xml(child, ArgDirection.OUT))
168
+
169
+ annotations = _fetch_annotations(element)
170
+
171
+ signal = Signal(name, args, annotations)
172
+
173
+ return signal
174
+
175
+ def to_xml(self) -> ET.Element:
176
+ """Convert this :class:`Signal` into an :class:`xml.etree.ElementTree.Element`."""
177
+ element = ET.Element("signal")
178
+ element.set("name", self.name)
179
+
180
+ for arg in self.args:
181
+ element.append(arg.to_xml())
182
+
183
+ _extract_annotations(element, self.annotations)
184
+
185
+ return element
186
+
187
+
188
+ class Method:
189
+ """A class that represents a method exposed on an :class:`Interface`.
190
+
191
+ :ivar name: The name of this method.
192
+ :vartype name: str
193
+ :ivar in_args: A list of input arguments to this method.
194
+ :vartype in_args: list(Arg)
195
+ :ivar out_args: A list of output arguments to this method.
196
+ :vartype out_args: list(Arg)
197
+ :ivar in_signature: The collected signature string of the input arguments.
198
+ :vartype in_signature: str
199
+ :ivar out_signature: The collected signature string of the output arguments.
200
+ :vartype out_signature: str
201
+ :ivar annotations: The annotations of this method.
202
+ :vartype annotations: dict[str, str]
203
+
204
+ :raises:
205
+ - :class:`InvalidMemberNameError <dbus_fast.InvalidMemberNameError>` - If the name of this method is not valid.
206
+ """
207
+
208
+ def __init__(
209
+ self,
210
+ name: str,
211
+ in_args: list[Arg] = [],
212
+ out_args: list[Arg] = [],
213
+ annotations: Optional[dict[str, str]] = None,
214
+ ):
215
+ assert_member_name_valid(name)
216
+
217
+ self.name = name
218
+ self.in_args = in_args
219
+ self.out_args = out_args
220
+ self.in_signature = "".join(arg.signature for arg in in_args)
221
+ self.out_signature = "".join(arg.signature for arg in out_args)
222
+ self.annotations = annotations or {}
223
+
224
+ def from_xml(element: ET.Element) -> "Method":
225
+ """Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Method`.
226
+
227
+ The element must be valid DBus introspection XML for a ``method``.
228
+
229
+ :param element: The parsed XML element.
230
+ :type element: :class:`xml.etree.ElementTree.Element`
231
+ :param is_root: Whether this is the root node
232
+ :type is_root: bool
233
+
234
+ :raises:
235
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
236
+ """
237
+ name = element.attrib.get("name")
238
+ if not name:
239
+ raise InvalidIntrospectionError('interfaces must have a "name" attribute')
240
+
241
+ in_args = []
242
+ out_args = []
243
+
244
+ for child in element:
245
+ if child.tag == "arg":
246
+ direction = ArgDirection(child.attrib.get("direction", "in"))
247
+ arg = Arg.from_xml(child, direction)
248
+ if direction == ArgDirection.IN:
249
+ in_args.append(arg)
250
+ elif direction == ArgDirection.OUT:
251
+ out_args.append(arg)
252
+
253
+ annotations = _fetch_annotations(element)
254
+
255
+ return Method(name, in_args, out_args, annotations)
256
+
257
+ def to_xml(self) -> ET.Element:
258
+ """Convert this :class:`Method` into an :class:`xml.etree.ElementTree.Element`."""
259
+ element = ET.Element("method")
260
+ element.set("name", self.name)
261
+
262
+ for arg in self.in_args:
263
+ element.append(arg.to_xml())
264
+ for arg in self.out_args:
265
+ element.append(arg.to_xml())
266
+
267
+ _extract_annotations(element, self.annotations)
268
+
269
+ return element
270
+
271
+
272
+ class Property:
273
+ """A class that represents a DBus property exposed on an
274
+ :class:`Interface`.
275
+
276
+ :ivar name: The name of this property.
277
+ :vartype name: str
278
+ :ivar signature: The signature string for this property. Must be a single complete type.
279
+ :vartype signature: str
280
+ :ivar access: Whether this property is readable and writable.
281
+ :vartype access: :class:`PropertyAccess <dbus_fast.PropertyAccess>`
282
+ :ivar type: The parsed type of this property.
283
+ :vartype type: :class:`SignatureType <dbus_fast.SignatureType>`
284
+ :ivar annotations: The annotations of this property.
285
+ :vartype annotations: dict[str, str]
286
+
287
+ :raises:
288
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the property is not a single complete type.
289
+ - :class `InvalidSignatureError <dbus_fast.InvalidSignatureError>` - If the given signature is not valid.
290
+ - :class: `InvalidMemberNameError <dbus_fast.InvalidMemberNameError>` - If the member name is not valid.
291
+ """
292
+
293
+ def __init__(
294
+ self,
295
+ name: str,
296
+ signature: str,
297
+ access: PropertyAccess = PropertyAccess.READWRITE,
298
+ annotations: Optional[dict[str, str]] = None,
299
+ validate: bool = True,
300
+ ):
301
+ if validate:
302
+ assert_member_name_valid(name)
303
+
304
+ tree = get_signature_tree(signature)
305
+ if len(tree.types) != 1:
306
+ raise InvalidIntrospectionError(
307
+ f"properties must have a single complete type. (has {len(tree.types)} types)"
308
+ )
309
+
310
+ self.name = name
311
+ self.signature = signature
312
+ self.access = access
313
+ self.type = tree.types[0]
314
+ self.annotations = annotations or {}
315
+
316
+ def from_xml(element, validate: bool = True):
317
+ """Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Property`.
318
+
319
+ The element must be valid DBus introspection XML for a ``property``.
320
+
321
+ :param element: The parsed XML element.
322
+ :type element: :class:`xml.etree.ElementTree.Element`
323
+
324
+ :raises:
325
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
326
+ """
327
+ name = element.attrib.get("name")
328
+ signature = element.attrib.get("type")
329
+ access = PropertyAccess(element.attrib.get("access", "readwrite"))
330
+
331
+ if not name:
332
+ raise InvalidIntrospectionError('properties must have a "name" attribute')
333
+ if not signature:
334
+ raise InvalidIntrospectionError('properties must have a "type" attribute')
335
+
336
+ annotations = _fetch_annotations(element)
337
+
338
+ return Property(
339
+ name, signature, access, annotations=annotations, validate=validate
340
+ )
341
+
342
+ def to_xml(self) -> ET.Element:
343
+ """Convert this :class:`Property` into an :class:`xml.etree.ElementTree.Element`."""
344
+ element = ET.Element("property")
345
+ element.set("name", self.name)
346
+ element.set("type", self.signature)
347
+ element.set("access", self.access.value)
348
+ _extract_annotations(element, self.annotations)
349
+ return element
350
+
351
+
352
+ class Interface:
353
+ """A class that represents a DBus interface exported on on object path.
354
+
355
+ Contains information about the methods, signals, and properties exposed on
356
+ this interface.
357
+
358
+ :ivar name: The name of this interface.
359
+ :vartype name: str
360
+ :ivar methods: A list of methods exposed on this interface.
361
+ :vartype methods: list(:class:`Method`)
362
+ :ivar signals: A list of signals exposed on this interface.
363
+ :vartype signals: list(:class:`Signal`)
364
+ :ivar properties: A list of properties exposed on this interface.
365
+ :vartype properties: list(:class:`Property`)
366
+ :ivar annotations: The annotations of this interface.
367
+ :vartype annotations: dict[str, str]
368
+
369
+ :raises:
370
+ - :class:`InvalidInterfaceNameError <dbus_fast.InvalidInterfaceNameError>` - If the name is not a valid interface name.
371
+ """
372
+
373
+ def __init__(
374
+ self,
375
+ name: str,
376
+ methods: Optional[list[Method]] = None,
377
+ signals: Optional[list[Signal]] = None,
378
+ properties: Optional[list[Property]] = None,
379
+ annotations: Optional[dict[str, str]] = None,
380
+ ):
381
+ assert_interface_name_valid(name)
382
+
383
+ self.name = name
384
+ self.methods = methods if methods is not None else []
385
+ self.signals = signals if signals is not None else []
386
+ self.properties = properties if properties is not None else []
387
+ self.annotations = annotations or {}
388
+
389
+ @staticmethod
390
+ def from_xml(
391
+ element: ET.Element, validate_property_names: bool = True
392
+ ) -> "Interface":
393
+ """Convert a :class:`xml.etree.ElementTree.Element` into a
394
+ :class:`Interface`.
395
+
396
+ The element must be valid DBus introspection XML for an ``interface``.
397
+
398
+ :param element: The parsed XML element.
399
+ :type element: :class:`xml.etree.ElementTree.Element`
400
+
401
+ :raises:
402
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
403
+ """
404
+ name = element.attrib.get("name")
405
+ if not name:
406
+ raise InvalidIntrospectionError('interfaces must have a "name" attribute')
407
+
408
+ interface = Interface(name)
409
+
410
+ for child in element:
411
+ if child.tag == "method":
412
+ interface.methods.append(Method.from_xml(child))
413
+ elif child.tag == "signal":
414
+ interface.signals.append(Signal.from_xml(child))
415
+ elif child.tag == "property":
416
+ interface.properties.append(
417
+ Property.from_xml(child, validate=validate_property_names)
418
+ )
419
+
420
+ interface.annotations = _fetch_annotations(element)
421
+
422
+ return interface
423
+
424
+ def to_xml(self) -> ET.Element:
425
+ """Convert this :class:`Interface` into an :class:`xml.etree.ElementTree.Element`."""
426
+ element = ET.Element("interface")
427
+ element.set("name", self.name)
428
+
429
+ for method in self.methods:
430
+ element.append(method.to_xml())
431
+ for signal in self.signals:
432
+ element.append(signal.to_xml())
433
+ for prop in self.properties:
434
+ element.append(prop.to_xml())
435
+
436
+ _extract_annotations(element, self.annotations)
437
+
438
+ return element
439
+
440
+
441
+ class Node:
442
+ """A class that represents a node in an object path in introspection data.
443
+
444
+ A node contains information about interfaces exported on this path and
445
+ child nodes. A node can be converted to and from introspection XML exposed
446
+ through the ``org.freedesktop.DBus.Introspectable`` standard DBus
447
+ interface.
448
+
449
+ This class is an essential building block for a high-level DBus interface.
450
+ This is the underlying data structure for the :class:`ProxyObject
451
+ <dbus_fast.proxy_object.BaseProxyInterface>`. A :class:`ServiceInterface
452
+ <dbus_fast.service.ServiceInterface>` definition is converted to this class
453
+ to expose XML on the introspectable interface.
454
+
455
+ :ivar interfaces: A list of interfaces exposed on this node.
456
+ :vartype interfaces: list(:class:`Interface <dbus_fast.introspection.Interface>`)
457
+ :ivar nodes: A list of child nodes.
458
+ :vartype nodes: list(:class:`Node`)
459
+ :ivar name: The object path of this node.
460
+ :vartype name: str
461
+ :ivar is_root: Whether this is the root node. False if it is a child node.
462
+ :vartype is_root: bool
463
+
464
+ :raises:
465
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the name is not a valid node name.
466
+ """
467
+
468
+ def __init__(
469
+ self,
470
+ name: Optional[str] = None,
471
+ interfaces: Optional[list[Interface]] = None,
472
+ is_root: bool = True,
473
+ ):
474
+ if not is_root and not name:
475
+ raise InvalidIntrospectionError('child nodes must have a "name" attribute')
476
+
477
+ self.interfaces = interfaces if interfaces is not None else []
478
+ self.nodes: list[Node] = []
479
+ self.name = name
480
+ self.is_root = is_root
481
+
482
+ @staticmethod
483
+ def from_xml(
484
+ element: ET.Element, is_root: bool = False, validate_property_names: bool = True
485
+ ) -> "Node":
486
+ """Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Node`.
487
+
488
+ The element must be valid DBus introspection XML for a ``node``.
489
+
490
+ :param element: The parsed XML element.
491
+ :type element: :class:`xml.etree.ElementTree.Element`
492
+ :param is_root: Whether this is the root node
493
+ :type is_root: bool
494
+ :param validate_property_names: Whether to validate property names or not
495
+ :type validate_property_names: bool
496
+
497
+ :raises:
498
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
499
+ """
500
+ node = Node(element.attrib.get("name"), is_root=is_root)
501
+
502
+ for child in element:
503
+ if child.tag == "interface":
504
+ node.interfaces.append(
505
+ Interface.from_xml(
506
+ child, validate_property_names=validate_property_names
507
+ )
508
+ )
509
+ elif child.tag == "node":
510
+ node.nodes.append(
511
+ Node.from_xml(
512
+ child, validate_property_names=validate_property_names
513
+ )
514
+ )
515
+
516
+ return node
517
+
518
+ @staticmethod
519
+ def parse(data: str, validate_property_names: bool = True) -> "Node":
520
+ """Parse XML data as a string into a :class:`Node`.
521
+
522
+ The string must be valid DBus introspection XML.
523
+
524
+ :param data: The XMl string.
525
+ :type data: str
526
+ :param validate_property_names: Whether to validate property names or not
527
+ :type validate_property_names: bool
528
+
529
+ :raises:
530
+ - :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the string is not valid introspection data.
531
+ """
532
+ element = ET.fromstring(data)
533
+ if element.tag != "node":
534
+ raise InvalidIntrospectionError(
535
+ 'introspection data must have a "node" for the root element'
536
+ )
537
+
538
+ return Node.from_xml(
539
+ element, is_root=True, validate_property_names=validate_property_names
540
+ )
541
+
542
+ def to_xml(self) -> ET.Element:
543
+ """Convert this :class:`Node` into an :class:`xml.etree.ElementTree.Element`."""
544
+ element = ET.Element("node")
545
+
546
+ if self.name:
547
+ element.set("name", self.name)
548
+
549
+ for interface in self.interfaces:
550
+ element.append(interface.to_xml())
551
+ for node in self.nodes:
552
+ element.append(node.to_xml())
553
+
554
+ return element
555
+
556
+ def tostring(self) -> str:
557
+ """Convert this :class:`Node` into a DBus introspection XML string."""
558
+ header = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"\n"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">\n'
559
+
560
+ def indent(elem, level=0):
561
+ i = "\n" + level * " "
562
+ if len(elem):
563
+ if not elem.text or not elem.text.strip():
564
+ elem.text = i + " "
565
+ if not elem.tail or not elem.tail.strip():
566
+ elem.tail = i
567
+ for elem_ in elem:
568
+ indent(elem_, level + 1)
569
+ if not elem.tail or not elem.tail.strip():
570
+ elem.tail = i
571
+ elif level and (not elem.tail or not elem.tail.strip()):
572
+ elem.tail = i
573
+
574
+ xml = self.to_xml()
575
+ indent(xml)
576
+ return header + ET.tostring(xml, encoding="unicode").rstrip()
577
+
578
+ @staticmethod
579
+ def default(name: Optional[str] = None) -> "Node":
580
+ """Create a :class:`Node` with the default interfaces supported by this library.
581
+
582
+ The default interfaces include:
583
+
584
+ * ``org.freedesktop.DBus.Introspectable``
585
+ * ``org.freedesktop.DBus.Peer``
586
+ * ``org.freedesktop.DBus.Properties``
587
+ * ``org.freedesktop.DBus.ObjectManager``
588
+ """
589
+ return Node(
590
+ name,
591
+ is_root=True,
592
+ interfaces=[
593
+ Interface(
594
+ "org.freedesktop.DBus.Introspectable",
595
+ methods=[
596
+ Method(
597
+ "Introspect", out_args=[Arg("s", ArgDirection.OUT, "data")]
598
+ )
599
+ ],
600
+ ),
601
+ Interface(
602
+ "org.freedesktop.DBus.Peer",
603
+ methods=[
604
+ Method(
605
+ "GetMachineId",
606
+ out_args=[Arg("s", ArgDirection.OUT, "machine_uuid")],
607
+ ),
608
+ Method("Ping"),
609
+ ],
610
+ ),
611
+ Interface(
612
+ "org.freedesktop.DBus.Properties",
613
+ methods=[
614
+ Method(
615
+ "Get",
616
+ in_args=[
617
+ Arg("s", ArgDirection.IN, "interface_name"),
618
+ Arg("s", ArgDirection.IN, "property_name"),
619
+ ],
620
+ out_args=[Arg("v", ArgDirection.OUT, "value")],
621
+ ),
622
+ Method(
623
+ "Set",
624
+ in_args=[
625
+ Arg("s", ArgDirection.IN, "interface_name"),
626
+ Arg("s", ArgDirection.IN, "property_name"),
627
+ Arg("v", ArgDirection.IN, "value"),
628
+ ],
629
+ ),
630
+ Method(
631
+ "GetAll",
632
+ in_args=[Arg("s", ArgDirection.IN, "interface_name")],
633
+ out_args=[Arg("a{sv}", ArgDirection.OUT, "props")],
634
+ ),
635
+ ],
636
+ signals=[
637
+ Signal(
638
+ "PropertiesChanged",
639
+ args=[
640
+ Arg("s", ArgDirection.OUT, "interface_name"),
641
+ Arg("a{sv}", ArgDirection.OUT, "changed_properties"),
642
+ Arg("as", ArgDirection.OUT, "invalidated_properties"),
643
+ ],
644
+ )
645
+ ],
646
+ ),
647
+ Interface(
648
+ "org.freedesktop.DBus.ObjectManager",
649
+ methods=[
650
+ Method(
651
+ "GetManagedObjects",
652
+ out_args=[
653
+ Arg(
654
+ "a{oa{sa{sv}}}",
655
+ ArgDirection.OUT,
656
+ "objpath_interfaces_and_properties",
657
+ )
658
+ ],
659
+ ),
660
+ ],
661
+ signals=[
662
+ Signal(
663
+ "InterfacesAdded",
664
+ args=[
665
+ Arg("o", ArgDirection.OUT, "object_path"),
666
+ Arg(
667
+ "a{sa{sv}}",
668
+ ArgDirection.OUT,
669
+ "interfaces_and_properties",
670
+ ),
671
+ ],
672
+ ),
673
+ Signal(
674
+ "InterfacesRemoved",
675
+ args=[
676
+ Arg("o", ArgDirection.OUT, "object_path"),
677
+ Arg("as", ArgDirection.OUT, "interfaces"),
678
+ ],
679
+ ),
680
+ ],
681
+ ),
682
+ ],
683
+ )
Binary file