Repository: iterative/dvc

Issue:
logger: Respect `--quiet` option
Progress currently uses the `print` function basically for the `print(message, end='')` functionality;

Now, `Logger` uses the `progress` function to wrap some calls https://github.com/iterative/dvc/blob/46831ea00a51e770e3a85c0b5fffb7c99677b149/dvc/logger.py#L137-L141

So we can't use `Logger` on `Progress`, that would create a circular dependency.


Discussion:
There's another instance of Logger using `print` that will not respect the quiet output at all.

https://github.com/iterative/dvc/blob/46831ea00a51e770e3a85c0b5fffb7c99677b149/dvc/logger.py#L224-L230
It is a quite important thing. I'd not wait - "help wanted".

Resolving patch:
diff --git a/dvc/logger.py b/dvc/logger.py
--- a/dvc/logger.py
+++ b/dvc/logger.py
@@ -184,8 +184,15 @@ def debug(cls, msg, exc=None):
     def info(msg):
         Logger._with_progress(Logger.logger().info, msg)
 
+    @staticmethod
+    def is_quiet():
+        return Logger.logger().level == logging.CRITICAL
+
     @classmethod
     def box(cls, msg, border_color=''):
+        if cls.is_quiet():
+            return
+
         lines = msg.split('\n')
         max_width = max(visual_width(line) for line in lines)
 
diff --git a/dvc/progress.py b/dvc/progress.py
--- a/dvc/progress.py
+++ b/dvc/progress.py
@@ -22,11 +22,11 @@ def is_finished(self):
         return self._n_total == self._n_finished
 
     def _clearln(self):
-        print('\r\x1b[K', end='')
+        self._print('\r\x1b[K', end='')
 
     def _writeln(self, line):
         self._clearln()
-        print(line, end='')
+        self._print(line, end='')
         sys.stdout.flush()
 
     def refresh(self, line=None):
@@ -54,7 +54,7 @@ def finish_target(self, name):
             if sys.stdout.isatty():
                 self._clearln()
 
-            print(bar)
+            self._print(bar)
 
             self._n_finished += 1
             self._line = None
@@ -85,6 +85,14 @@ def _bar(self, target_name, current, total):
 
         return num + bar + percent + target_name
 
+    def _print(self, *args, **kwargs):
+        from dvc.logger import Logger
+
+        if Logger.is_quiet():
+            return
+
+        print(*args, **kwargs)
+
     def __enter__(self):
         self._lock.acquire(True)
         if self._line is not None:


Test patch:
diff --git a/tests/test_logger.py b/tests/test_logger.py
--- a/tests/test_logger.py
+++ b/tests/test_logger.py
@@ -70,6 +70,30 @@ def test_stdout(self, mock_stdout, mock_stderr):
                                    mock_stdout.getvalue())
 
 
+class TestLoggerQuiet(TestDvc):
+    def setUp(self):
+        super(TestLoggerQuiet, self).setUp()
+        class A(object):
+            quiet = True
+            verbose = False
+        CmdBase._set_loglevel(A())
+
+    @patch('sys.stderr', new_callable=StringIO)
+    @patch('sys.stdout', new_callable=StringIO)
+    def test_progress(self, mock_stdout, mock_stderr):
+        from dvc.progress import progress
+        progress.update_target('target', 50, 100)
+        self.assertEqual('', mock_stdout.getvalue())
+        self.assertEqual('', mock_stderr.getvalue())
+
+    @patch('sys.stderr', new_callable=StringIO)
+    @patch('sys.stdout', new_callable=StringIO)
+    def test_box(self, mock_stdout, mock_stderr):
+        Logger.box('message')
+        self.assertEqual('', mock_stdout.getvalue())
+        self.assertEqual('', mock_stderr.getvalue())
+
+
 class TestLoggerCLI(TestDvc):
     def test(self):
         class A(object):