1"""Utilities for writing code that runs on Python 2 and 3"""
2
3# Copyright (c) 2010-2014 Benjamin Peterson
4#
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:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
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
21# SOFTWARE.
22
23import operator
24import sys
25import types
26
27__author__ = "Benjamin Peterson <benjamin@python.org>"
28__version__ = "1.6.1"
29
30# Useful for very coarse version differentiation.
31PY2 = sys.version_info[0] == 2
32PY3 = sys.version_info[0] == 3
33
34if PY3:
35    string_types = str,
36    integer_types = int,
37    class_types = type,
38    text_type = str
39    binary_type = bytes
40
41    MAXSIZE = sys.maxsize
42else:
43    string_types = basestring,
44    integer_types = (int, long)
45    class_types = (type, types.ClassType)
46    text_type = unicode
47    binary_type = str
48
49    if sys.platform.startswith("java"):
50        # Jython always uses 32 bits.
51        MAXSIZE = int((1 << 31) - 1)
52    else:
53        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
54        class X(object):
55
56            def __len__(self):
57                return 1 << 31
58
59        try:
60            len(X())
61        except OverflowError:
62            # 32-bit
63            MAXSIZE = int((1 << 31) - 1)
64        else:
65            # 64-bit
66            MAXSIZE = int((1 << 63) - 1)
67        del X
68
69
70def _add_doc(func, doc):
71    """Add documentation to a function."""
72    func.__doc__ = doc
73
74
75def _import_module(name):
76    """Import module, returning the module after the last dot."""
77    __import__(name)
78    return sys.modules[name]
79
80
81class _LazyDescr(object):
82
83    def __init__(self, name):
84        self.name = name
85
86    def __get__(self, obj, tp):
87        try:
88            result = self._resolve()
89        except ImportError:
90            # See the nice big comment in MovedModule.__getattr__.
91            raise AttributeError("%s could not be imported " % self.name)
92        setattr(obj, self.name, result)  # Invokes __set__.
93        # This is a bit ugly, but it avoids running this again.
94        delattr(obj.__class__, self.name)
95        return result
96
97
98class MovedModule(_LazyDescr):
99
100    def __init__(self, name, old, new=None):
101        super(MovedModule, self).__init__(name)
102        if PY3:
103            if new is None:
104                new = name
105            self.mod = new
106        else:
107            self.mod = old
108
109    def _resolve(self):
110        return _import_module(self.mod)
111
112    def __getattr__(self, attr):
113        # It turns out many Python frameworks like to traverse sys.modules and
114        # try to load various attributes. This causes problems if this is a
115        # platform-specific module on the wrong platform, like _winreg on
116        # Unixes. Therefore, we silently pretend unimportable modules do not
117        # have any attributes. See issues #51, #53, #56, and #63 for the full
118        # tales of woe.
119        #
120        # First, if possible, avoid loading the module just to look at __file__,
121        # __name__, or __path__.
122        if (attr in ("__file__", "__name__", "__path__") and self.mod not in sys.modules):
123            raise AttributeError(attr)
124        try:
125            _module = self._resolve()
126        except ImportError:
127            raise AttributeError(attr)
128        value = getattr(_module, attr)
129        setattr(self, attr, value)
130        return value
131
132
133class _LazyModule(types.ModuleType):
134
135    def __init__(self, name):
136        super(_LazyModule, self).__init__(name)
137        self.__doc__ = self.__class__.__doc__
138
139    def __dir__(self):
140        attrs = ["__doc__", "__name__"]
141        attrs += [attr.name for attr in self._moved_attributes]
142        return attrs
143
144    # Subclasses should override this
145    _moved_attributes = []
146
147
148class MovedAttribute(_LazyDescr):
149
150    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
151        super(MovedAttribute, self).__init__(name)
152        if PY3:
153            if new_mod is None:
154                new_mod = name
155            self.mod = new_mod
156            if new_attr is None:
157                if old_attr is None:
158                    new_attr = name
159                else:
160                    new_attr = old_attr
161            self.attr = new_attr
162        else:
163            self.mod = old_mod
164            if old_attr is None:
165                old_attr = name
166            self.attr = old_attr
167
168    def _resolve(self):
169        module = _import_module(self.mod)
170        return getattr(module, self.attr)
171
172
173class _MovedItems(_LazyModule):
174    """Lazy loading of moved objects"""
175
176
177_moved_attributes = [
178  MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
179  MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
180  MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
181  MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
182  MovedAttribute("map", "itertools", "builtins", "imap", "map"),
183  MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
184  MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
185  MovedAttribute("reduce", "__builtin__", "functools"),
186  MovedAttribute("StringIO", "StringIO", "io"),
187  MovedAttribute("UserDict", "UserDict", "collections"),
188  MovedAttribute("UserList", "UserList", "collections"),
189  MovedAttribute("UserString", "UserString", "collections"),
190  MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
191  MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
192  MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
193  MovedModule("builtins", "__builtin__"),
194  MovedModule("configparser", "ConfigParser"),
195  MovedModule("copyreg", "copy_reg"),
196  MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
197  MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
198  MovedModule("http_cookies", "Cookie", "http.cookies"),
199  MovedModule("html_entities", "htmlentitydefs", "html.entities"),
200  MovedModule("html_parser", "HTMLParser", "html.parser"),
201  MovedModule("http_client", "httplib", "http.client"),
202  MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
203  MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
204  MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
205  MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
206  MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
207  MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
208  MovedModule("cPickle", "cPickle", "pickle"),
209  MovedModule("queue", "Queue"),
210  MovedModule("reprlib", "repr"),
211  MovedModule("socketserver", "SocketServer"),
212  MovedModule("_thread", "thread", "_thread"),
213  MovedModule("tkinter", "Tkinter"),
214  MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
215  MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
216  MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
217  MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
218  MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
219  MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
220  MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
221  MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
222  MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"),
223  MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"),
224  MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
225  MovedModule("tkinter_font", "tkFont", "tkinter.font"),
226  MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
227  MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"),
228  MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
229  MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
230  MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
231  MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
232  MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
233  MovedModule("xmlrpc_server", "xmlrpclib", "xmlrpc.server"),
234  MovedModule("winreg", "_winreg"),
235]
236for attr in _moved_attributes:
237    setattr(_MovedItems, attr.name, attr)
238    if isinstance(attr, MovedModule):
239        sys.modules[__name__ + ".moves." + attr.name] = attr
240del attr
241
242_MovedItems._moved_attributes = _moved_attributes
243
244moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves")
245
246
247class Module_six_moves_urllib_parse(_LazyModule):
248    """Lazy loading of moved objects in six.moves.urllib_parse"""
249
250
251_urllib_parse_moved_attributes = [
252  MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
253  MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
254  MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
255  MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
256  MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
257  MovedAttribute("urljoin", "urlparse", "urllib.parse"),
258  MovedAttribute("urlparse", "urlparse", "urllib.parse"),
259  MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
260  MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
261  MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
262  MovedAttribute("quote", "urllib", "urllib.parse"),
263  MovedAttribute("quote_plus", "urllib", "urllib.parse"),
264  MovedAttribute("unquote", "urllib", "urllib.parse"),
265  MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
266  MovedAttribute("urlencode", "urllib", "urllib.parse"),
267  MovedAttribute("splitquery", "urllib", "urllib.parse"),
268]
269for attr in _urllib_parse_moved_attributes:
270    setattr(Module_six_moves_urllib_parse, attr.name, attr)
271del attr
272
273Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
274
275sys.modules[__name__ + ".moves.urllib_parse"] = sys.modules[
276  __name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(__name__
277                                                                    + ".moves.urllib_parse")
278
279
280class Module_six_moves_urllib_error(_LazyModule):
281    """Lazy loading of moved objects in six.moves.urllib_error"""
282
283
284_urllib_error_moved_attributes = [
285  MovedAttribute("URLError", "urllib2", "urllib.error"),
286  MovedAttribute("HTTPError", "urllib2", "urllib.error"),
287  MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
288]
289for attr in _urllib_error_moved_attributes:
290    setattr(Module_six_moves_urllib_error, attr.name, attr)
291del attr
292
293Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
294
295sys.modules[__name__ + ".moves.urllib_error"] = sys.modules[
296  __name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(__name__
297                                                                    + ".moves.urllib.error")
298
299
300class Module_six_moves_urllib_request(_LazyModule):
301    """Lazy loading of moved objects in six.moves.urllib_request"""
302
303
304_urllib_request_moved_attributes = [
305  MovedAttribute("urlopen", "urllib2", "urllib.request"),
306  MovedAttribute("install_opener", "urllib2", "urllib.request"),
307  MovedAttribute("build_opener", "urllib2", "urllib.request"),
308  MovedAttribute("pathname2url", "urllib", "urllib.request"),
309  MovedAttribute("url2pathname", "urllib", "urllib.request"),
310  MovedAttribute("getproxies", "urllib", "urllib.request"),
311  MovedAttribute("Request", "urllib2", "urllib.request"),
312  MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
313  MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
314  MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
315  MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
316  MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
317  MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
318  MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
319  MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
320  MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
321  MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
322  MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
323  MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
324  MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
325  MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
326  MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
327  MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
328  MovedAttribute("FileHandler", "urllib2", "urllib.request"),
329  MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
330  MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
331  MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
332  MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
333  MovedAttribute("urlretrieve", "urllib", "urllib.request"),
334  MovedAttribute("urlcleanup", "urllib", "urllib.request"),
335  MovedAttribute("URLopener", "urllib", "urllib.request"),
336  MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
337  MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
338]
339for attr in _urllib_request_moved_attributes:
340    setattr(Module_six_moves_urllib_request, attr.name, attr)
341del attr
342
343Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
344
345sys.modules[__name__ + ".moves.urllib_request"] = sys.modules[
346  __name__ + ".moves.urllib.request"] = Module_six_moves_urllib_request(__name__
347                                                                        + ".moves.urllib.request")
348
349
350class Module_six_moves_urllib_response(_LazyModule):
351    """Lazy loading of moved objects in six.moves.urllib_response"""
352
353
354_urllib_response_moved_attributes = [
355  MovedAttribute("addbase", "urllib", "urllib.response"),
356  MovedAttribute("addclosehook", "urllib", "urllib.response"),
357  MovedAttribute("addinfo", "urllib", "urllib.response"),
358  MovedAttribute("addinfourl", "urllib", "urllib.response"),
359]
360for attr in _urllib_response_moved_attributes:
361    setattr(Module_six_moves_urllib_response, attr.name, attr)
362del attr
363
364Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
365
366sys.modules[__name__ + ".moves.urllib_response"] = sys.modules[
367  __name__ + ".moves.urllib.response"] = Module_six_moves_urllib_response(__name__
368                                                                          + ".moves.urllib.response")
369
370
371class Module_six_moves_urllib_robotparser(_LazyModule):
372    """Lazy loading of moved objects in six.moves.urllib_robotparser"""
373
374
375_urllib_robotparser_moved_attributes = [
376  MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
377]
378for attr in _urllib_robotparser_moved_attributes:
379    setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
380del attr
381
382Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
383
384sys.modules[__name__ + ".moves.urllib_robotparser"] = sys.modules[
385  __name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(
386    __name__ + ".moves.urllib.robotparser")
387
388
389class Module_six_moves_urllib(types.ModuleType):
390    """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
391    parse = sys.modules[__name__ + ".moves.urllib_parse"]
392    error = sys.modules[__name__ + ".moves.urllib_error"]
393    request = sys.modules[__name__ + ".moves.urllib_request"]
394    response = sys.modules[__name__ + ".moves.urllib_response"]
395    robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"]
396
397    def __dir__(self):
398        return ['parse', 'error', 'request', 'response', 'robotparser']
399
400
401sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib(__name__ + ".moves.urllib")
402
403
404def add_move(move):
405    """Add an item to six.moves."""
406    setattr(_MovedItems, move.name, move)
407
408
409def remove_move(name):
410    """Remove item from six.moves."""
411    try:
412        delattr(_MovedItems, name)
413    except AttributeError:
414        try:
415            del moves.__dict__[name]
416        except KeyError:
417            raise AttributeError("no such move, %r" % (name, ))
418
419
420if PY3:
421    _meth_func = "__func__"
422    _meth_self = "__self__"
423
424    _func_closure = "__closure__"
425    _func_code = "__code__"
426    _func_defaults = "__defaults__"
427    _func_globals = "__globals__"
428else:
429    _meth_func = "im_func"
430    _meth_self = "im_self"
431
432    _func_closure = "func_closure"
433    _func_code = "func_code"
434    _func_defaults = "func_defaults"
435    _func_globals = "func_globals"
436
437try:
438    advance_iterator = next
439except NameError:
440
441    def advance_iterator(it):
442        return it.next()
443
444
445next = advance_iterator
446
447try:
448    callable = callable
449except NameError:
450
451    def callable(obj):
452        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
453
454
455if PY3:
456
457    def get_unbound_function(unbound):
458        return unbound
459
460    create_bound_method = types.MethodType
461
462    Iterator = object
463else:
464
465    def get_unbound_function(unbound):
466        return unbound.im_func
467
468    def create_bound_method(func, obj):
469        return types.MethodType(func, obj, obj.__class__)
470
471    class Iterator(object):
472
473        def next(self):
474            return type(self).__next__(self)
475
476    callable = callable
477_add_doc(get_unbound_function, """Get the function out of a possibly unbound function""")
478
479get_method_function = operator.attrgetter(_meth_func)
480get_method_self = operator.attrgetter(_meth_self)
481get_function_closure = operator.attrgetter(_func_closure)
482get_function_code = operator.attrgetter(_func_code)
483get_function_defaults = operator.attrgetter(_func_defaults)
484get_function_globals = operator.attrgetter(_func_globals)
485
486if PY3:
487
488    def iterkeys(d, **kw):
489        return iter(d.keys(**kw))
490
491    def itervalues(d, **kw):
492        return iter(d.values(**kw))
493
494    def iteritems(d, **kw):
495        return iter(d.items(**kw))
496
497    def iterlists(d, **kw):
498        return iter(d.lists(**kw))
499else:
500
501    def iterkeys(d, **kw):
502        return iter(d.iterkeys(**kw))
503
504    def itervalues(d, **kw):
505        return iter(d.itervalues(**kw))
506
507    def iteritems(d, **kw):
508        return iter(d.iteritems(**kw))
509
510    def iterlists(d, **kw):
511        return iter(d.iterlists(**kw))
512
513
514_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
515_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
516_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.")
517_add_doc(iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary.")
518
519if PY3:
520
521    def b(s):
522        return s.encode("latin-1")
523
524    def u(s):
525        return s
526
527    unichr = chr
528    if sys.version_info[1] <= 1:
529
530        def int2byte(i):
531            return bytes((i, ))
532    else:
533        # This is about 2x faster than the implementation above on 3.2+
534        int2byte = operator.methodcaller("to_bytes", 1, "big")
535    byte2int = operator.itemgetter(0)
536    indexbytes = operator.getitem
537    iterbytes = iter
538    import io
539    StringIO = io.StringIO
540    BytesIO = io.BytesIO
541else:
542
543    def b(s):
544        return s
545    # Workaround for standalone backslash
546
547    def u(s):
548        return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
549
550    unichr = unichr
551    int2byte = chr
552
553    def byte2int(bs):
554        return ord(bs[0])
555
556    def indexbytes(buf, i):
557        return ord(buf[i])
558
559    def iterbytes(buf):
560        return (ord(byte) for byte in buf)
561
562    import StringIO
563    StringIO = BytesIO = StringIO.StringIO
564_add_doc(b, """Byte literal""")
565_add_doc(u, """Text literal""")
566
567if PY3:
568    exec_ = getattr(moves.builtins, "exec")
569
570    def reraise(tp, value, tb=None):
571        if value.__traceback__ is not tb:
572            raise value.with_traceback(tb)
573        raise value
574
575else:
576
577    def exec_(_code_, _globs_=None, _locs_=None):
578        """Execute code in a namespace."""
579        if _globs_ is None:
580            frame = sys._getframe(1)
581            _globs_ = frame.f_globals
582            if _locs_ is None:
583                _locs_ = frame.f_locals
584            del frame
585        elif _locs_ is None:
586            _locs_ = _globs_
587        exec("""exec _code_ in _globs_, _locs_""")
588
589    exec_("""def reraise(tp, value, tb=None):
590    raise tp, value, tb
591""")
592
593print_ = getattr(moves.builtins, "print", None)
594if print_ is None:
595
596    def print_(*args, **kwargs):
597        """The new-style print function for Python 2.4 and 2.5."""
598        fp = kwargs.pop("file", sys.stdout)
599        if fp is None:
600            return
601
602        def write(data):
603            if not isinstance(data, basestring):
604                data = str(data)
605            # If the file has an encoding, encode unicode with it.
606            if (isinstance(fp, file) and isinstance(data, unicode) and fp.encoding is not None):
607                errors = getattr(fp, "errors", None)
608                if errors is None:
609                    errors = "strict"
610                data = data.encode(fp.encoding, errors)
611            fp.write(data)
612
613        want_unicode = False
614        sep = kwargs.pop("sep", None)
615        if sep is not None:
616            if isinstance(sep, unicode):
617                want_unicode = True
618            elif not isinstance(sep, str):
619                raise TypeError("sep must be None or a string")
620        end = kwargs.pop("end", None)
621        if end is not None:
622            if isinstance(end, unicode):
623                want_unicode = True
624            elif not isinstance(end, str):
625                raise TypeError("end must be None or a string")
626        if kwargs:
627            raise TypeError("invalid keyword arguments to print()")
628        if not want_unicode:
629            for arg in args:
630                if isinstance(arg, unicode):
631                    want_unicode = True
632                    break
633        if want_unicode:
634            newline = unicode("\n")
635            space = unicode(" ")
636        else:
637            newline = "\n"
638            space = " "
639        if sep is None:
640            sep = space
641        if end is None:
642            end = newline
643        for i, arg in enumerate(args):
644            if i:
645                write(sep)
646            write(arg)
647        write(end)
648
649
650_add_doc(reraise, """Reraise an exception.""")
651
652
653def with_metaclass(meta, *bases):
654    """Create a base class with a metaclass."""
655    return meta("NewBase", bases, {})
656
657
658def add_metaclass(metaclass):
659    """Class decorator for creating a class with a metaclass."""
660
661    def wrapper(cls):
662        orig_vars = cls.__dict__.copy()
663        orig_vars.pop('__dict__', None)
664        orig_vars.pop('__weakref__', None)
665        slots = orig_vars.get('__slots__')
666        if slots is not None:
667            if isinstance(slots, str):
668                slots = [slots]
669            for slots_var in slots:
670                orig_vars.pop(slots_var)
671        return metaclass(cls.__name__, cls.__bases__, orig_vars)
672
673    return wrapper
674
675
676# added as part of the RDKit port
677if PY3:
678
679    def cmp(t1, t2):
680        return (t1 < t2) * -1 or (t1 > t2) * 1
681else:
682    cmp = cmp
683