aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2024-10-27 18:17:11 +0100
committerChristian Tismer <tismer@stackless.com>2024-11-01 13:40:14 +0000
commit07ee31548a3af6552e62625860c20772503e658c (patch)
tree9c247657936f2735834c4f3f2ad06f5beae2ebe0
parentcc1164d29878ab74dbbd94718eee1bc2acdddbf6 (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.in17
-rw-r--r--sources/pyside6/tests/pysidetest/all_modules_load_test.py12
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.cpp25
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.h5
-rw-r--r--sources/shiboken6/shibokenmodule/shibokenmodule.cpp5
-rw-r--r--sources/shiboken6/shibokenmodule/typesystem_shiboken.xml4
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>