Read total and detail in DirFileSystem when passed positionally - #2181
Rodrigo-Palma wants to merge 3 commits into
Conversation
DirFileSystem.du, its async counterpart and DirFileSystem.find forward *args untouched to the wrapped filesystem, but read the flag they need for post-processing from kwargs alone. In the base signatures total is the first positional parameter after path (AbstractFileSystem.du) and detail is the fourth (AbstractFileSystem.find), so a caller passing them positionally never reaches kwargs. The wrapper then takes the default branch: du(path, False) returns the wrapped filesystem's absolute paths instead of paths relative to the DirFileSystem root, and find(path, None, False, True) drops the detail mapping and returns a plain list. Both fail silently, with a result that looks well formed. Bind each flag from kwargs first and from *args second, so the two call styles agree. _find and glob are left alone: neither accepts these flags positionally in the base class.
|
Or we could enforce kwarg-only? |
Review feedback on fsspec#2181: reading the value out of *args by a hardcoded index goes silently wrong if a parameter is ever inserted before it in AbstractFileSystem, so state the parameters the wrapper needs and let Python bind them. du and find now carry the same signature as the base, which keeps positional calls working (the behaviour the PR set out to fix) and drops the _bind helper. The dirfs tests passed ARGS = ["foo", "bar"] through these two methods as opaque filler and asserted it arrived untouched; those values never matched a real parameter, so they now pass the actual arguments and assert on those.
|
Good instinct on the index: I measured kwarg-only before going the other way, because it does have a real cost here:
So That did mean touching the 12 tests, and it is worth saying why they were failing. They passed Full suite is green. Happy to switch to kwarg-only instead if you would rather have the stricter API and accept the divergence from the base, it is a small change from here. |
|
OK, then I suggest dropping this PR completely. It's the caller's responsibility to pass the right arguments - it's not typical in python to thoroughly check inputs anyway. |
|
Happy to close it. One thing first, in case it did not come across in the diff, because checking inputs is not what this changes. The caller here is passing the right arguments. >>> dirfs = DirFileSystem(path="/root", fs=mem)
>>> dirfs.du("", False)
{'/root/a.txt': 5, '/root/sub/b.txt': 10}
>>> dirfs.du("", total=False)
{'a.txt': 5, 'sub/b.txt': 10}The root prefix leaks out of the wrapper on a correct call, with nothing raised. So nothing is being validated and no input is rejected. The wrapper misreads one of its own arguments and hands back a different answer than the caller asked for, which is the part I was trying to fix. Your call either way. Say the word and I will close it. |
|
Yes, I understood what it does, but it amounts to the same pattern. Correcting for the args order is like checking argument types, and brittle to changes, as you saw. |
|
Fair enough, closing. One note for the record: the version I pushed does not correct for argument order. It states the parameters and lets Python bind them, which is what That said, your point about drift is real: a mirrored signature can fall out of step with the base, and judging that cost is yours to make. Thanks for the quick turnarounds today. |
The
du,_duandfindwrappers inDirFileSystemforward*argsuntouched to the wrapped filesystem, but read the flag they need for post-processing fromkwargsalone:In the base signatures
totalis the first positional parameter afterpath(AbstractFileSystem.du(path, total=True, maxdepth=None, withdirs=False, **kwargs)) anddetailis the fourth (AbstractFileSystem.find(path, maxdepth=None, withdirs=False, detail=False, **kwargs)). A caller who passes them positionally never reacheskwargs, so the wrapper takes its default branch and skips the conversion:Both fail silently, returning a well formed result that is wrong: the first leaks paths outside the directory the
DirFileSystemis meant to scope to, which the class docstring states it assumes everything is relative to.This binds each flag from
kwargsfirst and from*argssecond, so the two call styles agree._findandglobare left alone on purpose: neither accepts these flags positionally in the base class, so reading them fromkwargsthere is correct.Two tests are added, each asserting that the positional call and the keyword call return the same thing.