diff options
Diffstat (limited to 'sources/shiboken6/libshiboken/helper.cpp')
-rw-r--r-- | sources/shiboken6/libshiboken/helper.cpp | 216 |
1 files changed, 194 insertions, 22 deletions
diff --git a/sources/shiboken6/libshiboken/helper.cpp b/sources/shiboken6/libshiboken/helper.cpp index 84231f844..46af68956 100644 --- a/sources/shiboken6/libshiboken/helper.cpp +++ b/sources/shiboken6/libshiboken/helper.cpp @@ -5,11 +5,15 @@ #include "basewrapper_p.h" #include "sbkstring.h" #include "sbkstaticstrings.h" +#include "sbkstaticstrings.h" +#include "pep384impl.h" #include <algorithm> +#include <optional> #include <iomanip> #include <iostream> +#include <climits> #include <cstring> #include <cstdarg> #include <cctype> @@ -20,11 +24,41 @@ # include <pthread.h> #endif -static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str) +static std::optional<std::string> getStringAttr(PyObject *obj, const char *what) +{ + if (PyObject_HasAttrString(obj, what) != 0) { // Check first to suppress error. + Shiboken::AutoDecRef result(PyObject_GetAttrString(obj, what)); + if (PyUnicode_Check(result.object()) != 0) + return _PepUnicode_AsString(result.object()); + } + return std::nullopt; +} + +static std::optional<int> getIntAttr(PyObject *obj, const char *what) { - if (obj) { - str << '"' << obj->tp_name << "\", 0x" << std::hex - << obj->tp_flags << std::dec; + if (PyObject_HasAttrString(obj, what) != 0) { // Check first to suppress error. + Shiboken::AutoDecRef result(PyObject_GetAttrString(obj, what)); + if (PyLong_Check(result.object()) != 0) + return PyLong_AsLong(result.object()); + } + return std::nullopt; +} + +static bool verbose = false; + +static void formatTypeTuple(PyObject *t, const char *what, std::ostream &str); + +static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str, bool verbose) +{ + if (obj == nullptr) { + str << '0'; + return; + } + + str << '"' << obj->tp_name << '"'; + if (verbose) { + bool immutableType = false; + str << ", 0x" << std::hex << obj->tp_flags << std::dec; if (obj->tp_flags & Py_TPFLAGS_HEAPTYPE) str << " [heaptype]"; if (obj->tp_flags & Py_TPFLAGS_BASETYPE) @@ -47,30 +81,59 @@ static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str) str << " [type]"; if (obj->tp_flags & Py_TPFLAGS_IS_ABSTRACT) str << " [abstract]"; -#if PY_VERSION_HEX >= 0x03080000 + if (obj->tp_flags & Py_TPFLAGS_READY) + str << " [ready]"; + if (obj->tp_flags & Py_TPFLAGS_READYING) + str << " [readying]"; if (obj->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) str << " [method_descriptor]"; -# if PY_VERSION_HEX >= 0x03090000 -# ifndef Py_LIMITED_API +# ifndef Py_LIMITED_API if (obj->tp_flags & Py_TPFLAGS_HAVE_VECTORCALL) str << " [vectorcall]"; -# endif // !Py_LIMITED_API -# if PY_VERSION_HEX >= 0x030A0000 - if (obj->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) +# endif // !Py_LIMITED_API +# if PY_VERSION_HEX >= 0x030A0000 + immutableType = (obj->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) != 0; + if (immutableType) str << " [immutabletype]"; if (obj->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION) str << " [disallow_instantiation]"; -# ifndef Py_LIMITED_API +# ifndef Py_LIMITED_API if (obj->tp_flags & Py_TPFLAGS_MAPPING) str << " [mapping]"; if (obj->tp_flags & Py_TPFLAGS_SEQUENCE) str << " [sequence]"; # endif // !Py_LIMITED_API -# endif // 3.10 -# endif // 3.9 -#endif // 3.8 - } else { - str << '0'; +# endif // 3.10 + if (obj->tp_basicsize != 0) + str << ", basicsize=" << obj->tp_basicsize; + if (verbose) { + formatTypeTuple(obj->tp_bases, "bases", str); + formatTypeTuple(obj->tp_mro, "mro", str); + if (!immutableType) { + auto *underlying = reinterpret_cast<const PyObject *>(obj)->ob_type; + if (underlying != nullptr && underlying != obj) { + str << ", underlying=\"" << underlying->tp_name << '"'; + } + } + } + } +} + +static void formatTypeTuple(PyObject *t, const char *what, std::ostream &str) +{ + const Py_ssize_t size = t != nullptr && PyTuple_Check(t) != 0 ? PyTuple_Size(t) : 0; + if (size > 0) { + str << ", " << what << "=[" << size << "]{"; + for (Py_ssize_t i = 0; i < size; ++i) { + if (i != 0) + str << ", "; + Shiboken::AutoDecRef item(PyTuple_GetItem(t, i)); + if (item.isNull()) + str << '0'; // Observed with non-ready types + else + str << '"' << reinterpret_cast<PyTypeObject *>(item.object())->tp_name << '"'; + } + str << '}'; } } @@ -149,13 +212,17 @@ static void formatPyUnicode(PyObject *obj, std::ostream &str) { // Note: The below call create the PyCompactUnicodeObject.utf8 representation str << '"' << _PepUnicode_AsString(obj) << '"'; + if (!verbose) + return; str << " (" << PyUnicode_GetLength(obj) << ')'; const auto kind = _PepUnicode_KIND(obj); switch (kind) { +#if PY_VERSION_HEX < 0x030C0000 case PepUnicode_WCHAR_KIND: str << " [wchar]"; break; +#endif case PepUnicode_1BYTE_KIND: str << " [1byte]"; break; @@ -176,8 +243,10 @@ static void formatPyUnicode(PyObject *obj, std::ostream &str) void *data =_PepUnicode_DATA(obj); str << ", data="; switch (kind) { +#if PY_VERSION_HEX < 0x030C0000 case PepUnicode_WCHAR_KIND: formatCharSequence(reinterpret_cast<const wchar_t *>(data), str); +#endif break; case PepUnicode_1BYTE_KIND: formatCharSequence(reinterpret_cast<const Py_UCS1 *>(data), str); @@ -206,22 +275,92 @@ static void formatPyUnicode(PyObject *obj, std::ostream &str) #endif // !Py_LIMITED_API } +static std::string getQualName(PyObject *obj) +{ + Shiboken::AutoDecRef result(PyObject_GetAttr(obj, Shiboken::PyMagicName::qualname())); + return result.object() != nullptr + ? _PepUnicode_AsString(result.object()) : std::string{}; +} + +static void formatPyFunction(PyObject *obj, std::ostream &str) +{ + str << '"' << getQualName(obj) << "()\""; +} + +static void formatPyMethod(PyObject *obj, std::ostream &str) +{ + if (auto *func = PyMethod_Function(obj)) + formatPyFunction(func, str); + str << ", instance=" << PyMethod_Self(obj); +} + +static void formatPyCodeObject(PyObject *obj, std::ostream &str) +{ + if (auto name = getStringAttr(obj, "co_name")) + str << '"' << name.value() << '"'; + if (auto qualName = getStringAttr(obj, "co_qualname")) + str << ", co_qualname=\"" << qualName.value() << '"'; + if (auto flags = getIntAttr(obj, "co_flags")) + str << ", flags=0x" << std::hex << flags.value() << std::dec; + if (auto c = getIntAttr(obj, "co_argcount")) + str << ", co_argcounts=" << c.value(); + if (auto c = getIntAttr(obj, "co_posonlyargcount")) + str << ", co_posonlyargcount=" << c.value(); + if (auto c = getIntAttr(obj, "co_kwonlyargcount")) + str << ", co_kwonlyargcount=" << c.value(); + if (auto fileName = getStringAttr(obj, "co_filename")) { + str << " @" << fileName.value(); + if (auto l = getIntAttr(obj, "co_firstlineno")) + str << ':'<< l.value(); + } +} + static void formatPyObjectHelper(PyObject *obj, std::ostream &str) { - str << ", refs=" << obj->ob_refcnt << ", "; + str << ", "; + if (obj == Py_None) { + str << "None"; + return; + } + if (obj == Py_True) { + str << "True"; + return; + } + if (obj == Py_False) { + str << "False"; + return; + } + const auto refs = Py_REFCNT(obj); + if (refs == UINT_MAX) // _Py_IMMORTAL_REFCNT + str << "immortal, "; + else + str << "refs=" << refs << ", "; if (PyType_Check(obj)) { str << "type: "; - formatPyTypeObject(reinterpret_cast<PyTypeObject *>(obj), str); + formatPyTypeObject(reinterpret_cast<PyTypeObject *>(obj), str, true); return; } - formatPyTypeObject(obj->ob_type, str); + formatPyTypeObject(obj->ob_type, str, false); str << ", "; - if (PyLong_Check(obj)) - str << PyLong_AsLong(obj); + if (PyLong_Check(obj)) { + const auto llv = PyLong_AsLongLong(obj); + if (PyErr_Occurred() != PyExc_OverflowError) { + str << llv; + } else { + PyErr_Clear(); + str << "0x" << std::hex << PyLong_AsUnsignedLongLong(obj) << std::dec; + } + } else if (PyFloat_Check(obj)) str << PyFloat_AsDouble(obj); else if (PyUnicode_Check(obj)) formatPyUnicode(obj, str); + else if (PyFunction_Check(obj) != 0) + formatPyFunction(obj, str); + else if (PyMethod_Check(obj) != 0) + formatPyMethod(obj, str); + else if (PepCode_Check(obj) != 0) + formatPyCodeObject(obj, str); else if (PySequence_Check(obj)) formatPySequence(obj, str); else if (PyDict_Check(obj)) @@ -261,7 +400,7 @@ debugPyBuffer::debugPyBuffer(const Py_buffer &b) : m_buffer(b) std::ostream &operator<<(std::ostream &str, const debugPyTypeObject &o) { str << "PyTypeObject("; - formatPyTypeObject(o.m_object, str); + formatPyTypeObject(o.m_object, str, true); str << ')'; return str; } @@ -297,6 +436,18 @@ std::ostream &operator<<(std::ostream &str, const debugPyBuffer &b) return str; } +std::ios_base &debugVerbose(std::ios_base &s) +{ + verbose = true; + return s; +} + +std::ios_base &debugBrief(std::ios_base &s) +{ + verbose = false; + return s; +} + #ifdef _WIN32 // Converts a Unicode string to a string encoded in the Windows console's // code page via wchar_t for use with argv (PYSIDE-1425). @@ -462,4 +613,25 @@ const char *typeNameOf(const char *typeIdName) return result; } +#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030A0000 && !defined(PYPY_VERSION) +static int _getPyVerbose() +{ + PyConfig config; + PyConfig_InitPythonConfig(&config); + return config.verbose; +} +#endif // !Py_LIMITED_API >= 3.10 + +int pyVerbose() +{ +#ifdef Py_LIMITED_API + return Pep_GetVerboseFlag(); +#elif PY_VERSION_HEX >= 0x030A0000 && !defined(PYPY_VERSION) + static const int result = _getPyVerbose(); + return result; +#else + return Py_VerboseFlag; +#endif +} + } // namespace Shiboken |