Skip to content

Commit 6c2d33a

Browse files
committed
Issue #24120: Ignore PermissionError in pathlib.Path.[r]glob(). Ulrich Petri.
1 parent 114a1d6 commit 6c2d33a

File tree

4 files changed

+59
-37
lines changed

4 files changed

+59
-37
lines changed

‎Lib/pathlib.py‎

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -454,12 +454,15 @@ def __init__(self, name, child_parts):
454454
_Selector.__init__(self, child_parts)
455455

456456
def _select_from(self, parent_path, is_dir, exists, listdir):
457-
if not is_dir(parent_path):
457+
try:
458+
if not is_dir(parent_path):
459+
return
460+
path = parent_path._make_child_relpath(self.name)
461+
if exists(path):
462+
for p in self.successor._select_from(path, is_dir, exists, listdir):
463+
yield p
464+
except PermissionError:
458465
return
459-
path = parent_path._make_child_relpath(self.name)
460-
if exists(path):
461-
for p in self.successor._select_from(path, is_dir, exists, listdir):
462-
yield p
463466

464467

465468
class _WildcardSelector(_Selector):
@@ -469,15 +472,19 @@ def __init__(self, pat, child_parts):
469472
_Selector.__init__(self, child_parts)
470473

471474
def _select_from(self, parent_path, is_dir, exists, listdir):
472-
if not is_dir(parent_path):
475+
try:
476+
if not is_dir(parent_path):
477+
return
478+
cf = parent_path._flavour.casefold
479+
for name in listdir(parent_path):
480+
casefolded = cf(name)
481+
if self.pat.match(casefolded):
482+
path = parent_path._make_child_relpath(name)
483+
for p in self.successor._select_from(path, is_dir, exists, listdir):
484+
yield p
485+
except PermissionError:
473486
return
474-
cf = parent_path._flavour.casefold
475-
for name in listdir(parent_path):
476-
casefolded = cf(name)
477-
if self.pat.match(casefolded):
478-
path = parent_path._make_child_relpath(name)
479-
for p in self.successor._select_from(path, is_dir, exists, listdir):
480-
yield p
487+
481488

482489

483490
class _RecursiveWildcardSelector(_Selector):
@@ -494,19 +501,22 @@ def _iterate_directories(self, parent_path, is_dir, listdir):
494501
yield p
495502

496503
def _select_from(self, parent_path, is_dir, exists, listdir):
497-
if not is_dir(parent_path):
504+
try:
505+
if not is_dir(parent_path):
506+
return
507+
with _cached(listdir) as listdir:
508+
yielded = set()
509+
try:
510+
successor_select = self.successor._select_from
511+
for starting_point in self._iterate_directories(parent_path, is_dir, listdir):
512+
for p in successor_select(starting_point, is_dir, exists, listdir):
513+
if p not in yielded:
514+
yield p
515+
yielded.add(p)
516+
finally:
517+
yielded.clear()
518+
except PermissionError:
498519
return
499-
with _cached(listdir) as listdir:
500-
yielded = set()
501-
try:
502-
successor_select = self.successor._select_from
503-
for starting_point in self._iterate_directories(parent_path, is_dir, listdir):
504-
for p in successor_select(starting_point, is_dir, exists, listdir):
505-
if p not in yielded:
506-
yield p
507-
yielded.add(p)
508-
finally:
509-
yielded.clear()
510520

511521

512522
#

‎Lib/test/test_pathlib.py‎

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,26 +1203,33 @@ class _BasePathTest(object):
12031203

12041204
# (BASE)
12051205
# |
1206-
# |-- dirA/
1207-
# |-- linkC -> "../dirB"
1208-
# |-- dirB/
1209-
# | |-- fileB
1210-
# |-- linkD -> "../dirB"
1211-
# |-- dirC/
1212-
# | |-- fileC
1213-
# | |-- fileD
1206+
# |-- brokenLink -> non-existing
1207+
# |-- dirA
1208+
# | `-- linkC -> ../dirB
1209+
# |-- dirB
1210+
# | |-- fileB
1211+
# | `-- linkD -> ../dirB
1212+
# |-- dirC
1213+
# | |-- dirD
1214+
# | | `-- fileD
1215+
# | `-- fileC
1216+
# |-- dirE
12141217
# |-- fileA
1215-
# |-- linkA -> "fileA"
1216-
# |-- linkB -> "dirB"
1218+
# |-- linkA -> fileA
1219+
# `-- linkB -> dirB
12171220
#
12181221

12191222
def setUp(self):
1223+
def cleanup():
1224+
os.chmod(join('dirE'), 0o777)
1225+
support.rmtree(BASE)
1226+
self.addCleanup(cleanup)
12201227
os.mkdir(BASE)
1221-
self.addCleanup(support.rmtree, BASE)
12221228
os.mkdir(join('dirA'))
12231229
os.mkdir(join('dirB'))
12241230
os.mkdir(join('dirC'))
12251231
os.mkdir(join('dirC', 'dirD'))
1232+
os.mkdir(join('dirE'))
12261233
with open(join('fileA'), 'wb') as f:
12271234
f.write(b"this is file A\n")
12281235
with open(join('dirB', 'fileB'), 'wb') as f:
@@ -1231,6 +1238,7 @@ def setUp(self):
12311238
f.write(b"this is file C\n")
12321239
with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
12331240
f.write(b"this is file D\n")
1241+
os.chmod(join('dirE'), 0)
12341242
if not symlink_skip_reason:
12351243
# Relative symlinks
12361244
os.symlink('fileA', join('linkA'))
@@ -1306,7 +1314,7 @@ def test_iterdir(self):
13061314
p = P(BASE)
13071315
it = p.iterdir()
13081316
paths = set(it)
1309-
expected = ['dirA', 'dirB', 'dirC', 'fileA']
1317+
expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA']
13101318
if not symlink_skip_reason:
13111319
expected += ['linkA', 'linkB', 'brokenLink']
13121320
self.assertEqual(paths, { P(BASE, q) for q in expected })

‎Misc/ACKS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ Gabriel de Perthuis
10751075
Tim Peters
10761076
Benjamin Peterson
10771077
Joe Peterson
1078+
Ulrich Petri
10781079
Chris Petrilli
10791080
Roumen Petrov
10801081
Bjorn Pettersen

‎Misc/NEWS‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Core and Builtins
1313
Library
1414
-------
1515

16+
- Issue #24120: Ignore PermissionError when traversing a tree with
17+
pathlib.Path.[r]glob(). Patch by Ulrich Petri.
18+
1619

1720
What's New in Python 3.4.4?
1821
===========================

0 commit comments

Comments
 (0)