blob: 44748d50bd292613b298f9cff5e538f87b48b718 [file] [log] [blame]
"""Utilities for writing code that runs on Python 2 and 3"""
import sys
import types
__author__ = "Benjamin Peterson <benjamin@python.org>"
__version__ = "1.0b1"
# 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
MAXSIZE = sys.maxint
def _add_doc(func, doc):
"""Add documentation to a function."""
func.__doc__ = doc
def _import_module(name):
"""Import module, returning last module in string."""
__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 _Module(_LazyDescr):
def __init__(self, name, old, new=None):
super(_Module, 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 _Attribute(_LazyDescr):
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
super(_Attribute, 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 = [
_Attribute("cStringIO", "cStringIO", "io", "StringIO"),
_Attribute("reload_module", "__builtin__", "imp", "reload"),
_Attribute("reduce", "__builtin__", "functools"),
_Attribute("StringIO", "StringIO", "io"),
_Attribute("xrange", "__builtin__", "builtins", "xrange", "range"),
_Module("builtins", "__builtin__"),
_Module("configparser", "ConfigParser"),
_Module("copyreg", "copy_reg"),
_Module("http_cookiejar", "cookielib", "http.cookiejar"),
_Module("http_cookies", "Cookie", "http.cookies"),
_Module("html_entities", "htmlentitydefs", "html.entities"),
_Module("html_parser", "HTMLParser", "html.parser"),
_Module("http_client", "httplib", "http.client"),
_Module("BaseHTTPServer", "BaseHTTPServer", "http.server"),
_Module("CGIHTTPServer", "CGIHTTPServer", "http.server"),
_Module("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
_Module("cPickle", "cPickle", "pickle"),
_Module("queue", "Queue"),
_Module("reprlib", "repr"),
_Module("socketserver", "SocketServer"),
_Module("tkinter", "Tkinter"),
_Module("tkinter_dialog", "Dialog", "tkinter.dialog"),
_Module("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
_Module("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
_Module("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
_Module("tkinter_tix", "Tix", "tkinter.tix"),
_Module("tkinter_constants", "Tkconstants", "tkinter.constants"),
_Module("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
_Module("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"),
_Module("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"),
_Module("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
_Module("tkinter_font", "tkFont", "tkinter.font"),
_Module("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
_Module("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"),
_Module("urllib_robotparser", "robotparser", "urllib.robotparser"),
_Module("winreg", "_winreg"),
]
for attr in _moved_attributes:
setattr(_MovedItems, attr.name, attr)
del attr
moves = sys.modules["six.moves"] = _MovedItems("moves")
if PY3:
_meth_func = "__func__"
_meth_self = "__self__"
_func_code = "__code__"
_func_defaults = "__defaults__"
else:
_meth_func = "im_func"
_meth_self = "im_self"
_func_code = "func_code"
_func_defaults = "func_defaults"
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""")
def get_method_function(meth):
"""Get the underlying function of a bound method."""
return getattr(meth, _meth_func)
def get_method_self(meth):
"""Get the self of a bound method."""
return getattr(meth, _meth_self)
def get_function_code(func):
"""Get code object of a function."""
return getattr(func, _func_code)
def get_function_defaults(func):
"""Get defaults of a function."""
return getattr(func, _func_defaults)
if PY3:
def b(s):
return s.encode("latin-1")
def u(s):
return s
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
else:
def b(s):
return s
def u(s):
return unicode(s)
import StringIO
StringIO = BytesIO = StringIO.StringIO
_add_doc(b, """Byte literal""")
_add_doc(u, """Text literal""")
if PY3:
exec_ = eval("exec")
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
print_ = eval("print")
def with_metaclass(meta, base=object):
ns = dict(base=base, meta=meta)
exec_("""class NewBase(base, metaclass=meta):
pass""", ns)
return ns["NewBase"]
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)
def with_metaclass(meta, base=object):
class NewBase(base):
__metaclass__ = meta
return NewBase
_add_doc(reraise, """Reraise an exception.""")
_add_doc(with_metaclass, """Create a base class with a metaclass""")