diff options
Diffstat (limited to 'sources/pyside2/PySide2/support/signature/parser.py')
-rw-r--r-- | sources/pyside2/PySide2/support/signature/parser.py | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/sources/pyside2/PySide2/support/signature/parser.py b/sources/pyside2/PySide2/support/signature/parser.py new file mode 100644 index 000000000..0224095b5 --- /dev/null +++ b/sources/pyside2/PySide2/support/signature/parser.py @@ -0,0 +1,229 @@ +############################################################################# +## +## Copyright (C) 2017 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of PySide2. +## +## $QT_BEGIN_LICENSE:LGPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 3 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL3 included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 3 requirements +## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 2.0 or (at your option) the GNU General +## Public license version 3 or any later version approved by the KDE Free +## Qt Foundation. The licenses are as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-2.0.html and +## https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from __future__ import print_function, absolute_import + +import sys +import re +import warnings +import types +import keyword +import functools +from .mapping import type_map, update_mapping, __dict__ as namespace + +_DEBUG = False + +TYPE_MAP_DOC = """ + The type_map variable is central for the signature package. + + PySide has a new function 'CppGenerator::writeSignatureInfo()' + that extracts the gathered information about the function arguments + and defaults as good as it can. But what PySide generates is still + very C-ish and has many constants that Python doesn't understand. + + The function 'try_to_guess()' below understands a lot of PySide's + peculiar way to assume local context. If it is able to do the guess, + then the result is inserted into the dict, so the search happens + not again. For everything that is not covered by these automatic + guesses, we provide an entry in 'type_map' that resolves it. + + In effect, 'type_map' maps text to real Python objects. +""" + +def dprint(*args, **kw): + if _DEBUG: + import pprint + for arg in args: + pprint.pprint(arg) + +def _parse_line(line): + line_re = r""" + ((?P<multi> ([0-9]+)) : )? # the optional multi-index + (?P<funcname> \w+(\.\w+)*) # the function name + \( (?P<arglist> .*?) \) # the argument list + ( -> (?P<returntype> .*) )? # the optional return type + $ + """ + ret = re.match(line_re, line, re.VERBOSE).groupdict() + arglist = ret["arglist"] + arglist = list(x.strip() for x in re.split(r""" + ( + (?: # inner group is not capturing + [^,()] # no commas or braces + | + \( + (?: + [^()]* # or one brace pair + | + \( + [^()]* # or doubls nested pair + \) + )* + \) + )+ # longest possible span + ) # this list is interspersed with "," and surrounded by "" + """, arglist, flags=re.VERBOSE) + if x.strip() not in ("", ",")) + args = [] + for arg in arglist: + name, ann = arg.split(":") + if name in keyword.kwlist: + name = name + "_" + if "=" in ann: + ann, default = ann.split("=") + tup = name, ann, default + else: + tup = name, ann + args.append(tup) + ret["arglist"] = args + multi = ret["multi"] + if multi is not None: + ret["multi"] = int(multi) + return ret + +def _resolve_number(thing): + try: + return eval(thing, namespace) + except Exception: + return None + +def try_to_guess(thing, valtype): + res = _resolve_number(thing) + if res is not None: + return res + if "." not in thing and "(" not in thing: + text = "{}.{}".format(valtype, thing) + try: + return eval(text, namespace) + except Exception: + pass + typewords = valtype.split(".") + valwords = thing.split(".") + braceless = valwords[0] + if "(" in braceless: + braceless = braceless[:braceless.index("(")] + for idx, w in enumerate(typewords): + if w == braceless: + text = ".".join(typewords[:idx] + valwords) + try: + return eval(text, namespace) + except Exception: + pass + return None + +def _resolve_value(thing, valtype, line): + if thing in type_map: + return type_map[thing] + try: + res = eval(thing, namespace) + type_map[thing] = res + return res + except Exception: + pass + res = try_to_guess(thing, valtype) if valtype else None + if res is not None: + type_map[thing] = res + return res + warnings.warn("""pyside_type_init: + + UNRECOGNIZED: {!r} + OFFENDING LINE: {!r} + """.format(thing, line), RuntimeWarning) + return thing + +def _resolve_type(thing, line): + return _resolve_value(thing, None, line) + +def calculate_props(line): + line = line.strip() + res = _parse_line(line) + arglist = res["arglist"] + annotations = {} + _defaults = [] + for tup in arglist: + name, ann = tup[:2] + annotations[name] = _resolve_type(ann, line) + if len(tup) == 3: + default = _resolve_value(tup[2], ann, line) + _defaults.append(default) + defaults = tuple(_defaults) + returntype = res["returntype"] + if returntype is not None: + annotations["return"] = _resolve_type(returntype, line) + props = {} + props["defaults"] = defaults + props["kwdefaults"] = {} + props["annotations"] = annotations + props["varnames"] = varnames = tuple(tup[0] for tup in arglist) + funcname = res["funcname"] + props["fullname"] = funcname + shortname = funcname[funcname.rindex(".")+1:] + props["name"] = shortname + props["multi"] = res["multi"] + return props + +def pyside_type_init(typemod, sig_str): + dprint() + if type(typemod) is types.ModuleType: + dprint("Initialization of module '{}'".format(typemod.__name__)) + else: + dprint("Initialization of type '{}.{}'".format(typemod.__module__, + typemod.__name__)) + update_mapping() + ret = {} + multi_props = [] + for line in sig_str.strip().splitlines(): + props = calculate_props(line) + shortname = props["name"] + multi = props["multi"] + if multi is None: + ret[shortname] = props + dprint(props) + else: + fullname = props.pop("fullname") + multi_props.append(props) + if multi > 0: + continue + multi_props = {"multi": multi_props, "fullname": fullname} + ret[shortname] = multi_props + dprint(multi_props) + multi_props = [] + return ret + +# end of file |