3030 "ismount" , "expanduser" ,"expandvars" ,"normpath" ,"abspath" ,
3131 "curdir" ,"pardir" ,"sep" ,"pathsep" ,"defpath" ,"altsep" ,
3232 "extsep" ,"devnull" ,"realpath" ,"supports_unicode_filenames" ,"relpath" ,
33- "samefile" , "sameopenfile" , "samestat" , "commonpath" ]
33+ "samefile" , "sameopenfile" , "samestat" , "commonpath" ,
34+ "ALLOW_MISSING" ]
3435
3536def _get_bothseps (path ):
3637 if isinstance (path , bytes ):
@@ -578,9 +579,10 @@ def abspath(path):
578579 from nt import _getfinalpathname , readlink as _nt_readlink
579580except ImportError :
580581 # realpath is a no-op on systems without _getfinalpathname support.
581- realpath = abspath
582+ def realpath (path , * , strict = False ):
583+ return abspath (path )
582584else :
583- def _readlink_deep (path ):
585+ def _readlink_deep (path , ignored_error = OSError ):
584586 # These error codes indicate that we should stop reading links and
585587 # return the path we currently have.
586588 # 1: ERROR_INVALID_FUNCTION
@@ -613,7 +615,7 @@ def _readlink_deep(path):
613615 path = old_path
614616 break
615617 path = normpath (join (dirname (old_path ), path ))
616- except OSError as ex :
618+ except ignored_error as ex :
617619 if ex .winerror in allowed_winerror :
618620 break
619621 raise
@@ -622,7 +624,7 @@ def _readlink_deep(path):
622624 break
623625 return path
624626
625- def _getfinalpathname_nonstrict (path ):
627+ def _getfinalpathname_nonstrict (path , ignored_error = OSError ):
626628 # These error codes indicate that we should stop resolving the path
627629 # and return the value we currently have.
628630 # 1: ERROR_INVALID_FUNCTION
@@ -649,17 +651,18 @@ def _getfinalpathname_nonstrict(path):
649651 try :
650652 path = _getfinalpathname (path )
651653 return join (path , tail ) if tail else path
652- except OSError as ex :
654+ except ignored_error as ex :
653655 if ex .winerror not in allowed_winerror :
654656 raise
655657 try :
656658 # The OS could not resolve this path fully, so we attempt
657659 # to follow the link ourselves. If we succeed, join the tail
658660 # and return.
659- new_path = _readlink_deep (path )
661+ new_path = _readlink_deep (path ,
662+ ignored_error = ignored_error )
660663 if new_path != path :
661664 return join (new_path , tail ) if tail else new_path
662- except OSError :
665+ except ignored_error :
663666 # If we fail to readlink(), let's keep traversing
664667 pass
665668 path , name = split (path )
@@ -690,24 +693,32 @@ def realpath(path, *, strict=False):
690693 if normcase (path ) == normcase (devnull ):
691694 return '\\ \\ .\\ NUL'
692695 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+
693705 if not had_prefix and not isabs (path ):
694706 path = join (cwd , path )
695707 try :
696708 path = _getfinalpathname (path )
697709 initial_winerror = 0
698710 except ValueError as ex :
699711 # 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.
701713 # Non-strict mode returns the path as-is, since we've already
702714 # made it absolute.
703715 if strict :
704716 raise OSError (str (ex )) from None
705717 path = normpath (path )
706- except OSError as ex :
707- if strict :
708- raise
718+ except ignored_error as ex :
709719 initial_winerror = ex .winerror
710- path = _getfinalpathname_nonstrict (path )
720+ path = _getfinalpathname_nonstrict (path ,
721+ ignored_error = ignored_error )
711722 # The path returned by _getfinalpathname will always start with \\?\ -
712723 # strip off that prefix unless it was already provided on the original
713724 # path.
0 commit comments