Makes XEP-0009 compatible with Python 3 while maintaining compatibility with Python 2.6 and up.

This commit is contained in:
Cédric Souchon 2015-03-09 12:33:18 +01:00
parent 27582f6fd2
commit 69022c6db7

View file

@ -6,7 +6,7 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
from binding import py2xml, xml2py, xml2fault, fault2xml from sleekxmpp.plugins.xep_0009.binding import py2xml, xml2py, xml2fault, fault2xml
from threading import RLock from threading import RLock
import abc import abc
import inspect import inspect
@ -18,6 +18,45 @@ import traceback
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# Define a function _isstr() to check if an object is a string in a way
# compatible with Python 2 and Python 3 (basestring does not exists in Python 3).
try:
basestring # This evaluation will throw an exception if basestring does not exists (Python 3).
def _isstr(obj):
return isinstance(obj, basestring)
except NameError:
def _isstr(obj):
return isinstance(obj, str)
# Class decorator to declare a metaclass to a class in a way compatible with Python 2 and 3.
# This decorator is copied from 'six' (https://bitbucket.org/gutworth/six):
#
# Copyright (c) 2010-2015 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
def _add_metaclass(metaclass):
def wrapper(cls):
orig_vars = cls.__dict__.copy()
slots = orig_vars.get('__slots__')
if slots is not None:
if isinstance(slots, str):
slots = [slots]
for slots_var in slots:
orig_vars.pop(slots_var)
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper
def _intercept(method, name, public): def _intercept(method, name, public):
def _resolver(instance, *args, **kwargs): def _resolver(instance, *args, **kwargs):
log.debug("Locally calling %s.%s with arguments %s.", instance.FQN(), method.__name__, args) log.debug("Locally calling %s.%s with arguments %s.", instance.FQN(), method.__name__, args)
@ -68,7 +107,7 @@ def remote(function_argument, public = True):
if hasattr(function_argument, '__call__'): if hasattr(function_argument, '__call__'):
return _intercept(function_argument, None, public) return _intercept(function_argument, None, public)
else: else:
if not isinstance(function_argument, basestring): if not _isstr(function_argument):
if not isinstance(function_argument, bool): if not isinstance(function_argument, bool):
raise Exception('Expected an RPC method name or visibility modifier!') raise Exception('Expected an RPC method name or visibility modifier!')
else: else:
@ -222,12 +261,11 @@ class TimeoutException(Exception):
pass pass
@_add_metaclass(abc.ABCMeta)
class Callback(object): class Callback(object):
''' '''
A base class for callback handlers. A base class for callback handlers.
''' '''
__metaclass__ = abc.ABCMeta
@abc.abstractproperty @abc.abstractproperty
def set_value(self, value): def set_value(self, value):
@ -291,7 +329,7 @@ class Future(Callback):
self._event.set() self._event.set()
@_add_metaclass(abc.ABCMeta)
class Endpoint(object): class Endpoint(object):
''' '''
The Endpoint class is an abstract base class for all objects The Endpoint class is an abstract base class for all objects
@ -303,8 +341,6 @@ class Endpoint(object):
which specifies which object an RPC call refers to. It is the which specifies which object an RPC call refers to. It is the
first part in a RPC method name '<fqn>.<method>'. first part in a RPC method name '<fqn>.<method>'.
''' '''
__metaclass__ = abc.ABCMeta
def __init__(self, session, target_jid): def __init__(self, session, target_jid):
''' '''
@ -491,7 +527,7 @@ class RemoteSession(object):
def _find_key(self, dict, value): def _find_key(self, dict, value):
"""return the key of dictionary dic given the value""" """return the key of dictionary dic given the value"""
search = [k for k, v in dict.iteritems() if v == value] search = [k for k, v in dict.items() if v == value]
if len(search) == 0: if len(search) == 0:
return None return None
else: else:
@ -547,7 +583,7 @@ class RemoteSession(object):
result = handler_cls(*args, **kwargs) result = handler_cls(*args, **kwargs)
Endpoint.__init__(result, self, self._client.boundjid.full) Endpoint.__init__(result, self, self._client.boundjid.full)
method_dict = result.get_methods() method_dict = result.get_methods()
for method_name, method in method_dict.iteritems(): for method_name, method in method_dict.items():
#!!! self._client.plugin['xep_0009'].register_call(result.FQN(), method, method_name) #!!! self._client.plugin['xep_0009'].register_call(result.FQN(), method, method_name)
self._register_call(result.FQN(), method, method_name) self._register_call(result.FQN(), method, method_name)
self._register_acl(result.FQN(), acl) self._register_acl(result.FQN(), acl)