diff options
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | CONTRIBUTORS | 2 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | documentation/index.rst | 11 | ||||
-rw-r--r-- | setup.cfg | 16 | ||||
-rw-r--r-- | six.py | 54 | ||||
-rw-r--r-- | test_six.py | 18 | ||||
-rw-r--r-- | tox.ini | 11 |
8 files changed, 95 insertions, 22 deletions
@@ -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 @@ -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` | +------------------------------+-------------------------------------+-------------------------------------+ @@ -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 + @@ -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): @@ -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 + |