16

I want to test if Python code is working with symlinks properly. How can I create symlinks (e.g. equivalent to how os.symlink() can be used) in a faked filesystem based on pathlib.Path in a Python2/3 compatible way?

glibdud
  • 7,550
  • 4
  • 27
  • 37
thinwybk
  • 4,193
  • 2
  • 40
  • 76

1 Answers1

34

For Python 3.x, the pathlib package is in the standard library. For Python 2.7 you can use the backport pathlib2.

Both packages have a .symlink_to(target, target_is_directory=False) method which should do what you want.

From experience, Python 2 does not like to make symbolic links in Windows environments, but Python 3 supports NTFS symbolic links. Linux is happy making symlinks too. Other environments I can't speak for.

Here is an example usage

In [1]: from pathlib import Path                                                                                                                                                                              

In [2]: Path('textfile.txt').write_text('hello world!')                                                                                                                                                       
Out[2]: 12

In [3]: print(list(Path('.').rglob('*.*')))                                                                                                                                                                   
[PosixPath('textfile.txt')]

In [4]: Path('link-to-textfile.txt').symlink_to(Path('textfile.txt'))                                                                                                                                         

In [5]: print(list(Path('.').rglob('*.*')))                                                                                                                                                                  
[PosixPath('textfile.txt'), PosixPath('link-to-textfile.txt')]

In [6]: Path('link-to-textfile.txt').read_text()                                                                                                                                                             
Out[6]: 'hello world!'
Błażej Michalik
  • 4,474
  • 40
  • 55
Andrew F
  • 2,690
  • 1
  • 14
  • 25
  • As a side note, both packages also have a [`.is_symlink()`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.is_symlink) method that may be useful to you. – Andrew F Feb 07 '19 at 12:49
  • I created a symlink to a file with `Path.symlink_to()`. For debugging I am using [`Path.rglob`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.rglob) to print dirs and files. However I am not seeing the target but the Path only. Is there a way to print targets? – thinwybk Feb 07 '19 at 13:37
  • 2
    I added an example to the original answer. The usage is generally `Path('the-link-you-want-to-create').symlink_to('the-original-file')`. You can check if a given `Path('file')` exists with the `.resolve()`, `.exists()`, or `.is_symlink()` methods (depending on what you're checking). – Andrew F Feb 07 '19 at 13:49
  • I am just fine with your answer. It turned out my problem is not the test, but the production code. The production code has to find files and symlinked files, has to be compatible with Python2.6 up to Python3.X and that it may not depend on any functionality other than from the Python standard libs. Different story :) – thinwybk Feb 07 '19 at 14:40
  • 1
    Well, [`os.symlink`](https://docs.python.org/2.6/library/os.html#os.symlink), [`os.lstat()`](https://docs.python.org/2.6/library/os.html#os.lstat) that doesn't follow links, and [`os.walk()`](https://docs.python.org/2.6/library/os.html#os.walk) all exist since at least Python 2.6. If your requirements are stdlib only, they should work (although not in the prettiest way). Good luck! – Andrew F Feb 07 '19 at 14:48
  • Thanks @AndrewF, I have just read the officail docs and did not pic up that weird order. Should be called `symlink_from`. This is a foot gun. In linux `cp`/`ln` its always FROM A to B. – run_the_race Feb 10 '22 at 18:09