@@ -259,6 +259,10 @@ def __init__(self, known_paths=None):
259259 *known_paths* is a set of case-normalized paths already present
260260 on sys.path, used to avoid duplicate path entries. When None
261261 (the default), it is initialized from the current sys.path.
262+
263+ A caller-supplied set is stored by reference and mutated in place
264+ as new paths are recorded; pass a fresh set per StartupState if
265+ isolation across instances is required.
262266 """
263267 self ._known_paths = (
264268 _init_pathinfo ()
@@ -280,7 +284,7 @@ def __init__(self, known_paths=None):
280284 self ._importexecs = {}
281285 self ._entrypoints = {}
282286
283- def add_sitedir (self , sitedir , * , process_known_sitedirs = True ):
287+ def _add_sitedir (self , sitedir , * , process_known_sitedirs = True ):
284288 sitedir , sitedircase = makepath (sitedir )
285289 # Have we already processed this sitedir?
286290 if sitedircase in self ._processed_sitedirs :
@@ -391,13 +395,20 @@ def process(self):
391395 self ._execute_start_entrypoints ()
392396
393397 def _extend_syspath (self ):
394- # Duplicates have already been filtered (in existing sys.path or
395- # across .pth files via known_paths), and entries are already
396- # abspath/normpath'd, so all that remains is to confirm that .pth
397- # file path entries exist before appending them. filename will be
398- # None for sitedir entries in the ledger, and these have already been
399- # checked for existence, so no need to do so again.
398+ # Duplicate path-extension specifications have already been filtered
399+ # out upstream across .pth files within this batch (via known_paths),
400+ # and ledger entries are already abspath/normpath'd. .pth-derived
401+ # entries (filename is not None) are existence-checked and skipped
402+ # with an error if missing. Sitedir entries (filename is None) are
403+ # appended unconditionally: legacy addsitedir() added the sitedir to
404+ # sys.path before attempting to list it, so an unreadable or
405+ # non-existent sitedir still landed on sys.path. Deferring the
406+ # append to here preserves that contract.
400407 for filename , dir_ in self ._path_entries :
408+ # As a backstop, known_paths may not have been seeded from sys.path
409+ # (callers can pass an empty set), and multiple StartupState
410+ # instances against the same sys.path don't share state, so always
411+ # do a final anti-duplication check.
401412 if dir_ in sys .path :
402413 continue
403414 if filename is None or os .path .exists (dir_ ):
@@ -485,8 +496,6 @@ def addpackage(sitedir, name, known_paths):
485496 else :
486497 reset = False
487498
488- # Although never documented, the semantics of addpackage() is to fully
489- # process a single sitedir.
490499 state = StartupState (known_paths )
491500 state .read_pth_file (sitedir , name )
492501 state .process ()
@@ -534,23 +543,26 @@ def addsitedir(sitedir, known_paths=None, *, startup_state=None):
534543 flush_now = True
535544 process_known_sitedirs = False
536545
537- sitedir = startup_state .add_sitedir (
546+ # Reach into StartupState's non-public API deliberately: sitedir
547+ # bookkeeping is a detail of how addsitedir() drives a batch, not
548+ # something callers should manage themselves. Keeping _add_sitedir()
549+ # private avoids committing it to the public StartupState API.
550+ sitedir = startup_state ._add_sitedir (
538551 sitedir ,
539552 process_known_sitedirs = process_known_sitedirs ,
540553 )
541554 if sitedir is None :
542- if not flush_now :
543- return startup_state
544- return None if reset else known_paths
555+ if flush_now :
556+ return None if reset else known_paths
557+ return startup_state
545558
546559 try :
547560 names = os .listdir (sitedir )
548561 except OSError :
549562 if flush_now :
550563 startup_state .process ()
551- if not flush_now :
552- return startup_state
553- return None if reset else known_paths
564+ return None if reset else known_paths
565+ return startup_state
554566
555567 # The following phases are defined by PEP 829.
556568 # Phases 1-3: Read .pth files, accumulating paths and import lines.
@@ -573,11 +585,8 @@ def addsitedir(sitedir, known_paths=None, *, startup_state=None):
573585
574586 if flush_now :
575587 startup_state .process ()
576-
577- if not flush_now :
578- return startup_state
579-
580- return None if reset else known_paths
588+ return None if reset else known_paths
589+ return startup_state
581590
582591
583592def check_enableusersite ():
0 commit comments