diff --git a/dvc/remote/base.py b/dvc/remote/base.py index f9bd7ef76..30ec6ed6b 100644 --- a/dvc/remote/base.py +++ b/dvc/remote/base.py @@ -515,9 +515,7 @@ class RemoteBASE(object): no_progress_bar=no_progress_bar, ) except Exception: - msg = "failed to upload '{}' to '{}'" - logger.exception(msg.format(from_info, to_info)) - return 1 # 1 fail + return 1, from_info, to_info, "upload" # 1 fail return 0 @@ -555,9 +553,7 @@ class RemoteBASE(object): from_info, tmp_file, name=name, no_progress_bar=no_progress_bar ) except Exception: - msg = "failed to download '{}' to '{}'" - logger.exception(msg.format(from_info, to_info)) - return 1 # 1 fail + return 1, from_info, to_info, "download" # 1 fail move(tmp_file, to_info, mode=file_mode) diff --git a/dvc/remote/local.py b/dvc/remote/local.py index dff433756..f9cdb5cdf 100644 --- a/dvc/remote/local.py +++ b/dvc/remote/local.py @@ -358,11 +358,24 @@ class RemoteLOCAL(RemoteBASE): if len(plans[0]) == 0: return 0 + fails = 0 + msgs = "" if jobs > 1: with TqdmThreadPoolExecutor(max_workers=jobs) as executor: - fails = sum(executor.map(func, *plans)) + failures = executor.map(func, *plans) else: - fails = sum(map(func, *plans)) + failures = list(map(func, *plans)) + + for it in failures: + if not isinstance(it, tuple): + continue + fails += it[0] + from_info, to_info = it[1], it[2] + operation = it[3] + msgs += f"Failed to {operation} '{from_info}' to '{to_info}'\n" + + if msgs: + logger.exception(msgs) if fails: if download: