1# mako/compat.py
2# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
3#
4# This module is part of Mako and is released under
5# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7import collections
8import inspect
9import sys
10
11py3k = sys.version_info >= (3, 0)
12py2k = sys.version_info < (3,)
13py27 = sys.version_info >= (2, 7)
14jython = sys.platform.startswith("java")
15win32 = sys.platform.startswith("win")
16pypy = hasattr(sys, "pypy_version_info")
17
18ArgSpec = collections.namedtuple(
19    "ArgSpec", ["args", "varargs", "keywords", "defaults"]
20)
21
22
23def inspect_getargspec(func):
24    """getargspec based on fully vendored getfullargspec from Python 3.3."""
25
26    if inspect.ismethod(func):
27        func = func.__func__
28    if not inspect.isfunction(func):
29        raise TypeError("{!r} is not a Python function".format(func))
30
31    co = func.__code__
32    if not inspect.iscode(co):
33        raise TypeError("{!r} is not a code object".format(co))
34
35    nargs = co.co_argcount
36    names = co.co_varnames
37    nkwargs = co.co_kwonlyargcount if py3k else 0
38    args = list(names[:nargs])
39
40    nargs += nkwargs
41    varargs = None
42    if co.co_flags & inspect.CO_VARARGS:
43        varargs = co.co_varnames[nargs]
44        nargs = nargs + 1
45    varkw = None
46    if co.co_flags & inspect.CO_VARKEYWORDS:
47        varkw = co.co_varnames[nargs]
48
49    return ArgSpec(args, varargs, varkw, func.__defaults__)
50
51
52if py3k:
53    from io import StringIO
54    import builtins as compat_builtins
55    from urllib.parse import quote_plus, unquote_plus
56    from html.entities import codepoint2name, name2codepoint
57
58    string_types = (str,)
59    binary_type = bytes
60    text_type = str
61
62    from io import BytesIO as byte_buffer
63
64    def u(s):
65        return s
66
67    def b(s):
68        return s.encode("latin-1")
69
70    def octal(lit):
71        return eval("0o" + lit)
72
73
74else:
75    import __builtin__ as compat_builtins  # noqa
76
77    try:
78        from cStringIO import StringIO
79    except:
80        from StringIO import StringIO
81
82    byte_buffer = StringIO
83
84    from urllib import quote_plus, unquote_plus  # noqa
85    from htmlentitydefs import codepoint2name, name2codepoint  # noqa
86
87    string_types = (basestring,)  # noqa
88    binary_type = str
89    text_type = unicode  # noqa
90
91    def u(s):
92        return unicode(s, "utf-8")  # noqa
93
94    def b(s):
95        return s
96
97    def octal(lit):
98        return eval("0" + lit)
99
100
101if py3k:
102    from importlib import machinery, util
103
104    if hasattr(util, 'module_from_spec'):
105        # Python 3.5+
106        def load_module(module_id, path):
107            spec = util.spec_from_file_location(module_id, path)
108            module = util.module_from_spec(spec)
109            spec.loader.exec_module(module)
110            return module
111    else:
112        def load_module(module_id, path):
113            module = machinery.SourceFileLoader(module_id, path).load_module()
114            del sys.modules[module_id]
115            return module
116
117else:
118    import imp
119
120    def load_module(module_id, path):
121        fp = open(path, "rb")
122        try:
123            module = imp.load_source(module_id, path, fp)
124            del sys.modules[module_id]
125            return module
126        finally:
127            fp.close()
128
129
130if py3k:
131
132    def reraise(tp, value, tb=None, cause=None):
133        if cause is not None:
134            value.__cause__ = cause
135        if value.__traceback__ is not tb:
136            raise value.with_traceback(tb)
137        raise value
138
139
140else:
141    exec(
142        "def reraise(tp, value, tb=None, cause=None):\n"
143        "    raise tp, value, tb\n"
144    )
145
146
147def exception_as():
148    return sys.exc_info()[1]
149
150
151all = all  # noqa
152
153
154def exception_name(exc):
155    return exc.__class__.__name__
156
157
158################################################
159# cross-compatible metaclass implementation
160# Copyright (c) 2010-2012 Benjamin Peterson
161def with_metaclass(meta, base=object):
162    """Create a base class with a metaclass."""
163    return meta("%sBase" % meta.__name__, (base,), {})
164
165
166################################################
167
168
169def arg_stringname(func_arg):
170    """Gets the string name of a kwarg or vararg
171    In Python3.4 a function's args are
172    of _ast.arg type not _ast.name
173    """
174    if hasattr(func_arg, "arg"):
175        return func_arg.arg
176    else:
177        return str(func_arg)
178