aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2018-11-20 10:47:21 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2018-11-20 10:47:24 +0100
commit30b7d287f3b53158d69b8346581b9d5f423883cf (patch)
treee46d163147df58b8c338d4ee992287978739f7e6
parenta140ef0cc43f14338f563b8e6a4499fcc1521a6e (diff)
parent6c62f0616919b1a715c965f14a40257e717cab9b (diff)
Merge remote-tracking branch 'origin/5.12' into dev
-rw-r--r--sources/pyside2/PySide2/QtCore/typesystem_core_common.xml34
-rw-r--r--sources/pyside2/PySide2/__init__.py.in2
-rw-r--r--sources/pyside2/PySide2/support/signature/__init__.py2
-rw-r--r--sources/pyside2/PySide2/support/signature/layout.py16
-rw-r--r--sources/pyside2/PySide2/support/signature/lib/enum_sig.py62
-rw-r--r--sources/pyside2/PySide2/support/signature/mapping.py42
-rw-r--r--sources/pyside2/PySide2/typesystem_templates.xml7
-rw-r--r--sources/pyside2/doc/CMakeLists.txt11
-rw-r--r--sources/pyside2/doc/conf.py.in2
-rw-r--r--sources/pyside2/doc/tutorials/basictutorial/clickablebutton.rst84
-rw-r--r--sources/pyside2/doc/tutorials/basictutorial/dialog.rst139
-rw-r--r--sources/pyside2/doc/tutorials/basictutorial/qml.rst63
-rw-r--r--sources/pyside2/doc/tutorials/basictutorial/uifiles.rst166
-rw-r--r--sources/pyside2/doc/tutorials/basictutorial/widgets.rst40
-rw-r--r--sources/pyside2/doc/tutorials/index.rst5
-rw-r--r--sources/pyside2/tests/QtCore/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/QtCore/qabstractitemmodel_test.py4
-rw-r--r--sources/pyside2/tests/QtCore/qjsondocument_test.py56
-rw-r--r--sources/pyside2/tests/QtCore/qmodelindex_internalpointer_test.py23
-rw-r--r--sources/pyside2/tests/registry/init_platform.py10
-rw-r--r--sources/shiboken2/doc/conf.py.in2
-rw-r--r--sources/shiboken2/generator/generator.cpp9
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp31
-rw-r--r--sources/shiboken2/libshiboken/qt_attribution.json2
-rw-r--r--sources/shiboken2/libshiboken/sbkconverter.cpp4
-rw-r--r--sources/shiboken2/libshiboken/sbkconverter.h3
-rw-r--r--sources/shiboken2/libshiboken/sbkconverter_p.h30
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp575
28 files changed, 1070 insertions, 355 deletions
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
index cff7e0af0..3b5d9f520 100644
--- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
+++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
@@ -1827,11 +1827,6 @@
</add-function>
</value-type>
<value-type name="QPersistentModelIndex" hash-function="qHash">
- <modify-function signature="internalPointer()const">
- <inject-code class="target" position="beginning">
- <insert-template name="return_internal_pointer" />
- </inject-code>
- </modify-function>
<modify-function signature="operator const QModelIndex&amp;()const">
<modify-argument index="return">
<parent index="this" action="add"/>
@@ -2101,36 +2096,12 @@
<object-type name="QAbstractItemModel">
<enum-type name="CheckIndexOption" flags="CheckIndexOptions" since="5.11"/>
<enum-type name="LayoutChangeHint" />
- <!-- This function was replaced by a added function -->
- <modify-function signature="createIndex(int,int,void*)const" remove="all"/>
<!-- This function is the same as createIndex(int, int, int)const -->
<modify-function signature="createIndex(int,int,quintptr)const">
<modify-argument index="3">
<replace-default-expression with="0" />
</modify-argument>
</modify-function>
- <add-function signature="createIndex(int,int,PyObject*)const" return-type="QModelIndex">
- <modify-argument index="1">
- <rename to="row"/>
- </modify-argument>
- <modify-argument index="2">
- <rename to="column"/>
- </modify-argument>
- <modify-argument index="3">
- <rename to="ptr"/>
- </modify-argument>
- <inject-code class="target" position="beginning">
- %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1, %2, %PYARG_3);
- %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
- </inject-code>
- <inject-documentation mode="append" format="target">
- Creates a model index for the given row and column with the internal pointer ptr.
- When using a QSortFilterProxyModel, its indexes have their own internal pointer. It is not advisable to access this internal pointer outside of the model. Use the data() function instead.
- This function provides a consistent interface that model subclasses must use to create model indexes.
-
- .. warning:: Because of some Qt/Python itegration rules, the ptr argument do not get the reference incremented during the QModelIndex life time. So it is necessary to keep the object used on ptr argument alive during the whole process. Do not destroy the object if you are not sure about that.
- </inject-documentation>
- </add-function>
<inject-code class="target" position="end">
qRegisterMetaType&lt;QVector&lt;int&gt; &gt;("QVector&lt;int&gt;");
</inject-code>
@@ -3890,11 +3861,6 @@
</modify-function>
</object-type>
<value-type name="QModelIndex" hash-function="qHash">
- <modify-function signature="internalPointer()const">
- <inject-code class="target" position="beginning">
- <insert-template name="return_internal_pointer" />
- </inject-code>
- </modify-function>
<modify-function signature="model()const">
<modify-argument index="return">
<define-ownership class="target" owner="default"/>
diff --git a/sources/pyside2/PySide2/__init__.py.in b/sources/pyside2/PySide2/__init__.py.in
index 631f5f13a..ac75f52b6 100644
--- a/sources/pyside2/PySide2/__init__.py.in
+++ b/sources/pyside2/PySide2/__init__.py.in
@@ -21,8 +21,6 @@ def _setupQtDirectories():
import shiboken2
pyside_package_dir = os.path.abspath(os.path.dirname(__file__))
- # Used by signature module.
- os.environ["PYSIDE_PACKAGE_DIR"] = pyside_package_dir
if sys.platform == 'win32':
# PATH has to contain the package directory, otherwise plugins
diff --git a/sources/pyside2/PySide2/support/signature/__init__.py b/sources/pyside2/PySide2/support/signature/__init__.py
index 14e63a5fb..49224bf92 100644
--- a/sources/pyside2/PySide2/support/signature/__init__.py
+++ b/sources/pyside2/PySide2/support/signature/__init__.py
@@ -42,5 +42,5 @@ from __future__ import print_function, absolute_import
from .loader import inspect
from PySide2 import QtCore
if QtCore.QProcess.__signature__:
- pass # trigger initialization
+ pass # trigger initialization phase 2, so we can import:
from signature_loader import get_signature
diff --git a/sources/pyside2/PySide2/support/signature/layout.py b/sources/pyside2/PySide2/support/signature/layout.py
index ac7833f03..e18cb2172 100644
--- a/sources/pyside2/PySide2/support/signature/layout.py
+++ b/sources/pyside2/PySide2/support/signature/layout.py
@@ -58,6 +58,7 @@ used literally as strings like "signature", "existence", etc.
from textwrap import dedent
from .loader import inspect
+
class SimpleNamespace(object):
# From types.rst, because the builtin is implemented in Python 3, only.
def __init__(self, **kwargs):
@@ -71,6 +72,7 @@ class SimpleNamespace(object):
def __eq__(self, other):
return self.__dict__ == other.__dict__
+
class SignatureLayout(SimpleNamespace):
"""
Configure a signature.
@@ -140,6 +142,7 @@ typeerror = SignatureLayout(definition=False,
return_annotation=False,
parameter_names=False)
+
def define_nameless_parameter():
"""
Create Nameless Parameters
@@ -168,8 +171,10 @@ def define_nameless_parameter():
body["__str__"] = __str__
return type(newname, bases, body)
+
NamelessParameter = define_nameless_parameter()
+
def make_signature_nameless(signature):
"""
Make a Signature Nameless
@@ -178,7 +183,8 @@ def make_signature_nameless(signature):
The signature looks different, but is totally intact.
"""
for key in signature.parameters.keys():
- Signature.parameters[key].__class__ = NamelessParameter
+ signature.parameters[key].__class__ = NamelessParameter
+
def create_signature(props, key):
if not props:
@@ -193,7 +199,7 @@ def create_signature(props, key):
else:
sig_kind, modifier = key, "signature"
- layout = globals()[modifier] # lookup of the modifier, here
+ layout = globals()[modifier] # lookup of the modifier in this module
if not isinstance(layout, SignatureLayout):
raise SystemError("Modifiers must be names of a SignatureLayout "
"instance")
@@ -201,14 +207,16 @@ def create_signature(props, key):
# this is the basic layout of a signature
varnames = props["varnames"]
if layout.definition:
- if sig_kind == "method":
+ if sig_kind == "function":
+ pass
+ elif sig_kind == "method":
varnames = ("self",) + varnames
elif sig_kind == "staticmethod":
pass
elif sig_kind == "classmethod":
varnames = ("klass",) + varnames
else:
- raise SystemError("Methods must be normal, staticmethod or "
+ raise SystemError("Methods must be function, method, staticmethod or "
"classmethod")
# calculate the modifications
defaults = props["defaults"][:]
diff --git a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
index 702ee7ebd..c043f04f8 100644
--- a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
+++ b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
@@ -37,6 +37,8 @@
##
#############################################################################
+from __future__ import print_function, absolute_import
+
import sys
from PySide2.support.signature import inspect, get_signature
@@ -58,7 +60,11 @@ class ExactEnumerator(object):
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))
return ret
@@ -79,8 +85,15 @@ class ExactEnumerator(object):
# class_members = inspect.getmembers(klass)
# gives us also the inherited things.
class_members = sorted(list(klass.__dict__.items()))
- for func_name, func in class_members:
- ret.update(self.function(func_name, func))
+ 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:
+ ret.update(self.function(thing_name, thing))
+ for subclass_name, subclass in subclasses:
+ ret.update(self.klass(subclass_name, subclass))
return ret
def function(self, func_name, func):
@@ -92,6 +105,27 @@ class ExactEnumerator(object):
return ret
+def simplify(signature):
+ if isinstance(signature, list):
+ # remove duplicates which still sometimes occour:
+ ret = set(simplify(sig) for sig in signature)
+ return sorted(ret) if len(ret) > 1 else list(ret)[0]
+ ret = []
+ for pv in signature.parameters.values():
+ txt = str(pv)
+ if ":" not in txt: # 'self' or '*args'
+ continue
+ txt = txt[txt.index(":") + 1:]
+ if "=" in txt:
+ txt = txt[:txt.index("=")]
+ quote = txt[0]
+ if quote in ("'", '"') and txt[-1] == quote:
+ txt = txt[1:-1]
+ ret.append(txt.strip())
+ return tuple(ret)
+
+
+### disabled for now:
class SimplifyingEnumerator(ExactEnumerator):
"""
SimplifyingEnumerator enumerates all signatures in a module filtered.
@@ -109,5 +143,27 @@ class SimplifyingEnumerator(ExactEnumerator):
signature = get_signature(func, 'existence')
if signature is not None and func_name not in ("next", "__next__"):
with self.fmt.function(func_name, signature) as key:
- ret[key] = signature
+ ret[key] = str(signature)
+ return ret
+
+
+class SimplifyingEnumerator(ExactEnumerator):
+ """
+ SimplifyingEnumerator enumerates all signatures in a module filtered.
+
+ There are no default values, no variable
+ names and no self parameter. Only types are present after simplification.
+ The functions 'next' resp. '__next__' are removed
+ to make the output identical for Python 2 and 3.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = getattr(func, '__signature__', None)
+ sig = simplify(signature) if signature is not None else None
+ if sig is not None and func_name not in ("next", "__next__", "__div__"):
+ with self.fmt.function(func_name, sig) as key:
+ ret[key] = sig
return ret
diff --git a/sources/pyside2/PySide2/support/signature/mapping.py b/sources/pyside2/PySide2/support/signature/mapping.py
index 6b7d1ad01..23ba6a7f1 100644
--- a/sources/pyside2/PySide2/support/signature/mapping.py
+++ b/sources/pyside2/PySide2/support/signature/mapping.py
@@ -56,6 +56,11 @@ import sys
import struct
import PySide2
try:
+ import sample
+except ImportError:
+ pass
+
+try:
from . import typing
except ImportError:
import typing
@@ -64,10 +69,12 @@ ellipsis = "..."
Char = typing.Union[str, int] # how do I model the limitation to 1 char?
StringList = typing.List[str]
IntList = typing.List[int]
+IntMatrix = typing.List[IntList]
Variant = typing.Any
ModelIndexList = typing.List[int]
QImageCleanupFunction = typing.Callable
-FloatMatrix = typing.List[typing.List[float]]
+FloatList = typing.List[float]
+FloatMatrix = typing.List[FloatList]
# Pair could be more specific, but we loose the info in the generator.
Pair = typing.Tuple[typing.Any, typing.Any]
MultiMap = typing.DefaultDict[str, typing.List[str]]
@@ -132,7 +139,7 @@ class Instance(_NotCalled):
class Reloader(object):
def __init__(self):
self.sys_module_count = 0
- self.uninitialized = PySide2.__all__[:]
+ self.uninitialized = PySide2.__all__[:] + ["sample"]
def update(self):
if self.sys_module_count == len(sys.modules):
@@ -140,7 +147,7 @@ class Reloader(object):
self.sys_module_count = len(sys.modules)
g = globals()
for mod_name in self.uninitialized[:]:
- if "PySide2." + mod_name in sys.modules:
+ if "PySide2." + mod_name in sys.modules or mod_name == "sample":
self.uninitialized.remove(mod_name)
proc_name = "init_" + mod_name
if proc_name in g:
@@ -289,6 +296,7 @@ def init_QtCore():
"PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
"QVariantMap": dict,
"PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr,
+ "PySide2.QtCore.double": float,
})
try:
type_map.update({
@@ -299,6 +307,7 @@ def init_QtCore():
pass
return locals()
+
def init_QtGui():
import PySide2.QtGui
type_map.update({
@@ -328,6 +337,7 @@ def init_QtGui():
})
return locals()
+
def init_QtWidgets():
import PySide2.QtWidgets
from PySide2.QtWidgets import QWidget, QMessageBox, QStyleOption, QStyleHintReturn, QStyleOptionComplex
@@ -364,6 +374,7 @@ def init_QtWidgets():
})
return locals()
+
def init_QtSql():
import PySide2.QtSql
from PySide2.QtSql import QSqlDatabase
@@ -373,6 +384,7 @@ def init_QtSql():
})
return locals()
+
def init_QtNetwork():
import PySide2.QtNetwork
type_map.update({
@@ -383,6 +395,7 @@ def init_QtNetwork():
})
return locals()
+
def init_QtXmlPatterns():
import PySide2.QtXmlPatterns
from PySide2.QtXmlPatterns import QXmlName
@@ -392,6 +405,7 @@ def init_QtXmlPatterns():
})
return locals()
+
def init_QtMultimedia():
import PySide2.QtMultimedia
import PySide2.QtMultimediaWidgets
@@ -401,6 +415,7 @@ def init_QtMultimedia():
})
return locals()
+
def init_QtOpenGL():
import PySide2.QtOpenGL
type_map.update({
@@ -417,6 +432,7 @@ def init_QtOpenGL():
})
return locals()
+
def init_QtQml():
import PySide2.QtQml
type_map.update({
@@ -429,6 +445,7 @@ def init_QtQml():
})
return locals()
+
def init_QtQuick():
import PySide2.QtQuick
type_map.update({
@@ -440,6 +457,7 @@ def init_QtQuick():
})
return locals()
+
def init_QtScript():
import PySide2.QtScript
type_map.update({
@@ -447,6 +465,7 @@ def init_QtScript():
})
return locals()
+
def init_QtTest():
import PySide2.QtTest
type_map.update({
@@ -471,6 +490,23 @@ def init_QtWinExtras():
})
return locals()
+def init_sample():
+ type_map.update({
+ "sample.int": int,
+ "Complex": complex,
+ "sample.OddBool": bool,
+ "sample.bool": bool,
+ "sample.PStr": str,
+ "double[]": FloatList,
+ "OddBool": bool,
+ "PStr": str,
+ "sample.char": Char,
+ "double[][]": FloatMatrix,
+ "int[]": IntList,
+ "int[][]": IntMatrix,
+ })
+ return locals()
+
# Here was testbinding, actually the source of all evil.
# end of file
diff --git a/sources/pyside2/PySide2/typesystem_templates.xml b/sources/pyside2/PySide2/typesystem_templates.xml
index 1cac1a6ba..f0e4a2bf8 100644
--- a/sources/pyside2/PySide2/typesystem_templates.xml
+++ b/sources/pyside2/PySide2/typesystem_templates.xml
@@ -354,13 +354,6 @@
%PYARG_0 = Shiboken::String::fromCString(qPrintable(format));
</template>
- <template name="return_internal_pointer">
- %PYARG_0 = reinterpret_cast&lt;PyObject*>(%CPPSELF.%FUNCTION_NAME());
- if (!%PYARG_0)
- %PYARG_0 = Py_None;
- Py_INCREF(%PYARG_0);
- </template>
-
<!-- Helpers for modifying "bool nativeEventFilter(QByteArray, void*, long *result)"
to return a tuple of bool,long -->
<template name="return_native_eventfilter_conversion_variables">
diff --git a/sources/pyside2/doc/CMakeLists.txt b/sources/pyside2/doc/CMakeLists.txt
index 5a78db453..428b83350 100644
--- a/sources/pyside2/doc/CMakeLists.txt
+++ b/sources/pyside2/doc/CMakeLists.txt
@@ -87,6 +87,16 @@ add_custom_target(qdoc
add_custom_target(apidoc
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/rst
COMMAND ${SHIBOKEN_PYTHON_INTERPRETER} ${SPHINX_BUILD} -b html ${CMAKE_CURRENT_BINARY_DIR}/rst html
+ #copying shiboken2 and ApiExtractor doc htmls
+ COMMENT "Copying over the Shiboken2 and ApiExtractor doc HTMLs..."
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/html/shiboken2
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/html/shiboken2/ApiExtractor
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${CMAKE_CURRENT_BINARY_DIR}/../../shiboken2/doc/html
+ ${CMAKE_CURRENT_BINARY_DIR}/html/shiboken2
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${CMAKE_CURRENT_BINARY_DIR}/../../shiboken2/ApiExtractor/doc/html
+ ${CMAKE_CURRENT_BINARY_DIR}/html/shiboken2/ApiExtractor
)
# create conf.py based on conf.py.in
@@ -128,7 +138,6 @@ add_dependencies(docrsts qdoc)
# COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_INSTALL_PREFIX}/share/devhelp/books"
# COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_INSTALL_PREFIX}/share/doc/${BINDING_NAME}/html" "${CMAKE_INSTALL_PREFIX}/share/devhelp/books/${BINDING_NAME}"
# )
-
#install files
add_custom_target(apidocinstall
COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX}/share/doc/PySide2-${BINDING_API_VERSION} && cp -rv ${CMAKE_CURRENT_BINARY_DIR}/html/* ${CMAKE_INSTALL_PREFIX}/share/doc/PySide-${BINDING_API_VERSION}
diff --git a/sources/pyside2/doc/conf.py.in b/sources/pyside2/doc/conf.py.in
index 2eb4e6bf3..dfbefee60 100644
--- a/sources/pyside2/doc/conf.py.in
+++ b/sources/pyside2/doc/conf.py.in
@@ -169,4 +169,4 @@ html_show_sourcelink = False
# Link to the shiboken2 sphinx project to enable linking
# between the two projects.
-intersphinx_mapping = {'shiboken2': ('../../../shiboken2/doc/html','../../../shiboken2/doc/html/objects.inv')}
+intersphinx_mapping = {'shiboken2': ('shiboken2','@CMAKE_BINARY_DIR@/../shiboken2/doc/html/objects.inv')}
diff --git a/sources/pyside2/doc/tutorials/basictutorial/clickablebutton.rst b/sources/pyside2/doc/tutorials/basictutorial/clickablebutton.rst
new file mode 100644
index 000000000..afec6d84f
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/basictutorial/clickablebutton.rst
@@ -0,0 +1,84 @@
+A Simple Button Tutorial
+************************
+
+In this tutorial, we'll show you how to handle **signals and slots**
+using Qt for Python. **Signals and slots** is a Qt feature that lets
+your graphical widgets communicate with other graphical widgets or
+your python code. Our application creates a button that logs the
+`Button clicked, Hello!` message to the python console each time you
+click it.
+
+Let's start by importing the necessary PySide2 classes and python
+`sys` module:
+::
+ import sys
+ from PySide2.QtWidgets import QApplication, QPushButton
+ from PySide2.QtCore import Slot
+
+Let's also create a python function that logs the message to the
+console:
+::
+
+ # Greetings
+ @Slot()
+ def say_hello():
+ print("Button clicked, Hello!")
+
+.. note:: The `@Slot()` is a decorator that identifies a function as
+ a slot. It is not important to understand why for now,
+ but use it always to avoid unexpected behavior.
+
+Now, as mentioned in previous examples you must create the
+`QApplication` to run your PySide2 code:
+::
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+
+Let's create the clickable button, which is a `QPushButton` instance.
+To label the button, we pass a python string to the constructor:
+::
+ # Create a button
+ button = QPushButton("Click me")
+
+Before we show the button, we must connect it to the `say_hello()`
+function that we defined earlier. There are two ways of doing this;
+using the old style or the new style, which is more pythonic. Let's
+use the new style in this case. You can find more information about
+both these styles in the
+`Signals and Slots in PySide2 <https://wiki.qt.io/Qt_for_Python_Signals_and_Slots>`_
+wiki page.
+
+The `QPushButton` has a predefined signal called **clicked**, which
+is triggered every time the button is clicked. We'll connect this
+signal to the `say_hello()` function:
+::
+ # Connect the button to the function
+ button.clicked.connect(say_hello)
+
+Finally, we show the button and start the Qt main loop:
+::
+ # Show the button
+ button.show()
+ # Run the main Qt loop
+ app.exec_()
+
+Here is the complete code for this example:
+::
+ #!/usr/bin/python
+
+ import sys
+ from PySide2.QtWidgets import QApplication, QPushButton
+ from PySide2.QtCore import Slot
+
+ @Slot()
+ def say_hello():
+ print("Button clicked, Hello!")
+
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+ # Create a button, connect it and show it
+ button = QPushButton("Click me")
+ button.clicked.connect(say_hello)
+ button.show()
+ # Run the main Qt loop
+ app.exec_()
diff --git a/sources/pyside2/doc/tutorials/basictutorial/dialog.rst b/sources/pyside2/doc/tutorials/basictutorial/dialog.rst
new file mode 100644
index 000000000..1daa6b89d
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/basictutorial/dialog.rst
@@ -0,0 +1,139 @@
+Creating a Simple PySide2 Dialog Application
+*********************************************
+
+This tutorial shows how to build a simple dialog with some
+basic widgets. The idea is to let users provide their name
+in a `QLineEdit`, and the dialog greets them on click of a
+`QPushButton`.
+
+Let us just start with a simple stub that creates and shows
+a dialog. This stub is updated during the course of this
+tutorial, but you can use this stub as is if you need to:
+::
+ import sys
+ from PySide2.QtWidgets import QApplication, QDialog, QLineEdit, QPushButton
+
+ class Form(QDialog):
+
+ def __init__(self, parent=None):
+ super(Form, self).__init__(parent)
+ self.setWindowTitle("My Form")
+
+
+ if __name__ == '__main__':
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+ # Create and show the form
+ form = Form()
+ form.show()
+ # Run the main Qt loop
+ sys.exit(app.exec_())
+
+The imports aren't new to you, the same for the creation of the
+`QApplication` and the execution of the Qt main loop.
+The only novelty here is the **class definition**.
+
+You can create any class that subclasses PySide2 widgets.
+In this case, we are subclassing `QDialog` to define a custom
+dialog, which we name as **Form**. We have also implemented the
+`init()` method that calls the `QDialog`'s init method with the
+parent widget, if any. Also, the new `setWindowTitle()` method
+just sets the title of the dialog window. In `main()`, you can see
+that we are creating a *Form object* and showing it to the world.
+
+Create the Widgets
+===================
+
+We are going to create two widgets: a `QLineEdit` where users can
+enter their name, and a `QPushButton` that prints the contents of
+the `QLineEdit`.
+So, let's add the following code to the `init()` method of our Form:
+::
+ # Create widgets
+ self.edit = QLineEdit("Write my name here..")
+ self.button = QPushButton("Show Greetings")
+
+It's obvious from the code that both widgets will show the corresponding
+texts.
+
+Create a layout to organize the Widgets
+========================================
+
+Qt comes with layout-support that helps you organize the widgets
+in your application. In this case, let's use `QVBoxLayout` to lay out
+the widgets vertically. Add the following code to the `init()` method,
+after creating the widgets:
+::
+ # Create layout and add widgets
+ layout = QVBoxLayout()
+ layout.addWidget(self.edit)
+ layout.addWidget(self.button)
+ # Set dialog layout
+ self.setLayout(layout)
+
+So, we create the layout, add the widgets with `addWidget()`,
+and finally we say that our **Form** will have our `QVBoxLayout`
+as its layout.
+
+Create the function to greet and connect the Button
+====================================================
+
+Finally, we just have to add a function to our custom **Form**
+and *connect* our button to it. Our function will be a part of
+the Form, so you have to add it after the `init()` function:
+::
+ # Greets the user
+ def greetings(self):
+ print ("Hello {}".format(self.edit.text()))
+
+Our function just prints the contents of the `QLineEdit` to the
+python console. We have access to the text by means of the
+`QLineEdit.text()` method.
+
+Now that we have everything, we just need to *connect* the
+`QPushButton` to the `Form.greetings()` method. To do so, add the
+following line to the `init()` method:
+::
+ # Add button signal to greetings slot
+ self.button.clicked.connect(self.greetings)
+
+Once executed, you can enter your name in the `QLineEdit` and watch
+the console for greetings.
+
+Complete code
+=============
+
+Here is the complete code for this tutorial:
+::
+ import sys
+ from PySide2.QtWidgets import (QLineEdit, QPushButton, QApplication,
+ QVBoxLayout, QDialog)
+
+ class Form(QDialog):
+
+ def __init__(self, parent=None):
+ super(Form, self).__init__(parent)
+ # Create widgets
+ self.edit = QLineEdit("Write my name here")
+ self.button = QPushButton("Show Greetings")
+ # Create layout and add widgets
+ layout = QVBoxLayout()
+ layout.addWidget(self.edit)
+ layout.addWidget(self.button)
+ # Set dialog layout
+ self.setLayout(layout)
+ # Add button signal to greetings slot
+ self.button.clicked.connect(self.greetings)
+
+ # Greets the user
+ def greetings(self):
+ print ("Hello %s" % self.edit.text())
+
+ if __name__ == '__main__':
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+ # Create and show the form
+ form = Form()
+ form.show()
+ # Run the main Qt loop
+ sys.exit(app.exec_())
diff --git a/sources/pyside2/doc/tutorials/basictutorial/qml.rst b/sources/pyside2/doc/tutorials/basictutorial/qml.rst
new file mode 100644
index 000000000..0b26b3b83
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/basictutorial/qml.rst
@@ -0,0 +1,63 @@
+Your First Application Using PySide2 and QtQuick/QML
+*****************************************************
+
+QML is a declarative language that lets you develop applications
+faster than with traditional languages. It is ideal for designing the
+UI of your applicataion because of its declarative nature. In QML, a
+user interface is specified as a tree of objects with properties. In
+this tutorial, we will show how to make a simple "Hello World"
+application with PySide2 and QML.
+
+A PySide2/QML application consists, at least, of two different files -
+a file with the QML description of the user interface, and a python file
+that loads the QML file. To make things easier, let's save both files in
+the same directory.
+
+Here is a simple QML file called `view.qml`:
+::
+ import QtQuick 2.0
+
+ Rectangle {
+ width: 200
+ height: 200
+ color: "green"
+
+ Text {
+ text: "Hello World"
+ anchors.centerIn: parent
+ }
+ }
+
+We start by importing `QtQuick 2.0`, which is a QML module.
+
+The rest of the QML code is pretty straightforward for those who
+have previously used HTML or XML files. Basically, we are creating
+a green rectangle with the size `200*200`, and adding a Text element
+that reads "Hello World". The code `anchors.centerIn: parent` makes
+the text appear centered in relation to its immediate parent, which
+is the Rectangle in this case.
+
+Now, let's see how the code looks on the PySide2.
+Let's call it `main.py`:
+::
+ from PySide2.QtWidgets import QApplication
+ from PySide2.QtQuick import QQuickView
+ from PySide2.QtCore import QUrl
+
+ app = QApplication([])
+ view = QQuickView()
+ url = QUrl("view.qml")
+
+ view.setSource(url)
+ view.show()
+ app.exec_()
+
+If you are already familiar with PySide2 and have followed our
+tutorials, you have already seen much of this code.
+The only novelties are that you must `import QtQuick` and set the
+source of the `QQuickView` object to the URL of your QML file.
+Then, as any Qt widget, you call `QQuickView.show()`.
+
+.. note:: If you are programming for desktop, you should consider
+ adding `view.setResizeMode(QQuickView.SizeRootObjectToView)`
+ before showing the view.
diff --git a/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst b/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst
new file mode 100644
index 000000000..00731abc3
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst
@@ -0,0 +1,166 @@
+Using UI Files
+***************
+
+This page describes the use of Qt Creator to create graphical
+interfaces for your Qt for Python project.
+You will need **Qt Creator** to design and modify your interface (UI file).
+
+If you don't know how to use Qt Creator, refer to the
+`Using Qt Designer <http://doc.qt.io/qtcreator/creator-using-qt-designer.html>`_
+documentation page.
+
+At Qt Creator, create a new Qt Design Form, choose "Main Window" for template.
+And save as `mainwindow.ui`.
+Add a `QPushButton` to the center of the centralwidget.
+
+Your file (mainwindow.ui) should look something like this:
+::
+ <?xml version="1.0" encoding="UTF-8"?>
+ <ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <widget class="QPushButton" name="pushButton">
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>80</y>
+ <width>201</width>
+ <height>81</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>20</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+ </ui>
+
+Now we are ready to decide how to use the **UI file** from Python.
+
+Generating a Python class
+=========================
+
+Another option to interact with a **UI file** is to generate a Python
+class from it. This is possible thanks to the `pyside2-uic` tool.
+To use this tool, you need to run the following command on a console:
+::
+ pyside2-uic mainwindow.ui > ui_mainwindow.py
+
+We redirect all the output of the command to a file called `ui_mainwindow.py`,
+which will be imported directly:
+::
+ from ui_mainwindow import Ui_MainWindow
+
+Now to use it, we should create a personalized class for our widget
+to **setup** this generated design.
+
+To understand the idea, let's take a look at the whole code:
+::
+ import sys
+ from PySide2.QtWidgets import QApplication, QMainWindow
+ from PySide2.QtCore import QFile
+ from ui_mainwindow import Ui_MainWindow
+
+ class MainWindow(QMainWindow):
+ def __init__(self):
+ super(MainWindow, self).__init__()
+ self.ui = Ui_MainWindow()
+ self.ui.setupUi(self)
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+
+ window = MainWindow()
+ window.show()
+
+ sys.exit(app.exec_())
+
+What is inside the *if* statement is already known from the previous
+examples, and our new basic class contains only two new lines
+that are in charge of loading the generated python class from the UI
+file:
+::
+ self.ui = Ui_MainWindow()
+ self.ui.setupUi(self)
+
+.. note:: You must run `pyside2-uic` again every time you make changes
+to the **UI file**.
+
+Loading it directly
+====================
+
+To load the UI file directly, we will need a class from the **QtUiTools**
+module:
+::
+ from PySide2.QtUiTools import QUiLoader
+
+The `QUiLoader` lets us load the **ui file** dynamically
+and use it right away:
+::
+ ui_file = QFile("mainwindow.ui")
+ ui_file.open(QFile.ReadOnly)
+
+ loader = QUiLoader()
+ window = loader.load(ui_file)
+ window.show()
+
+The complete code of this example looks like this:
+::
+ # File: main.py
+ import sys
+ from PySide2.QtUiTools import QUiLoader
+ from PySide2.QtWidgets import QApplication
+ from PySide2.QtCore import QFile
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+
+ ui_file = QFile("mainwindow.ui")
+ ui_file.open(QFile.ReadOnly)
+
+ loader = QUiLoader()
+ window = loader.load(ui_file)
+ ui_file.close()
+ window.show()
+
+ sys.exit(app.exec_())
+
+Then to execute it we just need to run the following on a
+command prompt:
+::
+ python main.py
diff --git a/sources/pyside2/doc/tutorials/basictutorial/widgets.rst b/sources/pyside2/doc/tutorials/basictutorial/widgets.rst
new file mode 100644
index 000000000..80c137cac
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/basictutorial/widgets.rst
@@ -0,0 +1,40 @@
+Your First QtWidgets Application
+*********************************
+
+As with any other programming framework,
+you start with the traditional "Hello World" program.
+
+Here is a simple example of a Hello World application in PySide2:
+::
+ import sys
+ from PySide2.QtWidgets import QApplication, QLabel
+
+ app = QApplication(sys.argv)
+ label = QLabel("Hello World!")
+ label.show()
+ app.exec_()
+
+
+For a widget application using PySide2, you must always start by
+importing the appropriate class from the `PySide2.QtWidgets` module.
+
+After the imports, you create a `QApplication` instance. As Qt can
+receive arguments from command line, you may pass any argument to
+the QApplication object. Usually, you don't need to pass any
+arguments so you can leave it as is, or use the following approach:
+::
+ app = QApplication([])
+
+After the creation of the application object, we have created a
+`QLabel` object. A `QLabel` is a widget that can present text
+(simple or rich, like html), and images:
+::
+ # This HTML approach will be valid too!
+ label = QLabel("<font color=red size=40>Hello World!</font>")
+
+.. note:: After the creation of the label, we are calling the
+method `show()` to show the label.
+
+Finally, we call `app.exec_()` to enter the Qt main loop and start
+to execute the Qt code. In reality, it is only here where the label
+is shown, but this can be ignored for now.
diff --git a/sources/pyside2/doc/tutorials/index.rst b/sources/pyside2/doc/tutorials/index.rst
index c09b48ab5..5b1eb9fe3 100644
--- a/sources/pyside2/doc/tutorials/index.rst
+++ b/sources/pyside2/doc/tutorials/index.rst
@@ -21,5 +21,10 @@ Tutorials
.. toctree::
:maxdepth: 2
+ basictutorial/widgets.rst
+ basictutorial/qml.rst
+ basictutorial/clickablebutton.rst
+ basictutorial/dialog.rst
+ basictutorial/uifiles.rst
qmltutorial/index.rst
qmladvancedtutorial/index.rst
diff --git a/sources/pyside2/tests/QtCore/CMakeLists.txt b/sources/pyside2/tests/QtCore/CMakeLists.txt
index d6d12f651..08e63d043 100644
--- a/sources/pyside2/tests/QtCore/CMakeLists.txt
+++ b/sources/pyside2/tests/QtCore/CMakeLists.txt
@@ -68,6 +68,7 @@ PYSIDE_TEST(qfile_test.py)
PYSIDE_TEST(qfileread_test.py)
PYSIDE_TEST(qflags_test.py)
PYSIDE_TEST(qinstallmsghandler_test.py)
+PYSIDE_TEST(qjsondocument_test.py)
PYSIDE_TEST(qlinef_test.py)
PYSIDE_TEST(qlocale_test.py)
PYSIDE_TEST(qlockfile_test.py)
diff --git a/sources/pyside2/tests/QtCore/qabstractitemmodel_test.py b/sources/pyside2/tests/QtCore/qabstractitemmodel_test.py
index 70b610c34..fd8d01c99 100644
--- a/sources/pyside2/tests/QtCore/qabstractitemmodel_test.py
+++ b/sources/pyside2/tests/QtCore/qabstractitemmodel_test.py
@@ -34,14 +34,12 @@ from PySide2.QtCore import *
class MyModel (QAbstractListModel):
pass
-class Foo:
- pass
class TestQModelIndexInternalPointer(unittest.TestCase):
def testInternalPointer(self):
m = MyModel()
- foo = Foo()
+ foo = QObject()
idx = m.createIndex(0,0, foo)
check = m.checkIndex(idx, QAbstractItemModel.CheckIndexOption.IndexIsValid
| QAbstractItemModel.CheckIndexOption.DoNotUseParent
diff --git a/sources/pyside2/tests/QtCore/qjsondocument_test.py b/sources/pyside2/tests/QtCore/qjsondocument_test.py
new file mode 100644
index 000000000..0cd4dc5b2
--- /dev/null
+++ b/sources/pyside2/tests/QtCore/qjsondocument_test.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## 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 General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## 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-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+'''Test cases for QJsonDocument/nullptr_t'''
+
+import unittest
+from PySide2.QtCore import QJsonDocument
+import py3kcompat as py3k
+
+class QJsonDocumentTest(unittest.TestCase):
+
+ def testToVariant(self):
+ a = QJsonDocument.fromJson(b'{"test": null}')
+ self.assertIsInstance(a, QJsonDocument)
+ if py3k.IS_PY3K:
+ self.assertEqual(str(a.toVariant()), "{'test': None}")
+ else:
+ self.assertEqual(str(a.toVariant()), "{u'test': None}")
+
+ b = QJsonDocument.fromJson(b'{"test": [null]}')
+ self.assertIsInstance(b, QJsonDocument)
+ if py3k.IS_PY3K:
+ self.assertEqual(str(b.toVariant()), "{'test': [None]}")
+ else:
+ self.assertEqual(str(b.toVariant()), "{u'test': [None]}")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside2/tests/QtCore/qmodelindex_internalpointer_test.py b/sources/pyside2/tests/QtCore/qmodelindex_internalpointer_test.py
index 875d2075c..a67bb380a 100644
--- a/sources/pyside2/tests/QtCore/qmodelindex_internalpointer_test.py
+++ b/sources/pyside2/tests/QtCore/qmodelindex_internalpointer_test.py
@@ -33,6 +33,7 @@
import sys
import unittest
from PySide2.QtCore import *
+from PySide2.support import VoidPtr
class MyModel (QAbstractListModel):
pass
@@ -50,22 +51,22 @@ class TestQModelIndexInternalPointer(unittest.TestCase):
def testInternalPointer(self):
#Test QAbstractListModel.createIndex and
- #QModelIndex.internalPointer with regular
- #Python objects
- idx = self.model.createIndex(0, 0, "Hello")
- self.assertEqual("Hello", idx.internalPointer())
- a = [1, 2, 3]
- idx = self.model.createIndex(0, 0, a)
- self.assertEqual(a, idx.internalPointer())
+ #QModelIndex.internalPointer
+ obj = QObject()
+ obj_ptr = VoidPtr(obj)
+ idx = self.model.createIndex(0, 0, obj)
+ i = idx.internalPointer()
+ self.assertEqual(int(obj_ptr), int(i))
def testReferenceCounting(self):
#Test reference counting when retrieving data with
#QModelIndex.internalPointer
- a = [1, 2, 3]
- a_refcnt = sys.getrefcount(a)
- idx = self.model.createIndex(0, 0, a)
+ o = QObject()
+ o_refcnt = sys.getrefcount(o)
+ idx = self.model.createIndex(0, 0, o)
ptr = idx.internalPointer()
- self.assertEqual(sys.getrefcount(a), a_refcnt + 1)
+ self.assertEqual(sys.getrefcount(o), o_refcnt)
+
def testIndexForDefaultDataArg(self):
#Test QAbstractListModel.createIndex with a default
diff --git a/sources/pyside2/tests/registry/init_platform.py b/sources/pyside2/tests/registry/init_platform.py
index 22875a63e..66ec6f566 100644
--- a/sources/pyside2/tests/registry/init_platform.py
+++ b/sources/pyside2/tests/registry/init_platform.py
@@ -143,7 +143,10 @@ class Formatter(object):
@contextmanager
def function(self, func_name, signature):
- key = viskey = "{}.{}".format(self.class_name, func_name)
+ if self.class_name is None:
+ key = viskey = "{}".format(func_name)
+ else:
+ key = viskey = "{}.{}".format(self.class_name, func_name)
if key.endswith("lY"):
# Some classes like PySide2.QtGui.QContextMenuEvent have functions
# globalX and the same with Y. The gerrit robot thinks that this
@@ -176,8 +179,9 @@ def generate_all():
This file contains the simplified signatures for all functions in PySide
for module '{}'. There are no default values, no variable
names and no self parameter. Only types are present after simplification.
- The functions 'next' resp. '__next__' are removed
- to make the output identical for Python 2 and 3.
+ The functions 'next' resp. '__next__' are removed to make the output
+ identical for Python 2 and 3. '__div__' is also removed,
+ since it exists in Python 2, only.
"""
'''.format(module)))
fmt.print("import sys")
diff --git a/sources/shiboken2/doc/conf.py.in b/sources/shiboken2/doc/conf.py.in
index 57c2f94b9..29517309d 100644
--- a/sources/shiboken2/doc/conf.py.in
+++ b/sources/shiboken2/doc/conf.py.in
@@ -159,4 +159,4 @@ html_show_sourcelink = False
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
-intersphinx_mapping = {'apiextractor': ('@CMAKE_BINARY_DIR@/ApiExtractor/doc/html','@CMAKE_BINARY_DIR@/ApiExtractor/doc/html/objects.inv')}
+intersphinx_mapping = {'apiextractor': ('ApiExtractor','@CMAKE_BINARY_DIR@/ApiExtractor/doc/html/objects.inv')}
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 8b37b44e0..ec227bd83 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -124,8 +124,13 @@ QString DefaultValue::constructorParameter() const
return QLatin1String("#error");
case DefaultValue::Boolean:
return QLatin1String("false");
- case DefaultValue::CppScalar:
- return m_value + QLatin1String("(0)");
+ case DefaultValue::CppScalar: {
+ // PYSIDE-846: Use static_cast in case of "unsigned long" and similar
+ const QString cast = m_value.contains(QLatin1Char(' '))
+ ? QLatin1String("static_cast<") + m_value + QLatin1Char('>')
+ : m_value;
+ return cast + QLatin1String("(0)");
+ }
case DefaultValue::Custom:
case DefaultValue::Enum:
return m_value;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 99947d347..393f8a850 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -5415,10 +5415,10 @@ bool CppGenerator::finishGeneration()
s << "#include <sbkpython.h>" << endl;
s << "#include <shiboken.h>" << endl;
s << "#include <algorithm>" << endl;
+ s << "#include <signature.h>" << endl;
if (usePySideExtensions()) {
s << includeQDebug;
s << "#include <pyside.h>" << endl;
- s << "#include <signature.h>" << endl;
s << "#include <qapp_macro.h>" << endl;
}
@@ -5714,22 +5714,25 @@ bool CppGenerator::finishGeneration()
// cleanup staticMetaObject attribute
s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);" << endl << endl;
+ }
- // PYSIDE-510: Create a signatures string for the introspection feature.
- s << "// The signatures string for the global functions." << endl;
- s << "// Multiple signatures have their index \"n:\" in front." << endl;
- s << "const char " << moduleName() << "_SignaturesString[] = \"\"" << endl;
- QString line;
- while (signatureStream.readLineInto(&line))
- s << INDENT << '"' << line << "\\n\"" << endl;
- s << ';' << endl;
- // finish the rest of __signature__ initialization.
- s << INDENT << "FinishSignatureInitialization(module, " << moduleName()
- << "_SignaturesString);" << endl;
+ // PYSIDE-510: Create a signatures string for the introspection feature.
+ s << "// The signatures string for the global functions." << endl;
+ s << "// Multiple signatures have their index \"n:\" in front." << endl;
+ s << "const char " << moduleName() << "_SignaturesString[] = \"\"" << endl;
+ QString line;
+ while (signatureStream.readLineInto(&line))
+ s << INDENT << '"' << line << "\\n\"" << endl;
+ s << ';' << endl;
+ // finish the rest of __signature__ initialization.
+ s << INDENT << "FinishSignatureInitialization(module, " << moduleName()
+ << "_SignaturesString);" << endl;
+
+ if (usePySideExtensions()) {
// initialize the qApp module.
- s << INDENT << "NotifyModuleForQApp(module);" << endl << endl;
+ s << INDENT << "NotifyModuleForQApp(module);" << endl;
}
-
+ s << endl;
s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
return file.done() != FileOut::Failure;
diff --git a/sources/shiboken2/libshiboken/qt_attribution.json b/sources/shiboken2/libshiboken/qt_attribution.json
index 12a0952df..071870780 100644
--- a/sources/shiboken2/libshiboken/qt_attribution.json
+++ b/sources/shiboken2/libshiboken/qt_attribution.json
@@ -7,6 +7,6 @@
"Homepage": "http://www.python.org/",
"Version": "3.7.0",
"License": "PSF LICENSE AGREEMENT FOR PYTHON 3.7.0",
- "LicenseFile": "bufferprocs27.h",
+ "LicenseFile": "bufferprocs_py37.h",
"Copyright": "© Copyright 2001-2018, Python Software Foundation."
}
diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp
index 65844151f..4f6ebf65f 100644
--- a/sources/shiboken2/libshiboken/sbkconverter.cpp
+++ b/sources/shiboken2/libshiboken/sbkconverter.cpp
@@ -78,7 +78,8 @@ void init()
Primitive<unsigned int>::createConverter(),
Primitive<unsigned long>::createConverter(),
Primitive<unsigned short>::createConverter(),
- VoidPtr::createConverter()
+ VoidPtr::createConverter(),
+ Primitive<std::nullptr_t>::createConverter()
};
PrimitiveTypeConverters = primitiveTypeConverters;
@@ -100,6 +101,7 @@ void init()
converters["unsigned long"] = primitiveTypeConverters[SBK_UNSIGNEDLONG_IDX];
converters["unsigned short"] = primitiveTypeConverters[SBK_UNSIGNEDSHORT_IDX];
converters["void*"] = primitiveTypeConverters[SBK_VOIDPTR_IDX];
+ converters["std::nullptr_t"] = primitiveTypeConverters[SBK_NULLPTR_T_IDX];
initArrayConverters();
}
diff --git a/sources/shiboken2/libshiboken/sbkconverter.h b/sources/shiboken2/libshiboken/sbkconverter.h
index 0effebf57..33c33025b 100644
--- a/sources/shiboken2/libshiboken/sbkconverter.h
+++ b/sources/shiboken2/libshiboken/sbkconverter.h
@@ -341,6 +341,7 @@ LIBSHIBOKEN_API bool pythonTypeIsWrapperType(const SbkConverter *converter);
#define SBK_UNSIGNEDLONG_IDX 14
#define SBK_UNSIGNEDSHORT_IDX 15
#define SBK_VOIDPTR_IDX 16
+#define SBK_NULLPTR_T_IDX 17
template<typename T> SbkConverter* PrimitiveTypeConverter() { return 0; }
template<> inline SbkConverter* PrimitiveTypeConverter<PY_LONG_LONG>() { return primitiveTypeConverter(SBK_PY_LONG_LONG_IDX); }
@@ -360,6 +361,7 @@ template<> inline SbkConverter* PrimitiveTypeConverter<unsigned int>() { return
template<> inline SbkConverter* PrimitiveTypeConverter<unsigned long>() { return primitiveTypeConverter(SBK_UNSIGNEDLONG_IDX); }
template<> inline SbkConverter* PrimitiveTypeConverter<unsigned short>() { return primitiveTypeConverter(SBK_UNSIGNEDSHORT_IDX); }
template<> inline SbkConverter* PrimitiveTypeConverter<void*>() { return primitiveTypeConverter(SBK_VOIDPTR_IDX); }
+template<> inline SbkConverter* PrimitiveTypeConverter<std::nullptr_t>() { return primitiveTypeConverter(SBK_NULLPTR_T_IDX); }
} // namespace Shiboken::Conversions
@@ -386,6 +388,7 @@ template<> inline PyTypeObject* SbkType<unsigned char>() { return &PyInt_Type; }
template<> inline PyTypeObject* SbkType<unsigned int>() { return &PyLong_Type; }
template<> inline PyTypeObject* SbkType<unsigned long>() { return &PyLong_Type; }
template<> inline PyTypeObject* SbkType<unsigned short>() { return &PyInt_Type; }
+template<> inline PyTypeObject* SbkType<std::nullptr_t>() { return Py_TYPE(&_Py_NoneStruct); }
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/sbkconverter_p.h b/sources/shiboken2/libshiboken/sbkconverter_p.h
index a4edfe81e..cb968ed89 100644
--- a/sources/shiboken2/libshiboken/sbkconverter_p.h
+++ b/sources/shiboken2/libshiboken/sbkconverter_p.h
@@ -533,6 +533,36 @@ struct Primitive<std::string> : TwoPrimitive<std::string>
}
};
+// nullptr_t
+template <>
+struct Primitive<std::nullptr_t> : TwoPrimitive<std::nullptr_t>
+{
+ static PyObject* toPython(const void* cppIn)
+ {
+ return Py_None;
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ *reinterpret_cast<std::nullptr_t*>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isConvertible(PyObject* pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject* pyIn, void* cppOut)
+ {
+ *reinterpret_cast<std::nullptr_t*>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject* pyIn)
+ {
+ if (pyIn == nullptr)
+ return otherToCpp;
+ return nullptr;
+ }
+};
+
namespace Shiboken {
namespace Conversions {
SbkConverter *createConverterObject(PyTypeObject *type,
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index 24d60acc4..962e50d46 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "basewrapper.h"
+#include "autodecref.h"
extern "C"
{
@@ -77,7 +78,9 @@ typedef struct safe_globals_struc {
static safe_globals pyside_globals = 0;
-static PyObject *GetSignature_Function(PyCFunctionObject *, const char *);
+static PyObject *GetClassKey(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 *get_signature(PyObject *self, PyObject *args);
@@ -108,24 +111,85 @@ CreateSignature(PyObject *props, PyObject *key)
static PyObject *
pyside_cf_get___signature__(PyObject *func, const char *modifier)
{
- return GetSignature_Function((PyCFunctionObject *)func, modifier);
+ return GetSignature_Function(func, modifier);
}
static PyObject *
pyside_sm_get___signature__(PyObject *sm, const char *modifier)
{
- PyObject *func, *ret;
+ Shiboken::AutoDecRef func(PyObject_GetAttrString(sm, "__func__"));
+ return GetSignature_Function(func, modifier);
+}
- func = PyObject_GetAttrString(sm, "__func__");
- ret = GetSignature_Function((PyCFunctionObject *)func, modifier);
- Py_XDECREF(func);
- return ret;
+static PyObject *
+_get_class_of_cf(PyObject *ob_cf)
+{
+ PyObject *selftype = PyCFunction_GET_SELF(ob_cf);
+ if (selftype == NULL)
+ selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)ob_cf);
+ if (selftype == NULL) {
+ if (!PyErr_Occurred())
+ Py_RETURN_NONE;
+ return NULL;
+ }
+ PyObject *typemod = (PyType_Check(selftype) || PyModule_Check(selftype))
+ ? selftype : (PyObject *)Py_TYPE(selftype);
+ // do we support module functions?
+ Py_INCREF(typemod);
+ return typemod;
+}
+
+static PyObject *
+_get_class_of_sm(PyObject *ob_sm)
+{
+ Shiboken::AutoDecRef func(PyObject_GetAttrString(ob_sm, "__func__"));
+ return _get_class_of_cf(func);
}
-#ifdef Py_LIMITED_API
+static PyObject *
+_get_class_of_descr(PyObject *ob)
+{
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__"));
+ return PyObject_GetAttrString(ob, "__objclass__");
+}
+
+static PyObject *
+GetClassOfFunc(PyObject *ob)
+{
+ if (PyType_Check(ob))
+ return ob;
+ if (Py_TYPE(ob) == &PyCFunction_Type)
+ return _get_class_of_cf(ob);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return _get_class_of_sm(ob);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return _get_class_of_descr(ob);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return _get_class_of_descr(ob);
+ Py_FatalError("unexpected type in GetClassOfFunc");
+ return nullptr;
+}
+
+static PyObject *
+compute_name_key(PyObject *ob)
+{
+ if (PyType_Check(ob))
+ return GetClassKey(GetClassOfFunc(ob));
+ PyObject *func = ob;
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ func = PyObject_GetAttrString(ob, "__func__");
+ else
+ Py_INCREF(func);
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(func, "__name__"));
+ Py_DECREF(func);
+ if (func_name.isNull())
+ Py_FatalError("unexpected name problem in compute_name_key");
+ Shiboken::AutoDecRef type_key(GetClassKey(GetClassOfFunc(ob)));
+ return Py_BuildValue("(OO)", type_key.object(), func_name.object());
+}
static int
-build_qualname_to_func(PyObject *obtype)
+build_name_key_to_func(PyObject *obtype)
{
PyTypeObject *type = (PyTypeObject *)obtype;
PyMethodDef *meth = type->tp_methods;
@@ -134,98 +198,53 @@ build_qualname_to_func(PyObject *obtype)
return 0;
for (; meth->ml_name != NULL; meth++) {
- PyObject *func = PyCFunction_NewEx(meth, obtype, NULL);
- PyObject *qualname = PyObject_GetAttrString(func, "__qualname__");
- if (func == NULL || qualname == NULL) {
+ Shiboken::AutoDecRef func(PyCFunction_NewEx(meth, obtype, NULL));
+ Shiboken::AutoDecRef name_key(compute_name_key(func));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
return -1;
- }
- if (PyDict_SetItem(pyside_globals->map_dict, qualname, func) < 0) {
- return -1;
- }
- Py_DECREF(func);
- Py_DECREF(qualname);
}
return 0;
}
static PyObject *
-qualname_to_typename(PyObject *qualname)
-{
- PyObject *func = PyObject_GetAttrString(qualname, "split");
- PyObject *list = func ? PyObject_CallFunction(func, (char *)"(s)", ".")
- : NULL;
- PyObject *res = list ? PyList_GetItem(list, 0) : NULL;
- Py_XINCREF(res);
- Py_XDECREF(func);
- Py_XDECREF(list);
- return res;
-}
-
-static PyObject *
-qualname_to_func(PyObject *ob)
+name_key_to_func(PyObject *ob)
{
/*
- * If we have __qualname__, then we can easily build a mapping
- * from __qualname__ to PyCFunction. This is necessary when
- * the limited API does not let us go easily from descriptor
- * to PyMethodDef.
+ * We build a mapping from name_key to function.
+ * This could also be computed directly, but the Limited API
+ * makes this impossible. So we always build our own mapping.
*/
- PyObject *ret;
- PyObject *qualname = PyObject_GetAttrString((PyObject *)ob,
- "__qualname__");
- if (qualname != NULL) {
- ret = PyDict_GetItem(pyside_globals->map_dict, qualname);
- if (ret == NULL) {
- // do a lazy initialization
- PyObject *type_name = qualname_to_typename(qualname);
- PyObject *type = PyDict_GetItem(pyside_globals->map_dict,
- type_name);
- Py_XDECREF(type_name);
- if (type == NULL)
- Py_RETURN_NONE;
- if (build_qualname_to_func(type) < 0)
- return NULL;
- ret = PyDict_GetItem(pyside_globals->map_dict, qualname);
- }
- Py_XINCREF(ret);
- Py_DECREF(qualname);
- }
- else
+ Shiboken::AutoDecRef name_key(compute_name_key(ob));
+ if (name_key.isNull())
Py_RETURN_NONE;
+
+ PyObject *ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ if (ret == NULL) {
+ // do a lazy initialization
+ Shiboken::AutoDecRef type_key(GetClassKey(GetClassOfFunc(ob)));
+ PyObject *type = PyDict_GetItem(pyside_globals->map_dict,
+ type_key);
+ if (type == nullptr)
+ Py_RETURN_NONE;
+ assert(PyType_Check(type));
+ if (build_name_key_to_func(type) < 0)
+ return NULL;
+ ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ }
+ Py_XINCREF(ret);
return ret;
}
-#endif
static PyObject *
-pyside_md_get___signature__(PyObject *ob, const char *modifier)
-{
- PyObject *func;
- PyObject *result;
-#ifndef Py_LIMITED_API
- PyMethodDescrObject *descr = (PyMethodDescrObject *)ob;
-
-# if PYTHON_USES_D_COMMON
- func = PyCFunction_NewEx(descr->d_method,
- (PyObject *)descr->d_common.d_type, NULL);
-# else
- func = PyCFunction_NewEx(descr->d_method,
- (PyObject *)descr->d_type, NULL);
-# endif
-#else
- /*
- * With limited access, we cannot use the fields of a method descriptor,
- * but in Python 3 we have the __qualname__ field which allows us to
- * grab the method object from our registry.
- */
- func = qualname_to_func(ob);
-#endif
- if (func == Py_None)
+pyside_md_get___signature__(PyObject *ob_md, const char *modifier)
+{
+ Shiboken::AutoDecRef func(name_key_to_func(ob_md));
+ if (func.object() == Py_None)
return Py_None;
- if (func == NULL)
+ if (func.isNull())
Py_FatalError("missing mapping in MethodDescriptor");
- result = pyside_cf_get___signature__(func, modifier);
- Py_DECREF(func);
- return result;
+ return pyside_cf_get___signature__(func, modifier);
}
static PyObject *
@@ -245,30 +264,44 @@ static PyObject *
GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier);
static PyObject *
-GetSignature_Function(PyCFunctionObject *func, const char *modifier)
+GetClassKey(PyObject *ob)
{
- PyObject *typemod, *type_name, *dict, *props, *selftype;
- PyObject *func_name = PyObject_GetAttrString((PyObject *)func, "__name__");
- const char *sig_kind;
- int flags;
+ assert(PyType_Check(ob) || PyModule_Check(ob));
+ /*
+ * We obtain a unique key using the module name and the class name.
+ *
+ * The class name is a bit funny when modules are nested.
+ * Example:
+ *
+ * "sample.Photon.ValueIdentity" is a class.
+ * name: "ValueIdentity"
+ * module: "sample.Photon"
+ *
+ * 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__"));
- selftype = PyCFunction_GET_SELF((PyObject *)func);
- if (selftype == NULL)
- selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func);
- if (selftype == NULL) {
- if (!PyErr_Occurred())
- Py_RETURN_NONE;
- return NULL;
- }
- if ((PyType_Check(selftype) || PyModule_Check(selftype)))
- typemod = selftype;
- else
- typemod = (PyObject *)Py_TYPE(selftype);
- type_name = PyObject_GetAttrString(typemod, "__name__");
- if (type_name == NULL)
+ if (module_name.isNull())
+ PyErr_Clear();
+
+ // Note: if we have a module, then __module__ is null, and we get
+ // the module name through __name__ .
+ if (class_name.isNull())
+ return nullptr;
+ if (module_name.object())
+ return Py_BuildValue("(OO)", module_name.object(), class_name.object());
+ return Py_BuildValue("O", class_name.object());
+}
+
+static PyObject *
+GetSignature_Function(PyObject *ob_func, const char *modifier)
+{
+ Shiboken::AutoDecRef typemod(GetClassOfFunc(ob_func));
+ Shiboken::AutoDecRef type_key(GetClassKey(typemod));
+ if (type_key.isNull())
Py_RETURN_NONE;
- dict = PyDict_GetItem(pyside_globals->arg_dict, type_name);
- Py_DECREF(type_name);
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key);
if (dict == NULL)
Py_RETURN_NONE;
if (PyTuple_Check(dict)) {
@@ -280,31 +313,35 @@ GetSignature_Function(PyCFunctionObject *func, const char *modifier)
if (dict == NULL)
Py_RETURN_NONE;
}
- props = PyDict_GetItem(dict, func_name);
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob_func, "__name__"));
+ PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
if (props == NULL)
Py_RETURN_NONE;
- flags = PyCFunction_GET_FLAGS((PyObject *)func);
- if (flags & METH_CLASS)
+
+ int flags = PyCFunction_GET_FLAGS(ob_func);
+ const char *sig_kind;
+ if (PyModule_Check(typemod))
+ sig_kind = "function";
+ else if (flags & METH_CLASS)
sig_kind = "classmethod";
else if (flags & METH_STATIC)
sig_kind = "staticmethod";
else
sig_kind = "method";
- return GetSignature_Cached(props, sig_kind, modifier);
+ PyObject *ret = GetSignature_Cached(props, sig_kind, modifier);
+ return ret;
}
static PyObject *
GetSignature_Wrapper(PyObject *ob, const char *modifier)
{
- PyObject *dict, *props;
- PyObject *func_name = PyObject_GetAttrString(ob, "__name__");
- PyObject *objclass = PyObject_GetAttrString(ob, "__objclass__");
- PyObject *class_name = PyObject_GetAttrString(objclass, "__name__");
- const char *sig_kind;
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__"));
+ Shiboken::AutoDecRef objclass(PyObject_GetAttrString(ob, "__objclass__"));
+ Shiboken::AutoDecRef class_key(GetClassKey(objclass));
- if (func_name == nullptr || objclass == nullptr || class_name == nullptr)
+ if (func_name.isNull() || objclass.isNull() || class_key.isNull())
return nullptr;
- dict = PyDict_GetItem(pyside_globals->arg_dict, class_name);
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, class_key);
if (dict == NULL)
Py_RETURN_NONE;
if (PyTuple_Check(dict)) {
@@ -316,65 +353,51 @@ GetSignature_Wrapper(PyObject *ob, const char *modifier)
if (dict == NULL)
Py_RETURN_NONE;
}
- props = PyDict_GetItem(dict, func_name);
- Py_DECREF(func_name);
- Py_DECREF(objclass);
- Py_DECREF(class_name);
+ PyObject *props = PyDict_GetItem(dict, func_name);
if (props == NULL)
Py_RETURN_NONE;
- sig_kind = "method";
- return GetSignature_Cached(props, sig_kind, modifier);
+ return GetSignature_Cached(props, "method", modifier);
}
static PyObject *
GetSignature_TypeMod(PyObject *ob, const char *modifier)
{
- PyObject *ob_name, *dict, *props;
- const char *sig_kind;
+ Shiboken::AutoDecRef ob_name(PyObject_GetAttrString(ob, "__name__"));
+ Shiboken::AutoDecRef ob_key(GetClassKey(ob));
- ob_name = PyObject_GetAttrString(ob, "__name__");
- dict = PyDict_GetItem(pyside_globals->arg_dict, ob_name);
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, ob_key);
if (dict == NULL)
Py_RETURN_NONE;
+
if (PyTuple_Check(dict)) {
dict = PySide_BuildSignatureProps(ob);
if (dict == NULL) {
Py_RETURN_NONE;
}
}
- props = PyDict_GetItem(dict, ob_name);
- Py_DECREF(ob_name);
+ PyObject *props = PyDict_GetItem(dict, ob_name);
if (props == NULL)
Py_RETURN_NONE;
- sig_kind = "method";
- return GetSignature_Cached(props, sig_kind, modifier);
+ return GetSignature_Cached(props, "method", modifier);
}
static PyObject *
GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier)
{
- PyObject *key, *value;
-
- if (modifier == nullptr)
- key = Py_BuildValue("s", sig_kind);
- else
- key = Py_BuildValue("(ss)", sig_kind, modifier);
- if (key == nullptr)
- return nullptr;
- value = PyDict_GetItem(props, key);
+ Shiboken::AutoDecRef key(modifier == nullptr
+ ? Py_BuildValue("s", sig_kind)
+ : Py_BuildValue("(ss)", sig_kind, modifier));
+ PyObject *value = PyDict_GetItem(props, key);
if (value == nullptr) {
// we need to compute a signature object
value = CreateSignature(props, key);
if (value != nullptr) {
- if (PyDict_SetItem(props, key, value) < 0) {
+ if (PyDict_SetItem(props, key, value) < 0)
// this is an error
- Py_DECREF(key);
return nullptr;
- }
}
else {
// key not found
- Py_DECREF(key);
Py_RETURN_NONE;
}
}
@@ -385,15 +408,14 @@ static const char PySide_PythonCode[] =
"from __future__ import print_function, absolute_import\n" R"~(if True:
import sys, os, traceback
-
- pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR')
- if pyside_package_dir is None:
- # This happens in shiboken running ctest.
- from distutils.sysconfig import get_python_lib
- pyside_package_dir = os.path.join(get_python_lib(), 'PySide2')
- __file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')
+ # We avoid imports in phase 1 that could fail. "import shiboken" of the
+ # binary would even crash in FinishSignatureInitialization.
def bootstrap():
+ global __file__
+ import PySide2 as root
+ rp = os.path.realpath(os.path.dirname(root.__file__))
+ __file__ = os.path.join(rp, 'support', 'signature', 'loader.py')
try:
with open(__file__) as _f:
exec(compile(_f.read(), __file__, 'exec'))
@@ -407,10 +429,9 @@ static const char PySide_PythonCode[] =
static safe_globals_struc *
init_phase_1(void)
{
- safe_globals_struc *p;
PyObject *d, *v;
-
- p = (safe_globals_struc *)malloc(sizeof(safe_globals_struc));
+ safe_globals_struc *p = (safe_globals_struc *)
+ malloc(sizeof(safe_globals_struc));
if (p == NULL)
goto error;
p->helper_module = PyImport_AddModule((char *) helper_module_name);
@@ -431,11 +452,10 @@ init_phase_1(void)
if (p->map_dict == NULL)
goto error;
- // Build a dict for the prepared arguments
+ // build a dict for the prepared arguments
p->arg_dict = PyDict_New();
- if (p->arg_dict == NULL)
- goto error;
- if (PyObject_SetAttrString(p->helper_module, arg_name, p->arg_dict) < 0)
+ if (p->arg_dict == NULL
+ || PyObject_SetAttrString(p->helper_module, arg_name, p->arg_dict) < 0)
goto error;
return p;
@@ -450,30 +470,25 @@ init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
PyObject *bootstrap_func, *v = nullptr;
PyMethodDef *ml;
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != NULL; ml++) {
+ v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr
+ || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0)
+ goto error;
+ Py_DECREF(v);
+ }
bootstrap_func = PyObject_GetAttrString(p->helper_module, bootstrap_name);
- if (bootstrap_func == NULL)
+ if (bootstrap_func == NULL
+ || PyObject_CallFunction(bootstrap_func, (char *)"()") == NULL)
goto error;
- if (PyObject_CallFunction(bootstrap_func, (char *)"()") == NULL)
- goto error;
- // now the loader is initialized
+ // now the loader should be initialized
p->sigparse_func = PyObject_GetAttrString(p->helper_module, func_name);
if (p->sigparse_func == NULL)
goto error;
p->createsig_func = PyObject_GetAttrString(p->helper_module, "create_signature");
if (p->createsig_func == NULL)
goto error;
-
- // The single function to be called, but maybe more to come.
- for (ml = methods; ml->ml_name != NULL; ml++) {
- v = PyCFunction_NewEx(ml, nullptr, nullptr);
- if (v == nullptr) {
- goto error;
- }
- if (PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0) {
- goto error;
- }
- Py_DECREF(v);
- }
return 0;
error:
@@ -485,23 +500,17 @@ error:
static int
add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp)
{
- PyObject *dict;
-
assert(PyType_Check(type));
PyType_Ready(type);
- dict = type->tp_dict;
+ PyObject *dict = type->tp_dict;
for (; gsp->name != NULL; gsp++) {
- PyObject *descr;
if (PyDict_GetItemString(dict, gsp->name))
continue;
- descr = PyDescr_NewGetSet(type, gsp);
- if (descr == NULL)
+ Shiboken::AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
+ if (descr.isNull())
return -1;
- if (PyDict_SetItemString(dict, gsp->name, descr) < 0) {
- Py_DECREF(descr);
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
return -1;
- }
- Py_DECREF(descr);
}
return 0;
}
@@ -611,13 +620,12 @@ void handler(int sig) {
static int
PySideType_Ready(PyTypeObject *type)
{
- PyObject *md, *wd;
static int init_done = 0;
if (!init_done) {
- md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); // method-descriptor
- wd = PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__"); // wrapper-descriptor
- if (md == nullptr || wd == nullptr
+ Shiboken::AutoDecRef md(PyObject_GetAttrString((PyObject *)&PyString_Type, "split")); // method-descriptor
+ Shiboken::AutoDecRef wd(PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__")); // wrapper-descriptor
+ if (md.isNull() || wd.isNull()
|| PyType_Ready(Py_TYPE(md)) < 0
|| add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets) < 0
|| add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0
@@ -626,8 +634,6 @@ PySideType_Ready(PyTypeObject *type)
|| add_more_getsets(Py_TYPE(wd), new_PyWrapperDescr_getsets) < 0
)
return -1;
- Py_DECREF(md);
- Py_DECREF(wd);
#ifndef _WIN32
// We enable the stack trace in CI, only.
const char *testEnv = getenv("QTEST_ENVIRONMENT");
@@ -639,31 +645,6 @@ PySideType_Ready(PyTypeObject *type)
return PyType_Ready(type);
}
-static int
-build_func_to_type(PyObject *obtype)
-{
- PyTypeObject *type = (PyTypeObject *)obtype;
- PyObject *dict = type->tp_dict;
- PyMethodDef *meth = type->tp_methods;
-
- if (meth == 0)
- return 0;
-
- for (; meth->ml_name != NULL; meth++) {
- if (meth->ml_flags & METH_STATIC) {
- PyObject *descr = PyDict_GetItemString(dict, meth->ml_name);
- if (descr == NULL)
- return -1;
- PyObject *func = PyObject_GetAttrString(descr, "__func__");
- if (func == NULL ||
- PyDict_SetItem(pyside_globals->map_dict, func, obtype) < 0)
- return -1;
- Py_DECREF(func);
- }
- }
- return 0;
-}
-
static void
init_module_1(void)
{
@@ -680,20 +661,26 @@ static int
PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
const char *signatures)
{
- PyObject *type_name, *arg_tup;
- const char *name = NULL;
+ PyObject *type_key, *arg_tup;
- init_module_1();;
+ init_module_1();
arg_tup = Py_BuildValue("(Os)", type, signatures);
if (arg_tup == NULL)
return -1;
- if (!PyModule_Check(module))
- return 0;
- name = PyModule_GetName(module);
- if (name == NULL)
- return -1;
- if (strncmp(name, "PySide2.Qt", 10) != 0)
- return 0;
+ /*
+ * We either get a module name or the dict of an EnclosingObject.
+ * We can ignore the EnclosingObject since we get full name info
+ * from the type.
+ */
+ if (PyModule_Check(module)) {
+ const char *name = PyModule_GetName(module);
+ if (name == NULL)
+ return -1;
+ if (strcmp(name, "testbinding") == 0)
+ return 0;
+ }
+ else
+ assert(PyDict_Check(module));
/*
* Normally, we would now just call the Python function with the
* arguments and then continue processing.
@@ -705,16 +692,17 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
* - by calling the python function late, we can freely import PySide
* without recursion problems.
*/
- type_name = PyObject_GetAttrString(type, "__name__");
- if (type_name == NULL)
+ type_key = GetClassKey(type);
+ if (type_key == nullptr)
return -1;
- if (PyDict_SetItem(pyside_globals->arg_dict, type_name, arg_tup) < 0)
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_key, arg_tup) < 0)
return -1;
/*
- * We record also a mapping from type name to type. This helps to lazily
- * initialize the Py_LIMITED_API in qualname_to_func().
+ * We record also a mapping from type key to type. This helps to lazily
+ * initialize the Py_LIMITED_API in name_key_to_func().
*/
- if (PyDict_SetItem(pyside_globals->map_dict, type_name, type) < 0)
+
+ if (PyDict_SetItem(pyside_globals->map_dict, type_key, type) < 0)
return -1;
return 0;
}
@@ -728,18 +716,20 @@ static PyMethodDef signature_methods[] = {
static void
init_module_2(void)
{
- static int init_done = 0;
+ static int init_done = 0, initializing = 0;
if (!init_done) {
+ if (initializing)
+ Py_FatalError("Init 2 called recursively!");
init_phase_2(pyside_globals, signature_methods);
init_done = 1;
+ initializing = 0;
}
}
static PyObject *
PySide_BuildSignatureProps(PyObject *classmod)
{
- PyObject *arg_tup, *dict, *type_name;
/*
* Here is the second part of the function.
* This part will be called on-demand when needed by some attribute.
@@ -747,20 +737,19 @@ PySide_BuildSignatureProps(PyObject *classmod)
* them by the function result.
*/
init_module_2();
- type_name = PyObject_GetAttrString(classmod, "__name__");
- if (type_name == NULL)
- return NULL;
- arg_tup = PyDict_GetItem(pyside_globals->arg_dict, type_name);
- if (arg_tup == NULL)
- return NULL;
- dict = PyObject_CallObject(pyside_globals->sigparse_func, arg_tup);
- if (dict == NULL)
- return NULL;
+ Shiboken::AutoDecRef type_key(GetClassKey(classmod));
+ if (type_key.isNull())
+ return nullptr;
+ PyObject *arg_tup = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ if (arg_tup == nullptr)
+ return nullptr;
+ PyObject *dict = PyObject_CallObject(pyside_globals->sigparse_func, arg_tup);
+ if (dict == nullptr)
+ return nullptr;
// We replace the arguments by the result dict.
- if (PyDict_SetItem(pyside_globals->arg_dict, type_name, dict) < 0)
- return NULL;
- Py_DECREF(type_name);
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_key, dict) < 0)
+ return nullptr;
return dict;
}
@@ -779,17 +768,22 @@ SbkSpecial_Type_Ready(PyObject *module, PyTypeObject *type,
return ret;
}
+static int _finish_nested_classes(PyObject *dict);
+static int _build_func_to_type(PyObject *obtype);
+
static int
PySide_FinishSignatures(PyObject *module, const char *signatures)
{
- const char *name = NULL;
+ /*
+ * Initialization of module functions and resolving of static methods.
+ */
// CRUCIAL: Do not call this on "testbinding":
// The module is different and should not get signatures, anyway.
- name = PyModule_GetName(module);
+ const char *name = PyModule_GetName(module);
if (name == NULL)
return -1;
- if (strncmp(name, "PySide2.Qt", 10) != 0)
+ if (strcmp(name, "testbinding") == 0)
return 0;
// we abuse the call for types, since they both have a __name__ attribute.
@@ -797,9 +791,6 @@ PySide_FinishSignatures(PyObject *module, const char *signatures)
return -1;
/*
- * Python2 does not abuse the 'm_self' field for the type. So we need to
- * supply this for all static methods.
- *
* Note: This function crashed when called from PySide_BuildSignatureArgs.
* Probably this was too early.
*
@@ -807,20 +798,72 @@ PySide_FinishSignatures(PyObject *module, const char *signatures)
* to the PyCFunction attributes. Therefore I simplified things
* and always use our own mapping.
*/
- {
- PyObject *key, *value;
- Py_ssize_t pos = 0;
- PyObject *dict = PyModule_GetDict(module);
+ PyObject *key, *func, *obdict = PyModule_GetDict(module);
+ Py_ssize_t pos = 0;
- if (dict == NULL)
- return -1;
+ while (PyDict_Next(obdict, &pos, &key, &func))
+ if (PyCFunction_Check(func))
+ if (PyDict_SetItem(pyside_globals->map_dict, func, module) < 0)
+ return -1;
+ if (_finish_nested_classes(obdict) < 0)
+ return -1;
+ return 0;
+}
+
+static int
+_finish_nested_classes(PyObject *obdict)
+{
+ PyObject *key, *value, *obtype;
+ PyTypeObject *subtype;
+ Py_ssize_t pos = 0;
- while (PyDict_Next(dict, &pos, &key, &value)) {
- if (PyType_Check(value)) {
- PyObject *type = value;
- if (build_func_to_type(type) < 0)
- return -1;
- }
+ if (obdict == NULL)
+ return -1;
+ while (PyDict_Next(obdict, &pos, &key, &value)) {
+ if (PyType_Check(value)) {
+ obtype = value;
+ if (_build_func_to_type(obtype) < 0)
+ return -1;
+ // now continue with nested cases
+ subtype = reinterpret_cast<PyTypeObject *>(obtype);
+ if (_finish_nested_classes(subtype->tp_dict) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+_build_func_to_type(PyObject *obtype)
+{
+ /*
+ * There is no general way to directly get the type of a static method.
+ * On Python 3, the type is hidden in an unused pointer in the
+ * PyCFunction structure, but the Limited API does not allow to access
+ * this, either.
+ *
+ * In the end, it was easier to avoid such tricks and build an explicit
+ * mapping from function to type.
+ *
+ * We walk through the method list of the type
+ * and record the mapping from function to this type in a dict.
+ */
+ PyTypeObject *type = reinterpret_cast<PyTypeObject *>(obtype);
+ PyObject *dict = type->tp_dict;
+ PyMethodDef *meth = type->tp_methods;
+
+ if (meth == 0)
+ return 0;
+
+ for (; meth->ml_name != NULL; meth++) {
+ if (meth->ml_flags & METH_STATIC) {
+ PyObject *descr = PyDict_GetItemString(dict, meth->ml_name);
+ if (descr == NULL)
+ return -1;
+ Shiboken::AutoDecRef func(PyObject_GetAttrString(descr, "__func__"));
+ if (func.isNull() ||
+ PyDict_SetItem(pyside_globals->map_dict, func, obtype) < 0)
+ return -1;
}
}
return 0;
@@ -829,6 +872,12 @@ PySide_FinishSignatures(PyObject *module, const char *signatures)
void
FinishSignatureInitialization(PyObject *module, const char *signatures)
{
+ /*
+ * This function is called at the very end of a module
+ * initialization. SbkSpecial_Type_Ready has already been run
+ * with all the types.
+ * We now initialize module functions and resolve static methods.
+ */
if (PySide_FinishSignatures(module, signatures) < 0) {
PyErr_Print();
PyErr_SetNone(PyExc_ImportError);