We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Handle KeyboardInterrupt gracefully
Currently, when you send a `SIGINT` to a running instance of DVC, it doesn't terminate properly.

```bash
dvc run 'sleep 999s'
# Ctrl+C
#   or
# pkill -INT dvc
```

Error:
```
Traceback (most recent call last):
  File "/home/mroutis/src/iterative/dvc/.venv/bin/dvc", line 11, in <module>
    load_entry_point('dvc', 'console_scripts', 'dvc')()
  File "/home/mroutis/src/iterative/dvc/dvc/main.py", line 22, in main
    ret = cmd.run_cmd()
  File "/home/mroutis/src/iterative/dvc/dvc/command/base.py", line 41, in run_cmd
    return self.run()
  File "/home/mroutis/src/iterative/dvc/dvc/command/run.py", line 34, in run
    no_exec=self.args.no_exec)
  File "/home/mroutis/src/iterative/dvc/dvc/project.py", line 355, in run
    stage.run()
  File "/home/mroutis/src/iterative/dvc/dvc/stage.py", line 488, in run
    self._run()
  File "/home/mroutis/src/iterative/dvc/dvc/stage.py", line 460, in _run
    p.communicate()
  File "/usr/lib/python3.7/subprocess.py", line 925, in communicate
    self.wait()
  File "/usr/lib/python3.7/subprocess.py", line 984, in wait
    return self._wait(timeout=timeout)
  File "/usr/lib/python3.7/subprocess.py", line 1618, in _wait
    (pid, sts) = self._try_wait(0)
  File "/usr/lib/python3.7/subprocess.py", line 1576, in _try_wait
    (pid, sts) = os.waitpid(self.pid, wait_flags)
KeyboardInterrupt
```



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dvc/logger.py`
Content:
```
1 import sys
2 import logging
3 import colorama
4 import traceback
5 import re
6 
7 
8 colorama.init()
9 
10 
11 def visual_width(line):
12     """ Get the the number of columns required to display a string """
13 
14     return len(re.sub(colorama.ansitowin32.AnsiToWin32.ANSI_CSI_RE, '', line))
15 
16 
17 def visual_center(line, width):
18     """ Center align string according to it's visual width """
19 
20     spaces = max(width - visual_width(line), 0)
21     left_padding = int(spaces / 2)
22     right_padding = (spaces - left_padding)
23 
24     return (left_padding * ' ') + line + (right_padding * ' ')
25 
26 
27 class Logger(object):
28     FMT = '%(message)s'
29     DEFAULT_LEVEL = logging.INFO
30 
31     LEVEL_MAP = {
32         'debug': logging.DEBUG,
33         'info': logging.INFO,
34         'warn': logging.WARNING,
35         'error': logging.ERROR
36     }
37 
38     COLOR_MAP = {
39         'green': colorama.Fore.GREEN,
40         'yellow': colorama.Fore.YELLOW,
41         'blue': colorama.Fore.BLUE,
42         'red': colorama.Fore.RED,
43     }
44 
45     LEVEL_COLOR_MAP = {
46         'debug': 'blue',
47         'warn': 'yellow',
48         'error': 'red',
49     }
50 
51     def __init__(self, loglevel=None):
52         if loglevel:
53             Logger.set_level(loglevel)
54 
55     @staticmethod
56     def init():
57 
58         class LogLevelFilter(logging.Filter):
59             def filter(self, record):
60                 return record.levelno <= logging.WARNING
61 
62         sh_out = logging.StreamHandler(sys.stdout)
63         sh_out.setFormatter(logging.Formatter(Logger.FMT))
64         sh_out.setLevel(logging.DEBUG)
65         sh_out.addFilter(LogLevelFilter())
66 
67         sh_err = logging.StreamHandler(sys.stderr)
68         sh_err.setFormatter(logging.Formatter(Logger.FMT))
69         sh_err.setLevel(logging.ERROR)
70 
71         Logger.logger().addHandler(sh_out)
72         Logger.logger().addHandler(sh_err)
73         Logger.set_level()
74 
75     @staticmethod
76     def logger():
77         return logging.getLogger('dvc')
78 
79     @staticmethod
80     def set_level(level=None):
81         if not level:
82             lvl = Logger.DEFAULT_LEVEL
83         else:
84             lvl = Logger.LEVEL_MAP.get(level.lower(), Logger.DEFAULT_LEVEL)
85         Logger.logger().setLevel(lvl)
86 
87     @staticmethod
88     def be_quiet():
89         Logger.logger().setLevel(logging.CRITICAL)
90 
91     @staticmethod
92     def be_verbose():
93         Logger.logger().setLevel(logging.DEBUG)
94 
95     @staticmethod
96     def colorize(msg, color):
97         header = ''
98         footer = ''
99 
100         if sys.stdout.isatty():  # pragma: no cover
101             header = Logger.COLOR_MAP.get(color.lower(), '')
102             footer = colorama.Style.RESET_ALL
103 
104         return u'{}{}{}'.format(header, msg, footer)
105 
106     @staticmethod
107     def parse_exc(exc, tb=None):
108         str_tb = tb if tb else None
109         str_exc = ': {}'.format(str(exc)) if exc else ""
110 
111         if exc and hasattr(exc, 'cause') and exc.cause:
112             cause_tb = exc.cause_tb if hasattr(exc, 'cause_tb') else None
113             cause_str_exc, cause_str_tb = Logger.parse_exc(exc.cause, cause_tb)
114 
115             str_tb = cause_str_tb
116             str_exc = '{}{}'.format(str_exc, cause_str_exc)
117 
118         return (str_exc, str_tb)
119 
120     @staticmethod
121     def _prefix(msg, typ):
122         color = Logger.LEVEL_COLOR_MAP.get(typ.lower(), '')
123         return Logger.colorize('{}: '.format(msg), color)
124 
125     @staticmethod
126     def error_prefix():
127         return Logger._prefix('Error', 'error')
128 
129     @staticmethod
130     def warning_prefix():
131         return Logger._prefix('Warning', 'warn')
132 
133     @staticmethod
134     def debug_prefix():
135         return Logger._prefix('Debug', 'debug')
136 
137     @staticmethod
138     def _with_progress(func, msg):
139         from dvc.progress import progress
140         with progress:
141             func(msg)
142 
143     @staticmethod
144     def _error_exc(exc):
145         if exc is None:
146             return
147 
148         if Logger.logger().getEffectiveLevel() != logging.DEBUG:
149             return
150 
151         prefix = Logger.error_prefix()
152         str_exc, str_tb = Logger.parse_exc(exc)
153         str_tb = str_tb if str_tb else traceback.format_exc()
154         Logger._with_progress(Logger.logger().error, prefix + str_tb)
155 
156     @staticmethod
157     def _with_exc(func, msg, suffix="", exc=None):
158         Logger._error_exc(exc)
159         msg = msg + Logger.parse_exc(exc)[0] + suffix
160         Logger._with_progress(func, msg)
161 
162     @staticmethod
163     def error(msg, exc=None):
164         chat = "\n\nHaving any troubles? Hit us up at dvc.org/support, " \
165                "we are always happy to help!"
166         Logger._with_exc(Logger.logger().error,
167                          Logger.error_prefix() + msg,
168                          suffix=chat,
169                          exc=exc)
170 
171     @classmethod
172     def warn(cls, msg, exc=None):
173         cls._with_exc(cls.logger().warning,
174                       cls.warning_prefix() + msg,
175                       exc=exc)
176 
177     @classmethod
178     def debug(cls, msg, exc=None):
179         cls._with_exc(cls.logger().debug,
180                       cls.debug_prefix() + msg,
181                       exc=exc)
182 
183     @staticmethod
184     def info(msg):
185         Logger._with_progress(Logger.logger().info, msg)
186 
187     @staticmethod
188     def is_quiet():
189         return Logger.logger().level == logging.CRITICAL
190 
191     @classmethod
192     def box(cls, msg, border_color=''):
193         if cls.is_quiet():
194             return
195 
196         lines = msg.split('\n')
197         max_width = max(visual_width(line) for line in lines)
198 
199         padding_horizontal = 5
200         padding_vertical = 1
201 
202         box_size_horizontal = (max_width + (padding_horizontal * 2))
203 
204         chars = {
205             'corner':     '+',
206             'horizontal': '-',
207             'vertical':   '|',
208             'empty':      ' ',
209         }
210 
211         margin = "{corner}{line}{corner}\n".format(
212             corner=chars['corner'],
213             line=chars['horizontal'] * box_size_horizontal,
214         )
215 
216         padding_lines = [
217             "{border}{space}{border}\n".format(
218                 border=cls.colorize(chars['vertical'], border_color),
219                 space=chars['empty'] * box_size_horizontal,
220             ) * padding_vertical
221         ]
222 
223         content_lines = [
224             "{border}{space}{content}{space}{border}\n".format(
225                 border=cls.colorize(chars['vertical'], border_color),
226                 space=chars['empty'] * padding_horizontal,
227                 content=visual_center(line, max_width),
228             ) for line in lines
229         ]
230 
231         box = "{margin}{padding}{content}{padding}{margin}".format(
232                 margin=cls.colorize(margin, border_color),
233                 padding=''.join(padding_lines),
234                 content=''.join(content_lines),
235             )
236 
237         print(box)
238
```

Path: `dvc/main.py`
Content:
```
1 from dvc.logger import Logger
2 from dvc.cli import parse_args
3 from dvc.command.base import CmdBase
4 from dvc.analytics import Analytics
5 from dvc.exceptions import NotDvcProjectError, DvcParserError
6 
7 
8 def main(argv=None):
9     Logger.init()
10 
11     args = None
12     cmd = None
13     try:
14         args = parse_args(argv)
15 
16         # Init loglevel early in case we'll run
17         # into errors before setting it properly
18         CmdBase._set_loglevel(args)
19 
20         cmd = args.func(args)
21 
22         ret = cmd.run_cmd()
23     except NotDvcProjectError as ex:
24         Logger.error(str(ex))
25         ret = 253
26     except DvcParserError:
27         ret = 254
28     except Exception as ex:
29         Logger.error('Unexpected error', ex)
30         ret = 255
31 
32     Analytics().send_cmd(cmd, args, ret)
33 
34     return ret
35
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/dvc/logger.py b/dvc/logger.py
--- a/dvc/logger.py
+++ b/dvc/logger.py
@@ -106,21 +106,26 @@
     @staticmethod
     def parse_exc(exc, tb=None):
         str_tb = tb if tb else None
-        str_exc = ': {}'.format(str(exc)) if exc else ""
+        str_exc = str(exc) if exc else ""
+        l_str_exc = []
+
+        if len(str_exc) != 0:
+            l_str_exc.append(str_exc)
 
         if exc and hasattr(exc, 'cause') and exc.cause:
             cause_tb = exc.cause_tb if hasattr(exc, 'cause_tb') else None
-            cause_str_exc, cause_str_tb = Logger.parse_exc(exc.cause, cause_tb)
+            l_cause_str_exc, cause_str_tb = Logger.parse_exc(exc.cause,
+                                                             cause_tb)
 
             str_tb = cause_str_tb
-            str_exc = '{}{}'.format(str_exc, cause_str_exc)
+            l_str_exc += l_cause_str_exc
 
-        return (str_exc, str_tb)
+        return (l_str_exc, str_tb)
 
     @staticmethod
     def _prefix(msg, typ):
         color = Logger.LEVEL_COLOR_MAP.get(typ.lower(), '')
-        return Logger.colorize('{}: '.format(msg), color)
+        return Logger.colorize('{}'.format(msg), color)
 
     @staticmethod
     def error_prefix():
@@ -141,43 +146,42 @@
             func(msg)
 
     @staticmethod
-    def _error_exc(exc):
-        if exc is None:
-            return
+    def _with_exc(func, prefix, msg, suffix="", exc=None):
+        l_str_exc, str_tb = Logger.parse_exc(exc)
 
-        if Logger.logger().getEffectiveLevel() != logging.DEBUG:
-            return
+        if exc is not None and Logger.is_verbose():
+            str_tb = str_tb if str_tb else traceback.format_exc()
+            Logger._with_progress(Logger.logger().error, str_tb)
 
-        prefix = Logger.error_prefix()
-        str_exc, str_tb = Logger.parse_exc(exc)
-        str_tb = str_tb if str_tb else traceback.format_exc()
-        Logger._with_progress(Logger.logger().error, prefix + str_tb)
+        l_msg = [prefix]
+        if msg is not None and len(msg) != 0:
+            l_msg.append(msg)
+        l_msg += l_str_exc
 
-    @staticmethod
-    def _with_exc(func, msg, suffix="", exc=None):
-        Logger._error_exc(exc)
-        msg = msg + Logger.parse_exc(exc)[0] + suffix
-        Logger._with_progress(func, msg)
+        Logger._with_progress(func, ': '.join(l_msg) + suffix)
 
     @staticmethod
     def error(msg, exc=None):
         chat = "\n\nHaving any troubles? Hit us up at dvc.org/support, " \
                "we are always happy to help!"
         Logger._with_exc(Logger.logger().error,
-                         Logger.error_prefix() + msg,
+                         Logger.error_prefix(),
+                         msg,
                          suffix=chat,
                          exc=exc)
 
     @classmethod
     def warn(cls, msg, exc=None):
         cls._with_exc(cls.logger().warning,
-                      cls.warning_prefix() + msg,
+                      cls.warning_prefix(),
+                      msg,
                       exc=exc)
 
     @classmethod
     def debug(cls, msg, exc=None):
         cls._with_exc(cls.logger().debug,
-                      cls.debug_prefix() + msg,
+                      cls.debug_prefix(),
+                      msg,
                       exc=exc)
 
     @staticmethod
@@ -188,6 +192,10 @@
     def is_quiet():
         return Logger.logger().level == logging.CRITICAL
 
+    @staticmethod
+    def is_verbose():
+        return Logger.logger().getEffectiveLevel() == logging.DEBUG
+
     @classmethod
     def box(cls, msg, border_color=''):
         if cls.is_quiet():
diff --git a/dvc/main.py b/dvc/main.py
--- a/dvc/main.py
+++ b/dvc/main.py
@@ -20,8 +20,11 @@
         cmd = args.func(args)
 
         ret = cmd.run_cmd()
+    except KeyboardInterrupt as ex:
+        Logger.error("Interrupted by the user", ex)
+        ret = 252
     except NotDvcProjectError as ex:
-        Logger.error(str(ex))
+        Logger.error("", ex)
         ret = 253
     except DvcParserError:
         ret = 254

{"golden_diff": "diff --git a/dvc/logger.py b/dvc/logger.py\n--- a/dvc/logger.py\n+++ b/dvc/logger.py\n@@ -106,21 +106,26 @@\n     @staticmethod\n     def parse_exc(exc, tb=None):\n         str_tb = tb if tb else None\n-        str_exc = ': {}'.format(str(exc)) if exc else \"\"\n+        str_exc = str(exc) if exc else \"\"\n+        l_str_exc = []\n+\n+        if len(str_exc) != 0:\n+            l_str_exc.append(str_exc)\n \n         if exc and hasattr(exc, 'cause') and exc.cause:\n             cause_tb = exc.cause_tb if hasattr(exc, 'cause_tb') else None\n-            cause_str_exc, cause_str_tb = Logger.parse_exc(exc.cause, cause_tb)\n+            l_cause_str_exc, cause_str_tb = Logger.parse_exc(exc.cause,\n+                                                             cause_tb)\n \n             str_tb = cause_str_tb\n-            str_exc = '{}{}'.format(str_exc, cause_str_exc)\n+            l_str_exc += l_cause_str_exc\n \n-        return (str_exc, str_tb)\n+        return (l_str_exc, str_tb)\n \n     @staticmethod\n     def _prefix(msg, typ):\n         color = Logger.LEVEL_COLOR_MAP.get(typ.lower(), '')\n-        return Logger.colorize('{}: '.format(msg), color)\n+        return Logger.colorize('{}'.format(msg), color)\n \n     @staticmethod\n     def error_prefix():\n@@ -141,43 +146,42 @@\n             func(msg)\n \n     @staticmethod\n-    def _error_exc(exc):\n-        if exc is None:\n-            return\n+    def _with_exc(func, prefix, msg, suffix=\"\", exc=None):\n+        l_str_exc, str_tb = Logger.parse_exc(exc)\n \n-        if Logger.logger().getEffectiveLevel() != logging.DEBUG:\n-            return\n+        if exc is not None and Logger.is_verbose():\n+            str_tb = str_tb if str_tb else traceback.format_exc()\n+            Logger._with_progress(Logger.logger().error, str_tb)\n \n-        prefix = Logger.error_prefix()\n-        str_exc, str_tb = Logger.parse_exc(exc)\n-        str_tb = str_tb if str_tb else traceback.format_exc()\n-        Logger._with_progress(Logger.logger().error, prefix + str_tb)\n+        l_msg = [prefix]\n+        if msg is not None and len(msg) != 0:\n+            l_msg.append(msg)\n+        l_msg += l_str_exc\n \n-    @staticmethod\n-    def _with_exc(func, msg, suffix=\"\", exc=None):\n-        Logger._error_exc(exc)\n-        msg = msg + Logger.parse_exc(exc)[0] + suffix\n-        Logger._with_progress(func, msg)\n+        Logger._with_progress(func, ': '.join(l_msg) + suffix)\n \n     @staticmethod\n     def error(msg, exc=None):\n         chat = \"\\n\\nHaving any troubles? Hit us up at dvc.org/support, \" \\\n                \"we are always happy to help!\"\n         Logger._with_exc(Logger.logger().error,\n-                         Logger.error_prefix() + msg,\n+                         Logger.error_prefix(),\n+                         msg,\n                          suffix=chat,\n                          exc=exc)\n \n     @classmethod\n     def warn(cls, msg, exc=None):\n         cls._with_exc(cls.logger().warning,\n-                      cls.warning_prefix() + msg,\n+                      cls.warning_prefix(),\n+                      msg,\n                       exc=exc)\n \n     @classmethod\n     def debug(cls, msg, exc=None):\n         cls._with_exc(cls.logger().debug,\n-                      cls.debug_prefix() + msg,\n+                      cls.debug_prefix(),\n+                      msg,\n                       exc=exc)\n \n     @staticmethod\n@@ -188,6 +192,10 @@\n     def is_quiet():\n         return Logger.logger().level == logging.CRITICAL\n \n+    @staticmethod\n+    def is_verbose():\n+        return Logger.logger().getEffectiveLevel() == logging.DEBUG\n+\n     @classmethod\n     def box(cls, msg, border_color=''):\n         if cls.is_quiet():\ndiff --git a/dvc/main.py b/dvc/main.py\n--- a/dvc/main.py\n+++ b/dvc/main.py\n@@ -20,8 +20,11 @@\n         cmd = args.func(args)\n \n         ret = cmd.run_cmd()\n+    except KeyboardInterrupt as ex:\n+        Logger.error(\"Interrupted by the user\", ex)\n+        ret = 252\n     except NotDvcProjectError as ex:\n-        Logger.error(str(ex))\n+        Logger.error(\"\", ex)\n         ret = 253\n     except DvcParserError:\n         ret = 254\n", "issue": "Handle KeyboardInterrupt gracefully\nCurrently, when you send a `SIGINT` to a running instance of DVC, it doesn't terminate properly.\r\n\r\n```bash\r\ndvc run 'sleep 999s'\r\n# Ctrl+C\r\n#   or\r\n# pkill -INT dvc\r\n```\r\n\r\nError:\r\n```\r\nTraceback (most recent call last):\r\n  File \"/home/mroutis/src/iterative/dvc/.venv/bin/dvc\", line 11, in <module>\r\n    load_entry_point('dvc', 'console_scripts', 'dvc')()\r\n  File \"/home/mroutis/src/iterative/dvc/dvc/main.py\", line 22, in main\r\n    ret = cmd.run_cmd()\r\n  File \"/home/mroutis/src/iterative/dvc/dvc/command/base.py\", line 41, in run_cmd\r\n    return self.run()\r\n  File \"/home/mroutis/src/iterative/dvc/dvc/command/run.py\", line 34, in run\r\n    no_exec=self.args.no_exec)\r\n  File \"/home/mroutis/src/iterative/dvc/dvc/project.py\", line 355, in run\r\n    stage.run()\r\n  File \"/home/mroutis/src/iterative/dvc/dvc/stage.py\", line 488, in run\r\n    self._run()\r\n  File \"/home/mroutis/src/iterative/dvc/dvc/stage.py\", line 460, in _run\r\n    p.communicate()\r\n  File \"/usr/lib/python3.7/subprocess.py\", line 925, in communicate\r\n    self.wait()\r\n  File \"/usr/lib/python3.7/subprocess.py\", line 984, in wait\r\n    return self._wait(timeout=timeout)\r\n  File \"/usr/lib/python3.7/subprocess.py\", line 1618, in _wait\r\n    (pid, sts) = self._try_wait(0)\r\n  File \"/usr/lib/python3.7/subprocess.py\", line 1576, in _try_wait\r\n    (pid, sts) = os.waitpid(self.pid, wait_flags)\r\nKeyboardInterrupt\r\n```\r\n\r\n\n", "before_files": [{"content": "import sys\nimport logging\nimport colorama\nimport traceback\nimport re\n\n\ncolorama.init()\n\n\ndef visual_width(line):\n    \"\"\" Get the the number of columns required to display a string \"\"\"\n\n    return len(re.sub(colorama.ansitowin32.AnsiToWin32.ANSI_CSI_RE, '', line))\n\n\ndef visual_center(line, width):\n    \"\"\" Center align string according to it's visual width \"\"\"\n\n    spaces = max(width - visual_width(line), 0)\n    left_padding = int(spaces / 2)\n    right_padding = (spaces - left_padding)\n\n    return (left_padding * ' ') + line + (right_padding * ' ')\n\n\nclass Logger(object):\n    FMT = '%(message)s'\n    DEFAULT_LEVEL = logging.INFO\n\n    LEVEL_MAP = {\n        'debug': logging.DEBUG,\n        'info': logging.INFO,\n        'warn': logging.WARNING,\n        'error': logging.ERROR\n    }\n\n    COLOR_MAP = {\n        'green': colorama.Fore.GREEN,\n        'yellow': colorama.Fore.YELLOW,\n        'blue': colorama.Fore.BLUE,\n        'red': colorama.Fore.RED,\n    }\n\n    LEVEL_COLOR_MAP = {\n        'debug': 'blue',\n        'warn': 'yellow',\n        'error': 'red',\n    }\n\n    def __init__(self, loglevel=None):\n        if loglevel:\n            Logger.set_level(loglevel)\n\n    @staticmethod\n    def init():\n\n        class LogLevelFilter(logging.Filter):\n            def filter(self, record):\n                return record.levelno <= logging.WARNING\n\n        sh_out = logging.StreamHandler(sys.stdout)\n        sh_out.setFormatter(logging.Formatter(Logger.FMT))\n        sh_out.setLevel(logging.DEBUG)\n        sh_out.addFilter(LogLevelFilter())\n\n        sh_err = logging.StreamHandler(sys.stderr)\n        sh_err.setFormatter(logging.Formatter(Logger.FMT))\n        sh_err.setLevel(logging.ERROR)\n\n        Logger.logger().addHandler(sh_out)\n        Logger.logger().addHandler(sh_err)\n        Logger.set_level()\n\n    @staticmethod\n    def logger():\n        return logging.getLogger('dvc')\n\n    @staticmethod\n    def set_level(level=None):\n        if not level:\n            lvl = Logger.DEFAULT_LEVEL\n        else:\n            lvl = Logger.LEVEL_MAP.get(level.lower(), Logger.DEFAULT_LEVEL)\n        Logger.logger().setLevel(lvl)\n\n    @staticmethod\n    def be_quiet():\n        Logger.logger().setLevel(logging.CRITICAL)\n\n    @staticmethod\n    def be_verbose():\n        Logger.logger().setLevel(logging.DEBUG)\n\n    @staticmethod\n    def colorize(msg, color):\n        header = ''\n        footer = ''\n\n        if sys.stdout.isatty():  # pragma: no cover\n            header = Logger.COLOR_MAP.get(color.lower(), '')\n            footer = colorama.Style.RESET_ALL\n\n        return u'{}{}{}'.format(header, msg, footer)\n\n    @staticmethod\n    def parse_exc(exc, tb=None):\n        str_tb = tb if tb else None\n        str_exc = ': {}'.format(str(exc)) if exc else \"\"\n\n        if exc and hasattr(exc, 'cause') and exc.cause:\n            cause_tb = exc.cause_tb if hasattr(exc, 'cause_tb') else None\n            cause_str_exc, cause_str_tb = Logger.parse_exc(exc.cause, cause_tb)\n\n            str_tb = cause_str_tb\n            str_exc = '{}{}'.format(str_exc, cause_str_exc)\n\n        return (str_exc, str_tb)\n\n    @staticmethod\n    def _prefix(msg, typ):\n        color = Logger.LEVEL_COLOR_MAP.get(typ.lower(), '')\n        return Logger.colorize('{}: '.format(msg), color)\n\n    @staticmethod\n    def error_prefix():\n        return Logger._prefix('Error', 'error')\n\n    @staticmethod\n    def warning_prefix():\n        return Logger._prefix('Warning', 'warn')\n\n    @staticmethod\n    def debug_prefix():\n        return Logger._prefix('Debug', 'debug')\n\n    @staticmethod\n    def _with_progress(func, msg):\n        from dvc.progress import progress\n        with progress:\n            func(msg)\n\n    @staticmethod\n    def _error_exc(exc):\n        if exc is None:\n            return\n\n        if Logger.logger().getEffectiveLevel() != logging.DEBUG:\n            return\n\n        prefix = Logger.error_prefix()\n        str_exc, str_tb = Logger.parse_exc(exc)\n        str_tb = str_tb if str_tb else traceback.format_exc()\n        Logger._with_progress(Logger.logger().error, prefix + str_tb)\n\n    @staticmethod\n    def _with_exc(func, msg, suffix=\"\", exc=None):\n        Logger._error_exc(exc)\n        msg = msg + Logger.parse_exc(exc)[0] + suffix\n        Logger._with_progress(func, msg)\n\n    @staticmethod\n    def error(msg, exc=None):\n        chat = \"\\n\\nHaving any troubles? Hit us up at dvc.org/support, \" \\\n               \"we are always happy to help!\"\n        Logger._with_exc(Logger.logger().error,\n                         Logger.error_prefix() + msg,\n                         suffix=chat,\n                         exc=exc)\n\n    @classmethod\n    def warn(cls, msg, exc=None):\n        cls._with_exc(cls.logger().warning,\n                      cls.warning_prefix() + msg,\n                      exc=exc)\n\n    @classmethod\n    def debug(cls, msg, exc=None):\n        cls._with_exc(cls.logger().debug,\n                      cls.debug_prefix() + msg,\n                      exc=exc)\n\n    @staticmethod\n    def info(msg):\n        Logger._with_progress(Logger.logger().info, msg)\n\n    @staticmethod\n    def is_quiet():\n        return Logger.logger().level == logging.CRITICAL\n\n    @classmethod\n    def box(cls, msg, border_color=''):\n        if cls.is_quiet():\n            return\n\n        lines = msg.split('\\n')\n        max_width = max(visual_width(line) for line in lines)\n\n        padding_horizontal = 5\n        padding_vertical = 1\n\n        box_size_horizontal = (max_width + (padding_horizontal * 2))\n\n        chars = {\n            'corner':     '+',\n            'horizontal': '-',\n            'vertical':   '|',\n            'empty':      ' ',\n        }\n\n        margin = \"{corner}{line}{corner}\\n\".format(\n            corner=chars['corner'],\n            line=chars['horizontal'] * box_size_horizontal,\n        )\n\n        padding_lines = [\n            \"{border}{space}{border}\\n\".format(\n                border=cls.colorize(chars['vertical'], border_color),\n                space=chars['empty'] * box_size_horizontal,\n            ) * padding_vertical\n        ]\n\n        content_lines = [\n            \"{border}{space}{content}{space}{border}\\n\".format(\n                border=cls.colorize(chars['vertical'], border_color),\n                space=chars['empty'] * padding_horizontal,\n                content=visual_center(line, max_width),\n            ) for line in lines\n        ]\n\n        box = \"{margin}{padding}{content}{padding}{margin}\".format(\n                margin=cls.colorize(margin, border_color),\n                padding=''.join(padding_lines),\n                content=''.join(content_lines),\n            )\n\n        print(box)\n", "path": "dvc/logger.py"}, {"content": "from dvc.logger import Logger\nfrom dvc.cli import parse_args\nfrom dvc.command.base import CmdBase\nfrom dvc.analytics import Analytics\nfrom dvc.exceptions import NotDvcProjectError, DvcParserError\n\n\ndef main(argv=None):\n    Logger.init()\n\n    args = None\n    cmd = None\n    try:\n        args = parse_args(argv)\n\n        # Init loglevel early in case we'll run\n        # into errors before setting it properly\n        CmdBase._set_loglevel(args)\n\n        cmd = args.func(args)\n\n        ret = cmd.run_cmd()\n    except NotDvcProjectError as ex:\n        Logger.error(str(ex))\n        ret = 253\n    except DvcParserError:\n        ret = 254\n    except Exception as ex:\n        Logger.error('Unexpected error', ex)\n        ret = 255\n\n    Analytics().send_cmd(cmd, args, ret)\n\n    return ret\n", "path": "dvc/main.py"}], "after_files": [{"content": "import sys\nimport logging\nimport colorama\nimport traceback\nimport re\n\n\ncolorama.init()\n\n\ndef visual_width(line):\n    \"\"\" Get the the number of columns required to display a string \"\"\"\n\n    return len(re.sub(colorama.ansitowin32.AnsiToWin32.ANSI_CSI_RE, '', line))\n\n\ndef visual_center(line, width):\n    \"\"\" Center align string according to it's visual width \"\"\"\n\n    spaces = max(width - visual_width(line), 0)\n    left_padding = int(spaces / 2)\n    right_padding = (spaces - left_padding)\n\n    return (left_padding * ' ') + line + (right_padding * ' ')\n\n\nclass Logger(object):\n    FMT = '%(message)s'\n    DEFAULT_LEVEL = logging.INFO\n\n    LEVEL_MAP = {\n        'debug': logging.DEBUG,\n        'info': logging.INFO,\n        'warn': logging.WARNING,\n        'error': logging.ERROR\n    }\n\n    COLOR_MAP = {\n        'green': colorama.Fore.GREEN,\n        'yellow': colorama.Fore.YELLOW,\n        'blue': colorama.Fore.BLUE,\n        'red': colorama.Fore.RED,\n    }\n\n    LEVEL_COLOR_MAP = {\n        'debug': 'blue',\n        'warn': 'yellow',\n        'error': 'red',\n    }\n\n    def __init__(self, loglevel=None):\n        if loglevel:\n            Logger.set_level(loglevel)\n\n    @staticmethod\n    def init():\n\n        class LogLevelFilter(logging.Filter):\n            def filter(self, record):\n                return record.levelno <= logging.WARNING\n\n        sh_out = logging.StreamHandler(sys.stdout)\n        sh_out.setFormatter(logging.Formatter(Logger.FMT))\n        sh_out.setLevel(logging.DEBUG)\n        sh_out.addFilter(LogLevelFilter())\n\n        sh_err = logging.StreamHandler(sys.stderr)\n        sh_err.setFormatter(logging.Formatter(Logger.FMT))\n        sh_err.setLevel(logging.ERROR)\n\n        Logger.logger().addHandler(sh_out)\n        Logger.logger().addHandler(sh_err)\n        Logger.set_level()\n\n    @staticmethod\n    def logger():\n        return logging.getLogger('dvc')\n\n    @staticmethod\n    def set_level(level=None):\n        if not level:\n            lvl = Logger.DEFAULT_LEVEL\n        else:\n            lvl = Logger.LEVEL_MAP.get(level.lower(), Logger.DEFAULT_LEVEL)\n        Logger.logger().setLevel(lvl)\n\n    @staticmethod\n    def be_quiet():\n        Logger.logger().setLevel(logging.CRITICAL)\n\n    @staticmethod\n    def be_verbose():\n        Logger.logger().setLevel(logging.DEBUG)\n\n    @staticmethod\n    def colorize(msg, color):\n        header = ''\n        footer = ''\n\n        if sys.stdout.isatty():  # pragma: no cover\n            header = Logger.COLOR_MAP.get(color.lower(), '')\n            footer = colorama.Style.RESET_ALL\n\n        return u'{}{}{}'.format(header, msg, footer)\n\n    @staticmethod\n    def parse_exc(exc, tb=None):\n        str_tb = tb if tb else None\n        str_exc = str(exc) if exc else \"\"\n        l_str_exc = []\n\n        if len(str_exc) != 0:\n            l_str_exc.append(str_exc)\n\n        if exc and hasattr(exc, 'cause') and exc.cause:\n            cause_tb = exc.cause_tb if hasattr(exc, 'cause_tb') else None\n            l_cause_str_exc, cause_str_tb = Logger.parse_exc(exc.cause,\n                                                             cause_tb)\n\n            str_tb = cause_str_tb\n            l_str_exc += l_cause_str_exc\n\n        return (l_str_exc, str_tb)\n\n    @staticmethod\n    def _prefix(msg, typ):\n        color = Logger.LEVEL_COLOR_MAP.get(typ.lower(), '')\n        return Logger.colorize('{}'.format(msg), color)\n\n    @staticmethod\n    def error_prefix():\n        return Logger._prefix('Error', 'error')\n\n    @staticmethod\n    def warning_prefix():\n        return Logger._prefix('Warning', 'warn')\n\n    @staticmethod\n    def debug_prefix():\n        return Logger._prefix('Debug', 'debug')\n\n    @staticmethod\n    def _with_progress(func, msg):\n        from dvc.progress import progress\n        with progress:\n            func(msg)\n\n    @staticmethod\n    def _with_exc(func, prefix, msg, suffix=\"\", exc=None):\n        l_str_exc, str_tb = Logger.parse_exc(exc)\n\n        if exc is not None and Logger.is_verbose():\n            str_tb = str_tb if str_tb else traceback.format_exc()\n            Logger._with_progress(Logger.logger().error, str_tb)\n\n        l_msg = [prefix]\n        if msg is not None and len(msg) != 0:\n            l_msg.append(msg)\n        l_msg += l_str_exc\n\n        Logger._with_progress(func, ': '.join(l_msg) + suffix)\n\n    @staticmethod\n    def error(msg, exc=None):\n        chat = \"\\n\\nHaving any troubles? Hit us up at dvc.org/support, \" \\\n               \"we are always happy to help!\"\n        Logger._with_exc(Logger.logger().error,\n                         Logger.error_prefix(),\n                         msg,\n                         suffix=chat,\n                         exc=exc)\n\n    @classmethod\n    def warn(cls, msg, exc=None):\n        cls._with_exc(cls.logger().warning,\n                      cls.warning_prefix(),\n                      msg,\n                      exc=exc)\n\n    @classmethod\n    def debug(cls, msg, exc=None):\n        cls._with_exc(cls.logger().debug,\n                      cls.debug_prefix(),\n                      msg,\n                      exc=exc)\n\n    @staticmethod\n    def info(msg):\n        Logger._with_progress(Logger.logger().info, msg)\n\n    @staticmethod\n    def is_quiet():\n        return Logger.logger().level == logging.CRITICAL\n\n    @staticmethod\n    def is_verbose():\n        return Logger.logger().getEffectiveLevel() == logging.DEBUG\n\n    @classmethod\n    def box(cls, msg, border_color=''):\n        if cls.is_quiet():\n            return\n\n        lines = msg.split('\\n')\n        max_width = max(visual_width(line) for line in lines)\n\n        padding_horizontal = 5\n        padding_vertical = 1\n\n        box_size_horizontal = (max_width + (padding_horizontal * 2))\n\n        chars = {\n            'corner':     '+',\n            'horizontal': '-',\n            'vertical':   '|',\n            'empty':      ' ',\n        }\n\n        margin = \"{corner}{line}{corner}\\n\".format(\n            corner=chars['corner'],\n            line=chars['horizontal'] * box_size_horizontal,\n        )\n\n        padding_lines = [\n            \"{border}{space}{border}\\n\".format(\n                border=cls.colorize(chars['vertical'], border_color),\n                space=chars['empty'] * box_size_horizontal,\n            ) * padding_vertical\n        ]\n\n        content_lines = [\n            \"{border}{space}{content}{space}{border}\\n\".format(\n                border=cls.colorize(chars['vertical'], border_color),\n                space=chars['empty'] * padding_horizontal,\n                content=visual_center(line, max_width),\n            ) for line in lines\n        ]\n\n        box = \"{margin}{padding}{content}{padding}{margin}\".format(\n                margin=cls.colorize(margin, border_color),\n                padding=''.join(padding_lines),\n                content=''.join(content_lines),\n            )\n\n        print(box)\n", "path": "dvc/logger.py"}, {"content": "from dvc.logger import Logger\nfrom dvc.cli import parse_args\nfrom dvc.command.base import CmdBase\nfrom dvc.analytics import Analytics\nfrom dvc.exceptions import NotDvcProjectError, DvcParserError\n\n\ndef main(argv=None):\n    Logger.init()\n\n    args = None\n    cmd = None\n    try:\n        args = parse_args(argv)\n\n        # Init loglevel early in case we'll run\n        # into errors before setting it properly\n        CmdBase._set_loglevel(args)\n\n        cmd = args.func(args)\n\n        ret = cmd.run_cmd()\n    except KeyboardInterrupt as ex:\n        Logger.error(\"Interrupted by the user\", ex)\n        ret = 252\n    except NotDvcProjectError as ex:\n        Logger.error(\"\", ex)\n        ret = 253\n    except DvcParserError:\n        ret = 254\n    except Exception as ex:\n        Logger.error('Unexpected error', ex)\n        ret = 255\n\n    Analytics().send_cmd(cmd, args, ret)\n\n    return ret\n", "path": "dvc/main.py"}]}