summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2014-01-04 16:04:08 -0600
committerBenjamin Peterson <benjamin@python.org>2014-01-04 16:04:08 -0600
commite06f3e68d9b157c1e5e3c63b184f00e01f7c1bfa (patch)
tree64eb502129b9af21f60046f733cbe441dde6b5b6
parent09fc7816662183c1a2341eb6deb611a1600ed237 (diff)
parentd667af632afc42f41caad3739014f872fb03fd48 (diff)
downloadsix-e06f3e68d9b157c1e5e3c63b184f00e01f7c1bfa.tar.gz
Merged in alexanderlukanin13/six/urllib_import_weirdness (pull request #22)
moves import bug fixed
-rw-r--r--CHANGES11
-rw-r--r--README2
-rw-r--r--documentation/index.rst20
-rw-r--r--six.py55
-rw-r--r--test_six.py58
5 files changed, 115 insertions, 31 deletions
diff --git a/CHANGES b/CHANGES
index 6ef6813..de20c4c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,17 @@ This file lists the changes in each six version.
Development version
-------------------
+- Issue #49: Add six.moves mapping for tkinter.ttk.
+
+- Pull request #24: Add __dir__ special method to six.moves modules.
+
+- Issue #47: Fix add_metaclass on classes with a string for the __slots__
+ variable.
+
+- Issue #44: Fix interpretation of backslashes on Python 2 in the u() function.
+
+- Pull request #21: Add import mapping for urllib's proxy_bypass function.
+
- Issue #43: Add import mapping for the Python 2 xmlrpclib module.
- Issue #39: Add import mapping for the Python 2 thread module.
diff --git a/README b/README
index 99bd3a6..4de73fa 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.4. It is contained in only one Python
+Six supports every Python version since 2.5. 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 ee8b60d..1bd327a 100644
--- a/documentation/index.rst
+++ b/documentation/index.rst
@@ -137,27 +137,26 @@ functions and methods is the stdlib :mod:`py3:inspect` module.
Get the closure (list of cells) associated with *func*. This is equivalent
to ``func.__closure__`` on Python 2.6+ and ``func.func_closure`` on Python
- 2.4 and 2.5.
+ 2.5.
.. function:: get_function_code(func)
Get the code object associated with *func*. This is equivalent to
- ``func.__code__`` on Python 2.6+ and ``func.func_code`` on Python 2.4 and
- 2.5.
+ ``func.__code__`` on Python 2.6+ and ``func.func_code`` on Python 2.5.
.. function:: get_function_defaults(func)
Get the defaults tuple associated with *func*. This is equivalent to
- ``func.__defaults__`` on Python 2.6+ and ``func.func_defaults`` on Python 2.4
- and 2.5.
+ ``func.__defaults__`` on Python 2.6+ and ``func.func_defaults`` on Python
+ 2.5.
.. function:: get_function_globals(func)
Get the globals of *func*. This is equivalent to ``func.__globals__`` on
- Python 2.6+ and ``func.func_globals`` on Python 2.4 and 2.5.
+ Python 2.6+ and ``func.func_globals`` on Python 2.5.
.. function:: next(it)
@@ -307,7 +306,7 @@ Python 2 and 3.
on Python 2.
Note that class decorators require Python 2.6. However, the effect of the
- decorator can be emulated on Python 2.4 and 2.5 like so::
+ decorator can be emulated on Python 2.5 like so::
class MyClass(object):
pass
@@ -506,9 +505,11 @@ Supported renames:
+------------------------------+-------------------------------------+-------------------------------------+
| ``tkinter_filedialog`` | :mod:`py2:FileDialog` | :mod:`py3:tkinter.FileDialog` |
+------------------------------+-------------------------------------+-------------------------------------+
-| ``tkinter_scrolledtext`` | :mod:`py2:ScrolledText` | :mod:`py3:tkinter.scrolledtext` |
+| ``tkinter_scrolledtext`` | :mod:`py2:ScrolledText` | :mod:`py3:tkinter.scrolledtext` |
++------------------------------+-------------------------------------+-------------------------------------+
+| ``tkinter_simpledialog`` | :mod:`py2:SimpleDialog` | :mod:`py3:tkinter.simpledialog` |
+------------------------------+-------------------------------------+-------------------------------------+
-| ``tkinter_simpledialog`` | :mod:`py2:SimpleDialog` | :mod:`py2:tkinter.simpledialog` |
+| ``tkinter_ttk`` | :mod:`py2:ttk` | :mod:`py3:tkinter.ttk` |
+------------------------------+-------------------------------------+-------------------------------------+
| ``tkinter_tix`` | :mod:`py2:Tix` | :mod:`py3:tkinter.tix` |
+------------------------------+-------------------------------------+-------------------------------------+
@@ -617,6 +618,7 @@ Contains items from Python 3's :mod:`py3:urllib.request` and Python 2's:
* :func:`py2:urllib.urlcleanup`
* :class:`py2:urllib.URLopener`
* :class:`py2:urllib.FancyURLopener`
+* :func:`py2:urllib.proxy_bypass`
and :mod:`py2:urllib2`:
diff --git a/six.py b/six.py
index 97a7312..1238290 100644
--- a/six.py
+++ b/six.py
@@ -112,6 +112,21 @@ class MovedModule(_LazyDescr):
return _import_module(self.mod)
+class _LazyModule(types.ModuleType):
+
+ def __init__(self, name):
+ super(_LazyModule, self).__init__(name)
+ self.__doc__ = self.__class__.__doc__
+
+ def __dir__(self):
+ attrs = ["__doc__", "__name__"]
+ attrs += [attr.name for attr in self._moved_attributes]
+ return attrs
+
+ # Subclasses should override this
+ _moved_attributes = []
+
+
class MovedAttribute(_LazyDescr):
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
@@ -138,7 +153,7 @@ class MovedAttribute(_LazyDescr):
-class _MovedItems(types.ModuleType):
+class _MovedItems(_LazyModule):
"""Lazy loading of moved objects"""
@@ -183,6 +198,7 @@ _moved_attributes = [
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
+ MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
MovedModule("tkinter_colorchooser", "tkColorChooser",
@@ -205,11 +221,13 @@ for attr in _moved_attributes:
setattr(_MovedItems, attr.name, attr)
del attr
+_MovedItems._moved_attributes = _moved_attributes
+
moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves")
-class Module_six_moves_urllib_parse(types.ModuleType):
+class Module_six_moves_urllib_parse(_LazyModule):
"""Lazy loading of moved objects in six.moves.urllib_parse"""
@@ -233,11 +251,13 @@ for attr in _urllib_parse_moved_attributes:
setattr(Module_six_moves_urllib_parse, attr.name, attr)
del attr
+Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
+
sys.modules[__name__ + ".moves.urllib_parse"] = Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse")
sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(__name__ + ".moves.urllib.parse")
-class Module_six_moves_urllib_error(types.ModuleType):
+class Module_six_moves_urllib_error(_LazyModule):
"""Lazy loading of moved objects in six.moves.urllib_error"""
@@ -250,11 +270,13 @@ for attr in _urllib_error_moved_attributes:
setattr(Module_six_moves_urllib_error, attr.name, attr)
del attr
+Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
+
sys.modules[__name__ + ".moves.urllib_error"] = Module_six_moves_urllib_error(__name__ + ".moves.urllib_error")
sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(__name__ + ".moves.urllib.error")
-class Module_six_moves_urllib_request(types.ModuleType):
+class Module_six_moves_urllib_request(_LazyModule):
"""Lazy loading of moved objects in six.moves.urllib_request"""
@@ -291,16 +313,19 @@ _urllib_request_moved_attributes = [
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
MovedAttribute("URLopener", "urllib", "urllib.request"),
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
+ MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
]
for attr in _urllib_request_moved_attributes:
setattr(Module_six_moves_urllib_request, attr.name, attr)
del attr
+Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
+
sys.modules[__name__ + ".moves.urllib_request"] = Module_six_moves_urllib_request(__name__ + ".moves.urllib_request")
sys.modules[__name__ + ".moves.urllib.request"] = Module_six_moves_urllib_request(__name__ + ".moves.urllib.request")
-class Module_six_moves_urllib_response(types.ModuleType):
+class Module_six_moves_urllib_response(_LazyModule):
"""Lazy loading of moved objects in six.moves.urllib_response"""
@@ -314,11 +339,13 @@ for attr in _urllib_response_moved_attributes:
setattr(Module_six_moves_urllib_response, attr.name, attr)
del attr
+Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
+
sys.modules[__name__ + ".moves.urllib_response"] = Module_six_moves_urllib_response(__name__ + ".moves.urllib_response")
sys.modules[__name__ + ".moves.urllib.response"] = Module_six_moves_urllib_response(__name__ + ".moves.urllib.response")
-class Module_six_moves_urllib_robotparser(types.ModuleType):
+class Module_six_moves_urllib_robotparser(_LazyModule):
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
@@ -329,6 +356,8 @@ for attr in _urllib_robotparser_moved_attributes:
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
del attr
+Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
+
sys.modules[__name__ + ".moves.urllib_robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib_robotparser")
sys.modules[__name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser")
@@ -341,6 +370,9 @@ class Module_six_moves_urllib(types.ModuleType):
response = sys.modules[__name__ + ".moves.urllib_response"]
robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"]
+ def __dir__(self):
+ return ['parse', 'error', 'request', 'response', 'robotparser']
+
sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib(__name__ + ".moves.urllib")
@@ -474,8 +506,9 @@ if PY3:
else:
def b(s):
return s
+ # Workaround for standalone backslash
def u(s):
- return unicode(s, "unicode_escape")
+ return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
unichr = unichr
int2byte = chr
def byte2int(bs):
@@ -586,7 +619,11 @@ def add_metaclass(metaclass):
orig_vars = cls.__dict__.copy()
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
- for slots_var in orig_vars.get('__slots__', ()):
- orig_vars.pop(slots_var)
+ slots = orig_vars.get('__slots__')
+ if slots is not None:
+ if isinstance(slots, str):
+ slots = [slots]
+ for slots_var in slots:
+ orig_vars.pop(slots_var)
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper
diff --git a/test_six.py b/test_six.py
index ec4d468..e6e75dd 100644
--- a/test_six.py
+++ b/test_six.py
@@ -59,11 +59,9 @@ def test_MAXSIZE():
except AttributeError:
# Before Python 2.6.
pass
- if sys.version_info[:2] == (2, 4):
- exc = ValueError
- else:
- exc = OverflowError
- py.test.raises(exc, operator.mul, [None], six.MAXSIZE + 1)
+ py.test.raises(
+ (ValueError, OverflowError),
+ operator.mul, [None], six.MAXSIZE + 1)
def test_lazy():
@@ -84,6 +82,15 @@ except ImportError:
else:
have_tkinter = True
+have_gdbm = True
+try:
+ import gdbm
+except ImportError:
+ try:
+ import dbm.gnu
+ except ImportError:
+ have_gdbm = False
+
@py.test.mark.parametrize("item_name",
[item.name for item in six._moved_attributes])
def test_move_items(item_name):
@@ -96,9 +103,15 @@ def test_move_items(item_name):
except ImportError:
if item_name == "winreg" and not sys.platform.startswith("win"):
py.test.skip("Windows only module")
- if item_name.startswith("tkinter") and not have_tkinter:
- py.test.skip("requires tkinter")
+ if item_name.startswith("tkinter"):
+ if not have_tkinter:
+ py.test.skip("requires tkinter")
+ if item_name == "tkinter_ttk" and sys.version_info <= (2, 6):
+ py.test.skip("ttk only available on 2.7+")
+ if item_name.startswith("dbm_gnu") and not have_gdbm:
+ py.test.skip("requires gdbm")
raise
+ assert item_name in dir(six.moves)
@py.test.mark.parametrize("item_name",
@@ -109,6 +122,8 @@ def test_move_items_urllib_parse(item_name):
py.test.skip("ParseResult is only found on 2.5+")
if item_name in ("parse_qs", "parse_qsl") and sys.version_info < (2, 6):
py.test.skip("parse_qs[l] is new in 2.6")
+ if sys.version_info[:2] >= (2, 6):
+ assert item_name in dir(six.moves.urllib.parse)
getattr(six.moves.urllib.parse, item_name)
@@ -116,6 +131,8 @@ def test_move_items_urllib_parse(item_name):
[item.name for item in six._urllib_error_moved_attributes])
def test_move_items_urllib_error(item_name):
"""Ensure that everything loads correctly."""
+ if sys.version_info[:2] >= (2, 6):
+ assert item_name in dir(six.moves.urllib.error)
getattr(six.moves.urllib.error, item_name)
@@ -123,6 +140,8 @@ def test_move_items_urllib_error(item_name):
[item.name for item in six._urllib_request_moved_attributes])
def test_move_items_urllib_request(item_name):
"""Ensure that everything loads correctly."""
+ if sys.version_info[:2] >= (2, 6):
+ assert item_name in dir(six.moves.urllib.request)
getattr(six.moves.urllib.request, item_name)
@@ -130,6 +149,8 @@ def test_move_items_urllib_request(item_name):
[item.name for item in six._urllib_response_moved_attributes])
def test_move_items_urllib_response(item_name):
"""Ensure that everything loads correctly."""
+ if sys.version_info[:2] >= (2, 6):
+ assert item_name in dir(six.moves.urllib.response)
getattr(six.moves.urllib.response, item_name)
@@ -137,6 +158,8 @@ def test_move_items_urllib_response(item_name):
[item.name for item in six._urllib_robotparser_moved_attributes])
def test_move_items_urllib_robotparser(item_name):
"""Ensure that everything loads correctly."""
+ if sys.version_info[:2] >= (2, 6):
+ assert item_name in dir(six.moves.urllib.robotparser)
getattr(six.moves.urllib.robotparser, item_name)
@@ -405,9 +428,9 @@ if six.PY3:
def test_u():
- s = six.u("hi")
+ s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
assert isinstance(s, str)
- assert s == "hi"
+ assert s == "hi \u0439 \U00000439 \\ \\\\ \n"
else:
@@ -419,9 +442,9 @@ else:
def test_u():
- s = six.u("hi")
+ s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
assert isinstance(s, unicode)
- assert s == "hi"
+ assert s == "hi \xd0\xb9 \xd0\xb9 \\ \\\\ \n".decode("utf8")
def test_u_escapes():
@@ -641,7 +664,7 @@ def test_add_metaclass():
assert instance.b == Base.b
assert instance.x == X.x
- # test a class with slots
+ # Test a class with slots.
class MySlots(object):
__slots__ = ["a", "b"]
MySlots = six.add_metaclass(Meta1)(MySlots)
@@ -650,3 +673,14 @@ def test_add_metaclass():
instance = MySlots()
instance.a = "foo"
py.test.raises(AttributeError, setattr, instance, "c", "baz")
+
+ # Test a class with string for slots.
+ class MyStringSlots(object):
+ __slots__ = "ab"
+ MyStringSlots = six.add_metaclass(Meta1)(MyStringSlots)
+ assert MyStringSlots.__slots__ == "ab"
+ instance = MyStringSlots()
+ instance.ab = "foo"
+ py.test.raises(AttributeError, setattr, instance, "a", "baz")
+ py.test.raises(AttributeError, setattr, instance, "b", "baz")
+