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