Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit af886ff

Browse filesBrowse files
akulakovbarneygale
andauthored
GH-89769: pathlib.Path.glob(): do not follow symlinks when checking for precise match (GH-29655)
Co-authored-by: Barney Gale <barney.gale@gmail.com>
1 parent c7c3a60 commit af886ff
Copy full SHA for af886ff

File tree

Expand file treeCollapse file tree

4 files changed

+25
-9
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+25
-9
lines changed

‎Doc/library/pathlib.rst

Copy file name to clipboardExpand all lines: Doc/library/pathlib.rst
+9-6Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -819,9 +819,14 @@ call fails (for example because the path doesn't exist).
819819
.. versionchanged:: 3.10
820820
The *follow_symlinks* parameter was added.
821821

822-
.. method:: Path.exists()
822+
.. method:: Path.exists(*, follow_symlinks=True)
823823

824-
Whether the path points to an existing file or directory::
824+
Return ``True`` if the path points to an existing file or directory.
825+
826+
This method normally follows symlinks; to check if a symlink exists, add
827+
the argument ``follow_symlinks=False``.
828+
829+
::
825830

826831
>>> Path('.').exists()
827832
True
@@ -832,10 +837,8 @@ call fails (for example because the path doesn't exist).
832837
>>> Path('nonexistentfile').exists()
833838
False
834839

835-
.. note::
836-
If the path points to a symlink, :meth:`exists` returns whether the
837-
symlink *points to* an existing file or directory.
838-
840+
.. versionchanged:: 3.12
841+
The *follow_symlinks* parameter was added.
839842

840843
.. method:: Path.expanduser()
841844

‎Lib/pathlib.py

Copy file name to clipboardExpand all lines: Lib/pathlib.py
+7-3Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ def __init__(self, name, child_parts, flavour):
135135
def _select_from(self, parent_path, is_dir, exists, scandir):
136136
try:
137137
path = parent_path._make_child_relpath(self.name)
138-
if (is_dir if self.dironly else exists)(path):
138+
follow = is_dir(path) if self.dironly else exists(path, follow_symlinks=False)
139+
if follow:
139140
for p in self.successor._select_from(path, is_dir, exists, scandir):
140141
yield p
141142
except PermissionError:
@@ -1122,12 +1123,15 @@ def hardlink_to(self, target):
11221123

11231124
# Convenience functions for querying the stat results
11241125

1125-
def exists(self):
1126+
def exists(self, *, follow_symlinks=True):
11261127
"""
11271128
Whether this path exists.
1129+
1130+
This method normally follows symlinks; to check whether a symlink exists,
1131+
add the argument follow_symlinks=False.
11281132
"""
11291133
try:
1130-
self.stat()
1134+
self.stat(follow_symlinks=follow_symlinks)
11311135
except OSError as e:
11321136
if not _ignore_error(e):
11331137
raise

‎Lib/test/test_pathlib.py

Copy file name to clipboardExpand all lines: Lib/test/test_pathlib.py
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,8 @@ def test_exists(self):
17001700
self.assertIs(True, (p / 'linkB').exists())
17011701
self.assertIs(True, (p / 'linkB' / 'fileB').exists())
17021702
self.assertIs(False, (p / 'linkA' / 'bah').exists())
1703+
self.assertIs(False, (p / 'brokenLink').exists())
1704+
self.assertIs(True, (p / 'brokenLink').exists(follow_symlinks=False))
17031705
self.assertIs(False, (p / 'foo').exists())
17041706
self.assertIs(False, P('/xyzzy').exists())
17051707
self.assertIs(False, P(BASE + '\udfff').exists())
@@ -1806,6 +1808,8 @@ def _check(glob, expected):
18061808
_check(p.glob("*/fileB"), ['dirB/fileB'])
18071809
else:
18081810
_check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
1811+
if os_helper.can_symlink():
1812+
_check(p.glob("brokenLink"), ['brokenLink'])
18091813

18101814
if not os_helper.can_symlink():
18111815
_check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"])
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fixed the bug in :meth:`pathlib.Path.glob` -- previously a dangling symlink
2+
would not be found by this method when the pattern is an exact match, but
3+
would be found when the pattern contains a wildcard or the recursive
4+
wildcard (``**``). With this change, a dangling symlink will be found in
5+
both cases.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.