diff options
Diffstat (limited to 'sources/shiboken2')
25 files changed, 277 insertions, 121 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 05f9cf203..d7ae45ae3 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -3088,8 +3088,11 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const // Member fields need to be initialized const AbstractMetaFieldList &fields = clazz->fields(); for (AbstractMetaField *field : fields) { - addClassDependency(field->type()->typeEntry(), clazz, classIndex, - map, &graph); + auto typeEntry = field->type()->typeEntry(); + if (typeEntry->isEnum()) // Enum defined in class? + typeEntry = typeEntry->parent(); + if (typeEntry != nullptr) + addClassDependency(typeEntry, clazz, classIndex, map, &graph); } } diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index f1f01e02c..723a13164 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -2123,6 +2123,12 @@ AbstractMetaField *AbstractMetaClass::findField(const QString &name) const return AbstractMetaField::find(m_fields, name); } +bool AbstractMetaClass::hasStaticFields() const +{ + return std::any_of(m_fields.cbegin(), m_fields.cend(), + [](const AbstractMetaField *f) { return f->isStatic(); }); +} + AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName) { if (AbstractMetaEnum *e = findByName(m_enums, enumName)) @@ -2171,6 +2177,11 @@ void AbstractMetaClass::getFunctionsFromInvisibleNamespacesToBeGenerated(Abstrac } } +QString AbstractMetaClass::fullName() const +{ + return package() + QLatin1Char('.') + m_typeEntry->targetLangName(); +} + static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType *type) { if (!type) @@ -2742,4 +2753,3 @@ QString AbstractMetaEnum::package() const { return m_typeEntry->targetLangPackage(); } - diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index c100c63a1..8a0363f4c 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -84,6 +84,7 @@ public: Format fmt = Documentation::Native); bool isEmpty() const; + bool hasBrief() const { return m_data.contains(Brief); } QString value(Type t = Documentation::Detailed) const; void setValue(const QString& value, Type t = Documentation::Detailed, @@ -1424,6 +1425,8 @@ public: AbstractMetaField *findField(const QString &name) const; + bool hasStaticFields() const; + const AbstractMetaEnumList &enums() const { return m_enums; } void setEnums(const AbstractMetaEnumList &enums) { @@ -1442,10 +1445,7 @@ public: void getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionList *funcList) const; - QString fullName() const - { - return package() + QLatin1Char('.') + name(); - } + QString fullName() const; /** * Retrieves the class name without any namespace/scope information. diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp index d439b3fd5..1aeab85ed 100644 --- a/sources/shiboken2/ApiExtractor/qtdocparser.cpp +++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp @@ -41,6 +41,9 @@ #include <QtCore/QXmlStreamReader> #include <QUrl> +static inline QString briefStartElement() { return QStringLiteral("<brief>"); } +static inline QString briefEndElement() { return QStringLiteral("</brief>"); } + Documentation QtDocParser::retrieveModuleDocumentation() { return retrieveModuleDocumentation(packageName()); @@ -206,6 +209,25 @@ QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName, return result; } +// Extract the <brief> section from a WebXML (class) documentation and remove it +// from the source. +static QString extractBrief(QString *value) +{ + const auto briefStart = value->indexOf(briefStartElement()); + if (briefStart < 0) + return {}; + const auto briefEnd = value->indexOf(briefEndElement(), + briefStart + briefStartElement().size()); + if (briefEnd < briefStart) + return {}; + const auto briefLength = briefEnd + briefEndElement().size() - briefStart; + QString briefValue = value->mid(briefStart, briefLength); + briefValue.insert(briefValue.size() - briefEndElement().size(), + QLatin1String("<rst> More_...</rst>")); + value->remove(briefStart, briefLength); + return briefValue; +} + void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) { if (!metaClass) @@ -257,9 +279,17 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) signedModifs.append(docModif); } - Documentation doc(getDocumentation(xquery, query, classModifs)); - if (doc.isEmpty()) - qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query))); + QString docString = getDocumentation(xquery, query, classModifs); + if (docString.isEmpty()) { + qCWarning(lcShibokenDoc, "%s", + qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query))); + } + const QString brief = extractBrief(&docString); + + Documentation doc; + if (!brief.isEmpty()) + doc.setValue(brief, Documentation::Brief); + doc.setValue(docString); metaClass->setDocumentation(doc); //Functions Documentation diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp index 6acac41d5..cf3982a18 100644 --- a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp @@ -72,13 +72,14 @@ R"(<typesystem package="Foo"> docParser.setDocumentationDataDirectory(tempDir.path()); docParser.fillDocumentation(classA); - const QString actualDocSimplified = classA->documentation().value().simplified(); + const Documentation &doc = classA->documentation(); + const QString actualDocSimplified = doc.value(Documentation::Detailed).simplified(); + const QString actualBriefSimplified = doc.value(Documentation::Brief).simplified(); QVERIFY(!actualDocSimplified.isEmpty()); const char expectedDoc[] = R"(<?xml version="1.0"?> <description>oi -<brief>Modified Brief</brief> <para>Paragraph number 1</para> <para>Paragraph number 2</para> <para>Some changed contents here</para> @@ -86,7 +87,7 @@ R"(<?xml version="1.0"?> )"; const QString expectedDocSimplified = QString::fromLatin1(expectedDoc).simplified(); // Check whether the first modification worked. - QVERIFY(actualDocSimplified.contains(QLatin1String("Modified Brief"))); + QVERIFY(actualBriefSimplified.contains(QLatin1String("Modified Brief"))); #ifndef HAVE_LIBXSLT // QtXmlPatterns is unable to handle para[3] in style sheets, diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt index 3de5d3223..8b626af09 100644 --- a/sources/shiboken2/CMakeLists.txt +++ b/sources/shiboken2/CMakeLists.txt @@ -197,6 +197,35 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") endif() ###################################################################### +## Define the Python files involved in the build process. +## +## They are installed into the file system (see shibokenmodule) +## and embedded into the libshiboken binary through a .zip file. +###################################################################### + +set(shiboken_python_files + "signature/lib/__init__.py" + "signature/lib/enum_sig.py" + "signature/lib/tool.py" + "signature/__init__.py" + "signature/errorhandler.py" + "signature/importhandler.py" + "signature/layout.py" + "signature/loader.py" + "signature/mapping.py" + "signature/parser.py" + "__init__.py" + "feature.py" + ) + +if (PYTHON_VERSION_MAJOR LESS 3) + list(APPEND shiboken_python_files + "backport_inspect.py" + "typing27.py" + ) +endif() + +###################################################################### # Adding sub directories to build ###################################################################### add_subdirectory(ApiExtractor) diff --git a/sources/shiboken2/doc/typesystem_codeinjection.rst b/sources/shiboken2/doc/typesystem_codeinjection.rst index b0d5f3851..836609508 100644 --- a/sources/shiboken2/doc/typesystem_codeinjection.rst +++ b/sources/shiboken2/doc/typesystem_codeinjection.rst @@ -112,7 +112,8 @@ Below is the example C++ class for whom wrapper code will be generated. .. code-block:: c++ - class InjectCode { + class InjectCode + { public: InjectCode(); double overloadedMethod(int arg); @@ -124,6 +125,10 @@ From the C++ class, |project| will generate a ``injectcode_wrapper.cpp`` file with the binding code. The next section will use a simplified version of the generated wrapper code with the injection spots marked with comments. +There are a number of placeholders indicated by a percent sign ``%``, which +will be expanded when inserting the code. For a list, see +:ref:`typesystemvariables`. + Noteworthy Cases ---------------- @@ -196,7 +201,7 @@ class is polymorphic. int InjectCodeWrapper::virtualMethod(int arg) { - PyObject* method = BindingManager::instance().getOverride(this, "virtualMethod"); + PyObject *method = BindingManager::instance().getOverride(this, "virtualMethod"); if (!py_override) return this->InjectCode::virtualMethod(arg); @@ -228,10 +233,9 @@ own ``beginning`` and ``end`` code injections. .. code-block:: c++ - static PyObject* - PyInjectCode_overloadedMethod(PyObject* self, PyObject* arg) + static PyObject *PyInjectCode_overloadedMethod(PyObject *self, PyObject *arg) { - PyObject* py_result = 0; + PyObject* py_result{}; if (PyFloat_Check(arg)) { double cpp_arg0 = Shiboken::Converter<double >::toCpp(arg); @@ -250,13 +254,13 @@ own ``beginning`` and ``end`` code injections. } else goto PyInjectCode_overloadedMethod_TypeError; if (PyErr_Occurred() || !py_result) - return 0; + return {}; return py_result; PyInjectCode_overloadedMethod_TypeError: PyErr_SetString(PyExc_TypeError, "'overloadedMethod()' called with wrong parameters."); - return 0; + return {}; } @@ -371,7 +375,7 @@ to prevent bad custom code to pass unnoticed. // INJECT-CODE: <typesystem><inject-code class="target" position="beginning"> // Uses: do something before the module is created. - PyObject* module = Py_InitModule("MODULENAME", MODULENAME_methods); + PyObject *module = Py_InitModule("MODULENAME", MODULENAME_methods); (... initialization of wrapped classes, namespaces, functions and enums ...) diff --git a/sources/shiboken2/doc/typesystem_conversionrule.rst b/sources/shiboken2/doc/typesystem_conversionrule.rst index 27e7a72de..fc87a85c9 100644 --- a/sources/shiboken2/doc/typesystem_conversionrule.rst +++ b/sources/shiboken2/doc/typesystem_conversionrule.rst @@ -32,6 +32,10 @@ conversion-rule </conversion-rule> </value-type> + The code can be inserted directly, via ``add-conversion`` (providing snippet + functionality) or via ``insert-template`` (XML template, + see :ref:`using-code-templates`). + The example above show the structure of a complete conversion rule. Each of the child tags comprising the conversion rule are described in their own sections below. diff --git a/sources/shiboken2/doc/typesystem_variables.rst b/sources/shiboken2/doc/typesystem_variables.rst index 73d4dd12c..3d4638253 100644 --- a/sources/shiboken2/doc/typesystem_variables.rst +++ b/sources/shiboken2/doc/typesystem_variables.rst @@ -1,3 +1,5 @@ +.. _typesystemvariables: + ********************* Type System Variables ********************* @@ -24,9 +26,9 @@ Variables .. _arg_number: -**%#** +**%<number>** - Replaced by the name of a C++ argument in the position indicated by ``#``. + Replaced by the name of a C++ argument in the position indicated by ``<number>``. The argument counting starts with ``%1``, since ``%0`` represents the return variable name. If the number indicates a variable that was removed in the type system description, but there is a default value for it, this value will @@ -214,13 +216,13 @@ Variables .. _pyarg: -**%PYARG_#** +**%PYARG_<number>** - Similar to ``%#``, but is replaced by the Python arguments (PyObjects) + Similar to ``%<number>``, but is replaced by the Python arguments (PyObjects) received by the Python wrapper method. If used in the context of a native code injection, i.e. in a virtual method - override, ``%PYARG_#`` will be translated to one item of the Python tuple + override, ``%PYARG_<number>`` will be translated to one item of the Python tuple holding the arguments that should be passed to the Python override for this virtual method. diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp index 5e75cbf87..d330d8c18 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -1588,30 +1588,6 @@ static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaCl s << classes.join(QLatin1String(", ")) << Qt::endl << Qt::endl; } -// Extract the <brief> section from a WebXML (class) documentation and remove it -// from the source. -static bool extractBrief(Documentation *sourceDoc, Documentation *brief) -{ - if (sourceDoc->format() != Documentation::Native) - return false; - QString value = sourceDoc->value(); - const int briefStart = value.indexOf(briefStartElement()); - if (briefStart < 0) - return false; - const int briefEnd = value.indexOf(briefEndElement(), briefStart + briefStartElement().size()); - if (briefEnd < briefStart) - return false; - const int briefLength = briefEnd + briefEndElement().size() - briefStart; - brief->setFormat(Documentation::Native); - QString briefValue = value.mid(briefStart, briefLength); - briefValue.insert(briefValue.size() - briefEndElement().size(), - QLatin1String("<rst> More_...</rst>")); - brief->setValue(briefValue); - value.remove(briefStart, briefLength); - sourceDoc->setValue(value); - return true; -} - void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &classContext) { const AbstractMetaClass *metaClass = classContext.metaClass(); @@ -1630,9 +1606,8 @@ void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &class s << Pad('*', className.count()) << Qt::endl << Qt::endl; auto documentation = metaClass->documentation(); - Documentation brief; - if (extractBrief(&documentation, &brief)) - writeFormattedText(s, brief.value(), metaClass); + if (documentation.hasBrief()) + writeFormattedText(s, documentation.value(Documentation::Brief), metaClass); s << ".. inheritance-diagram:: " << metaClass->fullName() << Qt::endl << " :parts: 2" << Qt::endl << Qt::endl; @@ -1659,7 +1634,7 @@ void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &class writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, nullptr); if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, nullptr)) - writeFormattedText(s, documentation.value(), metaClass); + writeFormattedText(s, documentation.value(Documentation::Detailed), metaClass); if (!metaClass->isNamespace()) writeConstructors(s, metaClass); @@ -1972,7 +1947,7 @@ bool QtDocGenerator::writeInjectDocumentation(QTextStream& s, continue; doc.setValue(mod.code(), Documentation::Detailed, fmt); - writeFormattedText(s, doc.value(), cppClass); + writeFormattedText(s, doc, cppClass); didSomething = true; } } diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index c84557180..9739dfef6 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -762,6 +762,9 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo writeConverterFunctions(s, metaClass, classContext); writeClassRegister(s, metaClass, classContext, signatureStream); + if (metaClass->hasStaticFields()) + writeStaticFieldInitialization(s, metaClass); + // class inject-code native/end if (!metaClass->typeEntry()->codeSnips().isEmpty()) { writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(), @@ -5281,6 +5284,12 @@ QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClass *me return initFunctionName; } +QString CppGenerator::getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const +{ + return QLatin1String("init_") + getSimpleClassInitFunctionName(metaClass) + + QLatin1String("StaticFields"); +} + QString CppGenerator::getInitFunctionName(const GeneratorContext &context) const { return !context.forSmartPointer() @@ -5483,18 +5492,6 @@ void CppGenerator::writeClassRegister(QTextStream &s, if (metaClass->hasSignals()) writeSignalInitialization(s, metaClass); - // Write static fields - const AbstractMetaFieldList &fields = metaClass->fields(); - for (const AbstractMetaField *field : fields) { - if (!field->isStatic()) - continue; - s << INDENT << QLatin1String("PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \""); - s << field->name() << "\", "; - writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name()); - s << ");\n"; - } - s << Qt::endl; - // class inject-code target/end if (!classTypeEntry->codeSnips().isEmpty()) { s << Qt::endl; @@ -5524,6 +5521,29 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "}\n"; } +void CppGenerator::writeStaticFieldInitialization(QTextStream &s, + const AbstractMetaClass *metaClass) +{ + s << "\nvoid " << getSimpleClassStaticFieldsInitFunctionName(metaClass) + << "()\n{\n" << INDENT << "auto dict = reinterpret_cast<PyTypeObject *>(" + << cpythonTypeName(metaClass) << ")->tp_dict;\n"; + const auto &fields = metaClass->fields(); + for (const AbstractMetaField *field : fields) { + if (field->isStatic()) { + QString cppName = field->originalName(); + if (cppName.isEmpty()) + cppName = field->name(); + const QString name = field->enclosingClass()->qualifiedCppName() + + QLatin1String("::") + cppName; + s << INDENT << "PyDict_SetItemString(dict, \"" << field->name() + << "\",\n" << INDENT << " "; + writeToPythonConversion(s, field->type(), metaClass, name); + s << ");\n"; + } + } + s << "\n}\n"; +} + void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, const GeneratorContext &context) const { const AbstractMetaClass *metaClass = context.metaClass(); @@ -5934,11 +5954,18 @@ bool CppGenerator::finishGeneration() } const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies); + QVector<const AbstractMetaClass *> classesWithStaticFields; + for (const AbstractMetaClass *cls : lst){ if (shouldGenerate(cls)) { writeInitFunc(s_classInitDecl, s_classPythonDefines, INDENT, getSimpleClassInitFunctionName(cls), cls->typeEntry()->targetLangEnclosingEntry()); + if (cls->hasStaticFields()) { + s_classInitDecl << "void " + << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n"; + classesWithStaticFields.append(cls); + } } } @@ -6240,6 +6267,14 @@ bool CppGenerator::finishGeneration() s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");\n"; s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");\n"; + // Static fields are registered last since they may use converter functions + // of the previously registered types (PYSIDE-1529). + if (!classesWithStaticFields.isEmpty()) { + s << "\n// Static field initialization\n"; + for (auto cls : qAsConst(classesWithStaticFields)) + s << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n"; + } + s << '\n' << INDENT << "if (PyErr_Occurred()) {\n" << indent(INDENT) << INDENT << "PyErr_Print();\n" << INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n" diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h index 25bb51ef5..64396d61f 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.h +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h @@ -257,6 +257,7 @@ private: QString getInitFunctionName(const GeneratorContext &context) const; QString getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) const; + QString getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const; void writeSignatureStrings(QTextStream &s, QTextStream &signatureStream, const QString &arrayName, @@ -265,6 +266,8 @@ private: const AbstractMetaClass *metaClass, const GeneratorContext &classContext, QTextStream &signatureStream); + void writeStaticFieldInitialization(QTextStream &s, + const AbstractMetaClass *metaClass); void writeClassDefinition(QTextStream &s, const AbstractMetaClass *metaClass, const GeneratorContext &classContext); diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt index 45b41fd13..96effd280 100644 --- a/sources/shiboken2/libshiboken/CMakeLists.txt +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -29,13 +29,35 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in" configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py" "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY) +# Variable from enclosing scope. +# list(TRANSFORM shiboken_python_files +# PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/" +# OUTPUT_VARIABLE embedded_shiboken_files) +# Replacement for CMake version < 3.12: +set(embedded_shiboken_files "") +foreach(item IN LISTS shiboken_python_files) + list(APPEND embedded_shiboken_files + "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/${item}") +endforeach() + +if (QUIET_BUILD) + set(embedding_option "--quiet") +else() + set(embedding_option "") +endif() + add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap_inc.h" OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_inc.h" COMMAND ${PYTHON_EXECUTABLE} -E "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py" --cmake-dir "${CMAKE_CURRENT_BINARY_DIR}/embed" - --limited-api ${PYTHON_LIMITED_API}) + --limited-api ${PYTHON_LIMITED_API} + ${embedding_option} + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py" + "${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py" + ${embedded_shiboken_files} + ) set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION}) set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION}) diff --git a/sources/shiboken2/libshiboken/embed/embedding_generator.py b/sources/shiboken2/libshiboken/embed/embedding_generator.py index 15f63649b..a9a58ee07 100644 --- a/sources/shiboken2/libshiboken/embed/embedding_generator.py +++ b/sources/shiboken2/libshiboken/embed/embedding_generator.py @@ -82,7 +82,7 @@ def runpy(cmd, **kw): subprocess.call([sys.executable, '-E'] + cmd.split(), **kw) -def create_zipfile(limited_api): +def create_zipfile(limited_api, quiet): """ Collect all Python files, compile them, create a zip file and make a chunked base64 encoded file from it. @@ -129,11 +129,28 @@ def create_zipfile(limited_api): with open(inc_name, "w") as inc: _embed_file(tmp, inc) tmp.close() + # also generate a simple embeddable .pyc file for signature_bootstrap.pyc boot_name = "signature_bootstrap.py" if limited_api else "signature_bootstrap.pyc" with open(boot_name, "rb") as ldr, open("signature_bootstrap_inc.h", "w") as inc: _embed_bytefile(ldr, inc, limited_api) os.chdir(cur_dir) + if quiet: + return + + # have a look at our populated folder unless quiet option + def list_files(startpath): + for root, dirs, files in os.walk(startpath): + level = root.replace(startpath, '').count(os.sep) + indent = ' ' * 4 * (level) + print('+ {}{}/'.format(indent, os.path.basename(root))) + subindent = ' ' * 4 * (level + 1) + for f in files: + print('+ {}{}'.format(subindent, f)) + + print("++++ Current contents of") + list_files(work_dir) + print("++++") def _embed_file(fin, fout): @@ -236,7 +253,8 @@ if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--cmake-dir', nargs="?") parser.add_argument('--limited-api', type=str2bool) + parser.add_argument('--quiet', action='store_true') args = parser.parse_args() if args.cmake_dir: work_dir = os.path.abspath(args.cmake_dir) - create_zipfile(args.limited_api) + create_zipfile(args.limited_api, args.quiet) diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp index fd09efdae..b828aa8e0 100644 --- a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp @@ -90,7 +90,6 @@ SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFu static PythonToCppFunc unimplementedArrayCheck(PyObject *, int, int) { - warning(PyExc_RuntimeWarning, 0, "SbkConverter: Unimplemented C++ array type."); return nullptr; } diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp index dd6e46320..8d44878ac 100644 --- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp +++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp @@ -74,6 +74,29 @@ void *Shiboken::Buffer::getPointer(PyObject *pyObj, Py_ssize_t *size) return const_cast<void *>(buffer); } +void *Shiboken::Buffer::copyData(PyObject *pyObj, Py_ssize_t *sizeIn) +{ + void *result = nullptr; + Py_ssize_t size = 0; + + Py_buffer view; + if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) { + size = view.len; + if (size) { + result = std::malloc(size); + if (result != nullptr) + std::memcpy(result, view.buf, size); + else + size = 0; + } + PyBuffer_Release(&view); + } + + if (sizeIn != nullptr) + *sizeIn = size; + return result; +} + PyObject *Shiboken::Buffer::newObject(void *memory, Py_ssize_t size, Type type) { if (size == 0) diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.h b/sources/shiboken2/libshiboken/shibokenbuffer.h index dc9f8d89f..512d9db4d 100644 --- a/sources/shiboken2/libshiboken/shibokenbuffer.h +++ b/sources/shiboken2/libshiboken/shibokenbuffer.h @@ -79,6 +79,14 @@ namespace Buffer */ LIBSHIBOKEN_API void *getPointer(PyObject *pyObj, Py_ssize_t *size = nullptr); + /** + * Returns a copy of the buffer data which should be free'd. + * + * If the \p pyObj is a non-contiguous buffer a Python error is set. + * nullptr is returned for empty buffers. + */ + LIBSHIBOKEN_API void *copyData(PyObject *pyObj, Py_ssize_t *size = nullptr); + } // namespace Buffer } // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/signature/signature.cpp b/sources/shiboken2/libshiboken/signature/signature.cpp index 4c251af5b..601df4730 100644 --- a/sources/shiboken2/libshiboken/signature/signature.cpp +++ b/sources/shiboken2/libshiboken/signature/signature.cpp @@ -499,7 +499,7 @@ static PyObject *adjustFuncName(const char *func_name) } // Finally, generate the correct path expression. - char _buf[200 + 1] = {}; + char _buf[250 + 1] = {}; if (is_prop) { auto _prop_name = String::toCString(prop_name); if (is_class_prop) diff --git a/sources/shiboken2/shiboken_version.py b/sources/shiboken2/shiboken_version.py index 0985e2559..ecc975ddf 100644 --- a/sources/shiboken2/shiboken_version.py +++ b/sources/shiboken2/shiboken_version.py @@ -39,7 +39,7 @@ major_version = "5" minor_version = "15" -patch_version = "3" +patch_version = "4" # For example: "a", "b", "rc" # (which means "alpha", "beta", "release candidate"). diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt index b14de5c9e..9b2b58528 100644 --- a/sources/shiboken2/shibokenmodule/CMakeLists.txt +++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt @@ -42,37 +42,12 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py" configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in" "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/__feature__.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/__feature__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/errorhandler.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/errorhandler.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/layout.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/layout.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/loader.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/loader.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/importhandler.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/importhandler.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/mapping.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/mapping.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/parser.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/parser.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/tool.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/tool.py" COPYONLY) -if (PYTHON_VERSION_MAJOR EQUAL 3) -else() - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/backport_inspect.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/backport_inspect.py" COPYONLY) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/typing27.py" - "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/typing27.py" COPYONLY) -endif() +# Variable from enclosing scope. +foreach(item IN LISTS shiboken_python_files) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/${item}" + "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/${item}" COPYONLY) +endforeach() + install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/files.dir" DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2") diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py index ece3d2edb..ece3d2edb 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py 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 21c284f88..088a93aa4 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 @@ -103,8 +103,6 @@ class ExactEnumerator(object): self.fmt.class_name = None for class_name, klass in members: ret.update(self.klass(class_name, klass)) - if isinstance(klass, EnumMeta): - raise SystemError("implement enum instances at module level") for func_name, func in functions: ret.update(self.function(func_name, func)) return ret diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py index a6c3e420d..a509ecf07 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py @@ -114,7 +114,7 @@ def finish_import(module): import signature_bootstrap -from shibokensupport import signature, __feature__ +from shibokensupport import signature, feature as __feature__ signature.get_signature = signature_bootstrap.get_signature # PYSIDE-1019: Publish the __feature__ dictionary. __feature__.pyside_feature_dict = signature_bootstrap.pyside_feature_dict @@ -195,8 +195,9 @@ def move_into_pyside_package(): try: import PySide2.support except ModuleNotFoundError: - PySide2.support = types.ModuleType("PySide2.support") - put_into_package(PySide2.support, __feature__) + # This can happen in the embedding case. + put_into_package(PySide2, shibokensupport, "support") + put_into_package(PySide2.support, __feature__, "__feature__") put_into_package(PySide2.support, signature) put_into_package(PySide2.support.signature, mapping) put_into_package(PySide2.support.signature, errorhandler) @@ -220,16 +221,18 @@ from shibokensupport.signature.lib import enum_sig if "PySide2" in sys.modules: # We publish everything under "PySide2.support.signature", again. move_into_pyside_package() + # PYSIDE-1502: Make sure that support can be imported. + try: + import PySide2.support + except ModuleNotFoundError as e: + print("PySide2.support could not be imported. " + "This is a serious configuration error.", file=sys.stderr) + raise # PYSIDE-1019: Modify `__import__` to be `__feature__` aware. # __feature__ is already in sys.modules, so this is actually no import - try: - import PySide2.support.__feature__ - sys.modules["__feature__"] = PySide2.support.__feature__ - PySide2.support.__feature__.original_import = __builtins__["__import__"] - __builtins__["__import__"] = PySide2.support.__feature__._import - # Maybe we should optimize that and change `__import__` from C, instead? - except ModuleNotFoundError: - print("__feature__ could not be imported. " - "This is an unsolved PyInstaller problem.", file=sys.stderr) + import PySide2.support.__feature__ + sys.modules["__feature__"] = PySide2.support.__feature__ + PySide2.support.__feature__.original_import = __builtins__["__import__"] + __builtins__["__import__"] = PySide2.support.__feature__._import # end of file diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 4c9f02dc2..92511df32 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -351,6 +351,10 @@ type_map.update({ "self" : "self", }) +# PYSIDE-1538: We need to treat "std::optional" accordingly. +type_map.update({ + "std.optional": typing.Optional, + }) # The Shiboken Part def init_Shiboken(): diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py index 20c791cc1..a1cb58074 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py @@ -196,7 +196,7 @@ def _resolve_value(thing, valtype, line): if res is not None: type_map[thing] = res return res - warnings.warn("""pyside_type_init: + warnings.warn("""pyside_type_init:_resolve_value UNRECOGNIZED: {!r} OFFENDING LINE: {!r} @@ -277,7 +277,15 @@ def _resolve_type(thing, line, level, var_handler): pieces.append(to_string(part)) thing = ", ".join(pieces) result = "{contr}[{thing}]".format(**locals()) - return eval(result, namespace) + # PYSIDE-1538: Make sure that the eval does not crash. + try: + return eval(result, namespace) + except Exception as e: + warnings.warn("""pyside_type_init:_resolve_type + + UNRECOGNIZED: {!r} + OFFENDING LINE: {!r} + """.format(result, line), RuntimeWarning) return _resolve_value(thing, None, line) @@ -380,7 +388,9 @@ def fix_variables(props, line): if not isinstance(ann, ResultVariable): continue # We move the variable to the end and remove it. - retvars.append(ann.type) + # PYSIDE-1409: If the variable was the first arg, we move it to the front. + # XXX This algorithm should probably be replaced by more introspection. + retvars.insert(0 if idx == 0 else len(retvars), ann.type) deletions.append(idx) del annos[name] for idx in reversed(deletions): |