Skip to content

Commit 576b1a1

Browse files
author
Martin Durant
committed
Put files under target directory if it exists
1 parent 06d1c7c commit 576b1a1

File tree

5 files changed

+26
-4
lines changed

5 files changed

+26
-4
lines changed

fsspec/asyn.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,9 @@ async def _put(
378378
lpath = make_path_posix(lpath)
379379
fs = LocalFileSystem()
380380
lpaths = fs.expand_path(lpath, recursive=recursive)
381-
rpaths = other_paths(lpaths, rpath)
381+
rpaths = other_paths(
382+
lpaths, rpath, exists=isinstance(rpath, str) and await self._isdir(rpath)
383+
)
382384

383385
is_dir = {l: os.path.isdir(l) for l in lpaths}
384386
rdirs = [r for l, r in zip(lpaths, rpaths) if is_dir[l]]

fsspec/implementations/tests/test_memory.py

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
import pytest
24

35

@@ -19,6 +21,17 @@ def test_strip(m):
1921
assert m._strip_protocol("/b/c/") == "/b/c"
2022

2123

24+
def test_put_single(m, tmpdir):
25+
fn = os.path.join(str(tmpdir), "dir")
26+
os.mkdir(fn)
27+
open(os.path.join(fn, "abc"), "w").write("text")
28+
m.put(fn, "/test") # no-op, no files
29+
assert not m.exists("/test/abc")
30+
assert not m.exists("/test/dir")
31+
m.put(fn + "/", "/test", recursive=True)
32+
assert m.cat("/test/dir/abc") == b"text"
33+
34+
2235
def test_ls(m):
2336
m.mkdir("/dir")
2437
m.mkdir("/dir/dir1")

fsspec/spec.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,9 @@ def put(self, lpath, rpath, recursive=False, callback=_DEFAULT_CALLBACK, **kwarg
802802
lpath = make_path_posix(lpath)
803803
fs = LocalFileSystem()
804804
lpaths = fs.expand_path(lpath, recursive=recursive)
805-
rpaths = other_paths(lpaths, rpath)
805+
rpaths = other_paths(
806+
lpaths, rpath, exists=isinstance(rpath, str) and self.isdir(rpath)
807+
)
806808

807809
callback.set_size(len(rpaths))
808810
for lpath, rpath in callback.wrap(zip(lpaths, rpaths)):

fsspec/tests/test_spec.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ def imitate_transfer(size, chunk, *, file=True):
462462
if file:
463463
# The reason that there is a relative_update(0) at the
464464
# end is that, we don't have an early exit on the
465-
# impleementations of get_file/put_file so it needs to
465+
# implementations of get_file/put_file so it needs to
466466
# go through the callback to get catch by the while's
467467
# condition and then it will stop the transfer.
468468
events.append(("relative_update", 0))

fsspec/utils.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ def common_prefix(paths):
334334
return "/".join(parts[0][:i])
335335

336336

337-
def other_paths(paths, path2, is_dir=None):
337+
def other_paths(paths, path2, is_dir=None, exists=False):
338338
"""In bulk file operations, construct a new file tree from a list of files
339339
340340
Parameters
@@ -348,6 +348,9 @@ def other_paths(paths, path2, is_dir=None):
348348
For the special case where the input in one element, whether to regard the value
349349
as the target path, or as a directory to put a file path within. If None, a
350350
directory is inferred if the path ends in '/'
351+
exists: bool (optional)
352+
For a str destination, it is already exists (and is a dir), files should
353+
end up inside.
351354
352355
Returns
353356
-------
@@ -358,6 +361,8 @@ def other_paths(paths, path2, is_dir=None):
358361
path2 = path2.rstrip("/")
359362
if len(paths) > 1:
360363
cp = common_prefix(paths)
364+
if exists:
365+
cp = cp.rsplit("/", 1)[0]
361366
path2 = [p.replace(cp, path2, 1) for p in paths]
362367
else:
363368
if is_dir:

0 commit comments

Comments
 (0)