diff options
Diffstat (limited to 'sources/shiboken6/shibokenmodule/files.dir/shibokensupport')
15 files changed, 554 insertions, 736 deletions
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py index 2d640cb89..db4f381f5 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py @@ -1,40 +1,5 @@ -############################################################################# -## -## Copyright (C) 2018 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations # this file intentionally left blank diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py index 8776c7de9..4a8ccdbc6 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py @@ -1,41 +1,9 @@ -############################################################################# -## -## Copyright (C) 2020 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations + +# flake8: noqa F:821 +# flake8: noqa F:401 """ __feature__.py (renamed to feature.py) @@ -51,9 +19,10 @@ The normal usage is like Alternatively, there is the `set_selection` function which uses select_id's and takes an optional `mod_name` parameter. -The select id `-1` has the spectial meaning "ignore this module". +The select id `-1` has the special meaning "ignore this module". """ +import inspect import sys from contextlib import contextmanager @@ -68,7 +37,7 @@ all_feature_names = [ "_feature_80", ] -__all__ = ["all_feature_names", "set_selection", "info"] + all_feature_names +__all__ = ["all_feature_names", "info", "reset", "set_selection"] + all_feature_names snake_case = 0x01 true_property = 0x02 @@ -115,11 +84,13 @@ None to indicate that a normal import should be performed, and All these variables are transparently kept in module `builtins`. """ + def feature_import(name, *args, **kwargs): # PYSIDE-1368: The `__name__` attribute does not need to exist in all modules. # PYSIDE-1398: sys._getframe(1) may not exist when embedding. # PYSIDE-1338: The "1" below is the redirection in loader.py . # PYSIDE-1548: Ensure that features are not affected by other imports. + # PYSIDE-2029: Need to always switch. The cache was wrong interpreted. calling_frame = _cf = sys._getframe(1).f_back importing_module = _cf.f_globals.get("__name__", "__main__") if _cf else "__main__" existing = pyside_feature_dict.get(importing_module, 0) @@ -141,24 +112,66 @@ def feature_import(name, *args, **kwargs): # Initialize feature (multiple times allowed) and clear cache. sys.modules["PySide6.QtCore"].__init_feature__() return sys.modules["__feature__"] - - if importing_module not in pyside_feature_dict: - # Ignore new modules if not from PySide. - default = 0 if name.split(".")[0] == "PySide6" else -1 - pyside_feature_dict[importing_module] = default # Redirect to the original import return None + _is_initialized = False + def __init__(): global _is_initialized if not _is_initialized: # use _one_ recursive import... import PySide6.QtCore # Initialize all prior imported modules - for name in sys.modules: - pyside_feature_dict.setdefault(name, -1) + for name, module in sys.modules.items(): + if name not in pyside_feature_dict: + pyside_feature_dict[name] = 0 if _mod_uses_pyside(module) else -1 + _is_initialized = True + + +def feature_imported(module): + # PYSIDE-2029: Need to inspect imported modules for PySide usage. + """ + Set the module feature default after import. + + A module that uses PySide has a switching default of 0 = "no feature". + Otherwise the default is -1 = "ignore this module". + """ + + # PYSIDE-1368: The `__name__` attribute does not need to exist in all modules. + if hasattr(module, "__name__"): + name = module.__name__ + if name not in pyside_feature_dict: + pyside_feature_dict[name] = 0 if _mod_uses_pyside(module) else -1 + + +def _mod_uses_pyside(module): + """ + Find out if this module uses PySide. + + Simple approach: Search the source code for the string "PySide6". + Maybe we later support source-less modules by inspecting all code objects. + """ + try: + source = inspect.getsource(module) + except TypeError: + # this is a builtin module like sys + return False + except OSError: + # this is a module withot source file + return False + except SyntaxError: + # PYSIDE-2189: A UnicodeError happens in tokenize.py in find_cookie + # which is then creating a SyntaxError in inspect. + # This is undocumented and a Python error, seen in Python 3.10.2 on Windows, + # importing `pythoncom` of the win32 package. + return False + except Exception: + # PYSIDE-2393: pytest behaves weird when allowing any other error. + return False + return "PySide6" in source def set_selection(select_id, mod_name=None): @@ -177,6 +190,14 @@ def set_selection(select_id, mod_name=None): return _current_selection(flag) +# The set_section(0) case seems to be unsafe. We will migrate to +# use the opaque feature.reset() call in all test cases. +def reset(): + set_selection(0) + pyside_feature_dict.clear() + _is_initialized = False + + def info(mod_name=None): """ Internal use: Return the current selection diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py index 396f6ca4c..524c1c483 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py @@ -1,44 +1,6 @@ -# This Python file uses the following encoding: utf-8 -# It has been edited by fix-complaints.py . - -############################################################################# -## -## 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations """ fix-complaints.py @@ -48,7 +10,6 @@ Run it once after copying a new version. It is idem-potent, unless you are changing messages (what I did, of course :-) . """ -import os import glob from pathlib import Path @@ -63,6 +24,7 @@ offending_words = { utf8_line = "# This Python file uses the following encoding: utf-8\n" marker_line = f"# It has been edited by {Path(__file__).name} .\n" + def patch_file(fname): with fname.open() as f: lines = f.readlines() @@ -80,6 +42,7 @@ def patch_file(fname): with open(fname, "w") as f: f.write("".join(lines)) + def doit(): dirname = Path(__file__).parent patched_files = [] @@ -90,6 +53,7 @@ def doit(): print("Working on", fname) patch_file(fname) + if __name__ == "__main__": doit() diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py index 7ae0a7f18..2704ffab7 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py @@ -1,40 +1,5 @@ -############################################################################# -## -## 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations __all__ = "get_signature layout mapping lib".split() diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py index 71f2ffbab..5ec41aa9f 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py @@ -1,41 +1,8 @@ -############################################################################# -## -## Copyright (C) 2020 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations + +# flake8: noqa E:721 """ errorhandler.py @@ -54,21 +21,33 @@ enough to produce a useful ValueError. This matter will be improved in a later version. """ -import inspect -import sys +import collections.abc +import typing from shibokensupport.signature import get_signature -from shibokensupport.signature.mapping import update_mapping, namespace +from shibokensupport.signature.mapping import namespace from textwrap import dedent def qt_isinstance(inst, the_type): if the_type == float: - return isinstance(inst, int) or isinstance(int, float) + # Qt thinks differently about int and float - simply keep it. + return isinstance(inst, int) or isinstance(inst, float) + if the_type.__module__ == "typing": + if the_type is typing.Any: + return True + if the_type.__origin__ is typing.Union: + return any(qt_isinstance(inst, _) for _ in the_type.__args__) + if the_type.__origin__ in (collections.abc.Sequence, + collections.abc.Iterable): + try: + return all(qt_isinstance(_, the_type.__args__[0]) for _ in inst) + except TypeError: + return False try: return isinstance(inst, the_type) except TypeError as e: - print("FIXME", e) + print(f"FIXME qt_isinstance({inst}, {the_type}):", e) return False @@ -82,13 +61,7 @@ def matched_type(args, sigs): if params[k].default is params[k].empty: # this is a necessary parameter, so it fails. continue - ok = True - for arg, param in zip(args, params): - ann = param.annotation - if qt_isinstance(arg, ann): - continue - ok = False - if ok: + if all(qt_isinstance(arg, param.annotation) for arg, param in zip(args, params)): return sig return None @@ -98,12 +71,15 @@ def seterror_argument(args, func_name, info): try: func = eval(func_name, namespace) except Exception as e: - msg = f"Internal error evaluating {func_name}: " + str(e) - return TypeError, msg + msg = f"Error evaluating `{func_name}`: {e}" + return type(e), msg if info and type(info) is str: err = TypeError if info == "<": msg = f"{func_name}(): not enough arguments" + elif info == "0": + msg = (f"{func_name}(): not enough arguments. " + "Note: keyword arguments are only supported for optional parameters.") elif info == ">": msg = f"{func_name}(): too many arguments" elif info.isalnum(): @@ -112,6 +88,12 @@ def seterror_argument(args, func_name, info): msg = f"{func_name}(): {info}" err = AttributeError return err, msg + if isinstance(info, Exception): + # PYSIDE-2230: Python 3.12 seems to always do normalization. + err = type(info) + info = info.args[0] + msg = f"{func_name}(): {info}" + return err, msg if info and type(info) is dict: msg = f"{func_name}(): unsupported keyword '{tuple(info)[0]}'" return AttributeError, msg @@ -151,6 +133,8 @@ def check_string_type(s): def make_helptext(func): existing_doc = func.__doc__ + if existing_doc is None and hasattr(func, "__dict__"): + existing_doc = func.__dict__.get("__doc__") sigs = get_signature(func) if not sigs: return existing_doc diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py index b37aefbb5..394e8cda3 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py @@ -1,41 +1,6 @@ -############################################################################# -## -## 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations """ importhandler.py @@ -70,9 +35,10 @@ def finish_import(module): except Exception as e: name = e.__class__.__qualname__ print(72 * "*") - print(f"Error in deprecated.py, ignored:") + print("Error in deprecated.py, ignored:") print(f" {name}: {e}") + """ A note for people who might think this could be written in pure Python: @@ -98,4 +64,3 @@ module, it is *perhaps* possible to solve that. I tried for a day and then gave up, since the solution is anyway not too nice when __import__ must be overridden. """ -#eof diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py index 2fd2b6c4f..6fc8ff1b3 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py @@ -1,41 +1,6 @@ -############################################################################# -## -## 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations """ layout.py @@ -115,6 +80,7 @@ class SignatureLayout(SimpleNamespace): The only allowed values are '{allowed_values}'. """)) + # The following names are used literally in this module. # This way, we avoid the dict hashing problem. signature = SignatureLayout() @@ -151,7 +117,7 @@ def define_nameless_parameter(): P = inspect.Parameter newname = "NamelessParameter" bases = P.__bases__ - body = dict(P.__dict__) # get rid of mappingproxy + body = dict(P.__dict__) # get rid of mappingproxy if "__slots__" in body: # __slots__ would create duplicates for name in body["__slots__"]: @@ -203,12 +169,13 @@ def make_signature_nameless(signature): signature.parameters[key].__class__ = NamelessParameter -_POSITIONAL_ONLY = inspect._POSITIONAL_ONLY -_POSITIONAL_OR_KEYWORD = inspect._POSITIONAL_OR_KEYWORD -_VAR_POSITIONAL = inspect._VAR_POSITIONAL -_KEYWORD_ONLY = inspect._KEYWORD_ONLY -_VAR_KEYWORD = inspect._VAR_KEYWORD -_empty = inspect._empty +_POSITIONAL_ONLY = inspect._POSITIONAL_ONLY # noqa E:201 +_POSITIONAL_OR_KEYWORD = inspect._POSITIONAL_OR_KEYWORD # noqa E:201 +_VAR_POSITIONAL = inspect._VAR_POSITIONAL # noqa E:201 +_KEYWORD_ONLY = inspect._KEYWORD_ONLY # noqa E:201 +_VAR_KEYWORD = inspect._VAR_KEYWORD # noqa E:201 +_empty = inspect._empty # noqa E:201 + def create_signature(props, key): if not props: @@ -219,9 +186,9 @@ def create_signature(props, key): return list(create_signature(elem, key) for elem in props["multi"]) if type(key) is tuple: - sig_kind, modifier = key + _, modifier = key else: - sig_kind, modifier = key, "signature" + _, modifier = key, "signature" layout = globals()[modifier] # lookup of the modifier in this module if not isinstance(layout, SignatureLayout): @@ -236,7 +203,7 @@ def create_signature(props, key): # parser. pass else: - if varnames[0] in ("self", "cls"): + if varnames and varnames[0] in ("self", "cls"): varnames = varnames[1:] # calculate the modifications @@ -270,8 +237,8 @@ def create_signature(props, key): if kind == _VAR_POSITIONAL: kind = _KEYWORD_ONLY sig = inspect.Signature(params, - return_annotation=annotations.get('return', _empty), - __validate_parameters__=False) + return_annotation=annotations.get('return', _empty), + __validate_parameters__=False) # the special case of nameless parameters if not layout.parameter_names: diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py index 2d640cb89..db4f381f5 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py @@ -1,40 +1,5 @@ -############################################################################# -## -## Copyright (C) 2018 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations # this file intentionally left blank diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py index 149881e01..9d98d7b1b 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py @@ -1,41 +1,6 @@ -############################################################################# -## -## Copyright (C) 2020 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations """ enum_sig.py @@ -50,9 +15,7 @@ by producing a lot of clarity. import inspect import sys import types -import typing from shibokensupport.signature import get_signature as get_sig -from shibokensupport.signature.layout import create_signature """ @@ -67,6 +30,16 @@ declared in the same class, we use `builtins.property` in the class and all sub-classes. The same consideration holds for "overload". """ +_normal_functions = (types.BuiltinFunctionType, types.FunctionType) +if hasattr(sys, "pypy_version_info"): + # In PyPy, there are more types because our builtin functions + # are created differently in C++ and not in PyPy. + _normal_functions += (type(get_sig),) + + +def signal_check(thing): + return thing and type(thing) in (Signal, SignalInstance) + class ExactEnumerator(object): """ @@ -78,13 +51,13 @@ class ExactEnumerator(object): """ def __init__(self, formatter, result_type=dict): - global EnumMeta + global EnumMeta, Signal, SignalInstance try: # Lazy import - from PySide6.QtCore import Qt + from PySide6.QtCore import Qt, Signal, SignalInstance EnumMeta = type(Qt.Key) except ImportError: - EnumMeta = None + EnumMeta = Signal = SignalInstance = None self.fmt = formatter self.result_type = result_type @@ -98,7 +71,7 @@ class ExactEnumerator(object): We check if it is a simple function. """ tp = type(self.func) - return tp not in (types.BuiltinFunctionType, types.FunctionType) + return tp not in _normal_functions def section(self): if hasattr(self.fmt, "section"): @@ -126,9 +99,13 @@ class ExactEnumerator(object): def klass(self, class_name, klass): ret = self.result_type() + if ("._") in class_name: + # This happens when introspecting enum.Enum etc. Python 3.8.8 does not + # like this, but we want to remove that, anyway. + return ret if "<" in class_name: # This is happening in QtQuick for some reason: - ## class QSharedPointer<QQuickItemGrabResult >: + # class std::shared_ptr<QQuickItemGrabResult >: # We simply skip over this class. return ret bases_list = [] @@ -146,9 +123,19 @@ class ExactEnumerator(object): functions = [] enums = [] properties = [] + signals = [] + attributes = {} for thing_name, thing in class_members: - if inspect.isclass(thing): + if signal_check(thing): + signals.append((thing_name, thing)) + elif inspect.isclass(thing): + # If this is the only member of the class, it causes the stub + # to be printed empty without ..., as self.fmt.have_body will + # then be True. (Example: QtCore.QCborTag). Skip it to avoid + # this problem. + if thing_name == "_member_type_": + continue subclass_name = ".".join((class_name, thing_name)) subclasses.append((subclass_name, thing)) elif inspect.isroutine(thing): @@ -156,22 +143,32 @@ class ExactEnumerator(object): functions.append((func_name, thing)) elif type(type(thing)) is EnumMeta: # take the real enum name, not what is in the dict - enums.append((thing_name, type(thing).__qualname__, thing)) + if not thing_name.startswith("_"): + enums.append((thing_name, type(thing).__qualname__, thing)) elif isinstance(thing, property): properties.append((thing_name, thing)) + # Support attributes that have PySide types as values, + # but we skip the 'staticMetaObject' that needs + # to be defined at a QObject level. + elif "PySide" in str(type(thing)) and "QMetaObject" not in str(type(thing)): + if class_name not in attributes: + attributes[class_name] = {} + attributes[class_name][thing_name] = thing if thing_name in self.collision_candidates: self.collision_track.add(thing_name) init_signature = getattr(klass, "__signature__", None) - enums.sort(key=lambda tup: tup[1 : 3]) # sort by class then enum value + # sort by class then enum value + enums.sort(key=lambda tup: (tup[1], tup[2].value)) # We want to handle functions and properties together. func_prop = sorted(functions + properties, key=lambda tup: tup[0]) # find out how many functions create a signature - sigs = list(_ for _ in functions if hasattr(_[1], "__signature__") and _[1].__signature__) - self.fmt.have_body = bool(subclasses or sigs or properties or enums or init_signature) + sigs = list(_ for _ in functions if get_sig(_[1])) + self.fmt.have_body = bool(subclasses or sigs or properties or enums or # noqa W:504 + init_signature or signals or attributes) with self.fmt.klass(class_name, class_str): self.fmt.level += 1 @@ -181,8 +178,25 @@ class ExactEnumerator(object): if len(enums): self.section() for enum_name, enum_class_name, value in enums: - with self.fmt.enum(enum_class_name, enum_name, int(value)): + with self.fmt.enum(enum_class_name, enum_name, value.value): pass + if hasattr(self.fmt, "signal"): + # this is an optional feature + if len(signals): + self.section() + for signal_name, signal in signals: + sig_class = type(signal) + sig_class_name = f"{sig_class.__qualname__}" + sig_str = str(signal) + with self.fmt.signal(sig_class_name, signal_name, sig_str): + pass + if hasattr(self.fmt, "attribute"): + if len(attributes): + self.section() + for class_name, attrs in attributes.items(): + for attr_name, attr_value in attrs.items(): + with self.fmt.attribute(attr_name, attr_value): + pass if len(subclasses): self.section() for subclass_name, subclass in subclasses: @@ -206,7 +220,7 @@ class ExactEnumerator(object): @staticmethod def get_signature(func): - return func.__signature__ + return get_sig(func) def function(self, func_name, func, decorator=None): self.func = func # for is_method() diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py index 8a786b574..641b6693a 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py @@ -1,44 +1,11 @@ LICENSE_TEXT = """ -############################################################################# -## -## Copyright (C) 2021 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations """ +# flake8: noqa E:402 + """ pyi_generator.py @@ -50,7 +17,6 @@ import io import logging import os import re -import subprocess import sys import typing @@ -58,7 +24,6 @@ from pathlib import Path from contextlib import contextmanager from textwrap import dedent -from shiboken6 import Shiboken from shibokensupport.signature.lib.enum_sig import HintingEnumerator from shibokensupport.signature.lib.tool import build_brace_pattern @@ -96,6 +61,7 @@ class Formatter(Writer): unrelated tasks of enumeration and formatting apart. """ def __init__(self, outfile, options, *args): + # XXX Find out which of these patches is still necessary! self.options = options Writer.__init__(self, outfile, *args) # patching __repr__ to disable the __repr__ of typing.TypeVar: @@ -111,8 +77,12 @@ class Formatter(Writer): """ def _typevar__repr__(self): return f"typing.{self.__name__}" - typing.TypeVar.__repr__ = _typevar__repr__ - + # This is no longer necessary for modern typing versions. + # Ignore therefore if the repr is read-only and cannot be changed. + try: + typing.TypeVar.__repr__ = _typevar__repr__ + except TypeError: + pass # Adding a pattern to substitute "Union[T, NoneType]" by "Optional[T]" # I tried hard to replace typing.Optional by a simple override, but # this became _way_ too much. @@ -121,6 +91,7 @@ class Formatter(Writer): pattern = fr"\b Union \s* \[ \s* {brace_pat} \s*, \s* NoneType \s* \]" replace = r"Optional[\1]" optional_searcher = re.compile(pattern, flags=re.VERBOSE) + def optional_replacer(source): return optional_searcher.sub(replace, str(source)) self.optional_replacer = optional_replacer @@ -138,8 +109,6 @@ class Formatter(Writer): txt = f"""\ # Module `{mod_name}` - from shiboken6 import Shiboken - <<IMPORTS>> """ self.print(dedent(txt)) @@ -190,17 +159,34 @@ class Formatter(Writer): self.print(f"{spaces}{enum_name:25}: {class_name} = ... # {hexval}") yield + @contextmanager + def attribute(self, attr_name, attr_value): + spaces = indent * self.level + self.print(f"{spaces}{attr_name:25} = ... # type: {type(attr_value).__qualname__}") + yield + + @contextmanager + def signal(self, class_name, sig_name, sig_str): + spaces = indent * self.level + self.print(f"{spaces}{sig_name:25}: ClassVar[{class_name}] = ... # {sig_str}") + yield + def find_imports(text): return [imp for imp in PySide6.__all__ if f"PySide6.{imp}." in text] FROM_IMPORTS = [ - ("typing", typing.__all__), - ("PySide6.QtCore", ["PyClassProperty"]), (None, ["builtins"]), + (None, ["os"]), + (None, ["enum"]), + ("collections.abc", ["Iterable"]), + ("typing", sorted(typing.__all__)), + ("PySide6.QtCore", ["PyClassProperty", "Signal", "SignalInstance"]), + ("shiboken6", ["Shiboken"]), ] + def filter_from_imports(from_struct, text): """ Build a reduced new `from` structure (nfs) with found entries, only @@ -210,8 +196,15 @@ def filter_from_imports(from_struct, text): lis = [] nfs.append((mod, lis)) for each in imports: - if re.search(rf"(\b|@){each}\b", text): - lis.append(each) + # PYSIDE-1603: We search text that is a usage of the class `each`, + # but only if the class is not also defined here. + if (f"class {each}(") not in text: + if re.search(rf"(\b|@){each}\b([^\s\(:]|\n)", text): + lis.append(each) + # Search if a type is present in the return statement + # of function declarations: '... -> here:' + if re.search(rf"->.*{each}.*:", text): + lis.append(each) if not lis: nfs.pop() return nfs @@ -250,12 +243,10 @@ def generate_pyi(import_name, outpath, options): obj = getattr(top, plainname) if import_name != plainname else top if not getattr(obj, "__file__", None) or Path(obj.__file__).is_dir(): raise ModuleNotFoundError(f"We do not accept a namespace as module `{plainname}`") - module = sys.modules[import_name] outfile = io.StringIO() fmt = Formatter(outfile, options) fmt.print(LICENSE_TEXT.strip()) - need_imports = options._pyside_call and not USE_PEP563 if USE_PEP563: fmt.print("from __future__ import annotations") fmt.print() @@ -282,35 +273,30 @@ def generate_pyi(import_name, outpath, options): # we remove the "<<IMPORTS>>" marker and insert imports if needed if line == "<<IMPORTS>>": text = outfile.getvalue() + wr.print("import " + import_name) + for mod_name in find_imports(text): + imp = "PySide6." + mod_name + if imp != import_name: + wr.print("import " + imp) + wr.print() for mod, imports in filter_from_imports(FROM_IMPORTS, text): import_args = ', '.join(imports) if mod is None: # special case, a normal import wr.print(f"import {import_args}") - elif mod != import_name: + else: wr.print(f"from {mod} import {import_args}") wr.print() - if need_imports: - for mod_name in find_imports(text): - imp = "PySide6." + mod_name - if imp != import_name: - wr.print("import " + imp) - # Do not import Shiboken which is handled already. - if import_name != "Shiboken": - wr.print("import " + import_name) wr.print() + wr.print("NoneType: TypeAlias = type[None]") wr.print() else: wr.print(line) if not options.quiet: options.logger.info(f"Generated: {outfilepath}") - if options and (options.check or options.is_ci): - # Python 3.7 and up: We can check the file directly if the syntax is ok. - if USE_PEP563: - subprocess.check_output([sys.executable, os.fspath(outfilepath)]) -if __name__ == "__main__": +def main(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=dedent("""\ @@ -322,11 +308,10 @@ if __name__ == "__main__": pyi_generator will try to generate an interface "<module>.pyi". """)) parser.add_argument("module", - help="The full path name of an importable module binary (.pyd, .so)") + help="The full path name of an importable module binary (.pyd, .so)") # noqa E:128 parser.add_argument("--quiet", action="store_true", help="Run quietly") - parser.add_argument("--check", action="store_true", help="Test the output") parser.add_argument("--outpath", - help="the output directory (default = location of module binary)") + help="the output directory (default = location of module binary)") # noqa E:128 options = parser.parse_args() module = options.module outpath = options.outpath @@ -344,4 +329,7 @@ if __name__ == "__main__": options.logger = logger generate_pyi(module, outpath, options=options) + +if __name__ == "__main__": + main() # eof diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py index 4ded95c36..48546d7cb 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py @@ -1,41 +1,6 @@ -############################################################################# -## -## 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations """ tool.py @@ -80,8 +45,8 @@ def build_brace_pattern(level, separators): ro, rc = round_ = "()" so, sc = square = "[]" - co, cc = curly = "CD" # we insert "{}", later... - ao, ac = angle = "<>" + co, cc = curly = "CD" # noqa E:201 we insert "{}", later... + ao, ac = angle = "<>" # noqa E:201 q2, bs, q1 = '"', "\\", "'" allpat = round_ + square + curly + angle __ = " " @@ -115,8 +80,8 @@ def build_brace_pattern(level, separators): {indent} )* """) for idx in range(level): - pattern = pattern.format(replacer = repeated if idx < level-1 else no_braces_q, - indent = idx * " ", **locals()) + pattern = pattern.format(replacer=repeated if idx < level - 1 else no_braces_q, + indent=idx * " ", **locals()) return pattern.replace("C", "{").replace("D", "}") diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py index 82d6f75b6..ba9f78761 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py @@ -1,44 +1,9 @@ -# This Python file uses the following encoding: utf-8 -# It has been edited by fix-complaints.py . - -############################################################################# -## -## 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations + +# flake8: noqa E:402 +# flake8: noqa F:401 """ loader.py @@ -69,39 +34,54 @@ import types def pyside_type_init(type_key, sig_strings): return parser.pyside_type_init(type_key, sig_strings) + # name used in signature.cpp def create_signature(props, key): return layout.create_signature(props, key) + # name used in signature.cpp def seterror_argument(args, func_name, info): return errorhandler.seterror_argument(args, func_name, info) + # name used in signature.cpp def make_helptext(func): return errorhandler.make_helptext(func) + # name used in signature.cpp def finish_import(module): return importhandler.finish_import(module) + # name used in signature.cpp def feature_import(*args, **kwds): # don't spend a stack level here for speed and compatibility global feature_import - feature_import = __feature__.feature_import + feature_import = feature.feature_import return feature_import(*args, **kwds) +# name used in signature.cpp +def feature_imported(*args, **kwds): + # don't spend a stack level here for speed and compatibility + global feature_imported + feature_imported = feature.feature_imported + return feature_imported(*args, **kwds) + + import builtins import signature_bootstrap -from shibokensupport import signature, feature as __feature__ +from shibokensupport import signature, feature signature.get_signature = signature_bootstrap.get_signature # PYSIDE-1019: Publish the __feature__ dictionary. -__feature__.pyside_feature_dict = signature_bootstrap.pyside_feature_dict +feature.pyside_feature_dict = signature_bootstrap.pyside_feature_dict builtins.__feature_import__ = signature_bootstrap.__feature_import__ del signature_bootstrap +is_pypy = hasattr(sys, "pypy_version_info") + def put_into_package(package, module, override=None): # take the last component of the module name @@ -124,7 +104,8 @@ def move_into_pyside_package(): except ModuleNotFoundError: # This can happen in the embedding case. put_into_package(PySide6, shibokensupport, "support") - put_into_package(PySide6.support, __feature__, "__feature__") + if not is_pypy: + put_into_package(PySide6.support, feature) put_into_package(PySide6.support, signature) put_into_package(PySide6.support.signature, mapping) put_into_package(PySide6.support.signature, errorhandler) @@ -136,6 +117,7 @@ def move_into_pyside_package(): put_into_package(PySide6.support.signature.lib, pyi_generator) put_into_package(PySide6.support.signature.lib, tool) + from shibokensupport.signature import mapping from shibokensupport.signature import errorhandler from shibokensupport.signature import layout @@ -146,21 +128,32 @@ from shibokensupport.signature.lib import enum_sig from shibokensupport.signature.lib import pyi_generator from shibokensupport.signature.lib import tool +import enum + +post_init = lambda: None # noqa E:731 default + if "PySide6" in sys.modules: # We publish everything under "PySide6.support", again. move_into_pyside_package() # PYSIDE-1502: Make sure that support can be imported. try: import PySide6.support - except ModuleNotFoundError as e: + except ModuleNotFoundError: print("PySide6.support could not be imported. " "This is a serious configuration error.", file=sys.stderr) raise - # PYSIDE-1019: Modify `__import__` to be `__feature__` aware. - # __feature__ is already in sys.modules, so this is actually no import - import PySide6.support.__feature__ - sys.modules["__feature__"] = PySide6.support.__feature__ - builtins.__orig_import__ = builtins.__import__ - builtins.__import__ = builtins.__feature_import__ + + def post_init(): + """ + This function needs to be called explicitly when all function pointers are set. + Doing this during import has bad side-effects when preloading the loader. + """ + # PYSIDE-1019: Modify `__import__` to be `__feature__` aware. + if not is_pypy: + # PYSIDE-535: Cannot enable __feature__ for various reasons. + import PySide6.support.feature + sys.modules["__feature__"] = PySide6.support.feature + builtins.__orig_import__ = builtins.__import__ + builtins.__import__ = builtins.__feature_import__ # end of file diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 73da611ba..3bdd4c1d2 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -1,41 +1,8 @@ -############################################################################# -## -## Copyright (C) 2021 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations + +# flake8: noqa E:203 """ mapping.py @@ -54,16 +21,17 @@ import typing from pathlib import Path from typing import TypeVar, Generic -from shibokensupport.signature.lib.tool import with_metaclass +from _imp import is_builtin + class ellipsis(object): def __repr__(self): return "..." + ellipsis = ellipsis() -Point = typing.Tuple[float, float] +Point = typing.Tuple[int, int] Variant = typing.Any -ModelIndexList = typing.List[int] QImageCleanupFunction = typing.Callable # unfortunately, typing.Optional[t] expands to typing.Union[t, NoneType] @@ -75,7 +43,7 @@ _S = TypeVar("_S") MultiMap = typing.DefaultDict[str, typing.List[str]] # ulong_max is only 32 bit on windows. -ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff +ulong_max = 2 * sys.maxsize + 1 if len(struct.pack("L", 1)) != 4 else 0xffffffff ushort_max = 0xffff GL_COLOR_BUFFER_BIT = 0x00004000 @@ -111,6 +79,7 @@ class _NotCalled(str): text = self if self.endswith(")") else self + "()" return eval(text, namespace) + USE_PEP563 = False # Note: we cannot know if this feature has been imported. # Otherwise it would be "sys.version_info[:2] >= (3, 7)". @@ -123,6 +92,7 @@ USE_PEP563 = False class Virtual(_NotCalled): pass + # Other types I simply could not find. class Missing(_NotCalled): # The string must be quoted, because the object does not exist. @@ -135,6 +105,7 @@ class Missing(_NotCalled): class Invalid(_NotCalled): pass + # Helper types class Default(_NotCalled): pass @@ -143,6 +114,7 @@ class Default(_NotCalled): class Instance(_NotCalled): pass + # Parameterized primitive variables class _Parameterized(object): def __init__(self, type): @@ -152,15 +124,18 @@ class _Parameterized(object): def __repr__(self): return f"{type(self).__name__}({self.type.__name__})" + # Mark the primitive variables to be moved into the result. class ResultVariable(_Parameterized): pass + # Mark the primitive variables to become Sequence, Iterable or List # (decided in the parser). class ArrayLikeVariable(_Parameterized): pass + StringList = ArrayLikeVariable(str) @@ -179,7 +154,7 @@ class Reloader(object): if getattr(mod, "__file__", None) and not Path(mod.__file__).is_dir(): ending = Path(mod.__file__).suffix return ending not in (".py", ".pyc", ".pyo", ".pyi") - return False + return bool(hasattr(mod, "__name__") and is_builtin(mod.__name__)) def update(self): """ @@ -217,28 +192,29 @@ def check_module(mod): mod_name = mod.__name__ raise ImportError(f"Module '{mod_name}' is not a binary module!") + update_mapping = Reloader().update type_map = {} namespace = globals() # our module's __dict__ type_map.update({ "...": ellipsis, + "Any": typing.Any, "bool": bool, "char": int, - "char*": str, - "char*const": str, "double": float, "float": float, "int": int, "List": ArrayLikeVariable, "Optional": typing.Optional, "long": int, + "long long": int, "nullptr": None, "PyCallable": typing.Callable, "PyObject": object, "PyObject*": object, "PyArrayObject": ArrayLikeVariable, # numpy - "PyPathLike": typing.Union[str, bytes, os.PathLike], + "PyPathLike": typing.Union[str, bytes, os.PathLike[str]], "PySequence": typing.Iterable, # important for numpy "PyTypeObject": type, "QChar": str, @@ -255,6 +231,7 @@ type_map.update({ "uintptr_t": int, "qintptr": int, "qsizetype": int, + "QFunctionPointer": int, "QList": ArrayLikeVariable, "qlonglong": int, "QMap": typing.Dict, @@ -265,6 +242,7 @@ type_map.update({ "qreal": float, "QSet": typing.Set, "QString": str, + "QLatin1String": str, "QStringView": str, "QStringList": StringList, "quint16": int, @@ -276,6 +254,7 @@ type_map.update({ "uint32_t": int, "uint64_t": int, "uint8_t": int, + "Union": typing.Union, "quintptr": int, "qulonglong": int, "QVariant": Variant, @@ -287,6 +266,7 @@ type_map.update({ "signed long": int, "std.list": typing.List, "std.map": typing.Dict, + "std.nullptr_t": NoneType, "std.pair": typing.Tuple, "std.string": str, "std.wstring": str, @@ -300,17 +280,16 @@ type_map.update({ "ulong": int, "ULONG_MAX": ulong_max, "UINT64_MAX": 0xffffffff, - "unsigned char": int, # 5.9 + "unsigned char": int, # 5.9 "unsigned char*": str, "unsigned int": int, - "unsigned long int": int, # 5.6, RHEL 6.6 + "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": int, # 5.6, RHEL 6.6 "unsigned short": int, - "Unspecified": None, "ushort": int, - "void": int, # be more specific? + "void": int, # be more specific? "WId": WId, "zero(bytes)": b"", "zero(Char)": 0, @@ -320,7 +299,11 @@ type_map.update({ "zero(str)": "", "zero(typing.Any)": None, "zero(Any)": None, - }) + # This can be refined by importing numpy.typing optionally, but better than nothing. + "numpy.ndarray": typing.List[typing.Any], + "std.array[int, 4]": typing.List[int], + "std.array[float, 4]": typing.List[float] +}) type_map.update({ # Handling variables declared as array: @@ -332,8 +315,8 @@ type_map.update({ "array long long*" : ArrayLikeVariable(int), "array long*" : ArrayLikeVariable(int), "array short*" : ArrayLikeVariable(int), - "array signed char*" : bytes, - "array unsigned char*" : bytes, + "array signed char*" : typing.Union[bytes, bytearray, memoryview], + "array unsigned char*" : typing.Union[bytes, bytearray, memoryview], "array unsigned int*" : ArrayLikeVariable(int), "array unsigned short*" : ArrayLikeVariable(int), # PYSIDE-1646: New macOS primitive types @@ -344,17 +327,17 @@ type_map.update({ "array int32_t*" : ArrayLikeVariable(int), "array uint32_t*" : ArrayLikeVariable(int), "array intptr_t*" : ArrayLikeVariable(int), - }) +}) type_map.update({ # Special cases: - "char*" : bytes, - "QChar*" : bytes, + "char*" : typing.Union[bytes, bytearray, memoryview], + "QChar*" : typing.Union[bytes, bytearray, memoryview], "quint32*" : int, # only for QRandomGenerator "quint8*" : bytearray, # only for QCborStreamReader and QCborValue - "uchar*" : bytes, - "unsigned char*": bytes, - }) + "uchar*" : typing.Union[bytes, bytearray, memoryview], + "unsigned char*": typing.Union[bytes, bytearray, memoryview], +}) type_map.update({ # Handling variables that are returned, eventually as Tuples: @@ -368,6 +351,7 @@ type_map.update({ "qint32*" : ResultVariable(int), "qint64*" : ResultVariable(int), "qreal*" : ResultVariable(float), + "qsizetype*" : ResultVariable(int), "QString*" : ResultVariable(str), "qintptr*" : ResultVariable(int), "quintptr*" : ResultVariable(int), @@ -375,7 +359,7 @@ type_map.update({ "uint*" : ResultVariable(int), "unsigned int*" : ResultVariable(int), "QStringList*" : ResultVariable(StringList), - }) +}) type_map.update({ @@ -383,20 +367,21 @@ type_map.update({ "[typing.Any]" : [typing.Any], "[typing.Any,typing.Any]" : [typing.Any, typing.Any], "None" : None, - }) +}) # PYSIDE-1328: We need to handle "self" explicitly. type_map.update({ "self" : "self", "cls" : "cls", - }) +}) # PYSIDE-1538: We need to treat "std::optional" accordingly. type_map.update({ "std.optional": typing.Optional, }) + # The Shiboken Part def init_Shiboken(): type_map.update({ @@ -406,6 +391,7 @@ def init_Shiboken(): }) return locals() + def init_minimal(): type_map.update({ "MinBool": bool, @@ -418,8 +404,10 @@ def init_sample(): type_map.update({ "char": int, "char**": typing.List[str], + "const char*": str, "Complex": complex, "double": float, + "ByteArray&": typing.Union[bytes, bytearray, memoryview], "Foo.HANDLE": int, "HANDLE": int, "Null": None, @@ -427,6 +415,7 @@ def init_sample(): "OddBool": bool, "PStr": str, "PyDate": datetime.date, + "PyBuffer": typing.Union[bytes, bytearray, memoryview], "sample.bool": bool, "sample.char": int, "sample.double": float, @@ -437,6 +426,7 @@ def init_sample(): "sample.Photon.TemplateBase[Photon.IdentityType]": sample.Photon.ValueIdentity, "sample.Point": Point, "sample.PStr": str, + "SampleNamespace.InValue.ZeroIn": 0, "sample.unsigned char": int, "std.size_t": int, "std.string": str, @@ -461,6 +451,7 @@ 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 @@ -473,8 +464,8 @@ def init_smart(): # The PySide Part def init_PySide6_QtCore(): from PySide6.QtCore import Qt, QUrl, QDir, QKeyCombination - from PySide6.QtCore import QRect, QSize, QPoint, QLocale, QByteArray - from PySide6.QtCore import QMarginsF # 5.9 + from PySide6.QtCore import QRect, QRectF, QSize, QPoint, QLocale, QByteArray + from PySide6.QtCore import QMarginsF # 5.9 from PySide6.QtCore import SignalInstance try: # seems to be not generated by 5.9 ATM. @@ -485,61 +476,69 @@ def init_PySide6_QtCore(): "' '": " ", "'%'": "%", "'g'": "g", - "4294967295UL": 4294967295, # 5.6, RHEL 6.6 + "4294967295UL": 4294967295, # 5.6, RHEL 6.6 "CheckIndexOption.NoOption": Instance( - "PySide6.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11 + "PySide6.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11 "DescriptorType(-1)": int, # Native handle of QSocketDescriptor "false": False, "list of QAbstractAnimation": typing.List[PySide6.QtCore.QAbstractAnimation], "long long": int, "size_t": int, - "NULL": None, # 5.6, MSVC - "nullptr": None, # 5.9 - "PyBuffer": bytes, + "NULL": None, # 5.6, MSVC + "nullptr": None, # 5.9 + "PyBuffer": typing.Union[bytes, bytearray, memoryview], "PyByteArray": bytearray, - "PyBytes": bytes, + "PyBytes": typing.Union[bytes, bytearray, memoryview], "PyTuple": typing.Tuple, "QDeadlineTimer(QDeadlineTimer.Forever)": Instance("PySide6.QtCore.QDeadlineTimer"), "PySide6.QtCore.QUrl.ComponentFormattingOptions": - PySide6.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why??? + PySide6.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why??? "PyUnicode": typing.Text, + "QByteArrayView": QByteArray, "Q_NULLPTR": None, + "QCalendar.Unspecified": PySide6.QtCore.QCalendar.Unspecified, + "QCborTag(-1)": ulong_max, "QDir.Filters(AllEntries | NoDotAndDotDot)": Instance( "QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)"), "QDir.SortFlags(Name | IgnoreCase)": Instance( "QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"), - "QEvent.Type.None" : None, - "QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok? + "QEvent.Type.None": None, + "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(NULL)": ellipsis, # 5.6, MSVC + "QGenericArgument(nullptr)": ellipsis, # 5.10 "QGenericArgument(Q_NULLPTR)": ellipsis, "QJsonObject": typing.Dict[str, PySide6.QtCore.QJsonValue], - "QModelIndex()": Invalid("PySide6.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?! - "QModelIndexList": ModelIndexList, - "QModelIndexList": ModelIndexList, + "QModelIndex()": Invalid("PySide6.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?! + "QModelIndexList": typing.List[PySide6.QtCore.QModelIndex], "PySideSignalInstance": SignalInstance, "QString()": "", "Flag.Default": Instance("PySide6.QtCore.QStringConverterBase.Flags"), "QStringList()": [], "QStringRef": str, "QStringRef": str, - "Qt.HANDLE": int, # be more explicit with some constants? + "Qt.HANDLE": int, # be more explicit with some constants? "QUrl.FormattingOptions(PrettyDecoded)": Instance( "QUrl.FormattingOptions(QUrl.PrettyDecoded)"), "QVariant()": Invalid(Variant), - "QVariant.Type": type, # not so sure here... - "QVariantMap": typing.Dict[str, Variant], + "QVariant.Type": type, # not so sure here... "QVariantMap": typing.Dict[str, Variant], + "std.chrono.seconds{5}" : ellipsis, }) try: type_map.update({ - "PySide6.QtCore.QMetaObject.Connection": PySide6.QtCore.Connection, # wrong! + "PySide6.QtCore.QMetaObject.Connection": PySide6.QtCore.Connection, # wrong! }) except AttributeError: # this does not exist on 5.9 ATM. pass + + # special case - char* can either be 'bytes' or 'str'. The default is 'bytes'. + # Here we manually set it to map to 'str'. + type_map.update({("PySide6.QtCore.QObject.setProperty", "char*"): str}) + type_map.update({("PySide6.QtCore.QObject.property", "char*"): str}) + return locals() @@ -554,37 +553,48 @@ def init_PySide6_QtConcurrent(): def init_PySide6_QtGui(): - from PySide6.QtGui import QPageLayout, QPageSize # 5.12 macOS + from PySide6.QtGui import QPageLayout, QPageSize # 5.12 macOS type_map.update({ "0.0f": 0.0, "1.0f": 1.0, "GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT, "GL_NEAREST": GL_NEAREST, "int32_t": int, - "QPixmap()": Default("PySide6.QtGui.QPixmap"), # can't create without qApp - "QPlatformSurface*": int, # a handle - "QVector< QTextLayout.FormatRange >()": [], # do we need more structure? + "HBITMAP": int, + "HICON": int, + "HMONITOR": int, + "HRGN": int, + "QPixmap()": Default("PySide6.QtGui.QPixmap"), # can't create without qApp + "QPlatformSurface*": int, # a handle + "QVector< QTextLayout.FormatRange >()": [], # do we need more structure? "uint32_t": int, "uint8_t": int, "USHRT_MAX": ushort_max, }) + + # special case - char* can either be 'bytes' or 'str'. The default is 'bytes'. + # Here we manually set it to map to 'str'. + type_map.update({("PySide6.QtGui.QPixmap.save", "char*"): str}) + return locals() def init_PySide6_QtWidgets(): - from PySide6.QtWidgets import QWidget, QMessageBox, QStyleOption, QStyleHintReturn, QStyleOptionComplex - from PySide6.QtWidgets import QGraphicsItem, QStyleOptionGraphicsItem # 5.9 + from PySide6.QtWidgets import (QWidget, QMessageBox, QStyleOption, + QStyleHintReturn, QStyleOptionComplex, + QGraphicsItem, QStyleOptionGraphicsItem) type_map.update({ "QMessageBox.StandardButtons(Yes | No)": Instance( "QMessageBox.StandardButtons(QMessageBox.Yes | QMessageBox.No)"), "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)"), - "Type": PySide6.QtWidgets.QListWidgetItem.Type, + "static_cast<Qt.MatchFlag>(Qt.MatchExactly|Qt.MatchCaseSensitive)": Instance( + "Qt.MatchFlag(Qt.MatchExactly | Qt.MatchCaseSensitive)"), + "QListWidgetItem.ItemType.Type": PySide6.QtWidgets.QListWidgetItem.Type, + "QTableWidgetItem.ItemType.Type": PySide6.QtWidgets.QTableWidgetItem.Type, + "QTreeWidgetItem.ItemType.Type": PySide6.QtWidgets.QTreeWidgetItem.Type, }) return locals() @@ -592,8 +602,8 @@ def init_PySide6_QtWidgets(): def init_PySide6_QtSql(): from PySide6.QtSql import QSqlDatabase type_map.update({ - "QLatin1String(defaultConnection)": QSqlDatabase.defaultConnection, - "QVariant.Invalid": Invalid("Variant"), # not sure what I should create, here... + "QLatin1StringView(QSqlDatabase.defaultConnection)": QSqlDatabase.defaultConnection, + "QVariant.Invalid": Invalid("Variant"), # not sure what I should create, here... }) return locals() @@ -613,27 +623,11 @@ def init_PySide6_QtNetwork(): return locals() -def init_PySide6_QtMultimedia(): - # PYSIDE-1599: We force pyi testing in wheel_tester. This seems to fail, sometimes. - try: - import PySide6.QtMultimediaWidgets - check_module(PySide6.QtMultimediaWidgets) - except SystemError: - print("Failure importing QtMultimediaWidgets") - return locals() - type_map.update({ - "QGraphicsVideoItem": PySide6.QtMultimediaWidgets.QGraphicsVideoItem, - "qint64": int, - "QVideoWidget": PySide6.QtMultimediaWidgets.QVideoWidget, - }) - return locals() - - def init_PySide6_QtOpenGL(): type_map.update({ "GLbitfield": int, "GLenum": int, - "GLfloat": float, # 5.6, MSVC 15 + "GLfloat": float, # 5.6, MSVC 15 "GLint": int, "GLuint": int, }) @@ -651,7 +645,7 @@ def init_PySide6_QtQuick(): type_map.update({ "PySide6.QtQuick.QSharedPointer[PySide6.QtQuick.QQuickItemGrabResult]": PySide6.QtQuick.QQuickItemGrabResult, - "UnsignedShortType": int, + "QSGGeometry.Type.UnsignedShortType": int, }) return locals() @@ -690,9 +684,36 @@ def init_PySide6_QtBluetooth(): return locals() +def init_PySide6_QtGraphs(): + from PySide6.QtGraphs import (QBarDataItem, QSurfaceDataItem) + QBarDataRow = typing.List[QBarDataItem] + QBarDataArray = typing.List[QBarDataRow] + QSurfaceDataRow = typing.List[QSurfaceDataItem] + QSurfaceDataArray = typing.List[QSurfaceDataRow] + type_map.update({ + "100.0f": 100.0, + "QBarDataArray": QBarDataArray, + "QBarDataArray*": QBarDataArray, + "QSurfaceDataArray": QSurfaceDataArray, + "QSurfaceDataArray*": QSurfaceDataArray, + }) + return locals() + + +def init_PySide6_QtHttpServer(): + type_map.update({ + "qMakePair(1u, 1u)": (1, 1), + }) + return locals() + + def init_testbinding(): type_map.update({ "testbinding.PySideCPP2.TestObjectWithoutNamespace": testbinding.TestObjectWithoutNamespace, + "testbinding.FlagsNamespace.Options": testbinding.Option, + "FlagsNamespace.Option.NoOptions": 0, + "StdIntList": typing.List[int], + 'Str("")': str(""), }) return locals() diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py index 8adac0725..6071dd92c 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py @@ -1,55 +1,20 @@ -############################################################################# -## -## 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$ -## -############################################################################# +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +from __future__ import annotations -import sys +import ast +import enum +import keyword +import os import re -import warnings -import types +import sys import typing -import keyword -import functools +import warnings from types import SimpleNamespace from shibokensupport.signature.mapping import (type_map, update_mapping, - namespace, _NotCalled, ResultVariable, ArrayLikeVariable) + namespace, _NotCalled, ResultVariable, ArrayLikeVariable) # noqa E:128 from shibokensupport.signature.lib.tool import build_brace_pattern -from shibokensupport import feature _DEBUG = False LIST_KEYWORDS = False @@ -74,6 +39,65 @@ guesses, we provide an entry in 'type_map' that resolves it. In effect, 'type_map' maps text to real Python objects. """ + +def _get_flag_enum_option(): + from shiboken6 import (__version_info__ as ver, # noqa F:401 + __minimum_python_version__ as pyminver, + __maximum_python_version__ as pymaxver) + + # PYSIDE-1735: Use the new Enums per default if version is >= 6.4 + # This decides between delivered vs. dev versions. + # When 6.4 is out, the switching mode will be gone. + flag = ver[:2] >= (6, 4) + envname = "PYSIDE6_OPTION_PYTHON_ENUM" + sysname = envname.lower() + opt = os.environ.get(envname) + if opt: + opt = opt.lower() + if opt in ("yes", "on", "true"): + flag = True + elif opt in ("no", "off", "false"): + flag = False + else: + # instead of a simple int() conversion, let's allow for "0xf" or "0b1111" + try: + flag = ast.literal_eval(opt) + except Exception: + flag = False # turn a forbidden option into an error + elif hasattr(sys, sysname): + opt2 = flag = getattr(sys, sysname) + if not isinstance(flag, int): + flag = False # turn a forbidden option into an error + p = f"\n *** Python is at version {'.'.join(map(str, pyminver or (0,)))} now." + q = f"\n *** PySide is at version {'.'.join(map(str, ver[:2]))} now." + # _PepUnicode_AsString: Fix a broken promise + if pyminver and pyminver >= (3, 10): + warnings.warn(f"{p} _PepUnicode_AsString can now be replaced by PyUnicode_AsUTF8! ***") + # PYSIDE-1960: Emit a warning when we may remove bufferprocs_py37.(cpp|h) + if pyminver and pyminver >= (3, 11): + warnings.warn(f"{p} The files bufferprocs_py37.(cpp|h) should be removed ASAP! ***") + # PYSIDE-1735: Emit a warning when we should maybe evict forgiveness mode + if ver[:2] >= (7, 0): + warnings.warn(f"{q} Please drop Enum forgiveness mode in `mangled_type_getattro` ***") + # PYSIDE-2404: Emit a warning when we should drop uppercase offset constants + if ver[:2] >= (7, 0): + warnings.warn(f"{q} Please drop uppercase type offsets in `copyOffsetEnumStream` ***") + # normalize the sys attribute + setattr(sys, sysname, flag) + os.environ[envname] = str(flag) + if int(flag) == 0: + raise RuntimeError(f"Old Enums are no longer supported. int({opt or opt2}) evaluates to 0)") + return flag + + +class EnumSelect(enum.Enum): + # PYSIDE-1735: Here we could save object.value expressions by using IntEnum. + # But it is nice to use just an Enum for selecting Enum version. + OLD = 1 + NEW = 2 + SELECTION = NEW if _get_flag_enum_option() else OLD + + def dprint(*args, **kw): if _DEBUG: import pprint @@ -84,6 +108,7 @@ def dprint(*args, **kw): _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 @@ -165,7 +190,7 @@ def _handle_instance_fixup(thing): if not match: return thing start, stop = match.start(), match.end() - 1 - pre, func, args = thing[:start], thing[start : stop], thing[stop:] + pre, func, args = thing[:start], thing[start:stop], thing[stop:] if func[0].isupper() or func.startswith("gl") and func[2:3].isupper(): return thing # Now convert this string to snake case. @@ -174,7 +199,7 @@ def _handle_instance_fixup(thing): if char.isupper(): if idx and func[idx - 1].isupper(): # two upper chars are forbidden - return things + return thing snake_func += f"_{char.lower()}" else: snake_func += char @@ -189,10 +214,11 @@ def make_good_value(thing, valtype): if thing.endswith("()"): thing = f'Default("{thing[:-2]}")' else: - ret = eval(thing, namespace) + # PYSIDE-1735: Use explicit globals and locals because of a bug in VsCode + ret = eval(thing, globals(), namespace) if valtype and repr(ret).startswith("<"): thing = f'Instance("{thing}")' - return eval(thing, namespace) + return eval(thing, globals(), namespace) except Exception: pass @@ -216,12 +242,14 @@ def try_to_guess(thing, valtype): return ret return None + def get_name(thing): if isinstance(thing, type): return getattr(thing, "__qualname__", thing.__name__) else: return thing.__name__ + def _resolve_value(thing, valtype, line): if thing in ("0", "None") and valtype: if valtype.startswith("PySide6.") or valtype.startswith("typing."): @@ -264,30 +292,44 @@ def _resolve_arraytype(thing, line): def to_string(thing): + # This function returns a string that creates the same object. + # It is absolutely crucial that str(eval(thing)) == str(thing), + # i.e. it must be an idempotent mapping. if isinstance(thing, str): return thing if hasattr(thing, "__name__") and thing.__module__ != "typing": - dot = "." in str(thing) + m = thing.__module__ + dot = "." in str(thing) or m not in (thing.__qualname__, "builtins") name = get_name(thing) - return thing.__module__ + "." + name if dot else name + ret = m + "." + name if dot else name + assert (eval(ret, globals(), namespace)) + return ret # Note: This captures things from the typing module: return str(thing) matrix_pattern = "PySide6.QtGui.QGenericMatrix" + def handle_matrix(arg): - n, m, typstr = tuple(map(lambda x:x.strip(), arg.split(","))) + n, m, typstr = tuple(map(lambda x: x.strip(), arg.split(","))) assert typstr == "float" result = f"PySide6.QtGui.QMatrix{n}x{m}" - return eval(result, namespace) + return eval(result, globals(), namespace) -def _resolve_type(thing, line, level, var_handler): +def _resolve_type(thing, line, level, var_handler, func_name=None): + # manual set of 'str' instead of 'bytes' + if func_name: + new_thing = (func_name, thing) + if new_thing in type_map: + return type_map[new_thing] + # Capture total replacements, first. Happens in # "PySide6.QtCore.QCborStreamReader.StringResult[PySide6.QtCore.QByteArray]" if thing in type_map: return type_map[thing] + # Now the nested structures are handled. if "[" in thing: # handle primitive arrays @@ -298,13 +340,13 @@ def _resolve_type(thing, line, level, var_handler): # Special case: Handle the generic matrices. if contr == matrix_pattern: return handle_matrix(thing) - contr = var_handler(_resolve_type(contr, line, level+1, var_handler)) + contr = var_handler(_resolve_type(contr, line, level + 1, var_handler)) if isinstance(contr, _NotCalled): raise SystemError("Container types must exist:", repr(contr)) contr = to_string(contr) pieces = [] for part in _parse_arglist(thing): - part = var_handler(_resolve_type(part, line, level+1, var_handler)) + part = var_handler(_resolve_type(part, line, level + 1, var_handler)) if isinstance(part, _NotCalled): # fix the tag (i.e. "Missing") by repr part = repr(part) @@ -313,8 +355,8 @@ def _resolve_type(thing, line, level, var_handler): result = f"{contr}[{thing}]" # PYSIDE-1538: Make sure that the eval does not crash. try: - return eval(result, namespace) - except Exception as e: + return eval(result, globals(), namespace) + except Exception: warnings.warn(f"""pyside_type_init:_resolve_type UNRECOGNIZED: {result!r} @@ -372,11 +414,11 @@ def calculate_props(line): name, ann = tup[:2] if ann == "...": name = "*args" if name.startswith("arg_") else "*" + name - # copy the pathed fields back + # copy the patched fields back ann = 'nullptr' # maps to None tup = name, ann arglist[idx] = tup - annotations[name] = _resolve_type(ann, line, 0, handle_argvar) + annotations[name] = _resolve_type(ann, line, 0, handle_argvar, parsed.funcname) if len(tup) == 3: default = _resolve_value(tup[2], ann, line) _defaults.append(default) @@ -393,9 +435,9 @@ def calculate_props(line): props.defaults = defaults props.kwdefaults = {} props.annotations = annotations - props.varnames = varnames = tuple(tup[0] for tup in arglist) + props.varnames = tuple(tup[0] for tup in arglist) funcname = parsed.funcname - shortname = funcname[funcname.rindex(".")+1:] + shortname = funcname[funcname.rindex(".") + 1:] props.name = shortname props.multi = parsed.multi fix_variables(props, line) @@ -441,7 +483,6 @@ def fix_variables(props, line): else: diff -= 1 if retvars: - rvs = [] retvars = list(handle_retvar(rv) if isinstance(rv, ArrayLikeVariable) else rv for rv in retvars) if len(retvars) == 1: @@ -449,7 +490,7 @@ def fix_variables(props, line): else: retvars_str = ", ".join(map(to_string, retvars)) typestr = f"typing.Tuple[{retvars_str}]" - returntype = eval(typestr, namespace) + returntype = eval(typestr, globals(), namespace) props.annotations["return"] = returntype props.varnames = tuple(varnames) props.defaults = tuple(defaults) diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json index 4cbec4824..0f05aea8b 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json @@ -3,7 +3,7 @@ "Name": "Python", "QDocModule": "QtForPython", "QtUsage": "Used for Qt for Python in the signature extension.", - "Description": "Qt for Python is an add-on for Python. The signature packages of PySide uses certain copied and adapted source files (backport_inspect.py, typing27.py). See the folder sources/shiboken6/files.dir/shibokensupport/signature .", + "Description": "Qt for Python is an add-on for Python. The signature packages of PySide uses certain copied and adapted source files. See the folder sources/shiboken6/files.dir/shibokensupport .", "Homepage": "http://www.python.org/", "Version": "3.7.0", "LicenseId": "Python-2.0", |