1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "sbkerrors.h"
#include "sbkstring.h"
#include "helper.h"
#include "gilstate.h"
#include <cstdio>
#include <string>
using namespace std::literals::string_literals;
namespace Shiboken
{
// PYSIDE-2335: Track down if we can reach a Python error handler.
// _pythonContextStack has always the current state of handler status
// in its lowest bit.
// Blocking calls like exec or run need to use `setBlocking`.
static thread_local std::size_t _pythonContextStack{};
PythonContextMarker::PythonContextMarker()
{
// Shift history up and set lowest bit.
_pythonContextStack = (_pythonContextStack * 2) + 1;
}
PythonContextMarker::~PythonContextMarker()
{
// Shift history down.
_pythonContextStack /= 2;
}
void PythonContextMarker::setBlocking()
{
// Clear lowest bit.
_pythonContextStack = _pythonContextStack / 2 * 2;
}
namespace Errors
{
void setIndexOutOfBounds(Py_ssize_t value, Py_ssize_t minValue, Py_ssize_t maxValue)
{
PyErr_Format(PyExc_IndexError,
"index %zd out of bounds %zd..%zd", value, minValue, maxValue);
}
void setInstantiateAbstractClass(const char *name)
{
PyErr_Format(PyExc_NotImplementedError,
"'%s' represents a C++ abstract class and cannot be instantiated", name);
}
void setInstantiateAbstractClassDisabledWrapper(const char *name)
{
PyErr_Format(PyExc_NotImplementedError,
"Abstract class '%s' cannot be instantiated since the wrapper has been disabled.",
name);
}
void setInstantiateNamespace(const char *name)
{
PyErr_Format(PyExc_NotImplementedError, "Namespace '%s' cannot be instantiated.", name);
}
void setInstantiateNonConstructible(const char *name)
{
PyErr_Format(PyExc_NotImplementedError, "Class '%s' cannot be instantiated.", name);
}
void setInvalidTypeDeletion(const char *name)
{
PyErr_Format(PyExc_TypeError, "'%s' may not be deleted", name);
}
void setOperatorNotImplemented()
{
PyErr_SetString(PyExc_NotImplementedError, "operator not implemented.");
}
void setPureVirtualMethodError(const char *name)
{
PyErr_Format(PyExc_NotImplementedError, "pure virtual method '%s' not implemented.", name);
}
void setPrivateMethod(const char *name)
{
PyErr_Format(PyExc_TypeError, "%s is a private method.\", ", name);
}
void setReverseOperatorNotImplemented()
{
PyErr_SetString(PyExc_NotImplementedError, "reverse operator not implemented.");
}
void setSequenceTypeError(const char *expectedType)
{
PyErr_Format(PyExc_TypeError,
"attributed value with wrong type, '%s' or other convertible type expected",
expectedType);
}
void setSetterTypeError(const char *name, const char *expectedType)
{
PyErr_Format(PyExc_TypeError,
"wrong type attributed to '%s', '%s' or convertible type expected",
name, expectedType);
}
void setWrongContainerType()
{
PyErr_SetString(PyExc_TypeError, "Wrong type passed to container conversion.");
}
// Prepend something to an exception message provided it is a single string
// argument.
static bool prependToExceptionMessage(PyObject *exc, const char *context)
{
Shiboken::AutoDecRef args(PepException_GetArgs(exc));
if (args.isNull() || PyTuple_Check(args.object()) == 0 || PyTuple_Size(args) != 1)
return false;
auto *oldMessage = PyTuple_GetItem(args, 0);
if (oldMessage == nullptr || PyUnicode_CheckExact(oldMessage) == 0)
return false;
auto *newMessage = PyUnicode_FromFormat("%s%U", context, oldMessage);
PepException_SetArgs(exc, PyTuple_Pack(1, newMessage));
return true;
}
struct ErrorStore {
PyObject *type;
PyObject *exc;
PyObject *traceback;
};
static thread_local ErrorStore savedError{};
static bool hasPythonContext()
{
return _pythonContextStack & 1;
}
void storeErrorOrPrint()
{
// This error happened in a function with no way to return an error state.
// Therefore, we handle the error when we are error checking, anyway.
// But we do that only when we know that an error handler can pick it up.
if (hasPythonContext())
PyErr_Fetch(&savedError.type, &savedError.exc, &savedError.traceback);
else
PyErr_Print();
}
// Like storeErrorOrPrint() with additional context info that is prepended
// to the exception message or printed.
static void storeErrorOrPrintWithContext(const char *context)
{
if (hasPythonContext()) {
PyErr_Fetch(&savedError.type, &savedError.exc, &savedError.traceback);
prependToExceptionMessage(savedError.exc, context);
} else {
std::fputs(context, stderr);
PyErr_Print();
}
}
void storePythonOverrideErrorOrPrint(const char *className, const char *funcName)
{
const std::string context = "Error calling Python override of "s
+ className + "::"s + funcName + "(): "s;
storeErrorOrPrintWithContext(context.c_str());
}
PyObject *occurred()
{
if (savedError.type) {
PyErr_Restore(savedError.type, savedError.exc, savedError.traceback);
savedError.type = nullptr;
}
return PyErr_Occurred();
}
} // namespace Errors
namespace Warnings
{
void warnInvalidReturnValue(const char *className, const char *functionName,
const char *expectedType, const char *actualType)
{
Shiboken::warning(PyExc_RuntimeWarning, 2,
"Invalid return value in function '%s.%s', expected %s, got %s.",
className, functionName, expectedType, actualType);
}
void warnDeprecated(const char *functionName)
{
Shiboken::warning(PyExc_DeprecationWarning, 1,
"Function: '%s' is marked as deprecated, please check "
"the documentation for more information.",
functionName);
}
void warnDeprecated(const char *className, const char *functionName)
{
Shiboken::warning(PyExc_DeprecationWarning, 1,
"Function: '%s.%s' is marked as deprecated, please check "
"the documentation for more information.",
className, functionName);
}
void warnDeprecatedEnum(const char *enumName)
{
Shiboken::warning(PyExc_DeprecationWarning, 1,
"Enum: '%s' is marked as deprecated, please check "
"the documentation for more information.",
enumName);
}
void warnDeprecatedEnumValue(const char *enumName, const char *valueName)
{
Shiboken::warning(PyExc_DeprecationWarning, 1,
"Enum value '%s.%s' is marked as deprecated, please check "
"the documentation for more information.",
enumName, valueName);
}
} // namespace Warnings
} // namespace Shiboken
|