1 """Utilities for writing code that runs on Python 2 and 3"""
3 # Copyright (c) 2010-2013 Benjamin Peterson
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included in all
13 # copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 __author__
= "Benjamin Peterson <benjamin@python.org>"
31 # Useful for very coarse version differentiation.
32 PY2
= sys
.version_info
[0] == 2
33 PY3
= sys
.version_info
[0] == 3
44 string_types
= basestring
,
45 integer_types
= (int, long)
46 class_types
= (type, types
.ClassType
)
50 if sys
.platform
.startswith("java"):
51 # Jython always uses 32 bits.
52 MAXSIZE
= int((1 << 31) - 1)
54 # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
62 MAXSIZE
= int((1 << 31) - 1)
65 MAXSIZE
= int((1 << 63) - 1)
69 def _add_doc(func
, doc
):
70 """Add documentation to a function."""
74 def _import_module(name
):
75 """Import module, returning the module after the last dot."""
77 return sys
.modules
[name
]
80 class _LazyDescr(object):
82 def __init__(self
, name
):
85 def __get__(self
, obj
, tp
):
86 result
= self
._resolve
()
87 setattr(obj
, self
.name
, result
)
88 # This is a bit ugly, but it avoids running this again.
89 delattr(tp
, self
.name
)
93 class MovedModule(_LazyDescr
):
95 def __init__(self
, name
, old
, new
=None):
96 super(MovedModule
, self
).__init
__(name
)
105 return _import_module(self
.mod
)
108 class MovedAttribute(_LazyDescr
):
110 def __init__(self
, name
, old_mod
, new_mod
, old_attr
=None, new_attr
=None):
111 super(MovedAttribute
, self
).__init
__(name
)
129 module
= _import_module(self
.mod
)
130 return getattr(module
, self
.attr
)
134 class _MovedItems(types
.ModuleType
):
135 """Lazy loading of moved objects"""
138 _moved_attributes
= [
139 MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
140 MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
141 MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
142 MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
143 MovedAttribute("map", "itertools", "builtins", "imap", "map"),
144 MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
145 MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
146 MovedAttribute("reduce", "__builtin__", "functools"),
147 MovedAttribute("StringIO", "StringIO", "io"),
148 MovedAttribute("UserString", "UserString", "collections"),
149 MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
150 MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
151 MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
153 MovedModule("builtins", "__builtin__"),
154 MovedModule("configparser", "ConfigParser"),
155 MovedModule("copyreg", "copy_reg"),
156 MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
157 MovedModule("http_cookies", "Cookie", "http.cookies"),
158 MovedModule("html_entities", "htmlentitydefs", "html.entities"),
159 MovedModule("html_parser", "HTMLParser", "html.parser"),
160 MovedModule("http_client", "httplib", "http.client"),
161 MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
162 MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
163 MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
164 MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
165 MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
166 MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
167 MovedModule("cPickle", "cPickle", "pickle"),
168 MovedModule("queue", "Queue"),
169 MovedModule("reprlib", "repr"),
170 MovedModule("socketserver", "SocketServer"),
171 MovedModule("tkinter", "Tkinter"),
172 MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
173 MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
174 MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
175 MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
176 MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
177 MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
178 MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
179 MovedModule("tkinter_colorchooser", "tkColorChooser",
180 "tkinter.colorchooser"),
181 MovedModule("tkinter_commondialog", "tkCommonDialog",
182 "tkinter.commondialog"),
183 MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
184 MovedModule("tkinter_font", "tkFont", "tkinter.font"),
185 MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
186 MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
187 "tkinter.simpledialog"),
188 MovedModule("urllib_parse", __name__
+ ".moves.urllib_parse", "urllib.parse"),
189 MovedModule("urllib_error", __name__
+ ".moves.urllib_error", "urllib.error"),
190 MovedModule("urllib", __name__
+ ".moves.urllib", __name__
+ ".moves.urllib"),
191 MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
192 MovedModule("winreg", "_winreg"),
194 for attr
in _moved_attributes
:
195 setattr(_MovedItems
, attr
.name
, attr
)
198 moves
= sys
.modules
[__name__
+ ".moves"] = _MovedItems(__name__
+ ".moves")
202 class Module_six_moves_urllib_parse(types
.ModuleType
):
203 """Lazy loading of moved objects in six.moves.urllib_parse"""
206 _urllib_parse_moved_attributes
= [
207 MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
208 MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
209 MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
210 MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
211 MovedAttribute("urljoin", "urlparse", "urllib.parse"),
212 MovedAttribute("urlparse", "urlparse", "urllib.parse"),
213 MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
214 MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
215 MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
216 MovedAttribute("quote", "urllib", "urllib.parse"),
217 MovedAttribute("quote_plus", "urllib", "urllib.parse"),
218 MovedAttribute("unquote", "urllib", "urllib.parse"),
219 MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
220 MovedAttribute("urlencode", "urllib", "urllib.parse"),
222 for attr
in _urllib_parse_moved_attributes
:
223 setattr(Module_six_moves_urllib_parse
, attr
.name
, attr
)
226 sys
.modules
[__name__
+ ".moves.urllib_parse"] = Module_six_moves_urllib_parse(__name__
+ ".moves.urllib_parse")
227 sys
.modules
[__name__
+ ".moves.urllib.parse"] = Module_six_moves_urllib_parse(__name__
+ ".moves.urllib.parse")
230 class Module_six_moves_urllib_error(types
.ModuleType
):
231 """Lazy loading of moved objects in six.moves.urllib_error"""
234 _urllib_error_moved_attributes
= [
235 MovedAttribute("URLError", "urllib2", "urllib.error"),
236 MovedAttribute("HTTPError", "urllib2", "urllib.error"),
237 MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
239 for attr
in _urllib_error_moved_attributes
:
240 setattr(Module_six_moves_urllib_error
, attr
.name
, attr
)
243 sys
.modules
[__name__
+ ".moves.urllib_error"] = Module_six_moves_urllib_error(__name__
+ ".moves.urllib_error")
244 sys
.modules
[__name__
+ ".moves.urllib.error"] = Module_six_moves_urllib_error(__name__
+ ".moves.urllib.error")
247 class Module_six_moves_urllib_request(types
.ModuleType
):
248 """Lazy loading of moved objects in six.moves.urllib_request"""
251 _urllib_request_moved_attributes
= [
252 MovedAttribute("urlopen", "urllib2", "urllib.request"),
253 MovedAttribute("install_opener", "urllib2", "urllib.request"),
254 MovedAttribute("build_opener", "urllib2", "urllib.request"),
255 MovedAttribute("pathname2url", "urllib", "urllib.request"),
256 MovedAttribute("url2pathname", "urllib", "urllib.request"),
257 MovedAttribute("getproxies", "urllib", "urllib.request"),
258 MovedAttribute("Request", "urllib2", "urllib.request"),
259 MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
260 MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
261 MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
262 MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
263 MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
264 MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
265 MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
266 MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
267 MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
268 MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
269 MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
270 MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
271 MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
272 MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
273 MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
274 MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
275 MovedAttribute("FileHandler", "urllib2", "urllib.request"),
276 MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
277 MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
278 MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
279 MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
280 MovedAttribute("urlretrieve", "urllib", "urllib.request"),
281 MovedAttribute("urlcleanup", "urllib", "urllib.request"),
282 MovedAttribute("URLopener", "urllib", "urllib.request"),
283 MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
285 for attr
in _urllib_request_moved_attributes
:
286 setattr(Module_six_moves_urllib_request
, attr
.name
, attr
)
289 sys
.modules
[__name__
+ ".moves.urllib_request"] = Module_six_moves_urllib_request(__name__
+ ".moves.urllib_request")
290 sys
.modules
[__name__
+ ".moves.urllib.request"] = Module_six_moves_urllib_request(__name__
+ ".moves.urllib.request")
293 class Module_six_moves_urllib_response(types
.ModuleType
):
294 """Lazy loading of moved objects in six.moves.urllib_response"""
297 _urllib_response_moved_attributes
= [
298 MovedAttribute("addbase", "urllib", "urllib.response"),
299 MovedAttribute("addclosehook", "urllib", "urllib.response"),
300 MovedAttribute("addinfo", "urllib", "urllib.response"),
301 MovedAttribute("addinfourl", "urllib", "urllib.response"),
303 for attr
in _urllib_response_moved_attributes
:
304 setattr(Module_six_moves_urllib_response
, attr
.name
, attr
)
307 sys
.modules
[__name__
+ ".moves.urllib_response"] = Module_six_moves_urllib_response(__name__
+ ".moves.urllib_response")
308 sys
.modules
[__name__
+ ".moves.urllib.response"] = Module_six_moves_urllib_response(__name__
+ ".moves.urllib.response")
311 class Module_six_moves_urllib_robotparser(types
.ModuleType
):
312 """Lazy loading of moved objects in six.moves.urllib_robotparser"""
315 _urllib_robotparser_moved_attributes
= [
316 MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
318 for attr
in _urllib_robotparser_moved_attributes
:
319 setattr(Module_six_moves_urllib_robotparser
, attr
.name
, attr
)
322 sys
.modules
[__name__
+ ".moves.urllib_robotparser"] = Module_six_moves_urllib_robotparser(__name__
+ ".moves.urllib_robotparser")
323 sys
.modules
[__name__
+ ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(__name__
+ ".moves.urllib.robotparser")
326 class Module_six_moves_urllib(types
.ModuleType
):
327 """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
328 parse
= sys
.modules
[__name__
+ ".moves.urllib_parse"]
329 error
= sys
.modules
[__name__
+ ".moves.urllib_error"]
330 request
= sys
.modules
[__name__
+ ".moves.urllib_request"]
331 response
= sys
.modules
[__name__
+ ".moves.urllib_response"]
332 robotparser
= sys
.modules
[__name__
+ ".moves.urllib_robotparser"]
335 sys
.modules
[__name__
+ ".moves.urllib"] = Module_six_moves_urllib(__name__
+ ".moves.urllib")
339 """Add an item to six.moves."""
340 setattr(_MovedItems
, move
.name
, move
)
343 def remove_move(name
):
344 """Remove item from six.moves."""
346 delattr(_MovedItems
, name
)
347 except AttributeError:
349 del moves
.__dict
__[name
]
351 raise AttributeError("no such move, %r" % (name
,))
355 _meth_func
= "__func__"
356 _meth_self
= "__self__"
358 _func_closure
= "__closure__"
359 _func_code
= "__code__"
360 _func_defaults
= "__defaults__"
361 _func_globals
= "__globals__"
364 _itervalues
= "values"
368 _meth_func
= "im_func"
369 _meth_self
= "im_self"
371 _func_closure
= "func_closure"
372 _func_code
= "func_code"
373 _func_defaults
= "func_defaults"
374 _func_globals
= "func_globals"
376 _iterkeys
= "iterkeys"
377 _itervalues
= "itervalues"
378 _iteritems
= "iteritems"
379 _iterlists
= "iterlists"
383 advance_iterator
= next
385 def advance_iterator(it
):
387 next
= advance_iterator
394 return any("__call__" in klass
.__dict
__ for klass
in type(obj
).__mro
__)
398 def get_unbound_function(unbound
):
401 create_bound_method
= types
.MethodType
405 def get_unbound_function(unbound
):
406 return unbound
.im_func
408 def create_bound_method(func
, obj
):
409 return types
.MethodType(func
, obj
, obj
.__class
__)
411 class Iterator(object):
414 return type(self
).__next
__(self
)
417 _add_doc(get_unbound_function
,
418 """Get the function out of a possibly unbound function""")
421 get_method_function
= operator
.attrgetter(_meth_func
)
422 get_method_self
= operator
.attrgetter(_meth_self
)
423 get_function_closure
= operator
.attrgetter(_func_closure
)
424 get_function_code
= operator
.attrgetter(_func_code
)
425 get_function_defaults
= operator
.attrgetter(_func_defaults
)
426 get_function_globals
= operator
.attrgetter(_func_globals
)
429 def iterkeys(d
, **kw
):
430 """Return an iterator over the keys of a dictionary."""
431 return iter(getattr(d
, _iterkeys
)(**kw
))
433 def itervalues(d
, **kw
):
434 """Return an iterator over the values of a dictionary."""
435 return iter(getattr(d
, _itervalues
)(**kw
))
437 def iteritems(d
, **kw
):
438 """Return an iterator over the (key, value) pairs of a dictionary."""
439 return iter(getattr(d
, _iteritems
)(**kw
))
441 def iterlists(d
, **kw
):
442 """Return an iterator over the (key, [values]) pairs of a dictionary."""
443 return iter(getattr(d
, _iterlists
)(**kw
))
448 return s
.encode("latin-1")
452 if sys
.version_info
[1] <= 1:
456 # This is about 2x faster than the implementation above on 3.2+
457 int2byte
= operator
.methodcaller("to_bytes", 1, "big")
458 byte2int
= operator
.itemgetter(0)
459 indexbytes
= operator
.getitem
462 StringIO
= io
.StringIO
468 return unicode(s
, "unicode_escape")
473 def indexbytes(buf
, i
):
476 return (ord(byte
) for byte
in buf
)
478 StringIO
= BytesIO
= StringIO
.StringIO
479 _add_doc(b
, """Byte literal""")
480 _add_doc(u
, """Text literal""")
485 exec_
= getattr(builtins
, "exec")
488 def reraise(tp
, value
, tb
=None):
489 if value
.__traceback
__ is not tb
:
490 raise value
.with_traceback(tb
)
494 print_
= getattr(builtins
, "print")
498 def exec_(_code_
, _globs_
=None, _locs_
=None):
499 """Execute code in a namespace."""
501 frame
= sys
._getframe
(1)
502 _globs_
= frame
.f_globals
504 _locs_
= frame
.f_locals
508 exec("""exec _code_ in _globs_, _locs_""")
511 exec_("""def reraise(tp, value, tb=None):
516 def print_(*args
, **kwargs
):
517 """The new-style print function."""
518 fp
= kwargs
.pop("file", sys
.stdout
)
522 if not isinstance(data
, basestring
):
526 sep
= kwargs
.pop("sep", None)
528 if isinstance(sep
, unicode):
530 elif not isinstance(sep
, str):
531 raise TypeError("sep must be None or a string")
532 end
= kwargs
.pop("end", None)
534 if isinstance(end
, unicode):
536 elif not isinstance(end
, str):
537 raise TypeError("end must be None or a string")
539 raise TypeError("invalid keyword arguments to print()")
542 if isinstance(arg
, unicode):
546 newline
= unicode("\n")
555 for i
, arg
in enumerate(args
):
561 _add_doc(reraise
, """Reraise an exception.""")
564 def with_metaclass(meta
, *bases
):
565 """Create a base class with a metaclass."""
566 return meta("NewBase", bases
, {})
568 def add_metaclass(metaclass
):
569 """Class decorator for creating a class with a metaclass."""
571 orig_vars
= cls
.__dict
__.copy()
572 orig_vars
.pop('__dict__', None)
573 orig_vars
.pop('__weakref__', None)
574 for slots_var
in orig_vars
.get('__slots__', ()):
575 orig_vars
.pop(slots_var
)
576 return metaclass(cls
.__name
__, cls
.__bases
__, orig_vars
)