[Python-modules-commits] [pydbus] 01/03: Import pydbus_0.6.0.orig.tar.gz
Alberto Caso
acaso-guest at moszumanska.debian.org
Wed Dec 28 10:42:49 UTC 2016
This is an automated email from the git hooks/post-receive script.
acaso-guest pushed a commit to branch master
in repository pydbus.
commit 9b3b40cf5b3ae18767621154ea6ce8ecfd40461d
Author: Alberto Caso <alberto.caso at juntaex.es>
Date: Wed Dec 28 11:30:31 2016 +0100
Import pydbus_0.6.0.orig.tar.gz
---
.gitignore | 3 -
.travis.yml | 24 ++++
MANIFEST.in | 1 +
Makefile | 9 ++
README.rst | 46 +++++--
doc/tutorial.rst | 29 +++--
{pydbus/examples => examples}/__init__.py | 0
.../examples => examples}/clientserver/__init__.py | 0
.../examples => examples}/clientserver/client.py | 0
.../examples => examples}/clientserver/server.py | 4 +-
examples/notifications_server.py | 65 ++++++++++
{pydbus/examples => examples/polkit}/__init__.py | 0
examples/polkit/dbus.conf | 15 +++
examples/polkit/service.py | 27 ++++
{pydbus/examples => examples}/systemctl.py | 1 -
pydbus/__init__.py | 5 +-
pydbus/_inspect3.py | 6 +
pydbus/auto_names.py | 4 +
pydbus/bus.py | 59 ++++++---
pydbus/bus_names.py | 25 ++--
pydbus/method_call_context.py | 34 +++++
pydbus/proxy.py | 31 +++--
pydbus/proxy_method.py | 23 +++-
pydbus/proxy_property.py | 4 +-
pydbus/publication.py | 13 +-
pydbus/registration.py | 117 +++++++++++-------
pydbus/request_name.py | 29 +++++
pydbus/subscription.py | 4 +-
pydbus/tests/context.py | 24 ----
pydbus/tests/publish.py | 62 ----------
pydbus/timeout.py | 15 +++
setup.py | 15 ++-
signal-spammer/Makefile | 2 -
signal-spammer/spammer.cpp | 137 ---------------------
{pydbus/tests => tests}/__init__.py | 0
tests/context.py | 39 ++++++
{pydbus/tests => tests}/gnome_music.py | 4 +-
{pydbus/tests => tests}/identifier.py | 0
tests/publish.py | 62 ++++++++++
{pydbus/tests => tests}/publish_multiface.py | 35 +++---
tests/publish_properties.py | 71 +++++++++++
tests/py2.7-ubuntu-14.04.dockerfile | 11 ++
tests/py2.7-ubuntu-16.04.dockerfile | 11 ++
tests/py3.4-ubuntu-14.04.dockerfile | 11 ++
tests/py3.5-ubuntu-16.04.dockerfile | 11 ++
tests/run.sh | 18 +++
46 files changed, 731 insertions(+), 375 deletions(-)
diff --git a/.gitignore b/.gitignore
index ed4c188..414b218 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,3 @@ coverage.xml
# Sphinx documentation
docs/_build/
-
-# Custom
-signal-spammer/spammer
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2c3691e
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,24 @@
+sudo: required
+
+env:
+ - distribution: ubuntu
+ version: 16.04
+ python: 3.5
+ - distribution: ubuntu
+ version: 16.04
+ python: 2.7
+ - distribution: ubuntu
+ version: 14.04
+ python: 3.4
+ - distribution: ubuntu
+ version: 14.04
+ python: 2.7
+
+services:
+ - docker
+
+before_install:
+ - "docker pull ${distribution}:${version}"
+
+script:
+ - "docker build --file=tests/py${python}-${distribution}-${version}.dockerfile ."
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..1aba38f
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include LICENSE
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..feb4988
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,9 @@
+packages: wheel sdist
+
+wheel:
+ rm -Rf build
+ ./setup.py bdist_wheel
+
+sdist:
+ rm -Rf build
+ ./setup.py sdist
diff --git a/README.rst b/README.rst
index b7ee90e..2538983 100644
--- a/README.rst
+++ b/README.rst
@@ -1,13 +1,23 @@
pydbus
======
+.. image:: https://travis-ci.org/LEW21/pydbus.svg?branch=master
+ :target: https://travis-ci.org/LEW21/pydbus
+.. image:: https://badge.fury.io/py/pydbus.svg
+ :target: https://badge.fury.io/py/pydbus
Pythonic DBus library.
-It's based on PyGI_, the Python GObject Introspection bindings, which is the recommended way to use GLib from Python. Unfortunately, PyGI is not packaged on pypi, so you need to install it from your distribution's repository (usually called python-gi, python-gobject or pygobject3).
+Changelog: https://github.com/LEW21/pydbus/releases
-It's pythonic!
+Requirements
+------------
+* Python 2.7+ - but works best on 3.4+ (help system is nicer there)
+* PyGI_ (not packaged on pypi, you need to install it from your distribution's repository - it's usually called python-gi, python-gobject or pygobject)
+* GLib_ 2.46+ and girepository_ 1.46+ (Ubuntu 16.04+) - for object publication support
-And now, it can also publish objects! Changelog: https://github.com/LEW21/pydbus/releases
+.. _PyGI: https://wiki.gnome.org/Projects/PyGObject
+.. _GLib: https://developer.gnome.org/glib/
+.. _girepository: https://wiki.gnome.org/Projects/GObjectIntrospection
Examples
--------
@@ -35,23 +45,35 @@ List systemd units
for unit in systemd.ListUnits():
print(unit)
+Start or stop systemd unit
+~~~~~~~~~~~~~~~~~~
+.. code-block:: python
+
+ from pydbus import SystemBus
+
+ bus = SystemBus()
+ systemd = bus.get(".systemd1")
+
+ job1 = systemd.StopUnit("ssh.service", "fail")
+ job2 = systemd.StartUnit("ssh.service", "fail")
+
Watch for new systemd jobs
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
from pydbus import SystemBus
- from gi.repository import GObject
+ from gi.repository import GLib
bus = SystemBus()
systemd = bus.get(".systemd1")
systemd.JobNew.connect(print)
- GObject.MainLoop().run()
+ GLib.MainLoop().run()
# or
systemd.onJobNew = print
- GObject.MainLoop().run()
+ GLib.MainLoop().run()
View object's API
~~~~~~~~~~~~~~~~~
@@ -69,13 +91,23 @@ More examples & documentation
The Tutorial_ contains more examples and docs.
-.. _PyGI: https://wiki.gnome.org/PyGObject
.. _Tutorial: https://github.com/LEW21/pydbus/blob/master/doc/tutorial.rst
Copyright Information
---------------------
+Copyright (C) 2014, 2015, 2016 Linus Lewandowski <linus at lew21.net>
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
diff --git a/doc/tutorial.rst b/doc/tutorial.rst
index 456917c..7474de3 100644
--- a/doc/tutorial.rst
+++ b/doc/tutorial.rst
@@ -2,14 +2,14 @@
pydbus tutorial
===============
-:Author: `Janusz Lewandowski`_
+:Author: `Linus Lewandowski`_
:Based on: python-dbus tutorial by Simon McVittie, `Collabora Ltd.`_ (2006-06-14)
-:Date: 2016-04-08
+:Date: 2016-09-26
.. _`Collabora Ltd.`: http://www.collabora.co.uk/
-.. _`Janusz Lewandowski`: http://lew21.net/
+.. _`Linus Lewandowski`: http://lew21.net/
-This tutorial requires Python 2.7 or up, and ``pydbus`` 0.5 or up.
+This tutorial requires Python 2.7 or up, and ``pydbus`` 0.6 or up.
.. contents::
@@ -86,13 +86,16 @@ Setting up an event loop
To handle signals emitted by exported objects, or to export your own objects, you need to setup an event loop.
-The only main loop supported by ``pydbus`` is GLib's GObject.MainLoop.
+The only main loop supported by ``pydbus`` is GLib.MainLoop.
+
+GLib.MainLoop
+-------------
To create the loop object use::
- from gi.repository import GObject
+ from gi.repository import GLib
- loop = GObject.MainLoop()
+ loop = GLib.MainLoop()
To execute the loop use::
@@ -185,7 +188,7 @@ in another, it won't work.
See also
~~~~~~~~
-See the examples in ``pydbus/examples/systemctl.py`` and ``pydbus/tests/gnome_music.py``.
+See the examples in ``examples/systemctl.py`` and ``tests/gnome_music.py``.
Interfaces
----------
@@ -313,9 +316,9 @@ method, that can be used as a context manager.
See also
~~~~~~~~
-See the example in ``pydbus/examples/clientserver/server.py``.
+See the example in ``examples/clientserver/server.py``.
-.. _bus.own_name:
+.. _bus.request_name:
.. _bus.register_object:
Lower level API
@@ -324,8 +327,8 @@ Lower level API
Sometimes, you can't just publish everything in one call, you need more control
over the process of binding a name and exporting single objects.
-In this case, you can use ``bus.own_name()`` and ``bus.register_object()`` yourself.
-See ``help(bus.own_name)`` and ``help(bus.register_object)`` for details.
+In this case, you can use ``bus.request_name()`` and ``bus.register_object()`` yourself.
+See ``help(bus.request_name)`` and ``help(bus.register_object)`` for details.
.. --------------------------------------------------------------------
@@ -380,7 +383,7 @@ License for this document
Copyright 2006-2007 `Collabora Ltd.`_
-Copyright 2016 `Janusz Lewandowski`_
+Copyright 2016 `Linus Lewandowski`_
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
diff --git a/pydbus/examples/__init__.py b/examples/__init__.py
similarity index 100%
copy from pydbus/examples/__init__.py
copy to examples/__init__.py
diff --git a/pydbus/examples/clientserver/__init__.py b/examples/clientserver/__init__.py
similarity index 100%
rename from pydbus/examples/clientserver/__init__.py
rename to examples/clientserver/__init__.py
diff --git a/pydbus/examples/clientserver/client.py b/examples/clientserver/client.py
similarity index 100%
rename from pydbus/examples/clientserver/client.py
rename to examples/clientserver/client.py
diff --git a/pydbus/examples/clientserver/server.py b/examples/clientserver/server.py
similarity index 94%
rename from pydbus/examples/clientserver/server.py
rename to examples/clientserver/server.py
index 4021117..25485ae 100644
--- a/pydbus/examples/clientserver/server.py
+++ b/examples/clientserver/server.py
@@ -5,10 +5,10 @@
# Python DBUS Test Server
# runs until the Quit() method is called via DBUS
-from gi.repository import GObject
+from gi.repository import GLib
from pydbus import SessionBus
-loop = GObject.MainLoop()
+loop = GLib.MainLoop()
class MyDBUSService(object):
"""
diff --git a/examples/notifications_server.py b/examples/notifications_server.py
new file mode 100644
index 0000000..3151974
--- /dev/null
+++ b/examples/notifications_server.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+from gi.repository import GLib
+from pydbus import SessionBus
+from pydbus.generic import signal
+
+class Notifications(object):
+ """
+ <node>
+ <interface name="org.freedesktop.Notifications">
+ <signal name="NotificationClosed">
+ <arg direction="out" type="u" name="id"/>
+ <arg direction="out" type="u" name="reason"/>
+ </signal>
+ <signal name="ActionInvoked">
+ <arg direction="out" type="u" name="id"/>
+ <arg direction="out" type="s" name="action_key"/>
+ </signal>
+ <method name="Notify">
+ <arg direction="out" type="u"/>
+ <arg direction="in" type="s" name="app_name"/>
+ <arg direction="in" type="u" name="replaces_id"/>
+ <arg direction="in" type="s" name="app_icon"/>
+ <arg direction="in" type="s" name="summary"/>
+ <arg direction="in" type="s" name="body"/>
+ <arg direction="in" type="as" name="actions"/>
+ <arg direction="in" type="a{sv}" name="hints"/>
+ <arg direction="in" type="i" name="timeout"/>
+ </method>
+ <method name="CloseNotification">
+ <arg direction="in" type="u" name="id"/>
+ </method>
+ <method name="GetCapabilities">
+ <arg direction="out" type="as" name="caps"/>
+ </method>
+ <method name="GetServerInformation">
+ <arg direction="out" type="s" name="name"/>
+ <arg direction="out" type="s" name="vendor"/>
+ <arg direction="out" type="s" name="version"/>
+ <arg direction="out" type="s" name="spec_version"/>
+ </method>
+ </interface>
+ </node>
+ """
+
+ NotificationClosed = signal()
+ ActionInvoked = signal()
+
+ def Notify(self, app_name, replaces_id, app_icon, summary, body, actions, hints, timeout):
+ print("Notification: {} {} {} {} {} {} {} {}".format(app_name, replaces_id, app_icon, summary, body, actions, hints, timeout))
+ return 4 # chosen by fair dice roll. guaranteed to be random.
+
+ def CloseNotification(self, id):
+ pass
+
+ def GetCapabilities(self):
+ return []
+
+ def GetServerInformation(self):
+ return ("pydbus.examples.notifications_server", "pydbus", "?", "1.1")
+
+bus = SessionBus()
+bus.publish("org.freedesktop.Notifications", Notifications())
+loop = GLib.MainLoop()
+loop.run()
diff --git a/pydbus/examples/__init__.py b/examples/polkit/__init__.py
similarity index 100%
rename from pydbus/examples/__init__.py
rename to examples/polkit/__init__.py
diff --git a/examples/polkit/dbus.conf b/examples/polkit/dbus.conf
new file mode 100644
index 0000000..44965a5
--- /dev/null
+++ b/examples/polkit/dbus.conf
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!-- Copy/symlink this file as /etc/dbus-1/system.d/pydbus-example.conf (or whatever.conf) -->
+<busconfig>
+ <policy user="root">
+ <allow own="net.lew21.pydbus.PolkitExample"/>
+ </policy>
+
+ <policy context="default">
+ <allow send_destination="net.lew21.pydbus.PolkitExample"/>
+
+ <allow receive_sender="net.lew21.pydbus.PolkitExample"/>
+ </policy>
+</busconfig>
diff --git a/examples/polkit/service.py b/examples/polkit/service.py
new file mode 100644
index 0000000..f80a6a5
--- /dev/null
+++ b/examples/polkit/service.py
@@ -0,0 +1,27 @@
+from pydbus import SystemBus
+from gi.repository import GLib
+import logging
+
+loop = GLib.MainLoop()
+
+class TestObject(object):
+ dbus = '''
+<node>
+ <interface name='net.lew21.pydbus.PolkitExample'>
+ <method name='TestAuth'>
+ <arg type='b' name='interactive' direction='in'/>
+ <arg type='s' name='response' direction='out'/>
+ </method>
+ </interface>
+</node>
+ '''
+ def TestAuth(self, interactive, dbus_context):
+ if dbus_context.is_authorized('org.freedesktop.policykit.exec', {'polkit.icon': 'abcd', 'aaaa': 'zzzz'}, interactive=interactive):
+ return "OK"
+ else:
+ return "Forbidden"
+
+with SystemBus() as bus:
+ with bus.publish("net.lew21.pydbus.PolkitExample", TestObject()):
+ logging.info("Started.")
+ loop.run()
diff --git a/pydbus/examples/systemctl.py b/examples/systemctl.py
similarity index 96%
rename from pydbus/examples/systemctl.py
rename to examples/systemctl.py
index 1e82dbc..e9c70a7 100644
--- a/pydbus/examples/systemctl.py
+++ b/examples/systemctl.py
@@ -1,5 +1,4 @@
from pydbus import SystemBus
-from gi.repository import Gio
bus = SystemBus()
diff --git a/pydbus/__init__.py b/pydbus/__init__.py
index 45fe1b7..5576517 100644
--- a/pydbus/__init__.py
+++ b/pydbus/__init__.py
@@ -1,3 +1,4 @@
-from .bus import SystemBus, SessionBus
+from .bus import SystemBus, SessionBus, connect
+from gi.repository.GLib import Variant
-__all__ = ["SystemBus", "SessionBus"]
+__all__ = ["SystemBus", "SessionBus", "connect", "Variant"]
diff --git a/pydbus/_inspect3.py b/pydbus/_inspect3.py
index a33b1e2..b0a2f22 100644
--- a/pydbus/_inspect3.py
+++ b/pydbus/_inspect3.py
@@ -1,4 +1,5 @@
from collections import OrderedDict
+from inspect import getargspec
class _empty:
pass
@@ -15,8 +16,13 @@ class Parameter:
POSITIONAL_ONLY = 0
POSITIONAL_OR_KEYWORD = 1
+ KEYWORD_ONLY = 999
def __init__(self, name, kind, default=_empty, annotation=_empty):
self.name = name
self.kind = kind
self.annotation = annotation
+
+def signature(f):
+ parameters = [Parameter(arg, Parameter.POSITIONAL_OR_KEYWORD) for arg in getargspec(f).args]
+ return Signature(parameters = parameters)
diff --git a/pydbus/auto_names.py b/pydbus/auto_names.py
index cd4c293..06c6c18 100644
--- a/pydbus/auto_names.py
+++ b/pydbus/auto_names.py
@@ -1,9 +1,13 @@
+from gi.repository import Gio
def auto_bus_name(bus_name):
if bus_name[0] == ".":
#Default namespace
bus_name = "org.freedesktop" + bus_name
+ if not Gio.dbus_is_name(bus_name):
+ raise ValueError("invalid bus name")
+
return bus_name
def auto_object_path(bus_name, object_path=None):
diff --git a/pydbus/bus.py b/pydbus/bus.py
index b010ed0..6726390 100644
--- a/pydbus/bus.py
+++ b/pydbus/bus.py
@@ -1,35 +1,60 @@
from gi.repository import Gio
from .proxy import ProxyMixin
+from .request_name import RequestNameMixin
from .bus_names import OwnMixin, WatchMixin
from .subscription import SubscriptionMixin
from .registration import RegistrationMixin
from .publication import PublicationMixin
-class Bus(ProxyMixin, OwnMixin, WatchMixin, SubscriptionMixin, RegistrationMixin, PublicationMixin):
+def pydbus_property(self):
+ try:
+ return self._pydbus
+ except AttributeError:
+ self._pydbus = Bus(self)
+ return self._pydbus
+
+Gio.DBusConnection.pydbus = property(pydbus_property)
+
+def bus_get(type):
+ return Gio.bus_get_sync(type, None).pydbus
+
+def connect(address):
+ c = Gio.DBusConnection.new_for_address_sync(address, Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT | Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION, None, None)
+ c.pydbus.autoclose = True
+ return c.pydbus
+
+class Bus(ProxyMixin, RequestNameMixin, OwnMixin, WatchMixin, SubscriptionMixin, RegistrationMixin, PublicationMixin):
Type = Gio.BusType
- def __init__(self, type, timeout=1000):
- self.con = Gio.bus_get_sync(type, None)
- self.timeout = timeout
+ def __init__(self, gio_con):
+ self.con = gio_con
+ self.autoclose = False
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
- self.con = None
+ if self.autoclose:
+ self.con.close_sync(None)
+
+ @property
+ def dbus(self):
+ try:
+ return self._dbus
+ except AttributeError:
+ self._dbus = self.get(".DBus")[""]
+ return self._dbus
+
+ @property
+ def polkit_authority(self):
+ try:
+ return self._polkit_authority
+ except AttributeError:
+ self._polkit_authority = self.get(".PolicyKit1", "Authority")[""]
+ return self._polkit_authority
def SystemBus():
- return Bus(Bus.Type.SYSTEM)
+ return bus_get(Bus.Type.SYSTEM)
def SessionBus():
- return Bus(Bus.Type.SESSION)
-
-if __name__ == "__main__":
- import sys
- title = sys.argv[1] if len(sys.argv) >= 2 else "Hello World!"
- message = sys.argv[2] if len(sys.argv) >= 3 else 'pydbus works :)'
-
- bus = SessionBus()
- notifications = bus.get('.Notifications') # org.freedesktop automatically prepended
- notifications[""].Notify('test', 0, 'dialog-information', title, message, [], {}, 5000)
- # [""] is not required, but makes us compatible with Gnome 2030.
+ return bus_get(Bus.Type.SESSION)
diff --git a/pydbus/bus_names.py b/pydbus/bus_names.py
index 290627a..3b27431 100644
--- a/pydbus/bus_names.py
+++ b/pydbus/bus_names.py
@@ -1,5 +1,6 @@
from gi.repository import Gio
from .exitable import ExitableWithAliases
+import warnings
class NameOwner(ExitableWithAliases("unown")):
Flags = Gio.BusNameOwnerFlags
@@ -22,13 +23,13 @@ class OwnMixin(object):
NameOwnerFlags = NameOwner.Flags
def own_name(self, name, flags=0, name_aquired=None, name_lost=None):
- """Asynchronously aquires a bus name.
+ """[DEPRECATED] Asynchronously aquires a bus name.
Starts acquiring name on the bus specified by bus_type and calls
name_acquired and name_lost when the name is acquired respectively lost.
- To receive name_aquired and name_lost callbacks, you need GLib main loop.
- You can execute it with GObject.MainLoop().run().
+ To receive name_aquired and name_lost callbacks, you need an event loop.
+ https://github.com/LEW21/pydbus/blob/master/doc/tutorial.rst#setting-up-an-event-loop
Parameters
----------
@@ -50,6 +51,8 @@ class OwnMixin(object):
See https://developer.gnome.org/gio/2.44/gio-Owning-Bus-Names.html#g-bus-own-name
for more information.
"""
+ warnings.warn("own_name() is deprecated, use request_name() instead.", DeprecationWarning)
+
name_aquired_handler = (lambda con, name: name_aquired()) if name_aquired is not None else None
name_lost_handler = (lambda con, name: name_lost()) if name_lost is not None else None
return NameOwner(self.con, name, flags, name_aquired_handler, name_lost_handler)
@@ -65,8 +68,8 @@ class WatchMixin(object):
name_appeared and name_vanished when the name is known to have a owner
respectively known to lose its owner.
- To receive name_appeared and name_vanished callbacks, you need GLib main loop.
- You can execute it with GObject.MainLoop().run().
+ To receive name_appeared and name_vanished callbacks, you need an event loop.
+ https://github.com/LEW21/pydbus/blob/master/doc/tutorial.rst#setting-up-an-event-loop
Parameters
----------
@@ -92,15 +95,3 @@ class WatchMixin(object):
name_appeared_handler = (lambda con, name, name_owner: name_appeared(name_owner)) if name_appeared is not None else None
name_vanished_handler = (lambda con, name: name_vanished()) if name_vanished is not None else None
return NameWatcher(self.con, name, flags, name_appeared_handler, name_vanished_handler)
-
-if __name__ == "__main__":
- from . import SessionBus
- from gi.repository import GObject
-
- def echo(x):
- print(x)
-
- bus = SessionBus()
- bus.watch_name("com.example", 0, echo)
- bus.own_name("com.example")
- GObject.MainLoop().run()
diff --git a/pydbus/method_call_context.py b/pydbus/method_call_context.py
new file mode 100644
index 0000000..a565631
--- /dev/null
+++ b/pydbus/method_call_context.py
@@ -0,0 +1,34 @@
+from gi.repository import GLib
+from collections import namedtuple
+
+AuthorizationResult = namedtuple("AuthorizationResult", "is_authorized is_challenge details")
+
+class MethodCallContext(object):
+ def __init__(self, gdbus_method_invocation):
+ self._mi = gdbus_method_invocation
+
+ @property
+ def bus(self):
+ return self._mi.get_connection().pydbus
+
+ @property
+ def sender(self):
+ return self._mi.get_sender()
+
+ @property
+ def object_path(self):
+ return self._mi.get_object_path()
+
+ @property
+ def interface_name(self):
+ return self._mi.get_interface_name()
+
+ @property
+ def method_name(self):
+ return self._mi.get_method_name()
+
+ def check_authorization(self, action_id, details, interactive=False):
+ return AuthorizationResult(*self.bus.polkit_authority.CheckAuthorization(('system-bus-name', {'name': GLib.Variant("s", self.sender)}), action_id, details, 1 if interactive else 0, ''))
+
+ def is_authorized(self, action_id, details, interactive=False):
+ return self.check_authorization(action_id, details, interactive).is_authorized
diff --git a/pydbus/proxy.py b/pydbus/proxy.py
index be1cdd2..c081113 100644
--- a/pydbus/proxy.py
+++ b/pydbus/proxy.py
@@ -5,11 +5,12 @@ from .auto_names import *
from .proxy_method import ProxyMethod
from .proxy_property import ProxyProperty
from .proxy_signal import ProxySignal, OnSignal
+from .timeout import timeout_to_glib
class ProxyMixin(object):
__slots__ = ()
- def get(self, bus_name, object_path=None):
+ def get(self, bus_name, object_path=None, **kwargs):
"""Get a remote object.
Parameters
@@ -31,26 +32,38 @@ class ProxyMixin(object):
>>> bus.get(".systemd1")[".Manager"]
which will give you access to the one specific interface.
"""
+ # Python 2 sux
+ for kwarg in kwargs:
+ if kwarg not in ("timeout",):
+ raise TypeError(self.__qualname__ + " got an unexpected keyword argument '{}'".format(kwarg))
+ timeout = kwargs.get("timeout", None)
+
bus_name = auto_bus_name(bus_name)
object_path = auto_object_path(bus_name, object_path)
- xml = self.con.call_sync(
+ ret = self.con.call_sync(
bus_name, object_path,
'org.freedesktop.DBus.Introspectable', "Introspect", None, GLib.VariantType.new("(s)"),
- 0, self.timeout, None).unpack()[0]
+ 0, timeout_to_glib(timeout), None)
+
+ if not ret:
+ raise KeyError("no such object; you might need to pass object path as the 2nd argument for get()")
- introspection = ET.fromstring(xml)
+ xml, = ret.unpack()
- if len(introspection) == 0:
- raise KeyError("no such object")
+ try:
+ introspection = ET.fromstring(xml)
+ except:
+ raise KeyError("object provides invalid introspection XML")
return CompositeInterface(introspection)(self, bus_name, object_path)
class ProxyObject(object):
- def __init__(self, bus, bus_name, path):
+ def __init__(self, bus, bus_name, path, object=None):
self._bus = bus
self._bus_name = bus_name
self._path = path
+ self._object = object if object else self
def Interface(iface):
@@ -90,7 +103,7 @@ def CompositeInterface(introspection):
assert(len(matching_bases) == 1)
iface_class = matching_bases[0]
- return iface_class(self._bus, self._bus_name, self._path)
+ return iface_class(self._bus, self._bus_name, self._path, self)
@classmethod
def _Introspect(cls):
@@ -101,6 +114,8 @@ def CompositeInterface(introspection):
pass
ifaces = sorted([x for x in introspection if x.tag == "interface"], key=lambda x: int(x.attrib["name"].startswith("org.freedesktop.DBus.")))
+ if not ifaces:
+ raise KeyError("object does not export any interfaces; you might need to pass object path as the 2nd argument for get()")
CompositeObject.__bases__ = tuple(Interface(iface) for iface in ifaces)
CompositeObject.__name__ = "<CompositeObject>"
CompositeObject.__qualname__ = "<CompositeObject>(" + "+".join(x.__name__ for x in CompositeObject.__bases__) + ")"
diff --git a/pydbus/proxy_method.py b/pydbus/proxy_method.py
index f5a9f30..8798edd 100644
--- a/pydbus/proxy_method.py
+++ b/pydbus/proxy_method.py
@@ -1,6 +1,7 @@
from gi.repository import GLib
from .generic import bound_method
from .identifier import filter_identifier
+from .timeout import timeout_to_glib
try:
from inspect import Signature, Parameter
@@ -32,14 +33,14 @@ class ProxyMethod(object):
self.__name__ = method.attrib["name"]
self.__qualname__ = self._iface_name + "." + self.__name__
- inargs = [(arg.attrib.get("name", ""), arg.attrib["type"]) for arg in method if arg.tag == "arg" and arg.attrib["direction"] == "in"]
+ self._inargs = [(arg.attrib.get("name", ""), arg.attrib["type"]) for arg in method if arg.tag == "arg" and arg.attrib["direction"] == "in"]
self._outargs = [arg.attrib["type"] for arg in method if arg.tag == "arg" and arg.attrib["direction"] == "out"]
- self._sinargs = "(" + "".join(x[1] for x in inargs) + ")"
+ self._sinargs = "(" + "".join(x[1] for x in self._inargs) + ")"
self._soutargs = "(" + "".join(self._outargs) + ")"
self_param = Parameter("self", Parameter.POSITIONAL_ONLY)
pos_params = []
- for i, a in enumerate(inargs):
+ for i, a in enumerate(self._inargs):
name = filter_identifier(a[0])
if not name:
@@ -55,11 +56,23 @@ class ProxyMethod(object):
if put_signature_in_doc:
self.__doc__ = self.__name__ + str(self.__signature__)
- def __call__(self, instance, *args):
+ def __call__(self, instance, *args, **kwargs):
+ argdiff = len(args) - len(self._inargs)
+ if argdiff < 0:
+ raise TypeError(self.__qualname__ + " missing {} required positional argument(s)".format(-argdiff))
+ elif argdiff > 0:
+ raise TypeError(self.__qualname__ + " takes {} positional argument(s) but {} was/were given".format(len(self._inargs), len(args)))
+
+ # Python 2 sux
+ for kwarg in kwargs:
+ if kwarg not in ("timeout",):
+ raise TypeError(self.__qualname__ + " got an unexpected keyword argument '{}'".format(kwarg))
+ timeout = kwargs.get("timeout", None)
+
ret = instance._bus.con.call_sync(
instance._bus_name, instance._path,
self._iface_name, self.__name__, GLib.Variant(self._sinargs, args), GLib.VariantType.new(self._soutargs),
- 0, instance._bus.timeout, None).unpack()
+ 0, timeout_to_glib(timeout), None).unpack()
if len(self._outargs) == 0:
return None
diff --git a/pydbus/proxy_property.py b/pydbus/proxy_property.py
index f7c3bf7..e06a17d 100644
--- a/pydbus/proxy_property.py
+++ b/pydbus/proxy_property.py
@@ -19,13 +19,13 @@ class ProxyProperty(object):
if not self._readable:
raise AttributeError("unreadable attribute")
- return instance["org.freedesktop.DBus.Properties"].Get(self._iface_name, self.__name__)
+ return instance._object["org.freedesktop.DBus.Properties"].Get(self._iface_name, self.__name__)
def __set__(self, instance, value):
if instance is None or not self._writeable:
raise AttributeError("can't set attribute")
- instance["org.freedesktop.DBus.Properties"].Set(self._iface_name, self.__name__, GLib.Variant(self._type, value))
+ instance._object["org.freedesktop.DBus.Properties"].Set(self._iface_name, self.__name__, GLib.Variant(self._type, value))
def __repr__(self):
return "<property " + self.__qualname__ + " at 0x" + format(id(self), "x") + ">"
diff --git a/pydbus/publication.py b/pydbus/publication.py
index 10cbb32..ef03825 100644
--- a/pydbus/publication.py
+++ b/pydbus/publication.py
@@ -5,9 +5,15 @@ from .auto_names import *
class Publication(ExitableWithAliases("unpublish")):
__slots__ = ()
- def __init__(self, bus, bus_name, *objects):
+ def __init__(self, bus, bus_name, *objects, **kwargs): # allow_replacement=True, replace=False
+ # Python 2 sux
+ for kwarg in kwargs:
+ if kwarg not in ("allow_replacement", "replace",):
+ raise TypeError(self.__qualname__ + " got an unexpected keyword argument '{}'".format(kwarg))
+ allow_replacement = kwargs.get("allow_replacement", True)
+ replace = kwargs.get("replace", False)
+
bus_name = auto_bus_name(bus_name)
- self._at_exit(bus.own_name(bus_name).__exit__)
for object_info in objects:
path, object, node_info = (None, None, None)
@@ -25,6 +31,9 @@ class Publication(ExitableWithAliases("unpublish")):
path = auto_object_path(bus_name, path)
self._at_exit(bus.register_object(path, object, node_info).__exit__)
+ # Request name only after registering all the objects.
+ self._at_exit(bus.request_name(bus_name, allow_replacement=allow_replacement, replace=replace).__exit__)
+
class PublicationMixin(object):
__slots__ = ()
diff --git a/pydbus/registration.py b/pydbus/registration.py
index ccdbc9d..f531539 100644
--- a/pydbus/registration.py
+++ b/pydbus/registration.py
@@ -3,9 +3,17 @@ import sys, traceback
from gi.repository import GLib, Gio
from . import generic
from .exitable import ExitableWithAliases
+from functools import partial
+from .method_call_context import MethodCallContext
+import logging
+
+try:
+ from inspect import signature, Parameter
+except:
+ from ._inspect3 import signature, Parameter
class ObjectWrapper(ExitableWithAliases("unwrap")):
- __slots__ = ["object", "outargs", "property_types"]
+ __slots__ = ["object", "outargs", "readable_properties", "writable_properties"]
def __init__(self, object, interfaces):
self.object = object
@@ -15,10 +23,14 @@ class ObjectWrapper(ExitableWithAliases("unwrap")):
for method in iface.methods:
self.outargs[iface.name + "." + method.name] = [arg.signature for arg in method.out_args]
- self.property_types = {}
+ self.readable_properties = {}
+ self.writable_properties = {}
for iface in interfaces:
for prop in iface.properties:
- self.property_types[iface.name + "." + prop.name] = prop.signature
+ if prop.flags & Gio.DBusPropertyInfoFlags.READABLE:
+ self.readable_properties[iface.name + "." + prop.name] = prop.signature
+ if prop.flags & Gio.DBusPropertyInfoFlags.WRITABLE:
+ self.writable_properties[iface.name + "." + prop.name] = prop.signature
for iface in interfaces:
for signal in iface.signals:
@@ -30,7 +42,7 @@ class ObjectWrapper(ExitableWithAliases("unwrap")):
if "org.freedesktop.DBus.Properties" not in (iface.name for iface in interfaces):
try:
def onPropertiesChanged(iface, changed, invalidated):
- changed = {key: GLib.Variant(self.property_types[iface + "." + key], val) for key, val in changed.items()}
+ changed = {key: GLib.Variant(self.readable_properties[iface + "." + key], val) for key, val in changed.items()}
args = GLib.Variant("(sa{sv}as)", (iface, changed, invalidated))
self.SignalEmitted("org.freedesktop.DBus.Properties", "PropertiesChanged", args)
self._at_exit(object.PropertiesChanged.connect(onPropertiesChanged).__exit__)
@@ -41,67 +53,88 @@ class ObjectWrapper(ExitableWithAliases("unwrap")):
def call_method(self, connection, sender, object_path, interface_name, method_name, parameters, invocation):
try:
- outargs = self.outargs[interface_name + "." + method_name]
- soutargs = "(" + "".join(outargs) + ")"
-
- method = getattr(self.object, method_name)
-
- result = method(*parameters)
-
- #if len(outargs) == 1:
- # result = (result,)
+ try:
+ outargs = self.outargs[interface_name + "." + method_name]
+ method = getattr(self.object, method_name)
+ except KeyError:
+ if interface_name == "org.freedesktop.DBus.Properties":
+ if method_name == "Get":
+ method = self.Get
+ outargs = ["v"]
+ elif method_name == "GetAll":
+ method = self.GetAll
+ outargs = ["a{sv}"]
+ elif method_name == "Set":
+ method = self.Set
+ outargs = []
+ else:
+ raise
+ else:
+ raise
+
+ sig = signature(method)
+
+ kwargs = {}
+ if "dbus_context" in sig.parameters and sig.parameters["dbus_context"].kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY):
+ kwargs["dbus_context"] = MethodCallContext(invocation)
+
+ result = method(*parameters, **kwargs)
if len(outargs) == 0:
invocation.return_value(None)
elif len(outargs) == 1:
- invocation.return_value(GLib.Variant(soutargs, (result,)))
+ invocation.return_value(GLib.Variant("(" + "".join(outargs) + ")", (result,)))
else:
- invocation.return_value(GLib.Variant(soutargs, result))
+ invocation.return_value(GLib.Variant("(" + "".join(outargs) + ")", result))
except Exception as e:
+ logger = logging.getLogger(__name__)
+ logger.exception("Exception while handling %s.%s()", interface_name, method_name)
+
... 808 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pydbus.git
More information about the Python-modules-commits
mailing list