Skip to content

Commit c4edbcb

Browse files
committed
Add missing follow_symlink argument to os.link
- fixes #973
1 parent 190390f commit c4edbcb

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ The released versions correspond to PyPI releases.
2121
* fixed creation of the temp directory in the fake file system after a filesystem reset
2222
(see [#965](../../issues/965))
2323
* fixed handling of `dirfd` in `os.symlink` (see [#968](../../issues/968))
24+
* add missing `follow_symlink` argument to `os.link` (see [#973](../../issues/973))
2425

2526
## [Version 5.3.5](https://pypi.python.org/pypi/pyfakefs/5.3.5) (2024-01-30)
2627
Fixes a regression.

pyfakefs/fake_os.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ def link(
11851185
*,
11861186
src_dir_fd: Optional[int] = None,
11871187
dst_dir_fd: Optional[int] = None,
1188+
follow_symlinks: Optional[bool] = None,
11881189
) -> None:
11891190
"""Create a hard link at dst, pointing at src.
11901191
@@ -1195,14 +1196,21 @@ def link(
11951196
with `src` being relative to this directory.
11961197
dst_dir_fd: If not `None`, the file descriptor of a directory,
11971198
with `dst` being relative to this directory.
1199+
follow_symlinks: (bool) If True (the default), symlinks in the
1200+
path are traversed.
11981201
11991202
Raises:
12001203
OSError: if something already exists at new_path.
12011204
OSError: if the parent directory doesn't exist.
12021205
"""
1206+
if IS_PYPY and follow_symlinks is not None:
1207+
raise OSError(errno.EINVAL, "Invalid argument: follow_symlinks")
1208+
if follow_symlinks is None:
1209+
follow_symlinks = True
1210+
12031211
src = self._path_with_dir_fd(src, self.link, src_dir_fd)
12041212
dst = self._path_with_dir_fd(dst, self.link, dst_dir_fd)
1205-
self.filesystem.link(src, dst)
1213+
self.filesystem.link(src, dst, follow_symlinks=follow_symlinks)
12061214

12071215
def fsync(self, fd: int) -> None:
12081216
"""Perform fsync for a fake file (in other words, do nothing).

pyfakefs/tests/fake_os_test.py

+23
Original file line numberDiff line numberDiff line change
@@ -2705,6 +2705,29 @@ def test_link_count1(self):
27052705
self.os.unlink(file1_path)
27062706
self.assertEqual(self.os.stat(file2_path).st_nlink, 1)
27072707

2708+
@unittest.skipIf(IS_PYPY, "follow_symlinks not supported in PyPi")
2709+
def test_link_no_follow_symlink(self):
2710+
self.skip_if_symlink_not_supported()
2711+
target_path = self.make_path("target_path")
2712+
self.create_file(target_path, contents="foo")
2713+
symlink_path = self.make_path("symlink_to_file")
2714+
self.create_symlink(symlink_path, target_path)
2715+
link_path = self.make_path("link_to_symlink")
2716+
self.os.link(symlink_path, link_path, follow_symlinks=False)
2717+
self.assertTrue(self.os.path.islink(link_path))
2718+
2719+
@unittest.skipIf(not IS_PYPY, "follow_symlinks only not supported in PyPi")
2720+
def test_link_follow_symlink_not_supported_inPypy(self):
2721+
self.skip_if_symlink_not_supported()
2722+
target_path = self.make_path("target_path")
2723+
self.create_file(target_path, contents="foo")
2724+
symlink_path = self.make_path("symlink_to_file")
2725+
self.create_symlink(symlink_path, target_path)
2726+
link_path = self.make_path("link_to_symlink")
2727+
with self.assertRaises(OSError) as cm:
2728+
self.os.link(symlink_path, link_path, follow_symlinks=False)
2729+
self.assertEqual(errno.EINVAL, cm.exception.errno)
2730+
27082731
def test_nlink_for_directories(self):
27092732
self.skip_real_fs()
27102733
self.create_dir(self.make_path("foo", "bar"))

0 commit comments

Comments
 (0)