We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Multiple calls to `pip.main()` produce duplicate output
For example:

```
>>> import pip
>>> pip.main(['install'])
You must give at least one requirement to install (see "pip help install")
0
>>> pip.main(['install'])
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
0
>>> pip.main(['install'])
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
0
>>> pip.main(['install'])
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
0
>>> pip.main(['install'])
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
You must give at least one requirement to install (see "pip help install")
0
```

Pip version: pip 1.6.dev1


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pip/log.py`
Content:
```
1 """Logging
2 """
3 
4 import sys
5 import os
6 import logging
7 
8 from pip._vendor import colorama, pkg_resources
9 
10 
11 def _color_wrap(*colors):
12     def wrapped(inp):
13         return "".join(list(colors) + [inp, colorama.Style.RESET_ALL])
14     return wrapped
15 
16 
17 def should_color(consumer, environ, std=(sys.stdout, sys.stderr)):
18     real_consumer = (
19         consumer if not isinstance(consumer, colorama.AnsiToWin32)
20         else consumer.wrapped
21     )
22 
23     # If consumer isn't stdout or stderr we shouldn't colorize it
24     if real_consumer not in std:
25         return False
26 
27     # If consumer is a tty we should color it
28     if hasattr(real_consumer, "isatty") and real_consumer.isatty():
29         return True
30 
31     # If we have an ASNI term we should color it
32     if environ.get("TERM") == "ANSI":
33         return True
34 
35     # If anything else we should not color it
36     return False
37 
38 
39 def should_warn(current_version, removal_version):
40     # Our Significant digits on versions is 2, so remove everything but the
41     #   first two places.
42     current_version = ".".join(current_version.split(".")[:2])
43     removal_version = ".".join(removal_version.split(".")[:2])
44 
45     # Our warning threshold is one minor version before removal, so we
46     #   decrement the minor version by one
47     major, minor = removal_version.split(".")
48     minor = str(int(minor) - 1)
49     warn_version = ".".join([major, minor])
50 
51     # Test if our current_version should be a warn
52     return (pkg_resources.parse_version(current_version)
53             < pkg_resources.parse_version(warn_version))
54 
55 
56 class Logger(object):
57     """
58     Logging object for use in command-line script.  Allows ranges of
59     levels, to avoid some redundancy of displayed information.
60     """
61     VERBOSE_DEBUG = logging.DEBUG - 1
62     DEBUG = logging.DEBUG
63     INFO = logging.INFO
64     NOTIFY = (logging.INFO + logging.WARN) / 2
65     WARN = WARNING = logging.WARN
66     ERROR = logging.ERROR
67     FATAL = logging.FATAL
68 
69     LEVELS = [VERBOSE_DEBUG, DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
70 
71     COLORS = {
72         WARN: _color_wrap(colorama.Fore.YELLOW),
73         ERROR: _color_wrap(colorama.Fore.RED),
74         FATAL: _color_wrap(colorama.Fore.RED),
75     }
76 
77     def __init__(self):
78         self.consumers = []
79         self.indent = 0
80         self.explicit_levels = False
81         self.in_progress = None
82         self.in_progress_hanging = False
83 
84     def add_consumers(self, *consumers):
85         if sys.platform.startswith("win"):
86             for level, consumer in consumers:
87                 if hasattr(consumer, "write"):
88                     self.consumers.append(
89                         (level, colorama.AnsiToWin32(consumer)),
90                     )
91                 else:
92                     self.consumers.append((level, consumer))
93         else:
94             self.consumers.extend(consumers)
95 
96     def debug(self, msg, *args, **kw):
97         self.log(self.DEBUG, msg, *args, **kw)
98 
99     def info(self, msg, *args, **kw):
100         self.log(self.INFO, msg, *args, **kw)
101 
102     def notify(self, msg, *args, **kw):
103         self.log(self.NOTIFY, msg, *args, **kw)
104 
105     def warn(self, msg, *args, **kw):
106         self.log(self.WARN, msg, *args, **kw)
107 
108     def error(self, msg, *args, **kw):
109         self.log(self.ERROR, msg, *args, **kw)
110 
111     def fatal(self, msg, *args, **kw):
112         self.log(self.FATAL, msg, *args, **kw)
113 
114     def deprecated(self, removal_version, msg, *args, **kwargs):
115         """
116         Logs deprecation message which is log level WARN if the
117         ``removal_version`` is > 1 minor release away and log level ERROR
118         otherwise.
119 
120         removal_version should be the version that the deprecated feature is
121         expected to be removed in, so something that will not exist in
122         version 1.7, but will in 1.6 would have a removal_version of 1.7.
123         """
124         from pip import __version__
125 
126         if should_warn(__version__, removal_version):
127             self.warn(msg, *args, **kwargs)
128         else:
129             self.error(msg, *args, **kwargs)
130 
131     def log(self, level, msg, *args, **kw):
132         if args:
133             if kw:
134                 raise TypeError(
135                     "You may give positional or keyword arguments, not both")
136         args = args or kw
137 
138         # render
139         if args:
140             rendered = msg % args
141         else:
142             rendered = msg
143         rendered = ' ' * self.indent + rendered
144         if self.explicit_levels:
145             # FIXME: should this be a name, not a level number?
146             rendered = '%02i %s' % (level, rendered)
147 
148         for consumer_level, consumer in self.consumers:
149             if self.level_matches(level, consumer_level):
150                 if (self.in_progress_hanging
151                         and consumer in (sys.stdout, sys.stderr)):
152                     self.in_progress_hanging = False
153                     sys.stdout.write('\n')
154                     sys.stdout.flush()
155                 if hasattr(consumer, 'write'):
156                     write_content = rendered + '\n'
157                     if should_color(consumer, os.environ):
158                         # We are printing to stdout or stderr and it supports
159                         #   colors so render our text colored
160                         colorizer = self.COLORS.get(level, lambda x: x)
161                         write_content = colorizer(write_content)
162 
163                     consumer.write(write_content)
164                     if hasattr(consumer, 'flush'):
165                         consumer.flush()
166                 else:
167                     consumer(rendered)
168 
169     def _show_progress(self):
170         """Should we display download progress?"""
171         return (self.stdout_level_matches(self.NOTIFY) and sys.stdout.isatty())
172 
173     def start_progress(self, msg):
174         assert not self.in_progress, (
175             "Tried to start_progress(%r) while in_progress %r"
176             % (msg, self.in_progress))
177         if self._show_progress():
178             sys.stdout.write(' ' * self.indent + msg)
179             sys.stdout.flush()
180             self.in_progress_hanging = True
181         else:
182             self.in_progress_hanging = False
183         self.in_progress = msg
184         self.last_message = None
185 
186     def end_progress(self, msg='done.'):
187         assert self.in_progress, (
188             "Tried to end_progress without start_progress")
189         if self._show_progress():
190             if not self.in_progress_hanging:
191                 # Some message has been printed out since start_progress
192                 sys.stdout.write('...' + self.in_progress + msg + '\n')
193                 sys.stdout.flush()
194             else:
195                 # These erase any messages shown with show_progress
196                 # (besides .'s)
197                 logger.show_progress('')
198                 logger.show_progress('')
199                 sys.stdout.write(msg + '\n')
200                 sys.stdout.flush()
201         self.in_progress = None
202         self.in_progress_hanging = False
203 
204     def show_progress(self, message=None):
205         """If we are in a progress scope, and no log messages have been
206         shown, write out another '.'"""
207         if self.in_progress_hanging:
208             if message is None:
209                 sys.stdout.write('.')
210                 sys.stdout.flush()
211             else:
212                 if self.last_message:
213                     padding = ' ' * max(
214                         0,
215                         len(self.last_message) - len(message)
216                     )
217                 else:
218                     padding = ''
219                 sys.stdout.write(
220                     '\r%s%s%s%s' %
221                     (' ' * self.indent, self.in_progress, message, padding)
222                 )
223                 sys.stdout.flush()
224                 self.last_message = message
225 
226     def stdout_level_matches(self, level):
227         """Returns true if a message at this level will go to stdout"""
228         return self.level_matches(level, self._stdout_level())
229 
230     def _stdout_level(self):
231         """Returns the level that stdout runs at"""
232         for level, consumer in self.consumers:
233             if consumer is sys.stdout:
234                 return level
235         return self.FATAL
236 
237     def level_matches(self, level, consumer_level):
238         """
239         >>> l = Logger()
240         >>> l.level_matches(3, 4)
241         False
242         >>> l.level_matches(3, 2)
243         True
244         >>> l.level_matches(slice(None, 3), 3)
245         False
246         >>> l.level_matches(slice(None, 3), 2)
247         True
248         >>> l.level_matches(slice(1, 3), 1)
249         True
250         >>> l.level_matches(slice(2, 3), 1)
251         False
252         """
253         if isinstance(level, slice):
254             start, stop = level.start, level.stop
255             if start is not None and start > consumer_level:
256                 return False
257             if stop is not None or stop <= consumer_level:
258                 return False
259             return True
260         else:
261             return level >= consumer_level
262 
263     @classmethod
264     def level_for_integer(cls, level):
265         levels = cls.LEVELS
266         if level < 0:
267             return levels[0]
268         if level >= len(levels):
269             return levels[-1]
270         return levels[level]
271 
272     def move_stdout_to_stderr(self):
273         to_remove = []
274         to_add = []
275         for consumer_level, consumer in self.consumers:
276             if consumer == sys.stdout:
277                 to_remove.append((consumer_level, consumer))
278                 to_add.append((consumer_level, sys.stderr))
279         for item in to_remove:
280             self.consumers.remove(item)
281         self.consumers.extend(to_add)
282 
283 logger = Logger()
284
```
--- 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/pip/log.py b/pip/log.py
--- a/pip/log.py
+++ b/pip/log.py
@@ -82,16 +82,23 @@
         self.in_progress_hanging = False
 
     def add_consumers(self, *consumers):
-        if sys.platform.startswith("win"):
-            for level, consumer in consumers:
-                if hasattr(consumer, "write"):
-                    self.consumers.append(
-                        (level, colorama.AnsiToWin32(consumer)),
-                    )
-                else:
-                    self.consumers.append((level, consumer))
-        else:
-            self.consumers.extend(consumers)
+        for level, consumer in consumers:
+            # Try to check for duplicate consumers before adding them
+            for chk_level, chk_consumer in self.consumers:
+                # Account for coloroma wrapped streams
+                if isinstance(chk_consumer, colorama.AnsiToWin32):
+                    chk_consumer = chk_consumer.wrapped
+
+                if (level, consumer) == (chk_level, chk_consumer):
+                    break
+            # If we didn't find a duplicate, then add it
+            else:
+                # Colorize consumer for Windows
+                if sys.platform.startswith('win') \
+                   and hasattr(consumer, 'write'):
+                    consumer = colorama.AnsiToWin32(consumer)
+
+                self.consumers.append((level, consumer))
 
     def debug(self, msg, *args, **kw):
         self.log(self.DEBUG, msg, *args, **kw)

{"golden_diff": "diff --git a/pip/log.py b/pip/log.py\n--- a/pip/log.py\n+++ b/pip/log.py\n@@ -82,16 +82,23 @@\n         self.in_progress_hanging = False\n \n     def add_consumers(self, *consumers):\n-        if sys.platform.startswith(\"win\"):\n-            for level, consumer in consumers:\n-                if hasattr(consumer, \"write\"):\n-                    self.consumers.append(\n-                        (level, colorama.AnsiToWin32(consumer)),\n-                    )\n-                else:\n-                    self.consumers.append((level, consumer))\n-        else:\n-            self.consumers.extend(consumers)\n+        for level, consumer in consumers:\n+            # Try to check for duplicate consumers before adding them\n+            for chk_level, chk_consumer in self.consumers:\n+                # Account for coloroma wrapped streams\n+                if isinstance(chk_consumer, colorama.AnsiToWin32):\n+                    chk_consumer = chk_consumer.wrapped\n+\n+                if (level, consumer) == (chk_level, chk_consumer):\n+                    break\n+            # If we didn't find a duplicate, then add it\n+            else:\n+                # Colorize consumer for Windows\n+                if sys.platform.startswith('win') \\\n+                   and hasattr(consumer, 'write'):\n+                    consumer = colorama.AnsiToWin32(consumer)\n+\n+                self.consumers.append((level, consumer))\n \n     def debug(self, msg, *args, **kw):\n         self.log(self.DEBUG, msg, *args, **kw)\n", "issue": "Multiple calls to `pip.main()` produce duplicate output\nFor example:\n\n```\n>>> import pip\n>>> pip.main(['install'])\nYou must give at least one requirement to install (see \"pip help install\")\n0\n>>> pip.main(['install'])\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\n0\n>>> pip.main(['install'])\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\n0\n>>> pip.main(['install'])\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\n0\n>>> pip.main(['install'])\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\nYou must give at least one requirement to install (see \"pip help install\")\n0\n```\n\nPip version: pip 1.6.dev1\n\n", "before_files": [{"content": "\"\"\"Logging\n\"\"\"\n\nimport sys\nimport os\nimport logging\n\nfrom pip._vendor import colorama, pkg_resources\n\n\ndef _color_wrap(*colors):\n    def wrapped(inp):\n        return \"\".join(list(colors) + [inp, colorama.Style.RESET_ALL])\n    return wrapped\n\n\ndef should_color(consumer, environ, std=(sys.stdout, sys.stderr)):\n    real_consumer = (\n        consumer if not isinstance(consumer, colorama.AnsiToWin32)\n        else consumer.wrapped\n    )\n\n    # If consumer isn't stdout or stderr we shouldn't colorize it\n    if real_consumer not in std:\n        return False\n\n    # If consumer is a tty we should color it\n    if hasattr(real_consumer, \"isatty\") and real_consumer.isatty():\n        return True\n\n    # If we have an ASNI term we should color it\n    if environ.get(\"TERM\") == \"ANSI\":\n        return True\n\n    # If anything else we should not color it\n    return False\n\n\ndef should_warn(current_version, removal_version):\n    # Our Significant digits on versions is 2, so remove everything but the\n    #   first two places.\n    current_version = \".\".join(current_version.split(\".\")[:2])\n    removal_version = \".\".join(removal_version.split(\".\")[:2])\n\n    # Our warning threshold is one minor version before removal, so we\n    #   decrement the minor version by one\n    major, minor = removal_version.split(\".\")\n    minor = str(int(minor) - 1)\n    warn_version = \".\".join([major, minor])\n\n    # Test if our current_version should be a warn\n    return (pkg_resources.parse_version(current_version)\n            < pkg_resources.parse_version(warn_version))\n\n\nclass Logger(object):\n    \"\"\"\n    Logging object for use in command-line script.  Allows ranges of\n    levels, to avoid some redundancy of displayed information.\n    \"\"\"\n    VERBOSE_DEBUG = logging.DEBUG - 1\n    DEBUG = logging.DEBUG\n    INFO = logging.INFO\n    NOTIFY = (logging.INFO + logging.WARN) / 2\n    WARN = WARNING = logging.WARN\n    ERROR = logging.ERROR\n    FATAL = logging.FATAL\n\n    LEVELS = [VERBOSE_DEBUG, DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]\n\n    COLORS = {\n        WARN: _color_wrap(colorama.Fore.YELLOW),\n        ERROR: _color_wrap(colorama.Fore.RED),\n        FATAL: _color_wrap(colorama.Fore.RED),\n    }\n\n    def __init__(self):\n        self.consumers = []\n        self.indent = 0\n        self.explicit_levels = False\n        self.in_progress = None\n        self.in_progress_hanging = False\n\n    def add_consumers(self, *consumers):\n        if sys.platform.startswith(\"win\"):\n            for level, consumer in consumers:\n                if hasattr(consumer, \"write\"):\n                    self.consumers.append(\n                        (level, colorama.AnsiToWin32(consumer)),\n                    )\n                else:\n                    self.consumers.append((level, consumer))\n        else:\n            self.consumers.extend(consumers)\n\n    def debug(self, msg, *args, **kw):\n        self.log(self.DEBUG, msg, *args, **kw)\n\n    def info(self, msg, *args, **kw):\n        self.log(self.INFO, msg, *args, **kw)\n\n    def notify(self, msg, *args, **kw):\n        self.log(self.NOTIFY, msg, *args, **kw)\n\n    def warn(self, msg, *args, **kw):\n        self.log(self.WARN, msg, *args, **kw)\n\n    def error(self, msg, *args, **kw):\n        self.log(self.ERROR, msg, *args, **kw)\n\n    def fatal(self, msg, *args, **kw):\n        self.log(self.FATAL, msg, *args, **kw)\n\n    def deprecated(self, removal_version, msg, *args, **kwargs):\n        \"\"\"\n        Logs deprecation message which is log level WARN if the\n        ``removal_version`` is > 1 minor release away and log level ERROR\n        otherwise.\n\n        removal_version should be the version that the deprecated feature is\n        expected to be removed in, so something that will not exist in\n        version 1.7, but will in 1.6 would have a removal_version of 1.7.\n        \"\"\"\n        from pip import __version__\n\n        if should_warn(__version__, removal_version):\n            self.warn(msg, *args, **kwargs)\n        else:\n            self.error(msg, *args, **kwargs)\n\n    def log(self, level, msg, *args, **kw):\n        if args:\n            if kw:\n                raise TypeError(\n                    \"You may give positional or keyword arguments, not both\")\n        args = args or kw\n\n        # render\n        if args:\n            rendered = msg % args\n        else:\n            rendered = msg\n        rendered = ' ' * self.indent + rendered\n        if self.explicit_levels:\n            # FIXME: should this be a name, not a level number?\n            rendered = '%02i %s' % (level, rendered)\n\n        for consumer_level, consumer in self.consumers:\n            if self.level_matches(level, consumer_level):\n                if (self.in_progress_hanging\n                        and consumer in (sys.stdout, sys.stderr)):\n                    self.in_progress_hanging = False\n                    sys.stdout.write('\\n')\n                    sys.stdout.flush()\n                if hasattr(consumer, 'write'):\n                    write_content = rendered + '\\n'\n                    if should_color(consumer, os.environ):\n                        # We are printing to stdout or stderr and it supports\n                        #   colors so render our text colored\n                        colorizer = self.COLORS.get(level, lambda x: x)\n                        write_content = colorizer(write_content)\n\n                    consumer.write(write_content)\n                    if hasattr(consumer, 'flush'):\n                        consumer.flush()\n                else:\n                    consumer(rendered)\n\n    def _show_progress(self):\n        \"\"\"Should we display download progress?\"\"\"\n        return (self.stdout_level_matches(self.NOTIFY) and sys.stdout.isatty())\n\n    def start_progress(self, msg):\n        assert not self.in_progress, (\n            \"Tried to start_progress(%r) while in_progress %r\"\n            % (msg, self.in_progress))\n        if self._show_progress():\n            sys.stdout.write(' ' * self.indent + msg)\n            sys.stdout.flush()\n            self.in_progress_hanging = True\n        else:\n            self.in_progress_hanging = False\n        self.in_progress = msg\n        self.last_message = None\n\n    def end_progress(self, msg='done.'):\n        assert self.in_progress, (\n            \"Tried to end_progress without start_progress\")\n        if self._show_progress():\n            if not self.in_progress_hanging:\n                # Some message has been printed out since start_progress\n                sys.stdout.write('...' + self.in_progress + msg + '\\n')\n                sys.stdout.flush()\n            else:\n                # These erase any messages shown with show_progress\n                # (besides .'s)\n                logger.show_progress('')\n                logger.show_progress('')\n                sys.stdout.write(msg + '\\n')\n                sys.stdout.flush()\n        self.in_progress = None\n        self.in_progress_hanging = False\n\n    def show_progress(self, message=None):\n        \"\"\"If we are in a progress scope, and no log messages have been\n        shown, write out another '.'\"\"\"\n        if self.in_progress_hanging:\n            if message is None:\n                sys.stdout.write('.')\n                sys.stdout.flush()\n            else:\n                if self.last_message:\n                    padding = ' ' * max(\n                        0,\n                        len(self.last_message) - len(message)\n                    )\n                else:\n                    padding = ''\n                sys.stdout.write(\n                    '\\r%s%s%s%s' %\n                    (' ' * self.indent, self.in_progress, message, padding)\n                )\n                sys.stdout.flush()\n                self.last_message = message\n\n    def stdout_level_matches(self, level):\n        \"\"\"Returns true if a message at this level will go to stdout\"\"\"\n        return self.level_matches(level, self._stdout_level())\n\n    def _stdout_level(self):\n        \"\"\"Returns the level that stdout runs at\"\"\"\n        for level, consumer in self.consumers:\n            if consumer is sys.stdout:\n                return level\n        return self.FATAL\n\n    def level_matches(self, level, consumer_level):\n        \"\"\"\n        >>> l = Logger()\n        >>> l.level_matches(3, 4)\n        False\n        >>> l.level_matches(3, 2)\n        True\n        >>> l.level_matches(slice(None, 3), 3)\n        False\n        >>> l.level_matches(slice(None, 3), 2)\n        True\n        >>> l.level_matches(slice(1, 3), 1)\n        True\n        >>> l.level_matches(slice(2, 3), 1)\n        False\n        \"\"\"\n        if isinstance(level, slice):\n            start, stop = level.start, level.stop\n            if start is not None and start > consumer_level:\n                return False\n            if stop is not None or stop <= consumer_level:\n                return False\n            return True\n        else:\n            return level >= consumer_level\n\n    @classmethod\n    def level_for_integer(cls, level):\n        levels = cls.LEVELS\n        if level < 0:\n            return levels[0]\n        if level >= len(levels):\n            return levels[-1]\n        return levels[level]\n\n    def move_stdout_to_stderr(self):\n        to_remove = []\n        to_add = []\n        for consumer_level, consumer in self.consumers:\n            if consumer == sys.stdout:\n                to_remove.append((consumer_level, consumer))\n                to_add.append((consumer_level, sys.stderr))\n        for item in to_remove:\n            self.consumers.remove(item)\n        self.consumers.extend(to_add)\n\nlogger = Logger()\n", "path": "pip/log.py"}], "after_files": [{"content": "\"\"\"Logging\n\"\"\"\n\nimport sys\nimport os\nimport logging\n\nfrom pip._vendor import colorama, pkg_resources\n\n\ndef _color_wrap(*colors):\n    def wrapped(inp):\n        return \"\".join(list(colors) + [inp, colorama.Style.RESET_ALL])\n    return wrapped\n\n\ndef should_color(consumer, environ, std=(sys.stdout, sys.stderr)):\n    real_consumer = (\n        consumer if not isinstance(consumer, colorama.AnsiToWin32)\n        else consumer.wrapped\n    )\n\n    # If consumer isn't stdout or stderr we shouldn't colorize it\n    if real_consumer not in std:\n        return False\n\n    # If consumer is a tty we should color it\n    if hasattr(real_consumer, \"isatty\") and real_consumer.isatty():\n        return True\n\n    # If we have an ASNI term we should color it\n    if environ.get(\"TERM\") == \"ANSI\":\n        return True\n\n    # If anything else we should not color it\n    return False\n\n\ndef should_warn(current_version, removal_version):\n    # Our Significant digits on versions is 2, so remove everything but the\n    #   first two places.\n    current_version = \".\".join(current_version.split(\".\")[:2])\n    removal_version = \".\".join(removal_version.split(\".\")[:2])\n\n    # Our warning threshold is one minor version before removal, so we\n    #   decrement the minor version by one\n    major, minor = removal_version.split(\".\")\n    minor = str(int(minor) - 1)\n    warn_version = \".\".join([major, minor])\n\n    # Test if our current_version should be a warn\n    return (pkg_resources.parse_version(current_version)\n            < pkg_resources.parse_version(warn_version))\n\n\nclass Logger(object):\n    \"\"\"\n    Logging object for use in command-line script.  Allows ranges of\n    levels, to avoid some redundancy of displayed information.\n    \"\"\"\n    VERBOSE_DEBUG = logging.DEBUG - 1\n    DEBUG = logging.DEBUG\n    INFO = logging.INFO\n    NOTIFY = (logging.INFO + logging.WARN) / 2\n    WARN = WARNING = logging.WARN\n    ERROR = logging.ERROR\n    FATAL = logging.FATAL\n\n    LEVELS = [VERBOSE_DEBUG, DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]\n\n    COLORS = {\n        WARN: _color_wrap(colorama.Fore.YELLOW),\n        ERROR: _color_wrap(colorama.Fore.RED),\n        FATAL: _color_wrap(colorama.Fore.RED),\n    }\n\n    def __init__(self):\n        self.consumers = []\n        self.indent = 0\n        self.explicit_levels = False\n        self.in_progress = None\n        self.in_progress_hanging = False\n\n    def add_consumers(self, *consumers):\n        for level, consumer in consumers:\n            # Try to check for duplicate consumers before adding them\n            for chk_level, chk_consumer in self.consumers:\n                # Account for coloroma wrapped streams\n                if isinstance(chk_consumer, colorama.AnsiToWin32):\n                    chk_consumer = chk_consumer.wrapped\n\n                if (level, consumer) == (chk_level, chk_consumer):\n                    break\n            # If we didn't find a duplicate, then add it\n            else:\n                # Colorize consumer for Windows\n                if sys.platform.startswith('win') \\\n                   and hasattr(consumer, 'write'):\n                    consumer = colorama.AnsiToWin32(consumer)\n\n                self.consumers.append((level, consumer))\n\n    def debug(self, msg, *args, **kw):\n        self.log(self.DEBUG, msg, *args, **kw)\n\n    def info(self, msg, *args, **kw):\n        self.log(self.INFO, msg, *args, **kw)\n\n    def notify(self, msg, *args, **kw):\n        self.log(self.NOTIFY, msg, *args, **kw)\n\n    def warn(self, msg, *args, **kw):\n        self.log(self.WARN, msg, *args, **kw)\n\n    def error(self, msg, *args, **kw):\n        self.log(self.ERROR, msg, *args, **kw)\n\n    def fatal(self, msg, *args, **kw):\n        self.log(self.FATAL, msg, *args, **kw)\n\n    def deprecated(self, removal_version, msg, *args, **kwargs):\n        \"\"\"\n        Logs deprecation message which is log level WARN if the\n        ``removal_version`` is > 1 minor release away and log level ERROR\n        otherwise.\n\n        removal_version should be the version that the deprecated feature is\n        expected to be removed in, so something that will not exist in\n        version 1.7, but will in 1.6 would have a removal_version of 1.7.\n        \"\"\"\n        from pip import __version__\n\n        if should_warn(__version__, removal_version):\n            self.warn(msg, *args, **kwargs)\n        else:\n            self.error(msg, *args, **kwargs)\n\n    def log(self, level, msg, *args, **kw):\n        if args:\n            if kw:\n                raise TypeError(\n                    \"You may give positional or keyword arguments, not both\")\n        args = args or kw\n\n        # render\n        if args:\n            rendered = msg % args\n        else:\n            rendered = msg\n        rendered = ' ' * self.indent + rendered\n        if self.explicit_levels:\n            # FIXME: should this be a name, not a level number?\n            rendered = '%02i %s' % (level, rendered)\n\n        for consumer_level, consumer in self.consumers:\n            if self.level_matches(level, consumer_level):\n                if (self.in_progress_hanging\n                        and consumer in (sys.stdout, sys.stderr)):\n                    self.in_progress_hanging = False\n                    sys.stdout.write('\\n')\n                    sys.stdout.flush()\n                if hasattr(consumer, 'write'):\n                    write_content = rendered + '\\n'\n                    if should_color(consumer, os.environ):\n                        # We are printing to stdout or stderr and it supports\n                        #   colors so render our text colored\n                        colorizer = self.COLORS.get(level, lambda x: x)\n                        write_content = colorizer(write_content)\n\n                    consumer.write(write_content)\n                    if hasattr(consumer, 'flush'):\n                        consumer.flush()\n                else:\n                    consumer(rendered)\n\n    def _show_progress(self):\n        \"\"\"Should we display download progress?\"\"\"\n        return (self.stdout_level_matches(self.NOTIFY) and sys.stdout.isatty())\n\n    def start_progress(self, msg):\n        assert not self.in_progress, (\n            \"Tried to start_progress(%r) while in_progress %r\"\n            % (msg, self.in_progress))\n        if self._show_progress():\n            sys.stdout.write(' ' * self.indent + msg)\n            sys.stdout.flush()\n            self.in_progress_hanging = True\n        else:\n            self.in_progress_hanging = False\n        self.in_progress = msg\n        self.last_message = None\n\n    def end_progress(self, msg='done.'):\n        assert self.in_progress, (\n            \"Tried to end_progress without start_progress\")\n        if self._show_progress():\n            if not self.in_progress_hanging:\n                # Some message has been printed out since start_progress\n                sys.stdout.write('...' + self.in_progress + msg + '\\n')\n                sys.stdout.flush()\n            else:\n                # These erase any messages shown with show_progress\n                # (besides .'s)\n                logger.show_progress('')\n                logger.show_progress('')\n                sys.stdout.write(msg + '\\n')\n                sys.stdout.flush()\n        self.in_progress = None\n        self.in_progress_hanging = False\n\n    def show_progress(self, message=None):\n        \"\"\"If we are in a progress scope, and no log messages have been\n        shown, write out another '.'\"\"\"\n        if self.in_progress_hanging:\n            if message is None:\n                sys.stdout.write('.')\n                sys.stdout.flush()\n            else:\n                if self.last_message:\n                    padding = ' ' * max(\n                        0,\n                        len(self.last_message) - len(message)\n                    )\n                else:\n                    padding = ''\n                sys.stdout.write(\n                    '\\r%s%s%s%s' %\n                    (' ' * self.indent, self.in_progress, message, padding)\n                )\n                sys.stdout.flush()\n                self.last_message = message\n\n    def stdout_level_matches(self, level):\n        \"\"\"Returns true if a message at this level will go to stdout\"\"\"\n        return self.level_matches(level, self._stdout_level())\n\n    def _stdout_level(self):\n        \"\"\"Returns the level that stdout runs at\"\"\"\n        for level, consumer in self.consumers:\n            if consumer is sys.stdout:\n                return level\n        return self.FATAL\n\n    def level_matches(self, level, consumer_level):\n        \"\"\"\n        >>> l = Logger()\n        >>> l.level_matches(3, 4)\n        False\n        >>> l.level_matches(3, 2)\n        True\n        >>> l.level_matches(slice(None, 3), 3)\n        False\n        >>> l.level_matches(slice(None, 3), 2)\n        True\n        >>> l.level_matches(slice(1, 3), 1)\n        True\n        >>> l.level_matches(slice(2, 3), 1)\n        False\n        \"\"\"\n        if isinstance(level, slice):\n            start, stop = level.start, level.stop\n            if start is not None and start > consumer_level:\n                return False\n            if stop is not None or stop <= consumer_level:\n                return False\n            return True\n        else:\n            return level >= consumer_level\n\n    @classmethod\n    def level_for_integer(cls, level):\n        levels = cls.LEVELS\n        if level < 0:\n            return levels[0]\n        if level >= len(levels):\n            return levels[-1]\n        return levels[level]\n\n    def move_stdout_to_stderr(self):\n        to_remove = []\n        to_add = []\n        for consumer_level, consumer in self.consumers:\n            if consumer == sys.stdout:\n                to_remove.append((consumer_level, consumer))\n                to_add.append((consumer_level, sys.stderr))\n        for item in to_remove:\n            self.consumers.remove(item)\n        self.consumers.extend(to_add)\n\nlogger = Logger()\n", "path": "pip/log.py"}]}