Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion dbus_next/aio/message_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class MessageBus(BaseMessageBus):
be :class:`None` until the message bus connects.
:vartype unique_name: str
"""

def __init__(self, bus_address: str = None, bus_type: BusType = BusType.SESSION):
super().__init__(bus_address, bus_type, ProxyObject)
self._loop = asyncio.get_event_loop()
Expand Down
2 changes: 0 additions & 2 deletions dbus_next/aio/proxy_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class ProxyInterface(BaseProxyInterface):
If the service returns an error for a DBus call, a :class:`DBusError
<dbus_next.DBusError>` will be raised with information about the error.
"""

def _add_method(self, intr_method):
async def method_fn(*args):
msg = await self.bus.call(
Expand Down Expand Up @@ -128,7 +127,6 @@ class ProxyObject(BaseProxyObject):

For more information, see the :class:`BaseProxyObject <dbus_next.proxy_object.BaseProxyObject>`.
"""

def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element],
bus: BaseMessageBus):
super().__init__(bus_name, path, introspection, bus, ProxyInterface)
Expand Down
1 change: 0 additions & 1 deletion dbus_next/glib/message_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ class MessageBus(BaseMessageBus):
be :class:`None` until the message bus connects.
:vartype unique_name: str
"""

def __init__(self, bus_address: str = None, bus_type: BusType = BusType.SESSION):
if _import_error:
raise _import_error
Expand Down
2 changes: 0 additions & 2 deletions dbus_next/glib/proxy_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ def set_callback(error: Exception)
:class:`DBusError <dbus_next.DBusError>` will be raised with information
about the error.
"""

def _add_method(self, intr_method):
in_len = len(intr_method.in_args)
out_len = len(intr_method.out_args)
Expand Down Expand Up @@ -270,7 +269,6 @@ class ProxyObject(BaseProxyObject):

For more information, see the :class:`BaseProxyObject <dbus_next.proxy_object.BaseProxyObject>`.
"""

def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element],
bus: BaseMessageBus):
super().__init__(bus_name, path, introspection, bus, ProxyInterface)
Expand Down
30 changes: 23 additions & 7 deletions dbus_next/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class Arg:
- :class:`InvalidSignatureError <dbus_next.InvalidSignatureError>` - If the signature is not valid.
- :class:`InvalidIntrospectionError <dbus_next.InvalidIntrospectionError>` - If the signature is not a single complete type.
"""

def __init__(self,
signature: Union[SignatureType, str],
direction: List[ArgDirection] = None,
Expand Down Expand Up @@ -101,7 +100,6 @@ class Signal:
:raises:
- :class:`InvalidMemberNameError <dbus_next.InvalidMemberNameError>` - If the name of the signal is not a valid member name.
"""

def __init__(self, name: str, args: List[Arg] = None):
if name is not None:
assert_member_name_valid(name)
Expand Down Expand Up @@ -165,7 +163,6 @@ class Method:
:raises:
- :class:`InvalidMemberNameError <dbus_next.InvalidMemberNameError>` - If the name of this method is not valid.
"""

def __init__(self, name: str, in_args: List[Arg] = [], out_args: List[Arg] = []):
assert_member_name_valid(name)

Expand Down Expand Up @@ -238,7 +235,6 @@ class Property:
- :class `InvalidSignatureError <dbus_next.InvalidSignatureError>` - If the given signature is not valid.
- :class: `InvalidMemberNameError <dbus_next.InvalidMemberNameError>` - If the member name is not valid.
"""

def __init__(self, name: str, signature: str,
access: PropertyAccess = PropertyAccess.READWRITE):
assert_member_name_valid(name)
Expand Down Expand Up @@ -303,7 +299,6 @@ class Interface:
:raises:
- :class:`InvalidInterfaceNameError <dbus_next.InvalidInterfaceNameError>` - If the name is not a valid interface name.
"""

def __init__(self,
name: str,
methods: List[Method] = None,
Expand Down Expand Up @@ -387,7 +382,6 @@ class Node:
:raises:
- :class:`InvalidIntrospectionError <dbus_next.InvalidIntrospectionError>` - If the name is not a valid node name.
"""

def __init__(self, name: str = None, interfaces: List[Interface] = None, is_root: bool = True):
if not is_root and not name:
raise InvalidIntrospectionError('child nodes must have a "name" attribute')
Expand Down Expand Up @@ -488,6 +482,7 @@ def default(name: str = None) -> 'Node':
* ``org.freedesktop.DBus.Introspectable``
* ``org.freedesktop.DBus.Peer``
* ``org.freedesktop.DBus.Properties``
* ``org.freedesktop.DBus.ObjectManager``
"""
return Node(name,
is_root=True,
Expand Down Expand Up @@ -530,5 +525,26 @@ def default(name: str = None) -> 'Node':
Arg('as', ArgDirection.OUT,
'invalidated_properties')
])
])
]),
Interface('org.freedesktop.DBus.ObjectManager',
methods=[
Method('GetManagedObjects',
out_args=[
Arg('a{oa{sa{sv}}}', ArgDirection.OUT,
'objpath_interfaces_and_properties')
]),
],
signals=[
Signal('InterfacesAdded',
args=[
Arg('o', ArgDirection.OUT, 'object_path'),
Arg('a{sa{sv}}', ArgDirection.OUT,
'interfaces_and_properties'),
]),
Signal('InterfacesRemoved',
args=[
Arg('o', ArgDirection.OUT, 'object_path'),
Arg('as', ArgDirection.OUT, 'interfaces'),
])
]),
])
1 change: 0 additions & 1 deletion dbus_next/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ class Message:
- :class:`InvalidMemberNameError` - If ``member`` is not a valid member name.
- :class:`InvalidInterfaceNameError` - If ``error_name`` or ``interface`` is not a valid interface name.
"""

def __init__(self,
destination: str = None,
path: str = None,
Expand Down
36 changes: 28 additions & 8 deletions dbus_next/message_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ class BaseMessageBus:
be :class:`None` until the message bus connects.
:vartype unique_name: str
"""

def __init__(self,
bus_address: Optional[str] = None,
bus_type: BusType = BusType.SESSION,
Expand Down Expand Up @@ -586,6 +585,9 @@ def _find_message_handler(self, msg):
handler = self._default_ping_handler
elif msg._matches(member='GetMachineId', signature=''):
handler = self._default_get_machine_id_handler
elif msg._matches(interface='org.freedesktop.DBus.ObjectManager',
member='GetManagedObjects'):
handler = self._default_object_manager

else:
for interface in self._path_exports.get(msg.path, []):
Expand Down Expand Up @@ -633,6 +635,19 @@ def reply_handler(reply, err):
interface='org.freedesktop.DBus.Peer',
member='GetMachineId'), reply_handler)

def _default_object_manager(self, msg):
result = {}

for node in self._path_exports:
if not node.startswith(msg.path + '/') and msg.path != '/':
continue

result[node] = {}
for interface in self._path_exports[node]:
result[node][interface.name] = self._get_all_properties(interface)

return Message.new_method_return(msg, 'a{oa{sa{sv}}}', [result])

def _default_properties_handler(self, msg):
methods = {'Get': 'ss', 'Set': 'ssv', 'GetAll': 's'}
if msg.member not in methods or methods[msg.member] != msg.signature:
Expand Down Expand Up @@ -686,13 +701,18 @@ def _default_properties_handler(self, msg):
return Message.new_method_return(msg)

elif msg.member == 'GetAll':
result = {}
for prop in ServiceInterface._get_properties(interface):
if prop.disabled or not prop.access.readable():
continue
result[prop.name] = Variant(prop.signature,
getattr(interface, prop.prop_getter.__name__))

result = self._get_all_properties(interface)
return Message.new_method_return(msg, 'a{sv}', [result])
else:
assert False

def _get_all_properties(self, interface):
result = {}

for prop in ServiceInterface._get_properties(interface):
if prop.disabled or not prop.access.readable():
continue
result[prop.name] = Variant(prop.signature, getattr(interface,
prop.prop_getter.__name__))

return result
2 changes: 0 additions & 2 deletions dbus_next/proxy_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class BaseProxyInterface:
:ivar bus: The message bus this proxy interface is connected to.
:vartype bus: :class:`BaseMessageBus <dbus_next.message_bus.BaseMessageBus>`
"""

def __init__(self, bus_name, path, introspection, bus):

self.bus_name = bus_name
Expand Down Expand Up @@ -104,7 +103,6 @@ class BaseProxyObject:
- :class:`InvalidObjectPathError <dbus_next.InvalidObjectPathError>` - If the given object path is not valid.
- :class:`InvalidIntrospectionError <dbus_next.InvalidIntrospectionError>` - If the introspection data for the node is not valid.
"""

def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element],
bus: 'message_bus.BaseMessageBus', ProxyInterface: Type[BaseProxyInterface]):
assert_object_path_valid(path)
Expand Down
1 change: 0 additions & 1 deletion dbus_next/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ class ServiceInterface:
valid interface name.
:vartype name: str
"""

def __init__(self, name: str):
# TODO cannot be overridden by a dbus member
self.name = name
Expand Down
2 changes: 0 additions & 2 deletions dbus_next/signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,6 @@ class SignatureTree:
:raises:
:class:`InvalidSignatureError` if the given signature is not valid.
"""

def __init__(self, signature: str = ''):
self.signature = signature

Expand Down Expand Up @@ -353,7 +352,6 @@ class Variant:
:class:`InvalidSignatureError` if the signature is not valid.
:class:`SignatureBodyMismatchError` if the signature does not match the body.
"""

def __init__(self, signature: Union[str, SignatureTree, SignatureType], value: Any):
signature_str = ''
signature_tree = None
Expand Down
1 change: 0 additions & 1 deletion test/service/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,3 @@ async def test_export_introspection():

root = bus._introspect_export_path('/')
assert len(root.nodes) == 1

77 changes: 76 additions & 1 deletion test/service/test_standard_interfaces.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dbus_next.service import ServiceInterface
from dbus_next.service import ServiceInterface, dbus_property, PropertyAccess
from dbus_next.signature import Variant
from dbus_next.aio import MessageBus
from dbus_next import Message, MessageType, introspection as intr

Expand All @@ -12,6 +13,21 @@ def __init__(self, name):
super().__init__(name)


class ExampleComplexInterface(ServiceInterface):
def __init__(self, name):
self._foo = 42
self._bar = 'str'
super().__init__(name)

@dbus_property(access=PropertyAccess.READ)
def Foo(self) -> 'y':
return self._foo

@dbus_property(access=PropertyAccess.READ)
def Bar(self) -> 's':
return self._bar


@pytest.mark.asyncio
async def test_introspectable_interface():
bus1 = await MessageBus().connect()
Expand Down Expand Up @@ -74,3 +90,62 @@ async def test_peer_interface():

assert reply.message_type == MessageType.METHOD_RETURN, reply.body[0]
assert reply.signature == 's'


@pytest.mark.asyncio
async def test_object_manager():
expected_reply = {
'/test/path/deeper': {
'test.interface2': {
'Bar': Variant('s', 'str'),
'Foo': Variant('y', 42)
}
}
}
reply_ext = {
'/test/path': {
'test.interface1': {},
'test.interface2': {
'Bar': Variant('s', 'str'),
'Foo': Variant('y', 42)
}
}
}

bus1 = await MessageBus().connect()
bus2 = await MessageBus().connect()

interface = ExampleInterface('test.interface1')
interface2 = ExampleComplexInterface('test.interface2')

export_path = '/test/path'
bus1.export(export_path, interface)
bus1.export(export_path, interface2)
bus1.export(export_path + '/deeper', interface2)

reply_root = await bus2.call(
Message(destination=bus1.unique_name,
path='/',
interface='org.freedesktop.DBus.ObjectManager',
member='GetManagedObjects'))

reply_level1 = await bus2.call(
Message(destination=bus1.unique_name,
path=export_path,
interface='org.freedesktop.DBus.ObjectManager',
member='GetManagedObjects'))

reply_level2 = await bus2.call(
Message(destination=bus1.unique_name,
path=export_path + '/deeper',
interface='org.freedesktop.DBus.ObjectManager',
member='GetManagedObjects'))

assert reply_root.signature == 'a{oa{sa{sv}}}'
assert reply_level1.signature == 'a{oa{sa{sv}}}'
assert reply_level2.signature == 'a{oa{sa{sv}}}'

assert reply_level2.body == [{}]
assert reply_level1.body == [expected_reply]
expected_reply.update(reply_ext)
assert reply_root.body == [expected_reply]