Skip to content

Commit d128d51

Browse files
authored
import: fix importing into subdirectory bug (#4340)
* tests: test importing into subdirectory * import: fix bug when output subdir doesnt already exist * use urlparse to determine if output path is local, not os.path.exists * account for windows drive letters * import: error out if output subdirectory does not exist
1 parent afa0a30 commit d128d51

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

dvc/utils/__init__.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,19 +363,22 @@ def resolve_output(inp, out):
363363

364364

365365
def resolve_paths(repo, out):
366+
from urllib.parse import urlparse
366367
from ..dvcfile import DVC_FILE_SUFFIX
367368
from ..path_info import PathInfo
368369
from .fs import contains_symlink_up_to
369370

370-
abspath = os.path.abspath(out)
371+
abspath = PathInfo(os.path.abspath(out))
371372
dirname = os.path.dirname(abspath)
372373
base = os.path.basename(os.path.normpath(out))
373374

374-
# NOTE: `out` might not exist yet, so using `dirname`(aka `wdir`) to check
375-
# if it is a local path.
375+
scheme = urlparse(out).scheme
376+
if os.name == "nt" and scheme == abspath.drive[0].lower():
377+
# urlparse interprets windows drive letters as URL scheme
378+
scheme = ""
376379
if (
377-
os.path.exists(dirname) # out might not exist yet, so
378-
and PathInfo(abspath).isin_or_eq(repo.root_dir)
380+
not scheme
381+
and abspath.isin_or_eq(repo.root_dir)
379382
and not contains_symlink_up_to(abspath, repo.root_dir)
380383
):
381384
wdir = dirname

tests/func/test_import.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from dvc.config import NoRemoteError
1010
from dvc.dvcfile import Dvcfile
1111
from dvc.exceptions import DownloadError, PathMissingError
12+
from dvc.stage.exceptions import StagePathNotFoundError
1213
from dvc.system import System
1314
from dvc.utils.fs import makedirs, remove
1415

@@ -132,6 +133,28 @@ def test_import_file_from_dir(tmp_dir, scm, dvc, erepo_dir):
132133
assert (tmp_dir / "X.dvc").exists()
133134

134135

136+
def test_import_file_from_dir_to_dir(tmp_dir, scm, dvc, erepo_dir):
137+
with erepo_dir.chdir():
138+
erepo_dir.dvc_gen({"dir": {"foo": "foo"}}, commit="create dir")
139+
140+
with pytest.raises(StagePathNotFoundError):
141+
dvc.imp(
142+
os.fspath(erepo_dir),
143+
os.path.join("dir", "foo"),
144+
out=os.path.join("dir", "foo"),
145+
)
146+
147+
tmp_dir.gen({"dir": {}})
148+
dvc.imp(
149+
os.fspath(erepo_dir),
150+
os.path.join("dir", "foo"),
151+
out=os.path.join("dir", "foo"),
152+
)
153+
assert not (tmp_dir / "foo.dvc").exists()
154+
assert (tmp_dir / "dir" / "foo").read_text() == "foo"
155+
assert (tmp_dir / "dir" / "foo.dvc").exists()
156+
157+
135158
def test_import_non_cached(erepo_dir, tmp_dir, dvc, scm):
136159
src = "non_cached_output"
137160
dst = src + "_imported"

0 commit comments

Comments
 (0)