|
1 | 1 | """Base Command class, and related routines"""
|
2 | 2 |
|
| 3 | +import functools |
3 | 4 | import logging
|
4 | 5 | import logging.config
|
5 | 6 | import optparse
|
6 | 7 | import os
|
7 | 8 | import sys
|
8 | 9 | import traceback
|
9 | 10 | from optparse import Values
|
10 |
| -from typing import Any, List, Optional, Tuple |
| 11 | +from typing import Any, Callable, List, Optional, Tuple |
11 | 12 |
|
12 | 13 | from pip._internal.cli import cmdoptions
|
13 | 14 | from pip._internal.cli.command_context import CommandContextMixIn
|
@@ -176,46 +177,60 @@ def _main(self, args):
|
176 | 177 | "This will become an error in pip 21.0."
|
177 | 178 | )
|
178 | 179 |
|
| 180 | + def intercepts_unhandled_exc(run_func): |
| 181 | + # type: (Callable[..., int]) -> Callable[..., int] |
| 182 | + @functools.wraps(run_func) |
| 183 | + def exc_logging_wrapper(*args): |
| 184 | + # type: (*Any) -> int |
| 185 | + try: |
| 186 | + status = run_func(*args) |
| 187 | + assert isinstance(status, int) |
| 188 | + return status |
| 189 | + except PreviousBuildDirError as exc: |
| 190 | + logger.critical(str(exc)) |
| 191 | + logger.debug("Exception information:", exc_info=True) |
| 192 | + |
| 193 | + return PREVIOUS_BUILD_DIR_ERROR |
| 194 | + except ( |
| 195 | + InstallationError, |
| 196 | + UninstallationError, |
| 197 | + BadCommand, |
| 198 | + NetworkConnectionError, |
| 199 | + ) as exc: |
| 200 | + logger.critical(str(exc)) |
| 201 | + logger.debug("Exception information:", exc_info=True) |
| 202 | + |
| 203 | + return ERROR |
| 204 | + except CommandError as exc: |
| 205 | + logger.critical("%s", exc) |
| 206 | + logger.debug("Exception information:", exc_info=True) |
| 207 | + |
| 208 | + return ERROR |
| 209 | + except BrokenStdoutLoggingError: |
| 210 | + # Bypass our logger and write any remaining messages to |
| 211 | + # stderr because stdout no longer works. |
| 212 | + print("ERROR: Pipe to stdout was broken", file=sys.stderr) |
| 213 | + if level_number <= logging.DEBUG: |
| 214 | + traceback.print_exc(file=sys.stderr) |
| 215 | + |
| 216 | + return ERROR |
| 217 | + except KeyboardInterrupt: |
| 218 | + logger.critical("Operation cancelled by user") |
| 219 | + logger.debug("Exception information:", exc_info=True) |
| 220 | + |
| 221 | + return ERROR |
| 222 | + except BaseException: |
| 223 | + logger.critical("Exception:", exc_info=True) |
| 224 | + |
| 225 | + return UNKNOWN_ERROR |
| 226 | + |
| 227 | + return exc_logging_wrapper |
| 228 | + |
179 | 229 | try:
|
180 |
| - status = self.run(options, args) |
181 |
| - assert isinstance(status, int) |
182 |
| - return status |
183 |
| - except PreviousBuildDirError as exc: |
184 |
| - logger.critical(str(exc)) |
185 |
| - logger.debug("Exception information:", exc_info=True) |
186 |
| - |
187 |
| - return PREVIOUS_BUILD_DIR_ERROR |
188 |
| - except ( |
189 |
| - InstallationError, |
190 |
| - UninstallationError, |
191 |
| - BadCommand, |
192 |
| - NetworkConnectionError, |
193 |
| - ) as exc: |
194 |
| - logger.critical(str(exc)) |
195 |
| - logger.debug("Exception information:", exc_info=True) |
196 |
| - |
197 |
| - return ERROR |
198 |
| - except CommandError as exc: |
199 |
| - logger.critical("%s", exc) |
200 |
| - logger.debug("Exception information:", exc_info=True) |
201 |
| - |
202 |
| - return ERROR |
203 |
| - except BrokenStdoutLoggingError: |
204 |
| - # Bypass our logger and write any remaining messages to stderr |
205 |
| - # because stdout no longer works. |
206 |
| - print("ERROR: Pipe to stdout was broken", file=sys.stderr) |
207 |
| - if level_number <= logging.DEBUG: |
208 |
| - traceback.print_exc(file=sys.stderr) |
209 |
| - |
210 |
| - return ERROR |
211 |
| - except KeyboardInterrupt: |
212 |
| - logger.critical("Operation cancelled by user") |
213 |
| - logger.debug("Exception information:", exc_info=True) |
214 |
| - |
215 |
| - return ERROR |
216 |
| - except BaseException: |
217 |
| - logger.critical("Exception:", exc_info=True) |
218 |
| - |
219 |
| - return UNKNOWN_ERROR |
| 230 | + if not options.debug_mode: |
| 231 | + run = intercepts_unhandled_exc(self.run) |
| 232 | + else: |
| 233 | + run = self.run |
| 234 | + return run(options, args) |
220 | 235 | finally:
|
221 | 236 | self.handle_pip_version_check(options)
|
0 commit comments