702702_PyModuleSpec_IsInitializing (PyObject * spec )
703703{
704704 if (spec != NULL ) {
705- PyObject * value = PyObject_GetAttr (spec , & _Py_ID (_initializing ));
705+ PyObject * value ;
706+ int ok = _PyObject_LookupAttr (spec , & _Py_ID (_initializing ), & value );
707+ if (ok == 0 ) {
708+ return 0 ;
709+ }
706710 if (value != NULL ) {
707711 int initializing = PyObject_IsTrue (value );
708712 Py_DECREF (value );
@@ -738,19 +742,37 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name)
738742 return is_uninitialized ;
739743}
740744
741- static PyObject *
742- module_getattro (PyModuleObject * m , PyObject * name )
745+ PyObject *
746+ _Py_module_getattro_impl (PyModuleObject * m , PyObject * name , int suppress )
743747{
748+ // When suppress=1, this function suppresses AttributeError.
744749 PyObject * attr , * mod_name , * getattr ;
745- attr = PyObject_GenericGetAttr ((PyObject * )m , name );
746- if (attr || ! PyErr_ExceptionMatches ( PyExc_AttributeError ) ) {
750+ attr = _PyObject_GenericGetAttrWithDict ((PyObject * )m , name , NULL , suppress );
751+ if (attr ) {
747752 return attr ;
748753 }
749- PyErr_Clear ();
754+ if (suppress == 1 ) {
755+ if (PyErr_Occurred ()) {
756+ // pass up non-AttributeError exception
757+ return NULL ;
758+ }
759+ }
760+ else {
761+ if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
762+ // pass up non-AttributeError exception
763+ return NULL ;
764+ }
765+ PyErr_Clear ();
766+ }
750767 assert (m -> md_dict != NULL );
751768 getattr = PyDict_GetItemWithError (m -> md_dict , & _Py_ID (__getattr__ ));
752769 if (getattr ) {
753- return PyObject_CallOneArg (getattr , name );
770+ PyObject * result = PyObject_CallOneArg (getattr , name );
771+ if (result == NULL && suppress == 1 && PyErr_ExceptionMatches (PyExc_AttributeError )) {
772+ // suppress AttributeError
773+ PyErr_Clear ();
774+ }
775+ return result ;
754776 }
755777 if (PyErr_Occurred ()) {
756778 return NULL ;
@@ -763,37 +785,48 @@ module_getattro(PyModuleObject *m, PyObject *name)
763785 Py_DECREF (mod_name );
764786 return NULL ;
765787 }
766- Py_XINCREF (spec );
767- if (_PyModuleSpec_IsInitializing (spec )) {
768- PyErr_Format (PyExc_AttributeError ,
769- "partially initialized "
770- "module '%U' has no attribute '%U' "
771- "(most likely due to a circular import)" ,
772- mod_name , name );
773- }
774- else if (_PyModuleSpec_IsUninitializedSubmodule (spec , name )) {
775- PyErr_Format (PyExc_AttributeError ,
776- "cannot access submodule '%U' of module '%U' "
777- "(most likely due to a circular import)" ,
778- name , mod_name );
779- }
780- else {
781- PyErr_Format (PyExc_AttributeError ,
782- "module '%U' has no attribute '%U'" ,
783- mod_name , name );
788+ if (suppress != 1 ) {
789+ Py_XINCREF (spec );
790+ if (_PyModuleSpec_IsInitializing (spec )) {
791+ PyErr_Format (PyExc_AttributeError ,
792+ "partially initialized "
793+ "module '%U' has no attribute '%U' "
794+ "(most likely due to a circular import)" ,
795+ mod_name , name );
796+ }
797+ else if (_PyModuleSpec_IsUninitializedSubmodule (spec , name )) {
798+ PyErr_Format (PyExc_AttributeError ,
799+ "cannot access submodule '%U' of module '%U' "
800+ "(most likely due to a circular import)" ,
801+ name , mod_name );
802+ }
803+ else {
804+ PyErr_Format (PyExc_AttributeError ,
805+ "module '%U' has no attribute '%U'" ,
806+ mod_name , name );
807+ }
808+ Py_XDECREF (spec );
784809 }
785- Py_XDECREF (spec );
786810 Py_DECREF (mod_name );
787811 return NULL ;
788812 }
789813 else if (PyErr_Occurred ()) {
790814 return NULL ;
791815 }
792- PyErr_Format (PyExc_AttributeError ,
793- "module has no attribute '%U'" , name );
816+ if (suppress != 1 ) {
817+ PyErr_Format (PyExc_AttributeError ,
818+ "module has no attribute '%U'" , name );
819+ }
794820 return NULL ;
795821}
796822
823+
824+ PyObject *
825+ _Py_module_getattro (PyModuleObject * m , PyObject * name )
826+ {
827+ return _Py_module_getattro_impl (m , name , 0 );
828+ }
829+
797830static int
798831module_traverse (PyModuleObject * m , visitproc visit , void * arg )
799832{
@@ -951,7 +984,7 @@ PyTypeObject PyModule_Type = {
951984 0 , /* tp_hash */
952985 0 , /* tp_call */
953986 0 , /* tp_str */
954- (getattrofunc )module_getattro , /* tp_getattro */
987+ (getattrofunc )_Py_module_getattro , /* tp_getattro */
955988 PyObject_GenericSetAttr , /* tp_setattro */
956989 0 , /* tp_as_buffer */
957990 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
0 commit comments