diff --git a/python/convert.c b/python/convert.c index 2b3a4e3dd1..b37ca481d9 100644 --- a/python/convert.c +++ b/python/convert.c @@ -214,6 +214,10 @@ static bool PyUpb_PyToUpbEnum(PyObject* obj, const upb_FieldDef* f, bool PyUpb_IsNumpyNdarray(PyObject* obj, const upb_FieldDef* f) { PyObject* type_name_obj = PyObject_GetAttrString((PyObject*)Py_TYPE(obj), "__name__"); + if (!type_name_obj) { + PyErr_Clear(); + return false; + } bool is_ndarray = false; if (!strcmp(PyUpb_GetStrData(type_name_obj), "ndarray")) { PyErr_Format(PyExc_TypeError, @@ -228,6 +232,10 @@ bool PyUpb_IsNumpyNdarray(PyObject* obj, const upb_FieldDef* f) { bool PyUpb_IsNumpyBoolScalar(PyObject* obj) { PyObject* type_module_obj = PyObject_GetAttrString((PyObject*)Py_TYPE(obj), "__module__"); + if (!type_module_obj) { + PyErr_Clear(); + return false; + } bool is_numpy = !strcmp(PyUpb_GetStrData(type_module_obj), "numpy"); Py_DECREF(type_module_obj); if (!is_numpy) { @@ -236,6 +244,10 @@ bool PyUpb_IsNumpyBoolScalar(PyObject* obj) { PyObject* type_name_obj = PyObject_GetAttrString((PyObject*)Py_TYPE(obj), "__name__"); + if (!type_name_obj) { + PyErr_Clear(); + return false; + } bool is_bool = !strcmp(PyUpb_GetStrData(type_name_obj), "bool"); Py_DECREF(type_name_obj); if (!is_bool) { diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py index 825f5cd1a5..2c21a17940 100644 --- a/python/google/protobuf/internal/message_factory_test.py +++ b/python/google/protobuf/internal/message_factory_test.py @@ -395,6 +395,21 @@ class MessageFactoryTest(unittest.TestCase): self.assertEqual('hello', values[0].key) self.assertEqual('welcome', values[0].value) + def testConvertNumpyDetectionNullAttribute(self): + class NamelessMeta(type): + def __getattribute__(cls, name): + if name == '__name__' or name == '__module__': + raise AttributeError('no attribute') + return super().__getattribute__(name) + + class Nameless(metaclass=NamelessMeta): + def __index__(self): + return 42 + + msg = factory_test1_pb2.Factory1Message() + msg.scalar_value = Nameless() + self.assertEqual(msg.scalar_value, 42) + if __name__ == '__main__': unittest.main() diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py index a12f42661f..e959688d39 100755 --- a/python/google/protobuf/internal/type_checkers.py +++ b/python/google/protobuf/internal/type_checkers.py @@ -121,8 +121,8 @@ class BoolValueChecker(object): if not hasattr(proposed_value, '__index__'): # Under NumPy 2.3, numpy.bool does not have an __index__ method. if ( - type(proposed_value).__module__ == 'numpy' - and type(proposed_value).__name__ == 'bool' + getattr(type(proposed_value), '__module__', None) == 'numpy' + and getattr(type(proposed_value), '__name__', None) == 'bool' ): return bool(proposed_value) message = '%.1024r has type %s, but expected one of: %s' % ( @@ -133,8 +133,8 @@ class BoolValueChecker(object): raise TypeError(message) if ( - type(proposed_value).__module__ == 'numpy' - and type(proposed_value).__name__ == 'ndarray' + getattr(type(proposed_value), '__module__', None) == 'numpy' + and getattr(type(proposed_value), '__name__', None) == 'ndarray' ): message = '%.1024r has type %s, but expected one of: %s' % ( proposed_value, @@ -166,8 +166,8 @@ class IntValueChecker(object): raise TypeError(message) if not hasattr(proposed_value, '__index__') or ( - type(proposed_value).__module__ == 'numpy' - and type(proposed_value).__name__ == 'ndarray' + getattr(type(proposed_value), '__module__', None) == 'numpy' + and getattr(type(proposed_value), '__name__', None) == 'ndarray' ): message = '%.1024r has type %s, but expected one of: %s' % ( proposed_value, @@ -301,8 +301,8 @@ class DoubleValueChecker(object): not hasattr(proposed_value, '__float__') and not hasattr(proposed_value, '__index__') ) or ( - type(proposed_value).__module__ == 'numpy' - and type(proposed_value).__name__ == 'ndarray' + getattr(type(proposed_value), '__module__', None) == 'numpy' + and getattr(type(proposed_value), '__name__', None) == 'ndarray' ): message = '%.1024r has type %s, but expected one of: int, float' % ( proposed_value,