diff options
| author | Christian Tismer <tismer@stackless.com> | 2024-10-27 18:17:11 +0100 |
|---|---|---|
| committer | Christian Tismer <tismer@stackless.com> | 2024-11-01 13:40:14 +0000 |
| commit | 07ee31548a3af6552e62625860c20772503e658c (patch) | |
| tree | 9c247657936f2735834c4f3f2ad06f5beae2ebe0 | |
| parent | cc1164d29878ab74dbbd94718eee1bc2acdddbf6 (diff) | |
setup: fix PySide6.__all__ after the wheel split, amendment 3
The __all__ support for the PySide6 module works just fine.
But there is a last incompatibility that might strike others
as it did hit ourselves when using PySide6.__dict["__all__"]:
Use a derived dict type and define a __missing__ attribute.
Derive further a module type, then it works without problems.
A little support function in Shiboken allows to replace the
dict of PySide6 with this derived type.
amends 703d975f16aff95bc9014a2689a3ae824b5a552f.
Pick-to: 6.8
Task-number: PYSIDE-2895
Task-number: PYSIDE-1890
Change-Id: I018228116a5fdd1401c1ebd42ceb886f6829deeb
Reviewed-by: Christian Tismer <tismer@stackless.com>
| -rw-r--r-- | sources/pyside6/PySide6/__init__.py.in | 17 | ||||
| -rw-r--r-- | sources/pyside6/tests/pysidetest/all_modules_load_test.py | 12 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbkmodule.cpp | 25 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbkmodule.h | 5 | ||||
| -rw-r--r-- | sources/shiboken6/shibokenmodule/shibokenmodule.cpp | 5 | ||||
| -rw-r--r-- | sources/shiboken6/shibokenmodule/typesystem_shiboken.xml | 4 |
6 files changed, 66 insertions, 2 deletions
diff --git a/sources/pyside6/PySide6/__init__.py.in b/sources/pyside6/PySide6/__init__.py.in index 5dc80c7aa..ca3b7fc6a 100644 --- a/sources/pyside6/PySide6/__init__.py.in +++ b/sources/pyside6/PySide6/__init__.py.in @@ -1,6 +1,8 @@ import os import sys from pathlib import Path +from types import ModuleType +# mypy: disable-error-code="name-defined" # __all__ is computed below. __pre_all__ = [@init_modules@] @@ -60,6 +62,7 @@ def _setupQtDirectories(): try: # PYSIDE-1497: we use the build dir or install dir or site-packages, whatever the path # setting dictates. There is no longer a difference in path structure. + global Shiboken from shiboken6 import Shiboken except Exception: paths = ', '.join(sys.path) @@ -121,4 +124,18 @@ def __getattr__(name: str) -> list[str]: raise AttributeError(f"module '{__name__}' has no attribute '{name}' :)") +# Be prepared that people can access the module dict instead. +class ModuleDict(dict): + def __missing__(self, key): + if key == "__all__": + self[key] = __all__ if "__all__" in globals() else __getattr__("__all__") + return __all__ + raise KeyError(f"dict of module '{__name__}' has no key '{key}' :)") + + +class SubModule(ModuleType): + pass + + _setupQtDirectories() +Shiboken.replaceModuleDict(sys.modules["PySide6"], SubModule, ModuleDict(globals())) diff --git a/sources/pyside6/tests/pysidetest/all_modules_load_test.py b/sources/pyside6/tests/pysidetest/all_modules_load_test.py index 16f2369a7..6b3ebe732 100644 --- a/sources/pyside6/tests/pysidetest/all_modules_load_test.py +++ b/sources/pyside6/tests/pysidetest/all_modules_load_test.py @@ -13,18 +13,26 @@ init_test_paths(False) import PySide6 + # Note: # "from PySide6 import *" can only be used at module level. # It is also really not recommended to use. But for testing, # the "__all__" variable is a great feature! - - class AllModulesImportTest(unittest.TestCase): def testAllModulesCanImport(self): # would also work: exec("from PySide6 import *") for name in PySide6.__all__: exec(f"import PySide6.{name}") + def testAllReappearsAfterDel(self): + # This is the only incompatibility that remains: + # After __all__ is deleted, it will re-appear. + PySide6.__all__ = 42 + self.assertEqual(PySide6.__dict__["__all__"], 42) + del PySide6.__all__ + self.assertTrue(PySide6.__dict__["__all__"]) + self.assertNotEqual(PySide6.__dict__["__all__"], 42) + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken6/libshiboken/sbkmodule.cpp b/sources/shiboken6/libshiboken/sbkmodule.cpp index 202bd27bd..f254cdfd1 100644 --- a/sources/shiboken6/libshiboken/sbkmodule.cpp +++ b/sources/shiboken6/libshiboken/sbkmodule.cpp @@ -539,4 +539,29 @@ SbkConverter **getTypeConverters(PyObject *module) return (iter == moduleConverters.end()) ? 0 : iter->second; } +// Replace the dictionary of a module by a different dict. +// The dict should be filled with the content of the old dict, before. +// Reason: Creating a module dict with __missing__ support. +typedef struct { + PyObject_HEAD + PyObject *md_dict; +} StartOf_PyModuleObject; + +bool replaceModuleDict(PyObject *module, PyObject *modClass, PyObject *dict) +{ + if (!(PyModule_Check(module) && PyType_Check(modClass) && PyDict_Check(dict))) + return false; + auto *modict = PyModule_GetDict(module); + auto *modIntern = reinterpret_cast<StartOf_PyModuleObject *>(module); + if (modict != modIntern->md_dict) + Py_FatalError("The layout of modules is incompatible"); + auto *hold = modIntern->md_dict; + modIntern->md_dict = dict; + Py_INCREF(dict); + Py_DECREF(hold); + Py_INCREF(modClass); + module->ob_type = reinterpret_cast<PyTypeObject *>(modClass); + return true; +} + } } // namespace Shiboken::Module diff --git a/sources/shiboken6/libshiboken/sbkmodule.h b/sources/shiboken6/libshiboken/sbkmodule.h index 2c407e09d..ac77604b8 100644 --- a/sources/shiboken6/libshiboken/sbkmodule.h +++ b/sources/shiboken6/libshiboken/sbkmodule.h @@ -84,6 +84,11 @@ LIBSHIBOKEN_API void registerTypeConverters(PyObject *module, SbkConverter **con */ LIBSHIBOKEN_API SbkConverter **getTypeConverters(PyObject *module); +/** + * Replace the dictionary of a module. This allows to use `__missing__`. + */ +LIBSHIBOKEN_API bool replaceModuleDict(PyObject *module, PyObject *modClass, PyObject *dict); + } // namespace Shiboken::Module #endif // SBK_MODULE_H diff --git a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp index 5c6219885..16cb0fcd3 100644 --- a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp +++ b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp @@ -75,6 +75,11 @@ if (!Shiboken::Object::checkType(%1)) { } // @snippet dump +// @snippet replacemoduledict +const bool ok = Shiboken::Module::replaceModuleDict(%1, %2, %3); +%PYARG_0 = %CONVERTTOPYTHON[bool](ok); +// @snippet replacemoduledict + // @snippet getallvalidwrappers const auto setAll = Shiboken::BindingManager::instance().getAllPyObjects(); PyObject* listAll = PyList_New(0); diff --git a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml index acb522ecc..851f4ef61 100644 --- a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml +++ b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml @@ -41,6 +41,10 @@ <inject-code file="shibokenmodule.cpp" snippet="disassembleframe"/> </add-function> + <add-function signature="replaceModuleDict(PyObject*, PyObject*, PyObject*)" return-type="bool"> + <inject-code file="shibokenmodule.cpp" snippet="replacemoduledict"/> + </add-function> + <add-function signature="dump(PyObject*)" return-type="const char *"> <inject-code file="shibokenmodule.cpp" snippet="dump"/> </add-function> |
