Skip to content

Commit 3f70eaf

Browse files
committed
Make EmitsChangedSignal introspection more accurate
Now has 5 values: None, True, False, 'const', 'invalidates'
1 parent 4e69458 commit 3f70eaf

2 files changed

Lines changed: 72 additions & 14 deletions

File tree

src/sdbus/interface_generator.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,16 @@
2020
from __future__ import annotations
2121

2222
from pathlib import Path
23-
from typing import Dict, Iterable, Iterator, List, Optional, Tuple, Union
23+
from typing import (
24+
Dict,
25+
Iterable,
26+
Iterator,
27+
List,
28+
Literal,
29+
Optional,
30+
Tuple,
31+
Union,
32+
)
2433
from xml.etree.ElementTree import Element
2534
from xml.etree.ElementTree import fromstring as etree_from_str
2635
from xml.etree.ElementTree import parse as etree_from_file
@@ -402,20 +411,21 @@ def __repr__(self) -> str:
402411

403412

404413
class DbusPropertyIntrospection(DbusMemberAbstract):
405-
_EMITS_CHANGED_MAP: Dict[str, Optional[str]] = {
406-
'true': 'DbusPropertyEmitsChangeFlag',
407-
'false': None,
408-
'invalidates': 'DbusPropertyEmitsInvalidationFlag',
409-
'const': 'DbusPropertyConstFlag',
410-
}
414+
_EMITS_CHANGED_MAP: \
415+
Dict[Union[bool, None, Literal['const', 'invalidates']], str] = {
416+
True: 'DbusPropertyEmitsChangeFlag',
417+
'invalidates': 'DbusPropertyEmitsInvalidationFlag',
418+
'const': 'DbusPropertyConstFlag',
419+
}
411420

412421
def __init__(self, element: Element):
413422
if element.tag != 'property':
414423
raise ValueError(f"Expected property tag, got {element.tag}")
415424

416425
self.dbus_signature = element.attrib['type']
417426

418-
self.emits_changed: Optional[str] = None
427+
self.emits_changed: \
428+
Union[bool, Literal['const', 'invalidates'], None] = None
419429
self.is_explicit = False
420430

421431
access_type = element.attrib['access']
@@ -429,8 +439,9 @@ def __init__(self, element: Element):
429439
super().__init__(element)
430440

431441
def _flags_iter(self) -> Iterator[str]:
432-
if self.emits_changed is not None:
433-
yield self.emits_changed
442+
emits_changed_str = self._EMITS_CHANGED_MAP.get(self.emits_changed)
443+
if emits_changed_str is not None:
444+
yield emits_changed_str
434445

435446
yield from super()._flags_iter()
436447

@@ -440,11 +451,17 @@ def _parse_annotation_data(self,
440451

441452
if annotation_name == ('org.freedesktop.DBus.Property'
442453
'.EmitsChangedSignal'):
443-
if annotation_value not in self._EMITS_CHANGED_MAP:
454+
if annotation_value == 'true':
455+
self.emits_changed = True
456+
elif annotation_value == 'false':
457+
self.emits_changed = False
458+
elif annotation_value == 'const':
459+
self.emits_changed = 'const'
460+
elif annotation_value == 'invalidates':
461+
self.emits_changed = 'invalidates'
462+
else:
444463
raise ValueError('Unknown EmitsChanged value',
445464
annotation_value)
446-
447-
self.emits_changed = self._EMITS_CHANGED_MAP[annotation_value]
448465
elif annotation_name == 'org.freedesktop.systemd1.Explicit':
449466
self.is_explicit = parse_str_bool(annotation_value)
450467

test/test_interface_generator.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@
5353
<arg name="new_value" type="b"/>
5454
</signal>
5555
<property name="Bar" type="y" access="readwrite"/>
56+
<property name="FooFoo" type="as" access="read">
57+
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal"
58+
value="false"/>
59+
</property>
60+
<property name="BoundBy" type="as" access="read">
61+
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal"
62+
value="const"/>
63+
</property>
64+
<property name="FooInvalidates" type="s" access="read">
65+
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal"
66+
value="invalidates"/>
67+
</property>
5668
</interface>
5769
<node name="child_of_sample_object"/>
5870
<node name="another_child_of_sample_object"/>
@@ -141,7 +153,36 @@ def test_parsing(self) -> None:
141153
if find_spec('jinja2') is None:
142154
raise SkipTest('Jinja2 not installed')
143155

144-
generate_async_py_file(interfaces_from_str(test_xml))
156+
interfaces_intro = interfaces_from_str(test_xml)
157+
158+
with self.subTest('Test introspection details'):
159+
test_interface = interfaces_intro[0]
160+
161+
for test_property in test_interface.properties:
162+
if test_property.method_name == 'BoundBy':
163+
self.assertEqual(
164+
test_property.emits_changed,
165+
'const',
166+
)
167+
elif test_property.method_name == 'Bar':
168+
self.assertEqual(
169+
test_property.emits_changed,
170+
None,
171+
)
172+
elif test_property.method_name == 'FooInvalidates':
173+
self.assertEqual(
174+
test_property.emits_changed,
175+
'invalidates',
176+
)
177+
elif test_property.method_name == 'FooFoo':
178+
self.assertEqual(
179+
test_property.emits_changed,
180+
False,
181+
)
182+
183+
generated = generate_async_py_file(interfaces_intro)
184+
self.assertIn('flags=DbusPropertyEmitsInvalidationFlag', generated)
185+
self.assertIn('flags=DbusPropertyConstFlag', generated)
145186

146187

147188
if __name__ == "__main__":

0 commit comments

Comments
 (0)