aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/shibokenmodule/files.dir/shibokensupport
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/shibokenmodule/files.dir/shibokensupport')
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py4
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py248
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py59
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject16
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt43
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py4
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py150
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py65
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py247
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py4
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py304
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py334
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py110
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py158
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py719
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py552
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json13
17 files changed, 3030 insertions, 0 deletions
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py
new file mode 100644
index 000000000..e54bec75a
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py
@@ -0,0 +1,4 @@
+# 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
+
+# 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
new file mode 100644
index 000000000..7a0871ee7
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
@@ -0,0 +1,248 @@
+# 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
+
+# flake8: noqa F:821
+# flake8: noqa F:401
+
+"""
+__feature__.py (renamed to feature.py)
+
+This is the feature file for the Qt for Python project. There is some
+similarity to Python's `__future__` file, but also some distinction.
+
+The normal usage is like
+
+ from __feature__ import <feature_name> [, ...]
+ ...
+
+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 special meaning "ignore this module".
+"""
+
+import inspect
+import sys
+from contextlib import contextmanager
+
+all_feature_names = [
+ "snake_case",
+ "true_property",
+ "_feature_04",
+ "_feature_08",
+ "_feature_10",
+ "_feature_20",
+ "_feature_40",
+ "_feature_80",
+]
+
+__all__ = ["all_feature_names", "info", "reset", "set_selection"] + all_feature_names
+
+snake_case = 0x01
+true_property = 0x02
+_feature_04 = 0x04
+_feature_08 = 0x08
+_feature_10 = 0x10
+_feature_20 = 0x20
+_feature_40 = 0x40
+_feature_80 = 0x80
+
+# let's remove the dummies for the normal user
+_really_all_feature_names = all_feature_names[:]
+all_feature_names = list(_ for _ in all_feature_names if not _.startswith("_"))
+
+# Install an import hook that controls the `__feature__` import.
+"""
+Note: This are two imports.
+>>> import dis
+>>> def test():
+... from __feature__ import snake_case
+...
+>>> dis.dis(test)
+ 2 0 LOAD_CONST 1 (0)
+ 2 LOAD_CONST 2 (('snake_case',))
+ 4 IMPORT_NAME 0 (__feature__)
+ 6 IMPORT_FROM 1 (snake_case)
+ 8 STORE_FAST 0 (snake_case)
+ 10 POP_TOP
+ 12 LOAD_CONST 0 (None)
+ 14 RETURN_VALUE
+"""
+
+"""
+The redirection of __import__
+-----------------------------
+
+This construction avoids irritating extra redirections in tracebacks.
+
+The normal `__import__` is replaced by C function `__feature_import__`.
+`__feature_import__` calls this `feature_import` function first, to
+see if a feature is requested. If this function does not handle it, it returns
+None to indicate that a normal import should be performed, and
+`__feature_import__` calls the original import `__orig_import__`.
+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)
+
+ if name == "__feature__" and args[2]:
+ __init__()
+
+ # This is an `import from` statement that corresponds to `IMPORT_NAME`.
+ # The following `IMPORT_FROM` will handle errors. (Confusing, ofc.)
+ flag = get_select_id(args[2])
+
+ flag |= existing & 255 if isinstance(existing, int) and existing >= 0 else 0
+ pyside_feature_dict[importing_module] = flag
+
+ if importing_module == "__main__":
+ # We need to add all modules here which should see __feature__.
+ pyside_feature_dict["rlcompleter"] = flag
+
+ # Initialize feature (multiple times allowed) and clear cache.
+ sys.modules["PySide6.QtCore"].__init_feature__()
+ return sys.modules["__feature__"]
+ # 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, 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):
+ """
+ Internal use: Set the feature directly by Id.
+ Id == -1: ignore this module in switching.
+ """
+ mod_name = mod_name or sys._getframe(1).f_globals['__name__']
+ __init__()
+ # Reset the features to the given id
+ flag = 0
+ if isinstance(select_id, int):
+ flag = select_id & 255
+ pyside_feature_dict[mod_name] = flag
+ sys.modules["PySide6.QtCore"].__init_feature__()
+ 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
+ """
+ mod_name = mod_name or sys._getframe(1).f_globals['__name__']
+ flag = pyside_feature_dict.get(mod_name, 0)
+ return _current_selection(flag)
+
+
+def _current_selection(flag):
+ names = []
+ if flag >= 0:
+ for idx, name in enumerate(_really_all_feature_names):
+ if (1 << idx) & flag:
+ names.append(name)
+ return names
+
+
+def get_select_id(feature_names):
+ flag = 0
+ for feature in feature_names:
+ if feature in _really_all_feature_names:
+ flag |= globals()[feature]
+ else:
+ raise SyntaxError(f"PySide feature {feature} is not defined")
+ return flag
+
+
+@contextmanager
+def force_selection(select_id, mod_name):
+ """
+ This function is for generating pyi files with features.
+ The selection id is set globally after performing the unswitched
+ import.
+
+ """
+ __init__()
+ saved_feature_dict = pyside_feature_dict.copy()
+ for name in pyside_feature_dict:
+ set_selection(0, name)
+ __import__(mod_name)
+ for name in pyside_feature_dict.copy():
+ set_selection(select_id, name)
+ try:
+ yield
+ finally:
+ pyside_feature_dict.update(saved_feature_dict)
+
+#eof
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py
new file mode 100644
index 000000000..f7190b12f
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py
@@ -0,0 +1,59 @@
+# 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
+
+"""
+fix-complaints.py
+
+This module fixes the buildbot messages of external python files.
+Run it once after copying a new version. It is idem-potent, unless
+you are changing messages (what I did, of course :-) .
+"""
+
+import glob
+from pathlib import Path
+
+patched_file_patterns = "backport_inspect.py typing27.py python_minilib_*.py"
+
+offending_words = {
+ "behavio""ur": "behavior",
+ "at""least": "at_least",
+ "reali""sed": "realized",
+}
+
+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()
+ dup = lines[:]
+ for idx, line in enumerate(lines):
+ for word, repl in offending_words.items():
+ if word in line:
+ lines[idx] = line.replace(word, repl)
+ print(f"line:{line!r} {word!r}->{repl!r}")
+ if lines[0].strip() != utf8_line.strip():
+ lines[:0] = [utf8_line, "\n"]
+ if lines[1] != marker_line:
+ lines[1:1] = marker_line
+ if lines != dup:
+ with open(fname, "w") as f:
+ f.write("".join(lines))
+
+
+def doit():
+ dirname = Path(__file__).parent
+ patched_files = []
+ for name in patched_file_patterns.split():
+ pattern = dirname / name
+ patched_files += glob.glob(pattern)
+ for fname in patched_files:
+ print("Working on", fname)
+ patch_file(fname)
+
+
+if __name__ == "__main__":
+ doit()
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject
new file mode 100644
index 000000000..7147a4148
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject
@@ -0,0 +1,16 @@
+{
+ "files": ["__init__.py",
+ "feature.py",
+ "fix-complaints.py",
+ "signature/__init__.py",
+ "signature/errorhandler.py",
+ "signature/importhandler.py",
+ "signature/layout.py",
+ "signature/lib/__init__.py",
+ "signature/lib/enum_sig.py",
+ "signature/lib/pyi_generator.py",
+ "signature/lib/tool.py",
+ "signature/loader.py",
+ "signature/mapping.py",
+ "signature/parser.py"]
+}
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt
new file mode 100644
index 000000000..be42010dd
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt
@@ -0,0 +1,43 @@
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py
new file mode 100644
index 000000000..bebf56c7e
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py
@@ -0,0 +1,4 @@
+# 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
+
+__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
new file mode 100644
index 000000000..c2a19efef
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
@@ -0,0 +1,150 @@
+# 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
+
+# flake8: noqa E:721
+
+"""
+errorhandler.py
+
+This module handles the TypeError messages which were previously
+produced by the generated C code.
+
+This version is at least consistent with the signatures, which
+are created by the same module.
+
+Experimentally, we are trying to guess those errors which are
+just the wrong number of elements in an iterator.
+At the moment, it is unclear whether the information given is
+enough to produce a useful ValueError.
+
+This matter will be improved in a later version.
+"""
+
+import collections.abc
+import typing
+
+from shibokensupport.signature import get_signature
+from shibokensupport.signature.mapping import namespace
+from textwrap import dedent
+
+
+def qt_isinstance(inst, the_type):
+ if the_type == 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(f"FIXME qt_isinstance({inst}, {the_type}):", e)
+ return False
+
+
+def matched_type(args, sigs):
+ for sig in sigs:
+ params = list(sig.parameters.values())
+ if len(args) > len(params):
+ continue
+ if len(args) < len(params):
+ k = len(args)
+ if params[k].default is params[k].empty:
+ # this is a necessary parameter, so it fails.
+ continue
+ if all(qt_isinstance(arg, param.annotation) for arg, param in zip(args, params)):
+ return sig
+ return None
+
+
+def seterror_argument(args, func_name, info):
+ func = None
+ try:
+ func = eval(func_name, namespace)
+ except Exception as e:
+ 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():
+ msg = f"{func_name}(): got multiple values for keyword argument '{info}'"
+ else:
+ 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
+ sigs = get_signature(func, "typeerror")
+ if not sigs:
+ msg = f"{func_name}({args}) is wrong (missing signature)"
+ return TypeError, msg
+ if type(sigs) != list:
+ sigs = [sigs]
+ if type(args) != tuple:
+ args = (args,)
+ # temp!
+ found = matched_type(args, sigs)
+ if found:
+ msg = dedent(f"""
+ {func_name!r} called with wrong argument values:
+ {func_name}{args}
+ Found signature:
+ {func_name}{found}
+ """).strip()
+ return ValueError, msg
+ type_str = ", ".join(type(arg).__name__ for arg in args)
+ msg = dedent(f"""
+ {func_name!r} called with wrong argument types:
+ {func_name}({type_str})
+ Supported signatures:
+ """).strip()
+ for sig in sigs:
+ msg += f"\n {func_name}{sig}"
+ # We don't raise the error here, to avoid the loader in the traceback.
+ return TypeError, msg
+
+
+def check_string_type(s):
+ return isinstance(s, str)
+
+
+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
+ if type(sigs) != list:
+ sigs = [sigs]
+ try:
+ func_name = func.__name__
+ except AttributeError:
+ func_name = func.__func__.__name__
+ sigtext = "\n".join(func_name + str(sig) for sig in sigs)
+ msg = f"{sigtext}\n\n{existing_doc}" if check_string_type(existing_doc) else sigtext
+ return msg
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
new file mode 100644
index 000000000..bae264294
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
@@ -0,0 +1,65 @@
+# 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
+
+"""
+importhandler.py
+
+This module handles special actions after the import of PySide modules.
+The reason for this was the wish to replace some deprecated functions
+by a Python implementation that gives a warning.
+
+It provides a framework to safely call functions outside of files.dir,
+because the implementation of deprecated functions should be visible
+to the users (in the hope they don't use it any longer <wink>).
+
+As a first approach, the function finish_import redirects to
+PySide6/support/deprecated.py . There can come other extensions as well.
+"""
+
+try:
+ from PySide6.support import deprecated
+ have_deprecated = True
+except ImportError:
+ have_deprecated = False
+
+
+# called by loader.py from signature.cpp
+def finish_import(module):
+ if have_deprecated and module.__name__.startswith("PySide6."):
+ try:
+ name = "fix_for_" + module.__name__.split(".")[1]
+ func = getattr(deprecated, name, None)
+ if func:
+ func(module)
+ except Exception as e:
+ name = e.__class__.__qualname__
+ print(72 * "*")
+ print("Error in deprecated.py, ignored:")
+ print(f" {name}: {e}")
+
+
+"""
+A note for people who might think this could be written in pure Python:
+
+Sure, by an explicit import of the modules to patch, this is no problem.
+But in the general case, a module should only be imported on user
+request and not because we want to patch it. So I started over.
+
+I then tried to do it on demand by redirection of the __import__ function.
+Things worked quite nicely as it seemed, but at second view this solution
+was much less appealing.
+
+Reason:
+If someone executes as the first PySide statement
+
+ from PySide6 import QtGui
+
+then this import is already running. We can see the other imports like the
+diverse initializations and QtCore, because it is triggered by import of
+QtGui. But the QtGui import can not be seen at all!
+
+With a lot of effort, sys.setprofile() and stack inspection with the inspect
+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.
+"""
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
new file mode 100644
index 000000000..0e781cbcb
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
@@ -0,0 +1,247 @@
+# 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
+
+"""
+layout.py
+
+The signature module now has the capability to configure
+differently formatted versions of signatures. The default
+layout is known from the "__signature__" attribute.
+
+The function "get_signature(ob, modifier=None)" produces the same
+signatures by default. By passing different modifiers, you
+can select different layouts.
+
+This module configures the different layouts which can be used.
+It also implements them in this file. The configurations are
+used literally as strings like "signature", "existence", etc.
+"""
+
+import inspect
+import typing
+
+from types import SimpleNamespace
+from textwrap import dedent
+from shibokensupport.signature.mapping import ellipsis
+
+
+class SignatureLayout(SimpleNamespace):
+ """
+ Configure a signature.
+
+ The layout of signatures can have different layouts which are
+ controlled by keyword arguments:
+
+ definition=True Determines if self will generated.
+ defaults=True
+ ellipsis=False Replaces defaults by "...".
+ return_annotation=True
+ parameter_names=True False removes names before ":".
+ """
+ allowed_keys = SimpleNamespace(definition=True,
+ defaults=True,
+ ellipsis=False,
+ return_annotation=True,
+ parameter_names=True)
+ allowed_values = True, False
+
+ def __init__(self, **kwds):
+ args = SimpleNamespace(**self.allowed_keys.__dict__)
+ args.__dict__.update(kwds)
+ self.__dict__.update(args.__dict__)
+ err_keys = list(set(self.__dict__) - set(self.allowed_keys.__dict__))
+ if err_keys:
+ self._attributeerror(err_keys)
+ err_values = list(set(self.__dict__.values()) - set(self.allowed_values))
+ if err_values:
+ self._valueerror(err_values)
+
+ def __setattr__(self, key, value):
+ if key not in self.allowed_keys.__dict__:
+ self._attributeerror([key])
+ if value not in self.allowed_values:
+ self._valueerror([value])
+ self.__dict__[key] = value
+
+ def _attributeerror(self, err_keys):
+ err_keys = ", ".join(err_keys)
+ allowed_keys = ", ".join(self.allowed_keys.__dict__.keys())
+ raise AttributeError(dedent(f"""\
+ Not allowed: '{err_keys}'.
+ The only allowed keywords are '{allowed_keys}'.
+ """))
+
+ def _valueerror(self, err_values):
+ err_values = ", ".join(map(str, err_values))
+ allowed_values = ", ".join(map(str, self.allowed_values))
+ raise ValueError(dedent(f"""\
+ Not allowed: '{err_values}'.
+ 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()
+
+existence = SignatureLayout(definition=False,
+ defaults=False,
+ return_annotation=False,
+ parameter_names=False)
+
+hintingstub = SignatureLayout(ellipsis=True)
+
+typeerror = SignatureLayout(definition=False,
+ return_annotation=False,
+ parameter_names=False)
+
+
+def define_nameless_parameter():
+ """
+ Create Nameless Parameters
+
+ A nameless parameter has a reduced string representation.
+ This is done by cloning the parameter type and overwriting its
+ __str__ method. The inner structure is still a valid parameter.
+ """
+ def __str__(self):
+ # for Python 2, we must change self to be an instance of P
+ klass = self.__class__
+ self.__class__ = P
+ txt = P.__str__(self)
+ self.__class__ = klass
+ txt = txt[txt.index(":") + 1:].strip() if ":" in txt else txt
+ return txt
+
+ P = inspect.Parameter
+ newname = "NamelessParameter"
+ bases = P.__bases__
+ body = dict(P.__dict__) # get rid of mappingproxy
+ if "__slots__" in body:
+ # __slots__ would create duplicates
+ for name in body["__slots__"]:
+ del body[name]
+ body["__str__"] = __str__
+ return type(newname, bases, body)
+
+
+NamelessParameter = define_nameless_parameter()
+
+"""
+Note on the "Optional" feature:
+
+When an annotation has a default value that is None, then the
+type has to be wrapped into "typing.Optional".
+
+Note that only the None value creates an Optional expression,
+because the None leaves the domain of the variable.
+Defaults like integer values are ignored: They stay in the domain.
+
+That information would be lost when we use the "..." convention.
+
+Note that the typing module has the remarkable expansion
+
+ Optional[T] is Union[T, NoneType]
+
+We want to avoid that when generating the .pyi file.
+This is done by a regex in pyi_generator.py .
+The following would work in Python 3, but this is a version-dependent
+hack that also won't work in Python 2 and would be _very_ complex.
+"""
+# import sys
+# if sys.version_info[0] == 3:
+# class hugo(list):pass
+# typing._normalize_alias["hugo"] = "Optional"
+# Optional = typing._alias(hugo, typing.T, inst=False)
+# else:
+# Optional = typing.Optional
+
+
+def make_signature_nameless(signature):
+ """
+ Make a Signature Nameless
+
+ We use an existing signature and change the type of its parameters.
+ The signature looks different, but is totally intact.
+ """
+ for key in signature.parameters.keys():
+ signature.parameters[key].__class__ = NamelessParameter
+
+
+_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:
+ # empty signatures string
+ return
+ if isinstance(props["multi"], list):
+ # multi sig: call recursively
+ return list(create_signature(elem, key)
+ for elem in props["multi"])
+ if type(key) is tuple:
+ _, modifier = key
+ else:
+ _, modifier = key, "signature"
+
+ layout = globals()[modifier] # lookup of the modifier in this module
+ if not isinstance(layout, SignatureLayout):
+ raise SystemError("Modifiers must be names of a SignatureLayout "
+ "instance")
+
+ # this is the basic layout of a signature
+ varnames = props["varnames"]
+ if layout.definition:
+ # PYSIDE-1328: We no longer use info from the sig_kind which is
+ # more complex for multiple signatures. We now get `self` from the
+ # parser.
+ pass
+ else:
+ if varnames and varnames[0] in ("self", "cls"):
+ varnames = varnames[1:]
+
+ # calculate the modifications
+ defaults = props["defaults"][:]
+ if not layout.defaults:
+ defaults = ()
+ annotations = props["annotations"].copy()
+ if not layout.return_annotation and "return" in annotations:
+ del annotations["return"]
+
+ # Build a signature.
+ kind = inspect._POSITIONAL_OR_KEYWORD
+ params = []
+ for idx, name in enumerate(varnames):
+ if name.startswith("**"):
+ kind = _VAR_KEYWORD
+ elif name.startswith("*"):
+ kind = _VAR_POSITIONAL
+ ann = annotations.get(name, _empty)
+ if ann in ("self", "cls"):
+ ann = _empty
+ name = name.lstrip("*")
+ defpos = idx - len(varnames) + len(defaults)
+ default = defaults[defpos] if defpos >= 0 else _empty
+ if default is None:
+ ann = typing.Optional[ann]
+ if default is not _empty and layout.ellipsis:
+ default = ellipsis
+ param = inspect.Parameter(name, kind, annotation=ann, default=default)
+ params.append(param)
+ if kind == _VAR_POSITIONAL:
+ kind = _KEYWORD_ONLY
+ sig = inspect.Signature(params,
+ return_annotation=annotations.get('return', _empty),
+ __validate_parameters__=False)
+
+ # the special case of nameless parameters
+ if not layout.parameter_names:
+ make_signature_nameless(sig)
+ return sig
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py
new file mode 100644
index 000000000..e54bec75a
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py
@@ -0,0 +1,4 @@
+# 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
+
+# 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
new file mode 100644
index 000000000..5650e2bc1
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
@@ -0,0 +1,304 @@
+# 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
+
+"""
+enum_sig.py
+
+Enumerate all signatures of a class.
+
+This module separates the enumeration process from the formatting.
+It is not easy to adhere to this protocol, but in the end, it paid off
+by producing a lot of clarity.
+"""
+
+import inspect
+import sys
+import types
+from shibokensupport.signature import get_signature as get_sig
+
+
+"""
+PYSIDE-1599: Making sure that pyi files always are tested.
+
+A new problem popped up when supporting true properties:
+When there exists an item named "property", then we cannot use
+the builtin `property` as decorator, but need to prefix it with "builtins".
+
+We scan for such a name in a class, and if there should a property be
+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):
+ """
+ ExactEnumerator enumerates all signatures in a module as they are.
+
+ This class is used for generating complete listings of all signatures.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def __init__(self, formatter, result_type=dict):
+ global EnumMeta, Signal, SignalInstance
+ try:
+ # Lazy import
+ from PySide6.QtCore import Qt, Signal, SignalInstance
+ EnumMeta = type(Qt.Key)
+ except ImportError:
+ EnumMeta = Signal = SignalInstance = None
+
+ self.fmt = formatter
+ self.result_type = result_type
+ self.fmt.level = 0
+ self.fmt.is_method = self.is_method
+ self.collision_candidates = {"property", "overload"}
+
+ def is_method(self):
+ """
+ Is this function a method?
+ We check if it is a simple function.
+ """
+ tp = type(self.func)
+ return tp not in _normal_functions
+
+ def section(self):
+ if hasattr(self.fmt, "section"):
+ self.fmt.section()
+
+ def module(self, mod_name):
+ __import__(mod_name)
+ self.fmt.mod_name = mod_name
+ with self.fmt.module(mod_name):
+ module = sys.modules[mod_name]
+ members = inspect.getmembers(module, inspect.isclass)
+ functions = inspect.getmembers(module, inspect.isroutine)
+ ret = self.result_type()
+ self.fmt.class_name = None
+ for class_name, klass in members:
+ self.collision_track = set()
+ ret.update(self.klass(class_name, klass))
+ if len(members):
+ self.section()
+ for func_name, func in functions:
+ ret.update(self.function(func_name, func))
+ if len(functions):
+ self.section()
+ return ret
+
+ 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 std::shared_ptr<QQuickItemGrabResult >:
+ # We simply skip over this class.
+ return ret
+ bases_list = []
+ for base in klass.__bases__:
+ name = base.__qualname__
+ if name not in ("object", "property", "type"):
+ name = base.__module__ + "." + name
+ bases_list.append(name)
+ bases_str = ', '.join(bases_list)
+ class_str = f"{class_name}({bases_str})"
+ # class_members = inspect.getmembers(klass)
+ # gives us also the inherited things.
+ class_members = sorted(list(klass.__dict__.items()))
+ subclasses = []
+ functions = []
+ enums = []
+ properties = []
+ signals = []
+ attributes = {}
+
+ for thing_name, thing in class_members:
+ 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):
+ func_name = thing_name.split(".")[0] # remove ".overload"
+ functions.append((func_name, thing))
+ elif type(type(thing)) is EnumMeta:
+ # take the real enum name, not what is in the dict
+ 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)
+ # 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 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
+ self.fmt.class_name = class_name
+ if hasattr(self.fmt, "enum"):
+ # this is an optional feature
+ if len(enums):
+ self.section()
+ for enum_name, enum_class_name, value in enums:
+ 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:
+ save = self.collision_track.copy()
+ ret.update(self.klass(subclass_name, subclass))
+ self.collision_track = save
+ self.fmt.class_name = class_name
+ if len(subclasses):
+ self.section()
+ ret.update(self.function("__init__", klass))
+ for func_name, func in func_prop:
+ if func_name != "__init__":
+ if isinstance(func, property):
+ ret.update(self.fproperty(func_name, func))
+ else:
+ ret.update(self.function(func_name, func))
+ self.fmt.level -= 1
+ if len(func_prop):
+ self.section()
+ return ret
+
+ @staticmethod
+ def get_signature(func):
+ return get_sig(func)
+
+ def function(self, func_name, func, decorator=None):
+ self.func = func # for is_method()
+ ret = self.result_type()
+ if decorator in self.collision_track:
+ decorator = f"builtins.{decorator}"
+ signature = self.get_signature(func, decorator)
+ if signature is not None:
+ with self.fmt.function(func_name, signature, decorator) as key:
+ ret[key] = signature
+ del self.func
+ return ret
+
+ def fproperty(self, prop_name, prop):
+ ret = self.function(prop_name, prop.fget, type(prop).__qualname__)
+ if prop.fset:
+ ret.update(self.function(prop_name, prop.fset, f"{prop_name}.setter"))
+ if prop.fdel:
+ ret.update(self.function(prop_name, prop.fdel, f"{prop_name}.deleter"))
+ return ret
+
+
+def stringify(signature):
+ if isinstance(signature, list):
+ # remove duplicates which still sometimes occour:
+ ret = set(stringify(sig) for sig in signature)
+ return sorted(ret) if len(ret) > 1 else list(ret)[0]
+ return tuple(str(pv) for pv in signature.parameters.values())
+
+
+class SimplifyingEnumerator(ExactEnumerator):
+ """
+ SimplifyingEnumerator enumerates all signatures in a module filtered.
+
+ There are no default values, no variable
+ names and no self parameter. Only types are present after simplification.
+ The functions 'next' resp. '__next__' are removed
+ to make the output identical for Python 2 and 3.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = get_sig(func, 'existence')
+ sig = stringify(signature) if signature is not None else None
+ if sig is not None and func_name not in ("next", "__next__", "__div__"):
+ with self.fmt.function(func_name, sig) as key:
+ ret[key] = sig
+ return ret
+
+
+class HintingEnumerator(ExactEnumerator):
+ """
+ HintingEnumerator enumerates all signatures in a module slightly changed.
+
+ This class is used for generating complete listings of all signatures for
+ hinting stubs. Only default values are replaced by "...".
+ """
+
+ def __init__(self, *args, **kwds):
+ super().__init__(*args, **kwds)
+ # We need to provide default signatures for class properties.
+ cls_param = inspect.Parameter("cls", inspect._POSITIONAL_OR_KEYWORD)
+ set_param = inspect.Parameter("arg_1", inspect._POSITIONAL_OR_KEYWORD, annotation=object)
+ self.getter_sig = inspect.Signature([cls_param], return_annotation=object)
+ self.setter_sig = inspect.Signature([cls_param, set_param])
+ self.deleter_sig = inspect.Signature([cls_param])
+
+ def get_signature(self, func, decorator=None):
+ # Class properties don't have signature support (yet).
+ # In that case, produce a fake one.
+ sig = get_sig(func, "hintingstub")
+ if not sig:
+ if decorator:
+ if decorator.endswith(".setter"):
+ sig = self.setter_sig
+ elif decorator.endswith(".deleter"):
+ sig = self.deleter_sig
+ else:
+ sig = self.getter_sig
+ return sig
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
new file mode 100644
index 000000000..ce12dd6c8
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
@@ -0,0 +1,334 @@
+LICENSE_TEXT = """
+# 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
+"""
+
+# flake8: noqa E:402
+
+"""
+pyi_generator.py
+
+This script generates .pyi files for arbitrary modules.
+"""
+
+import argparse
+import io
+import logging
+import os
+import re
+import sys
+import typing
+
+from pathlib import Path
+from contextlib import contextmanager
+from textwrap import dedent
+
+from shibokensupport.signature.lib.enum_sig import HintingEnumerator
+from shibokensupport.signature.lib.tool import build_brace_pattern
+
+# Can we use forward references?
+USE_PEP563 = sys.version_info[:2] >= (3, 7)
+
+indent = " " * 4
+
+
+class Writer(object):
+ def __init__(self, outfile, *args):
+ self.outfile = outfile
+ self.history = [True, True]
+
+ def print(self, *args, **kw):
+ # controlling too much blank lines
+ if self.outfile:
+ if args == () or args == ("",):
+ # We use that to skip too many blank lines:
+ if self.history[-2:] == [True, True]:
+ return
+ print("", file=self.outfile, **kw)
+ self.history.append(True)
+ else:
+ print(*args, file=self.outfile, **kw)
+ self.history.append(False)
+
+
+class Formatter(Writer):
+ """
+ Formatter is formatting the signature listing of an enumerator.
+
+ It is written as context managers in order to avoid many callbacks.
+ The separation in formatter and enumerator is done to keep the
+ 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:
+ """
+ def __repr__(self):
+ if self.__covariant__:
+ prefix = '+'
+ elif self.__contravariant__:
+ prefix = '-'
+ else:
+ prefix = '~'
+ return prefix + self.__name__
+ """
+ def _typevar__repr__(self):
+ return f"typing.{self.__name__}"
+ # 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.
+ # See also the comment in layout.py .
+ brace_pat = build_brace_pattern(3, ",")
+ 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
+ # self.level is maintained by enum_sig.py
+ # self.is_method() is true for non-plain functions.
+
+ def section(self):
+ if self.level == 0:
+ self.print()
+ self.print()
+
+ @contextmanager
+ def module(self, mod_name):
+ self.mod_name = mod_name
+ txt = f"""\
+ # Module `{mod_name}`
+
+ <<IMPORTS>>
+ """
+ self.print(dedent(txt))
+ yield
+
+ @contextmanager
+ def klass(self, class_name, class_str):
+ spaces = indent * self.level
+ while "." in class_name:
+ class_name = class_name.split(".", 1)[-1]
+ class_str = class_str.split(".", 1)[-1]
+ if self.have_body:
+ self.print(f"{spaces}class {class_str}:")
+ else:
+ self.print(f"{spaces}class {class_str}: ...")
+ yield
+
+ @contextmanager
+ def function(self, func_name, signature, decorator=None):
+ if func_name == "__init__":
+ self.print()
+ key = func_name
+ spaces = indent * self.level
+ if isinstance(signature, list):
+ for sig in signature:
+ self.print(f'{spaces}@overload')
+ self._function(func_name, sig, spaces)
+ else:
+ self._function(func_name, signature, spaces, decorator)
+ if func_name == "__init__":
+ self.print()
+ yield key
+
+ def _function(self, func_name, signature, spaces, decorator=None):
+ if decorator:
+ # In case of a PyClassProperty the classmethod decorator is not used.
+ self.print(f'{spaces}@{decorator}')
+ elif self.is_method() and "self" not in signature.parameters:
+ kind = "class" if "cls" in signature.parameters else "static"
+ self.print(f'{spaces}@{kind}method')
+ signature = self.optional_replacer(signature)
+ self.print(f'{spaces}def {func_name}{signature}: ...')
+
+ @contextmanager
+ def enum(self, class_name, enum_name, value):
+ spaces = indent * self.level
+ hexval = hex(value)
+ 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 = [
+ (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
+ """
+ nfs = []
+ for mod, imports in from_struct:
+ lis = []
+ nfs.append((mod, lis))
+ for each in imports:
+ # 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
+
+
+def find_module(import_name, outpath, from_pyside):
+ """
+ Find a module either directly by import, or use the full path,
+ add the path to sys.path and import then.
+ """
+ if from_pyside:
+ # internal mode for generate_pyi.py
+ plainname = import_name.split(".")[-1]
+ outfilepath = Path(outpath) / f"{plainname}.pyi"
+ return import_name, plainname, outfilepath
+ # we are alone in external module mode
+ p = Path(import_name).resolve()
+ if not p.exists():
+ raise ValueError(f"File {p} does not exist.")
+ if not outpath:
+ outpath = p.parent
+ # temporarily add the path and do the import
+ sys.path.insert(0, os.fspath(p.parent))
+ plainname = p.name.split(".")[0]
+ __import__(plainname)
+ sys.path.pop(0)
+ return plainname, plainname, Path(outpath) / (plainname + ".pyi")
+
+
+def generate_pyi(import_name, outpath, options):
+ """
+ Generates a .pyi file.
+ """
+ import_name, plainname, outfilepath = find_module(import_name, outpath, options._pyside_call)
+ top = __import__(import_name)
+ 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}`")
+
+ outfile = io.StringIO()
+ fmt = Formatter(outfile, options)
+ fmt.print(LICENSE_TEXT.strip())
+ if USE_PEP563:
+ fmt.print("from __future__ import annotations")
+ fmt.print()
+ fmt.print(dedent(f'''\
+ """
+ This file contains the exact signatures for all functions in module
+ {import_name}, except for defaults which are replaced by "...".
+ """
+ '''))
+ HintingEnumerator(fmt).module(import_name)
+ fmt.print("# eof")
+ # Postprocess: resolve the imports
+ if options._pyside_call:
+ global PySide6
+ import PySide6
+ with outfilepath.open("w") as realfile:
+ wr = Writer(realfile)
+ outfile.seek(0)
+ while True:
+ line = outfile.readline()
+ if not line:
+ break
+ line = line.rstrip()
+ # 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}")
+ else:
+ wr.print(f"from {mod} import {import_args}")
+ wr.print()
+ wr.print()
+ wr.print("NoneType: TypeAlias = type[None]")
+ wr.print()
+ else:
+ wr.print(line)
+ if not options.quiet:
+ options.logger.info(f"Generated: {outfilepath}")
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description=dedent("""\
+ pyi_generator.py
+ ----------------
+
+ This script generates the .pyi file for an arbitrary module.
+ You pass in the full path of a compiled, importable module.
+ 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)") # noqa E:128
+ parser.add_argument("--quiet", action="store_true", help="Run quietly")
+ parser.add_argument("--outpath",
+ help="the output directory (default = location of module binary)") # noqa E:128
+ options = parser.parse_args()
+ module = options.module
+ outpath = options.outpath
+
+ qtest_env = os.environ.get("QTEST_ENVIRONMENT", "")
+ logging.basicConfig(level=logging.DEBUG if qtest_env else logging.INFO)
+ logger = logging.getLogger("pyi_generator")
+
+ if outpath and not Path(outpath).exists():
+ os.makedirs(outpath)
+ logger.info(f"+++ Created path {outpath}")
+ options._pyside_call = False
+ options.is_ci = qtest_env == "ci"
+
+ 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
new file mode 100644
index 000000000..979dcf4ce
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
@@ -0,0 +1,110 @@
+# 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
+
+"""
+tool.py
+
+Some useful stuff, see below.
+On the function with_metaclass see the answer from Martijn Pieters on
+https://stackoverflow.com/questions/18513821/python-metaclass-understanding-the-with-metaclass
+"""
+
+from inspect import currentframe
+from textwrap import dedent
+
+
+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.
+ """
+ assert type(separators) is str
+
+ def escape(txt):
+ return "".join("\\" + c for c in txt)
+
+ ro, rc = round_ = "()"
+ so, sc = square = "[]"
+ co, cc = curly = "CD" # noqa E:201 we insert "{}", later...
+ ao, ac = angle = "<>" # noqa E:201
+ q2, bs, q1 = '"', "\\", "'"
+ allpat = round_ + square + curly + angle
+ __ = " "
+ ro, rc, so, sc, co, cc, ao, ac, separators, q2, bs, q1, allpat = map(
+ escape, (ro, rc, so, sc, co, cc, ao, ac, separators, q2, bs, q1, allpat))
+
+ no_brace_sep_q = fr"[^{allpat}{separators}{q2}{bs}{q1}]"
+ no_quot2 = fr"(?: [^{q2}{bs}] | {bs}. )*"
+ no_quot1 = fr"(?: [^{q1}{bs}] | {bs}. )*"
+ pattern = dedent(r"""
+ (
+ (?: {__} {no_brace_sep_q}
+ | {q2} {no_quot2} {q2}
+ | {q1} {no_quot1} {q1}
+ | {ro} {replacer} {rc}
+ | {so} {replacer} {sc}
+ | {co} {replacer} {cc}
+ | {ao} {replacer} {ac}
+ )+
+ )
+ """)
+ no_braces_q = f"[^{allpat}{q2}{bs}{q1}]*"
+ repeated = dedent(r"""
+ {indent} (?: {__} {no_braces_q}
+ {indent} | {q2} {no_quot2} {q2}
+ {indent} | {q1} {no_quot1} {q1}
+ {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", "}")
+
+
+# Copied from the six module:
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass."""
+ # This requires a bit of explanation: the basic idea is to make a dummy
+ # metaclass for one level of class instantiation that replaces itself with
+ # the actual metaclass.
+ class metaclass(type):
+
+ def __new__(cls, name, this_bases, d):
+ return meta(name, bases, d)
+
+ @classmethod
+ def __prepare__(cls, name, this_bases):
+ return meta.__prepare__(name, bases)
+ return type.__new__(metaclass, 'temporary_class', (), {})
+
+
+# A handy tool that shows the current line number and indents.
+def lno(level):
+ lineno = currentframe().f_back.f_lineno
+ spaces = level * " "
+ return f"{lineno}{spaces}"
+
+# eof
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py
new file mode 100644
index 000000000..fb4c9eeca
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py
@@ -0,0 +1,158 @@
+# 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
+
+# flake8: noqa E:402
+# flake8: noqa F:401
+
+"""
+loader.py
+
+The loader has to load the signature module completely at startup,
+to make sure that the functions are available when needed.
+This is meanwhile necessary to make the '__doc__' attribute work correctly.
+
+It does not mean that everything is initialized in advance. Only the modules
+are loaded completely after 'import PySide6'.
+
+This version uses both a normal directory, but has also an embedded ZIP file
+as a fallback solution. The ZIP file is generated by 'embedding_generator.py'
+and embedded into 'signature.cpp' as "embed/signature.inc".
+
+Meanwhile, the ZIP file grew so much, that MSVC had problems
+with it's 64k string limit, so we had to break the string up.
+See 'zipped_string_sequence' in signature.cpp.
+"""
+
+import sys
+import os
+import traceback
+import types
+
+
+# name used in signature.cpp
+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
+ 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
+signature.get_signature = signature_bootstrap.get_signature
+# PYSIDE-1019: Publish the __feature__ dictionary.
+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
+ name = (override if override else module.__spec__.name).rsplit(".", 1)[-1]
+ # allow access as {package}.{name}
+ if package:
+ setattr(package, name, module)
+ # put into sys.modules as a package to allow all import options
+ fullname = f"{package.__spec__.name}.{name}" if package else name
+ module.__spec__.name = fullname
+ # publish new dotted name in sys.modules
+ sys.modules[fullname] = module
+
+
+def move_into_pyside_package():
+ import shibokensupport
+ import PySide6
+ try:
+ import PySide6.support
+ except ModuleNotFoundError:
+ # This can happen in the embedding case.
+ put_into_package(PySide6, shibokensupport, "support")
+ 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)
+ put_into_package(PySide6.support.signature, layout)
+ put_into_package(PySide6.support.signature, lib)
+ put_into_package(PySide6.support.signature, parser)
+ put_into_package(PySide6.support.signature, importhandler)
+ put_into_package(PySide6.support.signature.lib, enum_sig)
+ 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
+from shibokensupport.signature import lib
+from shibokensupport.signature import parser
+from shibokensupport.signature import importhandler
+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:
+ print("PySide6.support could not be imported. "
+ "This is a serious configuration error.", file=sys.stderr)
+ raise
+
+ 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
new file mode 100644
index 000000000..944a928e6
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -0,0 +1,719 @@
+# 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
+
+# flake8: noqa E:203
+
+"""
+mapping.py
+
+This module has the mapping from the pyside C-modules view of signatures
+to the Python representation.
+
+The PySide modules are not loaded in advance, but only after they appear
+in sys.modules. This minimizes the loading overhead.
+"""
+
+import os
+import struct
+import sys
+import typing
+
+from pathlib import Path
+from typing import TypeVar, Generic
+from _imp import is_builtin
+
+
+class ellipsis(object):
+ def __repr__(self):
+ return "..."
+
+
+ellipsis = ellipsis()
+Point = typing.Tuple[int, int]
+Variant = typing.Any
+QImageCleanupFunction = typing.Callable
+
+# unfortunately, typing.Optional[t] expands to typing.Union[t, NoneType]
+# Until we can force it to create Optional[t] again, we use this.
+NoneType = type(None)
+
+_S = TypeVar("_S")
+
+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
+ushort_max = 0xffff
+
+GL_COLOR_BUFFER_BIT = 0x00004000
+GL_NEAREST = 0x2600
+
+WId = int
+
+# from 5.9
+GL_TEXTURE_2D = 0x0DE1
+GL_RGBA = 0x1908
+
+
+class _NotCalled(str):
+ """
+ Wrap some text with semantics
+
+ This class is wrapped around text in order to avoid calling it.
+ There are three reasons for this:
+
+ - some instances cannot be created since they are abstract,
+ - some can only be created after qApp was created,
+ - some have an ugly __repr__ with angle brackets in it.
+
+ By using derived classes, good looking instances can be created
+ which can be used to generate source code or .pyi files. When the
+ real object is needed, the wrapper can simply be called.
+ """
+ def __repr__(self):
+ return f"{type(self).__name__}({self})"
+
+ def __call__(self):
+ from shibokensupport.signature.mapping import __dict__ as namespace
+ 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)".
+# 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.
+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.
+ def __repr__(self):
+ if USE_PEP563:
+ return _NotCalled.__repr__(self)
+ return f'{type(self).__name__}("{self}")'
+
+
+class Invalid(_NotCalled):
+ pass
+
+
+# Helper types
+class Default(_NotCalled):
+ pass
+
+
+class Instance(_NotCalled):
+ pass
+
+
+# Parameterized primitive variables
+class _Parameterized(object):
+ def __init__(self, type):
+ self.type = type
+ self.__name__ = self.__class__.__name__
+
+ 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)
+
+
+class Reloader(object):
+ """
+ Reloder class
+
+ This is a singleton class which provides the update function for the
+ shiboken and PySide classes.
+ """
+ def __init__(self):
+ self.sys_module_count = 0
+
+ @staticmethod
+ def module_valid(mod):
+ 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 bool(hasattr(mod, "__name__") and is_builtin(mod.__name__))
+
+ def update(self):
+ """
+ 'update' imports all binary modules which are already in sys.modules.
+ The reason is to follow all user imports without introducing new ones.
+ This function is called by pyside_type_init to adapt imports
+ when the number of imported modules has changed.
+ """
+ if self.sys_module_count == len(sys.modules):
+ return
+ self.sys_module_count = len(sys.modules)
+ g = globals()
+ # PYSIDE-1009: Try to recognize unknown modules in errorhandler.py
+ candidates = list(mod_name for mod_name in sys.modules.copy()
+ if self.module_valid(sys.modules[mod_name]))
+ for mod_name in candidates:
+ # 'top' is PySide6 when we do 'import PySide.QtCore'
+ # or Shiboken if we do 'import Shiboken'.
+ # Convince yourself that these two lines below have the same
+ # global effect as "import Shiboken" or "import PySide6.QtCore".
+ top = __import__(mod_name)
+ g[top.__name__] = top
+ proc_name = "init_" + mod_name.replace(".", "_")
+ if proc_name in g:
+ # Modules are in place, we can update the type_map.
+ g.update(g.pop(proc_name)())
+
+
+def check_module(mod):
+ # During a build, there exist the modules already as directories,
+ # although the '*.so' was not yet created. This causes a problem
+ # in Python 3, because it accepts folders as namespace modules
+ # without enforcing an '__init__.py'.
+ if not Reloader.module_valid(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,
+ "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[str]],
+ "PySequence": typing.Iterable, # important for numpy
+ "PyTypeObject": type,
+ "QChar": str,
+ "QHash": typing.Dict,
+ "qint16": int,
+ "qint32": int,
+ "qint64": int,
+ "qint8": int,
+ "int16_t": int,
+ "int32_t": int,
+ "int64_t": int,
+ "int8_t": int,
+ "intptr_t": int,
+ "uintptr_t": int,
+ "qintptr": int,
+ "qsizetype": int,
+ "QFunctionPointer": int,
+ "QList": ArrayLikeVariable,
+ "qlonglong": int,
+ "QMap": typing.Dict,
+ "QMultiHash": typing.Dict,
+ "QMultiMap": typing.Dict,
+ "QPair": typing.Tuple,
+ "qptrdiff": int,
+ "qreal": float,
+ "QSet": typing.Set,
+ "QString": str,
+ "QLatin1String": str,
+ "QStringView": str,
+ "QStringList": StringList,
+ "quint16": int,
+ "quint32": int,
+ "quint32": int,
+ "quint64": int,
+ "quint8": int,
+ "uint16_t": int,
+ "uint32_t": int,
+ "uint64_t": int,
+ "uint8_t": int,
+ "Union": typing.Union,
+ "quintptr": int,
+ "qulonglong": int,
+ "QVariant": Variant,
+ "QVector": typing.List,
+ "QSharedPointer": typing.Tuple,
+ "real": float,
+ "short": int,
+ "signed char": int,
+ "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,
+ "std.vector": typing.List,
+ "str": str,
+ "true": True,
+ "Tuple": typing.Tuple,
+ "uchar": int,
+ "uchar*": str,
+ "uint": int,
+ "ulong": int,
+ "ULONG_MAX": ulong_max,
+ "UINT64_MAX": 0xffffffff,
+ "unsigned char": int, # 5.9
+ "unsigned char*": str,
+ "unsigned int": int,
+ "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,
+ "ushort": int,
+ "void": int, # be more specific?
+ "WId": WId,
+ "zero(bytes)": b"",
+ "zero(Char)": 0,
+ "zero(float)": 0,
+ "zero(int)": 0,
+ "zero(object)": None,
+ "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:
+ "array double*" : ArrayLikeVariable(float),
+ "array float*" : ArrayLikeVariable(float),
+ "array GLint*" : ArrayLikeVariable(int),
+ "array GLuint*" : ArrayLikeVariable(int),
+ "array int*" : ArrayLikeVariable(int),
+ "array long long*" : ArrayLikeVariable(int),
+ "array long*" : ArrayLikeVariable(int),
+ "array short*" : ArrayLikeVariable(int),
+ "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
+ "array int8_t*" : ArrayLikeVariable(int),
+ "array uint8_t*" : ArrayLikeVariable(int),
+ "array int16_t*" : ArrayLikeVariable(int),
+ "array uint16_t*" : ArrayLikeVariable(int),
+ "array int32_t*" : ArrayLikeVariable(int),
+ "array uint32_t*" : ArrayLikeVariable(int),
+ "array intptr_t*" : ArrayLikeVariable(int),
+})
+
+type_map.update({
+ # Special cases:
+ "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*" : typing.Union[bytes, bytearray, memoryview],
+ "unsigned char*": typing.Union[bytes, bytearray, memoryview],
+})
+
+type_map.update({
+ # Handling variables that are returned, eventually as Tuples:
+ "PySide6.QtQml.atomic[bool]": ResultVariable(bool), # QmlIncubationController::incubateWhile()
+ "bool*" : ResultVariable(bool),
+ "float*" : ResultVariable(float),
+ "int*" : ResultVariable(int),
+ "long long*" : ResultVariable(int),
+ "long*" : ResultVariable(int),
+ "PStr*" : ResultVariable(str), # module sample
+ "qint32*" : ResultVariable(int),
+ "qint64*" : ResultVariable(int),
+ "qreal*" : ResultVariable(float),
+ "qsizetype*" : ResultVariable(int),
+ "QString*" : ResultVariable(str),
+ "qintptr*" : ResultVariable(int),
+ "quintptr*" : ResultVariable(int),
+ "quint16*" : ResultVariable(int),
+ "uint*" : ResultVariable(int),
+ "unsigned int*" : ResultVariable(int),
+ "QStringList*" : ResultVariable(StringList),
+})
+
+
+type_map.update({
+ # Hack, until improving the parser:
+ "[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({
+ "PyType": type,
+ "shiboken6.bool": bool,
+ "size_t": int,
+ })
+ return locals()
+
+
+def init_minimal():
+ type_map.update({
+ "MinBool": bool,
+ })
+ return locals()
+
+
+def init_sample():
+ import datetime
+ 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,
+ "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"),
+ "OddBool": bool,
+ "PStr": str,
+ "PyDate": datetime.date,
+ "PyBuffer": typing.Union[bytes, bytearray, memoryview],
+ "sample.bool": bool,
+ "sample.char": int,
+ "sample.double": float,
+ "sample.int": int,
+ "sample.ObjectType": object,
+ "sample.OddBool": bool,
+ "sample.Photon.TemplateBase[Photon.DuplicatorType]": sample.Photon.ValueDuplicator,
+ "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,
+ "ZeroIn": 0,
+ 'Str("<unk")': "<unk",
+ 'Str("<unknown>")': "<unknown>",
+ 'Str("nown>")': "nown>",
+ })
+ return locals()
+
+
+def init_other():
+ import numbers
+ type_map.update({
+ "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.Smart.Integer2": int,
+ })
+ return locals()
+
+
+# The PySide Part
+def init_PySide6_QtCore():
+ from PySide6.QtCore import Qt, QUrl, QDir, QKeyCombination
+ 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.
+ from PySide6.QtCore import Connection
+ except ImportError:
+ pass
+ type_map.update({
+ "' '": " ",
+ "'%'": "%",
+ "'g'": "g",
+ "4294967295UL": 4294967295, # 5.6, RHEL 6.6
+ "CheckIndexOption.NoOption": Instance(
+ "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": typing.Union[bytes, bytearray, memoryview],
+ "PyByteArray": bytearray,
+ "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???
+ "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?
+ "QGenericArgument()": ellipsis,
+ "QGenericArgument(0)": ellipsis,
+ "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": 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?
+ "QUrl.FormattingOptions(PrettyDecoded)": Instance(
+ "QUrl.FormattingOptions(QUrl.PrettyDecoded)"),
+ "QVariant()": Invalid(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!
+ })
+ 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()
+
+
+def init_PySide6_QtConcurrent():
+ type_map.update({
+ "PySide6.QtCore.QFuture[QString]":
+ PySide6.QtConcurrent.QFutureQString,
+ "PySide6.QtCore.QFuture[void]":
+ PySide6.QtConcurrent.QFutureVoid,
+ })
+ return locals()
+
+
+def init_PySide6_QtGui():
+ 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,
+ "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,
+ 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)"),
+ "static_cast<Qt.MatchFlags>(Qt.MatchExactly|Qt.MatchCaseSensitive)": Instance(
+ "Qt.MatchFlags(Qt.MatchExactly | Qt.MatchCaseSensitive)"),
+ "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()
+
+
+def init_PySide6_QtSql():
+ from PySide6.QtSql import QSqlDatabase
+ type_map.update({
+ "QLatin1StringView(QSqlDatabase.defaultConnection)": QSqlDatabase.defaultConnection,
+ "QVariant.Invalid": Invalid("Variant"), # not sure what I should create, here...
+ })
+ return locals()
+
+
+def init_PySide6_QtNetwork():
+ from PySide6.QtNetwork import QNetworkRequest, QHostAddress
+ best_structure = typing.OrderedDict if getattr(typing, "OrderedDict", None) else typing.Dict
+ type_map.update({
+ "QMultiMap[PySide6.QtNetwork.QSsl.AlternativeNameEntryType, QString]":
+ best_structure[PySide6.QtNetwork.QSsl.AlternativeNameEntryType, typing.List[str]],
+ "DefaultTransferTimeoutConstant":
+ QNetworkRequest.TransferTimeoutConstant,
+ "QNetworkRequest.DefaultTransferTimeoutConstant":
+ QNetworkRequest.TransferTimeoutConstant,
+ })
+ del best_structure
+ return locals()
+
+
+def init_PySide6_QtOpenGL():
+ type_map.update({
+ "GLbitfield": int,
+ "GLenum": int,
+ "GLfloat": float, # 5.6, MSVC 15
+ "GLint": int,
+ "GLuint": int,
+ })
+ return locals()
+
+
+def init_PySide6_QtQml():
+ type_map.update({
+ "VolatileBool": PySide6.QtQml.VolatileBool,
+ })
+ return locals()
+
+
+def init_PySide6_QtQuick():
+ type_map.update({
+ "PySide6.QtQuick.QSharedPointer[PySide6.QtQuick.QQuickItemGrabResult]":
+ PySide6.QtQuick.QQuickItemGrabResult,
+ "QSGGeometry.Type.UnsignedShortType": int,
+ })
+ return locals()
+
+
+def init_PySide6_QtTest():
+ from PySide6.QtCore import SignalInstance
+ type_map.update({
+ "PySideSignalInstance": SignalInstance,
+ "PySide6.QtTest.QTest.PySideQTouchEventSequence": PySide6.QtTest.QTest.QTouchEventSequence,
+ "PySide6.QtTest.QTouchEventSequence": PySide6.QtTest.QTest.QTouchEventSequence,
+ })
+ return locals()
+
+
+# from 5.12, macOS
+def init_PySide6_QtDataVisualization():
+ from PySide6.QtDataVisualization 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_QtBluetooth():
+ type_map.update({
+ "QVariant*": object,
+ })
+ 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()
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
new file mode 100644
index 000000000..9b48ab442
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -0,0 +1,552 @@
+# 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
+
+import ast
+import enum
+import keyword
+import os
+import re
+import sys
+import typing
+import warnings
+
+from types import SimpleNamespace
+from shibokensupport.signature.mapping import (type_map, update_mapping,
+ namespace, _NotCalled, ResultVariable, ArrayLikeVariable) # noqa E:128
+from shibokensupport.signature.lib.tool import build_brace_pattern
+
+_DEBUG = False
+LIST_KEYWORDS = False
+
+"""
+parser.py
+
+This module parses the signature text and creates properties for the
+signature objects.
+
+PySide has a new function 'CppGenerator::writeSignatureInfo()'
+that extracts the gathered information about the function arguments
+and defaults as good as it can. But what PySide generates is still
+very C-ish and has many constants that Python doesn't understand.
+
+The function 'try_to_guess()' below understands a lot of PySide's
+peculiar way to assume local context. If it is able to do the guess,
+then the result is inserted into the dict, so the search happens
+not again. For everything that is not covered by these automatic
+guesses, we provide an entry in 'type_map' that resolves it.
+
+In effect, 'type_map' maps text to real Python objects.
+"""
+
+
+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
+ for arg in args:
+ 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
+ (?P<funcname> \w+(\.\w+)*) # the function name
+ \( (?P<arglist> .*?) \) # the argument list
+ ( -> (?P<returntype> .*) )? # the optional return type
+ $
+ """
+ matches = re.match(line_re, line, re.VERBOSE)
+ if not matches:
+ raise SystemError("Error parsing line:", repr(line))
+ ret = SimpleNamespace(**matches.groupdict())
+ # PYSIDE-1095: Handle arbitrary default expressions
+ argstr = ret.arglist.replace("->", ".deref.")
+ arglist = _parse_arglist(argstr)
+ args = []
+ for idx, arg in enumerate(arglist):
+ tokens = arg.split(":")
+ if len(tokens) < 2 and idx == 0 and tokens[0] in ("self", "cls"):
+ tokens = 2 * tokens # "self: self"
+ if len(tokens) != 2:
+ # This should never happen again (but who knows?)
+ raise SystemError(f'Invalid argument "{arg}" in "{line}".')
+ name, ann = tokens
+ if name in keyword.kwlist:
+ if LIST_KEYWORDS:
+ print("KEYWORD", ret)
+ name = name + "_"
+ if "=" in ann:
+ ann, default = ann.split("=", 1)
+ tup = name, ann, default
+ else:
+ tup = name, ann
+ args.append(tup)
+ ret.arglist = args
+ multi = ret.multi
+ if multi is not None:
+ ret.multi = int(multi)
+ funcname = ret.funcname
+ parts = funcname.split(".")
+ if parts[-1] in keyword.kwlist:
+ ret.funcname = funcname + "_"
+ return vars(ret)
+
+
+def _using_snake_case():
+ # Note that this function should stay here where we use snake_case.
+ if "PySide6.QtCore" not in sys.modules:
+ return False
+ from PySide6.QtCore import QDir
+ return hasattr(QDir, "cd_up")
+
+
+def _handle_instance_fixup(thing):
+ """
+ Default expressions using instance methods like
+ (...,device=QPointingDevice.primaryPointingDevice())
+ need extra handling for snake_case. These are:
+ QPointingDevice.primaryPointingDevice()
+ QInputDevice.primaryKeyboard()
+ QKeyCombination.fromCombined(0)
+ QSslConfiguration.defaultConfiguration()
+ """
+ match = re.search(r"\w+\(", thing)
+ if not match:
+ return thing
+ start, stop = match.start(), match.end() - 1
+ 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.
+ snake_func = ""
+ for idx, char in enumerate(func):
+ if char.isupper():
+ if idx and func[idx - 1].isupper():
+ # two upper chars are forbidden
+ return thing
+ snake_func += f"_{char.lower()}"
+ else:
+ snake_func += char
+ return f"{pre}{snake_func}{args}"
+
+
+def make_good_value(thing, valtype):
+ # PYSIDE-1019: Handle instance calls (which are really seldom)
+ if "(" in thing and _using_snake_case():
+ thing = _handle_instance_fixup(thing)
+ try:
+ if thing.endswith("()"):
+ thing = f'Default("{thing[:-2]}")'
+ else:
+ # 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, globals(), namespace)
+ except Exception:
+ pass
+
+
+def try_to_guess(thing, valtype):
+ if "." not in thing and "(" not in thing:
+ text = f"{valtype}.{thing}"
+ ret = make_good_value(text, valtype)
+ if ret is not None:
+ return ret
+ typewords = valtype.split(".")
+ valwords = thing.split(".")
+ braceless = valwords[0] # Yes, not -1. Relevant is the overlapped word.
+ if "(" in braceless:
+ braceless = braceless[:braceless.index("(")]
+ for idx, w in enumerate(typewords):
+ if w == braceless:
+ text = ".".join(typewords[:idx] + valwords)
+ ret = make_good_value(text, valtype)
+ if ret is not None:
+ 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."):
+ return None
+ map = type_map[valtype]
+ # typing.Any: '_SpecialForm' object has no attribute '__name__'
+ name = get_name(map) if hasattr(map, "__name__") else str(map)
+ thing = f"zero({name})"
+ if thing in type_map:
+ return type_map[thing]
+ res = make_good_value(thing, valtype)
+ if res is not None:
+ type_map[thing] = res
+ return res
+ res = try_to_guess(thing, valtype) if valtype else None
+ if res is not None:
+ type_map[thing] = res
+ return res
+ warnings.warn(f"""pyside_type_init:_resolve_value
+
+ UNRECOGNIZED: {thing!r}
+ OFFENDING LINE: {line!r}
+ """, RuntimeWarning)
+ return thing
+
+
+def _resolve_arraytype(thing, line):
+ search = re.search(r"\[(\d*)\]$", thing)
+ thing = thing[:search.start()]
+ if thing.endswith("]"):
+ thing = _resolve_arraytype(thing, line)
+ 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):
+ # 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":
+ m = thing.__module__
+ dot = "." in str(thing) or m not in (thing.__qualname__, "builtins")
+ name = get_name(thing)
+ 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(",")))
+ assert typstr == "float"
+ result = f"PySide6.QtGui.QMatrix{n}x{m}"
+ return eval(result, globals(), namespace)
+
+
+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
+ 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()
+ # 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))
+ 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))
+ if isinstance(part, _NotCalled):
+ # fix the tag (i.e. "Missing") by repr
+ part = repr(part)
+ pieces.append(to_string(part))
+ thing = ", ".join(pieces)
+ result = f"{contr}[{thing}]"
+ # PYSIDE-1538: Make sure that the eval does not crash.
+ try:
+ return eval(result, globals(), namespace)
+ except Exception:
+ warnings.warn(f"""pyside_type_init:_resolve_type
+
+ UNRECOGNIZED: {result!r}
+ OFFENDING LINE: {line!r}
+ """, RuntimeWarning)
+ return _resolve_value(thing, None, line)
+
+
+def _handle_generic(obj, repl):
+ """
+ Assign repl if obj is an ArrayLikeVariable
+
+ This is a neat trick. Example:
+
+ obj repl result
+ ---------------------- -------- ---------
+ ArrayLikeVariable List List
+ ArrayLikeVariable(str) List List[str]
+ ArrayLikeVariable Sequence Sequence
+ ArrayLikeVariable(str) Sequence Sequence[str]
+ """
+ if isinstance(obj, ArrayLikeVariable):
+ return repl[obj.type]
+ if isinstance(obj, type) and issubclass(obj, ArrayLikeVariable):
+ # was "if obj is ArrayLikeVariable"
+ return repl
+ return obj
+
+
+def handle_argvar(obj):
+ """
+ Decide how array-like variables are resolved in arguments
+
+ Currently, the best approximation is types.Sequence.
+ We want to change that to types.Iterable in the near future.
+ """
+ return _handle_generic(obj, typing.Sequence)
+
+
+def handle_retvar(obj):
+ """
+ Decide how array-like variables are resolved in results
+
+ This will probably stay typing.List forever.
+ """
+ return _handle_generic(obj, typing.List)
+
+
+def calculate_props(line):
+ parsed = SimpleNamespace(**_parse_line(line.strip()))
+ arglist = parsed.arglist
+ annotations = {}
+ _defaults = []
+ for idx, tup in enumerate(arglist):
+ name, ann = tup[:2]
+ if ann == "...":
+ name = "*args" if name.startswith("arg_") else "*" + name
+ # 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, parsed.funcname)
+ if len(tup) == 3:
+ default = _resolve_value(tup[2], ann, line)
+ _defaults.append(default)
+ defaults = tuple(_defaults)
+ returntype = parsed.returntype
+ if isinstance(returntype, str) and returntype.startswith("("):
+ # PYSIDE-1588: Simplify the handling of returned tuples for now.
+ # Later we might create named tuples, instead.
+ returntype = "Tuple"
+ # PYSIDE-1383: We need to handle `None` explicitly.
+ annotations["return"] = (_resolve_type(returntype, line, 0, handle_retvar)
+ if returntype is not None else None)
+ props = SimpleNamespace()
+ props.defaults = defaults
+ props.kwdefaults = {}
+ props.annotations = annotations
+ props.varnames = tuple(tup[0] for tup in arglist)
+ funcname = parsed.funcname
+ shortname = funcname[funcname.rindex(".") + 1:]
+ props.name = shortname
+ props.multi = parsed.multi
+ fix_variables(props, line)
+ return vars(props)
+
+
+def fix_variables(props, line):
+ annos = props.annotations
+ if not any(isinstance(ann, (ResultVariable, ArrayLikeVariable))
+ for ann in annos.values()):
+ return
+ retvar = annos.get("return", None)
+ if retvar and isinstance(retvar, (ResultVariable, ArrayLikeVariable)):
+ # Special case: a ResultVariable which is the result will always be an array!
+ annos["return"] = retvar = typing.List[retvar.type]
+ varnames = list(props.varnames)
+ defaults = list(props.defaults)
+ diff = len(varnames) - len(defaults)
+
+ safe_annos = annos.copy()
+ retvars = [retvar] if retvar else []
+ deletions = []
+ for idx, name in enumerate(varnames):
+ ann = safe_annos[name]
+ if isinstance(ann, ArrayLikeVariable):
+ ann = typing.Sequence[ann.type]
+ annos[name] = ann
+ if not isinstance(ann, ResultVariable):
+ continue
+ # We move the variable to the end and remove it.
+ # PYSIDE-1409: If the variable was the first arg, we move it to the front.
+ # XXX This algorithm should probably be replaced by more introspection.
+ retvars.insert(0 if idx == 0 else len(retvars), ann.type)
+ deletions.append(idx)
+ del annos[name]
+ for idx in reversed(deletions):
+ # varnames: 0 1 2 3 4 5 6 7
+ # defaults: 0 1 2 3 4
+ # diff: 3
+ del varnames[idx]
+ if idx >= diff:
+ del defaults[idx - diff]
+ else:
+ diff -= 1
+ if retvars:
+ retvars = list(handle_retvar(rv) if isinstance(rv, ArrayLikeVariable) else rv
+ for rv in retvars)
+ if len(retvars) == 1:
+ returntype = retvars[0]
+ else:
+ retvars_str = ", ".join(map(to_string, retvars))
+ typestr = f"typing.Tuple[{retvars_str}]"
+ returntype = eval(typestr, globals(), namespace)
+ props.annotations["return"] = returntype
+ props.varnames = tuple(varnames)
+ props.defaults = tuple(defaults)
+
+
+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:
+ multi = re.match(r"([0-9]+):", line)
+ if multi:
+ idx, rest = int(multi.group(1)), line[multi.end():]
+ multi_lines.append(rest)
+ if idx > 0:
+ continue
+ # remove duplicates
+ multi_lines = sorted(set(multi_lines))
+ # renumber or return a single line
+ nmulti = len(multi_lines)
+ if nmulti > 1:
+ for idx, line in enumerate(multi_lines):
+ res.append(f"{nmulti-idx-1}:{line}")
+ else:
+ res.append(multi_lines[0])
+ multi_lines = []
+ else:
+ res.append(line)
+ return res
+
+
+def pyside_type_init(type_key, sig_strings):
+ dprint()
+ dprint(f"Initialization of type key '{type_key}'")
+ update_mapping()
+ lines = fixup_multilines(sig_strings)
+ ret = {}
+ multi_props = []
+ for line in lines:
+ props = calculate_props(line)
+ shortname = props["name"]
+ multi = props["multi"]
+ if multi is None:
+ ret[shortname] = props
+ dprint(props)
+ else:
+ multi_props.append(props)
+ if multi > 0:
+ continue
+ multi_props = {"multi": multi_props}
+ ret[shortname] = multi_props
+ dprint(multi_props)
+ multi_props = []
+ return ret
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json
new file mode 100644
index 000000000..0f05aea8b
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "python",
+ "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. See the folder sources/shiboken6/files.dir/shibokensupport .",
+ "Homepage": "http://www.python.org/",
+ "Version": "3.7.0",
+ "LicenseId": "Python-2.0",
+ "License": "Python License 2.0",
+ "LicenseFile": "PSF-3.7.0.txt",
+ "Copyright": "© Copyright 2001-2018, Python Software Foundation."
+}