diff --git a/dvc/remote/s3.py b/dvc/remote/s3.py index e471af617..2f006135c 100644 --- a/dvc/remote/s3.py +++ b/dvc/remote/s3.py @@ -207,17 +207,24 @@ class RemoteS3(RemoteBASE): def list_cache_paths(self): return self._list_paths(self.path_info) + def isfile(self, path_info): + if path_info.path.endswith("/"): + return False + + try: + self.get_head_object(self.s3, path_info.bucket, path_info.path) + except DvcException: + return False + + return True + def exists(self, path_info): - dir_path = path_info / "" + """Check if the blob exists. If it does not exist, + it could be a part of a directory path. - if self.isdir(dir_path): - return True - - for fname in self._list_paths(path_info): - if path_info.path == fname: - return True - - return False + eg: if `data/file.txt` exists, check for `data` should return True + """ + return True if self.isfile(path_info) else self.isdir(path_info) def makedirs(self, path_info): # We need to support creating empty directories, which means diff --git a/tests/unit/remote/test_s3.py b/tests/unit/remote/test_s3.py index 1d188b84c..bb0abe594 100644 --- a/tests/unit/remote/test_s3.py +++ b/tests/unit/remote/test_s3.py @@ -118,3 +118,23 @@ def test_makedirs(remote): assert not remote.exists(empty_dir) remote.makedirs(empty_dir) assert remote.exists(empty_dir) + + +def test_isfile(remote): + test_cases = [ + (False, "empty_dir/"), + (True, "empty_file"), + (True, "foo"), + (True, "data/alice"), + (True, "data/alpha"), + (True, "data/subdir/1"), + (True, "data/subdir/2"), + (True, "data/subdir/3"), + (False, "data/subdir/empty_dir/"), + (False, "data/subdir/1/"), + (False, "something-that-does-not-exist"), + (False, "empty_dir"), + ] + + for expected, path in test_cases: + assert remote.isfile(remote.path_info / path) == expected