Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Doc/library/os.path.rst
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ the :mod:`glob` module.)
Accepts a :term:`path-like object`.


.. function:: samefile(path1, path2)
.. function:: samefile(path1, path2, follow_symlinks=True)

Return ``True`` if both pathname arguments refer to the same file or directory.
This is determined by the device number and i-node number and raises an
Expand All @@ -394,6 +394,9 @@ the :mod:`glob` module.)
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.

.. versionchanged:: 3.10
Supports optional argument ``follow_symlinks``.


.. function:: sameopenfile(fp1, fp2)

Expand Down
5 changes: 4 additions & 1 deletion Doc/library/pathlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ call fails (for example because the path doesn't exist).
Remove this directory. The directory must be empty.


.. method:: Path.samefile(other_path)
.. method:: Path.samefile(other_path, follow_symlinks=True)

Return whether this path points to the same file as *other_path*, which
can be either a Path object, or a string. The semantics are similar
Expand All @@ -1098,6 +1098,9 @@ call fails (for example because the path doesn't exist).

.. versionadded:: 3.5

.. versionchanged:: 3.10
Supports optional argument ``follow_symlinks``.


.. method:: Path.symlink_to(target, target_is_directory=False)

Expand Down
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ descriptors without copying between kernel address space and user
address space, where one of the file descriptors must refer to a
pipe. (Contributed by Pablo Galindo in :issue:`41625`.)

Added optional ``follow_symlinks`` argument to :func:`os.path.samefile`.
(Contributed by Ross Rhodes in :issue:`42778`.)

pathlib
-------

Expand All @@ -274,6 +277,9 @@ Added negative indexing support to :attr:`PurePath.parents
<pathlib.PurePath.parents>`.
(Contributed by Yaroslav Pankovych in :issue:`21041`)

Added optional ``follow_symlinks`` argument to :func:`pathlib.samefile`.
(Contributed by Ross Rhodes in :issue:`42778`.)

platform
--------

Expand Down
6 changes: 3 additions & 3 deletions Lib/genericpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ def samestat(s1, s2):


# Are two filenames really pointing to the same file?
def samefile(f1, f2):
def samefile(f1, f2, follow_symlinks=True):
"""Test whether two pathnames reference the same actual file or directory

This is determined by the device number and i-node number and
raises an exception if an os.stat() call on either pathname fails.
"""
s1 = os.stat(f1)
s2 = os.stat(f2)
s1 = os.stat(f1, follow_symlinks=follow_symlinks)
s2 = os.stat(f2, follow_symlinks=follow_symlinks)
return samestat(s1, s2)


Expand Down
12 changes: 6 additions & 6 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1134,15 +1134,15 @@ def home(cls):
"""
return cls(cls()._flavour.gethomedir(None))

def samefile(self, other_path):
def samefile(self, other_path, follow_symlinks=True):
"""Return whether other_path is the same or not as this file
(as returned by os.path.samefile()).
"""
st = self.stat()
st = self.stat(follow_symlinks=follow_symlinks)
try:
other_st = other_path.stat()
other_st = other_path.stat(follow_symlinks=follow_symlinks)
except AttributeError:
other_st = self._accessor.stat(other_path)
other_st = self._accessor.stat(other_path, follow_symlinks=follow_symlinks)
return os.path.samestat(st, other_st)

def iterdir(self):
Expand Down Expand Up @@ -1216,12 +1216,12 @@ def resolve(self, strict=False):
obj._init(template=self)
return obj

def stat(self):
def stat(self, follow_symlinks=True):
"""
Return the result of the stat() system call on this path, like
os.stat() does.
"""
return self._accessor.stat(self)
return self._accessor.stat(self, follow_symlinks=follow_symlinks)

def owner(self):
"""
Expand Down
27 changes: 20 additions & 7 deletions Lib/test/test_genericpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,28 +227,41 @@ def test_samefile(self):

self.assertRaises(TypeError, self.pathmodule.samefile)

def _test_samefile_on_link_func(self, func):
@os_helper.skip_unless_symlink
def test_samefile_on_symlink(self):
test_fn1 = os_helper.TESTFN
test_fn2 = os_helper.TESTFN + "2"
self.addCleanup(os_helper.unlink, test_fn1)
self.addCleanup(os_helper.unlink, test_fn2)

create_file(test_fn1)

func(test_fn1, test_fn2)
os.symlink(test_fn1, test_fn2)
self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2))
self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2, follow_symlinks=False))
os.remove(test_fn2)

create_file(test_fn2)
self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))

@os_helper.skip_unless_symlink
def test_samefile_on_symlink(self):
self._test_samefile_on_link_func(os.symlink)
self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2, follow_symlinks=False))

def test_samefile_on_link(self):
try:
self._test_samefile_on_link_func(os.link)
test_fn1 = os_helper.TESTFN
test_fn2 = os_helper.TESTFN + "2"
self.addCleanup(os_helper.unlink, test_fn1)
self.addCleanup(os_helper.unlink, test_fn2)

create_file(test_fn1)

os.link(test_fn1, test_fn2)
self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2))
self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2, follow_symlinks=False))
os.remove(test_fn2)

create_file(test_fn2)
self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))
self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2, follow_symlinks=False))
except PermissionError as e:
self.skipTest('os.link(): %s' % e)

Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,7 @@ Bernhard Reiter
Steven Reiz
Roeland Rengelink
Antoine Reversat
Ross Rhodes
Flávio Ribeiro
Francesco Ricciardi
Tim Rice
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add 'follow_symlinks' optional argument to os.path and pathlib samefile
methods