@@ -788,7 +788,7 @@ PyObject*
788
788
_Py_module_getattro_impl (PyModuleObject * m , PyObject * name , int suppress )
789
789
{
790
790
// When suppress=1, this function suppresses AttributeError.
791
- PyObject * attr , * mod_name , * getattr , * origin ;
791
+ PyObject * attr , * mod_name , * getattr ;
792
792
attr = _PyObject_GenericGetAttrWithDict ((PyObject * )m , name , NULL , suppress );
793
793
if (attr ) {
794
794
return attr ;
@@ -837,48 +837,120 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
837
837
Py_DECREF (mod_name );
838
838
return NULL ;
839
839
}
840
- int rc = _PyModuleSpec_IsInitializing ( spec ) ;
841
- if (rc > 0 ) {
842
- int valid_spec = PyObject_GetOptionalAttr (spec , & _Py_ID (origin ), & origin );
843
- if (valid_spec == -1 ) {
844
- Py_XDECREF (spec );
840
+ PyObject * origin = NULL ;
841
+ if (spec ) {
842
+ int rc = PyObject_GetOptionalAttr (spec , & _Py_ID (origin ), & origin );
843
+ if (rc == -1 ) {
844
+ Py_DECREF (spec );
845
845
Py_DECREF (mod_name );
846
846
return NULL ;
847
847
}
848
- if (valid_spec == 1 && !PyUnicode_Check (origin )) {
849
- valid_spec = 0 ;
850
- Py_DECREF (origin );
851
- }
852
- if (valid_spec == 1 ) {
853
- PyErr_Format (PyExc_AttributeError ,
854
- "partially initialized "
855
- "module '%U' from '%U' has no attribute '%U' "
856
- "(most likely due to a circular import)" ,
857
- mod_name , origin , name );
848
+ if (rc == 1 && !PyUnicode_Check (origin )) {
858
849
Py_DECREF (origin );
850
+ origin = NULL ;
859
851
}
860
- else {
861
- PyErr_Format (PyExc_AttributeError ,
862
- "partially initialized "
863
- "module '%U' has no attribute '%U' "
864
- "(most likely due to a circular import)" ,
865
- mod_name , name );
852
+ }
853
+
854
+ int is_script_shadowing_stdlib = 0 ;
855
+ // Check mod.__name__ in sys.stdlib_module_names
856
+ // and os.path.dirname(mod.__spec__.origin) == os.getcwd()
857
+ PyObject * stdlib = NULL ;
858
+ if (origin ) {
859
+ if (
860
+ // avoid bad recursion
861
+ PyUnicode_CompareWithASCIIString (mod_name , "sys" ) != 0
862
+ && PyUnicode_CompareWithASCIIString (mod_name , "os" ) != 0
863
+ && PyUnicode_CompareWithASCIIString (mod_name , "builtins" ) != 0
864
+ ) {
865
+ stdlib = _PyImport_GetModuleAttrString ("sys" , "stdlib_module_names" );
866
+ if (!stdlib ) {
867
+ if (PyErr_ExceptionMatches (PyExc_AttributeError )) {
868
+ PyErr_Clear ();
869
+ } else {
870
+ goto done ;
871
+ }
872
+ }
873
+ if (stdlib && PyFrozenSet_Check (stdlib ) && PySet_Contains (stdlib , mod_name )) {
874
+ PyObject * os_path = _PyImport_GetModuleAttrString ("os" , "path" );
875
+ if (!os_path ) {
876
+ goto done ;
877
+ }
878
+ PyObject * dirname = PyObject_GetAttrString (os_path , "dirname" );
879
+ Py_DECREF (os_path );
880
+ if (!dirname ) {
881
+ goto done ;
882
+ }
883
+ PyObject * origin_dir = _PyObject_CallOneArg (dirname , origin );
884
+ Py_DECREF (dirname );
885
+ if (!origin_dir ) {
886
+ goto done ;
887
+ }
888
+
889
+ PyObject * getcwd = _PyImport_GetModuleAttrString ("os" , "getcwd" );
890
+ if (!getcwd ) {
891
+ Py_DECREF (origin_dir );
892
+ goto done ;
893
+ }
894
+ PyObject * cwd = _PyObject_CallNoArgs (getcwd );
895
+ Py_DECREF (getcwd );
896
+ if (!cwd ) {
897
+ Py_DECREF (origin_dir );
898
+ goto done ;
899
+ }
900
+
901
+ is_script_shadowing_stdlib = PyObject_RichCompareBool (origin_dir , cwd , Py_EQ );
902
+ Py_DECREF (origin_dir );
903
+ Py_DECREF (cwd );
904
+ if (is_script_shadowing_stdlib < 0 ) {
905
+ goto done ;
906
+ }
907
+ }
866
908
}
867
909
}
868
- else if (rc == 0 ) {
869
- rc = _PyModuleSpec_IsUninitializedSubmodule (spec , name );
910
+
911
+ if (is_script_shadowing_stdlib == 1 ) {
912
+ PyErr_Format (PyExc_AttributeError ,
913
+ "module '%U' has no attribute '%U' "
914
+ "(most likely due to '%U' shadowing the standard library "
915
+ "module named '%U')" ,
916
+ mod_name , name , origin , mod_name );
917
+ } else {
918
+ int rc = _PyModuleSpec_IsInitializing (spec );
870
919
if (rc > 0 ) {
871
- PyErr_Format (PyExc_AttributeError ,
872
- "cannot access submodule '%U' of module '%U' "
873
- "(most likely due to a circular import)" ,
874
- name , mod_name );
920
+ if (origin ) {
921
+ PyErr_Format (PyExc_AttributeError ,
922
+ "partially initialized "
923
+ "module '%U' from '%U' has no attribute '%U' "
924
+ "(most likely due to a circular import)" ,
925
+ mod_name , origin , name );
926
+ }
927
+ else {
928
+ PyErr_Format (PyExc_AttributeError ,
929
+ "partially initialized "
930
+ "module '%U' has no attribute '%U' "
931
+ "(most likely due to a circular import)" ,
932
+ mod_name , name );
933
+ }
875
934
}
876
935
else if (rc == 0 ) {
877
- PyErr_Format (PyExc_AttributeError ,
878
- "module '%U' has no attribute '%U'" ,
879
- mod_name , name );
936
+ rc = _PyModuleSpec_IsUninitializedSubmodule (spec , name );
937
+ if (rc > 0 ) {
938
+ PyErr_Format (PyExc_AttributeError ,
939
+ "cannot access submodule '%U' of module '%U' "
940
+ "(most likely due to a circular import)" ,
941
+ name , mod_name );
942
+ }
943
+ else if (rc == 0 ) {
944
+ PyErr_Format (PyExc_AttributeError ,
945
+ "module '%U' has no attribute '%U'" ,
946
+ mod_name , name );
947
+ }
880
948
}
881
949
}
950
+
951
+ done :
952
+ Py_XDECREF (stdlib );
953
+ Py_XDECREF (origin );
882
954
Py_XDECREF (spec );
883
955
Py_DECREF (mod_name );
884
956
return NULL ;
0 commit comments