Skip to content

Commit 07ee315

Browse files
committed
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 703d975. Pick-to: 6.8 Task-number: PYSIDE-2895 Task-number: PYSIDE-1890 Change-Id: I018228116a5fdd1401c1ebd42ceb886f6829deeb Reviewed-by: Christian Tismer <[email protected]>
1 parent cc1164d commit 07ee315

File tree

6 files changed

+66
-2
lines changed

6 files changed

+66
-2
lines changed

sources/pyside6/PySide6/__init__.py.in

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
import sys
33
from pathlib import Path
4+
from types import ModuleType
5+
# mypy: disable-error-code="name-defined"
46

57
# __all__ is computed below.
68
__pre_all__ = [@init_modules@]
@@ -60,6 +62,7 @@ def _setupQtDirectories():
6062
try:
6163
# PYSIDE-1497: we use the build dir or install dir or site-packages, whatever the path
6264
# setting dictates. There is no longer a difference in path structure.
65+
global Shiboken
6366
from shiboken6 import Shiboken
6467
except Exception:
6568
paths = ', '.join(sys.path)
@@ -121,4 +124,18 @@ def __getattr__(name: str) -> list[str]:
121124
raise AttributeError(f"module '{__name__}' has no attribute '{name}' :)")
122125

123126

127+
# Be prepared that people can access the module dict instead.
128+
class ModuleDict(dict):
129+
def __missing__(self, key):
130+
if key == "__all__":
131+
self[key] = __all__ if "__all__" in globals() else __getattr__("__all__")
132+
return __all__
133+
raise KeyError(f"dict of module '{__name__}' has no key '{key}' :)")
134+
135+
136+
class SubModule(ModuleType):
137+
pass
138+
139+
124140
_setupQtDirectories()
141+
Shiboken.replaceModuleDict(sys.modules["PySide6"], SubModule, ModuleDict(globals()))

sources/pyside6/tests/pysidetest/all_modules_load_test.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,26 @@
1313

1414
import PySide6
1515

16+
1617
# Note:
1718
# "from PySide6 import *" can only be used at module level.
1819
# It is also really not recommended to use. But for testing,
1920
# the "__all__" variable is a great feature!
20-
21-
2221
class AllModulesImportTest(unittest.TestCase):
2322
def testAllModulesCanImport(self):
2423
# would also work: exec("from PySide6 import *")
2524
for name in PySide6.__all__:
2625
exec(f"import PySide6.{name}")
2726

27+
def testAllReappearsAfterDel(self):
28+
# This is the only incompatibility that remains:
29+
# After __all__ is deleted, it will re-appear.
30+
PySide6.__all__ = 42
31+
self.assertEqual(PySide6.__dict__["__all__"], 42)
32+
del PySide6.__all__
33+
self.assertTrue(PySide6.__dict__["__all__"])
34+
self.assertNotEqual(PySide6.__dict__["__all__"], 42)
35+
2836

2937
if __name__ == '__main__':
3038
unittest.main()

sources/shiboken6/libshiboken/sbkmodule.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,4 +539,29 @@ SbkConverter **getTypeConverters(PyObject *module)
539539
return (iter == moduleConverters.end()) ? 0 : iter->second;
540540
}
541541

542+
// Replace the dictionary of a module by a different dict.
543+
// The dict should be filled with the content of the old dict, before.
544+
// Reason: Creating a module dict with __missing__ support.
545+
typedef struct {
546+
PyObject_HEAD
547+
PyObject *md_dict;
548+
} StartOf_PyModuleObject;
549+
550+
bool replaceModuleDict(PyObject *module, PyObject *modClass, PyObject *dict)
551+
{
552+
if (!(PyModule_Check(module) && PyType_Check(modClass) && PyDict_Check(dict)))
553+
return false;
554+
auto *modict = PyModule_GetDict(module);
555+
auto *modIntern = reinterpret_cast<StartOf_PyModuleObject *>(module);
556+
if (modict != modIntern->md_dict)
557+
Py_FatalError("The layout of modules is incompatible");
558+
auto *hold = modIntern->md_dict;
559+
modIntern->md_dict = dict;
560+
Py_INCREF(dict);
561+
Py_DECREF(hold);
562+
Py_INCREF(modClass);
563+
module->ob_type = reinterpret_cast<PyTypeObject *>(modClass);
564+
return true;
565+
}
566+
542567
} } // namespace Shiboken::Module

sources/shiboken6/libshiboken/sbkmodule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ LIBSHIBOKEN_API void registerTypeConverters(PyObject *module, SbkConverter **con
8484
*/
8585
LIBSHIBOKEN_API SbkConverter **getTypeConverters(PyObject *module);
8686

87+
/**
88+
* Replace the dictionary of a module. This allows to use `__missing__`.
89+
*/
90+
LIBSHIBOKEN_API bool replaceModuleDict(PyObject *module, PyObject *modClass, PyObject *dict);
91+
8792
} // namespace Shiboken::Module
8893

8994
#endif // SBK_MODULE_H

sources/shiboken6/shibokenmodule/shibokenmodule.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ if (!Shiboken::Object::checkType(%1)) {
7575
}
7676
// @snippet dump
7777

78+
// @snippet replacemoduledict
79+
const bool ok = Shiboken::Module::replaceModuleDict(%1, %2, %3);
80+
%PYARG_0 = %CONVERTTOPYTHON[bool](ok);
81+
// @snippet replacemoduledict
82+
7883
// @snippet getallvalidwrappers
7984
const auto setAll = Shiboken::BindingManager::instance().getAllPyObjects();
8085
PyObject* listAll = PyList_New(0);

sources/shiboken6/shibokenmodule/typesystem_shiboken.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
<inject-code file="shibokenmodule.cpp" snippet="disassembleframe"/>
4242
</add-function>
4343

44+
<add-function signature="replaceModuleDict(PyObject*, PyObject*, PyObject*)" return-type="bool">
45+
<inject-code file="shibokenmodule.cpp" snippet="replacemoduledict"/>
46+
</add-function>
47+
4448
<add-function signature="dump(PyObject*)" return-type="const char *">
4549
<inject-code file="shibokenmodule.cpp" snippet="dump"/>
4650
</add-function>

0 commit comments

Comments
 (0)