diff --git a/ubelt/_win32_links.py b/ubelt/_win32_links.py index 32a15073..1c948ada 100644 --- a/ubelt/_win32_links.py +++ b/ubelt/_win32_links.py @@ -361,6 +361,13 @@ def _win32_is_junction(path): """ Determines if a path is a win32 junction + Note: + on PyPy this is bugged and will currently return True for a symlinked + directory. + + Returns: + bool: + Example: >>> # xdoctest: +REQUIRES(WIN32) >>> from ubelt._win32_links import _win32_junction, _win32_is_junction @@ -396,12 +403,14 @@ def _is_reparse_point(path): """ Check if a directory is a reparse point in windows. + Note: a reparse point seems like it could be a junction or symlink. + .. [SO54678399] https://stackoverflow.com/a/54678399/887074 """ if jwfs is None: raise ImportError('jaraco.windows.filesystem is required to run _is_reparse_point') # if jwfs is not None: - return jwfs.is_reparse_point(path) + return jwfs.is_reparse_point(os.fspath(path)) # else: # # Fallback without jaraco: TODO: test this is 1-to-1 # # Seems to break on pypy? diff --git a/ubelt/util_links.py b/ubelt/util_links.py index 15d48402..a34ec701 100644 --- a/ubelt/util_links.py +++ b/ubelt/util_links.py @@ -229,6 +229,15 @@ def _readlink(link): if _win32_links: # nocover if _win32_links._win32_is_junction(link): + import platform + if platform.python_implementation() == 'PyPy': + # On PyPy this test can have a false positive + # for what should be a regular link. + path = os.readlink(link) + junction_prefix = '\\\\?\\' + if path.startswith(junction_prefix): + path = path[len(junction_prefix):] + return path return _win32_links._win32_read_junction(link) try: path = os.readlink(link) @@ -338,7 +347,8 @@ def _dirstats(dpath=None): # nocover raise AssertionError(str(ELFDJ) + str(path)) line = '{E:d} {L:d} {F:d} {D:d} {J:d} - {path}'.format(**locals()) if os.path.islink(full_path): - line += ' -> ' + os.readlink(full_path) + # line += ' -> ' + os.readlink(full_path) + line += ' -> ' + _readlink(full_path) elif _win32_links is not None: if _win32_links._win32_is_junction(full_path): resolved = _win32_links._win32_read_junction(full_path) diff --git a/ubelt/util_path.py b/ubelt/util_path.py index db830eec..0d933bac 100644 --- a/ubelt/util_path.py +++ b/ubelt/util_path.py @@ -1174,6 +1174,24 @@ def chmod(self, mode, follow_symlinks=True): # """ # return self.chmod(mode, follow_symlinks=False) + # TODO: + # chainable symlink_to that returns the new link + # chainable hardlink_to that returns the new link + # probably can just uncomment when ready for a new feature + # def symlink_to(self, target, target_is_directory=False): + # """ + # Make this path a symlink pointing to the target path. + # """ + # super().symlink_to(target, target_is_directory=target_is_directory) + # return self + + # def hardlink_to(self, target): + # """ + # Make this path a hard link pointing to the same file as *target*. + # """ + # super().hardlink_to(target) + # return self + def touch(self, mode=0o0666, exist_ok=True): """ Create this file with the given access mode, if it doesn't exist.