Skip to content

Commit

Permalink
Adding support for onerror parameter in walk
Browse files Browse the repository at this point in the history
  • Loading branch information
epizut committed Jul 4, 2023
1 parent 348d4ab commit 54ddc90
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
6 changes: 4 additions & 2 deletions fsspec/asyn.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ async def _info(self, path, **kwargs):
async def _ls(self, path, detail=True, **kwargs):
raise NotImplementedError

async def _walk(self, path, maxdepth=None, **kwargs):
async def _walk(self, path, maxdepth=None, onerror=None, **kwargs):
if maxdepth is not None and maxdepth < 1:
raise ValueError("maxdepth must be at least 1")

Expand All @@ -653,7 +653,9 @@ async def _walk(self, path, maxdepth=None, **kwargs):
detail = kwargs.pop("detail", False)
try:
listing = await self._ls(path, detail=True, **kwargs)
except (FileNotFoundError, OSError):
except (FileNotFoundError, OSError) as e:
if onerror is not None:
onerror(e)
if detail:
yield path, {}, {}
else:
Expand Down
11 changes: 9 additions & 2 deletions fsspec/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ def _ls_from_cache(self, path):
except KeyError:
pass

def walk(self, path, maxdepth=None, topdown=True, **kwargs):
def walk(self, path, maxdepth=None, topdown=True, onerror=None, **kwargs):
"""Return all files belows path
List all files, recursing into subdirectories; output is iterator-style,
Expand All @@ -386,6 +386,11 @@ def walk(self, path, maxdepth=None, topdown=True, **kwargs):
it resumes walk() again.
Modifying dirnames when topdown is False has no effect. (see os.walk)
If optional argument onerror is specified, it should be a function;
it will be called with one argument, an OSError instance.
It can report the error to continue with the walk,
or raise the exception to abort the walk.
Note that the "files" outputted will include anything that is not
a directory, such as links.
Expand All @@ -412,7 +417,9 @@ def walk(self, path, maxdepth=None, topdown=True, **kwargs):
detail = kwargs.pop("detail", False)
try:
listing = self.ls(path, detail=True, **kwargs)
except (FileNotFoundError, OSError):
except (FileNotFoundError, OSError) as e:
if onerror is not None:
onerror(e)
if detail:
return path, {}, {}
return path, [], []
Expand Down
18 changes: 18 additions & 0 deletions fsspec/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import pickle
import tempfile
from unittest.mock import Mock

import pytest

Expand Down Expand Up @@ -479,3 +480,20 @@ def _walk(*args, **kwargs):
(dir12, [], ["file121"]),
(dir1, ["dir11", "dir12"], ["file11"]),
]

# onerror skip by default
assert list(m.walk("do_not_exist")) == []
# onerror skip function
mock = Mock()
assert list(m.walk("do_not_exist", onerror=mock.onerror)) == []
mock.onerror.assert_called()
assert mock.onerror.call_args.kwargs == {}
assert len(mock.onerror.call_args.args) == 1
assert isinstance(mock.onerror.call_args.args[0], FileNotFoundError)
# onerror re-raise function
with pytest.raises(FileNotFoundError):

def onerror(e):
raise e

list(m.walk("do_not_exist", onerror=onerror))

0 comments on commit 54ddc90

Please sign in to comment.