Repository: iterative/dvc

Issue:
progress: take account interruptions
**Current**:
```
Preparing to upload data to 'ssh://root@localhost:1234/tmp/storage'
Preparing to collect status from ssh://root@localhost:1234/tmp/storage
[######### ] 30% Collecting informationEnter a private key passphrase or a password for host 'localhost' port '1234' user 'root':`
```

**Expected**:
```
Preparing to upload data to 'ssh://root@localhost:1234/tmp/storage'
Preparing to collect status from ssh://root@localhost:1234/tmp/storage
[######### ] 30% Collecting information
Enter a private key passphrase or a password for host 'localhost' port '1234' user 'root':`
```

**Related**: https://github.com/iterative/dvc/issues/1595#issuecomment-461994616


Discussion:

Resolving patch:
diff --git a/dvc/logger.py b/dvc/logger.py
--- a/dvc/logger.py
+++ b/dvc/logger.py
@@ -4,6 +4,7 @@
 
 from dvc.exceptions import DvcException
 from dvc.utils.compat import str
+from dvc.progress import progress_aware
 
 import re
 import sys
@@ -15,6 +16,7 @@
 import colorama
 
 
+@progress_aware
 def info(message):
     """Prints an info message."""
     logger.info(message)
@@ -29,6 +31,7 @@ def debug(message):
     logger.debug(out)
 
 
+@progress_aware
 def warning(message, parse_exception=False):
     """Prints a warning message."""
     prefix = colorize("Warning", color="yellow")
@@ -47,6 +50,7 @@ def warning(message, parse_exception=False):
     logger.warning(out)
 
 
+@progress_aware
 def error(message=None):
     """Prints an error message."""
     prefix = colorize("Error", color="red")
diff --git a/dvc/progress.py b/dvc/progress.py
--- a/dvc/progress.py
+++ b/dvc/progress.py
@@ -7,7 +7,6 @@
 
 import sys
 import threading
-import dvc.logger as logger
 
 
 class Progress(object):
@@ -100,6 +99,8 @@ def _bar(self, target_name, current, total):
 
     @staticmethod
     def _print(*args, **kwargs):
+        import dvc.logger as logger
+
         if logger.is_quiet():
             return
 
@@ -116,4 +117,18 @@ def __exit__(self, typ, value, tbck):
         self._lock.release()
 
 
+def progress_aware(f):
+    """ Decorator to add a new line if progress bar hasn't finished  """
+    from functools import wraps
+
+    @wraps(f)
+    def wrapper(*args, **kwargs):
+        if not progress.is_finished:
+            progress._print()
+
+        return f(*args, **kwargs)
+
+    return wrapper
+
+
 progress = Progress()  # pylint: disable=invalid-name
diff --git a/dvc/prompt.py b/dvc/prompt.py
--- a/dvc/prompt.py
+++ b/dvc/prompt.py
@@ -6,6 +6,7 @@
 import sys
 from getpass import getpass
 
+from dvc.progress import progress_aware
 from dvc.utils.compat import input
 
 
@@ -32,6 +33,7 @@ def _ask(prompt, limited_to=None):
         )
 
 
+@progress_aware
 def confirm(statement):
     """Ask the user for confirmation about the specified statement.
 
@@ -46,6 +48,7 @@ def confirm(statement):
     return answer and answer.startswith("y")
 
 
+@progress_aware
 def password(statement):
     """Ask the user for a password.
 


Test patch:
diff --git a/tests/unit/progress.py b/tests/unit/progress.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/progress.py
@@ -0,0 +1,20 @@
+import mock
+from unittest import TestCase
+
+from dvc.progress import progress, progress_aware
+
+
+class TestProgressAware(TestCase):
+    @mock.patch("sys.stdout.isatty", return_value=True)
+    @mock.patch("dvc.progress.Progress._print")
+    def test(self, mock_print, mock_isatty):
+        function = progress_aware(lambda: None)
+
+        function()
+        mock_print.assert_not_called()
+
+        progress.update_target("testing", 0, 100)
+        function()
+        mock_print.assert_called()
+
+        progress.finish_target("testing")