aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py')
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py248
1 files changed, 248 insertions, 0 deletions
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