Python Forum

Full Version: os.listdir() and follow_symlinks
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
many functions call with a file system path can also choose whether to follow symlinks (usually the default) or not. is there a way to make this choice with os.listdir()? what about a file descriptor open to a directory (i am thinking to open the directory of interest ahead with os.open() then using that file descriptor on listdir)? same questions for os.scandir().
What would be the purpose of the follow_symlink option when you list the content of a directory? How would the result differ depending on the option's value?
case A: the given path is a directory
case B: the given path is a symlink to a directory

other functions differentiate these cases in exceptions. i was just thinking listdir and/or scandir ought to, as well. by default, os.listdir() follows symlinks. many other functions have followsymlinks= to allow disabling this so that symlinks are not followed in which case NotADirectoryError should be raised. coders using os.listdir() should handle this kind of exception around os.listdir() unless they are 100% sure it cannot ever happen. presumably os.scandir() has the same issue.

(May-18-2024, 07:45 PM)Gribouillis Wrote: [ -> ]What would be the purpose of the follow_symlink option when you list the content of a directory?

to ensure that a symlink named like the believed directory is not followed. i use os.lstat() for a like purpose.

of course there is if not os.path.islink(this_path):.
(May-18-2024, 05:44 PM)Skaperen Wrote: [ -> ]many functions call with a file system path can also choose whether to follow symlinks (usually the default) or not. is there a way to make this choice with os.listdir()?
os.listdir does not distinguish between regular files and symbolic links.
With os.scandir can check if an entry is a symbolic link
This allows you to manually choose whether to follow symbolic links or not.
import os

with os.scandir('path/to/directory') as it:
    for entry in it:
        if entry.is_symlink():
            print(f"{entry.name} is a symbolic link")
        else:
            print(entry.name)
Pathlib also has a resolve(returns the absolute path of the target file or directory).
Follows all levels of symlinks until it reaches the final target.
from pathlib import Path

path = Path('path/to/symlink')
if path.is_symlink():
    target_path = path.resolve()
    print(f"{path} points to {target_path}")
else:
    print(f"{symlink_path} is not a symbolic link")
You'll have to write your own
def mylistdir(path, follow_symlinks=True):
    if follow_symlinks or not os.path.islink(path):
        return os.listdir(path)
    raise NotADirectoryError(path)
(May-18-2024, 05:44 PM)Skaperen Wrote: [ -> ]is there a way to make this choice with os.listdir()?

Probably not because os.listdir() is mainly just C's readdir() wrapped up.

If you pass a symlink to readdir(), it follows it, and there are no options not to. Since this is how POSIX has worked for a long time, most folks will assume the same here.
(May-23-2024, 07:05 AM)bowlofred Wrote: [ -> ]If you pass a symlink to readdir(), it follows it, and there are no options not to. Since this is how POSIX has worked for a long time, most folks will assume the same here.
i had hoped Python's library layer would clean up most of these inconsistencies. it seems to favor being too much like C.