diff options
author | Anselm Kruis <a.kruis@science-computing.de> | 2014-05-27 22:17:16 +0200 |
---|---|---|
committer | Anselm Kruis <a.kruis@science-computing.de> | 2014-05-27 22:17:16 +0200 |
commit | c8c2e281b6618c5f219a2a8bcda65635ad558e2a (patch) | |
tree | 859b4fd252bcc8d683d296c6a5d39bf976532f68 | |
parent | de1f05da84175a19ca999bec05d33b0c7039e5a2 (diff) | |
parent | af207053a3474247f47459263486b5fcc9ff8975 (diff) | |
download | six-git-c8c2e281b6618c5f219a2a8bcda65635ad558e2a.tar.gz |
Merge heads.
-rw-r--r-- | CHANGES | 16 | ||||
-rw-r--r-- | CONTRIBUTORS | 6 | ||||
-rw-r--r-- | documentation/index.rst | 13 | ||||
-rw-r--r-- | six.py | 79 | ||||
-rw-r--r-- | test_six.py | 34 | ||||
-rw-r--r-- | tox.ini | 4 |
6 files changed, 123 insertions, 29 deletions
@@ -3,6 +3,22 @@ Changelog for six This file lists the changes in each six version. +Development version +------------------- + +- Pull request #32: Add six.wraps, which is like functools.wraps but always sets + the __wrapped__ attribute. + +- Pull request #35: Improve add_metaclass, so that it doesn't end up inserting + another class into the hierarchy. + +- Pull request #34: Add import mappings for dummy_thread. + +- Pull request #33: Add import mappings for UserDict and UserList. + +- Pull request #31: Select the implementations of dictionary iterator routines + at import time for a 20% speed boost. + 1.6.1 ----- diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 8f9412f..971038b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,6 +1,6 @@ The primary author and maintainer of six is Benjamin Peterson. He would like to acknowledge the following people who submitted bug reports, pull requests, and -otherwised worked to improve six: +otherwise worked to improve six: Marc Abramowitz Aymeric Augustin @@ -8,9 +8,13 @@ Ned Batchelder Jason R. Coombs Julien Danjou Ben Darnell +Ben Davis +Joshua Harlow Alexander Lukanin James Mills Sridhar Ratnakumar +Erik Rose +Peter Ruibal Miroslav Shubernetskiy If you think you belong on this list, please let me know! --Benjamin diff --git a/documentation/index.rst b/documentation/index.rst index 3d7828b..298bea7 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -222,6 +222,13 @@ functions and methods is the stdlib :mod:`py3:inspect` module. aliased to :class:`py3:object`.) +.. function:: wraps(wrapped) + + This is exactly the :func:`py3:functools.wraps` decorator, but it sets the + ``__wrapped__`` attribute on what it decorates as :func:`py3:functools.wraps` + does on Python versions after 3.2. + + Syntax compatibility >>>>>>>>>>>>>>>>>>>> @@ -477,6 +484,8 @@ Supported renames: +------------------------------+-------------------------------------+-------------------------------------+ | ``dbm_gnu`` | :func:`py2:gdbm` | :class:`py3:dbm.gnu` | +------------------------------+-------------------------------------+-------------------------------------+ +| ``_dummy_thread`` | :mod:`py2:dummy_thread` | :mod:`py3:_dummy_thread` | ++------------------------------+-------------------------------------+-------------------------------------+ | ``email_mime_multipart`` | :mod:`py2:email.MIMEMultipart` | :mod:`py3:email.mime.multipart` | +------------------------------+-------------------------------------+-------------------------------------+ | ``email_mime_text`` | :mod:`py2:email.MIMEText` | :mod:`py3:email.mime.text` | @@ -563,6 +572,10 @@ Supported renames: +------------------------------+-------------------------------------+-------------------------------------+ | ``urllib_robotparser`` | :mod:`py2:robotparser` | :mod:`py3:urllib.robotparser` | +------------------------------+-------------------------------------+-------------------------------------+ +| ``UserDict`` | :class:`py2:UserDict.UserDict` | :class:`py3:collections.UserDict` | ++------------------------------+-------------------------------------+-------------------------------------+ +| ``UserList`` | :class:`py2:UserList.UserList` | :class:`py3:collections.UserList` | ++------------------------------+-------------------------------------+-------------------------------------+ | ``UserString`` | :class:`py2:UserString.UserString` | :class:`py3:collections.UserString` | +------------------------------+-------------------------------------+-------------------------------------+ | ``winreg`` | :mod:`py2:_winreg` | :mod:`py3:winreg` | @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import functools import operator import sys import types @@ -229,6 +230,8 @@ _moved_attributes = [ MovedAttribute("reload_module", "__builtin__", "imp", "reload"), MovedAttribute("reduce", "__builtin__", "functools"), MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), MovedAttribute("UserString", "UserString", "collections"), MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), @@ -238,6 +241,7 @@ _moved_attributes = [ MovedModule("configparser", "ConfigParser"), MovedModule("copyreg", "copy_reg"), MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), MovedModule("http_cookies", "Cookie", "http.cookies"), MovedModule("html_entities", "htmlentitydefs", "html.entities"), @@ -469,11 +473,6 @@ if PY3: _func_code = "__code__" _func_defaults = "__defaults__" _func_globals = "__globals__" - - _iterkeys = "keys" - _itervalues = "values" - _iteritems = "items" - _iterlists = "lists" else: _meth_func = "im_func" _meth_self = "im_self" @@ -483,11 +482,6 @@ else: _func_defaults = "func_defaults" _func_globals = "func_globals" - _iterkeys = "iterkeys" - _itervalues = "itervalues" - _iteritems = "iteritems" - _iterlists = "iterlists" - try: advance_iterator = next @@ -536,21 +530,37 @@ get_function_defaults = operator.attrgetter(_func_defaults) get_function_globals = operator.attrgetter(_func_globals) -def iterkeys(d, **kw): - """Return an iterator over the keys of a dictionary.""" - return iter(getattr(d, _iterkeys)(**kw)) +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) -def itervalues(d, **kw): - """Return an iterator over the values of a dictionary.""" - return iter(getattr(d, _itervalues)(**kw)) + def iterlists(d, **kw): + return iter(d.lists(**kw)) +else: + def iterkeys(d, **kw): + return iter(d.iterkeys(**kw)) + + def itervalues(d, **kw): + return iter(d.itervalues(**kw)) + + def iteritems(d, **kw): + return iter(d.iteritems(**kw)) -def iteritems(d, **kw): - """Return an iterator over the (key, value) pairs of a dictionary.""" - return iter(getattr(d, _iteritems)(**kw)) + def iterlists(d, **kw): + return iter(d.iterlists(**kw)) -def iterlists(d, **kw): - """Return an iterator over the (key, [values]) pairs of a dictionary.""" - return iter(getattr(d, _iterlists)(**kw)) +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") if PY3: @@ -676,10 +686,33 @@ if print_ is None: _add_doc(reraise, """Reraise an exception.""") +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped): + def wrapper(f): + f = functools.wraps(wrapped)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" - return meta("NewBase", bases, {}) + # This requires a bit of explanation: the basic idea is to make a + # dummy metaclass for one level of class instantiation that replaces + # itself with the actual metaclass. Because of internal type checks + # we also need to make sure that we downgrade the custom metaclass + # for one level to something closer to type (that's why __call__ and + # __init__ comes back from type etc.). + class metaclass(meta): + __call__ = type.__call__ + __init__ = type.__init__ + def __new__(cls, name, this_bases, d): + if this_bases is None: + return type.__new__(cls, name, (), d) + return meta(name, bases, d) + return metaclass('temporary_class', None, {}) + def add_metaclass(metaclass): """Class decorator for creating a class with a metaclass.""" diff --git a/test_six.py b/test_six.py index 47ad1ce..a520a83 100644 --- a/test_six.py +++ b/test_six.py @@ -353,6 +353,14 @@ def test_get_function_globals(): def test_dictionary_iterators(monkeypatch): + def stock_method_name(iterwhat): + """Given a method suffix like "lists" or "values", return the name + of the dict method that delivers those on the version of Python + we're running in.""" + if six.PY3: + return iterwhat + return 'iter' + iterwhat + class MyDict(dict): if not six.PY3: def lists(self, **kw): @@ -361,7 +369,8 @@ def test_dictionary_iterators(monkeypatch): return iter([1, 2, 3]) f = MyDict.iterlists del MyDict.iterlists - setattr(MyDict, six._iterlists, f) + setattr(MyDict, stock_method_name('lists'), f) + d = MyDict(zip(range(10), reversed(range(10)))) for name in "keys", "values", "items", "lists": meth = getattr(six, "iter" + name) @@ -373,8 +382,8 @@ def test_dictionary_iterators(monkeypatch): def with_kw(*args, **kw): record.append(kw["kw"]) return old(*args) - old = getattr(MyDict, getattr(six, "_iter" + name)) - monkeypatch.setattr(MyDict, getattr(six, "_iter" + name), with_kw) + old = getattr(MyDict, stock_method_name(name)) + monkeypatch.setattr(MyDict, stock_method_name(name), with_kw) meth(d, kw=42) assert record == [42] monkeypatch.undo() @@ -625,6 +634,25 @@ def test_with_metaclass(): assert type(X) is Meta assert issubclass(X, Base) assert issubclass(X, Base2) + assert X.__mro__ == (X, Base, Base2, object) + + +def test_wraps(): + def f(g): + @six.wraps(g) + def w(): + return 42 + return w + def k(): + pass + original_k = k + k = f(f(k)) + assert hasattr(k, '__wrapped__') + k = k.__wrapped__ + assert hasattr(k, '__wrapped__') + k = k.__wrapped__ + assert k is original_k + assert not hasattr(k, '__wrapped__') def test_add_metaclass(): @@ -1,12 +1,12 @@ [tox] -envlist=py24,py25,py26,py27,py31,py32,py33,pypy +envlist=py25,py26,py27,py31,py32,py33,py34,pypy indexserver= default = http://pypi.python.org/simple testrun = http://pypi.testrun.org [testenv] deps=pytest -commands= py.test -rfsxX +commands= py.test -rfsxX {posargs} [pytest] minversion=2.2.0 |