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" , "isjunction" ]
33
+ "samefile" , "sameopenfile" , "samestat" , "commonpath" , "isjunction" ,
34
+ "ALLOW_MISSING" ]
34
35
35
36
def _get_bothseps (path ):
36
37
if isinstance (path , bytes ):
@@ -609,9 +610,10 @@ def abspath(path):
609
610
from nt import _getfinalpathname , readlink as _nt_readlink
610
611
except ImportError :
611
612
# realpath is a no-op on systems without _getfinalpathname support.
612
- realpath = abspath
613
+ def realpath (path , * , strict = False ):
614
+ return abspath (path )
613
615
else :
614
- def _readlink_deep (path ):
616
+ def _readlink_deep (path , ignored_error = OSError ):
615
617
# These error codes indicate that we should stop reading links and
616
618
# return the path we currently have.
617
619
# 1: ERROR_INVALID_FUNCTION
@@ -644,7 +646,7 @@ def _readlink_deep(path):
644
646
path = old_path
645
647
break
646
648
path = normpath (join (dirname (old_path ), path ))
647
- except OSError as ex :
649
+ except ignored_error as ex :
648
650
if ex .winerror in allowed_winerror :
649
651
break
650
652
raise
@@ -653,7 +655,7 @@ def _readlink_deep(path):
653
655
break
654
656
return path
655
657
656
- def _getfinalpathname_nonstrict (path ):
658
+ def _getfinalpathname_nonstrict (path , ignored_error = OSError ):
657
659
# These error codes indicate that we should stop resolving the path
658
660
# and return the value we currently have.
659
661
# 1: ERROR_INVALID_FUNCTION
@@ -680,17 +682,18 @@ def _getfinalpathname_nonstrict(path):
680
682
try :
681
683
path = _getfinalpathname (path )
682
684
return join (path , tail ) if tail else path
683
- except OSError as ex :
685
+ except ignored_error as ex :
684
686
if ex .winerror not in allowed_winerror :
685
687
raise
686
688
try :
687
689
# The OS could not resolve this path fully, so we attempt
688
690
# to follow the link ourselves. If we succeed, join the tail
689
691
# and return.
690
- new_path = _readlink_deep (path )
692
+ new_path = _readlink_deep (path ,
693
+ ignored_error = ignored_error )
691
694
if new_path != path :
692
695
return join (new_path , tail ) if tail else new_path
693
- except OSError :
696
+ except ignored_error :
694
697
# If we fail to readlink(), let's keep traversing
695
698
pass
696
699
path , name = split (path )
@@ -721,24 +724,32 @@ def realpath(path, *, strict=False):
721
724
if normcase (path ) == normcase (devnull ):
722
725
return '\\ \\ .\\ NUL'
723
726
had_prefix = path .startswith (prefix )
727
+
728
+ if strict is ALLOW_MISSING :
729
+ ignored_error = FileNotFoundError
730
+ strict = True
731
+ elif strict :
732
+ ignored_error = ()
733
+ else :
734
+ ignored_error = OSError
735
+
724
736
if not had_prefix and not isabs (path ):
725
737
path = join (cwd , path )
726
738
try :
727
739
path = _getfinalpathname (path )
728
740
initial_winerror = 0
729
741
except ValueError as ex :
730
742
# gh-106242: Raised for embedded null characters
731
- # In strict mode , we convert into an OSError.
743
+ # In strict modes , we convert into an OSError.
732
744
# Non-strict mode returns the path as-is, since we've already
733
745
# made it absolute.
734
746
if strict :
735
747
raise OSError (str (ex )) from None
736
748
path = normpath (path )
737
- except OSError as ex :
738
- if strict :
739
- raise
749
+ except ignored_error as ex :
740
750
initial_winerror = ex .winerror
741
- path = _getfinalpathname_nonstrict (path )
751
+ path = _getfinalpathname_nonstrict (path ,
752
+ ignored_error = ignored_error )
742
753
# The path returned by _getfinalpathname will always start with \\?\ -
743
754
# strip off that prefix unless it was already provided on the original
744
755
# path.
0 commit comments