Skip to content

Commit

Permalink
Add @setter_private support for property overrides
Browse files Browse the repository at this point in the history
This lets you define a private setter that can only be called from
local object to the existing read only property.
  • Loading branch information
igo95862 committed Dec 16, 2023
1 parent e6c89c8 commit 513fd92
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/sdbus/dbus_common_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,18 @@ class DbusOverload:
def __init__(self, original: T):
self.original = original
self.setter_overload: Optional[Callable[[Any, T], None]] = None
self.is_setter_public = True

def setter(self, new_setter: Optional[Callable[[Any, T], None]]) -> None:
self.setter_overload = new_setter

def setter_private(
self,
new_setter: Optional[Callable[[Any, T], None]],
) -> None:
self.setter_overload = new_setter
self.is_setter_public = False


class DbusRemoteObjectMeta:
def __init__(
Expand Down
3 changes: 3 additions & 0 deletions src/sdbus/dbus_proxy_async_interface_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ def __new__(cls, name: str,
dbus_element_override.property_setter = (
override.setter_overload
)
dbus_element_override.property_setter_is_public = (
override.is_setter_public
)
else:
raise TypeError(
f"Unknown override {collision_name!r} "
Expand Down
59 changes: 59 additions & 0 deletions test/test_sdbus_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,3 +820,62 @@ async def set_property() -> None:
)

self.assertIn('TestPropertyPrivate', changed_properties[1])

async def test_property_override_setter_private(self) -> None:

test_int = 1

class TestInterfacePrivateSetter(TestInterface):
@dbus_property_async_override()
def test_property_private(self) -> int:
return test_int

@test_property_private.setter_private
def _private_setter(self, new_value: int) -> None:
nonlocal test_int
test_int = new_value

test_object = TestInterfacePrivateSetter()
test_object.export_to_dbus('/')
test_object_connection = TestInterface.new_proxy(
TEST_SERVICE_NAME, '/')

self.assertEqual(
await test_object_connection.test_property_private,
test_int,
)

async def catch_properties_changed() -> int:
async for x in test_object_connection.properties_changed:
changed_attr = parse_properties_changed(
TestInterface, x)["test_property_private"]

if not isinstance(changed_attr, int):
raise TypeError

return changed_attr

raise RuntimeError

catch_changed_task = get_running_loop(
).create_task(catch_properties_changed())

with self.assertRaises(DbusPropertyReadOnlyError):
await test_object_connection.test_property_private.set_async(10)

await test_object.test_property_private.set_async(10)

self.assertEqual(
await test_object_connection.test_property_private,
10,
)

self.assertEqual(
await test_object.test_property_private,
test_int,
)

self.assertEqual(
await wait_for(catch_changed_task, timeout=1),
10,
)

0 comments on commit 513fd92

Please sign in to comment.