From 01b43dc3d93e632c3c42fb8e1105f200b9cee2ae Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Tue, 13 Aug 2019 11:15:52 +0200 Subject: Add QtCore.Slot.__signature__ and much more manually The signature of QtCore.Slot and other classes could not automatically be generated because the function is not generated by cppgenerator.cpp . We add it manually in the C++ code into the generation process. The case of QtCore.Slot had diverse follow-up issues to be solved: - Classes which did not inherit from Shiboken were not generated. This is a long-standing omission and creates very many new simple types. - The arity of Slot has default arguments after the varargs parameter "*types". This needed an extended Python parser analysis that fixes the arguments given to the inspect module, accordingly. - The signature generation was completely new implemented and relies no longer on the restricted syntax of a Python (2) function but generates signatures directly as Parameter instances. Implemented classes with hand-made signatures: QtCore.ClassInfo QtCore.MetaFunction, QtCore.MetaSignal QtCore.Property QtCore.Signal QtCore.SignalInstance QtCore.Slot QtQml.ListProperty QtQml.VolatileBool As a side effect, many more subtypes were published. Enums are done, which concludes this work. Fixes: PYSIDE-945 Fixes: PYSIDE-1052 Change-Id: Ic09f02ece3a90325519e42e4e39719beb0c27ae9 Reviewed-by: Christian Tismer --- .../files.dir/shibokensupport/signature/layout.py | 38 ++++++++++++++++------ .../shibokensupport/signature/lib/enum_sig.py | 20 +++++++++++- .../files.dir/shibokensupport/signature/mapping.py | 6 ++++ .../files.dir/shibokensupport/signature/parser.py | 14 ++++---- 4 files changed, 61 insertions(+), 17 deletions(-) (limited to 'sources/shiboken2/shibokenmodule') diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py index bd827f1ee..af8ada065 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py @@ -174,6 +174,13 @@ def make_signature_nameless(signature): signature.parameters[key].__class__ = NamelessParameter +_POSITIONAL_ONLY = inspect._POSITIONAL_ONLY +_POSITIONAL_OR_KEYWORD = inspect._POSITIONAL_OR_KEYWORD +_VAR_POSITIONAL = inspect._VAR_POSITIONAL +_KEYWORD_ONLY = inspect._KEYWORD_ONLY +_VAR_KEYWORD = inspect._VAR_KEYWORD +_empty = inspect._empty + def create_signature(props, key): if not props: # empty signatures string @@ -204,8 +211,8 @@ def create_signature(props, key): elif sig_kind == "classmethod": varnames = ("klass",) + varnames else: - raise SystemError("Methods must be function, method, staticmethod or " - "classmethod") + raise SystemError("Methods must be function, method, staticmethod" + " or classmethod") # calculate the modifications defaults = props["defaults"][:] if not layout.defaults: @@ -216,14 +223,25 @@ def create_signature(props, key): if not layout.return_annotation and "return" in annotations: del annotations["return"] - # attach parameters to a fake function and build a signature - argstr = ", ".join(varnames) - fakefunc = eval("lambda {}: None".format(argstr)) - fakefunc.__name__ = props["name"] - fakefunc.__defaults__ = defaults - fakefunc.__kwdefaults__ = props["kwdefaults"] - fakefunc.__annotations__ = annotations - sig = inspect._signature_from_function(inspect.Signature, fakefunc) + # Build a signature. + kind = inspect._POSITIONAL_OR_KEYWORD + params = [] + for idx, name in enumerate(varnames): + if name.startswith("**"): + kind = _VAR_KEYWORD + elif name.startswith("*"): + kind = _VAR_POSITIONAL + ann = annotations.get(name, _empty) + name = name.lstrip("*") + defpos = idx - len(varnames) + len(defaults) + default = defaults[defpos] if defpos >= 0 else _empty + param = inspect.Parameter(name, kind, annotation=ann, default=default) + params.append(param) + if kind == _VAR_POSITIONAL: + kind = _KEYWORD_ONLY + sig = inspect.Signature(params, + return_annotation=annotations.get('return', _empty), + __validate_parameters__=False) # the special case of nameless parameters if not layout.parameter_names: diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py index e6f6dc379..42b123046 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py @@ -52,6 +52,11 @@ by producing a lot of clarity. import sys from shibokensupport.signature import inspect from shibokensupport.signature import get_signature +try: + from PySide2.QtCore import Qt + EnumType = type(Qt.Key) +except ImportError: + EnumType = None class ExactEnumerator(object): @@ -82,7 +87,8 @@ class ExactEnumerator(object): return ret def klass(self, class_name, klass): - if not "Shiboken" in repr(klass.mro()): + modname = klass.__module__ + if not (modname.startswith("PySide2") or modname.startswith("shiboken2")): # don't look into any foreign classes! ret = self.result_type() return ret @@ -111,6 +117,8 @@ class ExactEnumerator(object): ret.update(self.function(func_name, thing)) for subclass_name, subclass in subclasses: ret.update(self.klass(subclass_name, subclass)) + if isinstance(subclass, EnumType): + self.enum(subclass) return ret def function(self, func_name, func): @@ -121,6 +129,16 @@ class ExactEnumerator(object): ret[key] = signature return ret + def enum(self, subclass): + if not hasattr(self.fmt, "enum"): + # this is an optional feature + return + class_name = subclass.__name__ + for enum_name, value in subclass.__dict__.items(): + if type(type(value)) is EnumType: + with self.fmt.enum(class_name, enum_name, int(value)): + pass + def stringify(signature): if isinstance(signature, list): diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 36b137104..10d0f16ad 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -67,6 +67,10 @@ ModelIndexList = typing.List[int] QImageCleanupFunction = typing.Callable StringList = typing.List[str] +# unfortunately, typing.Optional[t] expands to typing.Union[t, NoneType] +# Until we can force it to create Optional[t] again, we use this. +NoneType = type(None) + _S = TypeVar("_S") # Building our own Char type, which is much nicer than @@ -316,6 +320,7 @@ type_map.update({ "zero(int)": 0, "zero(object)": None, "zero(str)": "", + "...": "...", }) @@ -345,6 +350,7 @@ def init_sample(): "Foo.HANDLE": int, "HANDLE": int, "Null": None, + "nullptr": None, "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"), "OddBool": bool, "PStr": str, diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py index 6109bceee..3d14ec7b3 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py @@ -116,7 +116,7 @@ def _parse_line(line): print("KEYWORD", ret) name = name + "_" if "=" in ann: - ann, default = ann.split("=") + ann, default = ann.split("=", 1) tup = name, ann, default else: tup = name, ann @@ -167,9 +167,11 @@ def try_to_guess(thing, valtype): def _resolve_value(thing, valtype, line): if thing in ("0", "None") and valtype: - if valtype.startswith("PySide2."): + if valtype.startswith("PySide2.") or valtype.startswith("typing."): return None - name = type_map[valtype].__name__ + mapped = type_map[valtype] + # typing.Any: '_SpecialForm' object has no attribute '__name__' + name = mapped.__name__ if hasattr(mapped, "__name__") else str(mapped) thing = "zero({})".format(name) if thing in type_map: return type_map[thing] @@ -275,9 +277,9 @@ def calculate_props(line): for idx, tup in enumerate(arglist): name, ann = tup[:2] if ann == "...": - name = "*args" - # copy the fields back :() - ann = 'NULL' # maps to None + name = "*args" if name.startswith("arg_") else "*" + name + # copy the pathed fields back + ann = 'nullptr' # maps to None tup = name, ann arglist[idx] = tup annotations[name] = _resolve_type(ann, line, 0) -- cgit v1.2.3