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