Loading django/utils/py3.pydeleted 100644 → 0 +0 −109 Original line number Diff line number Diff line # Compatibility layer for running Django both in 2.x and 3.x import sys if sys.version_info[0] < 3: PY3 = False # Changed module locations from urlparse import (urlparse, urlunparse, urljoin, urlsplit, urlunsplit, urldefrag, parse_qsl) from urllib import (quote, unquote, quote_plus, urlopen, urlencode, url2pathname, urlretrieve, unquote_plus) from urllib2 import (Request, OpenerDirector, UnknownHandler, HTTPHandler, HTTPSHandler, HTTPDefaultErrorHandler, FTPHandler, HTTPError, HTTPErrorProcessor) import urllib2 import Cookie as cookies try: import cPickle as pickle except ImportError: import pickle try: import thread except ImportError: import dummy_thread as thread from htmlentitydefs import name2codepoint import HTMLParser from os import getcwdu from itertools import izip as zip unichr = unichr xrange = xrange maxsize = sys.maxint # Type aliases string_types = basestring, text_type = unicode integer_types = int, long long_type = long from io import BytesIO as OutputIO # Glue code for syntax differences def reraise(tp, value, tb=None): exec("raise tp, value, tb") def with_metaclass(meta, base=object): class _DjangoBase(base): __metaclass__ = meta return _DjangoBase iteritems = lambda o: o.iteritems() itervalues = lambda o: o.itervalues() iterkeys = lambda o: o.iterkeys() # n() is useful when python3 needs a str (unicode), and python2 str (bytes) n = lambda s: s.encode('utf-8') else: PY3 = True import builtins # Changed module locations from urllib.parse import (urlparse, urlunparse, urlencode, urljoin, urlsplit, urlunsplit, quote, unquote, quote_plus, unquote_plus, parse_qsl, urldefrag) from urllib.request import (urlopen, url2pathname, Request, OpenerDirector, UnknownHandler, HTTPHandler, HTTPSHandler, HTTPDefaultErrorHandler, FTPHandler, HTTPError, HTTPErrorProcessor, urlretrieve) import urllib.request as urllib2 import http.cookies as cookies import pickle try: import _thread as thread except ImportError: import _dummy_thread as thread from html.entities import name2codepoint import html.parser as HTMLParser from os import getcwd as getcwdu zip = zip unichr = chr xrange = range maxsize = sys.maxsize # Type aliases string_types = str, text_type = str integer_types = int, long_type = int from io import StringIO as OutputIO # Glue code for syntax differences def reraise(tp, value, tb=None): if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value def with_metaclass(meta, base=object): ns = dict(base=base, meta=meta) exec("""class _DjangoBase(base, metaclass=meta): pass""", ns) return ns["_DjangoBase"] iteritems = lambda o: o.items() itervalues = lambda o: o.values() iterkeys = lambda o: o.keys() n = lambda s: s django/utils/six.py 0 → 100644 +353 −0 Original line number Diff line number Diff line """Utilities for writing code that runs on Python 2 and 3""" import operator import sys import types __author__ = "Benjamin Peterson <benjamin@python.org>" __version__ = "1.1.0" # True if we are running on Python 3. PY3 = sys.version_info[0] == 3 if PY3: string_types = str, integer_types = int, class_types = type, text_type = str binary_type = bytes MAXSIZE = sys.maxsize else: string_types = basestring, integer_types = (int, long) class_types = (type, types.ClassType) text_type = unicode binary_type = str # It's possible to have sizeof(long) != sizeof(Py_ssize_t). class X(object): def __len__(self): return 1 << 31 try: len(X()) except OverflowError: # 32-bit MAXSIZE = int((1 << 31) - 1) else: # 64-bit MAXSIZE = int((1 << 63) - 1) del X def _add_doc(func, doc): """Add documentation to a function.""" func.__doc__ = doc def _import_module(name): """Import module, returning the module after the last dot.""" __import__(name) return sys.modules[name] class _LazyDescr(object): def __init__(self, name): self.name = name def __get__(self, obj, tp): result = self._resolve() setattr(obj, self.name, result) # This is a bit ugly, but it avoids running this again. delattr(tp, self.name) return result class MovedModule(_LazyDescr): def __init__(self, name, old, new=None): super(MovedModule, self).__init__(name) if PY3: if new is None: new = name self.mod = new else: self.mod = old def _resolve(self): return _import_module(self.mod) class MovedAttribute(_LazyDescr): def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): super(MovedAttribute, self).__init__(name) if PY3: if new_mod is None: new_mod = name self.mod = new_mod if new_attr is None: if old_attr is None: new_attr = name else: new_attr = old_attr self.attr = new_attr else: self.mod = old_mod if old_attr is None: old_attr = name self.attr = old_attr def _resolve(self): module = _import_module(self.mod) return getattr(module, self.attr) class _MovedItems(types.ModuleType): """Lazy loading of moved objects""" _moved_attributes = [ MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), MovedAttribute("map", "itertools", "builtins", "imap", "map"), MovedAttribute("reload_module", "__builtin__", "imp", "reload"), MovedAttribute("reduce", "__builtin__", "functools"), MovedAttribute("StringIO", "StringIO", "io"), MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), MovedModule("builtins", "__builtin__"), MovedModule("configparser", "ConfigParser"), MovedModule("copyreg", "copy_reg"), MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), MovedModule("http_cookies", "Cookie", "http.cookies"), MovedModule("html_entities", "htmlentitydefs", "html.entities"), MovedModule("html_parser", "HTMLParser", "html.parser"), MovedModule("http_client", "httplib", "http.client"), MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), MovedModule("cPickle", "cPickle", "pickle"), MovedModule("queue", "Queue"), MovedModule("reprlib", "repr"), MovedModule("socketserver", "SocketServer"), MovedModule("tkinter", "Tkinter"), MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), MovedModule("tkinter_tix", "Tix", "tkinter.tix"), MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), MovedModule("tkinter_font", "tkFont", "tkinter.font"), MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), MovedModule("winreg", "_winreg"), ] for attr in _moved_attributes: setattr(_MovedItems, attr.name, attr) del attr moves = sys.modules["six.moves"] = _MovedItems("moves") def add_move(move): """Add an item to six.moves.""" setattr(_MovedItems, move.name, move) def remove_move(name): """Remove item from six.moves.""" try: delattr(_MovedItems, name) except AttributeError: try: del moves.__dict__[name] except KeyError: raise AttributeError("no such move, %r" % (name,)) if PY3: _meth_func = "__func__" _meth_self = "__self__" _func_code = "__code__" _func_defaults = "__defaults__" _iterkeys = "keys" _itervalues = "values" _iteritems = "items" else: _meth_func = "im_func" _meth_self = "im_self" _func_code = "func_code" _func_defaults = "func_defaults" _iterkeys = "iterkeys" _itervalues = "itervalues" _iteritems = "iteritems" if PY3: def get_unbound_function(unbound): return unbound advance_iterator = next def callable(obj): return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) else: def get_unbound_function(unbound): return unbound.im_func def advance_iterator(it): return it.next() callable = callable _add_doc(get_unbound_function, """Get the function out of a possibly unbound function""") get_method_function = operator.attrgetter(_meth_func) get_method_self = operator.attrgetter(_meth_self) get_function_code = operator.attrgetter(_func_code) get_function_defaults = operator.attrgetter(_func_defaults) def iterkeys(d): """Return an iterator over the keys of a dictionary.""" return getattr(d, _iterkeys)() def itervalues(d): """Return an iterator over the values of a dictionary.""" return getattr(d, _itervalues)() def iteritems(d): """Return an iterator over the (key, value) pairs of a dictionary.""" return getattr(d, _iteritems)() if PY3: def b(s): return s.encode("latin-1") def u(s): return s if sys.version_info[1] <= 1: def int2byte(i): return bytes((i,)) else: # This is about 2x faster than the implementation above on 3.2+ int2byte = operator.methodcaller("to_bytes", 1, "big") import io StringIO = io.StringIO BytesIO = io.BytesIO else: def b(s): return s def u(s): return unicode(s, "unicode_escape") int2byte = chr import StringIO StringIO = BytesIO = StringIO.StringIO _add_doc(b, """Byte literal""") _add_doc(u, """Text literal""") if PY3: import builtins exec_ = getattr(builtins, "exec") def reraise(tp, value, tb=None): if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value print_ = getattr(builtins, "print") del builtins else: def exec_(code, globs=None, locs=None): """Execute code in a namespace.""" if globs is None: frame = sys._getframe(1) globs = frame.f_globals if locs is None: locs = frame.f_locals del frame elif locs is None: locs = globs exec("""exec code in globs, locs""") exec_("""def reraise(tp, value, tb=None): raise tp, value, tb """) def print_(*args, **kwargs): """The new-style print function.""" fp = kwargs.pop("file", sys.stdout) if fp is None: return def write(data): if not isinstance(data, basestring): data = str(data) fp.write(data) want_unicode = False sep = kwargs.pop("sep", None) if sep is not None: if isinstance(sep, unicode): want_unicode = True elif not isinstance(sep, str): raise TypeError("sep must be None or a string") end = kwargs.pop("end", None) if end is not None: if isinstance(end, unicode): want_unicode = True elif not isinstance(end, str): raise TypeError("end must be None or a string") if kwargs: raise TypeError("invalid keyword arguments to print()") if not want_unicode: for arg in args: if isinstance(arg, unicode): want_unicode = True break if want_unicode: newline = unicode("\n") space = unicode(" ") else: newline = "\n" space = " " if sep is None: sep = space if end is None: end = newline for i, arg in enumerate(args): if i: write(sep) write(arg) write(end) _add_doc(reraise, """Reraise an exception.""") def with_metaclass(meta, base=object): """Create a base class with a metaclass.""" return meta("NewBase", (base,), {}) docs/topics/python3.txt +25 −228 Original line number Diff line number Diff line Loading @@ -2,251 +2,48 @@ Python 3 compatibility ====================== Django 1.5 introduces a compatibility layer that allows the code to be run both in Python 2 (2.6/2.7) and Python 3 (>= 3.2) (*work in progress*). Django 1.5 is the first version of Django to support Python 3. This document is not meant as a complete Python 2 to Python 3 migration guide. There are many existing resources you can read. But we describe some utilities and guidelines that we recommend you should use when you want to ensure your code can be run with both Python 2 and 3. The same code runs both on Python 2 (≥2.6.5) and Python 3 (≥3.2). To achieve this: * http://docs.python.org/py3k/howto/pyporting.html * http://python3porting.com/ - wherever possible, Django uses the six_ compatibility layer, - all modules declare ``from __future__ import unicode_literals``. django.utils.py3 ================ .. _six: http://packages.python.org/six/ This document is not meant as a Python 2 to Python 3 migration guide. There are many existing resources, including `Python's official porting guide`_. But it describes guidelines that apply to Django's code and are recommended for pluggable apps that run with both Python 2 and 3. Whenever a symbol or module has different semantics or different locations on Python 2 and Python 3, you can import it from ``django.utils.py3`` where it will be automatically converted depending on your current Python version. .. _Python's official porting guide: http://docs.python.org/py3k/howto/pyporting.html PY3 --- .. module: django.utils.six If you need to know anywhere in your code if you are running Python 3 or a previous Python 2 version, you can check the ``PY3`` boolean variable:: django.utils.six ================ from django.utils.py3 import PY3 Read the documentation of six_. It's the canonical compatibility library for supporting Python 2 and 3 in a single codebase. if PY3: # Do stuff Python 3-wise else: # Do stuff Python 2-wise ``six`` is bundled with Django: you can import it as :mod:`django.utils.six`. This should be considered as a last resort solution when it is not possible to import a compatible name from django.utils.py3, as described in the sections below. .. _string-handling: String handling =============== In Python 3, all strings are considered Unicode strings by default. Byte strings have to be prefixed with the letter 'b'. To mimic the same behaviour in Python 2, we recommend you import ``unicode_literals`` from the ``__future__`` library:: In Python 3, all strings are considered Unicode strings by default. Byte strings must be prefixed with the letter ``b``. In order to enable the same behavior in Python 2, every module must import ``unicode_literals`` from ``__future__``:: from __future__ import unicode_literals my_string = "This is an unicode literal" my_bytestring = b"This is a bytestring" Be cautious if you have to slice bytestrings. See http://docs.python.org/py3k/howto/pyporting.html#bytes-literals Different expected strings -------------------------- Some method parameters have changed the expected string type of a parameter. For example, ``strftime`` format parameter expects a bytestring on Python 2 but a normal (Unicode) string on Python 3. For these cases, ``django.utils.py3`` provides a ``n()`` function which encodes the string parameter only with Python 2. >>> from __future__ import unicode_literals >>> from datetime import datetime >>> print(datetime.date(2012, 5, 21).strftime(n("%m → %Y"))) 05 → 2012 Renamed types ============= Several types are named differently in Python 2 and Python 3. In order to keep compatibility while using those types, import their corresponding aliases from ``django.utils.py3``. =========== ========= ===================== Python 2 Python 3 django.utils.py3 =========== ========= ===================== basestring, str, string_types (tuple) unicode str text_type int, long int, integer_types (tuple) long int long_type =========== ========= ===================== String aliases -------------- Code sample:: if isinstance(foo, basestring): print("foo is a string") # I want to convert a number to a Unicode string bar = 45 bar_string = unicode(bar) Should be replaced by:: from django.utils.py3 import string_types, text_type if isinstance(foo, string_types): print("foo is a string") # I want to convert a number to a Unicode string bar = 45 bar_string = text_type(bar) No more long type ----------------- ``long`` and ``int`` types have been unified in Python 3, meaning that ``long`` is no longer available. ``django.utils.py3`` provides both ``long_type`` and ``integer_types`` aliases. For example: .. code-block:: python # Old Python 2 code my_var = long(333463247234623) if isinstance(my_var, (int, long)): # ... Should be replaced by: .. code-block:: python from django.utils.py3 import long_type, integer_types my_var = long_type(333463247234623) if isinstance(my_var, integer_types): # ... Changed module locations ======================== The following modules have changed their location in Python 3. Therefore, it is recommended to import them from the ``django.utils.py3`` compatibility layer: =============================== ====================================== ====================== Python 2 Python3 django.utils.py3 =============================== ====================================== ====================== Cookie http.cookies cookies urlparse.urlparse urllib.parse.urlparse urlparse urlparse.urlunparse urllib.parse.urlunparse urlunparse urlparse.urljoin urllib.parse.urljoin urljoin urlparse.urlsplit urllib.parse.urlsplit urlsplit urlparse.urlunsplit urllib.parse.urlunsplit urlunsplit urlparse.urldefrag urllib.parse.urldefrag urldefrag urlparse.parse_qsl urllib.parse.parse_qsl parse_qsl urllib.quote urllib.parse.quote quote urllib.unquote urllib.parse.unquote unquote urllib.quote_plus urllib.parse.quote_plus quote_plus urllib.unquote_plus urllib.parse.unquote_plus unquote_plus urllib.urlencode urllib.parse.urlencode urlencode urllib.urlopen urllib.request.urlopen urlopen urllib.url2pathname urllib.request.url2pathname url2pathname urllib.urlretrieve urllib.request.urlretrieve urlretrieve urllib2 urllib.request urllib2 urllib2.Request urllib.request.Request Request urllib2.OpenerDirector urllib.request.OpenerDirector OpenerDirector urllib2.UnknownHandler urllib.request.UnknownHandler UnknownHandler urllib2.HTTPHandler urllib.request.HTTPHandler HTTPHandler urllib2.HTTPSHandler urllib.request.HTTPSHandler HTTPSHandler urllib2.HTTPDefaultErrorHandler urllib.request.HTTPDefaultErrorHandler HTTPDefaultErrorHandler urllib2.FTPHandler urllib.request.FTPHandler FTPHandler urllib2.HTTPError urllib.request.HTTPError HTTPError urllib2.HTTPErrorProcessor urllib.request.HTTPErrorProcessor HTTPErrorProcessor htmlentitydefs.name2codepoint html.entities.name2codepoint name2codepoint HTMLParser html.parser HTMLParser cPickle/pickle pickle pickle thread/dummy_thread _thread/_dummy_thread thread os.getcwdu os.getcwd getcwdu itertools.izip zip zip sys.maxint sys.maxsize maxsize unichr chr unichr xrange range xrange =============================== ====================================== ====================== Output encoding now Unicode =========================== If you want to catch stdout/stderr output, the output content is UTF-8 encoded in Python 2, while it is Unicode strings in Python 3. You can use the OutputIO stream to capture this output:: from django.utils.py3 import OutputIO try: old_stdout = sys.stdout out = OutputIO() sys.stdout = out # Do stuff which produces standard output result = out.getvalue() finally: sys.stdout = old_stdout Dict iteritems/itervalues/iterkeys ================================== The iteritems(), itervalues() and iterkeys() methods of dictionaries do not exist any more in Python 3, simply because they represent the default items() values() and keys() behavior in Python 3. Therefore, to keep compatibility, use similar functions from ``django.utils.py3``:: from django.utils.py3 import iteritems, itervalues, iterkeys my_dict = {'a': 21, 'b': 42} for key, value in iteritems(my_dict): # ... for value in itervalues(my_dict): # ... for key in iterkeys(my_dict): # ... Note that in Python 3, dict.keys(), dict.items() and dict.values() return "views" instead of lists. Wrap them into list() if you really need their return values to be in a list. http://docs.python.org/release/3.0.1/whatsnew/3.0.html#views-and-iterators-instead-of-lists Metaclass ========= The syntax for declaring metaclasses has changed in Python 3. ``django.utils.py3`` offers a compatible way to declare metaclasses:: from django.utils.py3 import with_metaclass class MyClass(with_metaclass(SubClass1, SubClass2,...)): # ... Re-raising exceptions ===================== One of the syntaxes to raise exceptions (raise E, V, T) is gone in Python 3. This is especially used in very specific cases where you want to re-raise a different exception that the initial one, while keeping the original traceback. So, instead of:: raise Exception, Exception(msg), traceback Use:: from django.utils.py3 import reraise reraise(Exception, Exception(msg), traceback) Be cautious if you have to `slice bytestrings`_. .. _slice bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals Loading
django/utils/py3.pydeleted 100644 → 0 +0 −109 Original line number Diff line number Diff line # Compatibility layer for running Django both in 2.x and 3.x import sys if sys.version_info[0] < 3: PY3 = False # Changed module locations from urlparse import (urlparse, urlunparse, urljoin, urlsplit, urlunsplit, urldefrag, parse_qsl) from urllib import (quote, unquote, quote_plus, urlopen, urlencode, url2pathname, urlretrieve, unquote_plus) from urllib2 import (Request, OpenerDirector, UnknownHandler, HTTPHandler, HTTPSHandler, HTTPDefaultErrorHandler, FTPHandler, HTTPError, HTTPErrorProcessor) import urllib2 import Cookie as cookies try: import cPickle as pickle except ImportError: import pickle try: import thread except ImportError: import dummy_thread as thread from htmlentitydefs import name2codepoint import HTMLParser from os import getcwdu from itertools import izip as zip unichr = unichr xrange = xrange maxsize = sys.maxint # Type aliases string_types = basestring, text_type = unicode integer_types = int, long long_type = long from io import BytesIO as OutputIO # Glue code for syntax differences def reraise(tp, value, tb=None): exec("raise tp, value, tb") def with_metaclass(meta, base=object): class _DjangoBase(base): __metaclass__ = meta return _DjangoBase iteritems = lambda o: o.iteritems() itervalues = lambda o: o.itervalues() iterkeys = lambda o: o.iterkeys() # n() is useful when python3 needs a str (unicode), and python2 str (bytes) n = lambda s: s.encode('utf-8') else: PY3 = True import builtins # Changed module locations from urllib.parse import (urlparse, urlunparse, urlencode, urljoin, urlsplit, urlunsplit, quote, unquote, quote_plus, unquote_plus, parse_qsl, urldefrag) from urllib.request import (urlopen, url2pathname, Request, OpenerDirector, UnknownHandler, HTTPHandler, HTTPSHandler, HTTPDefaultErrorHandler, FTPHandler, HTTPError, HTTPErrorProcessor, urlretrieve) import urllib.request as urllib2 import http.cookies as cookies import pickle try: import _thread as thread except ImportError: import _dummy_thread as thread from html.entities import name2codepoint import html.parser as HTMLParser from os import getcwd as getcwdu zip = zip unichr = chr xrange = range maxsize = sys.maxsize # Type aliases string_types = str, text_type = str integer_types = int, long_type = int from io import StringIO as OutputIO # Glue code for syntax differences def reraise(tp, value, tb=None): if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value def with_metaclass(meta, base=object): ns = dict(base=base, meta=meta) exec("""class _DjangoBase(base, metaclass=meta): pass""", ns) return ns["_DjangoBase"] iteritems = lambda o: o.items() itervalues = lambda o: o.values() iterkeys = lambda o: o.keys() n = lambda s: s
django/utils/six.py 0 → 100644 +353 −0 Original line number Diff line number Diff line """Utilities for writing code that runs on Python 2 and 3""" import operator import sys import types __author__ = "Benjamin Peterson <benjamin@python.org>" __version__ = "1.1.0" # True if we are running on Python 3. PY3 = sys.version_info[0] == 3 if PY3: string_types = str, integer_types = int, class_types = type, text_type = str binary_type = bytes MAXSIZE = sys.maxsize else: string_types = basestring, integer_types = (int, long) class_types = (type, types.ClassType) text_type = unicode binary_type = str # It's possible to have sizeof(long) != sizeof(Py_ssize_t). class X(object): def __len__(self): return 1 << 31 try: len(X()) except OverflowError: # 32-bit MAXSIZE = int((1 << 31) - 1) else: # 64-bit MAXSIZE = int((1 << 63) - 1) del X def _add_doc(func, doc): """Add documentation to a function.""" func.__doc__ = doc def _import_module(name): """Import module, returning the module after the last dot.""" __import__(name) return sys.modules[name] class _LazyDescr(object): def __init__(self, name): self.name = name def __get__(self, obj, tp): result = self._resolve() setattr(obj, self.name, result) # This is a bit ugly, but it avoids running this again. delattr(tp, self.name) return result class MovedModule(_LazyDescr): def __init__(self, name, old, new=None): super(MovedModule, self).__init__(name) if PY3: if new is None: new = name self.mod = new else: self.mod = old def _resolve(self): return _import_module(self.mod) class MovedAttribute(_LazyDescr): def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): super(MovedAttribute, self).__init__(name) if PY3: if new_mod is None: new_mod = name self.mod = new_mod if new_attr is None: if old_attr is None: new_attr = name else: new_attr = old_attr self.attr = new_attr else: self.mod = old_mod if old_attr is None: old_attr = name self.attr = old_attr def _resolve(self): module = _import_module(self.mod) return getattr(module, self.attr) class _MovedItems(types.ModuleType): """Lazy loading of moved objects""" _moved_attributes = [ MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), MovedAttribute("map", "itertools", "builtins", "imap", "map"), MovedAttribute("reload_module", "__builtin__", "imp", "reload"), MovedAttribute("reduce", "__builtin__", "functools"), MovedAttribute("StringIO", "StringIO", "io"), MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), MovedModule("builtins", "__builtin__"), MovedModule("configparser", "ConfigParser"), MovedModule("copyreg", "copy_reg"), MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), MovedModule("http_cookies", "Cookie", "http.cookies"), MovedModule("html_entities", "htmlentitydefs", "html.entities"), MovedModule("html_parser", "HTMLParser", "html.parser"), MovedModule("http_client", "httplib", "http.client"), MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), MovedModule("cPickle", "cPickle", "pickle"), MovedModule("queue", "Queue"), MovedModule("reprlib", "repr"), MovedModule("socketserver", "SocketServer"), MovedModule("tkinter", "Tkinter"), MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), MovedModule("tkinter_tix", "Tix", "tkinter.tix"), MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), MovedModule("tkinter_font", "tkFont", "tkinter.font"), MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), MovedModule("winreg", "_winreg"), ] for attr in _moved_attributes: setattr(_MovedItems, attr.name, attr) del attr moves = sys.modules["six.moves"] = _MovedItems("moves") def add_move(move): """Add an item to six.moves.""" setattr(_MovedItems, move.name, move) def remove_move(name): """Remove item from six.moves.""" try: delattr(_MovedItems, name) except AttributeError: try: del moves.__dict__[name] except KeyError: raise AttributeError("no such move, %r" % (name,)) if PY3: _meth_func = "__func__" _meth_self = "__self__" _func_code = "__code__" _func_defaults = "__defaults__" _iterkeys = "keys" _itervalues = "values" _iteritems = "items" else: _meth_func = "im_func" _meth_self = "im_self" _func_code = "func_code" _func_defaults = "func_defaults" _iterkeys = "iterkeys" _itervalues = "itervalues" _iteritems = "iteritems" if PY3: def get_unbound_function(unbound): return unbound advance_iterator = next def callable(obj): return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) else: def get_unbound_function(unbound): return unbound.im_func def advance_iterator(it): return it.next() callable = callable _add_doc(get_unbound_function, """Get the function out of a possibly unbound function""") get_method_function = operator.attrgetter(_meth_func) get_method_self = operator.attrgetter(_meth_self) get_function_code = operator.attrgetter(_func_code) get_function_defaults = operator.attrgetter(_func_defaults) def iterkeys(d): """Return an iterator over the keys of a dictionary.""" return getattr(d, _iterkeys)() def itervalues(d): """Return an iterator over the values of a dictionary.""" return getattr(d, _itervalues)() def iteritems(d): """Return an iterator over the (key, value) pairs of a dictionary.""" return getattr(d, _iteritems)() if PY3: def b(s): return s.encode("latin-1") def u(s): return s if sys.version_info[1] <= 1: def int2byte(i): return bytes((i,)) else: # This is about 2x faster than the implementation above on 3.2+ int2byte = operator.methodcaller("to_bytes", 1, "big") import io StringIO = io.StringIO BytesIO = io.BytesIO else: def b(s): return s def u(s): return unicode(s, "unicode_escape") int2byte = chr import StringIO StringIO = BytesIO = StringIO.StringIO _add_doc(b, """Byte literal""") _add_doc(u, """Text literal""") if PY3: import builtins exec_ = getattr(builtins, "exec") def reraise(tp, value, tb=None): if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value print_ = getattr(builtins, "print") del builtins else: def exec_(code, globs=None, locs=None): """Execute code in a namespace.""" if globs is None: frame = sys._getframe(1) globs = frame.f_globals if locs is None: locs = frame.f_locals del frame elif locs is None: locs = globs exec("""exec code in globs, locs""") exec_("""def reraise(tp, value, tb=None): raise tp, value, tb """) def print_(*args, **kwargs): """The new-style print function.""" fp = kwargs.pop("file", sys.stdout) if fp is None: return def write(data): if not isinstance(data, basestring): data = str(data) fp.write(data) want_unicode = False sep = kwargs.pop("sep", None) if sep is not None: if isinstance(sep, unicode): want_unicode = True elif not isinstance(sep, str): raise TypeError("sep must be None or a string") end = kwargs.pop("end", None) if end is not None: if isinstance(end, unicode): want_unicode = True elif not isinstance(end, str): raise TypeError("end must be None or a string") if kwargs: raise TypeError("invalid keyword arguments to print()") if not want_unicode: for arg in args: if isinstance(arg, unicode): want_unicode = True break if want_unicode: newline = unicode("\n") space = unicode(" ") else: newline = "\n" space = " " if sep is None: sep = space if end is None: end = newline for i, arg in enumerate(args): if i: write(sep) write(arg) write(end) _add_doc(reraise, """Reraise an exception.""") def with_metaclass(meta, base=object): """Create a base class with a metaclass.""" return meta("NewBase", (base,), {})
docs/topics/python3.txt +25 −228 Original line number Diff line number Diff line Loading @@ -2,251 +2,48 @@ Python 3 compatibility ====================== Django 1.5 introduces a compatibility layer that allows the code to be run both in Python 2 (2.6/2.7) and Python 3 (>= 3.2) (*work in progress*). Django 1.5 is the first version of Django to support Python 3. This document is not meant as a complete Python 2 to Python 3 migration guide. There are many existing resources you can read. But we describe some utilities and guidelines that we recommend you should use when you want to ensure your code can be run with both Python 2 and 3. The same code runs both on Python 2 (≥2.6.5) and Python 3 (≥3.2). To achieve this: * http://docs.python.org/py3k/howto/pyporting.html * http://python3porting.com/ - wherever possible, Django uses the six_ compatibility layer, - all modules declare ``from __future__ import unicode_literals``. django.utils.py3 ================ .. _six: http://packages.python.org/six/ This document is not meant as a Python 2 to Python 3 migration guide. There are many existing resources, including `Python's official porting guide`_. But it describes guidelines that apply to Django's code and are recommended for pluggable apps that run with both Python 2 and 3. Whenever a symbol or module has different semantics or different locations on Python 2 and Python 3, you can import it from ``django.utils.py3`` where it will be automatically converted depending on your current Python version. .. _Python's official porting guide: http://docs.python.org/py3k/howto/pyporting.html PY3 --- .. module: django.utils.six If you need to know anywhere in your code if you are running Python 3 or a previous Python 2 version, you can check the ``PY3`` boolean variable:: django.utils.six ================ from django.utils.py3 import PY3 Read the documentation of six_. It's the canonical compatibility library for supporting Python 2 and 3 in a single codebase. if PY3: # Do stuff Python 3-wise else: # Do stuff Python 2-wise ``six`` is bundled with Django: you can import it as :mod:`django.utils.six`. This should be considered as a last resort solution when it is not possible to import a compatible name from django.utils.py3, as described in the sections below. .. _string-handling: String handling =============== In Python 3, all strings are considered Unicode strings by default. Byte strings have to be prefixed with the letter 'b'. To mimic the same behaviour in Python 2, we recommend you import ``unicode_literals`` from the ``__future__`` library:: In Python 3, all strings are considered Unicode strings by default. Byte strings must be prefixed with the letter ``b``. In order to enable the same behavior in Python 2, every module must import ``unicode_literals`` from ``__future__``:: from __future__ import unicode_literals my_string = "This is an unicode literal" my_bytestring = b"This is a bytestring" Be cautious if you have to slice bytestrings. See http://docs.python.org/py3k/howto/pyporting.html#bytes-literals Different expected strings -------------------------- Some method parameters have changed the expected string type of a parameter. For example, ``strftime`` format parameter expects a bytestring on Python 2 but a normal (Unicode) string on Python 3. For these cases, ``django.utils.py3`` provides a ``n()`` function which encodes the string parameter only with Python 2. >>> from __future__ import unicode_literals >>> from datetime import datetime >>> print(datetime.date(2012, 5, 21).strftime(n("%m → %Y"))) 05 → 2012 Renamed types ============= Several types are named differently in Python 2 and Python 3. In order to keep compatibility while using those types, import their corresponding aliases from ``django.utils.py3``. =========== ========= ===================== Python 2 Python 3 django.utils.py3 =========== ========= ===================== basestring, str, string_types (tuple) unicode str text_type int, long int, integer_types (tuple) long int long_type =========== ========= ===================== String aliases -------------- Code sample:: if isinstance(foo, basestring): print("foo is a string") # I want to convert a number to a Unicode string bar = 45 bar_string = unicode(bar) Should be replaced by:: from django.utils.py3 import string_types, text_type if isinstance(foo, string_types): print("foo is a string") # I want to convert a number to a Unicode string bar = 45 bar_string = text_type(bar) No more long type ----------------- ``long`` and ``int`` types have been unified in Python 3, meaning that ``long`` is no longer available. ``django.utils.py3`` provides both ``long_type`` and ``integer_types`` aliases. For example: .. code-block:: python # Old Python 2 code my_var = long(333463247234623) if isinstance(my_var, (int, long)): # ... Should be replaced by: .. code-block:: python from django.utils.py3 import long_type, integer_types my_var = long_type(333463247234623) if isinstance(my_var, integer_types): # ... Changed module locations ======================== The following modules have changed their location in Python 3. Therefore, it is recommended to import them from the ``django.utils.py3`` compatibility layer: =============================== ====================================== ====================== Python 2 Python3 django.utils.py3 =============================== ====================================== ====================== Cookie http.cookies cookies urlparse.urlparse urllib.parse.urlparse urlparse urlparse.urlunparse urllib.parse.urlunparse urlunparse urlparse.urljoin urllib.parse.urljoin urljoin urlparse.urlsplit urllib.parse.urlsplit urlsplit urlparse.urlunsplit urllib.parse.urlunsplit urlunsplit urlparse.urldefrag urllib.parse.urldefrag urldefrag urlparse.parse_qsl urllib.parse.parse_qsl parse_qsl urllib.quote urllib.parse.quote quote urllib.unquote urllib.parse.unquote unquote urllib.quote_plus urllib.parse.quote_plus quote_plus urllib.unquote_plus urllib.parse.unquote_plus unquote_plus urllib.urlencode urllib.parse.urlencode urlencode urllib.urlopen urllib.request.urlopen urlopen urllib.url2pathname urllib.request.url2pathname url2pathname urllib.urlretrieve urllib.request.urlretrieve urlretrieve urllib2 urllib.request urllib2 urllib2.Request urllib.request.Request Request urllib2.OpenerDirector urllib.request.OpenerDirector OpenerDirector urllib2.UnknownHandler urllib.request.UnknownHandler UnknownHandler urllib2.HTTPHandler urllib.request.HTTPHandler HTTPHandler urllib2.HTTPSHandler urllib.request.HTTPSHandler HTTPSHandler urllib2.HTTPDefaultErrorHandler urllib.request.HTTPDefaultErrorHandler HTTPDefaultErrorHandler urllib2.FTPHandler urllib.request.FTPHandler FTPHandler urllib2.HTTPError urllib.request.HTTPError HTTPError urllib2.HTTPErrorProcessor urllib.request.HTTPErrorProcessor HTTPErrorProcessor htmlentitydefs.name2codepoint html.entities.name2codepoint name2codepoint HTMLParser html.parser HTMLParser cPickle/pickle pickle pickle thread/dummy_thread _thread/_dummy_thread thread os.getcwdu os.getcwd getcwdu itertools.izip zip zip sys.maxint sys.maxsize maxsize unichr chr unichr xrange range xrange =============================== ====================================== ====================== Output encoding now Unicode =========================== If you want to catch stdout/stderr output, the output content is UTF-8 encoded in Python 2, while it is Unicode strings in Python 3. You can use the OutputIO stream to capture this output:: from django.utils.py3 import OutputIO try: old_stdout = sys.stdout out = OutputIO() sys.stdout = out # Do stuff which produces standard output result = out.getvalue() finally: sys.stdout = old_stdout Dict iteritems/itervalues/iterkeys ================================== The iteritems(), itervalues() and iterkeys() methods of dictionaries do not exist any more in Python 3, simply because they represent the default items() values() and keys() behavior in Python 3. Therefore, to keep compatibility, use similar functions from ``django.utils.py3``:: from django.utils.py3 import iteritems, itervalues, iterkeys my_dict = {'a': 21, 'b': 42} for key, value in iteritems(my_dict): # ... for value in itervalues(my_dict): # ... for key in iterkeys(my_dict): # ... Note that in Python 3, dict.keys(), dict.items() and dict.values() return "views" instead of lists. Wrap them into list() if you really need their return values to be in a list. http://docs.python.org/release/3.0.1/whatsnew/3.0.html#views-and-iterators-instead-of-lists Metaclass ========= The syntax for declaring metaclasses has changed in Python 3. ``django.utils.py3`` offers a compatible way to declare metaclasses:: from django.utils.py3 import with_metaclass class MyClass(with_metaclass(SubClass1, SubClass2,...)): # ... Re-raising exceptions ===================== One of the syntaxes to raise exceptions (raise E, V, T) is gone in Python 3. This is especially used in very specific cases where you want to re-raise a different exception that the initial one, while keeping the original traceback. So, instead of:: raise Exception, Exception(msg), traceback Use:: from django.utils.py3 import reraise reraise(Exception, Exception(msg), traceback) Be cautious if you have to `slice bytestrings`_. .. _slice bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals