@@ -1579,50 +1579,71 @@ def get_exe_prefixes(exe_filename):
15791579class PthDistributions (Environment ):
15801580 """A .pth file with Distribution paths in it"""
15811581
1582- dirty = False
1583-
15841582 def __init__ (self , filename , sitedirs = ()):
15851583 self .filename = filename
15861584 self .sitedirs = list (map (normalize_path , sitedirs ))
15871585 self .basedir = normalize_path (os .path .dirname (self .filename ))
1588- self ._load ()
1586+ self .paths , self . dirty = self . _load ()
15891587 super ().__init__ ([], None , None )
15901588 for path in yield_lines (self .paths ):
15911589 list (map (self .add , find_distributions (path , True )))
15921590
1593- def _load (self ):
1594- self . paths = []
1595- saw_import = False
1591+ def _load_raw (self ):
1592+ paths = []
1593+ dirty = saw_import = False
15961594 seen = dict .fromkeys (self .sitedirs )
1597- if os . path . isfile (self .filename ):
1598- f = open ( self . filename , 'rt' )
1599- for line in f :
1600- if line . startswith ( 'import' ):
1601- saw_import = True
1602- continue
1603- path = line . rstrip ()
1604- self . paths . append ( path )
1605- if not path . strip () or path . strip () .startswith ('#' ):
1606- continue
1607- # skip non-existent paths, in case somebody deleted a package
1608- # manually, and duplicate paths as well
1609- path = self .paths [ - 1 ] = normalize_path (
1610- os .path .join ( self . basedir , path )
1611- )
1612- if not os . path . exists ( path ) or path in seen :
1613- self . paths .pop () # skip it
1614- self . dirty = True # we cleaned up, so we're dirty now :)
1615- continue
1616- seen [ path ] = 1
1617- f . close ( )
1595+ f = open (self .filename , 'rt' )
1596+ for line in f :
1597+ path = line . rstrip ()
1598+ stripped_path = path . strip ()
1599+ paths . append ( path ) # still keep imports and empty/commented lines for formatting
1600+ if line . startswith (( 'import ' , 'from ' )):
1601+ saw_import = True
1602+ continue
1603+ if not stripped_path or stripped_path .startswith ('#' ):
1604+ continue
1605+ # skip non-existent paths, in case somebody deleted a package
1606+ # manually, and duplicate paths as well
1607+ normalized_path = normalize_path ( os . path . join ( self .basedir , path ))
1608+ if not os .path .exists ( path ) or normalized_path in seen :
1609+ log . debug ( "cleaned up dirty or duplicated %r" , path )
1610+ dirty = True
1611+ paths .pop ()
1612+ continue
1613+ seen [ normalized_path ] = 1
1614+ f . close ()
1615+ return paths , dirty or ( paths and saw_import )
16181616
1619- if self .paths and not saw_import :
1620- self .dirty = True # ensure anything we touch has import wrappers
1621- while self .paths and not self .paths [- 1 ].strip ():
1622- self .paths .pop ()
1617+ def _load (self ):
1618+ if os .path .isfile (self .filename ):
1619+ paths , dirty = self ._load_raw ()
1620+ # lights cleaning:
1621+ while paths and not paths [- 1 ].strip ():
1622+ paths .pop ()
1623+ else :
1624+ paths = []
1625+ dirty = False
1626+ return paths , dirty
16231627
16241628 def save (self ):
16251629 """Write changed .pth file back to disk"""
1630+ last_paths , last_dirty = self ._load ()
1631+ for path in last_paths [:]:
1632+ if path not in self .paths :
1633+ self .paths .append (path )
1634+ log .info ("detected new path %r" , path )
1635+ last_dirty = True
1636+ else :
1637+ last_paths .remove (path )
1638+ for path in self .paths [:]:
1639+ if path not in last_paths \
1640+ and not path .startswith (('import ' , 'from ' )) \
1641+ and not os .path .exists (path ):
1642+ self .paths .remove (path )
1643+ log .info ("removing now non-existent path %r" , path )
1644+ last_dirty = True
1645+ self .dirty |= last_dirty
1646+
16261647 if not self .dirty :
16271648 return
16281649
0 commit comments