facundo
(Facundo Batista)
March 19, 2024, 7:46pm
1
I have a weird situation here, but the question goes for the issubclass
message/behaviour, see…
I have a two objects from the system I’m debugging, obj_x
and obj_y
.
They are probably classes:
(Pdb) inspect.isclass(obj_x)
True
(Pdb) inspect.isclass(obj_y)
True
They are not subclass of something I just create:
(Pdb) class C: pass
(Pdb) issubclass(obj_x, C)
False
(Pdb) issubclass(obj_y, C)
False
And the thing I just created is not subclass of those!
(Pdb) issubclass(C, obj_x)
False
(Pdb) issubclass(C, obj_y)
False
Now the strange thing:
(Pdb) issubclass(obj_x, obj_y)
*** TypeError: issubclass() arg 1 must be a class
What? It is a class! …or maybe not? What?
(BTW, the “arg 1” also confused me… I initially thought it was the second argument)
So, why is it saying that obj_x
is not a class? What is it checking?
Shall I open a bug about this?
Thanks!
Maybe obj_x
doesn’t have __bases__
properly set?
cpython does this check
if (!check_class(derived,
"issubclass() arg 1 must be a class"))
return -1;
where
static int
check_class(PyObject *cls, const char *error)
{
PyObject *bases = abstract_get_bases(cls);
if (bases == NULL) {
/* Do not mask errors. */
PyThreadState *tstate = _PyThreadState_GET();
if (!_PyErr_Occurred(tstate)) {
_PyErr_SetString(tstate, PyExc_TypeError, error);
}
return 0;
}
Py_DECREF(bases);
return -1;
}
kknechtel
(Karl Knechtel)
March 19, 2024, 9:04pm
3
Do you have any code that reliably reproduces the situation? Is there any of your own C code involved in causing the problem?
facundo
(Facundo Batista)
March 19, 2024, 9:05pm
4
Both have __bases__
.
Following the C code, can’t understand how it’s failing like this.
facundo
(Facundo Batista)
March 19, 2024, 9:07pm
5
This is the worst part. No, I cannot reproduce it in a snippet … big proprietary system, super complex.
facundo
(Facundo Batista)
March 20, 2024, 2:42am
7
Sorry, I’ll clarify. I probably could reproduce it in a snippet, but it would be a lot of work to reduce crazy-inheritance multi-modules packages to just one file.
I’m tempted, though.
Spitballing: Maybe __bases__
is not a tuple (due to failing the check for the flag below) !?
static PyObject *
abstract_get_bases(PyObject *cls)
{
PyObject *bases;
(void)PyObject_GetOptionalAttr(cls, &_Py_ID(__bases__), &bases);
if (bases != NULL && !PyTuple_Check(bases)) {
Py_DECREF(bases);
return NULL;
}
return bases;
}
where
#define PyTuple_Check(op) \
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TUPLE_SUBCLASS)
I thought I had a smaller example - but mixed up my classes and instances…
On the Python level (3.11) it’s not possible to assign anything apart from tuples to the __bases__
, so I suppose something must be going wrong deeper down…