summaryrefslogtreecommitdiff
path: root/dbus
diff options
context:
space:
mode:
authorBarry Warsaw <barry@python.org>2011-12-15 06:57:21 -0500
committerBarry Warsaw <barry@python.org>2011-12-15 06:57:21 -0500
commit4c1c2eade1c5b383adad94a7a4fd6553873fecf0 (patch)
treeb9e0f45fc19539bcaddff69e661bf0c5d21bab5a /dbus
parent667082d0b4aef9c438a2e7fec89614b5b8ef960a (diff)
downloaddbus-python-4c1c2eade1c5b383adad94a7a4fd6553873fecf0.tar.gz
This is the big one; it adds Python 3 support.
Diffstat (limited to 'dbus')
-rw-r--r--dbus/__init__.py19
-rw-r--r--dbus/_compat.py8
-rw-r--r--dbus/_dbus.py11
-rw-r--r--dbus/_expat_introspect_parser.py2
-rw-r--r--dbus/bus.py23
-rw-r--r--dbus/connection.py79
-rw-r--r--dbus/decorators.py19
-rw-r--r--dbus/proxies.py12
-rw-r--r--dbus/service.py25
-rw-r--r--dbus/types.py6
10 files changed, 138 insertions, 66 deletions
diff --git a/dbus/__init__.py b/dbus/__init__.py
index 803ed2a..eb9717a 100644
--- a/dbus/__init__.py
+++ b/dbus/__init__.py
@@ -34,9 +34,7 @@ to export objects or claim well-known names.
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
-import os
-
-__all__ = (
+__all__ = [
# from _dbus
'Bus', 'SystemBus', 'SessionBus', 'StarterBus',
@@ -56,7 +54,7 @@ __all__ = (
'ObjectPath', 'ByteArray', 'Signature', 'Byte', 'Boolean',
'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64',
- 'Double', 'String', 'Array', 'Struct', 'Dictionary', 'UTF8String',
+ 'Double', 'String', 'Array', 'Struct', 'Dictionary',
# from exceptions
'DBusException',
@@ -66,7 +64,12 @@ __all__ = (
# submodules
'service', 'mainloop', 'lowlevel'
- )
+ ]
+
+from dbus._compat import is_py2
+if is_py2:
+ __all__.append('UTF8String')
+
__docformat__ = 'restructuredtext'
try:
@@ -92,6 +95,10 @@ from dbus.exceptions import (
ValidationException)
from _dbus_bindings import (
Array, Boolean, Byte, ByteArray, Dictionary, Double, Int16, Int32, Int64,
- ObjectPath, Signature, String, Struct, UInt16, UInt32, UInt64, UTF8String)
+ ObjectPath, Signature, String, Struct, UInt16, UInt32, UInt64)
+
+if is_py2:
+ from _dbus_bindings import UTF8String
+
from dbus._dbus import Bus, SystemBus, SessionBus, StarterBus
from dbus.proxies import Interface
diff --git a/dbus/_compat.py b/dbus/_compat.py
new file mode 100644
index 0000000..45a0c97
--- /dev/null
+++ b/dbus/_compat.py
@@ -0,0 +1,8 @@
+# Python 2 / Python 3 compatibility helpers.
+
+import sys
+
+# In Python 2.6, sys.version_info is not a namedtuple, so we can't use
+# sys.version_info.major.
+is_py3 = (sys.version_info[0] == 3)
+is_py2 = not is_py3
diff --git a/dbus/_dbus.py b/dbus/_dbus.py
index 808d44b..5a497f4 100644
--- a/dbus/_dbus.py
+++ b/dbus/_dbus.py
@@ -30,19 +30,18 @@ from __future__ import generators
__all__ = ('Bus', 'SystemBus', 'SessionBus', 'StarterBus')
__docformat__ = 'reStructuredText'
-import os
-import sys
-import weakref
-from traceback import print_exc
-
from dbus.exceptions import DBusException
from _dbus_bindings import (
BUS_DAEMON_IFACE, BUS_DAEMON_NAME, BUS_DAEMON_PATH, BUS_SESSION,
BUS_STARTER, BUS_SYSTEM, DBUS_START_REPLY_ALREADY_RUNNING,
- DBUS_START_REPLY_SUCCESS, UTF8String, validate_bus_name,
+ DBUS_START_REPLY_SUCCESS, validate_bus_name,
validate_interface_name, validate_member_name, validate_object_path)
from dbus.bus import BusConnection
from dbus.lowlevel import SignalMessage
+from dbus._compat import is_py2
+
+if is_py2:
+ from _dbus_bindings import UTF8String
class Bus(BusConnection):
diff --git a/dbus/_expat_introspect_parser.py b/dbus/_expat_introspect_parser.py
index de38c45..1cf8a6c 100644
--- a/dbus/_expat_introspect_parser.py
+++ b/dbus/_expat_introspect_parser.py
@@ -23,7 +23,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
-from xml.parsers.expat import ExpatError, ParserCreate
+from xml.parsers.expat import ParserCreate
from dbus.exceptions import IntrospectionParserException
class _Parser(object):
diff --git a/dbus/bus.py b/dbus/bus.py
index 9f77717..109f4c6 100644
--- a/dbus/bus.py
+++ b/dbus/bus.py
@@ -39,6 +39,7 @@ from _dbus_bindings import (
from dbus.connection import Connection
from dbus.exceptions import DBusException
from dbus.lowlevel import HANDLER_RESULT_NOT_YET_HANDLED
+from dbus._compat import is_py2
_NAME_OWNER_CHANGE_MATCH = ("type='signal',sender='%s',"
@@ -77,13 +78,16 @@ class NameOwnerWatch(object):
BUS_DAEMON_NAME,
BUS_DAEMON_PATH,
arg0=bus_name)
+ keywords = {}
+ if is_py2:
+ keywords['utf8_strings'] = True
self._pending_call = bus_conn.call_async(BUS_DAEMON_NAME,
BUS_DAEMON_PATH,
BUS_DAEMON_IFACE,
'GetNameOwner',
's', (bus_name,),
callback, error_cb,
- utf8_strings=True)
+ **keywords)
def cancel(self):
if self._match is not None:
@@ -230,7 +234,7 @@ class BusConnection(Connection):
bus_name = named_service
if kwargs:
raise TypeError('get_object does not take these keyword '
- 'arguments: %s' % ', '.join(kwargs.iterkeys()))
+ 'arguments: %s' % ', '.join(kwargs.keys()))
return self.ProxyObjectClass(self, bus_name, object_path,
introspect=introspect,
@@ -321,9 +325,12 @@ class BusConnection(Connection):
:Returns: a dbus.Array of dbus.UTF8String
:Since: 0.81.0
"""
+ keywords = {}
+ if is_py2:
+ keywords['utf8_strings'] = True
return self.call_blocking(BUS_DAEMON_NAME, BUS_DAEMON_PATH,
BUS_DAEMON_IFACE, 'ListNames',
- '', (), utf8_strings=True)
+ '', (), **keywords)
def list_activatable_names(self):
"""Return a list of all names that can be activated on the bus.
@@ -331,9 +338,12 @@ class BusConnection(Connection):
:Returns: a dbus.Array of dbus.UTF8String
:Since: 0.81.0
"""
+ keywords = {}
+ if is_py2:
+ keywords['utf8_strings'] = True
return self.call_blocking(BUS_DAEMON_NAME, BUS_DAEMON_PATH,
BUS_DAEMON_IFACE, 'ListActivatableNames',
- '', (), utf8_strings=True)
+ '', (), **keywords)
def get_name_owner(self, bus_name):
"""Return the unique connection name of the primary owner of the
@@ -342,10 +352,13 @@ class BusConnection(Connection):
:Raises `DBusException`: if the `bus_name` has no owner
:Since: 0.81.0
"""
+ keywords = {}
+ if is_py2:
+ keywords['utf8_strings'] = True
validate_bus_name(bus_name, allow_unique=False)
return self.call_blocking(BUS_DAEMON_NAME, BUS_DAEMON_PATH,
BUS_DAEMON_IFACE, 'GetNameOwner',
- 's', (bus_name,), utf8_strings=True)
+ 's', (bus_name,), **keywords)
def watch_name_owner(self, bus_name, callback):
"""Watch the unique connection name of the primary owner of the
diff --git a/dbus/connection.py b/dbus/connection.py
index 1215519..f4124bd 100644
--- a/dbus/connection.py
+++ b/dbus/connection.py
@@ -28,7 +28,7 @@ import threading
import weakref
from _dbus_bindings import (
- Connection as _Connection, LOCAL_IFACE, LOCAL_PATH, UTF8String,
+ Connection as _Connection, LOCAL_IFACE, LOCAL_PATH,
validate_bus_name, validate_error_name, validate_interface_name,
validate_member_name, validate_object_path)
from dbus.exceptions import DBusException
@@ -36,6 +36,10 @@ from dbus.lowlevel import (
ErrorMessage, HANDLER_RESULT_NOT_YET_HANDLED, MethodCallMessage,
MethodReturnMessage, SignalMessage)
from dbus.proxies import ProxyObject
+from dbus._compat import is_py2
+
+if is_py2:
+ from _dbus_bindings import UTF8String
_logger = logging.getLogger('dbus.connection')
@@ -46,15 +50,19 @@ def _noop(*args, **kwargs):
class SignalMatch(object):
- __slots__ = ('_sender_name_owner', '_member', '_interface', '_sender',
- '_path', '_handler', '_args_match', '_rule',
- '_utf8_strings', '_byte_arrays', '_conn_weakref',
- '_destination_keyword', '_interface_keyword',
- '_message_keyword', '_member_keyword',
- '_sender_keyword', '_path_keyword', '_int_args_match')
+ _slots = ['_sender_name_owner', '_member', '_interface', '_sender',
+ '_path', '_handler', '_args_match', '_rule',
+ '_byte_arrays', '_conn_weakref',
+ '_destination_keyword', '_interface_keyword',
+ '_message_keyword', '_member_keyword',
+ '_sender_keyword', '_path_keyword', '_int_args_match']
+ if is_py2:
+ _slots.append('_utf8_strings')
+
+ __slots__ = tuple(_slots)
def __init__(self, conn, sender, object_path, dbus_interface,
- member, handler, utf8_strings=False, byte_arrays=False,
+ member, handler, byte_arrays=False,
sender_keyword=None, path_keyword=None,
interface_keyword=None, member_keyword=None,
message_keyword=None, destination_keyword=None,
@@ -80,7 +88,11 @@ class SignalMatch(object):
# this later
self._sender_name_owner = sender
- self._utf8_strings = utf8_strings
+ if is_py2:
+ self._utf8_strings = kwargs.pop('utf8_strings', False)
+ elif 'utf8_strings' in kwargs:
+ raise TypeError("unexpected keyword argument 'utf8_strings'")
+
self._byte_arrays = byte_arrays
self._sender_keyword = sender_keyword
self._path_keyword = path_keyword
@@ -134,7 +146,7 @@ class SignalMatch(object):
if self._member is not None:
rule.append("member='%s'" % self._member)
if self._int_args_match is not None:
- for index, value in self._int_args_match.iteritems():
+ for index, value in self._int_args_match.items():
rule.append("arg%d='%s'" % (index, value))
self._rule = ','.join(rule)
@@ -172,10 +184,15 @@ class SignalMatch(object):
return False
if self._int_args_match is not None:
# extracting args with utf8_strings and byte_arrays is less work
- args = message.get_args_list(utf8_strings=True, byte_arrays=True)
- for index, value in self._int_args_match.iteritems():
+ kwargs = dict(byte_arrays=True)
+ if is_py2:
+ kwargs['utf8_strings'] = True
+ args = message.get_args_list(**kwargs)
+ for index, value in self._int_args_match.items():
if (index >= len(args)
- or not isinstance(args[index], UTF8String)
+ or (not isinstance(args[index], UTF8String)
+ if is_py2
+ else False)
or args[index] != value):
return False
@@ -191,9 +208,12 @@ class SignalMatch(object):
# minor optimization: if we already extracted the args with the
# right calling convention to do the args match, don't bother
# doing so again
- if args is None or not self._utf8_strings or not self._byte_arrays:
- args = message.get_args_list(utf8_strings=self._utf8_strings,
- byte_arrays=self._byte_arrays)
+ utf8_strings = (is_py2 and self._utf8_strings)
+ if args is None or not utf8_strings or not self._byte_arrays:
+ kwargs = dict(byte_arrays=self._byte_arrays)
+ if is_py2:
+ kwargs['utf8_strings'] = self._utf8_strings
+ args = message.get_args_list(**kwargs)
kwargs = {}
if self._sender_keyword is not None:
kwargs[self._sender_keyword] = message.get_sender()
@@ -301,7 +321,7 @@ class Connection(_Connection):
bus_name = named_service
if kwargs:
raise TypeError('get_object does not take these keyword '
- 'arguments: %s' % ', '.join(kwargs.iterkeys()))
+ 'arguments: %s' % ', '.join(kwargs.keys()))
return self.ProxyObjectClass(self, bus_name, object_path,
introspect=introspect)
@@ -421,8 +441,7 @@ class Connection(_Connection):
member_keys = (None,)
for path in path_keys:
- by_interface = self._signal_recipients_by_object_path.get(path,
- None)
+ by_interface = self._signal_recipients_by_object_path.get(path)
if by_interface is None:
continue
for dbus_interface in interface_keys:
@@ -531,8 +550,8 @@ class Connection(_Connection):
def call_async(self, bus_name, object_path, dbus_interface, method,
signature, args, reply_handler, error_handler,
- timeout=-1.0, utf8_strings=False, byte_arrays=False,
- require_main_loop=True):
+ timeout=-1.0, byte_arrays=False,
+ require_main_loop=True, **kwargs):
"""Call the given method, asynchronously.
If the reply_handler is None, successful replies will be ignored.
@@ -550,8 +569,11 @@ class Connection(_Connection):
'interface %s' % LOCAL_IFACE)
# no need to validate other args - MethodCallMessage ctor will do
- get_args_opts = {'utf8_strings': utf8_strings,
- 'byte_arrays': byte_arrays}
+ get_args_opts = dict(byte_arrays=byte_arrays)
+ if is_py2:
+ get_args_opts['utf8_strings'] = kwargs.get('utf8_strings', False)
+ elif 'utf8_strings' in kwargs:
+ raise TypeError("unexpected keyword argument 'utf8_strings'")
message = MethodCallMessage(destination=bus_name,
path=object_path,
@@ -591,8 +613,8 @@ class Connection(_Connection):
require_main_loop=require_main_loop)
def call_blocking(self, bus_name, object_path, dbus_interface, method,
- signature, args, timeout=-1.0, utf8_strings=False,
- byte_arrays=False):
+ signature, args, timeout=-1.0,
+ byte_arrays=False, **kwargs):
"""Call the given method, synchronously.
:Since: 0.81.0
"""
@@ -604,8 +626,11 @@ class Connection(_Connection):
'interface %s' % LOCAL_IFACE)
# no need to validate other args - MethodCallMessage ctor will do
- get_args_opts = {'utf8_strings': utf8_strings,
- 'byte_arrays': byte_arrays}
+ get_args_opts = dict(byte_arrays=byte_arrays)
+ if is_py2:
+ get_args_opts['utf8_strings'] = kwargs.get('utf8_strings', False)
+ elif 'utf8_strings' in kwargs:
+ raise TypeError("unexpected keyword argument 'utf8_strings'")
message = MethodCallMessage(destination=bus_name,
path=object_path,
diff --git a/dbus/decorators.py b/dbus/decorators.py
index 71a7203..b164582 100644
--- a/dbus/decorators.py
+++ b/dbus/decorators.py
@@ -33,14 +33,15 @@ import inspect
from dbus import validate_interface_name, Signature, validate_member_name
from dbus.lowlevel import SignalMessage
from dbus.exceptions import DBusException
+from dbus._compat import is_py2
def method(dbus_interface, in_signature=None, out_signature=None,
- async_callbacks=None,
- sender_keyword=None, path_keyword=None, destination_keyword=None,
- message_keyword=None, connection_keyword=None,
- utf8_strings=False, byte_arrays=False,
- rel_path_keyword=None):
+ async_callbacks=None,
+ sender_keyword=None, path_keyword=None, destination_keyword=None,
+ message_keyword=None, connection_keyword=None,
+ byte_arrays=False,
+ rel_path_keyword=None, **kwargs):
"""Factory for decorators used to mark methods of a `dbus.service.Object`
to be exported on the D-Bus.
@@ -198,8 +199,12 @@ def method(dbus_interface, in_signature=None, out_signature=None,
func._dbus_message_keyword = message_keyword
func._dbus_connection_keyword = connection_keyword
func._dbus_args = args
- func._dbus_get_args_options = {'byte_arrays': byte_arrays,
- 'utf8_strings': utf8_strings}
+ func._dbus_get_args_options = dict(byte_arrays=byte_arrays)
+ if is_py2:
+ func._dbus_get_args_options['utf8_strings'] = kwargs.get(
+ 'utf8_strings', False)
+ elif 'utf8_strings' in kwargs:
+ raise TypeError("unexpected keyword argument 'utf8_strings'")
return func
return decorator
diff --git a/dbus/proxies.py b/dbus/proxies.py
index f9b2e4e..c7cd802 100644
--- a/dbus/proxies.py
+++ b/dbus/proxies.py
@@ -23,7 +23,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
-import sys
import logging
try:
@@ -45,6 +44,7 @@ _logger = logging.getLogger('dbus.proxies')
from _dbus_bindings import (
BUS_DAEMON_IFACE, BUS_DAEMON_NAME, BUS_DAEMON_PATH, INTROSPECTABLE_IFACE,
LOCAL_PATH)
+from dbus._compat import is_py2
class _DeferredMethod:
@@ -59,7 +59,7 @@ class _DeferredMethod:
self._block = block
def __call__(self, *args, **keywords):
- if (keywords.has_key('reply_handler') or
+ if ('reply_handler' in keywords or
keywords.get('ignore_reply', False)):
# defer the async call til introspection finishes
self._append(self._proxy_method, args, keywords)
@@ -226,7 +226,7 @@ class ProxyObject(object):
if kwargs:
raise TypeError('ProxyObject.__init__ does not take these '
'keyword arguments: %s'
- % ', '.join(kwargs.iterkeys()))
+ % ', '.join(kwargs.keys()))
if follow_name_owner_changes:
# we don't get the signals unless the Bus has a main loop
@@ -369,13 +369,15 @@ class ProxyObject(object):
**keywords)
def _Introspect(self):
+ kwargs = {}
+ if is_py2:
+ kwargs['utf8_strings'] = True
return self._bus.call_async(self._named_service,
self.__dbus_object_path__,
INTROSPECTABLE_IFACE, 'Introspect', '', (),
self._introspect_reply_handler,
self._introspect_error_handler,
- utf8_strings=True,
- require_main_loop=False)
+ require_main_loop=False, **kwargs)
def _introspect_execute_queue(self):
# FIXME: potential to flood the bus
diff --git a/dbus/service.py b/dbus/service.py
index bc7fe09..b1fc21d 100644
--- a/dbus/service.py
+++ b/dbus/service.py
@@ -28,9 +28,9 @@ __docformat__ = 'restructuredtext'
import sys
import logging
-import operator
import threading
import traceback
+from collections import Sequence
import _dbus_bindings
from dbus import (
@@ -41,6 +41,7 @@ from dbus.exceptions import (
DBusException, NameExistsException, UnknownMethodException)
from dbus.lowlevel import ErrorMessage, MethodReturnMessage, MethodCallMessage
from dbus.proxies import LOCAL_PATH
+from dbus._compat import is_py2
_logger = logging.getLogger('dbus.service')
@@ -56,10 +57,14 @@ class _VariantSignature(object):
"""Return self."""
return self
- def next(self):
+ def __next__(self):
"""Return 'v' whenever called."""
return 'v'
+ if is_py2:
+ next = __next__
+
+
class BusName(object):
"""A base class for exporting your own Named Services across the Bus.
@@ -305,7 +310,7 @@ class InterfaceType(type):
for b in bases:
base_name = b.__module__ + '.' + b.__name__
if getattr(b, '_dbus_class_table', False):
- for (interface, method_table) in class_table[base_name].iteritems():
+ for (interface, method_table) in class_table[base_name].items():
our_method_table = interface_table.setdefault(interface, {})
our_method_table.update(method_table)
@@ -365,8 +370,11 @@ class InterfaceType(type):
return reflection_data
-class Interface(object):
- __metaclass__ = InterfaceType
+
+# Define Interface as an instance of the metaclass InterfaceType, in a way
+# that is compatible across both Python 2 and Python 3.
+Interface = InterfaceType('Interface', (object,), {})
+
#: A unique object used as the value of Object._object_path and
#: Object._connection if it's actually in more than one place
@@ -719,8 +727,9 @@ class Object(Interface):
elif len(signature_tuple) == 1:
retval = (retval,)
else:
- if operator.isSequenceType(retval):
- # multi-value signature, multi-value return... proceed unchanged
+ if isinstance(retval, Sequence):
+ # multi-value signature, multi-value return... proceed
+ # unchanged
pass
else:
raise TypeError('%s has multiple output values in signature %s but did not return a sequence' %
@@ -754,7 +763,7 @@ class Object(Interface):
reflection_data += '<node name="%s">\n' % object_path
interfaces = self._dbus_class_table[self.__class__.__module__ + '.' + self.__class__.__name__]
- for (name, funcs) in interfaces.iteritems():
+ for (name, funcs) in interfaces.items():
reflection_data += ' <interface name="%s">\n' % (name)
for func in funcs.values():
diff --git a/dbus/types.py b/dbus/types.py
index 3623437..a134495 100644
--- a/dbus/types.py
+++ b/dbus/types.py
@@ -5,5 +5,9 @@ __all__ = ('ObjectPath', 'ByteArray', 'Signature', 'Byte', 'Boolean',
from _dbus_bindings import (
Array, Boolean, Byte, ByteArray, Dictionary, Double, Int16, Int32, Int64,
- ObjectPath, Signature, String, Struct, UInt16, UInt32, UInt64, UTF8String,
+ ObjectPath, Signature, String, Struct, UInt16, UInt32, UInt64,
UnixFd)
+
+from dbus._compat import is_py2
+if is_py2:
+ from _dbus_bindings import UTF8String