Browse files

Now depends on importlib+ordereddict if used with Python < 2.7, and s…

…implejson if < 2.6
  • Loading branch information...
1 parent 8fe0fef commit 2767ebe8514a004b0361318039a2eb4cc781fcb4 @ask ask committed Sep 12, 2012
View
11 kombu/tests/transport/test_transport.py
@@ -10,14 +10,11 @@
class test_transport(TestCase):
- def test_resolve_transport__no_class_name(self):
- with self.assertRaises(KeyError):
- transport.resolve_transport('nonexistant')
-
def test_resolve_transport_when_callable(self):
- self.assertTupleEqual(transport.resolve_transport(
- lambda: 'kombu.transport.memory.Transport'),
- ('kombu.transport.memory', 'Transport'))
+ from kombu.transport.memory import Transport
+ self.assertIs(transport.resolve_transport(
+ 'kombu.transport.memory:Transport'),
+ Transport)
class test_transport_gettoq(TestCase):
View
30 kombu/transport/__init__.py
@@ -10,9 +10,8 @@
"""
from __future__ import absolute_import
-import sys
-
from kombu.syn import _detect_environment
+from kombu.utils import symbol_by_name
def supports_librabbitmq():
@@ -77,20 +76,17 @@ def __inner():
def resolve_transport(transport=None):
- transport = TRANSPORT_ALIASES.get(transport, transport)
- if callable(transport):
- transport = transport()
- transport_module_name, _, transport_cls_name = transport.rpartition('.')
- if not transport_module_name:
- raise KeyError('No such transport: %s' % (transport, ))
- return transport_module_name, transport_cls_name
-
-
-def _get_transport_cls(transport=None):
- transport_module_name, transport_cls_name = resolve_transport(transport)
- __import__(transport_module_name)
- transport_module = sys.modules[transport_module_name]
- return getattr(transport_module, transport_cls_name)
+ if isinstance(transport, basestring):
+ try:
+ transport = TRANSPORT_ALIASES[transport]
+ except KeyError:
+ if '.' not in transport and ':' not in transport:
+ raise KeyError('No such transport: %s' % transport)
+ else:
+ if callable(transport):
+ transport = transport()
+ return symbol_by_name(transport)
+ return transport
def get_transport_cls(transport=None):
@@ -105,5 +101,5 @@ def get_transport_cls(transport=None):
"""
if transport not in _transport_cache:
- _transport_cache[transport] = _get_transport_cls(transport)
+ _transport_cache[transport] = resolve_transport(transport)
return _transport_cache[transport]
View
60 kombu/utils/__init__.py
@@ -10,6 +10,7 @@
"""
from __future__ import absolute_import
+import importlib
import random
import sys
@@ -31,6 +32,65 @@
'reprkwargs', 'reprcall', 'nested']
+def symbol_by_name(name, aliases={}, imp=None, package=None,
+ sep='.', default=None, **kwargs):
+ """Get symbol by qualified name.
+
+ The name should be the full dot-separated path to the class::
+
+ modulename.ClassName
+
+ Example::
+
+ celery.concurrency.processes.TaskPool
+ ^- class name
+
+ or using ':' to separate module and symbol::
+
+ celery.concurrency.processes:TaskPool
+
+ If `aliases` is provided, a dict containing short name/long name
+ mappings, the name is looked up in the aliases first.
+
+ Examples:
+
+ >>> symbol_by_name('celery.concurrency.processes.TaskPool')
+ <class 'celery.concurrency.processes.TaskPool'>
+
+ >>> symbol_by_name('default', {
+ ... 'default': 'celery.concurrency.processes.TaskPool'})
+ <class 'celery.concurrency.processes.TaskPool'>
+
+ # Does not try to look up non-string names.
+ >>> from celery.concurrency.processes import TaskPool
+ >>> symbol_by_name(TaskPool) is TaskPool
+ True
+
+ """
+ if imp is None:
+ imp = importlib.import_module
+
+ if not isinstance(name, basestring):
+ return name # already a class
+
+ name = aliases.get(name) or name
+ sep = ':' if ':' in name else sep
+ module_name, _, cls_name = name.rpartition(sep)
+ if not module_name:
+ cls_name, module_name = None, package if package else cls_name
+ try:
+ try:
+ module = imp(module_name, package=package, **kwargs)
+ except ValueError, exc:
+ raise ValueError, ValueError(
+ "Couldn't import %r: %s" % (name, exc)), sys.exc_info()[2]
+ return getattr(module, cls_name) if cls_name else module
+ except (ImportError, AttributeError):
+ if default is None:
+ raise
+ return default
+
+
def eqhash(o):
try:
return o.__eqhash__()
View
219 kombu/utils/compat.py
@@ -8,7 +8,6 @@
:license: BSD, see LICENSE for more details.
"""
-import sys
############## __builtins__.next #############################################
try:
@@ -23,226 +22,10 @@ def next(it, *args): # noqa
return args[0]
############## collections.OrderedDict #######################################
-
-import weakref
-try:
- from collections import MutableMapping
-except ImportError:
- from UserDict import DictMixin as MutableMapping # noqa
-from itertools import imap as _imap
-from operator import eq as _eq
-
-
-class _Link(object):
- """Doubly linked list."""
- __slots__ = 'prev', 'next', 'key', '__weakref__'
-
-
-class CompatOrderedDict(dict, MutableMapping):
- """Dictionary that remembers insertion order"""
- # An inherited dict maps keys to values.
- # The inherited dict provides __getitem__, __len__, __contains__, and get.
- # The remaining methods are order-aware.
- # Big-O running times for all methods are the same as for regular
- # dictionaries.
-
- # The internal self.__map dictionary maps keys to links in a doubly
- # linked list.
- # The circular doubly linked list starts and ends with a sentinel element.
- # The sentinel element never gets deleted (this simplifies the algorithm).
- # The prev/next links are weakref proxies (to prevent circular
- # references).
- # Individual links are kept alive by the hard reference in self.__map.
- # Those hard references disappear when a key is deleted from
- # an OrderedDict.
-
- __marker = object()
-
- def __init__(self, *args, **kwds):
- """Initialize an ordered dictionary.
-
- Signature is the same as for regular dictionaries, but keyword
- arguments are not recommended because their insertion order is
- arbitrary.
-
- """
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % (
- len(args)))
- try:
- self.__root
- except AttributeError:
- # sentinel node for the doubly linked list
- self.__root = root = _Link()
- root.prev = root.next = root
- self.__map = {}
- self.update(*args, **kwds)
-
- def clear(self):
- "od.clear() -> None. Remove all items from od."
- root = self.__root
- root.prev = root.next = root
- self.__map.clear()
- dict.clear(self)
-
- def __setitem__(self, key, value):
- "od.__setitem__(i, y) <==> od[i]=y"
- # Setting a new item creates a new link which goes at the end of the
- # linked list, and the inherited dictionary is updated with the new
- # key/value pair.
- if key not in self:
- self.__map[key] = link = _Link()
- root = self.__root
- last = root.prev
- link.prev, link.next, link.key = last, root, key
- last.next = root.prev = weakref.proxy(link)
- dict.__setitem__(self, key, value)
-
- def __delitem__(self, key):
- """od.__delitem__(y) <==> del od[y]"""
- # Deleting an existing item uses self.__map to find the
- # link which is then removed by updating the links in the
- # predecessor and successor nodes.
- dict.__delitem__(self, key)
- link = self.__map.pop(key)
- link.prev.next = link.next
- link.next.prev = link.prev
-
- def __iter__(self):
- """od.__iter__() <==> iter(od)"""
- # Traverse the linked list in order.
- root = self.__root
- curr = root.next
- while curr is not root:
- yield curr.key
- curr = curr.next
-
- def __reversed__(self):
- """od.__reversed__() <==> reversed(od)"""
- # Traverse the linked list in reverse order.
- root = self.__root
- curr = root.prev
- while curr is not root:
- yield curr.key
- curr = curr.prev
-
- def __reduce__(self):
- """Return state information for pickling"""
- items = [[k, self[k]] for k in self]
- tmp = self.__map, self.__root
- del(self.__map, self.__root)
- inst_dict = vars(self).copy()
- self.__map, self.__root = tmp
- if inst_dict:
- return (self.__class__, (items,), inst_dict)
- return self.__class__, (items,)
-
- def setdefault(self, key, default=None):
- try:
- return self[key]
- except KeyError:
- self[key] = default
- return default
-
- def update(self, other=(), **kwds):
- if isinstance(other, dict):
- for key in other:
- self[key] = other[key]
- elif hasattr(other, 'keys'):
- for key in other.keys():
- self[key] = other[key]
- else:
- for key, value in other:
- self[key] = value
- for key, value in kwds.items():
- self[key] = value
-
- def pop(self, key, default=__marker):
- try:
- value = self[key]
- except KeyError:
- if default is self.__marker:
- raise
- return default
- else:
- del self[key]
- return value
-
- def values(self):
- return [self[key] for key in self]
-
- def items(self):
- return [(key, self[key]) for key in self]
-
- def itervalues(self):
- for key in self:
- yield self[key]
-
- def iteritems(self):
- for key in self:
- yield (key, self[key])
-
- def iterkeys(self):
- return iter(self)
-
- def keys(self):
- return list(self)
-
- def popitem(self, last=True):
- """od.popitem() -> (k, v)
-
- Return and remove a (key, value) pair.
- Pairs are returned in LIFO order if last is true or FIFO
- order if false.
-
- """
- if not self:
- raise KeyError('dictionary is empty')
- if last:
- if sys.platform.startswith('java'):
- key = self.keys()[-1]
- else:
- key = reversed(self).next()
- else:
- key = iter(self).next()
- value = self.pop(key)
- return key, value
-
- def __repr__(self):
- "od.__repr__() <==> repr(od)"
- if not self:
- return '%s()' % (self.__class__.__name__,)
- return '%s(%r)' % (self.__class__.__name__, self.items())
-
- def copy(self):
- "od.copy() -> a shallow copy of od"
- return self.__class__(self)
-
- @classmethod
- def fromkeys(cls, iterable, value=None):
- """OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
- and values equal to v (which defaults to None)."""
- d = cls()
- for key in iterable:
- d[key] = value
- return d
-
- def __eq__(self, other):
- """od.__eq__(y) <==> od==y. Comparison to another OD is
- order-sensitive while comparison to a regular mapping
- is order-insensitive."""
- if isinstance(other, OrderedDict):
- return len(self) == len(other) and \
- all(_imap(_eq, self.iteritems(), other.iteritems()))
- return dict.__eq__(self, other)
-
- def __ne__(self, other):
- return not (self == other)
-
try:
from collections import OrderedDict
except ImportError:
- OrderedDict = CompatOrderedDict # noqa
+ from ordereddict import OrderedDict # noqa
############## queue.LifoQueue ##############################################
from Queue import Queue
View
3 requirements/py25.txt
@@ -0,0 +1,3 @@
+importlib
+ordereddict
+simplejson
View
2 requirements/py26.txt
@@ -0,0 +1,2 @@
+importlib
+ordereddict
View
1 requirements/test-py25.txt
@@ -1 +0,0 @@
-simplejson
View
7 setup.py
@@ -111,6 +111,10 @@ def reqs(f):
os.path.join(os.getcwd(), 'requirements', f)).readlines()])
install_requires = reqs('default.txt')
+if py_version[0:2] == (2, 6):
+ install_requires.extend(reqs('py26.txt'))
+elif py_version[0:2] == (2, 5):
+ install_requires.extend(reqs('py25.txt'))
# -*- Tests Requires -*-
@@ -119,9 +123,6 @@ def reqs(f):
else:
tests_require = reqs('test.txt')
-if py_version[0:2] == (2, 5):
- tests_require.extend('test-py25.txt')
-
setup(
name='kombu',
version=meta['VERSION'],
View
4 tox.ini
@@ -51,6 +51,7 @@ commands = {toxinidir}/extra/release/removepyc.sh {toxinidir}
[testenv:py26]
basepython = python2.6
deps = -r{toxinidir}/requirements/default.txt
+ -r{toxinidir}/requirements/py26.txt
-r{toxinidir}/requirements/test.txt
-r{toxinidir}/requirements/test-ci.txt
commands = {toxinidir}/extra/release/removepyc.sh {toxinidir}
@@ -63,8 +64,8 @@ commands = {toxinidir}/extra/release/removepyc.sh {toxinidir}
[testenv:py25]
basepython = python2.5
deps = -r{toxinidir}/requirements/default.txt
+ -r{toxinidir}/requirements/py25.txt
-r{toxinidir}/requirements/test.txt
- -r{toxinidir}/requirements/test-py25.txt
-r{toxinidir}/requirements/test-ci.txt
commands = {toxinidir}/extra/release/removepyc.sh {toxinidir}
nosetests --with-xunit \
@@ -91,7 +92,6 @@ recreate = True
where = .tox
deps = -r{toxinidir}/requirements/default.txt
-r{toxinidir}/requirements/test.txt
- -r{toxinidir}/requirements/test-py25.txt
-r{toxinidir}/requirements/test-ci.txt
commands = {toxinidir}/extra/release/removepyc.sh {toxinidir}
{toxinidir}/extra/release/jython-run-tests {toxinidir}

0 comments on commit 2767ebe

Please sign in to comment.