1010from test .support import os_helper
1111from test .support import socket_helper
1212from test .support import captured_stderr
13- from test .support .os_helper import TESTFN , EnvironmentVarGuard , change_cwd
13+ from test .support .os_helper import TESTFN , EnvironmentVarGuard
1414import ast
1515import builtins
16- import encodings
1716import glob
1817import io
1918import os
2019import re
2120import shutil
21+ import stat
2222import subprocess
2323import sys
2424import sysconfig
@@ -195,6 +195,47 @@ def test_addsitedir(self):
195195 finally :
196196 pth_file .cleanup ()
197197
198+ def test_addsitedir_dotfile (self ):
199+ pth_file = PthFile ('.dotfile' )
200+ pth_file .cleanup (prep = True )
201+ try :
202+ pth_file .create ()
203+ site .addsitedir (pth_file .base_dir , set ())
204+ self .assertNotIn (site .makepath (pth_file .good_dir_path )[0 ], sys .path )
205+ self .assertIn (pth_file .base_dir , sys .path )
206+ finally :
207+ pth_file .cleanup ()
208+
209+ @unittest .skipUnless (hasattr (os , 'chflags' ), 'test needs os.chflags()' )
210+ def test_addsitedir_hidden_flags (self ):
211+ pth_file = PthFile ()
212+ pth_file .cleanup (prep = True )
213+ try :
214+ pth_file .create ()
215+ st = os .stat (pth_file .file_path )
216+ os .chflags (pth_file .file_path , st .st_flags | stat .UF_HIDDEN )
217+ site .addsitedir (pth_file .base_dir , set ())
218+ self .assertNotIn (site .makepath (pth_file .good_dir_path )[0 ], sys .path )
219+ self .assertIn (pth_file .base_dir , sys .path )
220+ finally :
221+ pth_file .cleanup ()
222+
223+ # TODO: RUSTPYTHON
224+ @unittest .expectedFailure
225+ @unittest .skipUnless (sys .platform == 'win32' , 'test needs Windows' )
226+ @support .requires_subprocess ()
227+ def test_addsitedir_hidden_file_attribute (self ):
228+ pth_file = PthFile ()
229+ pth_file .cleanup (prep = True )
230+ try :
231+ pth_file .create ()
232+ subprocess .check_call (['attrib' , '+H' , pth_file .file_path ])
233+ site .addsitedir (pth_file .base_dir , set ())
234+ self .assertNotIn (site .makepath (pth_file .good_dir_path )[0 ], sys .path )
235+ self .assertIn (pth_file .base_dir , sys .path )
236+ finally :
237+ pth_file .cleanup ()
238+
198239 # This tests _getuserbase, hence the double underline
199240 # to distinguish from a test for getuserbase
200241 def test__getuserbase (self ):
@@ -468,10 +509,10 @@ def test_sitecustomize_executed(self):
468509 else :
469510 self .fail ("sitecustomize not imported automatically" )
470511
471- @test .support .requires_resource ('network' )
472- @test .support .system_must_validate_cert
473512 @unittest .skipUnless (hasattr (urllib .request , "HTTPSHandler" ),
474513 'need SSL support to download license' )
514+ @test .support .requires_resource ('network' )
515+ @test .support .system_must_validate_cert
475516 def test_license_exists_at_url (self ):
476517 # This test is a bit fragile since it depends on the format of the
477518 # string displayed by license in the absence of a LICENSE file.
@@ -581,7 +622,7 @@ def _create_underpth_exe(self, lines, exe_pth=True):
581622 _pth_file = os .path .splitext (exe_file )[0 ] + '._pth'
582623 else :
583624 _pth_file = os .path .splitext (dll_file )[0 ] + '._pth'
584- with open (_pth_file , 'w' ) as f :
625+ with open (_pth_file , 'w' , encoding = 'utf8' ) as f :
585626 for line in lines :
586627 print (line , file = f )
587628 return exe_file
@@ -608,19 +649,33 @@ def _calc_sys_path_for_underpth_nosite(self, sys_prefix, lines):
608649 sys_path .append (abs_path )
609650 return sys_path
610651
652+ def _get_pth_lines (self , libpath : str , * , import_site : bool ):
653+ pth_lines = ['fake-path-name' ]
654+ # include 200 lines of `libpath` in _pth lines (or fewer
655+ # if the `libpath` is long enough to get close to 32KB
656+ # see https://github.com/python/cpython/issues/113628)
657+ encoded_libpath_length = len (libpath .encode ("utf-8" ))
474E
tr>658+ repetitions = min (200 , 30000 // encoded_libpath_length )
659+ if repetitions <= 2 :
660+ self .skipTest (
661+ f"Python stdlib path is too long ({ encoded_libpath_length :,} bytes)" )
662+ pth_lines .extend (libpath for _ in range (repetitions ))
663+ pth_lines .extend (['' , '# comment' ])
664+ if import_site :
665+ pth_lines .append ('import site' )
666+ return pth_lines
667+
611668 # TODO: RUSTPYTHON
612669 @unittest .expectedFailure
613670 @support .requires_subprocess ()
614671 def test_underpth_basic (self ):
615- libpath = test .support .STDLIB_DIR
616- exe_prefix = os .path .dirname (sys .executable )
617672 pth_lines = ['#.' , '# ..' , * sys .path , '.' , '..' ]
618673 exe_file = self ._create_underpth_exe (pth_lines )
619674 sys_path = self ._calc_sys_path_for_underpth_nosite (
620675 os .path .dirname (exe_file ),
621676 pth_lines )
622677
623- output = subprocess .check_output ([exe_file , '-c' ,
678+ output = subprocess .check_output ([exe_file , '-X' , 'utf8' , '- c' ,
624679 'import sys; print("\\ n".join(sys.path) if sys.flags.no_site else "")'
625680 ], encoding = 'utf-8' , errors = 'surrogateescape' )
626681 actual_sys_path = output .rstrip ().split ('\n ' )
@@ -637,12 +692,7 @@ def test_underpth_basic(self):
637692 def test_underpth_nosite_file (self ):
638693 libpath = test .support .STDLIB_DIR
639694 exe_prefix = os .path .dirname (sys .executable )
640- pth_lines = [
641- 'fake-path-name' ,
642- * [libpath for _ in range (200 )],
643- '' ,
644- '# comment' ,
645- ]
695+ pth_lines = self ._get_pth_lines (libpath , import_site = False )
646696 exe_file = self ._create_underpth_exe (pth_lines )
647697 sys_path = self ._calc_sys_path_for_underpth_nosite (
648698 os .path .dirname (exe_file ),
@@ -668,13 +718,8 @@ def test_underpth_nosite_file(self):
668718 def test_underpth_file (self ):
669719 libpath = test .support .STDLIB_DIR
670720 exe_prefix = os .path .dirname (sys .executable )
671- exe_file = self ._create_underpth_exe ([
672- 'fake-path-name' ,
673- * [libpath for _ in range (200 )],
674- '' ,
675- '# comment' ,
676- 'import site'
677- ])
721+ exe_file = self ._create_underpth_exe (
722+ self ._get_pth_lines (libpath , import_site = True ))
678723 sys_prefix = os .path .dirname (exe_file )
679724 env = os .environ .copy ()
680725 env ['PYTHONPATH' ] = 'from-env'
@@ -695,13 +740,8 @@ def test_underpth_file(self):
695740 def test_underpth_dll_file (self ):
696741 libpath = test .support .STDLIB_DIR
697742 exe_prefix = os .path .dirname (sys .executable )
698- exe_file = self ._create_underpth_exe ([
699- 'fake-path-name' ,
700- * [libpath for _ in range (200 )],
701- '' ,
702- '# comment' ,
703- 'import site'
704- ], exe_pth = False )
743+ exe_file = self ._create_underpth_exe (
744+ self ._get_pth_lines (libpath , import_site = True ), exe_pth = False )
705745 sys_prefix = os .path .dirname (exe_file )
706746 env = os .environ .copy ()
707747 env ['PYTHONPATH' ] = 'from-env'
0 commit comments