ifcwrap: accept numpy scalars in aggregate type check #5873

check_aggregate_of_type used an exact type comparison (element->ob_type ==
type_obj), so a numpy array was rejected because its elements are numpy scalars
(numpy.float64) rather than direct float instances. For the numeric types,
accept subclasses: PyFloat_Check for double (numpy.float64 subclasses float) and
PyLong_Check (excluding bool) for int. The SPF REAL vs INTEGER distinction is
kept, so a float is not accepted where an int is expected and vice versa.

This replaces the earlier Python-side walk() approach, which the maintainer
preferred not to take since walk() is removed in v0.9. Verified with a runtime
red-green (built as a shared lib, called via ctypes): the old check rejects
np.array([3.0, 4.0]) and the new one accepts it, plain lists still work, an int
list is still rejected where a REAL is expected, and bool is rejected for INTEGER.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Petru Conduraru
2026-07-06 12:56:01 +03:00
committed by Thomas Krijnen
parent d2381ad6c6
commit b1be7d92e6
+13 -3
View File
@@ -34,9 +34,19 @@
if (PySequence_Size(aggregate) == -1) return false;
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
PyObject* element = PySequence_GetItem(aggregate, i);
// This is equivalent to the PyFloat_CheckExact macro. This means
// that direct instances of int, float, str, etc. need to be used.
bool b = element->ob_type == type_obj;
// Accept the exact type or, for the numeric types, a subclass such
// as a numpy scalar (numpy.float64 subclasses float), so that numpy
// arrays can be assigned. The REAL vs INTEGER distinction is kept: a
// float is not accepted where an int is expected and vice versa, and
// bool (a subclass of int) is still rejected for INTEGER. See #5873.
bool b;
if (type_obj == static_cast<void*>(&PyFloat_Type)) {
b = PyFloat_Check(element);
} else if (type_obj == static_cast<void*>(&PyLong_Type)) {
b = PyLong_Check(element) && !PyBool_Check(element);
} else {
b = element->ob_type == type_obj;
}
Py_DECREF(element);
if (!b) {
return false;