- 8 DB models (services, incidents, monitors, subscribers, etc.) - Full CRUD API for services, incidents, monitors - Public status page with live data - Incident detail page with timeline - API key authentication - Uptime monitoring scheduler - 13 tests passing - TECHNICAL_DESIGN.md with full spec
209 lines
5.1 KiB
C
209 lines
5.1 KiB
C
// Collects code that was copied in from cpython, for a couple of different reasons:
|
|
// * We wanted to modify it to produce a more efficient version for our uses
|
|
// * We needed to call it and it was static :(
|
|
// * We wanted to call it and needed to backport it
|
|
|
|
#include "pythonsupport.h"
|
|
|
|
/////////////////////////////////////////
|
|
// Adapted from bltinmodule.c in Python 3.7.0
|
|
PyObject*
|
|
update_bases(PyObject *bases)
|
|
{
|
|
Py_ssize_t i, j;
|
|
PyObject *base, *meth, *new_base, *result, *new_bases = NULL;
|
|
PyObject *stack[1] = {bases};
|
|
assert(PyTuple_Check(bases));
|
|
|
|
Py_ssize_t nargs = PyTuple_GET_SIZE(bases);
|
|
for (i = 0; i < nargs; i++) {
|
|
base = PyTuple_GET_ITEM(bases, i);
|
|
if (PyType_Check(base)) {
|
|
if (new_bases) {
|
|
/* If we already have made a replacement, then we append every normal base,
|
|
otherwise just skip it. */
|
|
if (PyList_Append(new_bases, base) < 0) {
|
|
goto error;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
if (PyObject_GetOptionalAttr(base, mypyc_interned_str.__mro_entries__, &meth) < 0) {
|
|
goto error;
|
|
}
|
|
if (!meth) {
|
|
if (new_bases) {
|
|
if (PyList_Append(new_bases, base) < 0) {
|
|
goto error;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
new_base = PyObject_Vectorcall(meth, stack, 1, NULL);
|
|
Py_DECREF(meth);
|
|
if (!new_base) {
|
|
goto error;
|
|
}
|
|
if (!PyTuple_Check(new_base)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"__mro_entries__ must return a tuple");
|
|
Py_DECREF(new_base);
|
|
goto error;
|
|
}
|
|
if (!new_bases) {
|
|
/* If this is a first successful replacement, create new_bases list and
|
|
copy previously encountered bases. */
|
|
if (!(new_bases = PyList_New(i))) {
|
|
goto error;
|
|
}
|
|
for (j = 0; j < i; j++) {
|
|
base = PyTuple_GET_ITEM(bases, j);
|
|
PyList_SET_ITEM(new_bases, j, base);
|
|
Py_INCREF(base);
|
|
}
|
|
}
|
|
j = PyList_GET_SIZE(new_bases);
|
|
if (PyList_SetSlice(new_bases, j, j, new_base) < 0) {
|
|
goto error;
|
|
}
|
|
Py_DECREF(new_base);
|
|
}
|
|
if (!new_bases) {
|
|
return bases;
|
|
}
|
|
result = PyList_AsTuple(new_bases);
|
|
Py_DECREF(new_bases);
|
|
return result;
|
|
|
|
error:
|
|
Py_XDECREF(new_bases);
|
|
return NULL;
|
|
}
|
|
|
|
// From Python 3.7's typeobject.c
|
|
int
|
|
init_subclass(PyTypeObject *type, PyObject *kwds)
|
|
{
|
|
PyObject *super, *func, *result;
|
|
PyObject *args[2] = {(PyObject *)type, (PyObject *)type};
|
|
|
|
super = PyObject_Vectorcall((PyObject *)&PySuper_Type, args, 2, NULL);
|
|
if (super == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
func = PyObject_GetAttr(super, mypyc_interned_str.__init_subclass__);
|
|
Py_DECREF(super);
|
|
if (func == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
result = _PyObject_FastCallDict(func, NULL, 0, kwds);
|
|
Py_DECREF(func);
|
|
if (result == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
Py_DECREF(result);
|
|
return 0;
|
|
}
|
|
|
|
#if CPY_3_12_FEATURES
|
|
|
|
// Slow path of CPyLong_AsSsize_tAndOverflow (non-inlined)
|
|
Py_ssize_t
|
|
CPyLong_AsSsize_tAndOverflow_(PyObject *vv, int *overflow)
|
|
{
|
|
PyLongObject *v = (PyLongObject *)vv;
|
|
size_t x, prev;
|
|
Py_ssize_t res;
|
|
Py_ssize_t i;
|
|
int sign;
|
|
|
|
*overflow = 0;
|
|
|
|
res = -1;
|
|
i = CPY_LONG_TAG(v);
|
|
|
|
sign = 1;
|
|
x = 0;
|
|
if (i & CPY_SIGN_NEGATIVE) {
|
|
sign = -1;
|
|
}
|
|
i >>= CPY_NON_SIZE_BITS;
|
|
while (--i >= 0) {
|
|
prev = x;
|
|
x = (x << PyLong_SHIFT) + CPY_LONG_DIGIT(v, i);
|
|
if ((x >> PyLong_SHIFT) != prev) {
|
|
*overflow = sign;
|
|
goto exit;
|
|
}
|
|
}
|
|
/* Haven't lost any bits, but casting to long requires extra
|
|
* care.
|
|
*/
|
|
if (x <= (size_t)CPY_TAGGED_MAX) {
|
|
res = (Py_ssize_t)x * sign;
|
|
}
|
|
else if (sign < 0 && x == CPY_TAGGED_ABS_MIN) {
|
|
res = CPY_TAGGED_MIN;
|
|
}
|
|
else {
|
|
*overflow = sign;
|
|
/* res is already set to -1 */
|
|
}
|
|
exit:
|
|
return res;
|
|
}
|
|
|
|
#else
|
|
|
|
// Slow path of CPyLong_AsSsize_tAndOverflow (non-inlined, Python 3.11 and earlier)
|
|
Py_ssize_t
|
|
CPyLong_AsSsize_tAndOverflow_(PyObject *vv, int *overflow)
|
|
{
|
|
/* This version by Tim Peters */
|
|
PyLongObject *v = (PyLongObject *)vv;
|
|
size_t x, prev;
|
|
Py_ssize_t res;
|
|
Py_ssize_t i;
|
|
int sign;
|
|
|
|
*overflow = 0;
|
|
|
|
res = -1;
|
|
i = Py_SIZE(v);
|
|
|
|
sign = 1;
|
|
x = 0;
|
|
if (i < 0) {
|
|
sign = -1;
|
|
i = -(i);
|
|
}
|
|
while (--i >= 0) {
|
|
prev = x;
|
|
x = (x << PyLong_SHIFT) + CPY_LONG_DIGIT(v, i);
|
|
if ((x >> PyLong_SHIFT) != prev) {
|
|
*overflow = sign;
|
|
goto exit;
|
|
}
|
|
}
|
|
/* Haven't lost any bits, but casting to long requires extra
|
|
* care.
|
|
*/
|
|
if (x <= (size_t)CPY_TAGGED_MAX) {
|
|
res = (Py_ssize_t)x * sign;
|
|
}
|
|
else if (sign < 0 && x == CPY_TAGGED_ABS_MIN) {
|
|
res = CPY_TAGGED_MIN;
|
|
}
|
|
else {
|
|
*overflow = sign;
|
|
/* res is already set to -1 */
|
|
}
|
|
exit:
|
|
return res;
|
|
}
|
|
|
|
|
|
#endif
|