ubelt.util_links module¶
Cross-platform logic for dealing with symlinks. Basic functionality should work on all operating systems including everyone’s favorite pathological OS (note that there is an additional helper file for this case), but there are some corner cases depending on your version. Recent versions of Windows tend to work, but there certain system settings that cause issues. Any POSIX system works without difficulty.
Example
>>> import ubelt as ub
>>> from os.path import normpath, join
>>> dpath = ub.ensure_app_cache_dir('ubelt', normpath('demo/symlink'))
>>> real_path = join(dpath, 'real_file.txt')
>>> link_path = join(dpath, 'link_file.txt')
>>> ub.touch(real_path)
>>> result = ub.symlink(real_path, link_path, overwrite=True, verbose=3)
>>> parts = result.split(os.path.sep)
>>> print(parts[-1])
link_file.txt
- ubelt.util_links.symlink(real_path, link_path, overwrite=False, verbose=0)[source]¶
Create a link
link_path
that mirrorsreal_path
.This function attempts to create a real symlink, but will fall back on a hard link or junction if symlinks are not supported.
- Parameters
path (str | PathLike) – path to real file or directory
link_path (str | PathLike) – path to desired location for symlink
overwrite (bool, default=False) – overwrite existing symlinks. This will not overwrite real files on systems with proper symlinks. However, on older versions of windows junctions are indistinguishable from real files, so we cannot make this guarantee.
verbose (int, default=0) – verbosity level
- Returns
link path
- Return type
str | PathLike
Note
On systems that do not contain support for symlinks (e.g. some versions / configurations of Windows), this function will fall back on hard links or junctions [WikiNTFSLinks], [WikiHardLink]. The differences between the two are explained in [WikiSymLink].
If symlinks are not available, then
link_path
andreal_path
must exist on the same filesystem. Given that, this function always works in the sense that (1)link_path
will mirror the data fromreal_path
, (2) updates to one will effect the other, and (3) no extra space will be used.More details can be found in
ubelt._win32_links
. On systems that support symlinks (e.g. Linux), none of the above applies.References
Example
>>> import ubelt as ub >>> dpath = ub.ensure_app_cache_dir('ubelt', 'test_symlink0') >>> real_path = join(dpath, 'real_file.txt') >>> link_path = join(dpath, 'link_file.txt') >>> [ub.delete(p) for p in [real_path, link_path]] >>> ub.writeto(real_path, 'foo') >>> result = symlink(real_path, link_path) >>> assert ub.readfrom(result) == 'foo' >>> [ub.delete(p) for p in [real_path, link_path]]
Example
>>> import ubelt as ub >>> from os.path import dirname >>> dpath = ub.ensure_app_cache_dir('ubelt', 'test_symlink1') >>> ub.delete(dpath) >>> ub.ensuredir(dpath) >>> _dirstats(dpath) >>> real_dpath = ub.ensuredir((dpath, 'real_dpath')) >>> link_dpath = ub.augpath(real_dpath, base='link_dpath') >>> real_path = join(dpath, 'afile.txt') >>> link_path = join(dpath, 'afile.txt') >>> [ub.delete(p) for p in [real_path, link_path]] >>> ub.writeto(real_path, 'foo') >>> result = symlink(real_dpath, link_dpath) >>> assert ub.readfrom(link_path) == 'foo', 'read should be same' >>> ub.writeto(link_path, 'bar') >>> _dirstats(dpath) >>> assert ub.readfrom(link_path) == 'bar', 'very bad bar' >>> assert ub.readfrom(real_path) == 'bar', 'changing link did not change real' >>> ub.writeto(real_path, 'baz') >>> _dirstats(dpath) >>> assert ub.readfrom(real_path) == 'baz', 'very bad baz' >>> assert ub.readfrom(link_path) == 'baz', 'changing real did not change link' >>> ub.delete(link_dpath, verbose=1) >>> _dirstats(dpath) >>> assert not exists(link_dpath), 'link should not exist' >>> assert exists(real_path), 'real path should exist' >>> _dirstats(dpath) >>> ub.delete(dpath, verbose=1) >>> _dirstats(dpath) >>> assert not exists(real_path)