aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--sources/pyside2/PySide2/support/generate_pyi.py4
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt2
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py15
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py135
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py360
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py185
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py15
-rw-r--r--sources/shiboken2/tests/minimalbinding/brace_pattern_test.py121
9 files changed, 562 insertions, 277 deletions
diff --git a/.gitignore b/.gitignore
index b8977159..c4bc8c8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,7 +69,7 @@ develop-eggs/
downloads/
eggs/
.eggs/
-lib/
+/lib/
lib64/
parts/
sdist/
diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py
index 294cdc91..c732227f 100644
--- a/sources/pyside2/PySide2/support/generate_pyi.py
+++ b/sources/pyside2/PySide2/support/generate_pyi.py
@@ -252,6 +252,10 @@ def generate_all_pyi(outpath, options):
from PySide2.support.signature import inspect
from PySide2.support.signature.lib.enum_sig import HintingEnumerator
+ # propagate USE_PEP563 to the mapping module.
+ # Perhaps this can be automated?
+ PySide2.support.signature.mapping.USE_PEP563 = USE_PEP563
+
outpath = outpath or os.path.dirname(PySide2.__file__)
name_list = PySide2.__all__ if options.modules == ["all"] else options.modules
errors = ", ".join(set(name_list) - set(PySide2.__all__))
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index 09731240..057a995f 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -61,6 +61,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/
"${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/__init__.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py"
"${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/tool.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/tool.py" COPYONLY)
if (PYTHON_VERSION_MAJOR EQUAL 3)
else()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/backport_inspect.py"
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
index c43d6d07..bd827f1e 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
@@ -58,20 +58,7 @@ used literally as strings like "signature", "existence", etc.
from textwrap import dedent
from shibokensupport.signature import inspect
from shibokensupport.signature.mapping import ellipsis
-
-
-class SimpleNamespace(object):
- # From types.rst, because the builtin is implemented in Python 3, only.
- def __init__(self, **kwargs):
- self.__dict__.update(kwargs)
-
- def __repr__(self):
- keys = sorted(self.__dict__)
- items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
- return "{}({})".format(type(self).__name__, ", ".join(items))
-
- def __eq__(self, other):
- return self.__dict__ == other.__dict__
+from shibokensupport.signature.lib.tool import SimpleNamespace
class SignatureLayout(SimpleNamespace):
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
new file mode 100644
index 00000000..b34bfb40
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
@@ -0,0 +1,135 @@
+#############################################################################
+##
+## 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+tool.py
+
+Some useful stuff, see below.
+"""
+
+from textwrap import dedent
+
+
+class SimpleNamespace(object):
+ # From types.rst, because the builtin is implemented in Python 3, only.
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)
+
+ def __repr__(self):
+ keys = sorted(self.__dict__)
+ items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
+ return "{}({})".format(type(self).__name__, ", ".join(items))
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+try:
+ from types import SimpleNamespace
+except ImportError:
+ pass
+
+
+def build_brace_pattern(level, separators=""):
+ """
+ Build a brace pattern upto a given depth
+
+ The brace pattern parses any pattern with round, square, curly, or angle
+ brackets. Inside those brackets, any characters are allowed.
+
+ The structure is quite simple and is recursively repeated as needed.
+ When separators are given, the match stops at that separator.
+
+ Reason to use this instead of some Python function:
+ The resulting regex is _very_ fast!
+
+ A faster replacement would be written in C, but this solution is
+ sufficient when the nesting level is not too large.
+
+ Because of the recursive nature of the pattern, the size grows by a factor
+ of 4 at every level, as does the creation time. Up to a level of 6, this
+ is below 10 ms.
+
+ There are other regex engines available which allow recursive patterns,
+ avoiding this problem completely. It might be considered to switch to
+ such an engine if the external module is not a problem.
+ """
+ def escape(str):
+ return "".join("\\" + c for c in str)
+
+ ro, rc = round = "()"
+ so, sc = square = "[]"
+ co, cc = curly = "CD" # we insert "{}", later...
+ ao, ac = angle = "<>"
+ qu, bs = '"', "\\"
+ all = round + square + curly + angle
+ __ = " "
+ ro, rc, so, sc, co, cc, ao, ac, separators, qu, bs, all = map(
+ escape, (ro, rc, so, sc, co, cc, ao, ac, separators, qu, bs, all))
+
+ no_brace_sep_q = r"[^{all}{separators}{qu}{bs}]".format(**locals())
+ no_quote = r"(?: [^{qu}{bs}] | {bs}. )*".format(**locals())
+ pattern = dedent(r"""
+ (
+ (?: {__} {no_brace_sep_q}
+ | {qu} {no_quote} {qu}
+ | {ro} {replacer} {rc}
+ | {so} {replacer} {sc}
+ | {co} {replacer} {cc}
+ | {ao} {replacer} {ac}
+ )*
+ )
+ """)
+ no_braces_q = "[^{all}{qu}{bs}]*".format(**locals())
+ repeated = dedent(r"""
+ {indent} (?: {__} {no_braces_q}
+ {indent} | {qu} {no_quote} {qu}
+ {indent} | {ro} {replacer} {rc}
+ {indent} | {so} {replacer} {sc}
+ {indent} | {co} {replacer} {cc}
+ {indent} | {ao} {replacer} {ac}
+ {indent} )*
+ """)
+ for idx in range(level):
+ pattern = pattern.format(replacer = repeated if idx < level-1 else no_braces_q,
+ indent = idx * " ", **locals())
+ return pattern.replace("C", "{").replace("D", "}")
+
+# eof
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
index 5f92446c..b8097719 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -61,24 +61,13 @@ class ellipsis(object):
return "..."
ellipsis = ellipsis()
-StringList = typing.List[str]
-IntList = typing.List[int]
Point = typing.Tuple[float, float]
-PointList = typing.List[Point]
-IntMatrix = typing.List[IntList]
Variant = typing.Any
ModelIndexList = typing.List[int]
QImageCleanupFunction = typing.Callable
+StringList = typing.List[str]
-# First time installing our own Pair type into typing.
-T = TypeVar('T')
-S = TypeVar('S')
-
-class Pair(Generic[T, S]):
- __module__ = "typing"
-
-typing.Pair = Pair
-
+_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?
@@ -174,7 +163,12 @@ class _NotCalled(str):
text = self if self.endswith(")") else self + "()"
return eval(text, namespace)
-USE_PEP563 = sys.version_info[:2] >= (3, 7)
+USE_PEP563 = False
+# Note: we cannot know if this feature has been imported.
+# Otherwise it would be "sys.version_info[:2] >= (3, 7)".
+# We *can* eventually inspect sys.modules and look if
+# the calling module has this future statement set,
+# but should we do that?
# Some types are abstract. They just show their name.
@@ -183,10 +177,11 @@ class Virtual(_NotCalled):
# Other types I simply could not find.
class Missing(_NotCalled):
- if not USE_PEP563:
- # The string must be quoted, because the object does not exist.
- def __repr__(self):
- return '{}("{}")'.format(type(self).__name__, self)
+ # The string must be quoted, because the object does not exist.
+ def __repr__(self):
+ if USE_PEP563:
+ return _NotCalled.__repr__(self)
+ return '{}("{}")'.format(type(self).__name__, self)
class Invalid(_NotCalled):
@@ -260,20 +255,76 @@ type_map = {}
namespace = globals() # our module's __dict__
type_map.update({
+ "bool": bool,
+ "char": Char,
+ "char*": str,
+ "char*const": str,
+ "double": float,
+ "float": float,
+ "int": int,
+ "List": typing.List,
+ "long": int,
+ "PyCallable": typing.Callable,
+ "PyObject": object,
+ "PySequence": typing.Iterable, # important for numpy
+ "PyTypeObject": type,
+ "QChar": Char,
+ "QHash": typing.Dict,
+ "qint16": int,
+ "qint32": int,
+ "qint64": int,
+ "qint8": int,
+ "qintptr": int,
"QList": typing.List,
- "QVector": typing.List,
- "QSet": typing.Set,
- "QPair": Pair,
+ "qlonglong": int,
"QMap": typing.Dict,
+ "QPair": typing.Tuple,
+ "qptrdiff": int,
+ "qreal": float,
+ "QSet": typing.Set,
+ "QString": str,
+ "QStringList": StringList,
+ "quint16": int,
+ "quint32": int,
+ "quint32": int,
+ "quint64": int,
+ "quint8": int,
+ "quintptr": int,
+ "qulonglong": int,
+ "QVariant": Variant,
+ "QVector": typing.List,
+ "real": float,
+ "short": int,
+ "signed char": Char,
+ "signed long": int,
+ "str": str,
+ "true": True,
+ "ULONG_MAX": ulong_max,
+ "unsigned char": Char,
+ "unsigned int": int, # should we define an unsigned type?
+ "unsigned long int": int, # 5.6, RHEL 6.6
+ "unsigned long long": int,
+ "unsigned long": int,
+ "unsigned short int": int, # 5.6, RHEL 6.6
+ "unsigned short": int,
+ "UnsignedShortType": int, # 5.9
+ "void": int, # be more specific?
+ "WId": WId,
+ "zero(bytes)": b"",
+ "zero(Char)": 0,
+ "zero(float)": 0,
+ "zero(int)": 0,
+ "zero(object)": None,
+ "zero(str)": "",
})
# The Shiboken Part
def init_Shiboken():
type_map.update({
+ "PyType": type,
"shiboken2.bool": bool,
"size_t": int,
- "PyType": type,
})
return locals()
@@ -288,36 +339,32 @@ def init_minimal():
def init_sample():
import datetime
type_map.update({
- "double": float,
- "sample.int": int,
+ "char": Char,
"Complex": complex,
- "sample.OddBool": bool,
- "sample.bool": bool,
- "sample.PStr": str,
+ "double": float,
+ "Foo.HANDLE": int,
+ "HANDLE": int,
+ "Null": None,
+ "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"),
"OddBool": bool,
"PStr": str,
- "char": Char,
+ "PyDate": datetime.date,
+ "sample.bool": bool,
"sample.char": Char,
- "sample.Point": Point,
+ "sample.double": float,
+ "sample.int": int,
"sample.ObjectType": object,
- "std.string": str,
- "HANDLE": int,
- "Foo.HANDLE": int,
+ "sample.OddBool": bool,
"sample.Photon.TemplateBase": Missing("sample.Photon.TemplateBase"),
- "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"),
- "zero(HANDLE)": 0,
- "Null": None,
- "zero(sample.ObjectType)": None,
+ "sample.Point": Point,
+ "sample.PStr": str,
+ "sample.unsigned char": Char,
"std.size_t": int,
- 'Str("<unknown>")': "<unknown>",
+ "std.string": str,
+ "ZeroIn": 0,
'Str("<unk")': "<unk",
+ 'Str("<unknown>")': "<unknown>",
'Str("nown>")': "nown>",
- "zero(sample.ObjectModel)": None,
- "sample.unsigned char": Char,
- "sample.double": float,
- "zero(sample.bool)": False,
- "PyDate": datetime.date,
- "ZeroIn": 0,
})
return locals()
@@ -325,15 +372,20 @@ def init_sample():
def init_other():
import numbers
type_map.update({
- "other.Number": numbers.Number,
"other.ExtendsNoImplicitConversion": Missing("other.ExtendsNoImplicitConversion"),
+ "other.Number": numbers.Number,
})
return locals()
def init_smart():
+ # This missing type should be defined in module smart. We cannot set it to Missing()
+ # because it is a container type. Therefore, we supply a surrogate:
+ global SharedPtr
+ class SharedPtr(Generic[_S]):
+ __module__ = "smart"
+ smart.SharedPtr = SharedPtr
type_map.update({
- "smart.SharedPtr": Missing("smart.SharedPtr"), # bad object "SharedPtr<Obj >"
"smart.Smart.Integer2": int,
})
return locals()
@@ -349,131 +401,88 @@ def init_PySide2_QtCore():
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",
+ "4294967295UL": 4294967295, # 5.6, RHEL 6.6
+ "CheckIndexOption.NoOption": Instance(
+ "PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
+ "false": False,
+ "list of QAbstractAnimation": typing.List[PySide2.QtCore.QAbstractAnimation],
+ "list of QAbstractState": typing.List[PySide2.QtCore.QAbstractState],
"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,
- "QChar": Char,
- "signed char": Char,
- "QVariant": Variant,
- "QVariant.Type": type, # not so sure here...
- "QStringRef": str,
- "QString()": "",
- "QModelIndexList": ModelIndexList,
- "unsigned char": Char,
- "QJsonObject": typing.Dict[str, PySide2.QtCore.QJsonValue],
- "QStringList()": [],
- "ULONG_MAX": ulong_max,
- "quintptr": int,
+ "NULL": None, # 5.6, MSVC
+ "nullptr": None, # 5.9
+ "PyByteArray": bytearray,
+ "PyBytes": bytes,
"PyCallable": typing.Callable,
- "PyTypeObject": type,
+ "PyObject": object,
"PySequence": typing.Iterable, # important for numpy
- "qptrdiff": int,
- "true": True,
- "Qt.HANDLE": int, # be more explicit with some consts?
- "list of QAbstractState": typing.List[PySide2.QtCore.QAbstractState],
- "list of QAbstractAnimation": typing.List[PySide2.QtCore.QAbstractAnimation],
- "QVariant()": Invalid(Variant),
"PySide2.QtCore.bool": bool,
- "QHash": typing.Dict,
- "PySide2.QtCore.QChar": Char,
- "PySide2.QtCore.qreal": float,
+ "PySide2.QtCore.char": StringList, # A 'char **' is a list of strings.
+ "PySide2.QtCore.double": float,
"PySide2.QtCore.float": float,
+ "PySide2.QtCore.int": int,
+ "PySide2.QtCore.int32_t": int, # 5.9
+ "PySide2.QtCore.int64_t": int, # 5.9
+ "PySide2.QtCore.long long": int, # 5.9, MSVC 15
+ "PySide2.QtCore.long": int,
+ "PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr,
+ "PySide2.QtCore.QChar": Char,
"PySide2.QtCore.qint16": int,
"PySide2.QtCore.qint32": int,
"PySide2.QtCore.qint64": int,
"PySide2.QtCore.qint8": int,
+ "PySide2.QtCore.qreal": float,
"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.QUrl.ComponentFormattingOptions":
+ PySide2.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why???
+ "PySide2.QtCore.QVariant": Variant,
"PySide2.QtCore.short": int,
- "PySide2.QtCore.unsigned short": int,
"PySide2.QtCore.signed char": Char,
"PySide2.QtCore.uchar": Char,
+ "PySide2.QtCore.uint32_t": int, # 5.9
"PySide2.QtCore.unsigned char": Char, # 5.9
- "PySide2.QtCore.long": int,
- "PySide2.QtCore.QUrl.ComponentFormattingOptions":
- PySide2.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why???
- "QUrl.FormattingOptions(PrettyDecoded)": Instance(
- "QUrl.FormattingOptions(QUrl.PrettyDecoded)"),
- # from 5.9
+ "PySide2.QtCore.unsigned int": int, # 5.9 Ubuntu
+ "PySide2.QtCore.unsigned short": int,
+ "PyTypeObject": type,
+ "PyUnicode": typing.Text,
+ "Q_NULLPTR": None,
+ "QChar": Char,
"QDir.Filters(AllEntries | NoDotAndDotDot)": Instance(
"QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)"),
- "NULL": None, # 5.6, MSVC
"QDir.SortFlags(Name | IgnoreCase)": Instance(
"QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"),
- "PyBytes": bytes,
- "PyByteArray": bytearray,
- "PyUnicode": typing.Text,
- "signed long": int,
- "PySide2.QtCore.int": int,
- "PySide2.QtCore.char": StringList, # A 'char **' is a list of strings.
- "unsigned long int": int, # 5.6, RHEL 6.6
- "unsigned short int": int, # 5.6, RHEL 6.6
- "4294967295UL": 4294967295, # 5.6, RHEL 6.6
- "PySide2.QtCore.int32_t": int, # 5.9
- "PySide2.QtCore.int64_t": int, # 5.9
- "UnsignedShortType": int, # 5.9
- "nullptr": None, # 5.9
- "uint64_t": int, # 5.9
- "PySide2.QtCore.uint32_t": int, # 5.9
- "PySide2.QtCore.unsigned int": int, # 5.9 Ubuntu
- "PySide2.QtCore.long long": int, # 5.9, MSVC 15
- "QGenericArgument(nullptr)": ellipsis, # 5.10
- "QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?!
"QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok?
"QGenericArgument()": ellipsis,
"QGenericArgument(0)": ellipsis,
"QGenericArgument(NULL)": ellipsis, # 5.6, MSVC
+ "QGenericArgument(nullptr)": ellipsis, # 5.10
"QGenericArgument(Q_NULLPTR)": ellipsis,
- "zero(PySide2.QtCore.QObject)": None,
- "zero(PySide2.QtCore.QThread)": None,
- "zero(quintptr)": 0,
- "zero(str)": "",
- "zero(int)": 0,
- "zero(PySide2.QtCore.QState)": None,
- "zero(PySide2.QtCore.bool)": False,
- "zero(PySide2.QtCore.int)": 0,
- "zero(void)": None,
- "zero(long long)": 0,
- "zero(PySide2.QtCore.QAbstractItemModel)": None,
- "zero(PySide2.QtCore.QJsonParseError)": None,
- "zero(double)": 0.0,
- "zero(PySide2.QtCore.qint64)": 0,
- "zero(PySide2.QtCore.QTextCodec.ConverterState)": None,
- "zero(long long)": 0,
- "zero(QImageCleanupFunction)": None,
- "zero(unsigned int)": 0,
- "zero(PySide2.QtCore.QPoint)": Default("PySide2.QtCore.QPoint"),
- "zero(unsigned char)": 0,
- "zero(PySide2.QtCore.QEvent.Type)": None,
- "CheckIndexOption.NoOption": Instance(
- "PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
+ "QHash": typing.Dict,
+ "QJsonObject": typing.Dict[str, PySide2.QtCore.QJsonValue],
+ "QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?!
+ "QModelIndexList": ModelIndexList,
+ "qptrdiff": int,
+ "QString": str,
+ "QString()": "",
+ "QStringList": StringList,
+ "QStringList()": [],
+ "QStringRef": str,
+ "Qt.HANDLE": int, # be more explicit with some consts?
+ "quintptr": int,
+ "QUrl.FormattingOptions(PrettyDecoded)": Instance(
+ "QUrl.FormattingOptions(QUrl.PrettyDecoded)"),
+ "QVariant": Variant,
+ "QVariant()": Invalid(Variant),
+ "QVariant.Type": type, # not so sure here...
"QVariantMap": typing.Dict[str, Variant],
- "PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr,
- "PySide2.QtCore.double": float,
})
try:
type_map.update({
@@ -488,29 +497,21 @@ def init_PySide2_QtCore():
def init_PySide2_QtGui():
from PySide2.QtGui import QPageLayout, QPageSize # 5.12 macOS
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,
+ "int32_t": int,
+ "PySide2.QtCore.uint8_t": int, # macOS 5.9
+ "PySide2.QtGui.QGenericMatrix": Missing("PySide2.QtGui.QGenericMatrix"),
"PySide2.QtGui.QPlatformSurface": int, # a handle
"QList< QTouchEvent.TouchPoint >()": [], # XXX improve?
"QPixmap()": Default("PySide2.QtGui.QPixmap"), # can't create without qApp
- "PySide2.QtCore.uint8_t": int, # macOS 5.9
- "zero(uint32_t)": 0,
- "zero(PySide2.QtGui.QWindow)": None,
- "zero(PySide2.QtGui.QOpenGLContext)": None,
- "zero(PySide2.QtGui.QRegion)": None,
- "zero(PySide2.QtGui.QPaintDevice)": None,
- "zero(PySide2.QtGui.QTextLayout.FormatRange)": None,
- "zero(PySide2.QtGui.QTouchDevice)": None,
- "zero(PySide2.QtGui.QScreen)": None,
- "PySide2.QtGui.QGenericMatrix": Missing("PySide2.QtGui.QGenericMatrix"),
+ "QVector< QTextLayout.FormatRange >()": [], # do we need more structure?
+ "uint32_t": int,
+ "uint8_t": int,
+ "USHRT_MAX": ushort_max,
+ "WId": WId,
})
return locals()
@@ -521,28 +522,15 @@ def init_PySide2_QtWidgets():
type_map.update({
"QMessageBox.StandardButtons(Yes | No)": Instance(
"QMessageBox.StandardButtons(QMessageBox.Yes | QMessageBox.No)"),
+ "QVector< int >()": [],
"QWidget.RenderFlags(DrawWindowBackground | DrawChildren)": Instance(
"QWidget.RenderFlags(QWidget.DrawWindowBackground | QWidget.DrawChildren)"),
+ "SH_Default": QStyleHintReturn.SH_Default,
+ "SO_Complex": QStyleOptionComplex.SO_Complex,
+ "SO_Default": QStyleOption.SO_Default,
"static_cast<Qt.MatchFlags>(Qt.MatchExactly|Qt.MatchCaseSensitive)": Instance(
"Qt.MatchFlags(Qt.MatchExactly | Qt.MatchCaseSensitive)"),
- "QVector< int >()": [],
- "WId": WId,
- # from 5.9
"Type": PySide2.QtWidgets.QListWidgetItem.Type,
- "SO_Default": QStyleOption.SO_Default,
- "SH_Default": QStyleHintReturn.SH_Default,
- "SO_Complex": QStyleOptionComplex.SO_Complex,
- "zero(PySide2.QtWidgets.QWidget)": None,
- "zero(PySide2.QtWidgets.QGraphicsItem)": None,
- "zero(PySide2.QtCore.QEvent)": None,
- "zero(PySide2.QtWidgets.QStyleOption)": None,
- "zero(PySide2.QtWidgets.QStyleHintReturn)": None,
- "zero(PySide2.QtWidgets.QGraphicsLayoutItem)": None,
- "zero(PySide2.QtWidgets.QListWidget)": None,
- "zero(PySide2.QtGui.QKeySequence)": None,
- "zero(PySide2.QtWidgets.QAction)": None,
- "zero(PySide2.QtWidgets.QUndoCommand)": None,
- "zero(WId)": 0,
})
return locals()
@@ -559,9 +547,6 @@ def init_PySide2_QtSql():
def init_PySide2_QtNetwork():
type_map.update({
"QMultiMap": MultiMap,
- "zero(unsigned short)": 0,
- "zero(PySide2.QtCore.QIODevice)": None,
- "zero(QList)": [],
})
return locals()
@@ -569,8 +554,8 @@ def init_PySide2_QtNetwork():
def init_PySide2_QtXmlPatterns():
from PySide2.QtXmlPatterns import QXmlName
type_map.update({
+ "QXmlName.NamespaceCode": Missing("PySide2.QtXmlPatterns.QXmlName.NamespaceCode"),
"QXmlName.PrefixCode": Missing("PySide2.QtXmlPatterns.QXmlName.PrefixCode"),
- "QXmlName.NamespaceCode": Missing("PySide2.QtXmlPatterns.QXmlName.NamespaceCode")
})
return locals()
@@ -588,39 +573,31 @@ def init_PySide2_QtMultimedia():
def init_PySide2_QtOpenGL():
type_map.update({
- "GLuint": int,
+ "GLbitfield": int,
"GLenum": int,
+ "GLfloat": float, # 5.6, MSVC 15
"GLint": int,
- "GLbitfield": int,
+ "GLuint": int,
"PySide2.QtOpenGL.GLint": int,
"PySide2.QtOpenGL.GLuint": int,
- "GLfloat": float, # 5.6, MSVC 15
- "zero(PySide2.QtOpenGL.QGLContext)": None,
- "zero(GLenum)": 0,
- "zero(PySide2.QtOpenGL.QGLWidget)": None,
})
return locals()
def init_PySide2_QtQml():
type_map.update({
- "QJSValueList()": [],
"PySide2.QtQml.bool volatile": bool,
- # from 5.9
+ "QJSValueList()": [],
"QVariantHash()": typing.Dict[str, Variant], # XXX sorted?
- "zero(PySide2.QtQml.QQmlContext)": None,
- "zero(PySide2.QtQml.QQmlEngine)": None,
})
return locals()
def init_PySide2_QtQuick():
type_map.update({
- "PySide2.QtQuick.QSharedPointer": int,
"PySide2.QtCore.uint": int,
+ "PySide2.QtQuick.QSharedPointer": int,
"T": int,
- "zero(PySide2.QtQuick.QQuickItem)": None,
- "zero(GLuint)": 0,
})
return locals()
@@ -638,13 +615,6 @@ def init_PySide2_QtTest():
})
return locals()
-# from 5.9
-def init_PySide2_QtWebEngineWidgets():
- type_map.update({
- "zero(PySide2.QtWebEngineWidgets.QWebEnginePage.FindFlags)": 0,
- })
- return locals()
-
# from 5.6, MSVC
def init_PySide2_QtWinExtras():
type_map.update({
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
index 72ca3575..6109bcee 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -47,6 +47,8 @@ import keyword
import functools
from shibokensupport.signature.mapping import (type_map, update_mapping,
namespace, typing, _NotCalled)
+from shibokensupport.signature.lib.tool import (SimpleNamespace,
+ build_brace_pattern)
_DEBUG = False
LIST_KEYWORDS = False
@@ -78,6 +80,23 @@ def dprint(*args, **kw):
pprint.pprint(arg)
sys.stdout.flush()
+
+_cache = {}
+
+def _parse_arglist(argstr):
+ # The following is a split re. The string is broken into pieces which are
+ # between the recognized strings. Because the re has groups, both the
+ # strings and the separators are returned, where the strings are not
+ # interesting at all: They are just the commata.
+ key = "_parse_arglist"
+ if key not in _cache:
+ regex = build_brace_pattern(level=3, separators=",")
+ _cache[key] = re.compile(regex, flags=re.VERBOSE)
+ split = _cache[key].split
+ # Note: this list is interspersed with "," and surrounded by ""
+ return [x.strip() for x in split(argstr) if x.strip() not in ("", ",")]
+
+
def _parse_line(line):
line_re = r"""
((?P<multi> ([0-9]+)) : )? # the optional multi-index
@@ -86,38 +105,9 @@ def _parse_line(line):
( -> (?P<returntype> .*) )? # the optional return type
$
"""
- ret = re.match(line_re, line, re.VERBOSE).groupdict()
- arglist = ret["arglist"]
- # The following is a split re. The string is broken into pieces which are
- # between the recognized strings. Because the re has groups, both the
- # strings and the delimiters are returned, where the strings are not
- # interesting at all: They are just the commata.
- # Note that it is necessary to put the characters with special handling in
- # the first group (comma, brace, angle bracket).
- # Then they are not recognized there, and we can handle them differently
- # in the following expressions.
- arglist = list(x.strip() for x in re.split(r"""
- (
- (?: # inner group is not capturing
- [^,()<>] # no commas or braces or angle brackets
- |
- \(
- (?:
- [^()]* # or one brace pair
- |
- \(
- [^()]* # or doubls nested pair
- \)
- )*
- \)
- |
- < # or one angle bracket pair
- [^<>]*
- >
- )+ # longest possible span
- ) # this list is interspersed with "," and surrounded by ""
- """, arglist, flags=re.VERBOSE)
- if x.strip() not in ("", ","))
+ ret = SimpleNamespace(**re.match(line_re, line, re.VERBOSE).groupdict())
+ argstr = ret.arglist
+ arglist = _parse_arglist(argstr)
args = []
for arg in arglist:
name, ann = arg.split(":")
@@ -131,15 +121,16 @@ def _parse_line(line):
else:
tup = name, ann
args.append(tup)
- ret["arglist"] = args
- multi = ret["multi"]
+ ret.arglist = args
+ multi = ret.multi
if multi is not None:
- ret["multi"] = int(multi)
- funcname = ret["funcname"]
+ ret.multi = int(multi)
+ funcname = ret.funcname
parts = funcname.split(".")
if parts[-1] in keyword.kwlist:
- ret["funcname"] = funcname + "_"
- return ret
+ ret.funcname = funcname + "_"
+ return vars(ret)
+
def make_good_value(thing, valtype):
try:
@@ -153,6 +144,7 @@ def make_good_value(thing, valtype):
except Exception:
pass
+
def try_to_guess(thing, valtype):
if "." not in thing and "(" not in thing:
text = "{}.{}".format(valtype, thing)
@@ -172,9 +164,13 @@ def try_to_guess(thing, valtype):
return ret
return None
+
def _resolve_value(thing, valtype, line):
if thing in ("0", "None") and valtype:
- thing = "zero({})".format(valtype)
+ if valtype.startswith("PySide2."):
+ return None
+ name = type_map[valtype].__name__
+ thing = "zero({})".format(name)
if thing in type_map:
return type_map[thing]
res = make_good_value(thing, valtype)
@@ -192,40 +188,88 @@ def _resolve_value(thing, valtype, line):
""".format(thing, line), RuntimeWarning)
return thing
+
def _resolve_arraytype(thing, line):
- thing = thing[:-2]
- if thing.endswith("[]"):
+ search = re.search(r"\[(\d*)\]$", thing)
+ thing = thing[:search.start()]
+ if thing.endswith("]"):
thing = _resolve_arraytype(thing, line)
- # this mapping is in shiboken
- thing = "QList[" + thing + "]"
+ if search.group(1):
+ # concrete array, use a tuple
+ nelem = int(search.group(1))
+ thing = ", ".join([thing] * nelem)
+ thing = "Tuple[" + thing + "]"
+ else:
+ thing = "QList[" + thing + "]"
return thing
+
def to_string(thing):
if isinstance(thing, str):
return thing
if hasattr(thing, "__name__"):
- dot = "." in str(type(thing))
+ dot = "." in str(thing)
return thing.__module__ + "." + thing.__name__ if dot else thing.__name__
# Note: This captures things from the typing module:
return str(thing)
-def _resolve_type(thing, line):
- if thing.endswith("[]"):
- thing = _resolve_arraytype(thing, line)
+
+matrix_pattern = "PySide2.QtGui.QGenericMatrix"
+
+# The matrix patch is borrowed from the future (extracted).
+# It will work when the parser recognizes matrices.
+def handle_matrix(arg):
+ n, m, typstr = tuple(map(lambda x:x.strip(), arg.split(",")))
+ assert typstr == "float"
+ result = "PySide2.QtGui.QMatrix{n}x{m}".format(**locals())
+ return eval(result, namespace)
+
+
+debugging_aid = """
+from inspect import currentframe
+
+def lno(level):
+ lineno = currentframe().f_back.f_lineno
+ spaces = level * " "
+ return "{lineno}{spaces}".format(**locals())
+"""
+
+
+def _resolve_type(thing, line, level):
+ # Capture total replacements, first. Happens in
+ # "PySide2.QtCore.QCborStreamReader.StringResult[PySide2.QtCore.QByteArray]"
+ if thing in type_map:
+ return type_map[thing]
+ # Now the nested structures are handled.
if "[" in thing:
+ # handle primitive arrays
+ if re.search(r"\[\d*\]$", thing):
+ thing = _resolve_arraytype(thing, line)
# Handle a container return type. (see PYSIDE-921 in cppgenerator.cpp)
contr, thing = re.match(r"(.*?)\[(.*?)\]$", thing).groups()
- contr = to_string(_resolve_type(contr, line))
- thing = to_string(_resolve_type(thing, line))
+ # Special case: Handle the generic matrices.
+ if contr == matrix_pattern:
+ return handle_matrix(thing)
+ contr = _resolve_type(contr, line, level+1)
+ if isinstance(contr, _NotCalled):
+ raise SystemError("Container types must exist:", repr(contr))
+ contr = to_string(contr)
+ pieces = []
+ for part in _parse_arglist(thing):
+ part = _resolve_type(part, line, level+1)
+ if isinstance(part, _NotCalled):
+ # fix the tag (i.e. "Missing") by repr
+ part = repr(part)
+ pieces.append(to_string(part))
+ thing = ", ".join(pieces)
result = "{contr}[{thing}]".format(**locals())
- if not isinstance(thing, _NotCalled):
- result = eval(result, namespace)
- return result
+ return eval(result, namespace)
return _resolve_value(thing, None, line)
+
def calculate_props(line):
- res = _parse_line(line)
- arglist = res["arglist"]
+ parsed = SimpleNamespace(**_parse_line(line.strip()))
+ arglist = parsed.arglist
annotations = {}
_defaults = []
for idx, tup in enumerate(arglist):
@@ -236,27 +280,33 @@ def calculate_props(line):
ann = 'NULL' # maps to None
tup = name, ann
arglist[idx] = tup
- annotations[name] = _resolve_type(ann, line)
+ annotations[name] = _resolve_type(ann, line, 0)
if len(tup) == 3:
default = _resolve_value(tup[2], ann, line)
_defaults.append(default)
defaults = tuple(_defaults)
- returntype = res["returntype"]
+ returntype = parsed.returntype
if returntype is not None:
- annotations["return"] = _resolve_type(returntype, line)
- props = {}
- props["defaults"] = defaults
- props["kwdefaults"] = {}
- props["annotations"] = annotations
- props["varnames"] = varnames = tuple(tup[0] for tup in arglist)
- funcname = res["funcname"]
- props["fullname"] = funcname
+ annotations["return"] = _resolve_type(returntype, line, 0)
+ props = SimpleNamespace()
+ props.defaults = defaults
+ props.kwdefaults = {}
+ props.annotations = annotations
+ props.varnames = varnames = tuple(tup[0] for tup in arglist)
+ funcname = parsed.funcname
+ props.fullname = funcname
shortname = funcname[funcname.rindex(".")+1:]
- props["name"] = shortname
- props["multi"] = res["multi"]
- return props
+ props.name = shortname
+ props.multi = parsed.multi
+ return vars(props)
+
def fixup_multilines(lines):
+ """
+ Multilines can collapse when certain distinctions between C++ types
+ vanish after mapping to Python.
+ This function fixes this by re-computing multiline-ness.
+ """
res = []
multi_lines = []
for line in lines:
@@ -280,6 +330,7 @@ def fixup_multilines(lines):
res.append(line)
return res
+
def pyside_type_init(type_key, sig_strings):
dprint()
dprint("Initialization of type key '{}'".format(type_key))
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
index dba8f8c7..786a84ec 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
@@ -1996,6 +1996,21 @@ 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
diff --git a/sources/shiboken2/tests/minimalbinding/brace_pattern_test.py b/sources/shiboken2/tests/minimalbinding/brace_pattern_test.py
new file mode 100644
index 00000000..89df998e
--- /dev/null
+++ b/sources/shiboken2/tests/minimalbinding/brace_pattern_test.py
@@ -0,0 +1,121 @@
+#############################################################################
+##
+## 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$
+##
+#############################################################################
+
+from __future__ import absolute_import, print_function
+
+import re
+import sys
+import os
+
+import shiboken2
+type.__signature__ # trigger bootstrap
+
+from shibokensupport.signature.lib.tool import build_brace_pattern
+import unittest
+
+"""
+This test tests the brace pattern from signature.lib.tool
+against a slower reference implementation.
+The pattern is crucial, because it is used heavily in signature.parser .
+"""
+
+# A slow reference parser for braces and strings
+def check(s):
+ open, close = "[{(<", "]})>"
+ escape, quote = "\\", '"'
+ instring = blind = False
+ stack = []
+ for c in s:
+ if instring:
+ if blind:
+ blind = False
+ elif c == escape:
+ blind = True
+ elif c == quote:
+ instring = False
+ stack.pop()
+ continue
+ if c in open:
+ stack.append(c)
+ elif c in close:
+ pos = close.index(c)
+ if ((len(stack) > 0) and
+ (open[pos] == stack[len(stack)-1])):
+ stack.pop()
+ else:
+ return False
+ elif c == escape:
+ return False
+ elif c == quote:
+ instring = True
+ stack.append(c)
+ return len(stack) == 0
+
+
+class TestBracePattern(unittest.TestCase):
+ tests = [
+ (r'{[]{()}}', True),
+ (r'[{}{})(]', False),
+ (r'[{}{} ")(" ]', True),
+ (r'[{}{} ")(\" ]', False),
+ (r'[{}{} ")(\" ]"]', True),
+ (r'a < b ( c [ d { "} \"\"}" } ] ) >', True),
+ (r'a < b ( c [ d { } ] ) >', True),
+ (r'a < b ( c [ d { "huh" } ] ) >', True),
+ (r'a < b ( c [ d { "huh\" \" \\\"" } ] ) >', True),
+ ]
+
+ def test_checkfunc(self):
+ for test, result in self.tests:
+ if result:
+ self.assertTrue(check(test))
+ else:
+ self.assertFalse(check(test))
+
+ def test_the_brace_pattern(self):
+ func = re.compile(build_brace_pattern(5) + "$", re.VERBOSE).match
+ for test, result in self.tests:
+ if result:
+ self.assertTrue(func(test))
+ else:
+ self.assertFalse(func(test))
+
+
+if __name__ == '__main__':
+ unittest.main()