Skip to content

Commit 773e34a

Browse files
committed
Move code exporting attributes to the attribute's classes
1 parent 11b7856 commit 773e34a

7 files changed

+163
-128
lines changed

src/sdbus/dbus_common_elements.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
SelfMeta = TypeVar('SelfMeta', bound="DbusInterfaceMetaCommon")
4747

48+
from .dbus_proxy_async_interface_base import DbusExportHandle
4849
from .sd_bus_internals import SdBus, SdBusInterface
4950

5051
T = TypeVar('T')
@@ -310,11 +311,20 @@ def attribute_name(self) -> str:
310311
return self.signal_name
311312

312313

313-
class DbusBoundAsync:
314-
...
314+
class DbusBoundAttribute(ABC):
315+
@property
316+
@abstractmethod
317+
def attribute(self) -> DbusAttributeCommon:
318+
...
319+
320+
321+
class DbusLocalAttributeAsync(DbusBoundAttribute):
322+
@abstractmethod
323+
def append_to_interface(self, interface: SdBusInterface, handle: DbusExportHandle) -> None:
324+
...
315325

316326

317-
class DbusBoundSync:
327+
class DbusProxyAttributeAsync(DbusBoundAttribute):
318328
...
319329

320330

src/sdbus/dbus_proxy_async_interface_base.py

Lines changed: 34 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from inspect import getmembers
2424
from itertools import chain
2525
from types import MethodType
26-
from typing import TYPE_CHECKING, Any, Callable, cast
26+
from typing import TYPE_CHECKING, Any, Callable, cast, Protocol
2727
from warnings import warn
2828
from weakref import WeakKeyDictionary, WeakValueDictionary
2929

@@ -37,14 +37,11 @@
3737
DbusAttributeAsync,
3838
DbusAttributeCommon,
3939
DbusAttributeSync,
40+
DbusLocalAttributeAsync,
4041
)
4142
from .dbus_common_funcs import get_default_bus
42-
from .dbus_proxy_async_method import DbusMethodAsync, DbusLocalMethodAsync
43-
from .dbus_proxy_async_property import (
44-
DbusPropertyAsync,
45-
DbusLocalPropertyAsync,
46-
)
47-
from .dbus_proxy_async_signal import DbusSignalAsync, DbusLocalSignalAsync
43+
from .dbus_proxy_async_method import DbusMethodAsync
44+
from .dbus_proxy_async_property import DbusPropertyAsync
4845
from .sd_bus_internals import SdBusInterface
4946

5047
if TYPE_CHECKING:
@@ -61,8 +58,7 @@
6158
Union,
6259
)
6360

64-
from .dbus_common_elements import DbusBoundAsync
65-
from .sd_bus_internals import SdBus, SdBusSlot
61+
from .sd_bus_internals import SdBus
6662

6763
T = TypeVar('T')
6864
Self = TypeVar('Self', bound="DbusInterfaceBaseAsync")
@@ -335,26 +331,17 @@ def export_to_dbus(
335331
if bus is None:
336332
bus = get_default_bus()
337333

334+
338335
local_object_meta.attached_bus = bus
339336
local_object_meta.serving_object_path = object_path
340337
# TODO: can be optimized with a single loop
341-
interface_map: Dict[str, List[DbusBoundAsync]] = {}
338+
interface_map: Dict[str, List[DbusLocalAttributeAsync]] = {}
342339

343340
for key, value in getmembers(self):
344341
assert not isinstance(value, DbusAttributeAsync)
345342

346-
if isinstance(value, DbusLocalMethodAsync):
347-
interface_name = value.dbus_method.interface_name
348-
if not value.dbus_method.serving_enabled:
349-
continue
350-
elif isinstance(value, DbusLocalPropertyAsync):
351-
interface_name = value.dbus_property.interface_name
352-
if not value.dbus_property.serving_enabled:
353-
continue
354-
elif isinstance(value, DbusLocalSignalAsync):
355-
interface_name = value.dbus_signal.interface_name
356-
if not value.dbus_signal.serving_enabled:
357-
continue
343+
if isinstance(value, DbusLocalAttributeAsync) and value.attribute.serving_enabled:
344+
interface_name = value.attribute.interface_name
358345
else:
359346
continue
360347

@@ -366,54 +353,20 @@ def export_to_dbus(
366353

367354
interface_member_list.append(value)
368355

356+
export_handle = DbusExportHandle()
357+
369358
for interface_name, member_list in interface_map.items():
370359
new_interface = SdBusInterface()
371360
for dbus_something in member_list:
372-
if isinstance(dbus_something, DbusLocalMethodAsync):
373-
new_interface.add_method(
374-
dbus_something.dbus_method.method_name,
375-
dbus_something.dbus_method.input_signature,
376-
dbus_something.dbus_method.input_args_names,
377-
dbus_something.dbus_method.result_signature,
378-
dbus_something.dbus_method.result_args_names,
379-
dbus_something.dbus_method.flags,
380-
dbus_something._dbus_reply_call,
381-
)
382-
elif isinstance(dbus_something, DbusLocalPropertyAsync):
383-
getter = dbus_something._dbus_reply_get
384-
dbus_property = dbus_something.dbus_property
385-
386-
if (
387-
dbus_property.property_setter is not None
388-
and
389-
dbus_property.property_setter_is_public
390-
):
391-
setter = dbus_something._dbus_reply_set
392-
else:
393-
setter = None
394-
395-
new_interface.add_property(
396-
dbus_property.property_name,
397-
dbus_property.property_signature,
398-
getter,
399-
setter,
400-
dbus_property.flags,
401-
)
402-
elif isinstance(dbus_something, DbusLocalSignalAsync):
403-
new_interface.add_signal(
404-
dbus_something.dbus_signal.signal_name,
405-
dbus_something.dbus_signal.signal_signature,
406-
dbus_something.dbus_signal.args_names,
407-
dbus_something.dbus_signal.flags,
408-
)
409-
else:
410-
raise TypeError
411-
361+
dbus_something.append_to_interface(new_interface, export_handle)
412362
bus.add_interface(new_interface, object_path,
413363
interface_name)
414364
local_object_meta.activated_interfaces.append(new_interface)
415365

416-
return DbusExportHandle(local_object_meta)
366+
assert new_interface.slot is not None
367+
export_handle.append(new_interface.slot)
368+
369+
return export_handle
417370

418371
def _connect(
419372
self,
@@ -469,13 +422,23 @@ def new_proxy(
469422
return new_object
470423

471424

425+
class Closeable(Protocol):
426+
def close(self) -> None:
427+
...
428+
429+
472430
class DbusExportHandle:
473-
def __init__(self, local_meta: DbusLocalObjectMeta):
474-
self._dbus_slots: List[SdBusSlot] = [
475-
i.slot
476-
for i in local_meta.activated_interfaces
477-
if i.slot is not None
478-
]
431+
def __init__(self, *items: Closeable) -> None:
432+
self._items = list(items)
433+
434+
def append(self, item: Closeable) -> None:
435+
self._items.append(item)
436+
437+
def close(self) -> None:
438+
while self._items:
439+
self._items.pop().close()
440+
441+
stop = close # for backwards compatibility
479442

480443
async def __aenter__(self) -> DbusExportHandle:
481444
return self
@@ -489,16 +452,12 @@ def __exit__(
489452
exc_value: Any,
490453
traceback: Any,
491454
) -> None:
492-
self.stop()
455+
self.close()
493456

494457
async def __aexit__(
495458
self,
496459
exc_type: Any,
497460
exc_value: Any,
498461
traceback: Any,
499462
) -> None:
500-
self.stop()
501-
502-
def stop(self) -> None:
503-
for slot in self._dbus_slots:
504-
slot.close()
463+
self.close()

src/sdbus/dbus_proxy_async_method.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,21 @@
2626
from weakref import ref as weak_ref
2727

2828
from .dbus_common_elements import (
29-
DbusBoundAsync,
29+
DbusBoundAttribute,
3030
DbusMethodCommon,
3131
DbusMethodOverride,
32+
DbusProxyAttributeAsync,
3233
DbusRemoteObjectMeta,
3334
DbusAttributeAsync,
35+
DbusLocalAttributeAsync,
3436
)
3537
from .dbus_exceptions import DbusFailedError
36-
from .sd_bus_internals import DbusNoReplyFlag
38+
from .sd_bus_internals import DbusNoReplyFlag, SdBusInterface
3739

3840
if TYPE_CHECKING:
3941
from typing import Any, Callable, Optional, Sequence, Type, TypeVar, Union
4042

41-
from .dbus_proxy_async_interface_base import DbusInterfaceBaseAsync
43+
from .dbus_proxy_async_interface_base import DbusInterfaceBaseAsync, DbusExportHandle
4244
from .sd_bus_internals import SdBusMessage
4345

4446
T = TypeVar('T')
@@ -85,19 +87,25 @@ def __get__(
8587
return self
8688

8789

88-
class DbusBoundMethodAsyncBase(DbusBoundAsync):
90+
class DbusBoundMethodAsyncBase(DbusBoundAttribute):
91+
def __init__(self, dbus_method: DbusMethodAsync) -> None:
92+
self.dbus_method = dbus_method
93+
94+
@property
95+
def attribute(self):
96+
return self.dbus_method
8997

9098
def __call__(self, *args: Any, **kwargs: Any) -> Any:
9199
raise NotImplementedError
92100

93101

94-
class DbusProxyMethodAsync(DbusBoundMethodAsyncBase):
102+
class DbusProxyMethodAsync(DbusBoundMethodAsyncBase, DbusProxyAttributeAsync):
95103
def __init__(
96104
self,
97105
dbus_method: DbusMethodAsync,
98106
proxy_meta: DbusRemoteObjectMeta,
99107
):
100-
self.dbus_method = dbus_method
108+
super().__init__(dbus_method)
101109
self.proxy_meta = proxy_meta
102110

103111
self.__doc__ = dbus_method.__doc__
@@ -145,17 +153,28 @@ def __call__(self, *args: Any, **kwargs: Any) -> Any:
145153
return self._dbus_async_call(new_call_message)
146154

147155

148-
class DbusLocalMethodAsync(DbusBoundMethodAsyncBase):
156+
class DbusLocalMethodAsync(DbusBoundMethodAsyncBase, DbusLocalAttributeAsync):
149157
def __init__(
150158
self,
151159
dbus_method: DbusMethodAsync,
152160
local_object: DbusInterfaceBaseAsync,
153161
):
154-
self.dbus_method = dbus_method
162+
super().__init__(dbus_method)
155163
self.local_object_ref = weak_ref(local_object)
156164

157165
self.__doc__ = dbus_method.__doc__
158166

167+
def append_to_interface(self, interface: SdBusInterface, handle: DbusExportHandle):
168+
interface.add_method(
169+
self.dbus_method.method_name,
170+
self.dbus_method.input_signature,
171+
self.dbus_method.input_args_names,
172+
self.dbus_method.result_signature,
173+
self.dbus_method.result_args_names,
174+
self.dbus_method.flags,
175+
self._dbus_reply_call,
176+
)
177+
159178
def __call__(self, *args: Any, **kwargs: Any) -> Any:
160179
local_object = self.local_object_ref()
161180
if local_object is None:
@@ -231,6 +250,10 @@ async def _dbus_reply_call(
231250

232251
reply_message.send()
233252

253+
# aliases for backwards compatibility
254+
DbusMethodAsyncBaseBind = DbusBoundMethodAsyncBase
255+
DbusMethodAsyncLocalBind = DbusLocalMethodAsync
256+
DbusMethodAsyncProxyBind = DbusProxyMethodAsync
234257

235258
def dbus_method_async(
236259
input_signature: str = "",

src/sdbus/dbus_proxy_async_object_manager.py

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from functools import partial
2323
from typing import TYPE_CHECKING
2424

25-
from .dbus_common_elements import DbusLocalObjectMeta
2625
from .dbus_common_funcs import get_default_bus
2726
from .dbus_proxy_async_interface_base import (
2827
DbusExportHandle,
@@ -38,18 +37,9 @@
3837
from .sd_bus_internals import SdBus, SdBusSlot
3938

4039

41-
class DbusObjectManagerExportHandle(DbusExportHandle):
42-
def __init__(
43-
self,
44-
local_meta: DbusLocalObjectMeta,
45-
remove_object_call: Callable[[], None],
46-
):
47-
super().__init__(local_meta)
48-
self.remove_object_call = remove_object_call
49-
50-
def stop(self) -> None:
51-
super().stop()
52-
self.remove_object_call()
40+
class CloseableFromCallback:
41+
def __init__(self, callback: Callable[[], None]) -> None:
42+
self.close = callback
5343

5444

5545
class DbusObjectManagerInterfaceAsync(
@@ -89,36 +79,33 @@ def export_to_dbus(
8979
)
9080
slot = bus.add_object_manager(object_path)
9181
self._object_manager_slot = slot
92-
export_handle._dbus_slots.append(slot)
82+
export_handle.append(slot)
9383
return export_handle
9484

9585
def export_with_manager(
9686
self,
9787
object_path: str,
9888
object_to_export: DbusInterfaceBaseAsync,
9989
bus: Optional[SdBus] = None,
100-
) -> DbusObjectManagerExportHandle:
90+
) -> DbusExportHandle:
10191
if self._object_manager_slot is None:
10292
raise RuntimeError('ObjectManager not intitialized')
10393

10494
if bus is None:
10595
bus = get_default_bus()
10696

107-
object_to_export.export_to_dbus(
97+
export_handle = object_to_export.export_to_dbus(
10898
object_path,
10999
bus,
110100
)
111-
meta = object_to_export._dbus
112-
if not isinstance(meta, DbusLocalObjectMeta):
113-
raise TypeError
114-
handle = DbusObjectManagerExportHandle(
115-
meta,
116-
partial(self.remove_managed_object, object_to_export),
101+
export_handle.append(
102+
CloseableFromCallback(
103+
partial(self.remove_managed_object, object_to_export),
104+
)
117105
)
118106
bus.emit_object_added(object_path)
119107
self._managed_object_to_path[object_to_export] = object_path
120-
121-
return handle
108+
return export_handle
122109

123110
def remove_managed_object(
124111
self,

0 commit comments

Comments
 (0)