diff options
5 files changed, 92 insertions, 38 deletions
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index c5c0c7c7f..139bc3bb7 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -729,7 +729,8 @@ void CppGenerator::generateClass(TextStream &s, if (rfunc->isConstructor()) { writeConstructorWrapper(s, overloadData, classContext); - writeSignatureInfo(signatureStream, overloadData); + // On constructors, we also generate the property initializers. + writeSignatureInfo(signatureStream, overloadData, true); } // call operators else if (rfunc->name() == u"operator()") { @@ -5284,7 +5285,8 @@ QString CppGenerator::signatureParameter(const AbstractMetaArgument &arg, bool i return result; } -void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloadData) const +void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloadData, + bool useProperties) const { const auto rfunc = overloadData.referenceFunction(); QString funcName = fullPythonFunctionName(rfunc, false); @@ -5317,6 +5319,33 @@ void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloa args.append(t); } } + // PYSIDE-1846: In a constructor, provide all properties as keyword-only parameters. + const auto &metaClass = rfunc->ownerClass(); + if (useProperties && !metaClass->propertySpecs().isEmpty()) { + args << "*:KeywordOnly=None"_L1; + for (const auto &spec : metaClass->propertySpecs()) { + auto typeEntry = spec.typeEntry(); + QString text; + if (typeEntry->isFlags()) { + const auto fte = std::static_pointer_cast<const FlagsTypeEntry>(typeEntry); + text = fte->originator()->qualifiedTargetLangName(); + } else { + text = typeEntry->qualifiedCppName(); + } + auto &inst = spec.type().instantiations(); + if (!inst.isEmpty()) { + text += u'['; + for (qsizetype i = 0, size = inst.size(); i < size; ++i) { + if (i > 0) + text += u", "_s; + text += pythonSignature(inst.at(i)); + } + text += u']'; + } + QString entry = spec.name() + u':' + text.replace(u"::"_s, u"."_s) + "=None"_L1; + args.append(entry); + } + } // mark the multiple signatures as such, to make it easier to generate different code if (multiple) diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h index 387d81ba9..dc4d4a96c 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.h +++ b/sources/shiboken6/generator/shiboken/cppgenerator.h @@ -419,7 +419,8 @@ private: QByteArrayList methodDefinitionParameters(const OverloadData &overloadData) const; QList<PyMethodDefEntry> methodDefinitionEntries(const OverloadData &overloadData) const; - void writeSignatureInfo(TextStream &s, const OverloadData &overloads) const; + void writeSignatureInfo(TextStream &s, const OverloadData &overloads, + bool useProperties=false) const; QString signatureParameter(const AbstractMetaArgument &arg, bool implicitConversions) const; QString pythonSignature(const AbstractMetaType &type) const; /// Writes the implementation of all methods part of python sequence protocol diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py index 7d5515c7c..a2d1ca121 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py @@ -171,12 +171,12 @@ def make_signature_nameless(signature): signature.parameters[key].__class__ = NamelessParameter -_POSITIONAL_ONLY = inspect.Parameter.POSITIONAL_ONLY # noqa E:201 +_POSITIONAL_ONLY = inspect.Parameter.POSITIONAL_ONLY # noqa E:201 _POSITIONAL_OR_KEYWORD = inspect.Parameter.POSITIONAL_OR_KEYWORD # noqa E:201 -_VAR_POSITIONAL = inspect.Parameter.VAR_POSITIONAL # noqa E:201 -_KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY # noqa E:201 -_VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD # noqa E:201 -_empty = inspect.Parameter.empty # noqa E:201 +_VAR_POSITIONAL = inspect.Parameter.VAR_POSITIONAL # noqa E:201 +_KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY # noqa E:201 +_VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD # noqa E:201 +_empty = inspect.Parameter.empty # noqa E:201 default_weights = { @@ -349,7 +349,13 @@ def create_signature(props, key): # Build a signature. kind = DEFAULT_PARAM_KIND params = [] + for idx, name in enumerate(varnames): + if name == "*": + # This is a switch. + # Important: It must have a default to simplify the calculation. + kind = _KEYWORD_ONLY + continue if name.startswith("**"): kind = _VAR_KEYWORD elif name.startswith("*"): @@ -360,14 +366,19 @@ def create_signature(props, key): name = name.lstrip("*") defpos = idx - len(varnames) + len(defaults) default = defaults[defpos] if defpos >= 0 else _empty + if default is not _empty: + if kind != _KEYWORD_ONLY: + kind = _POSITIONAL_OR_KEYWORD if default is None: ann = typing.Optional[ann] if default is not _empty and layout.ellipsis: default = ellipsis + # See if this is a duplicate name - happens with properties + if kind is _KEYWORD_ONLY and varnames.count(name) > 1: + continue param = inspect.Parameter(name, kind, annotation=ann, default=default) params.append(param) - if kind == _VAR_POSITIONAL: - kind = _KEYWORD_ONLY + ret_anno = annotations.get('return', _empty) if ret_anno is not _empty and props["fullname"] in missing_optional_return: ret_anno = typing.Optional[ret_anno] diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 8e12cc907..f0ef8784d 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -121,6 +121,10 @@ class Instance(_NotCalled): pass +class KeywordOnly(_NotCalled): + pass + + # Parameterized primitive variables class _Parameterized(object): def __init__(self, type): @@ -188,6 +192,10 @@ class Reloader(object): # Modules are in place, we can update the type_map. g.update(g.pop(proc_name)()) + # Also record an efficient list of modules for PySide. + if mod_name.startswith("PySide6."): + pyside_modules.add(mod_name) + def check_module(mod): # During a build, there exist the modules already as directories, @@ -202,6 +210,7 @@ def check_module(mod): update_mapping = Reloader().update type_map = {} namespace = globals() # our module's __dict__ +pyside_modules: set[str] = set() type_map.update({ "...": ellipsis, @@ -298,14 +307,6 @@ type_map.update({ "ushort": int, "void": int, # be more specific? "WId": WId, - "zero(bytes)": b"", - "zero(Char)": 0, - "zero(float)": 0, - "zero(int)": 0, - "zero(object)": None, - "zero(str)": "", - "zero(typing.Any)": None, - "zero(Any)": None, # This can be refined by importing numpy.typing optionally, but better than nothing. "numpy.ndarray": typing.List[typing.Any], "std.array[int, 4]": typing.List[int], @@ -387,8 +388,12 @@ type_map.update({ # PYSIDE-1538: We need to treat "std::optional" accordingly. type_map.update({ "std.optional": typing.Optional, - }) +}) +# PYSIDE-2846: A special keyord only switching token. +type_map.update({ + "KeywordOnly": KeywordOnly("None"), +}) # The Shiboken Part def init_Shiboken(): @@ -471,15 +476,9 @@ def init_smart(): # The PySide Part def init_PySide6_QtCore(): - from PySide6.QtCore import Qt, QUrl, QDir, QKeyCombination, QObject - from PySide6.QtCore import QRect, QRectF, QSize, QPoint, QLocale, QByteArray + from PySide6.QtCore import Qt, QUrl, QDir, QByteArray + from PySide6.QtCore import QRect, QRectF, QSize, QPoint from PySide6.QtCore import QMarginsF # 5.9 - from PySide6.QtCore import SignalInstance - try: - # seems to be not generated by 5.9 ATM. - from PySide6.QtCore import Connection - except ImportError: - pass type_map.update({ "' '": " ", @@ -506,14 +505,10 @@ def init_PySide6_QtCore(): "PySide6.QtCore.QUrl.ComponentFormattingOptions": PySide6.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why??? "PyUnicode": typing.Text, - "QByteArrayView": QByteArray, + "QByteArrayView": PySide6.QtCore.QByteArray, "Q_NULLPTR": None, "QCalendar.Unspecified": PySide6.QtCore.QCalendar.Unspecified, "QCborTag(-1)": ulong_max, - "QDir.Filters(AllEntries | NoDotAndDotDot)": Instance( - "QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)"), - "QDir.SortFlags(Name | IgnoreCase)": Instance( - "QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"), "QEvent.Type.None": None, "QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok? "QGenericArgument()": ellipsis, @@ -524,7 +519,7 @@ def init_PySide6_QtCore(): "QJsonObject": typing.Dict[str, PySide6.QtCore.QJsonValue], "QModelIndex()": Invalid("PySide6.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?! "QModelIndexList": typing.List[PySide6.QtCore.QModelIndex], - "PySideSignalInstance": SignalInstance, + "PySideSignalInstance": PySide6.QtCore.SignalInstance, "QString()": "", "Flag.Default": Instance("PySide6.QtCore.QStringConverterBase.Flags"), "QStringList()": [], @@ -537,6 +532,7 @@ def init_PySide6_QtCore(): "QVariant.Type": type, # not so sure here... "QVariantMap": typing.Dict[str, Variant], "std.chrono.seconds{5}" : ellipsis, + # new entries from property init }) try: type_map.update({ @@ -663,9 +659,7 @@ def init_PySide6_QtQuick(): def init_PySide6_QtTest(): - from PySide6.QtCore import SignalInstance type_map.update({ - "PySideSignalInstance": SignalInstance, "PySide6.QtTest.QTest.PySideQTouchEventSequence": PySide6.QtTest.QTest.QTouchEventSequence, "PySide6.QtTest.QTouchEventSequence": PySide6.QtTest.QTest.QTouchEventSequence, }) diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py index 490b8a6ec..f54a0a65b 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py @@ -13,7 +13,7 @@ import warnings from types import SimpleNamespace from shibokensupport.signature.mapping import (type_map, update_mapping, - namespace, _NotCalled, ResultVariable, ArrayLikeVariable) # noqa E:128 + namespace, _NotCalled, ResultVariable, ArrayLikeVariable, pyside_modules) # noqa E:128 from shibokensupport.signature.lib.tool import build_brace_pattern _DEBUG = False @@ -254,10 +254,11 @@ def _resolve_value(thing, valtype, line): if thing in ("0", "None") and valtype: if valtype.startswith("PySide6.") or valtype.startswith("typing."): return None - map = type_map[valtype] + mapped = type_map.get(valtype) # typing.Any: '_SpecialForm' object has no attribute '__name__' - name = get_name(map) if hasattr(map, "__name__") else str(map) + name = get_name(mapped) if hasattr(mapped, "__name__") else str(mapped) thing = f"zero({name})" + type_map[f"zero({name})"] = None if thing in type_map: return type_map[thing] res = make_good_value(thing, valtype) @@ -268,6 +269,9 @@ def _resolve_value(thing, valtype, line): if res is not None: type_map[thing] = res return res + # Still not found. Look into the imported modules. + if res := get_from_another_module(thing): + return res warnings.warn(f"""pyside_type_init:_resolve_value UNRECOGNIZED: {thing!r} @@ -323,6 +327,21 @@ def handle_matrix(arg): return eval(result, globals(), namespace) +def get_from_another_module(thing): + top = thing.split(".", 1)[0] if "." in thing else thing + for mod_name in pyside_modules: + mod = sys.modules[mod_name] + if hasattr(mod, top): + try: + res = eval(f"{mod_name}.{thing}", globals(), namespace) + type_map[thing] = res + return res + except AttributeError: + # Maybe it was anothr module... + pass + return None + + def _resolve_type(thing, line, level, var_handler, func_name=None): # manual set of 'str' instead of 'bytes' if func_name: |
