Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/xml/dombookmarks/dombookmarks.py20
-rw-r--r--sources/pyside6/PySide6/QtXml/typesystem_xml.xml4
-rw-r--r--sources/pyside6/tests/QtXml/qdomdocument_test.py23
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp20
-rw-r--r--sources/shiboken6/ApiExtractor/parser/typeinfo.cpp38
-rw-r--r--sources/shiboken6/ApiExtractor/parser/typeinfo.h5
-rw-r--r--sources/shiboken6/doc/typesystem_converters.rst36
-rw-r--r--sources/shiboken6/doc/typesystem_specifying_types.rst3
-rw-r--r--sources/shiboken6/doc/typesystem_variables.rst2
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py2
-rw-r--r--sources/shiboken6/tests/libsample/samplenamespace.cpp9
-rw-r--r--sources/shiboken6/tests/libsample/samplenamespace.h4
-rw-r--r--sources/shiboken6/tests/samplebinding/sample_test.py7
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystem_sample.xml19
14 files changed, 135 insertions, 57 deletions
diff --git a/examples/xml/dombookmarks/dombookmarks.py b/examples/xml/dombookmarks/dombookmarks.py
index f5afdeef8..f02251849 100644
--- a/examples/xml/dombookmarks/dombookmarks.py
+++ b/examples/xml/dombookmarks/dombookmarks.py
@@ -7,7 +7,7 @@ from __future__ import annotations
import sys
-from PySide6.QtCore import QDir, QFile, Qt, QTextStream
+from PySide6.QtCore import QDir, QFile, QObject, Qt, QTextStream
from PySide6.QtGui import QAction, QIcon, QKeySequence
from PySide6.QtWidgets import (QApplication, QFileDialog, QHeaderView,
QMainWindow, QMessageBox, QStyle, QTreeWidget,
@@ -93,6 +93,7 @@ class XbelTree(QTreeWidget):
def __init__(self, parent=None):
super().__init__(parent)
+ self._update_conn_id = None
self.header().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.setHeaderLabels(("Title", "Location"))
@@ -111,11 +112,12 @@ class XbelTree(QTreeWidget):
self._bookmark_icon.addPixmap(style.standardPixmap(QStyle.StandardPixmap.SP_FileIcon))
def read(self, device):
- ok, errorStr, errorLine, errorColumn = self._dom_document.setContent(device, True)
- if not ok:
+ result = self._dom_document.setContent(device,
+ QDomDocument.ParseOption.UseNamespaceProcessing)
+ if not result:
QMessageBox.information(self.window(), "DOM Bookmarks",
- f"Parse error at line {errorLine}, "
- f"column {errorColumn}:\n{errorStr}")
+ f"Parse error at line {result.errorLine}, "
+ f"column {result.errorColumn}:\n{result.errorMessage}")
return False
root = self._dom_document.documentElement()
@@ -131,17 +133,15 @@ class XbelTree(QTreeWidget):
self.clear()
# It might not be connected.
- try:
- self.itemChanged.disconnect(self.update_dom_element)
- except RuntimeError:
- pass
+ if self._update_conn_id:
+ QObject.disconnect(self._update_conn_id)
child = root.firstChildElement('folder')
while not child.isNull():
self.parse_folder_element(child)
child = child.nextSiblingElement('folder')
- self.itemChanged.connect(self.update_dom_element)
+ self._update_conn_id = self.itemChanged.connect(self.update_dom_element)
return True
diff --git a/sources/pyside6/PySide6/QtXml/typesystem_xml.xml b/sources/pyside6/PySide6/QtXml/typesystem_xml.xml
index 089978b6d..93d3c1f56 100644
--- a/sources/pyside6/PySide6/QtXml/typesystem_xml.xml
+++ b/sources/pyside6/PySide6/QtXml/typesystem_xml.xml
@@ -20,7 +20,7 @@
<enum-type name="ParseOption" flags="ParseOptions" since="6.5"/>
<!-- will be replaced in inject code -->
- <value-type name="ParseResult"/>
+ <value-type name="ParseResult" operator-bool="yes"/>
<modify-function signature="setContent(const QByteArray&amp;,bool,QString*,int*,int*)">
<modify-argument index="3">
@@ -130,6 +130,8 @@
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtxml.cpp" snippet="qdomdocument-setcontent" />
</modify-function>
+ <declare-function signature="setContent(const QByteArray&amp;@data@, QDomDocument::ParseOptions@options@=QDomDocument::ParseOption::Default)"
+ return-type="QDomDocument::ParseResult" since="6.8" />
</value-type>
<value-type name="QDomDocumentFragment"/>
diff --git a/sources/pyside6/tests/QtXml/qdomdocument_test.py b/sources/pyside6/tests/QtXml/qdomdocument_test.py
index 8fe4f6e17..b321b1bdf 100644
--- a/sources/pyside6/tests/QtXml/qdomdocument_test.py
+++ b/sources/pyside6/tests/QtXml/qdomdocument_test.py
@@ -44,18 +44,20 @@ class QDomDocumentTest(unittest.TestCase):
def testQDomDocumentSetContentWithBadXmlData(self):
'''Sets invalid xml as the QDomDocument contents.'''
- ok, errorStr, errorLine, errorColumn = self.dom.setContent(self.badXmlData, True)
- self.assertFalse(ok)
- self.assertEqual(errorStr, 'Opening and ending tag mismatch.')
- self.assertEqual(errorLine, 4)
+ parseResult = self.dom.setContent(self.badXmlData,
+ QDomDocument.ParseOption.UseNamespaceProcessing)
+ self.assertFalse(parseResult)
+ self.assertEqual(parseResult.errorMessage, 'Opening and ending tag mismatch.')
+ self.assertEqual(parseResult.errorLine, 4)
def testQDomDocumentSetContentWithGoodXmlData(self):
'''Sets valid xml as the QDomDocument contents.'''
- ok, errorStr, errorLine, errorColumn = self.dom.setContent(self.goodXmlData, True)
- self.assertTrue(ok)
- self.assertEqual(errorStr, '')
- self.assertEqual(errorLine, 0)
- self.assertEqual(errorColumn, 0)
+ parseResult = self.dom.setContent(self.goodXmlData,
+ QDomDocument.ParseOption.UseNamespaceProcessing)
+ self.assertTrue(parseResult)
+ self.assertEqual(parseResult.errorMessage, '')
+ self.assertEqual(parseResult.errorLine, 0)
+ self.assertEqual(parseResult.errorColumn, 0)
def testQDomDocumentData(self):
'''Checks the QDomDocument elements for the valid xml contents.'''
@@ -66,7 +68,8 @@ class QDomDocumentTest(unittest.TestCase):
self.assertTrue(element.hasAttribute(attribute))
self.assertEqual(element.attribute(attribute), value)
- ok, errorStr, errorLine, errorColumn = self.dom.setContent(self.goodXmlData, True)
+ parseResult = self.dom.setContent(self.goodXmlData, # noqa F:841
+ QDomDocument.ParseOption.UseNamespaceProcessing)
root = self.dom.documentElement()
self.assertEqual(root.tagName(), 'typesystem')
checkAttribute(root, 'package', 'PySide6.QtXml')
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
index 27570ec4f..fb5399baa 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -2664,7 +2664,7 @@ std::optional<AbstractMetaType>
qsizetype i = d ? d->m_scopes.size() - 1 : -1;
while (i >= 0) {
typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--));
- if (typeInfo.qualifiedName().join(u"::"_s) != _typei.qualifiedName().join(u"::"_s))
+ if (typeInfo.qualifiedName() != _typei.qualifiedName())
break;
}
@@ -2757,12 +2757,22 @@ std::optional<AbstractMetaType>
// 4. Special case QFlags (include instantiation in name)
if (qualifiedName == u"QFlags") {
- qualifiedName = typeInfo.toString();
+ qualifiedName = typeInfo.qualifiedInstantationName();
typeInfo.clearInstantiations();
}
TypeEntryCList types = findTypeEntries(qualifiedName, name, flags,
currentClass, d, errorMessageIn);
+ if (types.isEmpty() && !typeInfo.instantiations().isEmpty()) {
+ // Allow for specifying template specializations as primitive types
+ // with converters ('std::optional<int>' or similar).
+ auto pt = TypeDatabase::instance()->findPrimitiveType(typeInfo.qualifiedInstantationName());
+ if (pt) {
+ types.append(pt);
+ typeInfo.clearInstantiations();
+ }
+ }
+
if (!flags.testFlag(AbstractMetaBuilder::TemplateArgument)) {
// Avoid clashes between QByteArray and enum value QMetaType::QByteArray
// unless we are looking for template arguments.
@@ -2796,7 +2806,7 @@ std::optional<AbstractMetaType>
// For non-type template parameters, create a dummy type entry on the fly
// as is done for classes.
if (!targType.has_value()) {
- const QString value = ti.qualifiedName().join(u"::"_s);
+ const QString value = ti.qualifiedNameString();
if (isNumber(value)) {
auto module = typeSystemTypeEntry(type);
TypeDatabase::instance()->addConstantValueTypeEntry(value, module);
@@ -3082,7 +3092,7 @@ AbstractMetaClassPtr
QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(u"::"_s) + u"::"_s : QString();
QString completeName = prefix + name;
const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage);
- QString qualifiedName = parsed.qualifiedName().join(u"::"_s);
+ QString qualifiedName = parsed.qualifiedNameString();
if (qualifiedName.isEmpty()) {
qWarning().noquote().nospace() << "Unable to parse type \"" << completeName
<< "\" while looking for template \"" << name << "\": " << errorMessage;
@@ -3196,7 +3206,7 @@ static std::optional<AbstractMetaType>
const AbstractMetaClassCPtr &templateClass,
const TypeInfo &info, QString *errorMessage)
{
- QString typeName = info.qualifiedName().join("::"_L1);
+ QString typeName = info.qualifiedNameString();
TypeDatabase *typeDb = TypeDatabase::instance();
TypeEntryPtr t;
// Check for a non-type template integer parameter, that is, for a base
diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
index 845a0f916..93627e6d5 100644
--- a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
+++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
@@ -110,6 +110,28 @@ QStringList TypeInfo::qualifiedName() const
return d->m_qualifiedName;
}
+QString TypeInfo::qualifiedNameString() const
+{
+ return d->m_qualifiedName.join("::"_L1);
+}
+
+QString TypeInfo::qualifiedInstantationName() const
+{
+ QString result = qualifiedNameString();
+ if (const auto instantiationCount = d->m_instantiations.size()) {
+ result += u'<';
+ for (qsizetype i = 0; i < instantiationCount; ++i) {
+ if (i)
+ result += ", "_L1;
+ result += d->m_instantiations.at(i).toString();
+ }
+ if (result.endsWith(u'>'))
+ result += u' ';
+ result += u'>';
+ }
+ return result;
+}
+
void TypeInfo::setQualifiedName(const QStringList &qualified_name)
{
if (d->m_qualifiedName != qualified_name)
@@ -300,7 +322,7 @@ TypeInfo TypeInfo::resolveType(const CodeModelItem &__item, TypeInfo const &__ty
// typedef struct xcb_connection_t xcb_connection_t;
if (nextItem.get() ==__item.get()) {
std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__
- << "() on " << qPrintable(__type.qualifiedName().join(u"::"_s))
+ << "() on " << qPrintable(__type.qualifiedNameString())
<< '\n';
return otherType;
}
@@ -385,19 +407,7 @@ QString TypeInfo::toString() const
if (isVolatile())
tmp += u"volatile "_s;
- tmp += d->m_qualifiedName.join(u"::"_s);
-
- if (const auto instantiationCount = d->m_instantiations.size()) {
- tmp += u'<';
- for (qsizetype i = 0; i < instantiationCount; ++i) {
- if (i)
- tmp += u", "_s;
- tmp += d->m_instantiations.at(i).toString();
- }
- if (tmp.endsWith(u'>'))
- tmp += u' ';
- tmp += u'>';
- }
+ tmp += qualifiedInstantationName();
for (Indirection i : d->m_indirections)
tmp.append(indirectionKeyword(i));
diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.h b/sources/shiboken6/ApiExtractor/parser/typeinfo.h
index 9cd746e85..6f75b5737 100644
--- a/sources/shiboken6/ApiExtractor/parser/typeinfo.h
+++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.h
@@ -39,6 +39,11 @@ public:
QStringList qualifiedName() const;
void setQualifiedName(const QStringList &qualified_name);
+ // Returns "std::list"
+ QString qualifiedNameString() const;
+ // Returns qualifiedName() with instantions ("std::list<int>")
+ QString qualifiedInstantationName() const;
+
void addName(const QString &);
bool isVoid() const;
diff --git a/sources/shiboken6/doc/typesystem_converters.rst b/sources/shiboken6/doc/typesystem_converters.rst
index ab6fba930..f34f5b829 100644
--- a/sources/shiboken6/doc/typesystem_converters.rst
+++ b/sources/shiboken6/doc/typesystem_converters.rst
@@ -16,7 +16,8 @@ C++ and vice-versa.
// C++ class
struct Complex {
- Complex(double real, double imag);
+ explicit Complex(double real, double imag);
+
double real() const;
double imag() const;
};
@@ -82,8 +83,9 @@ Here's how to do it:
<!-- Code injection at module level. -->
<inject-code class="native" position="beginning">
- static bool Check2TupleOfNumbers(PyObject* pyIn) {
- if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2))
+ static bool Check2TupleOfNumbers(PyObject *pyIn)
+ {
+ if (PySequence_Check(pyIn) == 0 || PySequence_Size(pyIn) != 2)
return false;
Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0));
if (!PyNumber_Check(pyReal))
@@ -134,7 +136,8 @@ Container Conversions
Converters for :ref:`container-type <container-type>` are pretty much the same as for other type,
except that they make use of the type system variables
-:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>`.
+:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>` denoting the
+template parameters.
|project| combines the conversion code for containers with the conversion
defined (or automatically generated) for the containers.
@@ -147,13 +150,12 @@ defined (or automatically generated) for the containers.
<native-to-target>
PyObject* %out = PyDict_New();
- %INTYPE::const_iterator it = %in.begin();
- for (; it != %in.end(); ++it) {
- %INTYPE_0 key = it->first;
- %INTYPE_1 value = it->second;
- PyDict_SetItem(%out,
+ for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) {
+ const auto &amp;key = it->first;
+ const auto &amp;value = it->second;
+ PyDict_SetItem(%out,
%CONVERTTOPYTHON[%INTYPE_0](key),
- %CONVERTTOPYTHON[%INTYPE_1](value));
+ %CONVERTTOPYTHON[%INTYPE_1](value));
}
return %out;
</native-to-target>
@@ -161,8 +163,8 @@ defined (or automatically generated) for the containers.
<target-to-native>
<add-conversion type="PyDict">
- PyObject* key;
- PyObject* value;
+ PyObject *key{};
+ PyObject *value{};
Py_ssize_t pos = 0;
while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;value)) {
%OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
@@ -183,10 +185,10 @@ defined (or automatically generated) for the containers.
For this case, a number of pre-defined conversion templates
are provided (see :ref:`predefined_templates`).
-.. _variables_and_functions:
+.. _converter_variables_and_functions:
-Variables & Functions
-=====================
+Converter Variables & Functions
+===============================
.. _in:
@@ -212,7 +214,7 @@ Variables & Functions
.. _intype_n:
**%INTYPE_#**
- Replaced by the name of the #th type used in a container.
+ Replaced by the name of the #th template parameter type used in a container.
.. _outtype:
@@ -225,7 +227,7 @@ Variables & Functions
.. _outtype_n:
**%OUTTYPE_#**
- Replaced by the name of the #th type used in a container.
+ Replaced by the name of the #th template parameter type used in a container.
.. _checktype:
diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst
index c03d203b9..60ac5c6d9 100644
--- a/sources/shiboken6/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken6/doc/typesystem_specifying_types.rst
@@ -208,6 +208,9 @@ can be generated for them. Instead, an instance of the viewed class should
be instantiated and passed to functions using the view class
for argument types.
+It is also possible to specify template specializations
+like "std::optional<int>" as primitive types with converters.
+
See :ref:`predefined_templates` for built-in templates for standard type
conversion rules.
diff --git a/sources/shiboken6/doc/typesystem_variables.rst b/sources/shiboken6/doc/typesystem_variables.rst
index 5eb5d5abe..6dfd1f801 100644
--- a/sources/shiboken6/doc/typesystem_variables.rst
+++ b/sources/shiboken6/doc/typesystem_variables.rst
@@ -16,6 +16,8 @@ implementation specifics.
Variables
=========
+In addition to the below listed variables, there are some variables specific to type
+conversion code (see :ref:`converter_variables_and_functions`).
.. _cpp_return_argument:
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
index 109562a98..8eea431c3 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
@@ -352,6 +352,7 @@ def create_signature_union(props, key):
if last == _VAR_POSITIONAL:
kind = _KEYWORD_ONLY
if default is None:
+ ann = typing.Union[ann]
ann = typing.Optional[ann]
if default is not _empty and layout.ellipsis:
default = ellipsis
@@ -373,6 +374,7 @@ def create_signature_union(props, key):
ret_anno = annotations.get('return', _empty)
if ret_anno is not _empty and props["fullname"] in missing_optional_return:
+ ret_anno = typing.Union[ret_anno]
ret_anno = typing.Optional[ret_anno]
return inspect.Signature(params, return_annotation=ret_anno,
__validate_parameters__=False)
diff --git a/sources/shiboken6/tests/libsample/samplenamespace.cpp b/sources/shiboken6/tests/libsample/samplenamespace.cpp
index 18a18d28d..3836f43aa 100644
--- a/sources/shiboken6/tests/libsample/samplenamespace.cpp
+++ b/sources/shiboken6/tests/libsample/samplenamespace.cpp
@@ -97,6 +97,15 @@ int passReferenceToObjectType(const ObjectType &obj, int multiplier)
return obj.objectName().size() * multiplier;
}
+// Exercise specifying complete template specializations as primitive types.
+std::optional<long> optionalMultiply(const std::optional<long> &v1,
+ const std::optional<long> &v2)
+{
+ if (!v1.has_value() || !v2.has_value())
+ return std::nullopt;
+ return v1.value() * v2.value();
+}
+
int variableInNamespace = 42;
} // namespace SampleNamespace
diff --git a/sources/shiboken6/tests/libsample/samplenamespace.h b/sources/shiboken6/tests/libsample/samplenamespace.h
index 99a0787ee..63dc2f316 100644
--- a/sources/shiboken6/tests/libsample/samplenamespace.h
+++ b/sources/shiboken6/tests/libsample/samplenamespace.h
@@ -9,6 +9,7 @@
#include "point.h"
#include "objecttype.h"
+#include <optional>
#include <list>
// Anonymous global enum
@@ -157,6 +158,9 @@ LIBSAMPLE_API double passReferenceToValueType(const Point &point, double multipl
// Add a new signature on type system with only a ObjectType pointer as parameter.
LIBSAMPLE_API int passReferenceToObjectType(const ObjectType &obj, int multiplier);
+LIBSAMPLE_API std::optional<long> optionalMultiply(const std::optional<long> &v1,
+ const std::optional<long> &v2);
+
extern LIBSAMPLE_API int variableInNamespace;
} // namespace SampleNamespace
diff --git a/sources/shiboken6/tests/samplebinding/sample_test.py b/sources/shiboken6/tests/samplebinding/sample_test.py
index c003ad398..43b84d36e 100644
--- a/sources/shiboken6/tests/samplebinding/sample_test.py
+++ b/sources/shiboken6/tests/samplebinding/sample_test.py
@@ -79,6 +79,13 @@ class ModuleTest(unittest.TestCase):
mo2 = sample.MoveOnlyHandler.passMoveOnly(mo)
self.assertEqual(mo2.value(), v)
+ def testOptionalLong(self):
+ v1 = 2
+ v2 = 3
+ self.assertEqual(sample.SampleNamespace.optionalMultiply(v1, v2), 6)
+ self.assertIsNone(sample.SampleNamespace.optionalMultiply(v1, None))
+ self.assertIsNone(sample.SampleNamespace.optionalMultiply(None, v2))
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
index 3f1b2e96f..391a0804d 100644
--- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
@@ -120,6 +120,25 @@
</conversion-rule>
</primitive-type>
+ <primitive-type name="std::optional&lt;long&gt;" target-langapi-name="PyObject">
+ <conversion-rule>
+ <native-to-target>
+ if (!%in.has_value())
+ Py_RETURN_NONE;
+ return PyLong_FromLong(%in.value());
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="Py_None">
+ SBK_UNUSED(%in)
+ %out = %OUTTYPE();
+ </add-conversion>
+ <add-conversion type="PyLong" check="PyLong_CheckExact(%in)">
+ %out = %OUTTYPE(PyLong_AsLong(%in));
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
<value-type name="MoveOnly"/>
<object-type name="MoveOnlyHandler"/>