@@ -935,24 +935,21 @@ def setUp(self):
935935 site ._pending_importexecs .clear ()
936936
937937 def tearDown (self ):
938- site ._pending_entrypoints .clear ()
939- site ._pending_entrypoints .update (self .saved_entrypoints )
940- site ._pending_syspaths .clear ()
941- site ._pending_syspaths .update (self .saved_syspaths )
942- site ._pending_importexecs .clear ()
943- site ._pending_importexecs .update (self .saved_importexecs )
938+ site ._pending_entrypoints = self .saved_entrypoints .copy ()
939+ site ._pending_syspaths = self .saved_syspaths .copy ()
940+ site ._pending_importexecs = self .saved_importexecs .copy ()
944941
945942 def _make_start (self , content , name = 'testpkg' ):
946943 """Write a <name>.start file and return its basename."""
947- basename = name + ' .start'
944+ basename = f" { name } .start"
948945 filepath = os .path .join (self .tmpdir , basename )
949946 with open (filepath , 'w' , encoding = 'utf-8' ) as f :
950947 f .write (content )
951948 return basename
952949
953950 def _make_pth (self , content , name = 'testpkg' ):
954951 """Write a <name>.pth file and return its basename."""
955- basename = name + ' .pth'
952+ basename = f" { name } .pth"
956953 filepath = os .path .join (self .tmpdir , basename )
957954 with open (filepath , 'w' , encoding = 'utf-8' ) as f :
958955 f .write (content )
@@ -966,6 +963,9 @@ def _all_entrypoints(self):
966963 result .append ((filename , entry ))
967964 return result
968965
966+ def _just_entrypoints (self ):
967+ return [entry for filename , entry in self ._all_entrypoints ()]
968+
969969 # --- _read_start_file tests ---
970970
971971 def test_read_start_file_basic (self ):
@@ -995,14 +995,21 @@ def test_read_start_file_missing_colon_skipped(self):
995995 self .assertEqual (site ._pending_entrypoints [fullname ], ['os.path:join' ])
996996
997997 def test_read_start_file_empty (self ):
998+ # PEP 829: an empty .start file is still registered as present
999+ # (with an empty entry-point list) so that it suppresses `import`
1000+ # lines in any matching .pth file.
9981001 self ._make_start ("" , name = 'foo' )
9991002 site ._read_start_file (self .sitedir , 'foo.start' )
1000- self .assertEqual (site ._pending_entrypoints , {})
1003+ fullname = os .path .join (self .sitedir , 'foo.start' )
1004+ self .assertEqual (site ._pending_entrypoints , {fullname : []})
10011005
10021006 def test_read_start_file_comments_only (self ):
1007+ # As with an empty file, a comments-only .start file is registered
1008+ # as present so it can suppress matching .pth `import` lines.
10031009 self ._make_start ("# just a comment\n # another\n " , name = 'foo' )
10041010 site ._read_start_file (self .sitedir , 'foo.start' )
1005- self .assertEqual (site ._pending_entrypoints , {})
1011+ fullname = os .path .join (self .sitedir , 'foo.start' )
1012+ self .assertEqual (site ._pending_entrypoints , {fullname : []})
10061013
10071014 def test_read_start_file_nonexistent (self ):
10081015 with captured_stderr ():
@@ -1026,6 +1033,14 @@ def test_read_start_file_duplicates_not_deduplicated(self):
10261033 self .assertEqual (site ._pending_entrypoints [fullname ],
10271034 ['os.path:join' , 'os.path:join' ])
10281035
1036+ def test_two_start_files_with_duplicates_not_deduplicated (self ):
1037+ self ._make_start ("os.path:join" , name = "foo" )
1038+ self ._make_start ("os.path:join" , name = "bar" )
1039+ site ._read_start_file (self .sitedir , 'foo.start' )
1040+ site ._read_start_file (self .sitedir , 'bar.start' )
1041+ self .assertEqual (self ._just_entrypoints (),
1042+ ['os.path:join' , 'os.path:join' ])
1043+
10291044 # --- _read_pth_file tests ---
10301045
10311046 def test_read_pth_file_paths (self ):
@@ -1060,7 +1075,7 @@ def test_read_pth_file_deduplication(self):
10601075 all_dirs = []
10611076 for dirs in site ._pending_syspaths .values ():
10621077 all_dirs .extend (dirs )
1063- self .assertEqual (all_dirs . count ( subdir ), 1 )
1078+ self .assertEqual (all_dirs , [ subdir ] )
10641079
10651080 def test_read_pth_file_bad_line_continues (self ):
10661081 # PEP 829: errors on individual lines don't abort the file.
@@ -1164,6 +1179,27 @@ def test_exec_imports_not_suppressed_by_different_start(self):
11641179 # Should execute the import line without error.
11651180 site ._exec_imports ()
11661181
1182+ def test_exec_imports_suppressed_by_empty_matching_start (self ):
1183+ self ._make_start ("" , name = 'foo' )
1184+ self ._make_pth ("import epmod; epmod.startup()" , name = 'foo' )
1185+ mod_dir = os .path .join (self .sitedir , 'epmod' )
1186+ os .mkdir (mod_dir )
1187+ init_file = os .path .join (mod_dir , '__init__.py' )
1188+ with open (init_file , 'w' ) as f :
1189+ f .write ("""\
1190+ called = False
1191+ def startup():
1192+ global called
1193+ called = True
1194+ """ )
1195+ sys .path .insert (0 , self .sitedir )
1196+ self .addCleanup (sys .modules .pop , 'epmod' , None )
1197+ site ._read_pth_file (self .sitedir , 'foo.pth' , set ())
1198+ site ._read_start_file (self .sitedir , 'foo.start' )
1199+ site ._exec_imports ()
1200+ import epmod
1201+ self .assertFalse (epmod .called )
1202+
11671203 # --- _extend_syspath tests ---
11681204
11691205 def test_extend_syspath_existing_dir (self ):
0 commit comments