Skip to content

Commit 3c4e972

Browse files
authored
GH-113568: Stop raising auditing events from pathlib ABCs (#113571)
Raise auditing events in `pathlib.Path.glob()`, `rglob()` and `walk()`, but not in `pathlib._abc.PathBase` methods. Also move generation of a deprecation warning into `pathlib.Path` so it gets the right stack level.
1 parent 99854ce commit 3c4e972

File tree

5 files changed

+64
-35
lines changed

5 files changed

+64
-35
lines changed

Lib/pathlib/__init__.py

+42-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import ntpath
1010
import os
1111
import posixpath
12+
import sys
13+
import warnings
1214

1315
try:
1416
import pwd
@@ -230,7 +232,6 @@ def _unsupported(cls, method_name):
230232

231233
def __init__(self, *args, **kwargs):
232234
if kwargs:
233-
import warnings
234235
msg = ("support for supplying keyword arguments to pathlib.PurePath "
235236
"is deprecated and scheduled for removal in Python {remove}")
236237
warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
@@ -309,6 +310,46 @@ def _make_child_entry(self, entry):
309310
path._tail_cached = self._tail + [entry.name]
310311
return path
311312

313+
def glob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
314+
"""Iterate over this subtree and yield all existing files (of any
315+
kind, including directories) matching the given relative pattern.
316+
"""
317+
sys.audit("pathlib.Path.glob", self, pattern)
318+
if pattern.endswith('**'):
319+
# GH-70303: '**' only matches directories. Add trailing slash.
320+
warnings.warn(
321+
"Pattern ending '**' will match files and directories in a "
322+
"future Python release. Add a trailing slash to match only "
323+
"directories and remove this warning.",
324+
FutureWarning, 2)
325+
pattern = f'{pattern}/'
326+
return _abc.PathBase.glob(
327+
self, pattern, case_sensitive=case_sensitive, follow_symlinks=follow_symlinks)
328+
329+
def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
330+
"""Recursively yield all existing files (of any kind, including
331+
directories) matching the given relative pattern, anywhere in
332+
this subtree.
333+
"""
334+
sys.audit("pathlib.Path.rglob", self, pattern)
335+
if pattern.endswith('**'):
336+
# GH-70303: '**' only matches directories. Add trailing slash.
337+
warnings.warn(
338+
"Pattern ending '**' will match files and directories in a "
339+
"future Python release. Add a trailing slash to match only "
340+
"directories and remove this warning.",
341+
FutureWarning, 2)
342+
pattern = f'{pattern}/'
343+
pattern = f'**/{pattern}'
344+
return _abc.PathBase.glob(
345+
self, pattern, case_sensitive=case_sensitive, follow_symlinks=follow_symlinks)
346+
347+
def walk(self, top_down=True, on_error=None, follow_symlinks=False):
348+
"""Walk the directory tree from this directory, similar to os.walk()."""
349+
sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
350+
return _abc.PathBase.walk(
351+
self, top_down=top_down, on_error=on_error, follow_symlinks=follow_symlinks)
352+
312353
def absolute(self):
313354
"""Return an absolute version of this path
314355
No normalization or symlink resolution is performed.

Lib/pathlib/_abc.py

+8-21
Original file line numberDiff line numberDiff line change
@@ -811,18 +811,6 @@ def glob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
811811
"""Iterate over this subtree and yield all existing files (of any
812812
kind, including directories) matching the given relative pattern.
813813
"""
814-
sys.audit("pathlib.Path.glob", self, pattern)
815-
return self._glob(pattern, case_sensitive, follow_symlinks)
816-
817-
def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
818-
"""Recursively yield all existing files (of any kind, including
819-
directories) matching the given relative pattern, anywhere in
820-
this subtree.
821-
"""
822-
sys.audit("pathlib.Path.rglob", self, pattern)
823-
return self._glob(f'**/{pattern}', case_sensitive, follow_symlinks)
824-
825-
def _glob(self, pattern, case_sensitive, follow_symlinks):
826814
path_pattern = self.with_segments(pattern)
827815
if path_pattern.drive or path_pattern.root:
828816
raise NotImplementedError("Non-relative patterns are unsupported")
@@ -833,14 +821,6 @@ def _glob(self, pattern, case_sensitive, follow_symlinks):
833821
if pattern[-1] in (self.pathmod.sep, self.pathmod.altsep):
834822
# GH-65238: pathlib doesn't preserve trailing slash. Add it back.
835823
pattern_parts.append('')
836-
if pattern_parts[-1] == '**':
837-
# GH-70303: '**' only matches directories. Add trailing slash.
838-
warnings.warn(
839-
"Pattern ending '**' will match files and directories in a "
840-
"future Python release. Add a trailing slash to match only "
841-
"directories and remove this warning.",
842-
FutureWarning, 3)
843-
pattern_parts.append('')
844824

845825
if case_sensitive is None:
846826
# TODO: evaluate case-sensitivity of each directory in _select_children().
@@ -895,9 +875,16 @@ def _glob(self, pattern, case_sensitive, follow_symlinks):
895875
paths = _select_children(paths, dir_only, follow_symlinks, match)
896876
return paths
897877

878+
def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
879+
"""Recursively yield all existing files (of any kind, including
880+
directories) matching the given relative pattern, anywhere in
881+
this subtree.
882+
"""
883+
return self.glob(
884+
f'**/{pattern}', case_sensitive=case_sensitive, follow_symlinks=follow_symlinks)
885+
898886
def walk(self, top_down=True, on_error=None, follow_symlinks=False):
899887
"""Walk the directory tree from this directory, similar to os.walk()."""
900-
sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
901888
paths = [self]
902889

903890
while paths:

Lib/test/test_pathlib/test_pathlib.py

+12
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,18 @@ def test_glob_above_recursion_limit(self):
17031703
with set_recursion_limit(recursion_limit):
17041704
list(base.glob('**/'))
17051705

1706+
def test_glob_recursive_no_trailing_slash(self):
1707+
P = self.cls
1708+
p = P(self.base)
1709+
with self.assertWarns(FutureWarning):
1710+
p.glob('**')
1711+
with self.assertWarns(FutureWarning):
1712+
p.glob('*/**')
1713+
with self.assertWarns(FutureWarning):
1714+
p.rglob('**')
1715+
with self.assertWarns(FutureWarning):
1716+
p.rglob('*/**')
1717+
17061718

17071719
@only_posix
17081720
class PosixPathTest(PathTest, PurePosixPathTest):

Lib/test/test_pathlib/test_pathlib_abc.py

-13
Original file line numberDiff line numberDiff line change
@@ -1266,19 +1266,6 @@ def test_glob_long_symlink(self):
12661266
bad_link.symlink_to("bad" * 200)
12671267
self.assertEqual(sorted(base.glob('**/*')), [bad_link])
12681268

1269-
def test_glob_recursive_no_trailing_slash(self):
1270-
P = self.cls
1271-
p = P(self.base)
1272-
with self.assertWarns(FutureWarning):
1273-
p.glob('**')
1274-
with self.assertWarns(FutureWarning):
1275-
p.glob('*/**')
1276-
with self.assertWarns(FutureWarning):
1277-
p.rglob('**')
1278-
with self.assertWarns(FutureWarning):
1279-
p.rglob('*/**')
1280-
1281-
12821269
def test_readlink(self):
12831270
if not self.can_symlink:
12841271
self.skipTest("symlinks required")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Raise audit events from :class:`pathlib.Path` and not its private base class
2+
``PathBase``.

0 commit comments

Comments
 (0)