diff options
-rw-r--r-- | sources/pyside6/PySide6/QtCore/typesystem_core_common.xml | 79 | ||||
-rw-r--r-- | sources/pyside6/PySide6/glue/qtcore.cpp | 8 | ||||
-rw-r--r-- | sources/pyside6/libpyside/pyside.cpp | 17 | ||||
-rw-r--r-- | sources/pyside6/libpyside/pyside.h | 5 | ||||
-rw-r--r-- | sources/pyside6/tests/QtCore/qfile_test.py | 22 | ||||
-rw-r--r-- | sources/pyside6/tests/QtCore/qfileinfo_test.py | 9 | ||||
-rw-r--r-- | sources/pyside6/tests/registry/init_platform.py | 3 | ||||
-rw-r--r-- | sources/shiboken6/generator/shiboken/pytypenames.h | 3 | ||||
-rw-r--r-- | sources/shiboken6/generator/shiboken/shibokengenerator.cpp | 4 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/CMakeLists.txt | 2 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbkstring.cpp | 24 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbkstring.h | 1 | ||||
-rw-r--r-- | sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py | 1 |
13 files changed, 172 insertions, 6 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml index 0cffffae0..856c01224 100644 --- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml +++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml @@ -47,6 +47,7 @@ <custom-type name="PyByteArray"/> <custom-type name="PyCallable"/> <custom-type name="PyObject"/> + <custom-type name="PyPathLike"/> <custom-type name="PySequence"/> <custom-type name="PyTypeObject"/> <custom-type name="PyUnicode"/> @@ -909,9 +910,30 @@ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatetime-topython"/> </add-function> </value-type> + <value-type name="QDir"> <enum-type name="Filter" flags="Filters"/> <enum-type name="SortFlag" flags="SortFlags"/> + + <!-- PYSIDE-1499: Replace QString by pathlib.Path (qdir.h) --> + <modify-function signature="QDir(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="QDir(const QString &,const QString &,SortFlags=SortFlags(Name|IgnoreCase),Filters=AllEntries)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="setPath(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="addSearchPath(const QString &,const QString &)" return-type="PyObject"> + <modify-argument index="2"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-2"/> + </modify-function> + <!-- PYSIDE-1499: End of insertion --> + <add-function signature="__reduce__" return-type="PyObject*"> <inject-code class="target" position="beginning"> <insert-template name="reduce_code"> @@ -1811,6 +1833,22 @@ <include file-name="QDateTime" location="global"/> <include file-name="QDir" location="global"/> </extra-includes> + + <!-- PYSIDE-1499: Replace QString by pathlib.Path (qfileinfo.h) --> + <modify-function signature="QFileInfo(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="QFileInfo(const QDir &,const QString &)" return-type="PyObject"> + <modify-argument index="2"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-2"/> + </modify-function> + <modify-function signature="setFile(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <!-- PYSIDE-1499: End of insertion --> + <add-function signature="__reduce__" return-type="PyObject*"> <inject-code class="target" position="beginning"> <insert-template name="reduce_code"> @@ -1820,6 +1858,7 @@ </inject-code> </add-function> </value-type> + <value-type name="QByteArray" hash-function="qHash"> <enum-type name="Base64Option" flags="Base64Options" since="5.2"/> <enum-type name="Base64DecodingStatus" since="5.15"/> @@ -2136,7 +2175,47 @@ </modify-function> <modify-function signature="flush()" allow-thread="yes"/> </object-type> + <object-type name="QFile"> + <!-- PYSIDE-1499: Replace QString by pathlib.Path (qfile.h) --> + <modify-function signature="fromFilesystemPath(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="QFile(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="QFile(const QString &,QObject *)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="setFileName(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="rename(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="link(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="copy(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="permissions(const QString &)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <modify-function signature="setPermissions(const QString &,Permissions)" return-type="PyObject"> + <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/> + </modify-function> + <!-- PYSIDE-1499: End of insertion --> + <modify-function signature="open(QFlags<QIODeviceBase::OpenModeFlag>)" allow-thread="yes"/> <modify-function signature="open(int,QFlags<QIODeviceBase::OpenModeFlag>,QFlags<QFileDevice::FileHandleFlag>)" allow-thread="yes"/> <modify-function signature="copy(const QString&)" allow-thread="yes"/> diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp index a041336da..a105666a1 100644 --- a/sources/pyside6/PySide6/glue/qtcore.cpp +++ b/sources/pyside6/PySide6/glue/qtcore.cpp @@ -1662,6 +1662,14 @@ PyMem_Free(temp); %out = %OUTTYPE(); // @snippet conversion-pynone +// @snippet qfile-path-1 +auto cppArg0 = PySide::pyPathToQString(%PYARG_1); +// @snippet qfile-path-1 + +// @snippet qfile-path-2 +auto cppArg1 = PySide::pyPathToQString(%PYARG_2); +// @snippet qfile-path-2 + // @snippet conversion-pystring-char char c = %CONVERTTOCPP[char](%in); %out = %OUTTYPE(c); diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp index a78e4e9eb..16d77ab57 100644 --- a/sources/pyside6/libpyside/pyside.cpp +++ b/sources/pyside6/libpyside/pyside.cpp @@ -478,7 +478,8 @@ void setQuickRegisterItemFunction(QuickRegisterItemFunction function) #endif // PYSIDE_QML_SUPPORT // Inspired by Shiboken::String::toCString; -QString pyStringToQString(PyObject *str) { +QString pyStringToQString(PyObject *str) +{ if (str == Py_None) return QString(); @@ -495,6 +496,20 @@ QString pyStringToQString(PyObject *str) { return QString(); } +// PySide-1499: Provide an efficient, correct PathLike interface +QString pyPathToQString(PyObject *path) +{ + // str or bytes pass through + if (PyUnicode_Check(path) || PyBytes_Check(path)) + return pyStringToQString(path); + + // Let PyOS_FSPath do its work and then fix the result for Windows. + Shiboken::AutoDecRef strPath(PyOS_FSPath(path)); + if (strPath.isNull()) + return QString(); + return QDir::fromNativeSeparators(pyStringToQString(strPath)); +} + static const unsigned char qt_resource_name[] = { // qt 0x0,0x2, diff --git a/sources/pyside6/libpyside/pyside.h b/sources/pyside6/libpyside/pyside.h index 3c4ae92b2..9bb0ab12e 100644 --- a/sources/pyside6/libpyside/pyside.h +++ b/sources/pyside6/libpyside/pyside.h @@ -157,6 +157,11 @@ PYSIDE_API void setQuickRegisterItemFunction(QuickRegisterItemFunction function) PYSIDE_API QString pyStringToQString(PyObject *str); /** + * Provide an efficient, correct PathLike interface. + */ +PYSIDE_API QString pyPathToQString(PyObject *path); + +/** * Registers a dynamic "qt.conf" file with the Qt resource system. * * This is used in a standalone build, to inform QLibraryInfo of the Qt prefix (where Qt libraries diff --git a/sources/pyside6/tests/QtCore/qfile_test.py b/sources/pyside6/tests/QtCore/qfile_test.py index 897b4583c..d480d5e30 100644 --- a/sources/pyside6/tests/QtCore/qfile_test.py +++ b/sources/pyside6/tests/QtCore/qfile_test.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2016 The Qt Company Ltd. +## Copyright (C) 2021 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the test suite of Qt for Python. @@ -86,5 +86,25 @@ class GetCharTest(unittest.TestCase): self.assertTrue(os.path.exists(QDir.toNativeSeparators(saveFile.fileName()))) +class GetCharTestPath(GetCharTest): + # PYSIDE-1499: Do the same with Path objects + + def setUp(self): + '''Acquire resources''' + handle, filename = tempfile.mkstemp() + self.filename = Path(filename) + os.write(handle, bytes('a', "UTF-8")) + os.close(handle) + + +class DirPath(unittest.TestCase): + # PYSIDE-1499: Test QDir with Path objects + def testQDirPath(self): + test_path = Path("some") / "dir" + qdir1 = QDir(os.fspath(test_path)) + qdir2 = QDir(test_path) + self.assertEqual(qdir1, qdir2) + + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/QtCore/qfileinfo_test.py b/sources/pyside6/tests/QtCore/qfileinfo_test.py index bbdd4bce9..d28be7c4c 100644 --- a/sources/pyside6/tests/QtCore/qfileinfo_test.py +++ b/sources/pyside6/tests/QtCore/qfileinfo_test.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2016 The Qt Company Ltd. +## Copyright (C) 2021 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the test suite of Qt for Python. @@ -46,6 +46,13 @@ class QFileConstructor(unittest.TestCase): '''QFileInfo(QFile)''' obj = QFileInfo(QFile()) + def testQFileInfoPath(self): + # PYSIDE-1499: Test QFileInfo with Path objects + test_path = Path("some") / "dir" + qinf1 = QFileInfo(os.fspath(test_path)) + qinf2 = QFileInfo(test_path) + self.assertEqual(qinf1, qinf2) + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/registry/init_platform.py b/sources/pyside6/tests/registry/init_platform.py index 41b49dd53..06c488ee3 100644 --- a/sources/pyside6/tests/registry/init_platform.py +++ b/sources/pyside6/tests/registry/init_platform.py @@ -136,9 +136,8 @@ if not have_build_dir: import testbinding all_modules.append("testbinding") -# Note: This is not the shiboken dir as usual, but the binary. from shiboken6 import Shiboken -all_modules.append("Shiboken") +all_modules.append("shiboken6.Shiboken") # 'sample/smart' are needed by 'other', so import them first. for modname in "minimal sample smart other".split(): diff --git a/sources/shiboken6/generator/shiboken/pytypenames.h b/sources/shiboken6/generator/shiboken/pytypenames.h index 779f67f2f..cec7054a0 100644 --- a/sources/shiboken6/generator/shiboken/pytypenames.h +++ b/sources/shiboken6/generator/shiboken/pytypenames.h @@ -38,6 +38,9 @@ static inline QString pyLongT() { return QStringLiteral("PyLong"); } static inline QString pyObjectT() { return QStringLiteral("object"); } static inline QString pyStrT() { return QStringLiteral("str"); } +// PYSIDE-1499: A custom type determined by existence of an `__fspath__` attribute. +static inline QString pyPathLikeT() { return QStringLiteral("PyPathLike"); } + static inline QString cPyBufferT() { return QStringLiteral("PyBuffer"); } static inline QString cPyListT() { return QStringLiteral("PyList"); } static inline QString cPyObjectT() { return QStringLiteral("PyObject"); } diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index 40608e566..03efdc7a4 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -1124,6 +1124,10 @@ ShibokenGenerator::CPythonCheckFunctionResult if (type == cPyArrayObjectT()) return {QLatin1String("PyArray_Check"), {}}; + // PYSIDE-1499: We replace some strings by path objects. + if (type == pyPathLikeT()) + return {QLatin1String("Shiboken::String::checkPath"), {}}; + CPythonCheckFunctionResult result; result.type = buildAbstractMetaTypeFromString(type); diff --git a/sources/shiboken6/libshiboken/CMakeLists.txt b/sources/shiboken6/libshiboken/CMakeLists.txt index 241318178..02be441f9 100644 --- a/sources/shiboken6/libshiboken/CMakeLists.txt +++ b/sources/shiboken6/libshiboken/CMakeLists.txt @@ -101,7 +101,7 @@ shiboken_compute_python_includes() shiboken_compute_python_libraries() if(PYTHON_LIMITED_API) - target_compile_definitions(libshiboken PUBLIC "-DPy_LIMITED_API=0x03050000") + target_compile_definitions(libshiboken PUBLIC "-DPy_LIMITED_API=0x03060000") endif() if(CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/sources/shiboken6/libshiboken/sbkstring.cpp b/sources/shiboken6/libshiboken/sbkstring.cpp index c234d7307..177b946fa 100644 --- a/sources/shiboken6/libshiboken/sbkstring.cpp +++ b/sources/shiboken6/libshiboken/sbkstring.cpp @@ -53,6 +53,30 @@ bool checkIterable(PyObject *obj) return PyObject_HasAttr(obj, Shiboken::PyMagicName::iter()); } +static PyObject *initPathLike() +{ + PyObject *PathLike{}; + auto osmodule = PyImport_ImportModule("os"); + if (osmodule == nullptr + || (PathLike = PyObject_GetAttrString(osmodule, "PathLike")) == nullptr) { + PyErr_Print(); + Py_FatalError("cannot import os.PathLike"); + } + return PathLike; +} + +// PYSIDE-1499: Migrate to pathlib.Path and support __fspath__ in PySide +bool checkPath(PyObject *path) +{ + // Let normal strings through, unchanged. + if (PyUnicode_Check(path) || PyBytes_Check(path)) + return true; + // Without the Limited API, we could look up an `__fspath__` class attribute. + // But we use `isinstance(os.PathLike)`, instead. + static PyObject *PathLike = initPathLike(); + return PyObject_IsInstance(path, PathLike); +} + bool checkType(PyTypeObject *type) { return type == &PyUnicode_Type; diff --git a/sources/shiboken6/libshiboken/sbkstring.h b/sources/shiboken6/libshiboken/sbkstring.h index 817b8acc2..4b416e16c 100644 --- a/sources/shiboken6/libshiboken/sbkstring.h +++ b/sources/shiboken6/libshiboken/sbkstring.h @@ -49,6 +49,7 @@ namespace String { LIBSHIBOKEN_API bool check(PyObject *obj); LIBSHIBOKEN_API bool checkIterable(PyObject *obj); + LIBSHIBOKEN_API bool checkPath(PyObject *path); LIBSHIBOKEN_API bool checkType(PyTypeObject *obj); LIBSHIBOKEN_API bool checkChar(PyObject *obj); LIBSHIBOKEN_API bool isConvertible(PyObject *obj); diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index be96a7689..72210fdde 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -237,6 +237,7 @@ type_map.update({ "PyObject": object, "PyObject*": object, "PyArrayObject": ArrayLikeVariable, # numpy + "PyPathLike": typing.Union[str, bytes, os.PathLike], "PySequence": typing.Iterable, # important for numpy "PyTypeObject": type, "QChar": str, |