Commits

Anonymous committed 4e2818b Merge

Merge upstream default into issue_19

Comments (0)

Files changed (7)

File contents unchanged.

 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.
-Copyright (c) 2010-2013 Benjamin Peterson
+Copyright (c) 2010-2014 Benjamin Peterson
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 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.)
 

documentation/index.rst

 
    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)
    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
 +------------------------------+-------------------------------------+-------------------------------------+
 | ``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:`py2:tkinter.simpledialog`     |
+| ``tkinter_simpledialog``     | :mod:`py2:SimpleDialog`             | :mod:`py3:tkinter.simpledialog`     |
++------------------------------+-------------------------------------+-------------------------------------+
+| ``tkinter_ttk``              | :mod:`py2:ttk`                      | :mod:`py3:tkinter.ttk`              |
 +------------------------------+-------------------------------------+-------------------------------------+
 | ``tkinter_tix``              | :mod:`py2:Tix`                      | :mod:`py3:tkinter.tix`              |
 +------------------------------+-------------------------------------+-------------------------------------+
 """Utilities for writing code that runs on Python 2 and 3"""
 
-# Copyright (c) 2010-2013 Benjamin Peterson
+# Copyright (c) 2010-2014 Benjamin Peterson
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
 
     def __get__(self, obj, tp):
         result = self._resolve()
-        setattr(obj, self.name, result)
+        setattr(obj, self.name, result) # Invokes __set__.
         # This is a bit ugly, but it avoids running this again.
-        delattr(tp, self.name)
+        delattr(obj.__class__, self.name)
         return result
 
 
         return getattr(_module, attr)
 
 
+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):
 
 
 
-class _MovedItems(types.ModuleType):
+class _MovedItems(_LazyModule):
     """Lazy loading of moved objects"""
 
 
     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",
         sys.modules[__name__ + ".moves." + 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"""
 
 
     setattr(Module_six_moves_urllib_parse, attr.name, attr)
 del attr
 
-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")
+Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
 
+sys.modules[__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"""
 
 
     setattr(Module_six_moves_urllib_error, attr.name, attr)
 del attr
 
-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")
+Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
 
+sys.modules[__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"""
 
 
     setattr(Module_six_moves_urllib_request, attr.name, attr)
 del attr
 
-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")
+Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
 
+sys.modules[__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"""
 
 
     setattr(Module_six_moves_urllib_response, attr.name, attr)
 del attr
 
-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")
+Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
 
+sys.modules[__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"""
 
 
     setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
 del attr
 
-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")
+Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
+
+sys.modules[__name__ + ".moves.urllib_robotparser"] = sys.modules[__name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser")
 
 
 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")
 
 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):
         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
     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():
 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):
     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",
         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)
 
 
                           [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)
 
 
                           [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)
 
 
                           [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)
 
 
                           [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)
 
 
+def test_import_moves_error_1():
+    from six.moves.urllib.parse import urljoin
+    from six import moves
+    # In 1.4.1: AttributeError: 'Module_six_moves_urllib_parse' object has no attribute 'urljoin'
+    assert moves.urllib.parse.urljoin
+
+
+def test_import_moves_error_2():
+    from six import moves
+    assert moves.urllib.parse.urljoin
+    # In 1.4.1: ImportError: cannot import name urljoin
+    from six.moves.urllib.parse import urljoin
+
+
+def test_import_moves_error_3():
+    from six.moves.urllib.parse import urljoin
+    # In 1.4.1: ImportError: cannot import name urljoin
+    from six.moves.urllib_parse import urljoin
+
+
 def test_from_six_moves_queue_import_Queue():
     from six.moves.queue import Queue
     assert isinstance(Queue, types.ClassType)
 
 
     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:
 
 
 
     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():
     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)
     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")
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.