aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/PySide2/support/signature/mapping.py
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2017-05-23 17:10:26 +0200
committerChristian Tismer <tismer@stackless.com>2017-09-20 21:52:50 +0000
commit30a1c9c41e5e6d4166f171b9477c6f46cafa782f (patch)
tree7aaa7b100d3fcc0cb8ad2f583928148b6abfbee5 /sources/pyside2/PySide2/support/signature/mapping.py
parent6678fc1a6353e596965f0daff74afec9d1605c57 (diff)
Implement introspection with __signature__ package
The signature module was turned into a package under 'PySide2/support/signature'. The package is completely isolated so that nothing is leaking into the normal import machinery. The package is also not initialized unless a __signature__ attribute is accessed. The only change to Python during a PySide run is the existence of the __signature__ attribute. As a side effect, all tests run at the same speed as before this extension. The module does not actively import PySide modules. Instead, it inspects sys.modules and reloads its mapping.py if needed. Example usage: >>> PySide2.QtWidgets.QGraphicsAnchorLayout.addAnchors.__signature__ >>> PySide2.QtWidgets.QGraphicsAnchorLayout.__signature__ The module has been thoroughly tested on macOS. I consider this ready. Task-number: PYSIDE-510 Change-Id: Ibb231a7fbb4ccc1a7249df55e3881a4e21a19c0d Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/pyside2/PySide2/support/signature/mapping.py')
-rw-r--r--sources/pyside2/PySide2/support/signature/mapping.py364
1 files changed, 364 insertions, 0 deletions
diff --git a/sources/pyside2/PySide2/support/signature/mapping.py b/sources/pyside2/PySide2/support/signature/mapping.py
new file mode 100644
index 000000000..d18ee561b
--- /dev/null
+++ b/sources/pyside2/PySide2/support/signature/mapping.py
@@ -0,0 +1,364 @@
+#############################################################################
+##
+## Copyright (C) 2017 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of PySide2.
+##
+## $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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+signature_mapping.py
+
+This module has the mapping from the pyside C-modules view of signatures
+to the Python representation.
+
+The PySide modules are not loaded in advance, but only after they appear
+in sys.modules. This minimises the loading overhead.
+In principle, we need to re-load the module, when the imports change.
+But it is much easier to do it on demand, when we get an exception.
+See _resolve_value() in singature.py
+"""
+
+import sys
+import collections
+import struct
+
+PY3 = sys.version_info >= (3,)
+if PY3:
+ from . import typing
+ exec("ellipsis = ...")
+ Char = typing.Union[str, int] # how do I model the limitation to 1 char?
+ StringList = typing.List[str]
+ Variant = typing.Union[str, int, float, Char, StringList, type(ellipsis)]
+ # much more, do we need that?
+ ModelIndexList = typing.List[int]
+ QImageCleanupFunction = typing.Callable[[bytes], None]
+else:
+ ellipsis = "..."
+ Char = str
+ StringList = list
+ Variant = object
+ ModelIndexList = list
+ QImageCleanupFunction = object
+Pair = collections.namedtuple('Pair', ['first', 'second'])
+# ulong_max is the long size, which is only 32 bit on windows.
+ulong_max = sys.maxsize if len(struct.pack("L", 1)) != 4 else 0xffffffff
+ushort_max = 0xffff
+
+GL_COLOR_BUFFER_BIT = 0x00004000
+GL_NEAREST = 0x2600
+
+WId = int
+
+# from 5.9
+GL_TEXTURE_2D = 0x0DE1
+GL_RGBA = 0x1908
+
+# Some types are abstract. They just show their name.
+class Virtual(str):
+ def __repr__(self):
+ return "Virtual({})".format(self)
+
+# Other types I simply could not find.
+class Missing(str):
+ def __repr__(self):
+ return "Missing({})".format(self)
+
+TYPE_MAP_DOC = """
+ The type_map variable is central for the signature module.
+
+ PySide has a new function 'CppGenerator::writeSignatureInfo()'
+ that extracts the gathered information about the function arguments
+ and defaults as good as it can. But what PySide generates is still
+ very C-ish and has many constants that Python doesn't understand.
+
+ The function 'try_to_guess()' below understands a lot of PySide's
+ peculiar way to assume local context. If it is able to do the guess,
+ then the result is inserted into the dict, so the search happens
+ not again. For everything that is not covered by these automatic
+ guesses, we provide an entry in 'type_map' that resolves it.
+
+ In effect, 'type_map' maps text to real Python objects.
+"""
+type_map = {}
+
+loaded_modules = sys.modules
+
+# QtCore
+if "PySide2.QtCore" in loaded_modules:
+ import PySide2.QtCore
+ from PySide2.QtCore import Qt, QUrl, QDir, QGenericArgument
+ from PySide2.QtCore import QMarginsF # 5.9
+ try:
+ # seems to be not generated by 5.9 ATM.
+ from PySide2.QtCore import Connection, QRect, QSize, QPoint
+ except ImportError:
+ pass
+ type_map.update({
+ "str": str,
+ "int": int,
+ "QString": str,
+ "bool": bool,
+ "PyObject": object,
+ "void": int, # be more specific?
+ "char": Char,
+ "'%'": "%",
+ "' '": " ",
+ "false": False,
+ "double": float,
+ "'g'": "g",
+ "long long": int,
+ "unsigned int": int, # should we define an unsigned type?
+ "Q_NULLPTR": None,
+ "long": int,
+ "float": float,
+ "short": int,
+ "unsigned long": int,
+ "unsigned long long": int,
+ "unsigned short": int,
+ "QStringList": StringList,
+ "QList": list,
+ "QChar": Char,
+ "signed char": Char,
+ "QVariant": Variant,
+ "QVariant.Type": type, # not so sure here...
+ "QStringRef": str,
+ "QString()": None, # unclear: "" would be isEmpty(), but not isNull()
+ "QModelIndexList": ModelIndexList,
+ "QPair": Pair,
+ "unsigned char": Char,
+ "QSet": set, # seems _not_ to work
+ "QVector": list,
+ "QJsonObject": dict, # seems to work
+ "QStringList()": [],
+ "ULONG_MAX": ulong_max,
+ "quintptr": int,
+ "PyCallable": callable,
+ "...": ellipsis, # no idea how this should be translated... maybe so?
+ "PyTypeObject": type,
+ "PySequence": list, # could be more generic
+ "qptrdiff": int,
+ "true": True,
+ "Qt.HANDLE": int, # be more explicit with some consts?
+ "list of QAbstractState": list, # how to use typing.List when we don't have QAbstractState?
+ "list of QAbstractAnimation": list, # dto.
+ "QVariant()": (ellipsis,), # no idea what to use here for "invalid Variant"?
+ "QMap": dict,
+ "PySide2.QtCore.bool": bool,
+ "QHash": dict,
+ "PySide2.QtCore.QChar": Char,
+ "PySide2.QtCore.qreal": float,
+ "PySide2.QtCore.float": float,
+ "PySide2.QtCore.qint16": int,
+ "PySide2.QtCore.qint32": int,
+ "PySide2.QtCore.qint64": int,
+ "PySide2.QtCore.qint8": int,
+ "PySide2.QtCore.QString": str,
+ "PySide2.QtCore.QStringList": StringList,
+ "PySide2.QtCore.QVariant": Variant,
+ "PySide2.QtCore.quint16": int,
+ "PySide2.QtCore.quint32": int,
+ "PySide2.QtCore.quint64": int,
+ "PySide2.QtCore.quint8": int,
+ "PySide2.QtCore.uchar": Char,
+ "QGenericArgument(0)": QGenericArgument(None),
+ "PySide2.QtCore.long": int,
+ "PySide2.QtCore.QUrl.ComponentFormattingOptions":
+ PySide2.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why???
+ "QUrl.FormattingOptions(PrettyDecoded)": QUrl.FormattingOptions(QUrl.PrettyDecoded),
+ # from 5.9
+ "QDir.Filters(AllEntries | NoDotAndDotDot)": QDir.Filters(QDir.AllEntries |
+ QDir.NoDotAndDotDot),
+ "QGenericArgument(Q_NULLPTR)": QGenericArgument(None),
+ "NULL": None, # 5.6, MSVC
+ "QGenericArgument(NULL)": QGenericArgument(None), # 5.6, MSVC
+ "QDir.SortFlags(Name | IgnoreCase)": QDir.SortFlags(QDir.Name | QDir.IgnoreCase),
+ "PyBytes": bytes,
+ "PyUnicode": str if PY3 else unicode,
+ "signed long": int,
+ "PySide2.QtCore.int": int,
+ "unsigned long int": int, # 5.6, RHEL 6.6
+ "unsigned short int": int, # 5.6, RHEL 6.6
+ "QGenericArgument((0))": None, # 5.6, RHEL 6.6. Is that ok?
+ "4294967295UL": 4294967295, # 5.6, RHEL 6.6
+ })
+
+ try:
+ type_map.update({
+ "PySide2.QtCore.QMetaObject.Connection": PySide2.QtCore.Connection, # wrong!
+ })
+ except AttributeError:
+ # this does not exist on 5.9 ATM.
+ pass
+
+# QtGui
+if "PySide2.QtGui" in loaded_modules:
+ import PySide2.QtGui
+ from PySide2.QtGui import QPageLayout, QPageSize # 5.9
+ type_map.update({
+ "QVector< QTextLayout.FormatRange >()": [], # do we need more structure?
+ "USHRT_MAX": ushort_max,
+ "0.0f": 0.0,
+ "1.0f": 1.0,
+ "uint32_t": int,
+ "uint8_t": int,
+ "int32_t": int,
+ "GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT,
+ "GL_NEAREST": GL_NEAREST,
+ "WId": WId,
+ "PySide2.QtGui.QPlatformSurface": Virtual("PySide2.QtGui.QPlatformSurface"), # hmm...
+ "PySide2.QtCore.char": StringList, # A 'char **' is a list of strings.
+ "QList< QTouchEvent.TouchPoint >()": list,
+ "QPixmap()": lambda:QPixmap(), # we cannot create this without qApp
+ })
+
+# QtWidgets
+if "PySide2.QtWidgets" in loaded_modules:
+ import PySide2.QtWidgets
+ from PySide2.QtWidgets import QWidget, QMessageBox, QStyleOption, QStyleHintReturn, QStyleOptionComplex
+ type_map.update({
+ "QMessageBox.StandardButtons(Yes | No)": QMessageBox.StandardButtons(
+ QMessageBox.Yes | QMessageBox.No),
+ "QWidget.RenderFlags(DrawWindowBackground | DrawChildren)": QWidget.RenderFlags(
+ QWidget.DrawWindowBackground | QWidget.DrawChildren),
+ "static_cast<Qt.MatchFlags>(Qt.MatchExactly|Qt.MatchCaseSensitive)": (
+ Qt.MatchFlags(Qt.MatchExactly | Qt.MatchCaseSensitive)),
+ "QVector< int >()": [],
+ # from 5.9
+ "Type": PySide2.QtWidgets.QListWidgetItem.Type,
+ "SO_Default": QStyleOption.SO_Default,
+ "SH_Default": QStyleHintReturn.SH_Default,
+ "SO_Complex": QStyleOptionComplex.SO_Complex,
+ })
+
+# QtSql
+if "PySide2.QtSql" in loaded_modules:
+ import PySide2.QtSql
+ from PySide2.QtSql import QSqlDatabase
+ type_map.update({
+ "QLatin1String(defaultConnection)": QSqlDatabase.defaultConnection,
+ "QVariant.Invalid": -1, # not sure what I should create, here...
+ })
+
+# QtNetwork
+if "PySide2.QtNetwork" in loaded_modules:
+ import PySide2.QtNetwork
+ type_map.update({
+ "QMultiMap": typing.DefaultDict(list) if PY3 else {},
+ })
+
+# QtXmlPatterns
+if "PySide2.QtXmlPatterns" in loaded_modules:
+ import PySide2.QtXmlPatterns
+ from PySide2.QtXmlPatterns import QXmlName
+ type_map.update({
+ "QXmlName.PrefixCode": Missing("PySide2.QtXmlPatterns.QXmlName.PrefixCode"),
+ "QXmlName.NamespaceCode": Missing("PySide2.QtXmlPatterns.QXmlName.NamespaceCode")
+ })
+
+# QtMultimedia
+if "PySide2.QtMultimedia" in loaded_modules:
+ import PySide2.QtMultimedia
+ import PySide2.QtMultimediaWidgets
+ type_map.update({
+ "QVariantMap": dict,
+ "QGraphicsVideoItem": PySide2.QtMultimediaWidgets.QGraphicsVideoItem,
+ "QVideoWidget": PySide2.QtMultimediaWidgets.QVideoWidget,
+ })
+
+# QtOpenGL
+if "PySide2.QtOpenGL" in loaded_modules:
+ import PySide2.QtOpenGL
+ type_map.update({
+ "GLuint": int,
+ "GLenum": int,
+ "GLint": int,
+ "GLbitfield": int,
+ "PySide2.QtOpenGL.GLint": int,
+ "PySide2.QtOpenGL.GLuint": int,
+ "GLfloat": float, # 5.6, MSVC 15
+ })
+
+# QtQml
+if "PySide2.QtQml" in loaded_modules:
+ import PySide2.QtQml
+ type_map.update({
+ "QJSValueList()": [],
+ "PySide2.QtQml.bool volatile": bool,
+ # from 5.9
+ "QVariantHash()": {},
+ })
+
+# QtQml
+if "PySide2.QtQuick" in loaded_modules:
+ import PySide2.QtQuick
+ type_map.update({
+ "PySide2.QtQuick.QSharedPointer": int,
+ "PySide2.QtCore.uint": int,
+ "T": int,
+ })
+
+# QtScript
+if "PySide2.QtScript" in loaded_modules:
+ import PySide2.QtScript
+ type_map.update({
+ "QScriptValueList()": [],
+ })
+
+# QtTest
+if "PySide2.QtTest" in loaded_modules:
+ import PySide2.QtTest
+ type_map.update({
+ "PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence,
+ })
+
+# from 5.9
+if "PySide2.QtWebEngineWidgets" in loaded_modules:
+ import PySide2.QtWebEngineWidgets
+ type_map.update({
+ "PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence,
+ })
+
+# from 5.6, MSVC
+if "PySide2.QtWinExtras" in loaded_modules:
+ import PySide2.QtWinExtras
+ type_map.update({
+ "QList< QWinJumpListItem* >()": [],
+ })
+
+# Here was testbinding, actually the source of all evil.
+
+# end of file