Issue #24120: Ignore PermissionError in pathlib.Path.[r]glob(). Ulrich Petri. (Merge 3.4->3.5)

This commit is contained in:
Guido van Rossum 2016-01-06 09:51:42 -08:00
commit d54377d2ca
4 changed files with 59 additions and 37 deletions

View file

@ -499,12 +499,15 @@ class _PreciseSelector(_Selector):
_Selector.__init__(self, child_parts) _Selector.__init__(self, child_parts)
def _select_from(self, parent_path, is_dir, exists, listdir): def _select_from(self, parent_path, is_dir, exists, listdir):
if not is_dir(parent_path): try:
if not is_dir(parent_path):
return
path = parent_path._make_child_relpath(self.name)
if exists(path):
for p in self.successor._select_from(path, is_dir, exists, listdir):
yield p
except PermissionError:
return return
path = parent_path._make_child_relpath(self.name)
if exists(path):
for p in self.successor._select_from(path, is_dir, exists, listdir):
yield p
class _WildcardSelector(_Selector): class _WildcardSelector(_Selector):
@ -514,15 +517,19 @@ class _WildcardSelector(_Selector):
_Selector.__init__(self, child_parts) _Selector.__init__(self, child_parts)
def _select_from(self, parent_path, is_dir, exists, listdir): def _select_from(self, parent_path, is_dir, exists, listdir):
if not is_dir(parent_path): try:
if not is_dir(parent_path):
return
cf = parent_path._flavour.casefold
for name in listdir(parent_path):
casefolded = cf(name)
if self.pat.match(casefolded):
path = parent_path._make_child_relpath(name)
for p in self.successor._select_from(path, is_dir, exists, listdir):
yield p
except PermissionError:
return return
cf = parent_path._flavour.casefold
for name in listdir(parent_path):
casefolded = cf(name)
if self.pat.match(casefolded):
path = parent_path._make_child_relpath(name)
for p in self.successor._select_from(path, is_dir, exists, listdir):
yield p
class _RecursiveWildcardSelector(_Selector): class _RecursiveWildcardSelector(_Selector):
@ -539,19 +546,22 @@ class _RecursiveWildcardSelector(_Selector):
yield p yield p
def _select_from(self, parent_path, is_dir, exists, listdir): def _select_from(self, parent_path, is_dir, exists, listdir):
if not is_dir(parent_path): try:
if not is_dir(parent_path):
return
with _cached(listdir) as listdir:
yielded = set()
try:
successor_select = self.successor._select_from
for starting_point in self._iterate_directories(parent_path, is_dir, listdir):
for p in successor_select(starting_point, is_dir, exists, listdir):
if p not in yielded:
yield p
yielded.add(p)
finally:
yielded.clear()
except PermissionError:
return return
with _cached(listdir) as listdir:
yielded = set()
try:
successor_select = self.successor._select_from
for starting_point in self._iterate_directories(parent_path, is_dir, listdir):
for p in successor_select(starting_point, is_dir, exists, listdir):
if p not in yielded:
yield p
yielded.add(p)
finally:
yielded.clear()
# #

View file

@ -1199,26 +1199,33 @@ class _BasePathTest(object):
# (BASE) # (BASE)
# | # |
# |-- dirA/ # |-- brokenLink -> non-existing
# |-- linkC -> "../dirB" # |-- dirA
# |-- dirB/ # | `-- linkC -> ../dirB
# | |-- fileB # |-- dirB
# |-- linkD -> "../dirB" # | |-- fileB
# |-- dirC/ # | `-- linkD -> ../dirB
# | |-- fileC # |-- dirC
# | |-- fileD # | |-- dirD
# | | `-- fileD
# | `-- fileC
# |-- dirE
# |-- fileA # |-- fileA
# |-- linkA -> "fileA" # |-- linkA -> fileA
# |-- linkB -> "dirB" # `-- linkB -> dirB
# #
def setUp(self): def setUp(self):
def cleanup():
os.chmod(join('dirE'), 0o777)
support.rmtree(BASE)
self.addCleanup(cleanup)
os.mkdir(BASE) os.mkdir(BASE)
self.addCleanup(support.rmtree, BASE)
os.mkdir(join('dirA')) os.mkdir(join('dirA'))
os.mkdir(join('dirB')) os.mkdir(join('dirB'))
os.mkdir(join('dirC')) os.mkdir(join('dirC'))
os.mkdir(join('dirC', 'dirD')) os.mkdir(join('dirC', 'dirD'))
os.mkdir(join('dirE'))
with open(join('fileA'), 'wb') as f: with open(join('fileA'), 'wb') as f:
f.write(b"this is file A\n") f.write(b"this is file A\n")
with open(join('dirB', 'fileB'), 'wb') as f: with open(join('dirB', 'fileB'), 'wb') as f:
@ -1227,6 +1234,7 @@ class _BasePathTest(object):
f.write(b"this is file C\n") f.write(b"this is file C\n")
with open(join('dirC', 'dirD', 'fileD'), 'wb') as f: with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
f.write(b"this is file D\n") f.write(b"this is file D\n")
os.chmod(join('dirE'), 0)
if not symlink_skip_reason: if not symlink_skip_reason:
# Relative symlinks # Relative symlinks
os.symlink('fileA', join('linkA')) os.symlink('fileA', join('linkA'))
@ -1363,7 +1371,7 @@ class _BasePathTest(object):
p = P(BASE) p = P(BASE)
it = p.iterdir() it = p.iterdir()
paths = set(it) paths = set(it)
expected = ['dirA', 'dirB', 'dirC', 'fileA'] expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA']
if not symlink_skip_reason: if not symlink_skip_reason:
expected += ['linkA', 'linkB', 'brokenLink'] expected += ['linkA', 'linkB', 'brokenLink']
self.assertEqual(paths, { P(BASE, q) for q in expected }) self.assertEqual(paths, { P(BASE, q) for q in expected })

View file

@ -1106,6 +1106,7 @@ Gabriel de Perthuis
Tim Peters Tim Peters
Benjamin Peterson Benjamin Peterson
Joe Peterson Joe Peterson
Ulrich Petri
Chris Petrilli Chris Petrilli
Roumen Petrov Roumen Petrov
Bjorn Pettersen Bjorn Pettersen

View file

@ -41,6 +41,9 @@ Core and Builtins
Library Library
------- -------
- Issue #24120: Ignore PermissionError when traversing a tree with
pathlib.Path.[r]glob(). Patch by Ulrich Petri.
- Issue #25447: fileinput now uses sys.stdin as-is if it does not have a - Issue #25447: fileinput now uses sys.stdin as-is if it does not have a
buffer attribute (restores backward compatibility). buffer attribute (restores backward compatibility).