Skip to content

Commit

Permalink
pythonGH-113568: Stop raising auditing events from pathlib ABCs (pyth…
Browse files Browse the repository at this point in the history
…on#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.
  • Loading branch information
barneygale authored and aisk committed Feb 11, 2024
1 parent 02927b8 commit eaf987a
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 35 deletions.
43 changes: 42 additions & 1 deletion Lib/pathlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import ntpath
import os
import posixpath
import sys
import warnings

try:
import pwd
Expand Down Expand Up @@ -230,7 +232,6 @@ def _unsupported(cls, method_name):

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

def glob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
"""Iterate over this subtree and yield all existing files (of any
kind, including directories) matching the given relative pattern.
"""
sys.audit("pathlib.Path.glob", self, pattern)
if pattern.endswith('**'):
# GH-70303: '**' only matches directories. Add trailing slash.
warnings.warn(
"Pattern ending '**' will match files and directories in a "
"future Python release. Add a trailing slash to match only "
"directories and remove this warning.",
FutureWarning, 2)
pattern = f'{pattern}/'
return _abc.PathBase.glob(
self, pattern, case_sensitive=case_sensitive, follow_symlinks=follow_symlinks)

def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
"""Recursively yield all existing files (of any kind, including
directories) matching the given relative pattern, anywhere in
this subtree.
"""
sys.audit("pathlib.Path.rglob", self, pattern)
if pattern.endswith('**'):
# GH-70303: '**' only matches directories. Add trailing slash.
warnings.warn(
"Pattern ending '**' will match files and directories in a "
"future Python release. Add a trailing slash to match only "
"directories and remove this warning.",
FutureWarning, 2)
pattern = f'{pattern}/'
pattern = f'**/{pattern}'
return _abc.PathBase.glob(
self, pattern, case_sensitive=case_sensitive, follow_symlinks=follow_symlinks)

def walk(self, top_down=True, on_error=None, follow_symlinks=False):
"""Walk the directory tree from this directory, similar to os.walk()."""
sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
return _abc.PathBase.walk(
self, top_down=top_down, on_error=on_error, follow_symlinks=follow_symlinks)

def absolute(self):
"""Return an absolute version of this path
No normalization or symlink resolution is performed.
Expand Down
29 changes: 8 additions & 21 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -811,18 +811,6 @@ def glob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
"""Iterate over this subtree and yield all existing files (of any
kind, including directories) matching the given relative pattern.
"""
sys.audit("pathlib.Path.glob", self, pattern)
return self._glob(pattern, case_sensitive, follow_symlinks)

def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
"""Recursively yield all existing files (of any kind, including
directories) matching the given relative pattern, anywhere in
this subtree.
"""
sys.audit("pathlib.Path.rglob", self, pattern)
return self._glob(f'**/{pattern}', case_sensitive, follow_symlinks)

def _glob(self, pattern, case_sensitive, follow_symlinks):
path_pattern = self.with_segments(pattern)
if path_pattern.drive or path_pattern.root:
raise NotImplementedError("Non-relative patterns are unsupported")
Expand All @@ -833,14 +821,6 @@ def _glob(self, pattern, case_sensitive, follow_symlinks):
if pattern[-1] in (self.pathmod.sep, self.pathmod.altsep):
# GH-65238: pathlib doesn't preserve trailing slash. Add it back.
pattern_parts.append('')
if pattern_parts[-1] == '**':
# GH-70303: '**' only matches directories. Add trailing slash.
warnings.warn(
"Pattern ending '**' will match files and directories in a "
"future Python release. Add a trailing slash to match only "
"directories and remove this warning.",
FutureWarning, 3)
pattern_parts.append('')

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

def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
"""Recursively yield all existing files (of any kind, including
directories) matching the given relative pattern, anywhere in
this subtree.
"""
return self.glob(
f'**/{pattern}', case_sensitive=case_sensitive, follow_symlinks=follow_symlinks)

def walk(self, top_down=True, on_error=None, follow_symlinks=False):
"""Walk the directory tree from this directory, similar to os.walk()."""
sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
paths = [self]

while paths:
Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_pathlib/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,18 @@ def test_glob_above_recursion_limit(self):
with set_recursion_limit(recursion_limit):
list(base.glob('**/'))

def test_glob_recursive_no_trailing_slash(self):
P = self.cls
p = P(self.base)
with self.assertWarns(FutureWarning):
p.glob('**')
with self.assertWarns(FutureWarning):
p.glob('*/**')
with self.assertWarns(FutureWarning):
p.rglob('**')
with self.assertWarns(FutureWarning):
p.rglob('*/**')


@only_posix
class PosixPathTest(PathTest, PurePosixPathTest):
Expand Down
13 changes: 0 additions & 13 deletions Lib/test/test_pathlib/test_pathlib_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1266,19 +1266,6 @@ def test_glob_long_symlink(self):
bad_link.symlink_to("bad" * 200)
self.assertEqual(sorted(base.glob('**/*')), [bad_link])

def test_glob_recursive_no_trailing_slash(self):
P = self.cls
p = P(self.base)
with self.assertWarns(FutureWarning):
p.glob('**')
with self.assertWarns(FutureWarning):
p.glob('*/**')
with self.assertWarns(FutureWarning):
p.rglob('**')
with self.assertWarns(FutureWarning):
p.rglob('*/**')


def test_readlink(self):
if not self.can_symlink:
self.skipTest("symlinks required")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Raise audit events from :class:`pathlib.Path` and not its private base class
``PathBase``.

0 comments on commit eaf987a

Please sign in to comment.