summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnselm Kruis <a.kruis@science-computing.de>2014-05-27 22:17:16 +0200
committerAnselm Kruis <a.kruis@science-computing.de>2014-05-27 22:17:16 +0200
commitc8c2e281b6618c5f219a2a8bcda65635ad558e2a (patch)
tree859b4fd252bcc8d683d296c6a5d39bf976532f68
parentde1f05da84175a19ca999bec05d33b0c7039e5a2 (diff)
parentaf207053a3474247f47459263486b5fcc9ff8975 (diff)
downloadsix-git-c8c2e281b6618c5f219a2a8bcda65635ad558e2a.tar.gz
Merge heads.
-rw-r--r--CHANGES16
-rw-r--r--CONTRIBUTORS6
-rw-r--r--documentation/index.rst13
-rw-r--r--six.py79
-rw-r--r--test_six.py34
-rw-r--r--tox.ini4
6 files changed, 123 insertions, 29 deletions
diff --git a/CHANGES b/CHANGES
index 140cae5..c87234f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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` |
diff --git a/six.py b/six.py
index 82825f0..51a3637 100644
--- a/six.py
+++ b/six.py
@@ -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():
diff --git a/tox.ini b/tox.ini
index 6dd6c05..b29b31a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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