aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2019-11-04 12:34:17 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2019-11-04 12:42:35 +0100
commit1704567d7ad0d21dd3b588af7aad40cd244c1799 (patch)
tree932b42988e482f01125dcbf4d470e9a56107689a /sources/shiboken2
parent1d77cd18510412242384c5b37a00efd5b6ce8a26 (diff)
parentc98ef56544cd54661b61529829caf6a799a1a94f (diff)
Merge "Merge remote-tracking branch 'origin/5.14' into 5.15"
Diffstat (limited to 'sources/shiboken2')
-rw-r--r--sources/shiboken2/ApiExtractor/CMakeLists.txt17
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp129
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.h11
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h9
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp44
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h18
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp66
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp33
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdtorinformation.h1
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp16
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.cpp32
-rw-r--r--sources/shiboken2/CMakeLists.txt276
-rw-r--r--sources/shiboken2/data/shiboken_helpers.cmake269
-rw-r--r--sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css175
-rw-r--r--sources/shiboken2/generator/generator.cpp9
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp19
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp88
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h2
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp7
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp14
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp49
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h5
-rw-r--r--sources/shiboken2/libshiboken/CMakeLists.txt10
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp94
-rw-r--r--sources/shiboken2/libshiboken/embed/embedding_generator.py4
-rw-r--r--sources/shiboken2/libshiboken/helper.cpp3
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp42
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h2
-rw-r--r--sources/shiboken2/libshiboken/qapp_macro.cpp9
-rw-r--r--sources/shiboken2/libshiboken/sbkstaticstrings.cpp92
-rw-r--r--sources/shiboken2/libshiboken/sbkstaticstrings.h65
-rw-r--r--sources/shiboken2/libshiboken/sbkstaticstrings_p.h73
-rw-r--r--sources/shiboken2/libshiboken/sbkstring.cpp71
-rw-r--r--sources/shiboken2/libshiboken/sbkstring.h10
-rw-r--r--sources/shiboken2/libshiboken/shiboken.h1
-rw-r--r--sources/shiboken2/libshiboken/shibokenbuffer.cpp4
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp132
-rw-r--r--sources/shiboken2/libshiboken/signature.h2
-rw-r--r--sources/shiboken2/libshiboken/typespec.cpp3
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt1
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py4
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py75
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py100
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py19
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py25
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py27
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py13
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py515
-rw-r--r--sources/shiboken2/tests/CMakeLists.txt14
-rw-r--r--sources/shiboken2/tests/libsample/modifications.cpp16
-rw-r--r--sources/shiboken2/tests/libsample/modifications.h10
-rw-r--r--sources/shiboken2/tests/samplebinding/modifications_test.py10
-rw-r--r--sources/shiboken2/tests/samplebinding/typesystem_sample.xml7
54 files changed, 1885 insertions, 859 deletions
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt
index c8a5fb336..c2a4c208e 100644
--- a/sources/shiboken2/ApiExtractor/CMakeLists.txt
+++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt
@@ -30,6 +30,22 @@ parser/enumvalue.cpp
xmlutils.cpp
)
+find_package(Qt5XmlPatterns 5.12)
+find_package(Qt5Xml 5.12)
+find_package(LibXml2 2.6.32)
+find_package(LibXslt 1.1.19)
+
+set(HAS_LIBXSLT 0)
+if (LIBXSLT_FOUND AND LIBXML2_FOUND)
+ set(HAS_LIBXSLT 1)
+endif()
+
+if(NOT Qt5XmlPatterns_FOUND AND NOT HAS_LIBXSLT)
+ set(DISABLE_DOCSTRINGS TRUE)
+ message(WARNING
+ "Documentation will not be built due to missing dependency (no Qt5XmlPatterns found).")
+endif()
+
add_library(apiextractor STATIC ${apiextractor_SRC})
target_include_directories(apiextractor PRIVATE ${CLANG_EXTRA_INCLUDES}
${CMAKE_CURRENT_SOURCE_DIR}
@@ -68,6 +84,7 @@ target_compile_definitions(apiextractor PRIVATE CMAKE_CXX_COMPILER="${CMAKE_CXX_
set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
if (BUILD_TESTS)
+ find_package(Qt5Test 5.12 REQUIRED)
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests)
enable_testing()
add_subdirectory(tests)
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 9c930dcdc..ae3cdd86b 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -248,6 +248,15 @@ void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &f
}
}
+void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceModelItem &nsItem)
+{
+ const FunctionList &streamOps = nsItem->findFunctions(QLatin1String("operator<<"));
+ for (const FunctionModelItem &item : streamOps)
+ registerToStringCapability(item, nullptr);
+ for (const NamespaceModelItem &ni : nsItem->namespaces())
+ registerToStringCapabilityIn(ni);
+}
+
/**
* Check if a class has a debug stream operator that can be used as toString
*/
@@ -261,7 +270,7 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelI
const ArgumentModelItem &arg = arguments.at(1);
if (AbstractMetaClass *cls = argumentToClass(arg, currentClass)) {
if (arg->type().indirections() < 2)
- cls->setToStringCapability(true);
+ cls->setToStringCapability(true, arg->type().indirections());
}
}
}
@@ -503,8 +512,12 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
ReportHandler::startProgress("Fixing class inheritance...");
for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) {
- if (!cls->isInterface() && !cls->isNamespace())
+ if (!cls->isInterface() && !cls->isNamespace()) {
setupInheritance(cls);
+ if (!cls->hasVirtualDestructor() && cls->baseClass()
+ && cls->baseClass()->hasVirtualDestructor())
+ cls->setHasVirtualDestructor(true);
+ }
}
ReportHandler::startProgress("Detecting inconsistencies in class model...");
@@ -591,11 +604,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
registerHashFunction(item, nullptr);
}
- {
- const FunctionList &streamOps = dom->findFunctions(QLatin1String("operator<<"));
- for (const FunctionModelItem &item : streamOps)
- registerToStringCapability(item, nullptr);
- }
+ registerToStringCapabilityIn(dom);
{
FunctionList binaryOperators = dom->findFunctions(QStringLiteral("operator=="));
@@ -1612,6 +1621,26 @@ void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem,
}
}
+static void applyDefaultExpressionModifications(const FunctionModificationList &functionMods,
+ int i, AbstractMetaArgument *metaArg)
+{
+ // use replace/remove-default-expression for set default value
+ for (const auto &modification : functionMods) {
+ for (const auto &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == i + 1) {
+ if (argumentModification.removedDefaultExpression) {
+ metaArg->setDefaultValueExpression(QString());
+ break;
+ }
+ if (!argumentModification.replacedDefaultExpression.isEmpty()) {
+ metaArg->setDefaultValueExpression(argumentModification.replacedDefaultExpression);
+ break;
+ }
+ }
+ }
+ }
+}
+
AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunctionPtr &addedFunc)
{
return traverseFunction(addedFunc, nullptr);
@@ -1670,20 +1699,13 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu
// Find the correct default values
+ const FunctionModificationList functionMods = metaFunction->modifications(metaClass);
for (int i = 0; i < metaArguments.size(); ++i) {
AbstractMetaArgument* metaArg = metaArguments.at(i);
- //use relace-default-expression for set default value
- QString replacedExpression;
- if (metaClass)
- replacedExpression = metaFunction->replacedDefaultExpression(metaClass, i + 1);
-
- if (!replacedExpression.isEmpty()) {
- if (!metaFunction->removedDefaultExpression(metaClass, i + 1)) {
- metaArg->setDefaultValueExpression(replacedExpression);
- metaArg->setOriginalDefaultValueExpression(replacedExpression);
- }
- }
+ // use replace-default-expression for set default value
+ applyDefaultExpressionModifications(functionMods, i, metaArg);
+ metaArg->setOriginalDefaultValueExpression(metaArg->defaultValueExpression()); // appear unmodified
}
metaFunction->setOriginalAttributes(metaFunction->attributes());
@@ -1915,7 +1937,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
AbstractMetaType *type = nullptr;
if (!returnType.isVoid()) {
- type = translateType(returnType, currentClass, true, &errorMessage);
+ type = translateType(returnType, currentClass, {}, &errorMessage);
if (!type) {
const QString reason = msgUnmatchedReturnType(functionItem, errorMessage);
qCWarning(lcShiboken, "%s",
@@ -1951,7 +1973,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
return nullptr;
}
- AbstractMetaType *metaType = translateType(arg->type(), currentClass, true, &errorMessage);
+ AbstractMetaType *metaType = translateType(arg->type(), currentClass, {}, &errorMessage);
if (!metaType) {
// If an invalid argument has a default value, simply remove it
if (arg->defaultValue()) {
@@ -2002,35 +2024,16 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
const ArgumentModelItem &arg = arguments.at(i);
AbstractMetaArgument* metaArg = metaArguments.at(i);
- //use relace-default-expression for set default value
- QString replacedExpression;
- if (currentClass) {
- replacedExpression = metaFunction->replacedDefaultExpression(currentClass, i + 1);
- } else {
- if (!functionMods.isEmpty()) {
- QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods;
- if (!argMods.isEmpty())
- replacedExpression = argMods.constFirst().replacedDefaultExpression;
- }
- }
+ const QString originalDefaultExpression =
+ fixDefaultValue(arg, metaArg->type(), metaFunction, currentClass, i);
- bool hasDefaultValue = false;
- if (arg->defaultValue() || !replacedExpression.isEmpty()) {
- QString expr = arg->defaultValueExpression();
- expr = fixDefaultValue(arg, metaArg->type(), metaFunction, currentClass, i);
- metaArg->setOriginalDefaultValueExpression(expr);
+ metaArg->setOriginalDefaultValueExpression(originalDefaultExpression);
+ metaArg->setDefaultValueExpression(originalDefaultExpression);
- if (metaFunction->removedDefaultExpression(currentClass, i + 1)) {
- expr.clear();
- } else if (!replacedExpression.isEmpty()) {
- expr = replacedExpression;
- }
- metaArg->setDefaultValueExpression(expr);
- hasDefaultValue = !expr.isEmpty();
- }
+ applyDefaultExpressionModifications(functionMods, i, metaArg);
//Check for missing argument name
- if (hasDefaultValue
+ if (!metaArg->defaultValueExpression().isEmpty()
&& !metaArg->hasName()
&& !metaFunction->isOperatorOverload()
&& !metaFunction->isSignal()
@@ -2155,22 +2158,27 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC
AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei,
AbstractMetaClass *currentClass,
- bool resolveType,
+ TranslateTypeFlags flags,
QString *errorMessage)
{
- return translateTypeStatic(_typei, currentClass, this, resolveType, errorMessage);
+ return translateTypeStatic(_typei, currentClass, this, flags, errorMessage);
}
AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei,
AbstractMetaClass *currentClass,
AbstractMetaBuilderPrivate *d,
- bool resolveType,
+ TranslateTypeFlags flags,
QString *errorMessageIn)
{
// 1. Test the type info without resolving typedefs in case this is present in the
// type system
+ const bool resolveType = !flags.testFlag(AbstractMetaBuilder::DontResolveType);
if (resolveType) {
- if (AbstractMetaType *resolved = translateTypeStatic(_typei, currentClass, d, false, errorMessageIn))
+ AbstractMetaType *resolved =
+ translateTypeStatic(_typei, currentClass, d,
+ flags | AbstractMetaBuilder::DontResolveType,
+ errorMessageIn);
+ if (resolved)
return resolved;
}
@@ -2229,7 +2237,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo
newInfo.setReferenceType(typeInfo.referenceType());
newInfo.setVolatile(typeInfo.isVolatile());
- AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, true, &errorMessage);
+ AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, flags, &errorMessage);
if (!elementType) {
if (errorMessageIn) {
errorMessage.prepend(QLatin1String("Unable to translate array element: "));
@@ -2340,7 +2348,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo
const auto &templateArguments = typeInfo.instantiations();
for (int t = 0, size = templateArguments.size(); t < size; ++t) {
const TypeInfo &ti = templateArguments.at(t);
- AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, true, &errorMessage);
+ AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage);
if (!targType) {
if (errorMessageIn)
*errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage);
@@ -2362,17 +2370,17 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo
AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei,
AbstractMetaClass *currentClass,
- bool resolveType,
+ TranslateTypeFlags flags,
QString *errorMessage)
{
return AbstractMetaBuilderPrivate::translateTypeStatic(_typei, currentClass,
- nullptr, resolveType,
+ nullptr, flags,
errorMessage);
}
AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t,
AbstractMetaClass *currentClass,
- bool resolveType,
+ TranslateTypeFlags flags,
QString *errorMessageIn)
{
QString errorMessage;
@@ -2385,7 +2393,7 @@ AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t,
qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
return nullptr;
}
- return translateType(typeInfo, currentClass, resolveType, errorMessageIn);
+ return translateType(typeInfo, currentClass, flags, errorMessageIn);
}
qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok)
@@ -2431,10 +2439,10 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &ite
AbstractMetaClass *implementingClass,
int /* argumentIndex */)
{
- QString functionName = fnc->name();
- QString className = implementingClass ? implementingClass->qualifiedCppName() : QString();
-
QString expr = item->defaultValueExpression();
+ if (expr.isEmpty())
+ return expr;
+
if (type) {
if (type->isPrimitive()) {
if (type->name() == QLatin1String("boolean")) {
@@ -2508,11 +2516,12 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &ite
}
}
} else {
+ const QString className = implementingClass ? implementingClass->qualifiedCppName() : QString();
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("undefined type for default value '%3' of argument in function '%1', class '%2'")
- .arg(functionName, className, item->defaultValueExpression());
+ .arg(fnc->name(), className, item->defaultValueExpression());
- expr = QString();
+ expr.clear();
}
return expr;
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
index 1789ca2aa..93b9d9fd2 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
@@ -90,13 +90,18 @@ public:
void setSkipDeprecated(bool value);
+ enum TranslateTypeFlag {
+ DontResolveType = 0x1
+ };
+ Q_DECLARE_FLAGS(TranslateTypeFlags, TranslateTypeFlag);
+
static AbstractMetaType *translateType(const TypeInfo &_typei,
AbstractMetaClass *currentClass = nullptr,
- bool resolveType = true,
+ TranslateTypeFlags flags = {},
QString *errorMessage = nullptr);
static AbstractMetaType *translateType(const QString &t,
AbstractMetaClass *currentClass = nullptr,
- bool resolveType = true,
+ TranslateTypeFlags flags = {},
QString *errorMessage = nullptr);
@@ -109,6 +114,8 @@ private:
AbstractMetaBuilderPrivate *d;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaBuilder::TranslateTypeFlags);
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab);
#endif
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
index fec2eddb9..30df236d6 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
@@ -43,6 +43,8 @@ class TypeDatabase;
class AbstractMetaBuilderPrivate
{
public:
+ using TranslateTypeFlags = AbstractMetaBuilder::TranslateTypeFlags;
+
Q_DISABLE_COPY(AbstractMetaBuilderPrivate)
AbstractMetaBuilderPrivate();
@@ -56,7 +58,7 @@ public:
void dumpLog() const;
AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClassList &classList,
const Dependencies &additionalDependencies = Dependencies()) const;
- ScopeModelItem popScope() { return m_scopes.takeLast(); }
+ NamespaceModelItem popScope() { return m_scopes.takeLast(); }
void pushScope(const NamespaceModelItem &item);
@@ -106,6 +108,7 @@ public:
void checkFunctionModifications();
void registerHashFunction(const FunctionModelItem &functionItem,
AbstractMetaClass *currentClass);
+ void registerToStringCapabilityIn(const NamespaceModelItem &namespaceItem);
void registerToStringCapability(const FunctionModelItem &functionItem,
AbstractMetaClass *currentClass);
@@ -135,12 +138,12 @@ public:
AbstractMetaType *translateType(const AddedFunction::TypeInfo &typeInfo);
AbstractMetaType *translateType(const TypeInfo &type,
AbstractMetaClass *currentClass,
- bool resolveType = true,
+ TranslateTypeFlags flags = {},
QString *errorMessage = nullptr);
static AbstractMetaType *translateTypeStatic(const TypeInfo &type,
AbstractMetaClass *current,
AbstractMetaBuilderPrivate *d = nullptr,
- bool resolveType = true,
+ TranslateTypeFlags flags = {},
QString *errorMessageIn = nullptr);
qint64 findOutValueFromString(const QString &stringValue, bool &ok);
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index 4ca448d50..99e9d01a3 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -731,37 +731,6 @@ ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls,
return ArgumentOwner();
}
-
-QString AbstractMetaFunction::replacedDefaultExpression(const AbstractMetaClass *cls, int key) const
-{
- const FunctionModificationList &modifications = this->modifications(cls);
- for (const FunctionModification &modification : modifications) {
- for (const ArgumentModification &argumentModification : modification.argument_mods) {
- if (argumentModification.index == key
- && !argumentModification.replacedDefaultExpression.isEmpty()) {
- return argumentModification.replacedDefaultExpression;
- }
- }
- }
-
- return QString();
-}
-
-bool AbstractMetaFunction::removedDefaultExpression(const AbstractMetaClass *cls, int key) const
-{
- const FunctionModificationList &modifications = this->modifications(cls);
- for (const FunctionModification &modification : modifications) {
- for (const ArgumentModification &argumentModification : modification.argument_mods) {
- if (argumentModification.index == key
- && argumentModification.removedDefaultExpression) {
- return true;
- }
- }
- }
-
- return false;
-}
-
QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const
{
const FunctionModificationList &modifications = this->modifications(declaringClass());
@@ -780,19 +749,6 @@ QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int
return QString();
}
-QString AbstractMetaFunction::argumentReplaced(int key) const
-{
- const FunctionModificationList &modifications = this->modifications(declaringClass());
- for (const FunctionModification &modification : modifications) {
- for (const ArgumentModification &argumentModification : modification.argument_mods) {
- if (argumentModification.index == key && !argumentModification.replace_value.isEmpty())
- return argumentModification.replace_value;
- }
- }
-
- return QString();
-}
-
// FIXME If we remove a arg. in the method at the base class, it will not reflect here.
bool AbstractMetaFunction::argumentRemoved(int key) const
{
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index 7f0f9fbaa..077191471 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -671,7 +671,9 @@ public:
}
bool hasDefaultValueExpression() const
- { return !m_originalExpression.isEmpty() || !m_expression.isEmpty(); }
+ { return !m_expression.isEmpty(); }
+ bool hasOriginalDefaultValueExpression() const
+ { return !m_originalExpression.isEmpty(); }
bool hasUnmodifiedDefaultValueExpression() const
{ return !m_originalExpression.isEmpty() && m_originalExpression == m_expression; }
bool hasModifiedDefaultValueExpression() const
@@ -1020,8 +1022,6 @@ public:
AbstractMetaFunction *copy() const;
- QString replacedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
- bool removedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
QString conversionRule(TypeSystem::Language language, int idx) const;
QVector<ReferenceCount> referenceCounts(const AbstractMetaClass *cls, int idx = -2) const;
ArgumentOwner argumentOwner(const AbstractMetaClass *cls, int idx) const;
@@ -1034,9 +1034,6 @@ public:
bool isRemovedFromAllLanguages(const AbstractMetaClass *) const;
bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const;
bool argumentRemoved(int) const;
-
- QString argumentReplaced(int key) const;
-
/**
* Verifies if any modification to the function is an inject code.
* \return true if there is inject code modifications to the function.
@@ -1695,9 +1692,10 @@ public:
return m_stream;
}
- void setToStringCapability(bool value)
+ void setToStringCapability(bool value, uint indirections = 0)
{
m_hasToStringCapability = value;
+ m_toStringCapabilityIndirections = indirections;
}
bool hasToStringCapability() const
@@ -1705,6 +1703,11 @@ public:
return m_hasToStringCapability;
}
+ uint toStringCapabilityIndirections() const
+ {
+ return m_toStringCapabilityIndirections;
+ }
+
bool deleteInMainThread() const;
static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
@@ -1757,6 +1760,7 @@ private:
// FunctionModelItem m_qDebugStreamFunction;
bool m_stream = false;
+ uint m_toStringCapabilityIndirections = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::FunctionQueryOptions)
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp
index 98b493c67..b85a022b3 100644
--- a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp
@@ -47,11 +47,12 @@ void TestAbstractMetaClass::testClassName()
void TestAbstractMetaClass::testClassNameUnderNamespace()
{
const char* cppCode ="namespace Namespace { class ClassName {}; }\n";
- const char* xmlCode = "\
- <typesystem package=\"Foo\">\n\
- <namespace-type name=\"Namespace\"/>\n\
- <value-type name=\"Namespace::ClassName\"/>\n\
- </typesystem>\n";
+ const char* xmlCode = R"XML(
+ <typesystem package="Foo">
+ <namespace-type name="Namespace">
+ <value-type name="ClassName"/>
+ </namespace-type>
+ </typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -201,11 +202,12 @@ void TestAbstractMetaClass::testDefaultValues()
class B {};\n\
void method(B b = B());\n\
};\n";
- const char* xmlCode = "\
- <typesystem package=\"Foo\">\n\
- <value-type name='A'/>\n\
- <value-type name='A::B'/>\n\
- </typesystem>\n";
+ const char* xmlCode = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -224,17 +226,17 @@ void TestAbstractMetaClass::testModifiedDefaultValues()
class B {};\n\
void method(B b = B());\n\
};\n";
- const char* xmlCode = "\
- <typesystem package=\"Foo\">\n\
- <value-type name='A'>\n\
- <modify-function signature='method(A::B)'>\n\
- <modify-argument index='1'>\n\
- <replace-default-expression with='Hello'/>\n\
- </modify-argument>\n\
- </modify-function>\n\
- </value-type>\n\
- <value-type name='A::B'/>\n\
- </typesystem>\n";
+ const char* xmlCode = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <modify-function signature='method(A::B)'>
+ <modify-argument index='1'>
+ <replace-default-expression with='Hello'/>
+ </modify-argument>
+ </modify-function>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -254,11 +256,12 @@ void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne()
class B {};\n\
virtual void method();\n\
};\n";
- const char* xmlCode = "\
- <typesystem package=\"Foo\">\n\
- <object-type name='A'/>\n\
- <value-type name='A::B'/>\n\
- </typesystem>\n";
+ const char* xmlCode = R"XML(
+ <typesystem package="Foo">
+ <object-type name='A'>
+ <value-type name='B'/>
+ </object-type>
+ </typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -281,11 +284,12 @@ void TestAbstractMetaClass::testForwardDeclaredInnerClass()
public:\n\
void foo();\n\
};\n";
- const char xmlCode[] = "\
- <typesystem package=\"Foo\">\n\
- <value-type name='A'/>\n\
- <value-type name='A::B'/>\n\
- </typesystem>\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
index c438e0c37..aeca2d3f4 100644
--- a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
@@ -71,8 +71,8 @@ void TestCodeInjections::testReadFile()
<value-type name='A'>\n\
<conversion-rule ") + attribute + QLatin1String("/>\n\
<inject-code class='target' ") + attribute + QLatin1String("/>\n\
+ <value-type name='B'/>\n\
</value-type>\n\
- <value-type name='A::B'/>\n\
</typesystem>\n");
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData()));
QVERIFY(!builder.isNull());
diff --git a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp
index f4204e9b9..0eee8af24 100644
--- a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp
@@ -69,6 +69,39 @@ void TestDtorInformation::testDtorIsVirtual()
QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasVirtualDestructor(), true);
}
+void TestDtorInformation::testDtorFromBaseIsVirtual()
+{
+ const char* cppCode = R"CPP(class ControlBase { public: ~ControlBase() {} };
+class Control : public ControlBase {};
+class SubjectBase { public: virtual ~SubjectBase() {} };
+class Subject : public SubjectBase {};
+)CPP";
+ const char* xmlCode = R"XML(<typesystem package="Foo"><value-type name="ControlBase"/>
+<value-type name="Control"/>"
+<value-type name="SubjectBase"/>"
+<value-type name="Subject"/>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 4);
+
+ auto klass = AbstractMetaClass::findClass(classes, QLatin1String("ControlBase"));
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, QLatin1String("Control"));
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+
+ klass = AbstractMetaClass::findClass(classes, QLatin1String("SubjectBase"));
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, QLatin1String("Subject"));
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+}
+
void TestDtorInformation::testClassWithVirtualDtorIsPolymorphic()
{
const char* cppCode ="class Control { public: virtual ~Control() {} }; class Subject { protected: virtual ~Subject() {} };";
diff --git a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h
index 068ef4952..0a57dd8d1 100644
--- a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h
+++ b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h
@@ -40,6 +40,7 @@ private slots:
void testDtorIsPrivate();
void testDtorIsProtected();
void testDtorIsVirtual();
+ void testDtorFromBaseIsVirtual();
void testClassWithVirtualDtorIsPolymorphic();
};
diff --git a/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp
index 2e5a5759a..2203f3648 100644
--- a/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp
@@ -44,13 +44,15 @@ void TestResolveType::testResolveReturnTypeFromParentScope()
C* method();\n\
};\n\
};";
- const char* xmlCode = "\n\
- <typesystem package='Foo'>\n\
- <namespace-type name='A'/>\n\
- <value-type name='A::B'/>\n\
- <value-type name='A::B::C'/>\n\
- <value-type name='A::D'/>\n\
- </typesystem>";
+ const char* xmlCode = R"XML(
+ <typesystem package='Foo'>
+ <namespace-type name='A'>
+ <value-type name='B'>
+ <value-type name='C'/>
+ </value-type>
+ <value-type name='D'/>
+ </namespace-type>
+ </typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
index 59b601f3b..5191cb38d 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
@@ -63,9 +63,10 @@ namespace Internet {
<typesystem package='Package.Internet'>
<load-typesystem name='%1' generate='no'/>
<container-type name='QList' type='list'/>
- <namespace-type name='Internet' generate='no'/>
- <value-type name='Internet::Url'/>
- <value-type name='Internet::Bookmarks'/>
+ <namespace-type name='Internet' generate='no'>
+ <value-type name='Url'/>
+ <value-type name='Bookmarks'/>
+ </namespace-type>
</typesystem>)XML").arg(file.fileName());
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false));
@@ -97,11 +98,12 @@ namespace Namespace {
const char xmlCode[] = R"XML(
<typesystem package="Package">
<container-type name='QList' type='list'/>
- <namespace-type name='Namespace'/>
- <enum-type name='Namespace::SomeEnum'/>
+ <namespace-type name='Namespace'>
+ <enum-type name='SomeEnum'/>
+ <object-type name='A' generate='no'/>
+ <object-type name='B'/>
+ </namespace-type>
<object-type name='Base'/>
- <object-type name='Namespace::A' generate='no'/>
- <object-type name='Namespace::B'/>
</typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
@@ -211,8 +213,9 @@ struct List {
const char xmlCode[] = R"XML(
<typesystem package='Package'>
- <container-type name='List' type='list'/>
- <value-type name='List::Iterator'/>
+ <container-type name='List' type='list'>
+ <value-type name='Iterator'/>
+ </container-type>
</typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
@@ -324,11 +327,12 @@ template<SomeEnum type> struct Future {};
const char xmlCode[] = R"XML(
<typesystem package='Package'>
- <namespace-type name='Namespace'/>
- <enum-type name='Namespace::SomeEnum'/>
- <value-type name='Namespace::A' generate='no'/>
- <value-type name='Namespace::B'/>
- <value-type name='Namespace::Future' generate='no'/>
+ <namespace-type name='Namespace'>
+ <enum-type name='SomeEnum'/>
+ <value-type name='A' generate='no'/>
+ <value-type name='B'/>
+ <value-type name='Future' generate='no'/>
+ </namespace-type>
</typesystem>)XML";
QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt
index be1b4cd7f..c1349cae6 100644
--- a/sources/shiboken2/CMakeLists.txt
+++ b/sources/shiboken2/CMakeLists.txt
@@ -19,42 +19,9 @@ option(USE_PYTHON_VERSION "Use specific python version to build shiboken2." "")
option(DISABLE_DOCSTRINGS "Disable documentation extraction." FALSE)
find_package(Qt5 5.12 REQUIRED COMPONENTS Core)
-find_package(Qt5Xml 5.12)
-find_package(Qt5XmlPatterns 5.12)
-find_package(LibXml2 2.6.32)
-find_package(LibXslt 1.1.19)
-if(BUILD_TESTS)
- find_package(Qt5Test 5.12 REQUIRED)
-endif()
-
-set(HAS_LIBXSLT 0)
-if (LIBXSLT_FOUND AND LIBXML2_FOUND)
- set(HAS_LIBXSLT 1)
-endif()
-
-if(NOT Qt5XmlPatterns_FOUND AND NOT HAS_LIBXSLT)
- set(DISABLE_DOCSTRINGS TRUE)
- message(WARNING
- "Documentation will not be built due to missing dependency (no Qt5XmlPatterns found).")
-endif()
-
-# Don't display "up-to-date / install" messages when installing, to reduce visual clutter.
-if (QUIET_BUILD)
- set(CMAKE_INSTALL_MESSAGE NEVER)
-endif()
-# Override message not to display info messages when doing a quiet build.
if (QUIET_BUILD)
- function(message)
- list(GET ARGV 0 MessageType)
- if (MessageType STREQUAL FATAL_ERROR OR
- MessageType STREQUAL SEND_ERROR OR
- MessageType STREQUAL WARNING OR
- MessageType STREQUAL AUTHOR_WARNING)
- list(REMOVE_AT ARGV 0)
- _message(${MessageType} "${ARGV}")
- endif()
- endfunction()
+ set_quiet_build()
endif()
if (USE_PYTHON_VERSION)
@@ -63,115 +30,11 @@ else()
shiboken_find_required_python()
endif()
-macro(get_python_arch)
- execute_process(
- COMMAND ${PYTHON_EXECUTABLE} -c "if True:
- import sys
- print('64' if sys.maxsize > 2**31-1 else '32')
- "
- OUTPUT_VARIABLE PYTHON_ARCH
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- message("PYTHON_ARCH: " ${PYTHON_ARCH})
-endmacro()
-
if (NOT PYTHON_ARCH)
get_python_arch()
endif()
-macro(get_llvm_config)
- execute_process(
- COMMAND ${PYTHON_EXECUTABLE} -c "if True:
- import os
- import sys
- sys.path.append(os.path.realpath(os.path.join('${CMAKE_CURRENT_LIST_DIR}', '..', '..')))
- from build_scripts.utils import find_llvm_config
- llvmConfig = find_llvm_config()
- if llvmConfig:
- print(llvmConfig)
- "
- OUTPUT_VARIABLE LLVM_CONFIG
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- message("LLVM_CONFIG: " ${LLVM_CONFIG})
-endmacro()
-
-set(CLANG_DIR "")
-set(CLANG_DIR_SOURCE "")
-
-set(clang_not_found_message "Unable to detect CLANG location by checking LLVM_INSTALL_DIR, \
- CLANG_INSTALL_DIR or running llvm-config.")
-
-if (DEFINED ENV{LLVM_INSTALL_DIR})
- set(CLANG_DIR $ENV{LLVM_INSTALL_DIR})
- string(REPLACE "_ARCH_" "${PYTHON_ARCH}" CLANG_DIR "${CLANG_DIR}")
- set(CLANG_DIR_SOURCE "LLVM_INSTALL_DIR")
-elseif (DEFINED ENV{CLANG_INSTALL_DIR})
- set(CLANG_DIR $ENV{CLANG_INSTALL_DIR})
- string(REPLACE "_ARCH_" "${PYTHON_ARCH}" CLANG_DIR "${CLANG_DIR}")
- set(CLANG_DIR_SOURCE "CLANG_INSTALL_DIR")
-else ()
- if (NOT LLVM_CONFIG)
- get_llvm_config()
- endif()
- set(CLANG_DIR_SOURCE "${LLVM_CONFIG}")
- if ("${CLANG_DIR_SOURCE}" STREQUAL "")
- message(FATAL_ERROR "${clang_not_found_message}")
- endif()
-
- EXEC_PROGRAM("${LLVM_CONFIG}" ARGS "--prefix" OUTPUT_VARIABLE CLANG_DIR)
- if (NOT "${CLANG_DIR}" STREQUAL "")
- EXEC_PROGRAM("${LLVM_CONFIG}" ARGS "--version" OUTPUT_VARIABLE CLANG_VERSION)
- if (CLANG_VERSION VERSION_LESS 3.9)
- message(FATAL_ERROR "libclang version 3.9 or higher is required (${LLVM_CONFIG} detected ${CLANG_VERSION} at ${CLANG_DIR}).")
- endif()
- endif()
-endif()
-
-if ("${CLANG_DIR}" STREQUAL "")
- message(FATAL_ERROR "${clang_not_found_message}")
-elseif (NOT IS_DIRECTORY ${CLANG_DIR})
- message(FATAL_ERROR "${CLANG_DIR} detected by ${CLANG_DIR_SOURCE} does not exist.")
-endif()
-
-# The non-development Debian / Ubuntu packages (e.g. libclang1-6.0) do not ship a
-# libclang.so symlink, but only libclang-6.0.so.1 and libclang.so.1 (adjusted for version number).
-# Thus searching for libclang would not succeed.
-# The "libclang.so" symlink is shipped as part of the development package (libclang-6.0-dev) which
-# we need anyway because of the headers. Thus we will search for libclang.so.1 also, and complain
-# about the headers not being found in a check further down. This is more friendly to the user,
-# so they don't scratch their head thinking that they have already installed the necessary package.
-set(CLANG_LIB_NAMES clang libclang.so libclang.so.1)
-if(MSVC)
- set(CLANG_LIB_NAMES libclang)
-endif()
-
-find_library(CLANG_LIBRARY NAMES ${CLANG_LIB_NAMES} HINTS ${CLANG_DIR}/lib)
-if (NOT EXISTS ${CLANG_LIBRARY})
- string(REPLACE ";" ", " CLANG_LIB_NAMES_STRING "${CLANG_LIB_NAMES}")
- message(FATAL_ERROR "Unable to find the Clang library in ${CLANG_DIR}.\
- Names tried: ${CLANG_LIB_NAMES_STRING}.")
-endif()
-
-message(STATUS "CLANG: ${CLANG_DIR}, ${CLANG_LIBRARY} detected by ${CLANG_DIR_SOURCE}")
-
-set(CLANG_EXTRA_INCLUDES ${CLANG_DIR}/include)
-set(CLANG_EXTRA_LIBRARIES ${CLANG_LIBRARY})
-
-# Check if one of the required clang headers is found. Error out early at CMake time instead of
-# compile time if not found.
-# It can happen that a user uses a distro-provided libclang.so, but no development header package
-# was installed (e.g. libclang-6.0-dev on Ubuntu).
-set(CMAKE_REQUIRED_INCLUDES ${CLANG_EXTRA_INCLUDES})
-set(CLANG_HEADER_FILE_TO_CHECK "clang-c/Index.h")
-check_include_file_cxx(${CLANG_HEADER_FILE_TO_CHECK} CLANG_INCLUDE_FOUND)
-unset(CMAKE_REQUIRED_INCLUDES)
-if (NOT CLANG_INCLUDE_FOUND)
- # Need to unset so that when installing the package, CMake doesn't complain that the header
- # still isn't found.
- unset(CLANG_INCLUDE_FOUND CACHE)
- message(FATAL_ERROR "Unable to find required Clang header file ${CLANG_HEADER_FILE_TO_CHECK} \
- in ${CLANG_DIR}/include. Perhaps you forgot to install the clang development header \
- package? (e.g. libclang-6.0-dev)")
-endif()
+setup_clang()
set(SHIBOKEN_VERSION_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/shiboken_version.py")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
@@ -209,29 +72,6 @@ message("PYTHONINTERP_FOUND: " ${PYTHONINTERP_FOUND})
message("PYTHON_EXECUTABLE: " ${PYTHON_EXECUTABLE})
message("PYTHON_VERSION: " ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH})
-macro(get_python_extension_suffix)
- # Result of imp.get_suffixes() depends on the platform, but generally looks something like:
- # [('.cpython-34m-x86_64-linux-gnu.so', 'rb', 3), ('.cpython-34m.so', 'rb', 3),
- # ('.abi3.so', 'rb', 3), ('.so', 'rb', 3), ('.py', 'r', 1), ('.pyc', 'rb', 2)]
- # We pick the first most detailed one, strip of the file extension part.
-
- execute_process(
- COMMAND ${PYTHON_EXECUTABLE} -c "if True:
- import imp, re
- first_suffix = imp.get_suffixes()[0][0]
- res = re.search(r'^(.+)\\.', first_suffix)
- if res:
- first_suffix = res.group(1)
- else:
- first_suffix = ''
- print(first_suffix)
- "
- OUTPUT_VARIABLE PYTHON_EXTENSION_SUFFIX
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- message("PYTHON_EXTENSION_SUFFIX: " ${PYTHON_EXTENSION_SUFFIX})
-endmacro()
-
-
if (NOT PYTHON_EXTENSION_SUFFIX)
get_python_extension_suffix()
endif()
@@ -242,42 +82,15 @@ set(PYTHON_LIMITED_API 0)
shiboken_check_if_limited_api()
if (PYTHON_LIMITED_API)
- if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}")
- message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!")
- endif()
- message(STATUS "******************************************************")
- message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}")
- message(STATUS "******************************************************")
+ set_limited_api()
endif()
if (NOT PYTHON_CONFIG_SUFFIX)
- if (PYTHON_VERSION_MAJOR EQUAL 2)
- set(PYTHON_CONFIG_SUFFIX "-python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
- if (PYTHON_EXTENSION_SUFFIX)
- set(PYTHON_CONFIG_SUFFIX "${PYTHON_CONFIG_SUFFIX}${PYTHON_EXTENSION_SUFFIX}")
- endif()
- elseif (PYTHON_VERSION_MAJOR EQUAL 3)
- if (PYTHON_LIMITED_API)
- if(WIN32)
- set(PYTHON_EXTENSION_SUFFIX "")
- else()
- set(PYTHON_EXTENSION_SUFFIX ".abi3")
- endif()
- set(PYTHON_CONFIG_SUFFIX ".abi3")
- else()
- set(PYTHON_CONFIG_SUFFIX "${PYTHON_EXTENSION_SUFFIX}")
- endif()
- endif()
+ set_python_config_suffix()
endif()
if (NOT PYTHON_SHARED_LIBRARY_SUFFIX)
- set(PYTHON_SHARED_LIBRARY_SUFFIX "${PYTHON_CONFIG_SUFFIX}")
-
- # Append a "v" to disambiguate the python version and the shiboken version in the
- # shared library file name.
- if (APPLE AND PYTHON_VERSION_MAJOR EQUAL 2)
- set(PYTHON_SHARED_LIBRARY_SUFFIX "${PYTHON_SHARED_LIBRARY_SUFFIX}v")
- endif()
+ set_python_shared_library_suffix()
endif()
if (NOT PYTHON_CONFIG_SUFFIX)
@@ -291,39 +104,10 @@ message(STATUS "PYTHON_SHARED_LIBRARY_SUFFIX: ${PYTHON_SHARED_LIBRARY_SUFFIX}")
if (NOT PYTHON_SITE_PACKAGES)
- execute_process(
- COMMAND ${PYTHON_EXECUTABLE} -c "if True:
- from distutils import sysconfig
- from os.path import sep
- print(sysconfig.get_python_lib(1, 0, prefix='${CMAKE_INSTALL_PREFIX}').replace(sep, '/'))
- "
- OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if (NOT PYTHON_SITE_PACKAGES)
- message(FATAL_ERROR "Could not detect Python module installation directory.")
- elseif (APPLE)
- message(STATUS "!!! The generated bindings will be installed on ${PYTHON_SITE_PACKAGES}, is it right!?")
- endif()
-endif()
-
-if(MSVC)
- # Qt5: this flag has changed from /Zc:wchar_t- in Qt4.X
- set(CMAKE_CXX_FLAGS "/Zc:wchar_t /GR /EHsc /DWIN32 /D_WINDOWS /D_SCL_SECURE_NO_WARNINGS")
-else()
- if(CMAKE_HOST_UNIX AND NOT CYGWIN)
- add_definitions(-fPIC)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fvisibility=hidden -Wno-strict-aliasing")
- endif()
- set(CMAKE_CXX_FLAGS_DEBUG "-g")
- option(ENABLE_GCC_OPTIMIZATION "Enable specific GCC flags to optimization library size and performance. Only available on Release Mode" 0)
- if(ENABLE_GCC_OPTIMIZATION)
- set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -Os -Wl,-O1")
- if(NOT CMAKE_HOST_APPLE)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--hash-style=gnu")
- endif()
- endif()
+ set_python_site_packages()
endif()
+set_cmake_cxx_flags()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D QT_NO_CAST_FROM_ASCII -D QT_NO_CAST_TO_ASCII")
# Force usage of the C++11 standard, without a silent fallback
@@ -332,8 +116,10 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" )
-set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
-set(BIN_INSTALL_DIR "bin" CACHE PATH "The subdirectory relative to the install prefix where dlls will be installed (default is /bin)" FORCE)
+set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install \
+ prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
+set(BIN_INSTALL_DIR "bin" CACHE PATH "The subdirectory relative to the install prefix where \
+ dlls will be installed (default is /bin)" FORCE)
if (WIN32)
set(PATH_SEP "\;")
@@ -342,26 +128,17 @@ else()
endif()
if(CMAKE_HOST_APPLE)
- set(OSX_USE_LIBCPP "OFF" CACHE BOOL "Explicitly link the libc++ standard library (useful for osx deployment targets lower than 10.9.")
+ set(OSX_USE_LIBCPP "OFF" CACHE BOOL "Explicitly link the libc++ standard library \
+ (useful for osx deployment targets lower than 10.9.")
if(OSX_USE_LIBCPP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
endif()
-# Build with Address sanitizer enabled if requested. This may break things, so use at your own risk.
+# Build with Address sanitizer enabled if requested.
+# This may break things, so use at your own risk.
if (SANITIZE_ADDRESS AND NOT MSVC)
- # Currently this does not check that the clang / gcc version used supports Address sanitizer,
- # so once again, use at your own risk.
- add_compile_options("-fsanitize=address" "-g" "-fno-omit-frame-pointer")
- # We need to add the sanitize address option to all linked executables / shared libraries
- # so that proper sanitizer symbols are linked in.
- #
- # Note that when running tests, you may need to set an additional environment variable
- # in set_tests_properties for shiboken2 / pyside tests, or exported in your shell. Address
- # sanitizer will tell you what environment variable needs to be exported. For example:
- # export DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/Toolchains/
- # ./XcodeDefault.xctoolchain/usr/lib/clang/8.1.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib
- set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_STANDARD_LIBRARIES} -fsanitize=address")
+ set_sanitize_address()
endif()
# Detect if the python libs were compiled in debug mode
@@ -410,23 +187,12 @@ execute_process(
set(SHIBOKEN_BUILD_TYPE "${CMAKE_BUILD_TYPE}")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
- set(SHIBOKEN_BUILD_TYPE "Debug")
-
- if(NOT PYTHON_DEBUG_LIBRARIES)
- message(WARNING "Python debug shared library not found; assuming python was built with shared library support disabled.")
- endif()
-
- if(NOT PYTHON_WITH_DEBUG)
- message(WARNING "Compiling shiboken2 with debug enabled, but the python executable was not compiled with debug support.")
- else()
- set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION " -DPy_DEBUG")
- endif()
-
- if (PYTHON_WITH_COUNT_ALLOCS)
- set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION "${SBK_PKG_CONFIG_PY_DEBUG_DEFINITION} -DCOUNT_ALLOCS")
- endif()
+ set_debug_build()
endif()
+######################################################################
+# Adding sub directories to build
+######################################################################
add_subdirectory(ApiExtractor)
set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX})
@@ -451,7 +217,7 @@ if (Qt5Core_FOUND AND PYTHONINTERP_FOUND)
add_subdirectory(tests)
endif()
else()
- message(WARNING "Some dependencies were not found, shiboken2 generator compilation disabled!")
+ message(WARNING "Some dependencies were not found: shiboken2 generator compilation disabled!")
endif()
add_subdirectory(data)
diff --git a/sources/shiboken2/data/shiboken_helpers.cmake b/sources/shiboken2/data/shiboken_helpers.cmake
index f4dd4d5dc..8111fa61f 100644
--- a/sources/shiboken2/data/shiboken_helpers.cmake
+++ b/sources/shiboken2/data/shiboken_helpers.cmake
@@ -1,5 +1,274 @@
include(CMakeParseArguments)
+macro(set_python_shared_library_suffix)
+ set(PYTHON_SHARED_LIBRARY_SUFFIX "${PYTHON_CONFIG_SUFFIX}")
+
+ # Append a "v" to disambiguate the python version and the shiboken version in the
+ # shared library file name.
+ if (APPLE AND PYTHON_VERSION_MAJOR EQUAL 2)
+ set(PYTHON_SHARED_LIBRARY_SUFFIX "${PYTHON_SHARED_LIBRARY_SUFFIX}v")
+ endif()
+endmacro()
+
+macro(set_limited_api)
+ if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}")
+ message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!")
+ endif()
+ message(STATUS "******************************************************")
+ message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}")
+ message(STATUS "******************************************************")
+endmacro()
+
+macro(set_debug_build)
+ set(SHIBOKEN_BUILD_TYPE "Debug")
+
+ if(NOT PYTHON_DEBUG_LIBRARIES)
+ message(WARNING "Python debug shared library not found; \
+ assuming python was built with shared library support disabled.")
+ endif()
+
+ if(NOT PYTHON_WITH_DEBUG)
+ message(WARNING "Compiling shiboken2 with debug enabled, \
+ but the python executable was not compiled with debug support.")
+ else()
+ set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION " -DPy_DEBUG")
+ endif()
+
+ if (PYTHON_WITH_COUNT_ALLOCS)
+ set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION "${SBK_PKG_CONFIG_PY_DEBUG_DEFINITION} -DCOUNT_ALLOCS")
+ endif()
+endmacro()
+
+macro(setup_sanitize_address)
+ # Currently this does not check that the clang / gcc version used supports Address sanitizer,
+ # so once again, use at your own risk.
+ add_compile_options("-fsanitize=address" "-g" "-fno-omit-frame-pointer")
+ # We need to add the sanitize address option to all linked executables / shared libraries
+ # so that proper sanitizer symbols are linked in.
+ #
+ # Note that when running tests, you may need to set an additional environment variable
+ # in set_tests_properties for shiboken2 / pyside tests, or exported in your shell. Address
+ # sanitizer will tell you what environment variable needs to be exported. For example:
+ # export DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/Toolchains/
+ # ./XcodeDefault.xctoolchain/usr/lib/clang/8.1.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib
+ set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_STANDARD_LIBRARIES} -fsanitize=address")
+endmacro()
+
+macro(set_cmake_cxx_flags)
+if(MSVC)
+ # Qt5: this flag has changed from /Zc:wchar_t- in Qt4.X
+ set(CMAKE_CXX_FLAGS "/Zc:wchar_t /GR /EHsc /DWIN32 /D_WINDOWS /D_SCL_SECURE_NO_WARNINGS")
+ #set(CMAKE_CXX_FLAGS "/Zc:wchar_t /GR /EHsc /DNOCOLOR /DWIN32 /D_WINDOWS /D_SCL_SECURE_NO_WARNINGS") # XXX
+else()
+ if(CMAKE_HOST_UNIX AND NOT CYGWIN)
+ add_definitions(-fPIC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fvisibility=hidden -Wno-strict-aliasing")
+ endif()
+ set(CMAKE_CXX_FLAGS_DEBUG "-g")
+ option(ENABLE_GCC_OPTIMIZATION "Enable specific GCC flags to optimization library \
+ size and performance. Only available on Release Mode" 0)
+ if(ENABLE_GCC_OPTIMIZATION)
+ set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -Os -Wl,-O1")
+ if(NOT CMAKE_HOST_APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--hash-style=gnu")
+ endif()
+ endif()
+ if(CMAKE_HOST_APPLE)
+ # ALTERNATIVE_QT_INCLUDE_DIR is deprecated, because CMake takes care of finding the proper
+ # include folders using the qmake found in the environment. Only use it for now in case
+ # something goes wrong with the cmake process.
+ if(ALTERNATIVE_QT_INCLUDE_DIR AND NOT QT_INCLUDE_DIR)
+ set(QT_INCLUDE_DIR ${ALTERNATIVE_QT_INCLUDE_DIR})
+ endif()
+ endif()
+endif()
+
+endmacro()
+
+macro(set_python_site_packages)
+ execute_process(
+ COMMAND ${PYTHON_EXECUTABLE} -c "if True:
+ from distutils import sysconfig
+ from os.path import sep
+ print(sysconfig.get_python_lib(1, 0, prefix='${CMAKE_INSTALL_PREFIX}').replace(sep, '/'))
+ "
+ OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (NOT PYTHON_SITE_PACKAGES)
+ message(FATAL_ERROR "Could not detect Python module installation directory.")
+ elseif (APPLE)
+ message(STATUS "!!! The generated bindings will be installed on ${PYTHON_SITE_PACKAGES}, \
+ is it right!?")
+ endif()
+endmacro()
+
+macro(set_python_config_suffix)
+ if (PYTHON_VERSION_MAJOR EQUAL 2)
+ set(PYTHON_CONFIG_SUFFIX "-python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
+ if (PYTHON_EXTENSION_SUFFIX)
+ set(PYTHON_CONFIG_SUFFIX "${PYTHON_CONFIG_SUFFIX}${PYTHON_EXTENSION_SUFFIX}")
+ endif()
+ elseif (PYTHON_VERSION_MAJOR EQUAL 3)
+ if (PYTHON_LIMITED_API)
+ if(WIN32)
+ set(PYTHON_EXTENSION_SUFFIX "")
+ else()
+ set(PYTHON_EXTENSION_SUFFIX ".abi3")
+ endif()
+ set(PYTHON_CONFIG_SUFFIX ".abi3")
+ else()
+ set(PYTHON_CONFIG_SUFFIX "${PYTHON_EXTENSION_SUFFIX}")
+ endif()
+ endif()
+endmacro()
+
+macro(setup_clang)
+ set(CLANG_DIR "")
+ set(CLANG_DIR_SOURCE "")
+
+ set(clang_not_found_message "Unable to detect CLANG location by checking LLVM_INSTALL_DIR, \
+ CLANG_INSTALL_DIR or running llvm-config.")
+
+ if (DEFINED ENV{LLVM_INSTALL_DIR})
+ set(CLANG_DIR $ENV{LLVM_INSTALL_DIR})
+ string(REPLACE "_ARCH_" "${PYTHON_ARCH}" CLANG_DIR "${CLANG_DIR}")
+ set(CLANG_DIR_SOURCE "LLVM_INSTALL_DIR")
+ elseif (DEFINED ENV{CLANG_INSTALL_DIR})
+ set(CLANG_DIR $ENV{CLANG_INSTALL_DIR})
+ string(REPLACE "_ARCH_" "${PYTHON_ARCH}" CLANG_DIR "${CLANG_DIR}")
+ set(CLANG_DIR_SOURCE "CLANG_INSTALL_DIR")
+ else ()
+ if (NOT LLVM_CONFIG)
+ get_llvm_config()
+ endif()
+ set(CLANG_DIR_SOURCE "${LLVM_CONFIG}")
+ if ("${CLANG_DIR_SOURCE}" STREQUAL "")
+ message(FATAL_ERROR "${clang_not_found_message}")
+ endif()
+
+ EXEC_PROGRAM("${LLVM_CONFIG}" ARGS "--prefix" OUTPUT_VARIABLE CLANG_DIR)
+ if (NOT "${CLANG_DIR}" STREQUAL "")
+ EXEC_PROGRAM("${LLVM_CONFIG}" ARGS "--version" OUTPUT_VARIABLE CLANG_VERSION)
+ if (CLANG_VERSION VERSION_LESS 3.9)
+ message(FATAL_ERROR "libclang version 3.9 or higher is required \
+ (${LLVM_CONFIG} detected ${CLANG_VERSION} at ${CLANG_DIR}).")
+ endif()
+ endif()
+ endif()
+
+ if ("${CLANG_DIR}" STREQUAL "")
+ message(FATAL_ERROR "${clang_not_found_message}")
+ elseif (NOT IS_DIRECTORY ${CLANG_DIR})
+ message(FATAL_ERROR "${CLANG_DIR} detected by ${CLANG_DIR_SOURCE} does not exist.")
+ endif()
+
+ # The non-development Debian / Ubuntu packages (e.g. libclang1-6.0) do not ship a
+ # libclang.so symlink, but only libclang-6.0.so.1 and libclang.so.1 (adjusted for version number).
+ # Thus searching for libclang would not succeed.
+ # The "libclang.so" symlink is shipped as part of the development package (libclang-6.0-dev) which
+ # we need anyway because of the headers. Thus we will search for libclang.so.1 also, and complain
+ # about the headers not being found in a check further down. This is more friendly to the user,
+ # so they don't scratch their head thinking that they have already installed the necessary package.
+ set(CLANG_LIB_NAMES clang libclang.so libclang.so.1)
+ if(MSVC)
+ set(CLANG_LIB_NAMES libclang)
+ endif()
+
+ find_library(CLANG_LIBRARY NAMES ${CLANG_LIB_NAMES} HINTS ${CLANG_DIR}/lib)
+ if (NOT EXISTS ${CLANG_LIBRARY})
+ string(REPLACE ";" ", " CLANG_LIB_NAMES_STRING "${CLANG_LIB_NAMES}")
+ message(FATAL_ERROR "Unable to find the Clang library in ${CLANG_DIR}.\
+ Names tried: ${CLANG_LIB_NAMES_STRING}.")
+ endif()
+
+ message(STATUS "CLANG: ${CLANG_DIR}, ${CLANG_LIBRARY} detected by ${CLANG_DIR_SOURCE}")
+
+ set(CLANG_EXTRA_INCLUDES ${CLANG_DIR}/include)
+ set(CLANG_EXTRA_LIBRARIES ${CLANG_LIBRARY})
+
+ # Check if one of the required clang headers is found. Error out early at CMake time instead of
+ # compile time if not found.
+ # It can happen that a user uses a distro-provided libclang.so, but no development header package
+ # was installed (e.g. libclang-6.0-dev on Ubuntu).
+ set(CMAKE_REQUIRED_INCLUDES ${CLANG_EXTRA_INCLUDES})
+ set(CLANG_HEADER_FILE_TO_CHECK "clang-c/Index.h")
+ check_include_file_cxx(${CLANG_HEADER_FILE_TO_CHECK} CLANG_INCLUDE_FOUND)
+ unset(CMAKE_REQUIRED_INCLUDES)
+ if (NOT CLANG_INCLUDE_FOUND)
+ # Need to unset so that when installing the package, CMake doesn't complain that the header
+ # still isn't found.
+ unset(CLANG_INCLUDE_FOUND CACHE)
+ message(FATAL_ERROR "Unable to find required Clang header file ${CLANG_HEADER_FILE_TO_CHECK} \
+ in ${CLANG_DIR}/include. Perhaps you forgot to install the clang development header \
+ package? (e.g. libclang-6.0-dev)")
+ endif()
+endmacro()
+
+macro(set_quiet_build)
+ # Don't display "up-to-date / install" messages when installing, to reduce visual clutter.
+ set(CMAKE_INSTALL_MESSAGE NEVER PARENT_SCOPE)
+ # Override message not to display info messages when doing a quiet build.
+ function(message)
+ list(GET ARGV 0 MessageType)
+ if (MessageType STREQUAL FATAL_ERROR OR
+ MessageType STREQUAL SEND_ERROR OR
+ MessageType STREQUAL WARNING OR
+ MessageType STREQUAL AUTHOR_WARNING)
+ list(REMOVE_AT ARGV 0)
+ _message(${MessageType} "${ARGV}")
+ endif()
+ endfunction()
+endmacro()
+
+macro(get_python_extension_suffix)
+ # Result of imp.get_suffixes() depends on the platform, but generally looks something like:
+ # [('.cpython-34m-x86_64-linux-gnu.so', 'rb', 3), ('.cpython-34m.so', 'rb', 3),
+ # ('.abi3.so', 'rb', 3), ('.so', 'rb', 3), ('.py', 'r', 1), ('.pyc', 'rb', 2)]
+ # We pick the first most detailed one, strip of the file extension part.
+
+ execute_process(
+ COMMAND ${PYTHON_EXECUTABLE} -c "if True:
+ import imp, re
+ first_suffix = imp.get_suffixes()[0][0]
+ res = re.search(r'^(.+)\\.', first_suffix)
+ if res:
+ first_suffix = res.group(1)
+ else:
+ first_suffix = ''
+ print(first_suffix)
+ "
+ OUTPUT_VARIABLE PYTHON_EXTENSION_SUFFIX
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message("PYTHON_EXTENSION_SUFFIX: " ${PYTHON_EXTENSION_SUFFIX})
+endmacro()
+
+macro(get_llvm_config)
+ execute_process(
+ COMMAND ${PYTHON_EXECUTABLE} -c "if True:
+ import os
+ import sys
+ sys.path.append(os.path.realpath(os.path.join('${CMAKE_CURRENT_LIST_DIR}', '..', '..')))
+ from build_scripts.utils import find_llvm_config
+ llvmConfig = find_llvm_config()
+ if llvmConfig:
+ print(llvmConfig)
+ "
+ OUTPUT_VARIABLE LLVM_CONFIG
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message("LLVM_CONFIG: " ${LLVM_CONFIG})
+endmacro()
+
+macro(get_python_arch)
+ execute_process(
+ COMMAND ${PYTHON_EXECUTABLE} -c "if True:
+ import sys
+ print('64' if sys.maxsize > 2**31-1 else '32')
+ "
+ OUTPUT_VARIABLE PYTHON_ARCH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message("PYTHON_ARCH: " ${PYTHON_ARCH})
+endmacro()
+
macro(shiboken_parse_all_arguments prefix type flags options multiopts)
cmake_parse_arguments(${prefix} "${flags}" "${options}" "${multiopts}" ${ARGN})
if(DEFINED ${prefix}_UNPARSED_ARGUMENTS)
diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css b/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css
index 956e3113b..23e460262 100644
--- a/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css
+++ b/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css
@@ -3,8 +3,8 @@
/* -- admonitions -- */
div.admonition {
- margin: 1em 0 1em;
- padding: 7px;
+ margin: 1.5em 0 1.5em;
+ padding: 0;
}
div.admonition dt {
@@ -19,6 +19,23 @@ p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
+
+div.admonition code {
+ font-family: inherit;
+}
+
+p.admonition-title + p {
+ padding-left: 1em;
+}
+
+div.admonition a:after {
+ content: ', ';
+}
+
+div.admonition a:last-child:after {
+ content: '';
+}
+
.body {
width: 100%
}
@@ -35,18 +52,21 @@ div.body p.centered {
margin-top: 25px;
}
+div.warning, div.seealso, div.note {
+ padding: 6px 0px 6px 10px;
+ border: none;
+}
+
div.warning {
background-color: #ffe4e4;
- border: 1px solid #f66;
}
div.seealso {
- background-color: #ffffcc;
- border: 1px solid #ffff66;
+ background-color: #fff2d6;
}
div.note {
- border: 1px solid #e3e3e3;
+ background-color: #f3f3f4;
}
table.docutils {
@@ -91,7 +111,7 @@ h2 em {
.body blockquote {
border: none;
padding-left: 0;
- margin-bottom: 2em;
+ margin-bottom: 1.5em;
}
.sphinxsidebar {
@@ -146,11 +166,8 @@ h2 em {
display: block;
padding: 5px;
margin: 0 10px 10px 0;
- border: 1px solid #ddd;
- background-color: #f4f4f4;
- -moz-border-radius:6px;
- -webkit-border-radius:6px;
- -khtml-border-radius:6px;
+ border: none;
+ background-color: #e2e2e2;
}
.section .docutils.container td {
@@ -290,14 +307,23 @@ tt.descname {
}
#functions ul, #virtual-functions ul, #slots ul, #signals ul, #static-functions ul {
- list-style: none;
- margin: 0px;
- padding: 10px;
+ margin: 0;
+ padding: 6px;
border: 1px solid #ddd;
- background-color: #f4f4f4;
- -moz-border-radius:10px;
- -webkit-border-radius:10px;
- -khtml-border-radius:10px;
+ border-radius: 0;
+ background-color: #e2e2e2;
+}
+
+#functions p, #virtual-functions p, #slots p, #signals p, #static-functions p {
+ margin: 0;
+ padding: 0;
+}
+
+#functions li, #virtual-functions li, #slots li, #signals li, #static-functions li {
+ list-style: none;
+ margin: 5px;
+ padding: 0;
+ font-size: 90%;
}
#synopsis span.pre {
@@ -312,11 +338,94 @@ tt.descname {
margin: 0px;
margin-bottom: 10px;
padding: 10px;
- border: 1px solid #ddd;
- background-color: #f4f4f4;
- -moz-border-radius:10px;
- -webkit-border-radius:10px;
- -khtml-border-radius:10px;
+ font-weight: bold;
+ background-color: #e2e2e2;
+ border: none;
+ border-radius: 0;
+}
+
+#detailed-description dd > blockquote,
+#detailed-description dd > .field-list {
+ font-family: 'Droid Sans Mono';
+ font-size: small;
+ border-left: 10px solid #e2e2e2;
+ padding-left: 10px;
+ margin-bottom: 1.5em;
+}
+
+#detailed-description dd > blockquote blockquote {
+ border: none;
+ padding: 0;
+}
+
+#detailed-description .class .field-odd,
+#detailed-description .method .field-odd,
+#detailed-description .staticmethod .field-odd,
+#detailed-description .attribute .field-odd {
+ margin: 0;
+ padding: 1px 0 0 0;
+ background-color: #ffffff;
+
+}
+
+#detailed-description .class .field-even,
+#detailed-description .method .field-even,
+#detailed-description .staticmethod .field-even,
+#detailed-description .attribute .field-even {
+ margin: 0;
+ padding: 1px 0 0 0;
+ background-color: #ffffff;
+}
+
+#detailed-description .class .field-odd li,
+#detailed-description .method .field-odd li,
+#detailed-description .staticmethod .field-odd li,
+#detailed-description .attribute .field-odd li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+
+}
+
+#detailed-description .class .field-even li,
+#detailed-description .method .field-even li,
+#detailed-description .staticmethod .field-even li,
+#detailed-description .attribute .field-even li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+#detailed-description .class .field-odd p,
+#detailed-description .method .field-odd p,
+#detailed-description .staticmethod .field-odd p,
+#detailed-description .attribute .field-odd p{
+ margin: 0;
+ margin-left: 20px;
+
+}
+
+#detailed-description .class .field-even p,
+#detailed-description .method .field-even p,
+#detailed-description .staticmethod .field-even p,
+#detailed-description .attribute .field-even p{
+ margin: 0;
+ margin-left: 20px;
+}
+
+#detailed-description .class .field-odd p:last-child,
+#detailed-description .method .field-odd p:last-child,
+#detailed-description .staticmethod .field-odd p:last-child,
+#detailed-description .attribute .field-odd p:last-child {
+ margin-bottom: 10px;
+
+}
+
+#detailed-description .class .field-even p:last-child,
+#detailed-description .method .field-even p:last-child,
+#detailed-description .staticmethod .field-even p:last-child,
+#detailed-description .attribute .field-even p:last-child{
+ margin-bottom: 10px;
}
.document dl.attribute,
@@ -333,6 +442,10 @@ tt.descname {
padding-left: 1em;
}
+#detailed-description .attribute td:nth-child(1) {
+ font-family: 'Droid Sans Mono';
+}
+
/* Qt theme */
#navbar {
position:fixed;
@@ -1056,9 +1169,15 @@ div.multi-column div {
}
.col-2 h2,.toc h3,.sidebar-content h2,
.sidebar-content h3,.sectionlist h2,
+.sphinxsidebar {
+ position: fixed;
+ overflow: scroll;
+ overflow-x: hidden;
+ overflow-y: hidden;
+}
.sphinxsidebar h3 {
- font-weight:400;
- margin-bottom:1em
+ font-weight: bold;
+ margin-bottom:1em;
}
.toc h3 a {
color:#404244
@@ -1450,6 +1569,10 @@ span.wrap:active {
code,.codelike {
font-family:"Droid Sans Mono"
}
+#detailed-description .function dt > code,
+#detailed-description .function dt > em {
+ font-weight:bold
+}
h3.fn code {
font-size:0.75em;
float:right;
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 6da9fd933..7c6e921c7 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -760,7 +760,7 @@ DefaultValue Generator::minimalConstructor(const AbstractMetaClass *metaClass) c
bool simple = true;
bool suitable = true;
for (int i = 0, size = arguments.size();
- suitable && i < size && !arguments.at(i)->hasDefaultValueExpression(); ++i) {
+ suitable && i < size && !arguments.at(i)->hasOriginalDefaultValueExpression(); ++i) {
const AbstractMetaArgument *arg = arguments.at(i);
const TypeEntry *aType = arg->type()->typeEntry();
suitable &= aType != cType;
@@ -777,11 +777,12 @@ DefaultValue Generator::minimalConstructor(const AbstractMetaClass *metaClass) c
bool ok = true;
for (int i =0, size = arguments.size(); ok && i < size; ++i) {
const AbstractMetaArgument *arg = arguments.at(i);
- if (arg->hasDefaultValueExpression()) {
- if (arg->hasModifiedDefaultValueExpression())
- args << arg->defaultValueExpression(); // Spell out modified values
+ if (arg->hasModifiedDefaultValueExpression()) {
+ args << arg->defaultValueExpression(); // Spell out modified values
break;
}
+ if (arg->hasOriginalDefaultValueExpression())
+ break;
auto argValue = minimalConstructor(arg->type());
ok &= argValue.isValid();
args << argValue.constructorParameter();
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index 9cad400f3..86abf21b0 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -349,6 +349,7 @@ QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, cons
m_handlerMap.insert(QLatin1String("skipto"), &QtXmlToSphinx::handleIgnoredTag);
m_handlerMap.insert(QLatin1String("target"), &QtXmlToSphinx::handleTargetTag);
m_handlerMap.insert(QLatin1String("page"), &QtXmlToSphinx::handlePageTag);
+ m_handlerMap.insert(QLatin1String("group"), &QtXmlToSphinx::handlePageTag);
// useless tags
m_handlerMap.insert(QLatin1String("description"), &QtXmlToSphinx::handleUselessTag);
@@ -1023,6 +1024,8 @@ QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type,
result->type = LinkContext::External;
else
result->type = LinkContext::Reference;
+ } else if (type == QLatin1String("external")) {
+ result->type = LinkContext::External;
} else {
result->type = LinkContext::Reference;
}
@@ -1228,14 +1231,11 @@ void QtXmlToSphinx::handlePageTag(QXmlStreamReader &reader)
m_output << rstLabel(title.toString());
const QStringRef fullTitle = reader.attributes().value(fullTitleAttribute());
- if (!fullTitle.isEmpty()) {
- const int size = writeEscapedRstText(m_output, fullTitle);
- m_output << endl << Pad('*', size) << endl << endl;
- }
+ const int size = fullTitle.isEmpty()
+ ? writeEscapedRstText(m_output, title)
+ : writeEscapedRstText(m_output, fullTitle);
- const QStringRef brief = reader.attributes().value(briefAttribute());
- if (!brief.isEmpty())
- m_output << escape(brief) << endl << endl;
+ m_output << endl << Pad('*', size) << endl << endl;
}
void QtXmlToSphinx::handleTargetTag(QXmlStreamReader &reader)
@@ -1621,7 +1621,7 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex
m_docParser->setPackageName(metaClass->package());
m_docParser->fillDocumentation(const_cast<AbstractMetaClass*>(metaClass));
- s << ".. module:: " << metaClass->package() << endl;
+ s << ".. currentmodule:: " << metaClass->package() << endl;
QString className = getClassTargetFullName(metaClass, false);
s << ".. _" << className << ":" << endl << endl;
@@ -2301,8 +2301,9 @@ void QtDocGenerator::writeAdditionalDocumentation()
if (fi.isFile()) {
const QString rstFileName = fi.baseName() + rstSuffix;
const QString rstFile = targetDir + QLatin1Char('/') + rstFileName;
+ const QString context = targetDir.mid(targetDir.lastIndexOf(QLatin1Char('/')) + 1);
if (QtXmlToSphinx::convertToRst(this, fi.absoluteFilePath(),
- rstFile, QString(), &errorMessage)) {
+ rstFile, context, &errorMessage)) {
++successCount;
qCDebug(lcShiboken).nospace().noquote() << __FUNCTION__
<< " converted " << fi.fileName()
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 5a4aa8eba..5460fd7c7 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -317,7 +317,10 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
s << "#include <pyside.h>" << endl;
s << "#include <destroylistener.h>" << endl;
s << "#include <qapp_macro.h>" << endl;
- }
+ s << endl;
+ s << "QT_WARNING_DISABLE_DEPRECATED" << endl;
+ s << endl;
+ }
s << "#include <typeinfo>" << endl;
if (usePySideExtensions() && metaClass->isQObject()) {
@@ -368,9 +371,6 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
s << "#Deprecated" << endl;
- if (usePySideExtensions())
- s << "\nQT_WARNING_DISABLE_DEPRECATED\n";
-
// Use class base namespace
{
const AbstractMetaClass *context = metaClass->enclosingClass();
@@ -1860,18 +1860,19 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
// For custom classes, operations like __radd__ and __rmul__
// will enter an infinite loop.
if (rfunc->isBinaryOperator() && revOpName.contains(QLatin1String("shift"))) {
+ s << INDENT << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"" << revOpName << "\"));" << endl;
s << INDENT << "if (!isReverse" << endl;
{
Indentation indent(INDENT);
s << INDENT << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")" << endl;
s << INDENT << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)" << endl;
- s << INDENT << "&& PyObject_HasAttrString(" << PYTHON_ARG << ", const_cast<char *>(\"" << revOpName << "\"))) {" << endl;
+ s << INDENT << "&& PyObject_HasAttr(" << PYTHON_ARG << ", attrName)) {" << endl;
// This PyObject_CallMethod call will emit lots of warnings like
// "deprecated conversion from string constant to char *" during compilation
// due to the method name argument being declared as "char *" instead of "const char *"
// issue 6952 http://bugs.python.org/issue6952
- s << INDENT << "PyObject *revOpMethod = PyObject_GetAttrString(" << PYTHON_ARG << ", const_cast<char *>(\"" << revOpName << "\"));" << endl;
+ s << INDENT << "PyObject *revOpMethod = PyObject_GetAttr(" << PYTHON_ARG << ", attrName);" << endl;
s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl;
{
Indentation indent(INDENT);
@@ -2154,6 +2155,8 @@ void CppGenerator::writeTypeCheck(QTextStream &s, const AbstractMetaType *argTyp
QString customCheck;
if (!customType.isEmpty()) {
AbstractMetaType *metaType;
+ // PYSIDE-795: Note: XML-Overrides are handled in this shibokengenerator function!
+ // This enables iterables for QMatrix4x4 for instance.
customCheck = guessCPythonCheckFunction(customType, &metaType);
if (metaType)
argType = metaType;
@@ -2939,6 +2942,9 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s,
typeCheck = QLatin1String("PyType_Check(%in)");
else if (pyTypeName == QLatin1String("PyObject"))
typeCheck = QLatin1String("PyObject_TypeCheck(%in, &PyBaseObject_Type)");
+ // PYSIDE-795: We abuse PySequence for iterables
+ else if (pyTypeName == QLatin1String("PySequence"))
+ typeCheck = QLatin1String("Shiboken::String::checkIterable(%in)");
else if (pyTypeName.startsWith(QLatin1String("Py")))
typeCheck = pyTypeName + QLatin1String("_Check(%in)");
}
@@ -3039,29 +3045,31 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe
QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG);
s << INDENT << "keyName = Py_BuildValue(\"s\",\"" << arg->name() << "\");" << endl;
s << INDENT << "if (PyDict_Contains(kwds, keyName)) {" << endl;
- s << INDENT << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
- s << INDENT << "if (value && " << pyArgName << ") {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << pyErrString.arg(arg->name()) << endl;
- s << INDENT << returnStatement(m_currentErrorCode) << endl;
- }
- s << INDENT << INDENT << "} else if (value) {" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << pyArgName << " = value;" << endl;
- s << INDENT << "if (!";
- writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1));
- s << ')' << endl;
+ s << INDENT << "value = PyDict_GetItem(kwds, keyName);" << endl;
+ s << INDENT << "if (value && " << pyArgName << ") {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl;
+ s << INDENT << pyErrString.arg(arg->name()) << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
+ s << INDENT << '}' << endl;
+ s << INDENT << "if (value) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pyArgName << " = value;" << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1));
+ s << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
}
s << INDENT << '}' << endl;
- if (arg != args.constLast())
- s << INDENT;
- s << "}" << endl;
}
}
s << INDENT << '}' << endl;
@@ -3933,9 +3941,10 @@ void CppGenerator::writeClassDefinition(QTextStream &s,
m_tpFuncs[func->name()] = cpythonFunctionName(func);
}
if (m_tpFuncs.value(QLatin1String("__repr__")).isEmpty()
- && !metaClass->isQObject()
&& metaClass->hasToStringCapability()) {
- m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s, classContext);
+ m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s,
+ classContext,
+ metaClass->toStringCapabilityIndirections());
}
// class or some ancestor has multiple inheritance
@@ -4608,6 +4617,15 @@ void CppGenerator::writeEnumsInitialization(QTextStream &s, AbstractMetaEnumList
}
}
+static QString mangleName(QString name)
+{
+ if ( name == QLatin1String("None")
+ || name == QLatin1String("False")
+ || name == QLatin1String("True"))
+ name += QLatin1Char('_');
+ return name;
+}
+
void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnum *cppEnum)
{
const AbstractMetaClass *enclosingClass = getProperEnclosingClassForEnum(cppEnum);
@@ -4687,7 +4705,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu
Indentation indent(INDENT);
s << INDENT << "PyObject *anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl;
s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable
- << "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl;
+ << "))->tp_dict, \"" << mangleName(enumValue->name()) << "\", anonEnumItem) < 0)" << endl;
{
Indentation indent(INDENT);
s << INDENT << returnStatement(m_currentErrorCode) << endl;
@@ -4696,7 +4714,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu
}
s << INDENT << '}' << endl;
} else {
- s << INDENT << "if (PyModule_AddIntConstant(module, \"" << enumValue->name() << "\", ";
+ s << INDENT << "if (PyModule_AddIntConstant(module, \"" << mangleName(enumValue->name()) << "\", ";
s << enumValueText << ") < 0)" << endl;
{
Indentation indent(INDENT);
@@ -4709,7 +4727,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu
s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem");
s << '(' << enumVarTypeObj << ',' << endl;
Indentation indent(INDENT);
- s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", ";
+ s << INDENT << enclosingObjectVariable << ", \"" << mangleName(enumValue->name()) << "\", ";
s << enumValueText << "))" << endl;
s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
@@ -4718,7 +4736,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu
s << INDENT << "if (!Shiboken::Enum::createScopedEnumItem("
<< enumVarTypeObj << ',' << endl;
Indentation indent(INDENT);
- s << INDENT << enumVarTypeObj<< ", \"" << enumValue->name() << "\", "
+ s << INDENT << enumVarTypeObj<< ", \"" << mangleName(enumValue->name()) << "\", "
<< enumValueText << "))" << endl
<< INDENT << returnStatement(m_currentErrorCode) << endl;
}
@@ -5541,10 +5559,11 @@ bool CppGenerator::finishGeneration()
{
Indentation indentation(INDENT);
s << INDENT << "PyObject *pyType = reinterpret_cast<PyObject *>(" << cppApiVariableName() << "[i]);" << endl;
- s << INDENT << "if (pyType && PyObject_HasAttrString(pyType, \"staticMetaObject\"))"<< endl;
+ s << INDENT << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"staticMetaObject\"));" << endl;
+ s << INDENT << "if (pyType && PyObject_HasAttr(pyType, attrName))"<< endl;
{
Indentation indentation(INDENT);
- s << INDENT << "PyObject_SetAttrString(pyType, \"staticMetaObject\", Py_None);" << endl;
+ s << INDENT << "PyObject_SetAttr(pyType, attrName, Py_None);" << endl;
}
}
s << INDENT << "}" << endl;
@@ -5981,7 +6000,9 @@ void CppGenerator::writeIndexError(QTextStream &s, const QString &errorMsg)
s << INDENT << '}' << endl;
}
-QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &context)
+QString CppGenerator::writeReprFunction(QTextStream &s,
+ GeneratorContext &context,
+ uint indirections)
{
const AbstractMetaClass *metaClass = context.metaClass();
QString funcName = cpythonBaseName(metaClass) + QLatin1String("__repr__");
@@ -5994,7 +6015,7 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex
s << INDENT << "buffer.open(QBuffer::ReadWrite);" << endl;
s << INDENT << "QDebug dbg(&buffer);" << endl;
s << INDENT << "dbg << ";
- if (metaClass->typeEntry()->isValue())
+ if (metaClass->typeEntry()->isValue() || indirections == 0)
s << '*';
s << CPP_SELF_VAR << ';' << endl;
s << INDENT << "buffer.close();" << endl;
@@ -6005,7 +6026,8 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex
Indentation indent(INDENT);
s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl;
}
- s << INDENT << "PyObject *mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl;
+ s << INDENT << "str = str.trimmed();" << endl;
+ s << INDENT << "PyObject *mod = PyDict_GetItem(Py_TYPE(self)->tp_dict, Shiboken::PyMagicName::module());" << endl;
// PYSIDE-595: The introduction of heap types has the side effect that the module name
// is always prepended to the type name. Therefore the strchr check:
s << INDENT << "if (mod && !strchr(str, '.'))" << endl;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index ae6da9582..005518f96 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -336,7 +336,7 @@ private:
/// Helper function for writeStdListWrapperMethods.
void writeIndexError(QTextStream &s, const QString &errorMsg);
- QString writeReprFunction(QTextStream &s, GeneratorContext &context);
+ QString writeReprFunction(QTextStream &s, GeneratorContext &context, uint indirections);
const AbstractMetaFunction *boolCast(const AbstractMetaClass *metaClass) const;
bool hasBoolCast(const AbstractMetaClass *metaClass) const
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
index 8a2c56232..e47c37523 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -454,6 +454,11 @@ bool HeaderGenerator::finishGeneration()
// TODO-CONVERTER ------------------------------------------------------------------------------
macrosStream << "// Macros for type check" << endl;
+
+ if (usePySideExtensions()) {
+ typeFunctions << "QT_WARNING_PUSH" << endl;
+ typeFunctions << "QT_WARNING_DISABLE_DEPRECATED" << endl;
+ }
for (const AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) {
if (cppEnum->isAnonymous() || cppEnum->isPrivate())
continue;
@@ -489,6 +494,8 @@ bool HeaderGenerator::finishGeneration()
includes << classType->include();
writeSbkTypeFunction(typeFunctions, metaType);
}
+ if (usePySideExtensions())
+ typeFunctions << "QT_WARNING_POP" << endl;
QString moduleHeaderFileName(outputDirectory()
+ QDir::separator() + subDirectoryForPackage(packageName())
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
index 4aa5e5c02..5f74ee64d 100644
--- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
@@ -520,7 +520,7 @@ void OverloadData::addOverload(const AbstractMetaFunction *func)
for (int i = 0; m_headOverloadData->m_minArgs > 0 && i < origNumArgs; i++) {
if (func->argumentRemoved(i + 1))
continue;
- if (!ShibokenGenerator::getDefaultValue(func, func->arguments().at(i)).isEmpty()) {
+ if (func->arguments().at(i)->hasDefaultValueExpression()) {
int fixedArgIndex = i - removed;
if (fixedArgIndex < m_headOverloadData->m_minArgs)
m_headOverloadData->m_minArgs = fixedArgIndex;
@@ -754,7 +754,7 @@ const AbstractMetaFunction *OverloadData::getFunctionWithDefaultValue() const
if (func->argumentRemoved(i + 1))
removedArgs++;
}
- if (!ShibokenGenerator::getDefaultValue(func, func->arguments().at(m_argPos + removedArgs)).isEmpty())
+ if (func->arguments().at(m_argPos + removedArgs)->hasDefaultValueExpression())
return func;
}
return nullptr;
@@ -771,7 +771,7 @@ QVector<int> OverloadData::invalidArgumentLengths() const
if (func->argumentRemoved(i+1)) {
offset++;
} else {
- if (!ShibokenGenerator::getDefaultValue(func, args[i]).isEmpty())
+ if (args.at(i)->hasDefaultValueExpression())
validArgLengths << i-offset;
}
}
@@ -820,7 +820,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList
if (func->argumentRemoved(j + 1))
continue;
int fixedArgIndex = j - removed;
- if (fixedArgIndex < minArgs && !ShibokenGenerator::getDefaultValue(func, func->arguments().at(j)).isEmpty())
+ if (fixedArgIndex < minArgs && func->arguments().at(j)->hasDefaultValueExpression())
minArgs = fixedArgIndex;
}
}
@@ -967,7 +967,7 @@ QString OverloadData::dumpGraph() const
const AbstractMetaArgument *arg = argument(func);
if (!arg)
continue;
- QString argDefault = ShibokenGenerator::getDefaultValue(func, arg);
+ QString argDefault = arg->defaultValueExpression();
if (!argDefault.isEmpty() ||
argDefault != arg->originalDefaultValueExpression()) {
s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
@@ -1038,7 +1038,7 @@ bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction *func)
for (const AbstractMetaArgument *arg : arguments) {
if (func->argumentRemoved(arg->argumentIndex() + 1))
continue;
- if (!ShibokenGenerator::getDefaultValue(func, arg).isEmpty())
+ if (arg->hasDefaultValueExpression())
return true;
}
return false;
@@ -1049,7 +1049,7 @@ AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const Abstr
AbstractMetaArgumentList args;
const AbstractMetaArgumentList &arguments = func->arguments();
for (AbstractMetaArgument *arg : arguments) {
- if (ShibokenGenerator::getDefaultValue(func, arg).isEmpty()
+ if (!arg->hasDefaultValueExpression()
|| func->argumentRemoved(arg->argumentIndex() + 1))
continue;
args << arg;
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 34e43a4c7..fd75c620e 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -324,18 +324,16 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaCl
void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList &enumList, const AbstractMetaClass *metaClass)
{
- if (!metaClass)
- return;
-
+ Q_ASSERT(metaClass);
+ // if a scope is not to be generated, collect its enums into the parent scope
if (metaClass->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) {
const AbstractMetaEnumList &enums = metaClass->enums();
- for (const AbstractMetaEnum *metaEnum : enums) {
- if (metaEnum->isPrivate() || metaEnum->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass)
- continue;
- if (!enumList.contains(const_cast<AbstractMetaEnum *>(metaEnum)))
- enumList.append(const_cast<AbstractMetaEnum *>(metaEnum));
+ for (AbstractMetaEnum *metaEnum : enums) {
+ if (!metaEnum->isPrivate() && metaEnum->typeEntry()->generateCode()
+ && !enumList.contains(metaEnum)) {
+ enumList.append(metaEnum);
+ }
}
- lookForEnumsInClassesNotToBeGenerated(enumList, metaClass->enclosingClass());
}
}
@@ -571,13 +569,13 @@ QString ShibokenGenerator::guessScopeForDefaultFlagsValue(const AbstractMetaFunc
QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction *func,
const AbstractMetaArgument *arg) const
{
- QString value = getDefaultValue(func, arg);
+ QString value = arg->defaultValueExpression();
- if (value.isEmpty())
- return QString();
-
- if (isPointer(arg->type()))
+ if (value.isEmpty()
+ || arg->hasModifiedDefaultValueExpression()
+ || isPointer(arg->type())) {
return value;
+ }
static const QRegularExpression enumValueRegEx(QStringLiteral("^([A-Za-z_]\\w*)?$"));
Q_ASSERT(enumValueRegEx.isValid());
@@ -1255,6 +1253,11 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry *type, bool gene
QString ShibokenGenerator::guessCPythonCheckFunction(const QString &type, AbstractMetaType **metaType)
{
*metaType = nullptr;
+ // PYSIDE-795: We abuse PySequence for iterables.
+ // This part handles the overrides in the XML files.
+ if (type == QLatin1String("PySequence"))
+ return QLatin1String("Shiboken::String::checkIterable");
+
if (type == QLatin1String("PyTypeObject"))
return QLatin1String("PyType_Check");
@@ -2306,7 +2309,7 @@ AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ
auto it = m_metaTypeFromStringCache.find(typeSignature);
if (it == m_metaTypeFromStringCache.end()) {
AbstractMetaType *metaType =
- AbstractMetaBuilder::translateType(typeSignature, nullptr, true, errorMessage);
+ AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage);
if (Q_UNLIKELY(!metaType)) {
if (errorMessage)
errorMessage->prepend(msgCannotBuildMetaType(typeSignature));
@@ -2708,22 +2711,6 @@ bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadD
|| overloadData.hasArgumentWithDefaultValue();
}
-QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction *func, const AbstractMetaArgument *arg)
-{
- if (!arg->defaultValueExpression().isEmpty())
- return arg->defaultValueExpression();
-
- //Check modifications
- const FunctionModificationList &mods = func->modifications();
- for (const FunctionModification &m : mods) {
- for (const ArgumentModification &am : m.argument_mods) {
- if (am.index == (arg->argumentIndex() + 1))
- return am.replacedDefaultExpression;
- }
- }
- return QString();
-}
-
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream &s, const AbstractMetaType *type, const QString &defaultCtor)
{
if (!defaultCtor.isEmpty()) {
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index 84b3137b8..7970ceb94 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -71,11 +71,6 @@ public:
const char *name() const override { return "Shiboken"; }
- /**
- * Helper function to find for argument default value
- */
- static QString getDefaultValue(const AbstractMetaFunction *func, const AbstractMetaArgument *arg);
-
/// Returns a list of all ancestor classes for the given class.
AbstractMetaClassList getAllAncestors(const AbstractMetaClass *metaClass) const;
diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt
index 7cbb22978..a38da8d89 100644
--- a/sources/shiboken2/libshiboken/CMakeLists.txt
+++ b/sources/shiboken2/libshiboken/CMakeLists.txt
@@ -30,8 +30,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
"${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY)
add_custom_command(
- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.inc"
- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature.inc"
+ 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"
@@ -53,6 +53,7 @@ sbkconverter.cpp
sbkenum.cpp
sbkmodule.cpp
sbkstring.cpp
+sbkstaticstrings.cpp
bindingmanager.cpp
threadstatesaver.cpp
shibokenbuffer.cpp
@@ -62,8 +63,8 @@ pep384impl.cpp
voidptr.cpp
typespec.cpp
bufferprocs_py37.cpp
-embed/signature_bootstrap.inc
-embed/signature.inc
+embed/signature_bootstrap_inc.h
+embed/signature_inc.h
)
get_numpy_location()
@@ -129,6 +130,7 @@ install(FILES
python25compat.h
sbkdbg.h
sbkstring.h
+ sbkstaticstrings.h
shiboken.h
shibokenmacros.h
threadstatesaver.h
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index b9f6735d8..000035627 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -44,6 +44,7 @@
#include "sbkconverter.h"
#include "sbkenum.h"
#include "sbkstring.h"
+#include "sbkstaticstrings_p.h"
#include "autodecref.h"
#include "gilstate.h"
#include <string>
@@ -92,6 +93,7 @@ static PyType_Slot SbkObjectType_Type_slots[] = {
{Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)},
{Py_tp_new, reinterpret_cast<void *>(SbkObjectTypeTpNew)},
{Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)},
+ {Py_tp_getset, reinterpret_cast<void *>(SbkObjectType_Type_getsetlist)},
{0, nullptr}
};
static PyType_Spec SbkObjectType_Type_spec = {
@@ -106,7 +108,7 @@ static PyType_Spec SbkObjectType_Type_spec = {
#if PY_VERSION_HEX < 0x03000000
/*****************************************************************************
*
- * PYSIDE-816: Workaround for Python 2.7
+ * PYSIDE-816: Workaround for Python 2.7 for SbkObjectType_TypeF().
*
* This is an add-on for function typeobject.c:tp_new_wrapper from Python 2.7 .
* Problem:
@@ -121,9 +123,16 @@ static PyType_Spec SbkObjectType_Type_spec = {
* The problem is that heap types have this unwanted dependency.
* But we cannot get at static slot_tp_new, and so we have to use
* the original function and patch Py_TPFLAGS_HEAPTYPE away during the call.
+ *
+ * PYSIDE-1051: The same problem holds for all dynamic metatypes generated by
+ * SbkObjectTypeTpNew() and all types generated by
+ * introduceWrapperType() .
+ *
+ * This led to a drastic overhaul of patch_tp_new_wrapper() which now adds
+ * the new wrapper to exactly those types which have the old wrapper.
*/
-static PyCFunction old_tp_new_wrapper = nullptr;
+ternaryfunc old_tp_new_wrapper = nullptr;
static PyObject *
tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
@@ -136,9 +145,9 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
return ret;
}
-// This is intentionally the new docstring of Python 3.7 .
+// This is intentionally the __new__ docstring of Python 3.7 .
static struct PyMethodDef tp_new_methoddef[] = {
- {"__new__", (PyCFunction)tp_new_wrapper, METH_VARARGS|METH_KEYWORDS,
+ {"__new__", reinterpret_cast<PyCFunction>(tp_new_wrapper), METH_VARARGS|METH_KEYWORDS,
PyDoc_STR("__new__($type, *args, **kwargs)\n--\n\n"
"Create and return a new object. "
"See help(type) for accurate signature.")},
@@ -146,43 +155,38 @@ static struct PyMethodDef tp_new_methoddef[] = {
};
static int
-get_old_tp_new_wrapper(void)
-{
- // We get the old tp_new_wrapper from any initialized type.
- PyTypeObject *type = &PyType_Type;
- PyObject *dict = type->tp_dict;
- PyObject *key, *func = nullptr;
- Py_ssize_t pos = 0;
- while (PyDict_Next(dict, &pos, &key, &func)) {
- char *name = PyString_AsString(key);
- if (strcmp(name, "__new__") == 0) {
- break;
+patch_tp_new_wrapper(PyTypeObject *type)
+{
+ /*
+ * The old tp_new_wrapper is added to all types that have tp_new.
+ * We patch that with a version that ignores the heaptype flag.
+ */
+ auto newMethod = Shiboken::PyMagicName::new_();
+ if (old_tp_new_wrapper == nullptr) {
+ PyObject *func = PyDict_GetItem(PyType_Type.tp_dict, newMethod);
+ assert(func);
+ PyCFunctionObject *pycf_ob = reinterpret_cast<PyCFunctionObject *>(func);
+ old_tp_new_wrapper = reinterpret_cast<ternaryfunc>(pycf_ob->m_ml->ml_meth);
+ }
+ PyObject *mro = type->tp_mro;
+ Py_ssize_t i, n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i));
+ PyObject *existing = PyDict_GetItem(type->tp_dict, newMethod);
+ if (existing && PyCFunction_Check(existing)
+ && type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+ auto *pycf_ob = reinterpret_cast<PyCFunctionObject *>(existing);
+ auto existing_wrapper = reinterpret_cast<ternaryfunc>(pycf_ob->m_ml->ml_meth);
+ if (existing_wrapper == tp_new_wrapper)
+ break;
+ if (existing_wrapper == old_tp_new_wrapper) {
+ PyObject *ob_type = reinterpret_cast<PyObject *>(type);
+ Shiboken::AutoDecRef func(PyCFunction_New(tp_new_methoddef, ob_type));
+ if (func.isNull() || PyDict_SetItem(type->tp_dict, newMethod, func))
+ return -1;
+ }
}
}
- if (func == nullptr)
- return -1;
- PyCFunctionObject *pycf_ob = reinterpret_cast<PyCFunctionObject *>(func);
- old_tp_new_wrapper = pycf_ob->m_ml->ml_meth;
- return 0;
-}
-
-static int
-add_tp_new_wrapper(PyTypeObject *type)
-{
- // get the original tp_new_wrapper
- if (old_tp_new_wrapper == nullptr && get_old_tp_new_wrapper() < 0)
- return -1;
- // initialize tp_dict
- if (type->tp_dict == nullptr)
- type->tp_dict = PyDict_New();
- if (type->tp_dict == nullptr)
- return -1;
- PyObject *ob_type = reinterpret_cast<PyObject *>(type);
- Shiboken::AutoDecRef func(PyCFunction_New(tp_new_methoddef, ob_type));
- if (func.isNull())
- return -1;
- if (PyDict_SetItemString(type->tp_dict, "__new__", func))
- return -1;
return 0;
}
/*****************************************************************************/
@@ -197,7 +201,7 @@ PyTypeObject *SbkObjectType_TypeF(void)
PepHeapType_SIZE + sizeof(SbkObjectTypePrivate);
type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObjectType_Type_spec));
#if PY_VERSION_HEX < 0x03000000
- if (add_tp_new_wrapper(type) < 0)
+ if (patch_tp_new_wrapper(type) < 0)
return nullptr;
#endif
}
@@ -452,6 +456,11 @@ PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *k
auto *newType = reinterpret_cast<SbkObjectType *>(type_new(metatype, args, kwds));
if (!newType)
return nullptr;
+#if PY_VERSION_HEX < 0x03000000
+ // PYSIDE-1051: The newly created metatype needs the PYSIDE-816 wrapper, too.
+ if (patch_tp_new_wrapper(&newType->type) < 0)
+ return nullptr;
+#endif
Shiboken::ObjectType::initPrivateData(newType);
SbkObjectTypePrivate *sotp = PepType_SOTP(newType);
@@ -842,6 +851,11 @@ introduceWrapperType(PyObject *enclosingObject,
Py_TYPE(heaptype) = SbkObjectType_TypeF();
Py_INCREF(Py_TYPE(heaptype));
auto *type = reinterpret_cast<SbkObjectType *>(heaptype);
+#if PY_VERSION_HEX < 0x03000000
+ // PYSIDE-1051: The newly created type needs the PYSIDE-816 wrapper, too.
+ if (patch_tp_new_wrapper(&type->type) < 0)
+ return nullptr;
+#endif
if (baseType) {
if (baseTypes) {
for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i)
diff --git a/sources/shiboken2/libshiboken/embed/embedding_generator.py b/sources/shiboken2/libshiboken/embed/embedding_generator.py
index 77aa5c329..15f63649b 100644
--- a/sources/shiboken2/libshiboken/embed/embedding_generator.py
+++ b/sources/shiboken2/libshiboken/embed/embedding_generator.py
@@ -88,7 +88,7 @@ def create_zipfile(limited_api):
and make a chunked base64 encoded file from it.
"""
zip_name = "signature.zip"
- inc_name = "signature.inc"
+ inc_name = "signature_inc.h"
flag = '-b' if sys.version_info >= (3,) else ''
os.chdir(work_dir)
@@ -131,7 +131,7 @@ def create_zipfile(limited_api):
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", "w") as inc:
+ 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)
diff --git a/sources/shiboken2/libshiboken/helper.cpp b/sources/shiboken2/libshiboken/helper.cpp
index fac72d56f..013080b6e 100644
--- a/sources/shiboken2/libshiboken/helper.cpp
+++ b/sources/shiboken2/libshiboken/helper.cpp
@@ -39,6 +39,7 @@
#include "helper.h"
#include "sbkstring.h"
+#include "sbkstaticstrings.h"
#include <stdarg.h>
#ifdef _WIN32
@@ -78,7 +79,7 @@ bool listToArgcArgv(PyObject *argList, int *argc, char ***argv, const char *defa
if (hasEmptyArgList) {
// Try to get the script name
PyObject *globals = PyEval_GetGlobals();
- PyObject *appName = PyDict_GetItemString(globals, "__file__");
+ PyObject *appName = PyDict_GetItem(globals, Shiboken::PyMagicName::file());
(*argv)[0] = strdup(appName ? Shiboken::String::toCString(appName) : defaultAppName);
} else {
for (int i = 0; i < numArgs; ++i) {
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index fe7157d24..5729100bf 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -39,6 +39,8 @@
#include "pep384impl.h"
#include "autodecref.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
extern "C"
{
@@ -85,14 +87,15 @@ static PyGetSetDef probe_getseters[] = {
#define probe_tp_str make_dummy(2)
#define probe_tp_traverse make_dummy(3)
#define probe_tp_clear make_dummy(4)
+#define probe_tp_iternext make_dummy(5)
#define probe_tp_methods probe_methoddef
#define probe_tp_getset probe_getseters
-#define probe_tp_descr_get make_dummy(7)
-#define probe_tp_init make_dummy(8)
-#define probe_tp_alloc make_dummy(9)
-#define probe_tp_new make_dummy(10)
-#define probe_tp_free make_dummy(11)
-#define probe_tp_is_gc make_dummy(12)
+#define probe_tp_descr_get make_dummy(8)
+#define probe_tp_init make_dummy(9)
+#define probe_tp_alloc make_dummy(10)
+#define probe_tp_new make_dummy(11)
+#define probe_tp_free make_dummy(12)
+#define probe_tp_is_gc make_dummy(13)
#define probe_tp_name "type.probe"
#define probe_tp_basicsize make_dummy_int(42)
@@ -102,6 +105,7 @@ static PyType_Slot typeprobe_slots[] = {
{Py_tp_str, probe_tp_str},
{Py_tp_traverse, probe_tp_traverse},
{Py_tp_clear, probe_tp_clear},
+ {Py_tp_iternext, probe_tp_iternext},
{Py_tp_methods, probe_tp_methods},
{Py_tp_getset, probe_tp_getset},
{Py_tp_descr_get, probe_tp_descr_get},
@@ -125,16 +129,16 @@ check_PyTypeObject_valid()
{
auto *obtype = reinterpret_cast<PyObject *>(&PyType_Type);
auto *probe_tp_base = reinterpret_cast<PyTypeObject *>(
- PyObject_GetAttrString(obtype, "__base__"));
- PyObject *probe_tp_bases = PyObject_GetAttrString(obtype, "__bases__");
+ PyObject_GetAttr(obtype, Shiboken::PyMagicName::base()));
+ auto *probe_tp_bases = PyObject_GetAttr(obtype, Shiboken::PyMagicName::bases());
auto *check = reinterpret_cast<PyTypeObject *>(
PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases));
auto *typetype = reinterpret_cast<PyTypeObject *>(obtype);
- PyObject *w = PyObject_GetAttrString(obtype, "__weakrefoffset__");
+ PyObject *w = PyObject_GetAttr(obtype, Shiboken::PyMagicName::weakrefoffset());
long probe_tp_weakrefoffset = PyLong_AsLong(w);
- PyObject *d = PyObject_GetAttrString(obtype, "__dictoffset__");
+ PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset());
long probe_tp_dictoffset = PyLong_AsLong(d);
- PyObject *probe_tp_mro = PyObject_GetAttrString(obtype, "__mro__");
+ PyObject *probe_tp_mro = PyObject_GetAttr(obtype, Shiboken::PyMagicName::mro());
if (false
|| strcmp(probe_tp_name, check->tp_name) != 0
|| probe_tp_basicsize != check->tp_basicsize
@@ -143,6 +147,7 @@ check_PyTypeObject_valid()
|| probe_tp_traverse != check->tp_traverse
|| probe_tp_clear != check->tp_clear
|| probe_tp_weakrefoffset != typetype->tp_weaklistoffset
+ || probe_tp_iternext != check->tp_iternext
|| probe_tp_methods != check->tp_methods
|| probe_tp_getset != check->tp_getset
|| probe_tp_base != typetype->tp_base
@@ -416,9 +421,10 @@ PepRun_GetResult(const char *command, const char *resvar)
PyObject *d, *v, *res;
d = PyDict_New();
- if (d == NULL || PyDict_SetItemString(d, "__builtins__",
- PyEval_GetBuiltins()) < 0)
- return NULL;
+ if (d == nullptr
+ || PyDict_SetItem(d, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) {
+ return nullptr;
+ }
v = PyRun_String(command, Py_file_input, d, d);
res = v ? PyDict_GetItemString(d, resvar) : NULL;
Py_XDECREF(v);
@@ -457,7 +463,7 @@ PyMethod_New(PyObject *func, PyObject *self)
PyObject *
PyMethod_Function(PyObject *im)
{
- PyObject *ret = PyObject_GetAttrString(im, "__func__");
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::func());
// We have to return a borrowed reference.
Py_DECREF(ret);
@@ -467,7 +473,7 @@ PyMethod_Function(PyObject *im)
PyObject *
PyMethod_Self(PyObject *im)
{
- PyObject *ret = PyObject_GetAttrString(im, "__self__");
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::self());
// We have to return a borrowed reference.
// If we don't obey that here, then we get a test error!
@@ -620,8 +626,8 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name)
return name;
}
#endif
- Shiboken::AutoDecRef privateobj(PyObject_GetAttrString(
- reinterpret_cast<PyObject *>(Py_TYPE(self)), "__name__"));
+ Shiboken::AutoDecRef privateobj(PyObject_GetAttr(
+ reinterpret_cast<PyObject *>(Py_TYPE(self)), Shiboken::PyMagicName::name()));
#ifndef Py_LIMITED_API
return _Py_Mangle(privateobj, name);
#else
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index 93f718988..1aa7e6fc0 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -110,7 +110,7 @@ typedef struct _typeobject {
void *X23; // richcmpfunc tp_richcompare;
Py_ssize_t tp_weaklistoffset;
void *X25; // getiterfunc tp_iter;
- void *X26; // iternextfunc tp_iternext;
+ iternextfunc tp_iternext;
struct PyMethodDef *tp_methods;
void *X28; // struct PyMemberDef *tp_members;
struct PyGetSetDef *tp_getset;
diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp
index 12af9613c..306f53b74 100644
--- a/sources/shiboken2/libshiboken/qapp_macro.cpp
+++ b/sources/shiboken2/libshiboken/qapp_macro.cpp
@@ -120,6 +120,7 @@ reset_qApp_var(void)
PyObject *
MakeSingletonQAppWrapper(PyTypeObject *type)
{
+ static bool app_created = false;
if (type == nullptr)
type = Py_NONE_TYPE;
if (!(type == Py_NONE_TYPE || Py_TYPE(qApp_content) == Py_NONE_TYPE)) {
@@ -145,6 +146,9 @@ MakeSingletonQAppWrapper(PyTypeObject *type)
Py_REFCNT(qApp_var) = 1; // fuse is armed...
}
if (type == Py_NONE_TYPE) {
+ // PYSIDE-1093: Ignore None when no instance has ever been created.
+ if (!app_created)
+ Py_RETURN_NONE;
// Debug mode showed that we need to do more than just remove the
// reference. To keep everything in the right order, it is easiest
// to do a full shutdown, using QtCore.__moduleShutdown().
@@ -158,9 +162,10 @@ MakeSingletonQAppWrapper(PyTypeObject *type)
Py_REFCNT(qApp_content) = Py_REFCNT(Py_None);
if (__moduleShutdown != nullptr)
Py_XDECREF(PyObject_CallFunction(__moduleShutdown, const_cast<char *>("()")));
+ } else {
+ PyObject_INIT(qApp_content, type);
+ app_created = true;
}
- else
- (void)PyObject_INIT(qApp_content, type);
Py_INCREF(qApp_content);
return qApp_content;
}
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
new file mode 100644
index 000000000..3727eb494
--- /dev/null
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $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$
+**
+****************************************************************************/
+
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkstring.h"
+
+#define STATIC_STRING_IMPL(funcName, value) \
+PyObject *funcName() \
+{ \
+ static PyObject *const s = Shiboken::String::createStaticString(value); \
+ return s; \
+}
+
+namespace Shiboken
+{
+namespace PyName {
+// exported:
+STATIC_STRING_IMPL(dumps, "dumps")
+STATIC_STRING_IMPL(loads, "loads")
+
+// Internal:
+STATIC_STRING_IMPL(classmethod, "classmethod")
+STATIC_STRING_IMPL(compile, "compile");
+STATIC_STRING_IMPL(function, "function")
+STATIC_STRING_IMPL(marshal, "marshal")
+STATIC_STRING_IMPL(method, "method")
+STATIC_STRING_IMPL(overload, "overload")
+STATIC_STRING_IMPL(staticmethod, "staticmethod")
+} // namespace PyName
+
+namespace PyMagicName {
+// exported:
+STATIC_STRING_IMPL(class_, "__class__")
+STATIC_STRING_IMPL(ecf, "__ecf__")
+STATIC_STRING_IMPL(file, "__file__")
+STATIC_STRING_IMPL(module, "__module__")
+STATIC_STRING_IMPL(name, "__name__")
+
+// Internal:
+STATIC_STRING_IMPL(base, "__base__")
+STATIC_STRING_IMPL(bases, "__bases__")
+STATIC_STRING_IMPL(builtins, "__builtins__")
+STATIC_STRING_IMPL(code, "__code__")
+STATIC_STRING_IMPL(dictoffset, "__dictoffset__")
+STATIC_STRING_IMPL(func, "__func__")
+STATIC_STRING_IMPL(func_kind, "__func_kind__")
+STATIC_STRING_IMPL(iter, "__iter__")
+STATIC_STRING_IMPL(mro, "__mro__")
+STATIC_STRING_IMPL(new_, "__new__")
+STATIC_STRING_IMPL(objclass, "__objclass__")
+STATIC_STRING_IMPL(self, "__self__")
+STATIC_STRING_IMPL(signature, "__signature__")
+STATIC_STRING_IMPL(weakrefoffset, "__weakrefoffset__")
+} // namespace PyMagicName
+} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.h b/sources/shiboken2/libshiboken/sbkstaticstrings.h
new file mode 100644
index 000000000..fa21a8e2c
--- /dev/null
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef SBKSTATICSTRINGS_H
+#define SBKSTATICSTRINGS_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+// Some often-used strings
+namespace PyName
+{
+LIBSHIBOKEN_API PyObject *dumps();
+LIBSHIBOKEN_API PyObject *loads();
+} // namespace PyName
+
+namespace PyMagicName
+{
+LIBSHIBOKEN_API PyObject *class_();
+LIBSHIBOKEN_API PyObject *ecf();
+LIBSHIBOKEN_API PyObject *file();
+LIBSHIBOKEN_API PyObject *module();
+LIBSHIBOKEN_API PyObject *name();
+} // namespace PyMagicName
+} // namespace Shiboken
+
+#endif // SBKSTATICSTRINGS_H
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings_p.h b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h
new file mode 100644
index 000000000..42c5585fa
--- /dev/null
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $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$
+**
+****************************************************************************/
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+namespace PyName
+{
+PyObject *classmethod();
+PyObject *compile();
+PyObject *function();
+PyObject *marshal();
+PyObject *method();
+PyObject *overload();
+PyObject *staticmethod();
+} // namespace PyName
+namespace PyMagicName
+{
+PyObject *base();
+PyObject *bases();
+PyObject *builtins();
+PyObject *code();
+PyObject *dictoffset();
+PyObject *func();
+PyObject *func_kind();
+PyObject *iter();
+PyObject *module();
+PyObject *mro();
+PyObject *new_();
+PyObject *objclass();
+PyObject *self();
+PyObject *signature();
+PyObject *weakrefoffset();
+} // namespace PyMagicName
+} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp
index 9ba5be281..4a441222f 100644
--- a/sources/shiboken2/libshiboken/sbkstring.cpp
+++ b/sources/shiboken2/libshiboken/sbkstring.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -38,14 +38,23 @@
****************************************************************************/
#include "sbkstring.h"
+#include "sbkstaticstrings_p.h"
#include "autodecref.h"
+#include <vector>
+
namespace Shiboken
{
namespace String
{
+// PYSIDE-795: Redirecting PySequence to Iterable
+bool checkIterable(PyObject *obj)
+{
+ return PyObject_HasAttr(obj, Shiboken::PyMagicName::iter());
+}
+
bool checkType(PyTypeObject *type)
{
return type == &PyUnicode_Type
@@ -200,6 +209,64 @@ Py_ssize_t len(PyObject *str)
return 0;
}
-} // namespace String
+///////////////////////////////////////////////////////////////////////
+//
+// Implementation of efficient Python strings
+// ------------------------------------------
+//
+// Instead of repetitively executing
+//
+// PyObject *attr = PyObject_GetAttrString(obj, "__name__");
+//
+// a helper of the form
+//
+// PyObject *name()
+// {
+// static PyObject *const s = Shiboken::String::createStaticString("__name__");
+// return result;
+// }
+//
+// can now be implemented, which registers the string into a static set avoiding
+// repetitive string creation. The resulting code looks like:
+//
+// PyObject *attr = PyObject_GetAttr(obj, name());
+//
+// Missing:
+// There is no finalization for the string structures, yet.
+// But this is a global fault in shiboken. We are missing a true
+// finalization like in all other modules.
+
+using StaticStrings = std::vector<PyObject *>;
+static StaticStrings &staticStrings()
+{
+ static StaticStrings result;
+ return result;
+}
+
+PyObject *createStaticString(const char *str)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ PyObject *result = PyUnicode_InternFromString(str);
+#else
+ PyObject *result = PyString_InternFromString(str);
+#endif
+ if (result == nullptr) {
+ // This error is never checked, but also very unlikely. Report and exit.
+ PyErr_Print();
+ Py_FatalError("unexpected error in createStaticString()");
+ }
+ staticStrings().push_back(result);
+ return result;
+}
+
+void finalizeStaticStrings() // Currently unused
+{
+ auto &list = staticStrings();
+ for (auto s : list)
+ Py_DECREF(s);
+ list.clear();
+}
+
+} // namespace String
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/sbkstring.h b/sources/shiboken2/libshiboken/sbkstring.h
index 7f434e1b9..84d7768c5 100644
--- a/sources/shiboken2/libshiboken/sbkstring.h
+++ b/sources/shiboken2/libshiboken/sbkstring.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -43,17 +43,12 @@
#include "sbkpython.h"
#include "shibokenmacros.h"
-#if PY_MAJOR_VERSION >= 3
- #define SBK_BYTES_NAME "bytes"
-#else
- #define SBK_BYTES_NAME "str"
-#endif
-
namespace Shiboken
{
namespace String
{
LIBSHIBOKEN_API bool check(PyObject *obj);
+ LIBSHIBOKEN_API bool checkIterable(PyObject *obj);
LIBSHIBOKEN_API bool checkType(PyTypeObject *obj);
LIBSHIBOKEN_API bool checkChar(PyObject *obj);
LIBSHIBOKEN_API bool isConvertible(PyObject *obj);
@@ -65,6 +60,7 @@ namespace String
LIBSHIBOKEN_API PyObject *fromStringAndSize(const char *str, Py_ssize_t size);
LIBSHIBOKEN_API int compare(PyObject *val1, const char *val2);
LIBSHIBOKEN_API Py_ssize_t len(PyObject *str);
+ LIBSHIBOKEN_API PyObject *createStaticString(const char *str);
} // namespace String
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/shiboken.h b/sources/shiboken2/libshiboken/shiboken.h
index 1356670aa..0d2d6b0a6 100644
--- a/sources/shiboken2/libshiboken/shiboken.h
+++ b/sources/shiboken2/libshiboken/shiboken.h
@@ -52,6 +52,7 @@
#include "sbkenum.h"
#include "sbkmodule.h"
#include "sbkstring.h"
+#include "sbkstaticstrings.h"
#include "shibokenmacros.h"
#include "shibokenbuffer.h"
diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
index 330470183..dd6e46320 100644
--- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp
+++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
@@ -43,7 +43,11 @@
bool Shiboken::Buffer::checkType(PyObject *pyObj)
{
+#ifdef IS_PY3K
+ return PyObject_CheckBuffer(pyObj) != 0;
+#else
return PyObject_CheckReadBuffer(pyObj) != 0;
+#endif
}
void *Shiboken::Buffer::getPointer(PyObject *pyObj, Py_ssize_t *size)
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index 07ef366ba..5430ab064 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -39,6 +39,8 @@
#include "basewrapper.h"
#include "autodecref.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
extern "C"
{
@@ -51,11 +53,11 @@ extern "C"
// These constants were needed in former versions of the module:
#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03030000)
-#define PYTHON_HAS_UNICODE (PY_VERSION_HEX >= 0x03000000)
#define PYTHON_HAS_WEAKREF_PYCFUNCTION (PY_VERSION_HEX >= 0x030500A0)
#define PYTHON_IS_PYTHON3 (PY_VERSION_HEX >= 0x03000000)
#define PYTHON_HAS_KEYWORDONLY (PYTHON_IS_PYTHON3)
#define PYTHON_USES_PERCENT_V_FORMAT (PYTHON_IS_PYTHON3)
+#define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000)
#define PYTHON_HAS_DESCR_REDUCE (PY_VERSION_HEX >= 0x03040000)
#define PYTHON_HAS_METH_REDUCE (PYTHON_HAS_DESCR_REDUCE)
#define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3)
@@ -64,7 +66,7 @@ extern "C"
#define PYTHON_HAS_INT_AND_LONG (!PYTHON_IS_PYTHON3)
// These constants are still in use:
-#define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000)
+#define PYTHON_USES_UNICODE (PY_VERSION_HEX >= 0x03000000)
typedef struct safe_globals_struc {
// init part 1: get arg_dict
@@ -84,11 +86,11 @@ static safe_globals pyside_globals = nullptr;
static PyObject *GetTypeKey(PyObject *ob);
-static PyObject *GetSignature_Function(PyObject *, const char *);
-static PyObject *GetSignature_TypeMod(PyObject *, const char *);
-static PyObject *GetSignature_Wrapper(PyObject *, const char *);
+static PyObject *GetSignature_Function(PyObject *, PyObject *);
+static PyObject *GetSignature_TypeMod(PyObject *, PyObject *);
+static PyObject *GetSignature_Wrapper(PyObject *, PyObject *);
static PyObject *get_signature(PyObject *self, PyObject *args);
-static PyObject *get_signature_intern(PyObject *ob, const char *modifier);
+static PyObject *get_signature_intern(PyObject *ob, PyObject *modifier);
static PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
@@ -100,7 +102,7 @@ CreateSignature(PyObject *props, PyObject *key)
{
/*
* Here is the new function to create all signatures. It simply calls
- * into Python and creates a signature object for a dummy-function.
+ * into Python and creates a signature object directly.
* This is so much simpler than using all the attributes explicitly
* to support '_signature_is_functionlike()'.
*/
@@ -108,10 +110,10 @@ CreateSignature(PyObject *props, PyObject *key)
const_cast<char *>("(OO)"), props, key);
}
-typedef PyObject *(*signaturefunc)(PyObject *, const char *);
+typedef PyObject *(*signaturefunc)(PyObject *, PyObject *);
static PyObject *
-_get_written_signature(signaturefunc sf, PyObject *ob, const char *modifier)
+_get_written_signature(signaturefunc sf, PyObject *ob, PyObject *modifier)
{
/*
* Be a writable Attribute, but have a computed value.
@@ -134,19 +136,19 @@ _get_written_signature(signaturefunc sf, PyObject *ob, const char *modifier)
}
static PyObject *
-pyside_cf_get___signature__(PyObject *func, const char *modifier)
+pyside_cf_get___signature__(PyObject *func, PyObject *modifier)
{
init_module_2();
return _get_written_signature(GetSignature_Function, func, modifier);
}
static PyObject *
-pyside_sm_get___signature__(PyObject *sm, const char *modifier)
+pyside_sm_get___signature__(PyObject *sm, PyObject *modifier)
{
init_module_2();
- Shiboken::AutoDecRef func(PyObject_GetAttrString(sm, "__func__"));
+ Shiboken::AutoDecRef func(PyObject_GetAttr(sm, Shiboken::PyMagicName::func()));
if (Py_TYPE(func) == PepFunction_TypePtr)
- return PyObject_GetAttrString(func, "__signature__");
+ return PyObject_GetAttr(func, Shiboken::PyMagicName::signature());
return _get_written_signature(GetSignature_Function, func, modifier);
}
@@ -158,7 +160,7 @@ _get_class_of_cf(PyObject *ob_cf)
selftype = PyDict_GetItem(pyside_globals->map_dict, ob_cf);
if (selftype == nullptr) {
// This must be an overloaded function that we handled special.
- Shiboken::AutoDecRef special(Py_BuildValue("(Os)", ob_cf, "overload"));
+ Shiboken::AutoDecRef special(Py_BuildValue("(OO)", ob_cf, Shiboken::PyName::overload()));
selftype = PyDict_GetItem(pyside_globals->map_dict, special);
if (selftype == nullptr) {
// This is probably a module function. We will return type(None).
@@ -176,15 +178,15 @@ _get_class_of_cf(PyObject *ob_cf)
static PyObject *
_get_class_of_sm(PyObject *ob_sm)
{
- Shiboken::AutoDecRef func(PyObject_GetAttrString(ob_sm, "__func__"));
+ Shiboken::AutoDecRef func(PyObject_GetAttr(ob_sm, Shiboken::PyMagicName::func()));
return _get_class_of_cf(func);
}
static PyObject *
_get_class_of_descr(PyObject *ob)
{
- Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__"));
- return PyObject_GetAttrString(ob, "__objclass__");
+ Shiboken::AutoDecRef func_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
+ return PyObject_GetAttr(ob, Shiboken::PyMagicName::objclass());
}
static PyObject *
@@ -216,10 +218,10 @@ get_funcname(PyObject *ob)
{
PyObject *func = ob;
if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
- func = PyObject_GetAttrString(ob, "__func__");
+ func = PyObject_GetAttr(ob, Shiboken::PyMagicName::func());
else
Py_INCREF(func);
- PyObject *func_name = PyObject_GetAttrString(func, "__name__");
+ PyObject *func_name = PyObject_GetAttr(func, Shiboken::PyMagicName::name());
Py_DECREF(func);
if (func_name == nullptr)
Py_FatalError("unexpected name problem in compute_name_key");
@@ -287,7 +289,7 @@ name_key_to_func(PyObject *ob)
}
static PyObject *
-pyside_md_get___signature__(PyObject *ob_md, const char *modifier)
+pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier)
{
init_module_2();
Shiboken::AutoDecRef func(name_key_to_func(ob_md));
@@ -299,14 +301,14 @@ pyside_md_get___signature__(PyObject *ob_md, const char *modifier)
}
static PyObject *
-pyside_wd_get___signature__(PyObject *ob, const char *modifier)
+pyside_wd_get___signature__(PyObject *ob, PyObject *modifier)
{
init_module_2();
return _get_written_signature(GetSignature_Wrapper, ob, modifier);
}
static PyObject *
-pyside_tp_get___signature__(PyObject *obtype_mod, const char *modifier)
+pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier)
{
init_module_2();
return _get_written_signature(GetSignature_TypeMod, obtype_mod, modifier);
@@ -314,7 +316,7 @@ pyside_tp_get___signature__(PyObject *obtype_mod, const char *modifier)
// forward
static PyObject *
-GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier);
+GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier);
static PyObject *
GetTypeKey(PyObject *ob)
@@ -332,8 +334,8 @@ GetTypeKey(PyObject *ob)
*
* This is the PyCFunction behavior, as opposed to Python functions.
*/
- Shiboken::AutoDecRef class_name(PyObject_GetAttrString(ob, "__name__"));
- Shiboken::AutoDecRef module_name(PyObject_GetAttrString(ob, "__module__"));
+ Shiboken::AutoDecRef class_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
+ Shiboken::AutoDecRef module_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::module()));
if (module_name.isNull())
PyErr_Clear();
@@ -364,7 +366,7 @@ TypeKey_to_PropsDict(PyObject *type_key, PyObject *obtype)
}
static PyObject *
-GetSignature_Function(PyObject *obfunc, const char *modifier)
+GetSignature_Function(PyObject *obfunc, PyObject *modifier)
{
// make sure that we look into PyCFunction, only...
if (Py_TYPE(obfunc) == PepFunction_TypePtr)
@@ -376,29 +378,29 @@ GetSignature_Function(PyObject *obfunc, const char *modifier)
PyObject *dict = TypeKey_to_PropsDict(type_key, obtype_mod);
if (dict == nullptr)
return nullptr;
- Shiboken::AutoDecRef func_name(PyObject_GetAttrString(obfunc, "__name__"));
+ Shiboken::AutoDecRef func_name(PyObject_GetAttr(obfunc, Shiboken::PyMagicName::name()));
PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
if (props == nullptr)
Py_RETURN_NONE;
int flags = PyCFunction_GET_FLAGS(obfunc);
- const char *sig_kind;
+ PyObject *func_kind;
if (PyModule_Check(obtype_mod))
- sig_kind = "function";
+ func_kind = Shiboken::PyName::function();
else if (flags & METH_CLASS)
- sig_kind = "classmethod";
+ func_kind = Shiboken::PyName::classmethod();
else if (flags & METH_STATIC)
- sig_kind = "staticmethod";
+ func_kind = Shiboken::PyName::staticmethod();
else
- sig_kind = "method";
- return GetSignature_Cached(props, sig_kind, modifier);
+ func_kind = Shiboken::PyName::method();
+ return GetSignature_Cached(props, func_kind, modifier);
}
static PyObject *
-GetSignature_Wrapper(PyObject *ob, const char *modifier)
+GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
{
- Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__"));
- Shiboken::AutoDecRef objclass(PyObject_GetAttrString(ob, "__objclass__"));
+ Shiboken::AutoDecRef func_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
+ Shiboken::AutoDecRef objclass(PyObject_GetAttr(ob, Shiboken::PyMagicName::objclass()));
Shiboken::AutoDecRef class_key(GetTypeKey(objclass));
if (func_name.isNull() || objclass.isNull() || class_key.isNull())
@@ -409,13 +411,13 @@ GetSignature_Wrapper(PyObject *ob, const char *modifier)
PyObject *props = PyDict_GetItem(dict, func_name);
if (props == nullptr)
Py_RETURN_NONE;
- return GetSignature_Cached(props, "method", modifier);
+ return GetSignature_Cached(props, Shiboken::PyName::method(), modifier);
}
static PyObject *
-GetSignature_TypeMod(PyObject *ob, const char *modifier)
+GetSignature_TypeMod(PyObject *ob, PyObject *modifier)
{
- Shiboken::AutoDecRef ob_name(PyObject_GetAttrString(ob, "__name__"));
+ Shiboken::AutoDecRef ob_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
Shiboken::AutoDecRef ob_key(GetTypeKey(ob));
PyObject *dict = TypeKey_to_PropsDict(ob_key, ob);
@@ -424,15 +426,26 @@ GetSignature_TypeMod(PyObject *ob, const char *modifier)
PyObject *props = PyDict_GetItem(dict, ob_name);
if (props == nullptr)
Py_RETURN_NONE;
- return GetSignature_Cached(props, "method", modifier);
+ return GetSignature_Cached(props, Shiboken::PyName::method(), modifier);
}
static PyObject *
-GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier)
+GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier)
{
+ // Special case: We want to know the func_kind.
+ if (modifier) {
+#if PYTHON_USES_UNICODE
+ PyUnicode_InternInPlace(&modifier);
+#else
+ PyString_InternInPlace(&modifier);
+#endif
+ if (modifier == Shiboken::PyMagicName::func_kind())
+ return Py_BuildValue("O", func_kind);
+ }
+
Shiboken::AutoDecRef key(modifier == nullptr
- ? Py_BuildValue("s", sig_kind)
- : Py_BuildValue("(ss)", sig_kind, modifier));
+ ? Py_BuildValue("O", func_kind)
+ : Py_BuildValue("(OO)", func_kind, modifier));
PyObject *value = PyDict_GetItem(props, key);
if (value == nullptr) {
// we need to compute a signature object
@@ -451,11 +464,11 @@ GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier)
}
static const char *PySide_CompressedSignaturePackage[] = {
-#include "embed/signature.inc"
+#include "embed/signature_inc.h"
};
static const unsigned char PySide_SignatureLoader[] = {
-#include "embed/signature_bootstrap.inc"
+#include "embed/signature_bootstrap_inc.h"
};
static safe_globals_struc *
@@ -474,13 +487,10 @@ init_phase_1(void)
#ifdef Py_LIMITED_API
// We must work for multiple versions, so use source code.
#else
- Shiboken::AutoDecRef marshal_str(Py_BuildValue("s", "marshal"));
- if (marshal_str.isNull())
- goto error;
- Shiboken::AutoDecRef marshal_module(PyImport_Import(marshal_str));
+ Shiboken::AutoDecRef marshal_module(PyImport_Import(Shiboken::PyName::marshal()));
if (marshal_module.isNull())
goto error;
- Shiboken::AutoDecRef loads(PyObject_GetAttrString(marshal_module, "loads"));
+ Shiboken::AutoDecRef loads(PyObject_GetAttr(marshal_module, Shiboken::PyName::loads()));
if (loads.isNull())
goto error;
#endif
@@ -492,7 +502,7 @@ init_phase_1(void)
goto error;
#ifdef Py_LIMITED_API
PyObject *builtins = PyEval_GetBuiltins();
- PyObject *compile = PyDict_GetItemString(builtins, "compile");
+ PyObject *compile = PyDict_GetItem(builtins, Shiboken::PyName::compile());
if (compile == nullptr)
goto error;
Shiboken::AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss",
@@ -509,7 +519,7 @@ init_phase_1(void)
goto error;
// Initialize the module
PyObject *mdict = PyModule_GetDict(p->helper_module);
- if (PyDict_SetItemString(mdict, "__builtins__", PyEval_GetBuiltins()) < 0)
+ if (PyDict_SetItem(mdict, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0)
goto error;
/*
* Unpack an embedded ZIP file with more signature modules.
@@ -555,7 +565,7 @@ init_phase_1(void)
}
error:
PyErr_Print();
- PyErr_SetString(PyExc_SystemError, "could not initialize part 1");
+ Py_FatalError("could not initialize part 1");
return nullptr;
}
@@ -597,11 +607,10 @@ init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
if (p->finish_import_func == nullptr)
goto error;
return 0;
- return 0;
}
error:
PyErr_Print();
- PyErr_SetString(PyExc_SystemError, "could not initialize part 2");
+ Py_FatalError("could not initialize part 2");
return -1;
}
@@ -799,7 +808,7 @@ static PyGetSetDef new_PyWrapperDescr_getsets[] = {
//
static PyObject *
-get_signature_intern(PyObject *ob, const char *modifier)
+get_signature_intern(PyObject *ob, PyObject *modifier)
{
if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
return pyside_cf_get___signature__(ob, modifier);
@@ -818,11 +827,11 @@ static PyObject *
get_signature(PyObject * /* self */, PyObject *args)
{
PyObject *ob;
- const char *modifier = nullptr;
+ PyObject *modifier = nullptr;
init_module_1();
- if (!PyArg_ParseTuple(args, "O|s", &ob, &modifier))
+ if (!PyArg_ParseTuple(args, "O|O", &ob, &modifier))
return nullptr;
if (Py_TYPE(ob) == PepFunction_TypePtr)
Py_RETURN_NONE;
@@ -1106,13 +1115,14 @@ _build_func_to_type(PyObject *obtype)
* "{name}.overload".
*/
PyObject *descr = PyDict_GetItemString(dict, meth->ml_name);
- const char *look_attr = meth->ml_flags & METH_STATIC ? "__func__" : "__name__";
+ PyObject *look_attr = meth->ml_flags & METH_STATIC
+ ? Shiboken::PyMagicName::func() : Shiboken::PyMagicName::name();
int check_name = meth->ml_flags & METH_STATIC ? 0 : 1;
if (descr == nullptr)
return -1;
// We first check all methods if one is hidden by something else.
- Shiboken::AutoDecRef look(PyObject_GetAttrString(descr, look_attr));
+ Shiboken::AutoDecRef look(PyObject_GetAttr(descr, look_attr));
Shiboken::AutoDecRef given(Py_BuildValue("s", meth->ml_name));
if (look.isNull()
|| (check_name && PyObject_RichCompareBool(look, given, Py_EQ) != 1)) {
@@ -1219,7 +1229,7 @@ SetError_Argument(PyObject *args, const char *func_name)
*/
PyObject *
-Sbk_TypeGet___signature__(PyObject *ob, const char *modifier)
+Sbk_TypeGet___signature__(PyObject *ob, PyObject *modifier)
{
return pyside_tp_get___signature__(ob, modifier);
}
diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h
index 57fd4047a..b22a78497 100644
--- a/sources/shiboken2/libshiboken/signature.h
+++ b/sources/shiboken2/libshiboken/signature.h
@@ -48,7 +48,7 @@ extern "C"
LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char *[]);
LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]);
LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *);
-LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, const char *);
+LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, PyObject *);
LIBSHIBOKEN_API PyObject *Sbk_TypeGet___doc__(PyObject *);
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp
index 6dc5b00bc..510ed51e6 100644
--- a/sources/shiboken2/libshiboken/typespec.cpp
+++ b/sources/shiboken2/libshiboken/typespec.cpp
@@ -39,6 +39,7 @@
#include "sbkpython.h"
#include "typespec.h"
+#include "sbkstaticstrings.h"
#include <structmember.h>
#if PY_MAJOR_VERSION < 3
@@ -730,7 +731,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
}
// no PyId_ things in Python 2
// err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname);
- err = PyDict_SetItemString(type->tp_dict, "__module__", modname);
+ err = PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::module(), modname);
Py_DECREF(modname);
if (err != 0)
goto fail;
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index 5e5cf21d7..e1eafa12f 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -30,7 +30,6 @@ if(WIN32)
endif()
target_link_libraries(shibokenmodule PUBLIC libshiboken)
-add_dependencies(shibokenmodule shiboken2)
create_generator_target(shibokenmodule)
install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}/shiboken2)
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py
index c690493b6..1f6d70b31 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py
@@ -113,7 +113,9 @@ CO_NOFREE = 0x0040
# We use '__builtin__' and '__name__' instead.
def formatannotation(annotation, base_module=None):
if getattr(annotation, '__module__', None) == 'typing':
- return repr(annotation).replace('typing.', '')
+ # The replace must not be done on Python 2.7 because it
+ # already happens somewhere else.
+ return repr(annotation) ##.replace('typing.', '')
if isinstance(annotation, type):
if annotation.__module__ in ('__builtin__', base_module):
return annotation.__name__
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
index bd827f1ee..384273d92 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
@@ -56,7 +56,7 @@ used literally as strings like "signature", "existence", etc.
"""
from textwrap import dedent
-from shibokensupport.signature import inspect
+from shibokensupport.signature import inspect, typing
from shibokensupport.signature.mapping import ellipsis
from shibokensupport.signature.lib.tool import SimpleNamespace
@@ -162,6 +162,35 @@ def define_nameless_parameter():
NamelessParameter = define_nameless_parameter()
+"""
+Note on the "Optional" feature:
+
+When an annotation has a default value that is None, then the
+type has to be wrapped into "typing.Optional".
+
+Note that only the None value creates an Optional expression,
+because the None leaves the domain of the variable.
+Defaults like integer values are ignored: They stay in the domain.
+
+That information would be lost when we use the "..." convention.
+
+Note that the typing module has the remarkable expansion
+
+ Optional[T] is Variant[T, NoneType]
+
+We want to avoid that when generating the .pyi file.
+This is done by a regex in generate_pyi.py .
+The following would work in Python 3, but this is a version-dependent
+hack that also won't work in Python 2 and would be _very_ complex.
+"""
+# import sys
+# if sys.version_info[0] == 3:
+# class hugo(list):pass
+# typing._normalize_alias["hugo"] = "Optional"
+# Optional = typing._alias(hugo, typing.T, inst=False)
+# else:
+# Optional = typing.Optional
+
def make_signature_nameless(signature):
"""
@@ -174,6 +203,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,26 +240,39 @@ 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:
defaults = ()
- if layout.ellipsis:
- defaults = (ellipsis,) * len(defaults)
annotations = props["annotations"].copy()
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
+ if default is None:
+ ann = typing.Optional[ann]
+ if default is not _empty and layout.ellipsis:
+ default = ellipsis
+ 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..f11f3cf3d 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
@@ -64,61 +64,109 @@ class ExactEnumerator(object):
"""
def __init__(self, formatter, result_type=dict):
+ global EnumType
+ try:
+ # Lazy import
+ from PySide2.QtCore import Qt
+ EnumType = type(Qt.Key)
+ except ImportError:
+ EnumType = None
+
self.fmt = formatter
self.result_type = result_type
+ self.fmt.level = 0
+ self.fmt.after_enum = self.after_enum
+ self._after_enum = False
+
+ def after_enum(self):
+ ret = self._after_enum
+ self._after_enum = False
def module(self, mod_name):
__import__(mod_name)
+ self.fmt.mod_name = mod_name
with self.fmt.module(mod_name):
module = sys.modules[mod_name]
members = inspect.getmembers(module, inspect.isclass)
functions = inspect.getmembers(module, inspect.isroutine)
ret = self.result_type()
self.fmt.class_name = None
- for func_name, func in functions:
- ret.update(self.function(func_name, func))
for class_name, klass in members:
ret.update(self.klass(class_name, klass))
+ if isinstance(klass, EnumType):
+ raise SystemError("implement enum instances at module level")
+ for func_name, func in functions:
+ ret.update(self.function(func_name, func))
return ret
def klass(self, class_name, klass):
- if not "Shiboken" in repr(klass.mro()):
- # don't look into any foreign classes!
- ret = self.result_type()
- return ret
bases_list = []
for base in klass.__bases__:
name = base.__name__
- if name == "object":
+ if name in ("object", "type"):
pass
else:
modname = base.__module__
name = modname + "." + base.__name__
bases_list.append(name)
class_str = "{}({})".format(class_name, ", ".join(bases_list))
+ ret = self.result_type()
+ # class_members = inspect.getmembers(klass)
+ # gives us also the inherited things.
+ class_members = sorted(list(klass.__dict__.items()))
+ subclasses = []
+ functions = []
+ enums = []
+
+ for thing_name, thing in class_members:
+ if inspect.isclass(thing):
+ subclass_name = ".".join((class_name, thing_name))
+ subclasses.append((subclass_name, thing))
+ elif inspect.isroutine(thing):
+ func_name = thing_name.split(".")[0] # remove ".overload"
+ signature = getattr(thing, "__signature__", None)
+ if signature is not None:
+ functions.append((func_name, thing))
+ elif type(type(thing)) is EnumType:
+ enums.append((thing_name, thing))
+ init_signature = getattr(klass, "__signature__", None)
+ enums.sort(key=lambda tup: tup[1]) # sort by enum value
+ self.fmt.have_body = bool(subclasses or functions or enums or init_signature)
+
with self.fmt.klass(class_name, class_str):
- ret = self.function("__init__", klass)
- # class_members = inspect.getmembers(klass)
- # gives us also the inherited things.
- class_members = sorted(list(klass.__dict__.items()))
- subclasses = []
- for thing_name, thing in class_members:
- if inspect.isclass(thing):
- subclass_name = ".".join((class_name, thing_name))
- subclasses.append((subclass_name, thing))
- else:
- func_name = thing_name.split(".")[0] # remove ".overload"
- ret.update(self.function(func_name, thing))
+ self.fmt.level += 1
+ self.fmt.class_name = class_name
+ if hasattr(self.fmt, "enum"):
+ # this is an optional feature
+ for enum_name, value in enums:
+ with self.fmt.enum(class_name, enum_name, int(value)):
+ pass
for subclass_name, subclass in subclasses:
+ if klass == subclass:
+ # this is a side effect of the typing module for Python 2.7
+ # via the "._gorg" property, which we can safely ignore.
+ print("Warning: {class_name} points to itself via {subclass_name}, skipped!"
+ .format(**locals()))
+ continue
ret.update(self.klass(subclass_name, subclass))
- return ret
+ self.fmt.class_name = class_name
+ ret.update(self.function("__init__", klass))
+ for func_name, func in functions:
+ func_kind = get_signature(func, "__func_kind__")
+ modifier = func_kind if func_kind in (
+ "staticmethod", "classmethod") else None
+ ret.update(self.function(func_name, func, modifier))
+ self.fmt.level -= 1
+ return ret
- def function(self, func_name, func):
+ def function(self, func_name, func, modifier=None):
+ self.fmt.level += 1
ret = self.result_type()
- signature = getattr(func, '__signature__', None)
+ signature = func.__signature__
if signature is not None:
- with self.fmt.function(func_name, signature) as key:
+ with self.fmt.function(func_name, signature, modifier) as key:
ret[key] = signature
+ self.fmt.level -= 1
return ret
@@ -142,7 +190,7 @@ class SimplifyingEnumerator(ExactEnumerator):
is desired.
"""
- def function(self, func_name, func):
+ def function(self, func_name, func, modifier=None):
ret = self.result_type()
signature = get_signature(func, 'existence')
sig = stringify(signature) if signature is not None else None
@@ -159,11 +207,11 @@ class HintingEnumerator(ExactEnumerator):
hinting stubs. Only default values are replaced by "...".
"""
- def function(self, func_name, func):
+ def function(self, func_name, func, modifier=None):
ret = self.result_type()
signature = get_signature(func, 'hintingstub')
if signature is not None:
- with self.fmt.function(func_name, signature) as key:
+ with self.fmt.function(func_name, signature, modifier) as key:
ret[key] = signature
return ret
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
index b34bfb404..3b0825049 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
@@ -43,6 +43,8 @@ from __future__ import print_function, absolute_import
tool.py
Some useful stuff, see below.
+On the function with_metaclass see the answer from Martijn Pieters on
+https://stackoverflow.com/questions/18513821/python-metaclass-understanding-the-with-metaclass
"""
from textwrap import dedent
@@ -132,4 +134,21 @@ def build_brace_pattern(level, separators=""):
indent = idx * " ", **locals())
return pattern.replace("C", "{").replace("D", "}")
+
+# Copied from the six module:
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass."""
+ # This requires a bit of explanation: the basic idea is to make a dummy
+ # metaclass for one level of class instantiation that replaces itself with
+ # the actual metaclass.
+ class metaclass(type):
+
+ def __new__(cls, name, this_bases, d):
+ return meta(name, bases, d)
+
+ @classmethod
+ def __prepare__(cls, name, this_bases):
+ return meta.__prepare__(name, bases)
+ return type.__new__(metaclass, 'temporary_class', (), {})
+
# eof
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
index 3d25c5690..a0367883a 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
@@ -85,20 +85,6 @@ def formatannotation(annotation, base_module=None):
return annotation.__module__ + '.' + annotation.__qualname__
return repr(annotation)
-# patching __repr__ to disable the __repr__ of typing.TypeVar:
-"""
- def __repr__(self):
- if self.__covariant__:
- prefix = '+'
- elif self.__contravariant__:
- prefix = '-'
- else:
- prefix = '~'
- return prefix + self.__name__
-"""
-def _typevar__repr__(self):
- return "typing." + self.__name__
-
# Note also that during the tests we have a different encoding that would
# break the Python license decorated files without an encoding line.
@@ -160,12 +146,18 @@ def list_modules(message):
print(" {:23}".format(name), repr(module)[:70])
+orig_typing = True
if sys.version_info >= (3,):
import typing
import inspect
inspect.formatannotation = formatannotation
else:
- from shibokensupport import typing27 as typing
+ if "typing" not in sys.modules:
+ orig_typing = False
+ from shibokensupport import typing27 as typing
+ sys.modules["typing"] = typing
+ else:
+ import typing
import inspect
namespace = inspect.__dict__
from shibokensupport import backport_inspect as inspect
@@ -174,7 +166,6 @@ else:
inspect.__doc__ += _doc
# force inspect to find all attributes. See "heuristic" in pydoc.py!
inspect.__all__ = list(x for x in dir(inspect) if not x.startswith("_"))
-typing.TypeVar.__repr__ = _typevar__repr__
# Fix the module names in typing if possible. This is important since
# the typing names should be I/O compatible, so that typing.Dict
@@ -206,7 +197,7 @@ def move_into_pyside_package():
put_into_package(PySide2.support.signature, importhandler)
put_into_package(PySide2.support.signature.lib, enum_sig)
- put_into_package(PySide2.support.signature, typing)
+ put_into_package(None if orig_typing else PySide2.support.signature, typing)
put_into_package(PySide2.support.signature, inspect)
from shibokensupport.signature import mapping
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
index 5d6a24016..2110ebe7a 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -55,6 +55,7 @@ import os
from shibokensupport.signature import typing
from shibokensupport.signature.typing import TypeVar, Generic
+from shibokensupport.signature.lib.tool import with_metaclass
class ellipsis(object):
def __repr__(self):
@@ -66,27 +67,15 @@ Variant = typing.Any
ModelIndexList = typing.List[int]
QImageCleanupFunction = typing.Callable
+# 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
# Char = typing.Union[str, int] # how do I model the limitation to 1 char?
-# Copied from the six module:
-def with_metaclass(meta, *bases):
- """Create a base class with a metaclass."""
- # This requires a bit of explanation: the basic idea is to make a dummy
- # metaclass for one level of class instantiation that replaces itself with
- # the actual metaclass.
- class metaclass(type):
-
- def __new__(cls, name, this_bases, d):
- return meta(name, bases, d)
-
- @classmethod
- def __prepare__(cls, name, this_bases):
- return meta.__prepare__(name, bases)
- return type.__new__(metaclass, 'temporary_class', (), {})
-
class _CharMeta(type):
def __repr__(self):
return '%s.%s' % (self.__module__, self.__name__)
@@ -208,7 +197,7 @@ class _Parameterized(object):
class ResultVariable(_Parameterized):
pass
-# Mark the primitive variables to become Sequence, Iterator or List
+# Mark the primitive variables to become Sequence, Iterable or List
# (decided in the parser).
class ArrayLikeVariable(_Parameterized):
pass
@@ -275,6 +264,7 @@ type_map = {}
namespace = globals() # our module's __dict__
type_map.update({
+ "...": ellipsis,
"bool": bool,
"char": Char,
"char*": str,
@@ -337,6 +327,7 @@ type_map.update({
"unsigned long": int,
"unsigned short int": int, # 5.6, RHEL 6.6
"unsigned short": int,
+ "Unspecified": None,
"ushort": int,
"void": int, # be more specific?
"WId": WId,
@@ -357,6 +348,7 @@ type_map.update({
"array GLuint*" : ArrayLikeVariable(int),
"array int*" : ArrayLikeVariable(int),
"array long long*" : ArrayLikeVariable(int),
+ "array long*" : ArrayLikeVariable(int),
"array short*" : ArrayLikeVariable(int),
"array signed char*" : bytes,
"array unsigned char*" : bytes,
@@ -420,6 +412,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 204f37384..8d970956b 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -106,7 +106,8 @@ def _parse_line(line):
$
"""
ret = SimpleNamespace(**re.match(line_re, line, re.VERBOSE).groupdict())
- argstr = ret.arglist
+ # PYSIDE-1095: Handle arbitrary default expressions
+ argstr = ret.arglist.replace("->", ".deref.")
arglist = _parse_arglist(argstr)
args = []
for arg in arglist:
@@ -116,7 +117,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,7 +168,7 @@ 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
map = type_map[valtype]
# typing.Any: '_SpecialForm' object has no attribute '__name__'
@@ -315,9 +316,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, handle_argvar)
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
index 786a84ecb..44d78c433 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
@@ -86,6 +86,10 @@ PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
to be bound by the terms and conditions of this License Agreement.
"""
+# This is the typing module for Python 2.7
+# https://github.com/python/typing
+# 2019-08-22
+
from __future__ import absolute_import, unicode_literals
import abc
@@ -108,8 +112,11 @@ __all__ = [
'Any',
'Callable',
'ClassVar',
+ 'Final',
'Generic',
+ 'Literal',
'Optional',
+ 'Protocol',
'Tuple',
'Type',
'TypeVar',
@@ -141,6 +148,7 @@ __all__ = [
'SupportsAbs',
'SupportsComplex',
'SupportsFloat',
+ 'SupportsIndex',
'SupportsInt',
# Concrete collection types.
@@ -152,17 +160,20 @@ __all__ = [
'Set',
'FrozenSet',
'NamedTuple', # Not really a type.
+ 'TypedDict', # Not really a type.
'Generator',
# One-off things.
'AnyStr',
'cast',
+ 'final',
'get_type_hints',
'NewType',
'no_type_check',
'no_type_check_decorator',
'NoReturn',
'overload',
+ 'runtime_checkable',
'Text',
'TYPE_CHECKING',
]
@@ -447,7 +458,7 @@ def _type_check(arg, msg):
if (
type(arg).__name__ in ('_Union', '_Optional') and
not getattr(arg, '__origin__', None) or
- isinstance(arg, TypingMeta) and arg._gorg in (Generic, _Protocol)
+ isinstance(arg, TypingMeta) and arg._gorg in (Generic, Protocol)
):
raise TypeError("Plain %s is not valid as type argument" % arg)
return arg
@@ -466,7 +477,7 @@ def _type_repr(obj):
return _qualname(obj)
return '%s.%s' % (obj.__module__, _qualname(obj))
if obj is Ellipsis:
- return('...')
+ return '...'
if isinstance(obj, types.FunctionType):
return obj.__name__
return repr(obj)
@@ -537,6 +548,157 @@ class _ClassVar(_FinalTypingBase):
ClassVar = _ClassVar(_root=True)
+class _FinalMeta(TypingMeta):
+ """Metaclass for _Final"""
+
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ self = super(_FinalMeta, cls).__new__(cls, name, bases, namespace)
+ return self
+
+
+class _Final(_FinalTypingBase):
+ """A special typing construct to indicate that a name
+ cannot be re-assigned or overridden in a subclass.
+ For example:
+
+ MAX_SIZE: Final = 9000
+ MAX_SIZE += 1 # Error reported by type checker
+
+ class Connection:
+ TIMEOUT: Final[int] = 10
+ class FastConnector(Connection):
+ TIMEOUT = 1 # Error reported by type checker
+
+ There is no runtime checking of these properties.
+ """
+
+ __metaclass__ = _FinalMeta
+ __slots__ = ('__type__',)
+
+ def __init__(self, tp=None, **kwds):
+ self.__type__ = tp
+
+ def __getitem__(self, item):
+ cls = type(self)
+ if self.__type__ is None:
+ return cls(_type_check(item,
+ '{} accepts only single type.'.format(cls.__name__[1:])),
+ _root=True)
+ raise TypeError('{} cannot be further subscripted'
+ .format(cls.__name__[1:]))
+
+ def _eval_type(self, globalns, localns):
+ new_tp = _eval_type(self.__type__, globalns, localns)
+ if new_tp == self.__type__:
+ return self
+ return type(self)(new_tp, _root=True)
+
+ def __repr__(self):
+ r = super(_Final, self).__repr__()
+ if self.__type__ is not None:
+ r += '[{}]'.format(_type_repr(self.__type__))
+ return r
+
+ def __hash__(self):
+ return hash((type(self).__name__, self.__type__))
+
+ def __eq__(self, other):
+ if not isinstance(other, _Final):
+ return NotImplemented
+ if self.__type__ is not None:
+ return self.__type__ == other.__type__
+ return self is other
+
+
+Final = _Final(_root=True)
+
+
+def final(f):
+ """This decorator can be used to indicate to type checkers that
+ the decorated method cannot be overridden, and decorated class
+ cannot be subclassed. For example:
+
+ class Base:
+ @final
+ def done(self) -> None:
+ ...
+ class Sub(Base):
+ def done(self) -> None: # Error reported by type checker
+ ...
+ @final
+ class Leaf:
+ ...
+ class Other(Leaf): # Error reported by type checker
+ ...
+
+ There is no runtime checking of these properties.
+ """
+ return f
+
+
+class _LiteralMeta(TypingMeta):
+ """Metaclass for _Literal"""
+
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ self = super(_LiteralMeta, cls).__new__(cls, name, bases, namespace)
+ return self
+
+
+class _Literal(_FinalTypingBase):
+ """A type that can be used to indicate to type checkers that the
+ corresponding value has a value literally equivalent to the
+ provided parameter. For example:
+
+ var: Literal[4] = 4
+
+ The type checker understands that 'var' is literally equal to the
+ value 4 and no other value.
+
+ Literal[...] cannot be subclassed. There is no runtime checking
+ verifying that the parameter is actually a value instead of a type.
+ """
+
+ __metaclass__ = _LiteralMeta
+ __slots__ = ('__values__',)
+
+ def __init__(self, values=None, **kwds):
+ self.__values__ = values
+
+ def __getitem__(self, item):
+ cls = type(self)
+ if self.__values__ is None:
+ if not isinstance(item, tuple):
+ item = (item,)
+ return cls(values=item,
+ _root=True)
+ raise TypeError('{} cannot be further subscripted'
+ .format(cls.__name__[1:]))
+
+ def _eval_type(self, globalns, localns):
+ return self
+
+ def __repr__(self):
+ r = super(_Literal, self).__repr__()
+ if self.__values__ is not None:
+ r += '[{}]'.format(', '.join(map(_type_repr, self.__values__)))
+ return r
+
+ def __hash__(self):
+ return hash((type(self).__name__, self.__values__))
+
+ def __eq__(self, other):
+ if not isinstance(other, _Literal):
+ return NotImplemented
+ if self.__values__ is not None:
+ return self.__values__ == other.__values__
+ return self is other
+
+
+Literal = _Literal(_root=True)
+
+
class AnyMeta(TypingMeta):
"""Metaclass for Any."""
@@ -1122,10 +1284,11 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
if base is Generic:
raise TypeError("Cannot inherit from plain Generic")
if (isinstance(base, GenericMeta) and
- base.__origin__ is Generic):
+ base.__origin__ in (Generic, Protocol)):
if gvars is not None:
raise TypeError(
- "Cannot inherit from Generic[...] multiple types.")
+ "Cannot inherit from Generic[...] or"
+ " Protocol[...] multiple times.")
gvars = base.__parameters__
if gvars is None:
gvars = tvars
@@ -1135,8 +1298,10 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
if not tvarset <= gvarset:
raise TypeError(
"Some type variables (%s) "
- "are not listed in Generic[%s]" %
+ "are not listed in %s[%s]" %
(", ".join(str(t) for t in tvars if t not in gvarset),
+ "Generic" if any(b.__origin__ is Generic
+ for b in bases) else "Protocol",
", ".join(str(g) for g in gvars)))
tvars = gvars
@@ -1285,25 +1450,21 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
"Parameter list to %s[...] cannot be empty" % _qualname(self))
msg = "Parameters to generic types must be types."
params = tuple(_type_check(p, msg) for p in params)
- if self is Generic:
+ if self in (Generic, Protocol):
# Generic can only be subscripted with unique type variables.
if not all(isinstance(p, TypeVar) for p in params):
raise TypeError(
- "Parameters to Generic[...] must all be type variables")
+ "Parameters to %s[...] must all be type variables" % self.__name__)
if len(set(params)) != len(params):
raise TypeError(
- "Parameters to Generic[...] must all be unique")
+ "Parameters to %s[...] must all be unique" % self.__name__)
tvars = params
args = params
elif self in (Tuple, Callable):
tvars = _type_vars(params)
args = params
- elif self is _Protocol:
- # _Protocol is internal, don't check anything.
- tvars = params
- args = params
- elif self.__origin__ in (Generic, _Protocol):
- # Can't subscript Generic[...] or _Protocol[...].
+ elif self.__origin__ in (Generic, Protocol):
+ # Can't subscript Generic[...] or Protocol[...].
raise TypeError("Cannot subscript already-subscripted %s" %
repr(self))
else:
@@ -1343,7 +1504,7 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
# latter, we must extend __instancecheck__ too. For simplicity
# we just skip the cache check -- instance checks for generic
# classes are supposed to be rare anyways.
- if not isinstance(instance, type):
+ if hasattr(instance, "__class__"):
return issubclass(instance.__class__, self)
return False
@@ -1690,85 +1851,175 @@ def overload(func):
return _overload_dummy
+_PROTO_WHITELIST = ['Callable', 'Iterable', 'Iterator',
+ 'Hashable', 'Sized', 'Container', 'Collection',
+ 'Reversible', 'ContextManager']
+
+
class _ProtocolMeta(GenericMeta):
- """Internal metaclass for _Protocol.
+ """Internal metaclass for Protocol.
- This exists so _Protocol classes can be generic without deriving
+ This exists so Protocol classes can be generic without deriving
from Generic.
"""
+ def __init__(cls, *args, **kwargs):
+ super(_ProtocolMeta, cls).__init__(*args, **kwargs)
+ if not cls.__dict__.get('_is_protocol', None):
+ cls._is_protocol = any(b is Protocol or
+ isinstance(b, _ProtocolMeta) and
+ b.__origin__ is Protocol
+ for b in cls.__bases__)
+ if cls._is_protocol:
+ for base in cls.__mro__[1:]:
+ if not (base in (object, Generic) or
+ base.__module__ == '_abcoll' and
+ base.__name__ in _PROTO_WHITELIST or
+ isinstance(base, TypingMeta) and base._is_protocol or
+ isinstance(base, GenericMeta) and base.__origin__ is Generic):
+ raise TypeError('Protocols can only inherit from other protocols,'
+ ' got %r' % base)
+ cls._callable_members_only = all(callable(getattr(cls, attr))
+ for attr in cls._get_protocol_attrs())
+
+ def _no_init(self, *args, **kwargs):
+ if type(self)._is_protocol:
+ raise TypeError('Protocols cannot be instantiated')
+ cls.__init__ = _no_init
+
+ def _proto_hook(cls, other):
+ if not cls.__dict__.get('_is_protocol', None):
+ return NotImplemented
+ if not isinstance(other, type):
+ # Similar error as for issubclass(1, int)
+ # (also not a chance for old-style classes)
+ raise TypeError('issubclass() arg 1 must be a new-style class')
+ for attr in cls._get_protocol_attrs():
+ for base in other.__mro__:
+ if attr in base.__dict__:
+ if base.__dict__[attr] is None:
+ return NotImplemented
+ break
+ else:
+ return NotImplemented
+ return True
+ if '__subclasshook__' not in cls.__dict__:
+ cls.__subclasshook__ = classmethod(_proto_hook)
- def __instancecheck__(self, obj):
- if _Protocol not in self.__bases__:
- return super(_ProtocolMeta, self).__instancecheck__(obj)
- raise TypeError("Protocols cannot be used with isinstance().")
+ def __instancecheck__(self, instance):
+ # We need this method for situations where attributes are assigned in __init__
+ if isinstance(instance, type):
+ # This looks like a fundamental limitation of Python 2.
+ # It cannot support runtime protocol metaclasses, On Python 2 classes
+ # cannot be correctly inspected as instances of protocols.
+ return False
+ if ((not getattr(self, '_is_protocol', False) or
+ self._callable_members_only) and
+ issubclass(instance.__class__, self)):
+ return True
+ if self._is_protocol:
+ if all(hasattr(instance, attr) and
+ (not callable(getattr(self, attr)) or
+ getattr(instance, attr) is not None)
+ for attr in self._get_protocol_attrs()):
+ return True
+ return super(GenericMeta, self).__instancecheck__(instance)
def __subclasscheck__(self, cls):
- if not self._is_protocol:
- # No structural checks since this isn't a protocol.
- return NotImplemented
+ if (self.__dict__.get('_is_protocol', None) and
+ not self.__dict__.get('_is_runtime_protocol', None)):
+ if (sys._getframe(1).f_globals['__name__'] in ['abc', 'functools'] or
+ # This is needed because we remove subclasses from unions on Python 2.
+ sys._getframe(2).f_globals['__name__'] == 'typing'):
+ return False
+ raise TypeError("Instance and class checks can only be used with"
+ " @runtime_checkable protocols")
+ if (self.__dict__.get('_is_runtime_protocol', None) and
+ not self._callable_members_only):
+ if sys._getframe(1).f_globals['__name__'] in ['abc', 'functools']:
+ return super(GenericMeta, self).__subclasscheck__(cls)
+ raise TypeError("Protocols with non-method members"
+ " don't support issubclass()")
+ return super(_ProtocolMeta, self).__subclasscheck__(cls)
- if self is _Protocol:
- # Every class is a subclass of the empty protocol.
- return True
+ def _get_protocol_attrs(self):
+ attrs = set()
+ for base in self.__mro__[:-1]: # without object
+ if base.__name__ in ('Protocol', 'Generic'):
+ continue
+ annotations = getattr(base, '__annotations__', {})
+ for attr in list(base.__dict__.keys()) + list(annotations.keys()):
+ if (not attr.startswith('_abc_') and attr not in (
+ '__abstractmethods__', '__annotations__', '__weakref__',
+ '_is_protocol', '_is_runtime_protocol', '__dict__',
+ '__args__', '__slots__', '_get_protocol_attrs',
+ '__next_in_mro__', '__parameters__', '__origin__',
+ '__orig_bases__', '__extra__', '__tree_hash__',
+ '__doc__', '__subclasshook__', '__init__', '__new__',
+ '__module__', '_MutableMapping__marker',
+ '__metaclass__', '_gorg', '_callable_members_only')):
+ attrs.add(attr)
+ return attrs
- # Find all attributes defined in the protocol.
- attrs = self._get_protocol_attrs()
- for attr in attrs:
- if not any(attr in d.__dict__ for d in cls.__mro__):
- return False
- return True
+class Protocol(object):
+ """Base class for protocol classes. Protocol classes are defined as::
- def _get_protocol_attrs(self):
- # Get all Protocol base classes.
- protocol_bases = []
- for c in self.__mro__:
- if getattr(c, '_is_protocol', False) and c.__name__ != '_Protocol':
- protocol_bases.append(c)
+ class Proto(Protocol):
+ def meth(self):
+ # type: () -> int
+ pass
- # Get attributes included in protocol.
- attrs = set()
- for base in protocol_bases:
- for attr in base.__dict__.keys():
- # Include attributes not defined in any non-protocol bases.
- for c in self.__mro__:
- if (c is not base and attr in c.__dict__ and
- not getattr(c, '_is_protocol', False)):
- break
- else:
- if (not attr.startswith('_abc_') and
- attr != '__abstractmethods__' and
- attr != '_is_protocol' and
- attr != '_gorg' and
- attr != '__dict__' and
- attr != '__args__' and
- attr != '__slots__' and
- attr != '_get_protocol_attrs' and
- attr != '__next_in_mro__' and
- attr != '__parameters__' and
- attr != '__origin__' and
- attr != '__orig_bases__' and
- attr != '__extra__' and
- attr != '__tree_hash__' and
- attr != '__module__'):
- attrs.add(attr)
+ Such classes are primarily used with static type checkers that recognize
+ structural subtyping (static duck-typing), for example::
- return attrs
+ class C:
+ def meth(self):
+ # type: () -> int
+ return 0
+
+ def func(x):
+ # type: (Proto) -> int
+ return x.meth()
+
+ func(C()) # Passes static type check
+ See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable
+ act as simple-minded runtime protocols that checks only the presence of
+ given attributes, ignoring their type signatures.
-class _Protocol(object):
- """Internal base class for protocol classes.
+ Protocol classes can be generic, they are defined as::
- This implements a simple-minded structural issubclass check
- (similar but more general than the one-offs in collections.abc
- such as Hashable).
+ class GenProto(Protocol[T]):
+ def meth(self):
+ # type: () -> T
+ pass
"""
__metaclass__ = _ProtocolMeta
__slots__ = ()
-
_is_protocol = True
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Protocol:
+ raise TypeError("Type Protocol cannot be instantiated; "
+ "it can be used only as a base class")
+ return _generic_new(cls.__next_in_mro__, cls, *args, **kwds)
+
+
+def runtime_checkable(cls):
+ """Mark a protocol class as a runtime protocol, so that it
+ can be used with isinstance() and issubclass(). Raise TypeError
+ if applied to a non-protocol class.
+
+ This allows a simple-minded structural check very similar to the
+ one-offs in collections.abc such as Hashable.
+ """
+ if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol:
+ raise TypeError('@runtime_checkable can be only applied to protocol classes,'
+ ' got %r' % cls)
+ cls._is_runtime_protocol = True
+ return cls
+
# Various ABCs mimicking those in collections.abc.
# A few are simply re-exported for completeness.
@@ -1786,7 +2037,8 @@ class Iterator(Iterable[T_co]):
__extra__ = collections_abc.Iterator
-class SupportsInt(_Protocol):
+@runtime_checkable
+class SupportsInt(Protocol):
__slots__ = ()
@abstractmethod
@@ -1794,7 +2046,8 @@ class SupportsInt(_Protocol):
pass
-class SupportsFloat(_Protocol):
+@runtime_checkable
+class SupportsFloat(Protocol):
__slots__ = ()
@abstractmethod
@@ -1802,7 +2055,8 @@ class SupportsFloat(_Protocol):
pass
-class SupportsComplex(_Protocol):
+@runtime_checkable
+class SupportsComplex(Protocol):
__slots__ = ()
@abstractmethod
@@ -1810,7 +2064,17 @@ class SupportsComplex(_Protocol):
pass
-class SupportsAbs(_Protocol[T_co]):
+@runtime_checkable
+class SupportsIndex(Protocol):
+ __slots__ = ()
+
+ @abstractmethod
+ def __index__(self):
+ pass
+
+
+@runtime_checkable
+class SupportsAbs(Protocol[T_co]):
__slots__ = ()
@abstractmethod
@@ -1823,7 +2087,8 @@ if hasattr(collections_abc, 'Reversible'):
__slots__ = ()
__extra__ = collections_abc.Reversible
else:
- class Reversible(_Protocol[T_co]):
+ @runtime_checkable
+ class Reversible(Protocol[T_co]):
__slots__ = ()
@abstractmethod
@@ -1996,21 +2261,6 @@ class DefaultDict(collections.defaultdict, MutableMapping[KT, VT]):
return _generic_new(collections.defaultdict, cls, *args, **kwds)
-############################
-# Insertion by CT 2019-02-21
-#
-class OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]):
- __slots__ = ()
- __extra__ = collections.OrderedDict
-
- def __new__(cls, *args, **kwds):
- if cls._gorg is OrderedDict:
- return collections.OrderedDict(*args, **kwds)
- return _generic_new(collections.OrderedDict, cls, *args, **kwds)
-#
-############################
-
-
class Counter(collections.Counter, Dict[T, int]):
__slots__ = ()
__extra__ = collections.Counter
@@ -2100,6 +2350,87 @@ def NamedTuple(typename, fields):
return cls
+def _check_fails(cls, other):
+ try:
+ if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools', 'typing']:
+ # Typed dicts are only for static structural subtyping.
+ raise TypeError('TypedDict does not support instance and class checks')
+ except (AttributeError, ValueError):
+ pass
+ return False
+
+
+def _dict_new(cls, *args, **kwargs):
+ return dict(*args, **kwargs)
+
+
+def _typeddict_new(cls, _typename, _fields=None, **kwargs):
+ total = kwargs.pop('total', True)
+ if _fields is None:
+ _fields = kwargs
+ elif kwargs:
+ raise TypeError("TypedDict takes either a dict or keyword arguments,"
+ " but not both")
+
+ ns = {'__annotations__': dict(_fields), '__total__': total}
+ try:
+ # Setting correct module is necessary to make typed dict classes pickleable.
+ ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__')
+ except (AttributeError, ValueError):
+ pass
+
+ return _TypedDictMeta(_typename, (), ns)
+
+
+class _TypedDictMeta(type):
+ def __new__(cls, name, bases, ns, total=True):
+ # Create new typed dict class object.
+ # This method is called directly when TypedDict is subclassed,
+ # or via _typeddict_new when TypedDict is instantiated. This way
+ # TypedDict supports all three syntaxes described in its docstring.
+ # Subclasses and instances of TypedDict return actual dictionaries
+ # via _dict_new.
+ ns['__new__'] = _typeddict_new if name == b'TypedDict' else _dict_new
+ tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns)
+
+ anns = ns.get('__annotations__', {})
+ msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
+ anns = {n: _type_check(tp, msg) for n, tp in anns.items()}
+ for base in bases:
+ anns.update(base.__dict__.get('__annotations__', {}))
+ tp_dict.__annotations__ = anns
+ if not hasattr(tp_dict, '__total__'):
+ tp_dict.__total__ = total
+ return tp_dict
+
+ __instancecheck__ = __subclasscheck__ = _check_fails
+
+
+TypedDict = _TypedDictMeta(b'TypedDict', (dict,), {})
+TypedDict.__module__ = __name__
+TypedDict.__doc__ = \
+ """A simple typed name space. At runtime it is equivalent to a plain dict.
+
+ TypedDict creates a dictionary type that expects all of its
+ instances to have a certain set of keys, with each key
+ associated with a value of a consistent type. This expectation
+ is not checked at runtime but is only enforced by type checkers.
+ Usage::
+
+ Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
+
+ a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK
+ b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check
+
+ assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
+
+ The type info could be accessed via Point2D.__annotations__. TypedDict
+ supports an additional equivalent form::
+
+ Point2D = TypedDict('Point2D', x=int, y=int, label=str)
+ """
+
+
def NewType(name, tp):
"""NewType creates simple unique types with almost zero
runtime overhead. NewType(name, tp) is considered a subtype of tp
diff --git a/sources/shiboken2/tests/CMakeLists.txt b/sources/shiboken2/tests/CMakeLists.txt
index 085a4344c..464707a9a 100644
--- a/sources/shiboken2/tests/CMakeLists.txt
+++ b/sources/shiboken2/tests/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(BUILD_TESTS)
+ find_package(Qt5Test 5.12 REQUIRED)
+endif()
+
add_subdirectory(libminimal)
if(NOT DEFINED MINIMAL_TESTS)
add_subdirectory(libsample)
@@ -74,24 +78,24 @@ add_subdirectory(dumpcodemodel)
if (NOT APIEXTRACTOR_DOCSTRINGS_DISABLED)
# project(sphinxtabletest)
-#
+#
# # TODO
# set(sphinxtabletest_SRC sphinxtabletest.cpp)
# qt4_automoc(${sphinxtabletest_SRC})
-#
+#
# include_directories(${QT_INCLUDE_DIR}
# ${QT_QTCORE_INCLUDE_DIR}
# ${CMAKE_CURRENT_BINARY_DIR}
# ${qtdoc_generator_SOURCE_DIR})
-#
+#
# add_executable(sphinxtabletest ${sphinxtabletest_SRC})
-#
+#
# target_link_libraries(sphinxtabletest
# ${QT_QTTEST_LIBRARY}
# ${APIEXTRACTOR_LIBRARY}
# qtdoc_generator
# genrunner)
-#
+#
# add_test("sphinxtable" sphinxtabletest)
# if (INSTALL_TESTS)
# install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/sphinxtabletest DESTINATION ${TEST_INSTALL_DIR})
diff --git a/sources/shiboken2/tests/libsample/modifications.cpp b/sources/shiboken2/tests/libsample/modifications.cpp
index 98b22f09b..56ba81875 100644
--- a/sources/shiboken2/tests/libsample/modifications.cpp
+++ b/sources/shiboken2/tests/libsample/modifications.cpp
@@ -149,3 +149,19 @@ Modifications::nonConversionRuleForArgumentWithDefaultValue(ObjectType** object)
*object = m_object;
return true;
}
+
+void Modifications::setEnumValue(TestEnum e)
+{
+ m_enumValue = e;
+}
+
+Modifications::TestEnum Modifications::enumValue() const
+{
+ return m_enumValue;
+}
+
+Modifications::TestEnum Modifications::defaultEnumValue() const
+{
+ return TestEnumValue2;
+}
+
diff --git a/sources/shiboken2/tests/libsample/modifications.h b/sources/shiboken2/tests/libsample/modifications.h
index fa32bdec3..674a05f27 100644
--- a/sources/shiboken2/tests/libsample/modifications.h
+++ b/sources/shiboken2/tests/libsample/modifications.h
@@ -51,6 +51,11 @@ public:
Overloaded_ibPP
};
+ enum TestEnum {
+ TestEnumValue1,
+ TestEnumValue2
+ };
+
// those overloaded methods should be heavily modified
// to push the overload decisor to its limits
inline OverloadedModFunc overloaded(int a0, bool b0, int c0, double d0) { return Overloaded_ibid; }
@@ -123,8 +128,13 @@ public:
// Inject code with a %CONVERTTOPYTHON that receives an user's primitive type.
static inline OddBool passOddBool(OddBool ob) { return ob; }
+ void setEnumValue(TestEnum e = TestEnumValue1);
+ TestEnum enumValue() const;
+ TestEnum defaultEnumValue() const;
+
private:
ObjectType* m_object;
+ TestEnum m_enumValue = TestEnumValue1;
};
class LIBSAMPLE_API AbstractModifications : public Modifications
diff --git a/sources/shiboken2/tests/samplebinding/modifications_test.py b/sources/shiboken2/tests/samplebinding/modifications_test.py
index 1dcd50359..e9a1eaf7f 100644
--- a/sources/shiboken2/tests/samplebinding/modifications_test.py
+++ b/sources/shiboken2/tests/samplebinding/modifications_test.py
@@ -220,5 +220,15 @@ class ModificationsTest(unittest.TestCase):
self.assertTrue(isinstance(res, float))
self.assertEqual(res, em.increment)
+ def testDefaultValueModifications(self):
+ # PSYIDE-1095: setEnumValue() has the default value modified to
+ # calling defaultEnumValue() which returns Modifications.TestEnumValue2.
+ # This used to generated broken code since defaultEnumValue() was
+ # qualified by the enum scope.
+ modifications = Modifications()
+ modifications.setEnumValue()
+ self.assertEqual(modifications.enumValue(), Modifications.TestEnumValue2)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
index 19b4948a1..30ad5def7 100644
--- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
@@ -227,7 +227,6 @@
</modify-argument>
<modify-argument index="1">
<replace-type modified-type="PStr"/>
- <remove-default-expression/>
<replace-default-expression with="PStr()"/>
</modify-argument>
<inject-code class="target" position="end">
@@ -956,6 +955,7 @@
<object-type name="Modifications">
<enum-type name="OverloadedModFunc"/>
+ <enum-type name="TestEnum"/>
<modify-function signature="overloaded(int, bool, int, double)">
<modify-argument index="2">
@@ -1287,6 +1287,11 @@
%PYARG_0 = %CONVERTTOPYTHON[OddBool](%0);
</inject-code>
</modify-function>
+ <modify-function signature="setEnumValue(Modifications::TestEnum)">
+ <modify-argument index="1">
+ <replace-default-expression with="cppSelf->defaultEnumValue()"/>
+ </modify-argument>
+ </modify-function>
</object-type>
<object-type name="AbstractModifications">