summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2015-03-20 10:27:28 -0500
committerBenjamin Peterson <benjamin@python.org>2015-03-20 10:27:28 -0500
commite477c1e074310a552cf4e922ef14969fcdca67f4 (patch)
treeb9634e5fcfbc789b0785950bdf8a81d1f01806e1
parente704f18aa5290aed689d3a5ea60a3321c71c6c95 (diff)
parent31666908f9c95fbcf80a1fe1960d350760fce67b (diff)
downloadsix-e477c1e074310a552cf4e922ef14969fcdca67f4.tar.gz
Merged in maxgrenderjones/six (pull request #60)
Fixes #108 (os.getcwd has been renamed in move from 2 to 3)
-rw-r--r--CHANGES3
-rw-r--r--CONTRIBUTORS2
-rw-r--r--README2
-rw-r--r--documentation/index.rst11
-rw-r--r--setup.cfg16
-rw-r--r--six.py54
-rw-r--r--test_six.py18
-rw-r--r--tox.ini11
8 files changed, 95 insertions, 22 deletions
diff --git a/CHANGES b/CHANGES
index 4b9425f..3434ff5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -26,6 +26,9 @@ This file lists the changes in each six version.
- Pull request #51: Add `six.view(keys|values|itmes)`, which provide dictionary
views on Python 2.7+.
+- Issue #112: `six.moves.reload_module` now uses the importlib module on
+ Python 3.4+.
+
1.8.0
-----
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 81c2eae..3122a57 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -6,6 +6,7 @@ Marc Abramowitz
Alexander Artemenko
Aymeric Augustin
Ned Batchelder
+Brett Cannon
Jason R. Coombs
Julien Danjou
Ben Darnell
@@ -16,6 +17,7 @@ Joshua Harlow
Anselm Kruis
Alexander Lukanin
James Mills
+Berker Peksag
Sridhar Ratnakumar
Erik Rose
Peter Ruibal
diff --git a/README b/README
index 32bab7c..2a22717 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@ for smoothing over the differences between the Python versions with the goal of
writing Python code that is compatible on both Python versions. See the
documentation for more information on what is provided.
-Six supports every Python version since 2.5. It is contained in only one Python
+Six supports every Python version since 2.6. It is contained in only one Python
file, so it can be easily copied into your project. (The copyright and license
notice must be retained.)
diff --git a/documentation/index.rst b/documentation/index.rst
index 1f27400..d838e38 100644
--- a/documentation/index.rst
+++ b/documentation/index.rst
@@ -232,6 +232,13 @@ functions and methods is the stdlib :mod:`py3:inspect` module.
requires the *obj*'s class to be passed.
+.. function:: create_unbound_method(func, cls)
+
+ Return an unbound method object wrapping *func*. In Python 2, this will return
+ a :func:`py3:types.MethodType` object. In Python 3 unbound methods do not
+ exist and this wrapper will return *func*.
+
+
.. class:: Iterator
A class for making portable iterators. The intention is that it be subclassed
@@ -598,7 +605,9 @@ Supported renames:
+------------------------------+-------------------------------------+-------------------------------------+
| ``reduce`` | :func:`py2:reduce` | :func:`py3:functools.reduce` |
+------------------------------+-------------------------------------+-------------------------------------+
-| ``reload_module`` | :func:`py2:reload` | :func:`py3:imp.reload` |
+| ``reload_module`` | :func:`py2:reload` | :func:`py3:imp.reload`, |
+| | | :func:`py3:importlib.reload` |
+| | | on Python 3.4+ |
+------------------------------+-------------------------------------+-------------------------------------+
| ``reprlib`` | :mod:`py2:repr` | :mod:`py3:reprlib` |
+------------------------------+-------------------------------------+-------------------------------------+
diff --git a/setup.cfg b/setup.cfg
index 5e40900..4a5b847 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,18 @@
[wheel]
universal = 1
+
+[flake8]
+max-line-length = 100
+ignore = F821
+
+[pytest]
+minversion=2.2.0
+pep8ignore =
+ documentation/*.py ALL
+ test_six.py ALL
+
+flakes-ignore =
+ documentation/*.py ALL
+ test_six.py ALL
+ six.py UndefinedName
+
diff --git a/six.py b/six.py
index da6afc5..36b7f9d 100644
--- a/six.py
+++ b/six.py
@@ -35,6 +35,7 @@ __version__ = "1.9.0"
# Useful for very coarse version differentiation.
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
+PY34 = sys.version_info[0:2] >= (3, 4)
if PY3:
string_types = str,
@@ -57,6 +58,7 @@ else:
else:
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
class X(object):
+
def __len__(self):
return 1 << 31
try:
@@ -88,7 +90,7 @@ class _LazyDescr(object):
def __get__(self, obj, tp):
result = self._resolve()
- setattr(obj, self.name, result) # Invokes __set__.
+ setattr(obj, self.name, result) # Invokes __set__.
try:
# This is a bit ugly, but it avoids running this again by
# removing this descriptor.
@@ -160,12 +162,14 @@ class MovedAttribute(_LazyDescr):
class _SixMetaPathImporter(object):
+
"""
A meta path importer to import six.moves and its submodules.
This class implements a PEP302 finder and loader. It should be compatible
with Python 2.5 and all existing versions of Python3
"""
+
def __init__(self, six_module_name):
self.name = six_module_name
self.known_modules = {}
@@ -223,6 +227,7 @@ _importer = _SixMetaPathImporter(__name__)
class _MovedItems(_LazyModule):
+
"""Lazy loading of moved objects"""
__path__ = [] # mark as package
@@ -237,7 +242,7 @@ _moved_attributes = [
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
+ MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
MovedAttribute("reduce", "__builtin__", "functools"),
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
MovedAttribute("StringIO", "StringIO", "io"),
@@ -247,7 +252,6 @@ _moved_attributes = [
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
-
MovedModule("builtins", "__builtin__"),
MovedModule("configparser", "ConfigParser"),
MovedModule("copyreg", "copy_reg"),
@@ -309,6 +313,7 @@ _importer._add_module(moves, "moves")
class Module_six_moves_urllib_parse(_LazyModule):
+
"""Lazy loading of moved objects in six.moves.urllib_parse"""
@@ -348,6 +353,7 @@ _importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_pa
class Module_six_moves_urllib_error(_LazyModule):
+
"""Lazy loading of moved objects in six.moves.urllib_error"""
@@ -367,6 +373,7 @@ _importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.er
class Module_six_moves_urllib_request(_LazyModule):
+
"""Lazy loading of moved objects in six.moves.urllib_request"""
@@ -416,6 +423,7 @@ _importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.
class Module_six_moves_urllib_response(_LazyModule):
+
"""Lazy loading of moved objects in six.moves.urllib_response"""
@@ -436,6 +444,7 @@ _importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib
class Module_six_moves_urllib_robotparser(_LazyModule):
+
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
@@ -453,6 +462,7 @@ _importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.url
class Module_six_moves_urllib(types.ModuleType):
+
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
__path__ = [] # mark as package
parse = _importer._get_module("moves.urllib_parse")
@@ -523,6 +533,9 @@ if PY3:
create_bound_method = types.MethodType
+ def create_unbound_method(func, cls):
+ return func
+
Iterator = object
else:
def get_unbound_function(unbound):
@@ -531,6 +544,9 @@ else:
def create_bound_method(func, obj):
return types.MethodType(func, obj, obj.__class__)
+ def create_unbound_method(func, cls):
+ return types.MethodType(func, None, cls)
+
class Iterator(object):
def next(self):
@@ -569,16 +585,16 @@ if PY3:
viewitems = operator.methodcaller("items")
else:
def iterkeys(d, **kw):
- return iter(d.iterkeys(**kw))
+ return d.iterkeys(**kw)
def itervalues(d, **kw):
- return iter(d.itervalues(**kw))
+ return d.itervalues(**kw)
def iteritems(d, **kw):
- return iter(d.iteritems(**kw))
+ return d.iteritems(**kw)
def iterlists(d, **kw):
- return iter(d.iterlists(**kw))
+ return d.iterlists(**kw)
viewkeys = operator.methodcaller("viewkeys")
@@ -597,6 +613,7 @@ _add_doc(iterlists,
if PY3:
def b(s):
return s.encode("latin-1")
+
def u(s):
return s
unichr = chr
@@ -613,18 +630,25 @@ if PY3:
StringIO = io.StringIO
BytesIO = io.BytesIO
_assertCountEqual = "assertCountEqual"
- _assertRaisesRegex = "assertRaisesRegex"
- _assertRegex = "assertRegex"
+ if sys.version_info[1] <= 1:
+ _assertRaisesRegex = "assertRaisesRegexp"
+ _assertRegex = "assertRegexpMatches"
+ else:
+ _assertRaisesRegex = "assertRaisesRegex"
+ _assertRegex = "assertRegex"
else:
def b(s):
return s
# Workaround for standalone backslash
+
def u(s):
return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
unichr = unichr
int2byte = chr
+
def byte2int(bs):
return ord(bs[0])
+
def indexbytes(buf, i):
return ord(buf[i])
iterbytes = functools.partial(itertools.imap, ord)
@@ -652,7 +676,6 @@ def assertRegex(self, *args, **kwargs):
if PY3:
exec_ = getattr(moves.builtins, "exec")
-
def reraise(tp, value, tb=None):
if value is None:
value = tp()
@@ -673,7 +696,6 @@ else:
_locs_ = _globs_
exec("""exec _code_ in _globs_, _locs_""")
-
exec_("""def reraise(tp, value, tb=None):
raise tp, value, tb
""")
@@ -701,13 +723,14 @@ if print_ is None:
fp = kwargs.pop("file", sys.stdout)
if fp is None:
return
+
def write(data):
if not isinstance(data, basestring):
data = str(data)
# If the file has an encoding, encode unicode with it.
if (isinstance(fp, file) and
- isinstance(data, unicode) and
- fp.encoding is not None):
+ isinstance(data, unicode) and
+ fp.encoding is not None):
errors = getattr(fp, "errors", None)
if errors is None:
errors = "strict"
@@ -750,6 +773,7 @@ if print_ is None:
write(end)
if sys.version_info[:2] < (3, 3):
_print = print_
+
def print_(*args, **kwargs):
fp = kwargs.get("file", sys.stdout)
flush = kwargs.pop("flush", False)
@@ -770,12 +794,14 @@ if sys.version_info[0:2] < (3, 4):
else:
wraps = functools.wraps
+
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
# 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.
class metaclass(meta):
+
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})
@@ -832,7 +858,7 @@ if sys.meta_path:
# the six meta path importer, since the other six instance will have
# inserted an importer with different class.
if (type(importer).__name__ == "_SixMetaPathImporter" and
- importer.name == __name__):
+ importer.name == __name__):
del sys.meta_path[i]
break
del i, importer
diff --git a/test_six.py b/test_six.py
index 76a8ccb..060a966 100644
--- a/test_six.py
+++ b/test_six.py
@@ -390,7 +390,7 @@ def test_dictionary_iterators(monkeypatch):
monkeypatch.undo()
-@py.test.mark.skipif(sys.version_info[:2] < (2, 7),
+@py.test.mark.skipif("sys.version_info[:2] < (2, 7)",
reason="view methods on dictionaries only available on 2.7+")
def test_dictionary_views():
def stock_method_name(viewwhat):
@@ -456,6 +456,20 @@ def test_create_bound_method():
assert b() is x
+def test_create_unbound_method():
+ class X(object):
+ pass
+
+ def f(self):
+ return self
+ u = six.create_unbound_method(f, X)
+ py.test.raises(TypeError, u)
+ if six.PY2:
+ assert isinstance(u, types.MethodType)
+ x = X()
+ assert f(x) is x
+
+
if six.PY3:
def test_b():
@@ -799,7 +813,7 @@ def test_add_metaclass():
assert type(MySlotsWeakref) is Meta
-@py.test.mark.skipif("sys.version_info[:2] < (2, 7)")
+@py.test.mark.skipif("sys.version_info[:2] < (2, 7) or sys.version_info[:2] in ((3, 0), (3, 1))")
def test_assertCountEqual():
class TestAssertCountEqual(unittest.TestCase):
def test(self):
diff --git a/tox.ini b/tox.ini
index b29b31a..617b7df 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,12 +1,15 @@
[tox]
-envlist=py25,py26,py27,py31,py32,py33,py34,pypy
+envlist=py26,py27,py31,py32,py33,py34,pypy,flake8
indexserver=
default = http://pypi.python.org/simple
testrun = http://pypi.testrun.org
[testenv]
-deps=pytest
+deps= pytest
commands= py.test -rfsxX {posargs}
-[pytest]
-minversion=2.2.0
+[testenv:flake8]
+basepython=python
+deps=flake8
+commands= flake8 six.py
+