@@ -118,7 +118,6 @@ def pth_file_tests(self, pth_file):
118118 "%s not in sys.modules" % pth_file .imported )
119119 self .assertIn (site .makepath (pth_file .good_dir_path )[0 ], sys .path )
120120 self .assertFalse (os .path .exists (pth_file .bad_dir_path ))
121- self .assertFalse (os .path .exists (pth_file .idempotent_fail_path ))
122121
123122 def test_addpackage (self ):
124123 # Make sure addpackage() imports if the line starts with 'import',
@@ -197,22 +196,13 @@ def test_addsitedir_explicit_flush(self):
197196 pth_file .cleanup (prep = True )
198197 with pth_file .create ():
199198 # Pass defer_processing_start_files=True to prevent flushing.
200- site .addsitedir (pth_file .base_dir , set (),
201- defer_processing_start_files = True )
199+ site .addsitedir (
200+ pth_file .base_dir , set (),
201+ defer_processing_start_files = True )
202202 self .assertNotIn (pth_file .imported , sys .modules )
203203 site .process_startup_files ()
204204 self .pth_file_tests (pth_file )
205205
206- def test_addsitedir_idempotent (self ):
207- pth_file = PthFile ()
208- pth_file .cleanup (prep = True )
209-
210- with pth_file .create ():
211- dirs = set ()
212- dirs = site .addsitedir (pth_file .base_dir , dirs )
213- dirs = site .addsitedir (pth_file .base_dir , dirs )
214- self .pth_file_tests (pth_file )
215-
216206 def test_addsitedir_dotfile (self ):
217207 pth_file = PthFile ('.dotfile' )
218208 # Ensure we have a clean slate.
@@ -422,7 +412,6 @@ def __init__(self, filename_base=TESTFN, imported="time",
422412 self .bad_dirname = bad_dirname
423413 self .good_dir_path = os .path .join (self .base_dir , self .good_dirname )
424414 self .bad_dir_path = os .path .join (self .base_dir , self .bad_dirname )
425- self .idempotent_fail_path = os .path .join (self .base_dir , 'idempotent' )
426415
427416 @contextlib .contextmanager
428417 def create (self ):
@@ -435,22 +424,14 @@ def create(self):
435424
436425 Used as a context manager: self.cleanup() is called on exit.
437426 """
438- FILE = open (self .file_path , 'w' )
439- try :
440- print ("#import @bad module name" , file = FILE )
441- print ("\n " , file = FILE )
442-
443- PROG = f'''\
444- if { self .imported !r} in sys.modules:
445- open({ self .idempotent_fail_path !r} , 'a+').close()
446- '''
447- print (f"import sys; exec({ PROG !r} )" , file = FILE )
448-
449- print ("import %s" % self .imported , file = FILE )
450- print (self .good_dirname , file = FILE )
451- print (self .bad_dirname , file = FILE )
452- finally :
453- FILE .close ()
427+ with open (self .file_path , 'w' ) as fp :
428+ print (f"""\
429+ #import @bad module name
430+ import { self .imported }
431+ { self .good_dirname }
432+ { self .bad_dirname }
433+ """ , file = fp )
434+
454435 os .mkdir (self .good_dir_path )
455436 try :
456437 yield self
@@ -474,8 +455,6 @@ def cleanup(self, prep=False):
474455 os .rmdir (self .good_dir_path )
475456 if os .path .exists (self .bad_dir_path ):
476457 os .rmdir (self .bad_dir_path )
477- if os .path .exists (self .idempotent_fail_path ):
478- os .remove (self .idempotent_fail_path )
479458
480459class ImportSideEffectTests (unittest .TestCase ):
481460 """Test side-effects from importing 'site'."""
@@ -965,6 +944,16 @@ def _make_pth(self, content, name='testpkg'):
965944 f .write (content )
966945 return basename
967946
947+ def _make_mod (self , contents , name = 'mod' ):
948+ """Write an importable <mod>.py, returning the module directory."""
949+ extdir = os .path .join (self .sitedir , 'extdir' )
950+ os .mkdir (extdir )
951+ modpath = os .path .join (extdir , f'{ name } .py' )
952+ with open (modpath , 'w' ) as fp :
953+ fp .write (contents )
954+ self .addCleanup (sys .modules .pop , name , None )
955+ return extdir
956+
968957 def _all_entrypoints (self ):
969958 """Flatten _pending_entrypoints dict into a list of (filename, entry) tuples."""
970959 result = []
@@ -1441,18 +1430,12 @@ def test_pth_path_is_available_to_start_entrypoint(self):
14411430 # point may live in a module reachable only via a .pth-extended
14421431 # path. If the flush phases were inverted, resolving the entry
14431432 # point would fail with ModuleNotFoundError.
1444- extdir = os .path .join (self .sitedir , 'extdir' )
1445- os .mkdir (extdir )
1446- modpath = os .path .join (extdir , 'mod.py' )
1447- with open (modpath , 'w' ) as f :
1448- f .write ("""\
1433+ extdir = self ._make_mod ("""\
14491434 called = False
14501435def hook():
14511436 global called
14521437 called = True
14531438""" )
1454- self .addCleanup (sys .modules .pop , 'mod' , None )
1455-
14561439 # extdir is not on sys.path; only the .pth file makes it so.
14571440 self .assertNotIn (extdir , sys .path )
14581441 self ._make_pth ("extdir\n " , name = 'extlib' )
@@ -1468,6 +1451,45 @@ def hook():
14681451 "entry point did not run; .pth path was likely not applied "
14691452 "before .start entry-point execution" )
14701453
1454+ # --- bugs ---
1455+
1456+ # gh-75723
1457+ def test_addsitdir_idempotent_pth (self ):
1458+ # Adding the same sitedir twice with a known_paths, should not
1459+ # process .pth files twice.
1460+ extdir = self ._make_mod ("""\
1461+ _pth_count = 0
1462+ """ )
1463+ self ._make_pth (f"""\
1464+ { extdir }
1465+ import mod; mod._pth_count += 1
1466+ """ )
1467+ dirs = set ()
1468+ dirs = site .addsitedir (self .sitedir , dirs )
1469+ dirs = site .addsitedir (self .sitedir , dirs )
1470+ import mod
1471+ self .assertEqual (mod ._pth_count , 1 )
1472+
1473+ def test_addsitdir_idempotent_start (self ):
1474+ # Adding the same sitedir twice with a known_paths, should not
1475+ # process .pth files twice.
1476+ extdir = self ._make_mod ("""\
1477+ _pth_count = 0
1478+ def increment():
1479+ global _pth_count
1480+ _pth_count += 1
1481+ """ )
1482+ self ._make_pth (f"""\
1483+ { extdir }
1484+ """ )
1485+ self ._make_start ("""\
1486+ mod:increment
1487+ """ )
1488+ dirs = set ()
1489+ dirs = site .addsitedir (self .sitedir , dirs )
1490+ dirs = site .addsitedir (self .sitedir , dirs )
1491+ import mod
1492+ self .assertEqual (mod ._pth_count , 1 )
14711493
14721494if __name__ == "__main__" :
14731495 unittest .main ()
0 commit comments