11import collections .abc
22import contextlib
33import errno
4+ import logging
45import os
56import re
67import stat
1011import unittest
1112import warnings
1213
13- # From CPython 3.13.5
1414from test import support
1515
1616
2323
2424# TESTFN_UNICODE is a non-ascii filename
2525TESTFN_UNICODE = TESTFN_ASCII + "-\xe0 \xf2 \u0258 \u0141 \u011f "
26- if sys . platform == 'darwin' :
27- #In Mac OS X 's VFS API file names are, by definition, canonically
26+ if support . is_apple :
27+ #On Apple 's VFS API file names are, by definition, canonically
2828# decomposed Unicode, encoded using UTF-8. See QA1173:
2929# http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
3030import unicodedata
4949'encoding (%s). Unicode filename tests may not be effective'
5050% (TESTFN_UNENCODABLE ,sys .getfilesystemencoding ()))
5151TESTFN_UNENCODABLE = None
52- #macOS and Emscripten deny unencodable filenames (invalid utf-8)
53- elif sys .platform not in {'darwin' , ' emscripten' , ' wasi' }:
52+ #Apple and Emscripten deny unencodable filenames (invalid utf-8)
53+ elif not support . is_apple and sys .platform not in {" emscripten" , " wasi" }:
5454try :
5555# ascii and utf-8 cannot encode the byte 0xff
5656b'\xff ' .decode (sys .getfilesystemencoding ())
@@ -199,10 +199,8 @@ def skip_unless_symlink(test):
199199return test if ok else unittest .skip (msg )(test )
200200
201201
202- # From CPython 3.13.5
203202_can_hardlink = None
204203
205- # From CPython 3.13.5
206204def can_hardlink ():
207205global _can_hardlink
208206if _can_hardlink is None :
@@ -212,7 +210,6 @@ def can_hardlink():
212210return _can_hardlink
213211
214212
215- # From CPython 3.13.5
216213def skip_unless_hardlink (test ):
217214ok = can_hardlink ()
218215msg = "requires hardlink support"
@@ -268,15 +265,15 @@ def can_chmod():
268265global _can_chmod
269266if _can_chmod is not None :
270267return _can_chmod
271- if not hasattr (os ,"chown " ):
268+ if not hasattr (os ,"chmod " ):
272269_can_chmod = False
273270return _can_chmod
274271try :
275272with open (TESTFN ,"wb" )as f :
276273try :
277- os .chmod (TESTFN ,0o777 )
274+ os .chmod (TESTFN ,0o555 )
278275mode1 = os .stat (TESTFN ).st_mode
279- os .chmod (TESTFN ,0o666 )
276+ os .chmod (TESTFN ,0o777 )
280277mode2 = os .stat (TESTFN ).st_mode
281278except OSError as e :
282279can = False
@@ -323,6 +320,10 @@ def can_dac_override():
323320else :
324321_can_dac_override = True
325322finally :
323+ try :
324+ os .chmod (TESTFN ,0o700 )
325+ except OSError :
326+ pass
326327unlink (TESTFN )
327328
328329return _can_dac_override
@@ -378,8 +379,12 @@ def _waitfor(func, pathname, waitall=False):
378379# Increase the timeout and try again
379380time .sleep (timeout )
380381timeout *= 2
381- warnings .warn ('tests may fail, delete still pending for ' + pathname ,
382- RuntimeWarning ,stacklevel = 4 )
382+ logging .getLogger (__name__ ).warning (
383+ 'tests may fail, delete still pending for %s' ,
384+ pathname ,
385+ stack_info = True ,
386+ stacklevel = 4 ,
387+ )
383388
384389def _unlink (filename ):
385390_waitfor (os .unlink ,filename )
@@ -494,9 +499,14 @@ def temp_dir(path=None, quiet=False):
494499except OSError as exc :
495500if not quiet :
496501raise
497- warnings .warn (f'tests may fail, unable to create '
498- f'temporary directory{ path !r} :{ exc } ' ,
499- RuntimeWarning ,stacklevel = 3 )
502+ logging .getLogger (__name__ ).warning (
503+ "tests may fail, unable to create temporary directory %r: %s" ,
504+ path ,
505+ exc ,
506+ exc_info = exc ,
507+ stack_info = True ,
508+ stacklevel = 3 ,
509+ )
500510if dir_created :
501511pid = os .getpid ()
502512try :
@@ -527,9 +537,15 @@ def change_cwd(path, quiet=False):
527537except OSError as exc :
528538if not quiet :
529539raise
530- warnings .warn (f'tests may fail, unable to change the current working '
531- f'directory to{ path !r} :{ exc } ' ,
532- RuntimeWarning ,stacklevel = 3 )
540+ logging .getLogger (__name__ ).warning (
541+ 'tests may fail, unable to change the current working directory '
542+ 'to %r: %s' ,
543+ path ,
544+ exc ,
545+ exc_info = exc ,
546+ stack_info = True ,
547+ stacklevel = 3 ,
548+ )
533549try :
534550yield os .getcwd ()
535551finally :
@@ -612,11 +628,18 @@ def __fspath__(self):
612628def fd_count ():
613629"""Count the number of open file descriptors.
614630 """
615- if sys .platform .startswith (('linux' ,'freebsd' ,'emscripten' )):
631+ if sys .platform .startswith (('linux' ,'android' ,'freebsd' ,'emscripten' )):
632+ fd_path = "/proc/self/fd"
633+ elif support .is_apple :
634+ fd_path = "/dev/fd"
635+ else :
636+ fd_path = None
637+
638+ if fd_path is not None :
616639try :
617- names = os .listdir ("/proc/self/fd" )
640+ names = os .listdir (fd_path )
618641# Subtract one because listdir() internally opens a file
619- # descriptor to list the content of the/proc/self/fd/ directory.
642+ # descriptor to list the content of the directory.
620643return len (names )- 1
621644except FileNotFoundError :
622645pass
@@ -686,9 +709,10 @@ def temp_umask(umask):
686709
687710
688711class EnvironmentVarGuard (collections .abc .MutableMapping ):
712+ """Class to help protect the environment variable properly.
689713
690- """Class to help protect the environment variable properly. Can be used as
691- a context manager. """
714+ Can be used as a context manager.
715+ """
692716
693717def __init__ (self ):
694718self ._environ = os .environ
@@ -722,7 +746,6 @@ def __len__(self):
722746def set (self ,envvar ,value ):
723747self [envvar ]= value
724748
725- # From CPython 3.13.5
726749def unset (self ,envvar ,/ ,* envvars ):
727750"""Unset one or more environment variables."""
728751for ev in (envvar ,* envvars ):
@@ -746,13 +769,16 @@ def __exit__(self, *ignore_exc):
746769
747770
748771try :
749- import ctypes
750- kernel32 = ctypes .WinDLL ('kernel32' ,use_last_error = True )
751-
752- ERROR_FILE_NOT_FOUND = 2
753- DDD_REMOVE_DEFINITION = 2
754- DDD_EXACT_MATCH_ON_REMOVE = 4
755- DDD_NO_BROADCAST_SYSTEM = 8
772+ if support .MS_WINDOWS :
773+ import ctypes
774+ kernel32 = ctypes .WinDLL ('kernel32' ,use_last_error = True )
775+
776+ ERROR_FILE_NOT_FOUND = 2
777+ DDD_REMOVE_DEFINITION = 2
778+ DDD_EXACT_MATCH_ON_REMOVE = 4
779+ DDD_NO_BROADCAST_SYSTEM = 8
780+ else :
781+ raise AttributeError
756782except (ImportError ,AttributeError ):
757783def subst_drive (path ):
758784raise unittest .SkipTest ('ctypes or kernel32 is not available' )