asd
This commit is contained in:
@ -0,0 +1,116 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<!-- GDBus 2.50.3 -->
|
||||
<node>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg type="s" name="interface_name" direction="in"/>
|
||||
<arg type="s" name="property_name" direction="in"/>
|
||||
<arg type="v" name="value" direction="out"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg type="s" name="interface_name" direction="in"/>
|
||||
<arg type="a{sv}" name="properties" direction="out"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg type="s" name="interface_name" direction="in"/>
|
||||
<arg type="s" name="property_name" direction="in"/>
|
||||
<arg type="v" name="value" direction="in"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg type="s" name="interface_name"/>
|
||||
<arg type="a{sv}" name="changed_properties"/>
|
||||
<arg type="as" name="invalidated_properties"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg type="s" name="xml_data" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Peer">
|
||||
<method name="Ping"/>
|
||||
<method name="GetMachineId">
|
||||
<arg type="s" name="machine_uuid" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.Secret.Service">
|
||||
<method name="OpenSession">
|
||||
<arg type="s" name="algorithm" direction="in"/>
|
||||
<arg type="v" name="input" direction="in"/>
|
||||
<arg type="v" name="output" direction="out"/>
|
||||
<arg type="o" name="result" direction="out"/>
|
||||
</method>
|
||||
<method name="CreateCollection">
|
||||
<arg type="a{sv}" name="properties" direction="in"/>
|
||||
<arg type="s" name="alias" direction="in"/>
|
||||
<arg type="o" name="collection" direction="out"/>
|
||||
<arg type="o" name="prompt" direction="out"/>
|
||||
</method>
|
||||
<method name="SearchItems">
|
||||
<arg type="a{ss}" name="attributes" direction="in"/>
|
||||
<arg type="ao" name="unlocked" direction="out"/>
|
||||
<arg type="ao" name="locked" direction="out"/>
|
||||
</method>
|
||||
<method name="Unlock">
|
||||
<arg type="ao" name="objects" direction="in"/>
|
||||
<arg type="ao" name="unlocked" direction="out"/>
|
||||
<arg type="o" name="prompt" direction="out"/>
|
||||
</method>
|
||||
<method name="Lock">
|
||||
<arg type="ao" name="objects" direction="in"/>
|
||||
<arg type="ao" name="locked" direction="out"/>
|
||||
<arg type="o" name="Prompt" direction="out"/>
|
||||
</method>
|
||||
<method name="LockService"/>
|
||||
<method name="ChangeLock">
|
||||
<arg type="o" name="collection" direction="in"/>
|
||||
<arg type="o" name="prompt" direction="out"/>
|
||||
</method>
|
||||
<method name="GetSecrets">
|
||||
<arg type="ao" name="items" direction="in"/>
|
||||
<arg type="o" name="session" direction="in"/>
|
||||
<arg type="a{o(oayays)}" name="secrets" direction="out"/>
|
||||
</method>
|
||||
<method name="ReadAlias">
|
||||
<arg type="s" name="name" direction="in"/>
|
||||
<arg type="o" name="collection" direction="out"/>
|
||||
</method>
|
||||
<method name="SetAlias">
|
||||
<arg type="s" name="name" direction="in"/>
|
||||
<arg type="o" name="collection" direction="in"/>
|
||||
</method>
|
||||
<signal name="CollectionCreated">
|
||||
<arg type="o" name="collection"/>
|
||||
</signal>
|
||||
<signal name="CollectionDeleted">
|
||||
<arg type="o" name="collection"/>
|
||||
</signal>
|
||||
<signal name="CollectionChanged">
|
||||
<arg type="o" name="collection"/>
|
||||
</signal>
|
||||
<property type="ao" name="Collections" access="read"/>
|
||||
</interface>
|
||||
<interface name="org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface">
|
||||
<method name="ChangeWithMasterPassword">
|
||||
<arg type="o" name="collection" direction="in"/>
|
||||
<arg type="(oayays)" name="original" direction="in"/>
|
||||
<arg type="(oayays)" name="master" direction="in"/>
|
||||
</method>
|
||||
<method name="ChangeWithPrompt">
|
||||
<arg type="o" name="collection" direction="in"/>
|
||||
<arg type="o" name="prompt" direction="out"/>
|
||||
</method>
|
||||
<method name="CreateWithMasterPassword">
|
||||
<arg type="a{sv}" name="attributes" direction="in"/>
|
||||
<arg type="(oayays)" name="master" direction="in"/>
|
||||
<arg type="o" name="collection" direction="out"/>
|
||||
</method>
|
||||
<method name="UnlockWithMasterPassword">
|
||||
<arg type="o" name="collection" direction="in"/>
|
||||
<arg type="(oayays)" name="master" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
<node name="session"/>
|
||||
<node name="collection"/>
|
||||
</node>
|
24
venv/lib/python3.12/site-packages/jeepney/tests/test_auth.py
Normal file
24
venv/lib/python3.12/site-packages/jeepney/tests/test_auth.py
Normal file
@ -0,0 +1,24 @@
|
||||
import pytest
|
||||
|
||||
from jeepney import auth
|
||||
|
||||
def test_make_auth_external():
|
||||
b = auth.make_auth_external()
|
||||
assert b.startswith(b'AUTH EXTERNAL')
|
||||
|
||||
def test_make_auth_anonymous():
|
||||
b = auth.make_auth_anonymous()
|
||||
assert b.startswith(b'AUTH ANONYMOUS')
|
||||
|
||||
def test_parser():
|
||||
p = auth.SASLParser()
|
||||
p.feed(b'OK 728d62bc2eb394')
|
||||
assert not p.authenticated
|
||||
p.feed(b'1ebbb0b42958b1e0d6\r\n')
|
||||
assert p.authenticated
|
||||
|
||||
def test_parser_rejected():
|
||||
p = auth.SASLParser()
|
||||
with pytest.raises(auth.AuthenticationError):
|
||||
p.feed(b'REJECTED EXTERNAL\r\n')
|
||||
assert not p.authenticated
|
@ -0,0 +1,28 @@
|
||||
from io import StringIO
|
||||
import os.path
|
||||
|
||||
from jeepney.low_level import MessageType, HeaderFields
|
||||
from jeepney.bindgen import code_from_xml
|
||||
|
||||
sample_file = os.path.join(os.path.dirname(__file__), 'secrets_introspect.xml')
|
||||
|
||||
def test_bindgen():
|
||||
with open(sample_file) as f:
|
||||
xml = f.read()
|
||||
sio = StringIO()
|
||||
n_interfaces = code_from_xml(xml, path='/org/freedesktop/secrets',
|
||||
bus_name='org.freedesktop.secrets',
|
||||
fh=sio)
|
||||
# 5 interfaces defined, but we ignore Properties, Introspectable, Peer
|
||||
assert n_interfaces == 2
|
||||
|
||||
# Run the generated code, defining the message generator classes.
|
||||
binding_ns = {}
|
||||
exec(sio.getvalue(), binding_ns)
|
||||
Service = binding_ns['Service']
|
||||
|
||||
# Check basic functionality of the Service class
|
||||
assert Service.interface == 'org.freedesktop.Secret.Service'
|
||||
msg = Service().SearchItems({"service": "foo", "user": "bar"})
|
||||
assert msg.header.message_type is MessageType.method_call
|
||||
assert msg.header.fields[HeaderFields.destination] == 'org.freedesktop.secrets'
|
24
venv/lib/python3.12/site-packages/jeepney/tests/test_bus.py
Normal file
24
venv/lib/python3.12/site-packages/jeepney/tests/test_bus.py
Normal file
@ -0,0 +1,24 @@
|
||||
import pytest
|
||||
from testpath import modified_env
|
||||
|
||||
from jeepney import bus
|
||||
|
||||
def test_get_connectable_addresses():
|
||||
a = list(bus.get_connectable_addresses('unix:path=/run/user/1000/bus'))
|
||||
assert a == ['/run/user/1000/bus']
|
||||
|
||||
a = list(bus.get_connectable_addresses('unix:abstract=/tmp/foo'))
|
||||
assert a == ['\0/tmp/foo']
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
list(bus.get_connectable_addresses('unix:tmpdir=/tmp'))
|
||||
|
||||
def test_get_bus():
|
||||
with modified_env({
|
||||
'DBUS_SESSION_BUS_ADDRESS':'unix:path=/run/user/1000/bus',
|
||||
'DBUS_SYSTEM_BUS_ADDRESS': 'unix:path=/var/run/dbus/system_bus_socket'
|
||||
}):
|
||||
assert bus.get_bus('SESSION') == '/run/user/1000/bus'
|
||||
assert bus.get_bus('SYSTEM') == '/var/run/dbus/system_bus_socket'
|
||||
|
||||
assert bus.get_bus('unix:path=/run/user/1002/bus') == '/run/user/1002/bus'
|
@ -0,0 +1,109 @@
|
||||
from jeepney import DBusAddress, new_signal, new_method_call
|
||||
from jeepney.bus_messages import MatchRule, message_bus
|
||||
|
||||
portal = DBusAddress(
|
||||
object_path='/org/freedesktop/portal/desktop',
|
||||
bus_name='org.freedesktop.portal.Desktop',
|
||||
)
|
||||
portal_req_iface = portal.with_interface('org.freedesktop.portal.Request')
|
||||
|
||||
|
||||
def test_match_rule_simple():
|
||||
rule = MatchRule(
|
||||
type='signal', interface='org.freedesktop.portal.Request',
|
||||
)
|
||||
assert rule.matches(new_signal(portal_req_iface, 'Response'))
|
||||
|
||||
# Wrong message type
|
||||
assert not rule.matches(new_method_call(portal_req_iface, 'Boo'))
|
||||
|
||||
# Wrong interface
|
||||
assert not rule.matches(new_signal(
|
||||
portal.with_interface('org.freedesktop.portal.FileChooser'), 'Response'
|
||||
))
|
||||
|
||||
|
||||
def test_match_rule_path_namespace():
|
||||
assert MatchRule(path_namespace='/org/freedesktop/portal').matches(
|
||||
new_signal(portal_req_iface, 'Response')
|
||||
)
|
||||
|
||||
# Prefix but not a parent in the path hierarchy
|
||||
assert not MatchRule(path_namespace='/org/freedesktop/por').matches(
|
||||
new_signal(portal_req_iface, 'Response')
|
||||
)
|
||||
|
||||
|
||||
def test_match_rule_arg():
|
||||
rule = MatchRule(type='method_call')
|
||||
rule.add_arg_condition(0, 'foo')
|
||||
|
||||
assert rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='s', body=('foo',)
|
||||
))
|
||||
|
||||
assert not rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='s', body=('foobar',)
|
||||
))
|
||||
|
||||
# No such argument
|
||||
assert not rule.matches(new_method_call(portal_req_iface, 'Boo'))
|
||||
|
||||
|
||||
def test_match_rule_arg_path():
|
||||
rule = MatchRule(type='method_call')
|
||||
rule.add_arg_condition(0, '/aa/bb/', kind='path')
|
||||
|
||||
# Exact match
|
||||
assert rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='s', body=('/aa/bb/',)
|
||||
))
|
||||
|
||||
# Match a prefix
|
||||
assert rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='s', body=('/aa/bb/cc',)
|
||||
))
|
||||
|
||||
# Argument is a prefix, ending with /
|
||||
assert rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='s', body=('/aa/',)
|
||||
))
|
||||
|
||||
# Argument is a prefix, but NOT ending with /
|
||||
assert not rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='s', body=('/aa',)
|
||||
))
|
||||
|
||||
assert not rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='s', body=('/aa/bb',)
|
||||
))
|
||||
|
||||
# Not a string
|
||||
assert not rule.matches(new_method_call(
|
||||
portal_req_iface, 'Boo', signature='u', body=(12,)
|
||||
))
|
||||
|
||||
|
||||
def test_match_rule_arg_namespace():
|
||||
rule = MatchRule(member='NameOwnerChanged')
|
||||
rule.add_arg_condition(0, 'com.example.backend1', kind='namespace')
|
||||
|
||||
# Exact match
|
||||
assert rule.matches(new_signal(
|
||||
message_bus, 'NameOwnerChanged', 's', ('com.example.backend1',)
|
||||
))
|
||||
|
||||
# Parent of the name
|
||||
assert rule.matches(new_signal(
|
||||
message_bus, 'NameOwnerChanged', 's', ('com.example.backend1.foo.bar',)
|
||||
))
|
||||
|
||||
# Prefix but not a parent in the namespace
|
||||
assert not rule.matches(new_signal(
|
||||
message_bus, 'NameOwnerChanged', 's', ('com.example.backend12',)
|
||||
))
|
||||
|
||||
# Not a string
|
||||
assert not rule.matches(new_signal(
|
||||
message_bus, 'NameOwnerChanged', 'u', (1,)
|
||||
))
|
80
venv/lib/python3.12/site-packages/jeepney/tests/test_fds.py
Normal file
80
venv/lib/python3.12/site-packages/jeepney/tests/test_fds.py
Normal file
@ -0,0 +1,80 @@
|
||||
import errno
|
||||
import os
|
||||
import socket
|
||||
|
||||
import pytest
|
||||
|
||||
from jeepney import FileDescriptor, NoFDError
|
||||
|
||||
def assert_not_fd(fd: int):
|
||||
"""Check that the given number is not open as a file descriptor"""
|
||||
with pytest.raises(OSError) as exc_info:
|
||||
os.stat(fd)
|
||||
assert exc_info.value.errno == errno.EBADF
|
||||
|
||||
|
||||
def test_close(tmp_path):
|
||||
fd = os.open(tmp_path / 'a', os.O_CREAT | os.O_RDWR)
|
||||
|
||||
with FileDescriptor(fd) as wfd:
|
||||
assert wfd.fileno() == fd
|
||||
# Leaving the with block is equivalent to calling .close()
|
||||
|
||||
assert 'closed' in repr(wfd)
|
||||
with pytest.raises(NoFDError):
|
||||
wfd.fileno()
|
||||
|
||||
assert_not_fd(fd)
|
||||
|
||||
|
||||
def test_to_raw_fd(tmp_path):
|
||||
fd = os.open(tmp_path / 'a', os.O_CREAT)
|
||||
wfd = FileDescriptor(fd)
|
||||
assert wfd.fileno() == fd
|
||||
|
||||
assert wfd.to_raw_fd() == fd
|
||||
|
||||
try:
|
||||
assert 'converted' in repr(wfd)
|
||||
with pytest.raises(NoFDError):
|
||||
wfd.fileno()
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
|
||||
def test_to_file(tmp_path):
|
||||
fd = os.open(tmp_path / 'a', os.O_CREAT | os.O_RDWR)
|
||||
wfd = FileDescriptor(fd)
|
||||
|
||||
with wfd.to_file('w') as f:
|
||||
assert f.write('abc')
|
||||
|
||||
assert 'converted' in repr(wfd)
|
||||
with pytest.raises(NoFDError):
|
||||
wfd.fileno()
|
||||
|
||||
assert_not_fd(fd) # Check FD was closed by file object
|
||||
|
||||
assert (tmp_path / 'a').read_text() == 'abc'
|
||||
|
||||
|
||||
def test_to_socket():
|
||||
s1, s2 = socket.socketpair()
|
||||
try:
|
||||
s1.sendall(b'abcd')
|
||||
sfd = s2.detach()
|
||||
wfd = FileDescriptor(sfd)
|
||||
|
||||
with wfd.to_socket() as sock:
|
||||
b = sock.recv(16)
|
||||
assert b and b'abcd'.startswith(b)
|
||||
|
||||
assert 'converted' in repr(wfd)
|
||||
with pytest.raises(NoFDError):
|
||||
wfd.fileno()
|
||||
|
||||
assert_not_fd(sfd) # Check FD was closed by socket object
|
||||
finally:
|
||||
s1.close()
|
||||
|
||||
|
@ -0,0 +1,87 @@
|
||||
import pytest
|
||||
from jeepney.low_level import *
|
||||
|
||||
HELLO_METHOD_CALL = (
|
||||
b'l\x01\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00m\x00\x00\x00\x01\x01o\x00\x15'
|
||||
b'\x00\x00\x00/org/freedesktop/DBus\x00\x00\x00\x02\x01s\x00\x14\x00\x00\x00'
|
||||
b'org.freedesktop.DBus\x00\x00\x00\x00\x03\x01s\x00\x05\x00\x00\x00Hello\x00'
|
||||
b'\x00\x00\x06\x01s\x00\x14\x00\x00\x00org.freedesktop.DBus\x00\x00\x00\x00')
|
||||
|
||||
|
||||
def test_parser_simple():
|
||||
msg = Parser().feed(HELLO_METHOD_CALL)[0]
|
||||
assert msg.header.fields[HeaderFields.member] == 'Hello'
|
||||
|
||||
def chunks(src, size):
|
||||
pos = 0
|
||||
while pos < len(src):
|
||||
end = pos + size
|
||||
yield src[pos:end]
|
||||
pos = end
|
||||
|
||||
def test_parser_chunks():
|
||||
p = Parser()
|
||||
chunked = list(chunks(HELLO_METHOD_CALL, 16))
|
||||
for c in chunked[:-1]:
|
||||
assert p.feed(c) == []
|
||||
msg = p.feed(chunked[-1])[0]
|
||||
assert msg.header.fields[HeaderFields.member] == 'Hello'
|
||||
|
||||
def test_multiple():
|
||||
msgs = Parser().feed(HELLO_METHOD_CALL * 6)
|
||||
assert len(msgs) == 6
|
||||
for msg in msgs:
|
||||
assert msg.header.fields[HeaderFields.member] == 'Hello'
|
||||
|
||||
def test_roundtrip():
|
||||
msg = Parser().feed(HELLO_METHOD_CALL)[0]
|
||||
assert msg.serialise() == HELLO_METHOD_CALL
|
||||
|
||||
def test_serialise_dict():
|
||||
data = {
|
||||
'a': 'b',
|
||||
'de': 'f',
|
||||
}
|
||||
string_type = simple_types['s']
|
||||
sig = Array(DictEntry([string_type, string_type]))
|
||||
print(sig.serialise(data, 0, Endianness.little))
|
||||
assert sig.serialise(data, 0, Endianness.little) == (
|
||||
b'\x1e\0\0\0' + # Length
|
||||
b'\0\0\0\0' + # Padding
|
||||
b'\x01\0\0\0a\0\0\0' +
|
||||
b'\x01\0\0\0b\0\0\0' +
|
||||
b'\x02\0\0\0de\0\0' +
|
||||
b'\x01\0\0\0f\0'
|
||||
)
|
||||
|
||||
def test_parse_signature():
|
||||
sig = parse_signature(list('(a{sv}(oayays)b)'))
|
||||
print(sig)
|
||||
assert sig == Struct([
|
||||
Array(DictEntry([simple_types['s'], Variant()])),
|
||||
Struct([
|
||||
simple_types['o'],
|
||||
Array(simple_types['y']),
|
||||
Array(simple_types['y']),
|
||||
simple_types['s']
|
||||
]),
|
||||
simple_types['b'],
|
||||
])
|
||||
|
||||
class fake_list(list):
|
||||
def __init__(self, n):
|
||||
super().__init__()
|
||||
self._n = n
|
||||
|
||||
def __len__(self):
|
||||
return self._n
|
||||
|
||||
def __iter__(self):
|
||||
return iter(range(self._n))
|
||||
|
||||
def test_array_limit():
|
||||
# The spec limits arrays to 64 MiB
|
||||
a = Array(FixedType(8, 'Q')) # 'at' - array of uint64
|
||||
a.serialise(fake_list(100), 0, Endianness.little)
|
||||
with pytest.raises(SizeLimitError):
|
||||
a.serialise(fake_list(2**23 + 1), 0, Endianness.little)
|
@ -0,0 +1,32 @@
|
||||
from asyncio import Future
|
||||
import pytest
|
||||
|
||||
from jeepney.routing import Router
|
||||
from jeepney.wrappers import new_method_return, new_error, DBusErrorResponse
|
||||
from jeepney.bus_messages import message_bus
|
||||
|
||||
def test_message_reply():
|
||||
router = Router(Future)
|
||||
call = message_bus.Hello()
|
||||
future = router.outgoing(call)
|
||||
router.incoming(new_method_return(call, 's', ('test',)))
|
||||
assert future.result() == ('test',)
|
||||
|
||||
def test_error():
|
||||
router = Router(Future)
|
||||
call = message_bus.Hello()
|
||||
future = router.outgoing(call)
|
||||
router.incoming(new_error(call, 'TestError', 'u', (31,)))
|
||||
with pytest.raises(DBusErrorResponse) as e:
|
||||
future.result()
|
||||
assert e.value.name == 'TestError'
|
||||
assert e.value.data == (31,)
|
||||
|
||||
def test_unhandled():
|
||||
unhandled = []
|
||||
router = Router(Future, on_unhandled=unhandled.append)
|
||||
msg = message_bus.Hello()
|
||||
router.incoming(msg)
|
||||
assert len(unhandled) == 1
|
||||
assert unhandled[0] == msg
|
||||
|
Reference in New Issue
Block a user