30
30
"ismount" , "expanduser" ,"expandvars" ,"normpath" ,"abspath" ,
31
31
"curdir" ,"pardir" ,"sep" ,"pathsep" ,"defpath" ,"altsep" ,
32
32
"extsep" ,"devnull" ,"realpath" ,"supports_unicode_filenames" ,"relpath" ,
33
- "samefile" , "sameopenfile" , "samestat" , "commonpath" ]
33
+ "samefile" , "sameopenfile" , "samestat" , "commonpath" ,
34
+ "ALLOW_MISSING" ]
34
35
35
36
def _get_bothseps (path ):
36
37
if isinstance (path , bytes ):
@@ -578,9 +579,10 @@ def abspath(path):
578
579
from nt import _getfinalpathname , readlink as _nt_readlink
579
580
except ImportError :
580
581
# realpath is a no-op on systems without _getfinalpathname support.
581
- realpath = abspath
582
+ def realpath (path , * , strict = False ):
583
+ return abspath (path )
582
584
else :
583
- def _readlink_deep (path ):
585
+ def _readlink_deep (path , ignored_error = OSError ):
584
586
# These error codes indicate that we should stop reading links and
585
587
# return the path we currently have.
586
588
# 1: ERROR_INVALID_FUNCTION
@@ -613,7 +615,7 @@ def _readlink_deep(path):
613
615
path = old_path
614
616
break
615
617
path = normpath (join (dirname (old_path ), path ))
616
- except OSError as ex :
618
+ except ignored_error as ex :
617
619
if ex .winerror in allowed_winerror :
618
620
break
619
621
raise
@@ -622,7 +624,7 @@ def _readlink_deep(path):
622
624
break
623
625
return path
624
626
625
- def _getfinalpathname_nonstrict (path ):
627
+ def _getfinalpathname_nonstrict (path , ignored_error = OSError ):
626
628
# These error codes indicate that we should stop resolving the path
627
629
# and return the value we currently have.
628
630
# 1: ERROR_INVALID_FUNCTION
@@ -649,17 +651,18 @@ def _getfinalpathname_nonstrict(path):
649
651
try :
650
652
path = _getfinalpathname (path )
651
653
return join (path , tail ) if tail else path
652
- except OSError as ex :
654
+ except ignored_error as ex :
653
655
if ex .winerror not in allowed_winerror :
654
656
raise
655
657
try :
656
658
# The OS could not resolve this path fully, so we attempt
657
659
# to follow the link ourselves. If we succeed, join the tail
658
660
# and return.
659
- new_path = _readlink_deep (path )
661
+ new_path = _readlink_deep (path ,
662
+ ignored_error = ignored_error )
660
663
if new_path != path :
661
664
return join (new_path , tail ) if tail else new_path
662
- except OSError :
665
+ except ignored_error :
663
666
# If we fail to readlink(), let's keep traversing
664
667
pass
665
668
path , name = split (path )
@@ -690,24 +693,32 @@ def realpath(path, *, strict=False):
690
693
if normcase (path ) == normcase (devnull ):
691
694
return '\\ \\ .\\ NUL'
692
695
had_prefix = path .startswith (prefix )
696
+
697
+ if strict is ALLOW_MISSING :
698
+ ignored_error = FileNotFoundError
699
+ strict = True
700
+ elif strict :
701
+ ignored_error = ()
702
+ else :
703
+ ignored_error = OSError
704
+
693
705
if not had_prefix and not isabs (path ):
694
706
path = join (cwd , path )
695
707
try :
696
708
path = _getfinalpathname (path )
697
709
initial_winerror = 0
698
710
except ValueError as ex :
699
711
# gh-106242: Raised for embedded null characters
700
- # In strict mode , we convert into an OSError.
712
+ # In strict modes , we convert into an OSError.
701
713
# Non-strict mode returns the path as-is, since we've already
702
714
# made it absolute.
703
715
if strict :
704
716
raise OSError (str (ex )) from None
705
717
path = normpath (path )
706
- except OSError as ex :
707
- if strict :
708
- raise
718
+ except ignored_error as ex :
709
719
initial_winerror = ex .winerror
710
- path = _getfinalpathname_nonstrict (path )
720
+ path = _getfinalpathname_nonstrict (path ,
721
+ ignored_error = ignored_error )
711
722
# The path returned by _getfinalpathname will always start with \\?\ -
712
723
# strip off that prefix unless it was already provided on the original
713
724
# path.
0 commit comments