def __init__(self, name: str, summary: str, isolated: bool = False) -> None: super().__init__() self.name = name self.summary = summary self.parser = ConfigOptionParser( usage=self.usage, prog=f"{get_prog()} {name}", formatter=UpdatingDefaultsHelpFormatter(), add_help_option=False, name=name, description=self.__doc__, isolated=isolated, ) self.tempdir_registry: Optional[TempDirRegistry] = None # Commands should add options to this option group optgroup_name = f"{self.name.capitalize()} Options" self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) # Add the general options gen_opts = cmdoptions.make_option_group( cmdoptions.general_group, self.parser, ) self.parser.add_option_group(gen_opts) self.add_options()
def __init__(self, name, summary, isolated=False): # type: (str, str, bool) -> None super(Command, self).__init__() parser_kw = { 'usage': self.usage, 'prog': '%s %s' % (get_prog(), name), 'formatter': UpdatingDefaultsHelpFormatter(), 'add_help_option': False, 'name': name, 'description': self.__doc__, 'isolated': isolated, } self.name = name self.summary = summary self.parser = ConfigOptionParser(**parser_kw) # Commands should add options to this option group optgroup_name = '%s Options' % self.name.capitalize() self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) # Add the general options gen_opts = cmdoptions.make_option_group( cmdoptions.general_group, self.parser, ) self.parser.add_option_group(gen_opts)
def create_main_parser() -> ConfigOptionParser: """Creates and returns the main parser for pip's CLI""" parser = ConfigOptionParser( usage="\n%prog <command> [options]", add_help_option=False, formatter=UpdatingDefaultsHelpFormatter(), name="global", prog=get_prog(), ) parser.disable_interspersed_args() parser.version = get_pip_version() # add the general options gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) parser.add_option_group(gen_opts) # so the help formatter knows parser.main = True # type: ignore # create command listing for description description = [""] + [ f"{name:27} {command_info.summary}" for name, command_info in commands_dict.items() ] parser.description = "\n".join(description) return parser
def create_main_parser(): # type: () -> ConfigOptionParser """Creates and returns the main parser for pip's CLI """ parser_kw = { 'usage': '\n%prog <command> [options]', 'add_help_option': False, 'formatter': UpdatingDefaultsHelpFormatter(), 'name': 'global', 'prog': get_prog(), } parser = ConfigOptionParser(**parser_kw) parser.disable_interspersed_args() parser.version = get_pip_version() # add the general options gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) parser.add_option_group(gen_opts) # so the help formatter knows parser.main = True # type: ignore # create command listing for description description = [''] + [ '%-27s %s' % (name, command_info.summary) for name, command_info in commands_dict.items() ] parser.description = '\n'.join(description) return parser
def create_main_parser(): # type: () -> ConfigOptionParser """Creates and returns the main parser for pip's CLI """ parser_kw = { 'usage': '\n%prog <command> [options]', 'add_help_option': False, 'formatter': UpdatingDefaultsHelpFormatter(), 'name': 'global', 'prog': get_prog(), } parser = ConfigOptionParser(**parser_kw) parser.disable_interspersed_args() pip_pkg_dir = os.path.abspath( os.path.join( os.path.dirname(__file__), "..", "..", )) parser.version = 'pip %s from %s (python %s)' % ( __version__, pip_pkg_dir, sys.version[:3], ) # add the general options gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) parser.add_option_group(gen_opts) # so the help formatter knows parser.main = True # type: ignore # create command listing for description command_summaries = get_summaries() description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries] parser.description = '\n'.join(description) return parser
class Command(CommandContextMixIn): usage = None # type: str ignore_require_venv = False # type: bool def __init__(self, name, summary, isolated=False): # type: (str, str, bool) -> None super(Command, self).__init__() parser_kw = { 'usage': self.usage, 'prog': '%s %s' % (get_prog(), name), 'formatter': UpdatingDefaultsHelpFormatter(), 'add_help_option': False, 'name': name, 'description': self.__doc__, 'isolated': isolated, } self.name = name self.summary = summary self.parser = ConfigOptionParser(**parser_kw) # Commands should add options to this option group optgroup_name = '%s Options' % self.name.capitalize() self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) # Add the general options gen_opts = cmdoptions.make_option_group( cmdoptions.general_group, self.parser, ) self.parser.add_option_group(gen_opts) def handle_pip_version_check(self, options): # type: (Values) -> None """ This is a no-op so that commands by default do not do the pip version check. """ # Make sure we do the pip version check if the index_group options # are present. assert not hasattr(options, 'no_index') def run(self, options, args): # type: (Values, List[Any]) -> Any raise NotImplementedError def parse_args(self, args): # type: (List[str]) -> Tuple # factored out for testability return self.parser.parse_args(args) def main(self, args): # type: (List[str]) -> int try: with self.main_context(): return self._main(args) finally: logging.shutdown() def _main(self, args): # type: (List[str]) -> int options, args = self.parse_args(args) # Set verbosity so that it can be used elsewhere. self.verbosity = options.verbose - options.quiet level_number = setup_logging( verbosity=self.verbosity, no_color=options.no_color, user_log_file=options.log, ) if sys.version_info[:2] == (2, 7): message = ( "A future version of pip will drop support for Python 2.7. " "More details about Python 2 support in pip, can be found at " "https://pip.pypa.io/en/latest/development/release-process/#python-2-support" # noqa ) if platform.python_implementation() == "CPython": message = ( "Python 2.7 will reach the end of its life on January " "1st, 2020. Please upgrade your Python as Python 2.7 " "won't be maintained after that date. ") + message deprecated(message, replacement=None, gone_in=None) # TODO: Try to get these passing down from the command? # without resorting to os.environ to hold these. # This also affects isolated builds and it should. if options.no_input: os.environ['PIP_NO_INPUT'] = '1' if options.exists_action: os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) if options.require_venv and not self.ignore_require_venv: # If a venv is required check if it can really be found if not running_under_virtualenv(): logger.critical( 'Could not find an activated virtualenv (required).') sys.exit(VIRTUALENV_NOT_FOUND) try: status = self.run(options, args) # FIXME: all commands should return an exit status # and when it is done, isinstance is not needed anymore if isinstance(status, int): return status except PreviousBuildDirError as exc: logger.critical(str(exc)) logger.debug('Exception information:', exc_info=True) return PREVIOUS_BUILD_DIR_ERROR except (InstallationError, UninstallationError, BadCommand) as exc: logger.critical(str(exc)) logger.debug('Exception information:', exc_info=True) return ERROR except CommandError as exc: logger.critical('%s', exc) logger.debug('Exception information:', exc_info=True) return ERROR except BrokenStdoutLoggingError: # Bypass our logger and write any remaining messages to stderr # because stdout no longer works. print('ERROR: Pipe to stdout was broken', file=sys.stderr) if level_number <= logging.DEBUG: traceback.print_exc(file=sys.stderr) return ERROR except KeyboardInterrupt: logger.critical('Operation cancelled by user') logger.debug('Exception information:', exc_info=True) return ERROR except BaseException: logger.critical('Exception:', exc_info=True) return UNKNOWN_ERROR finally: self.handle_pip_version_check(options) return SUCCESS
class Command(object): name = None # type: Optional[str] usage = None # type: Optional[str] hidden = False # type: bool ignore_require_venv = False # type: bool def __init__(self, isolated=False): parser_kw = { 'usage': self.usage, 'prog': '%s %s' % (get_prog(), self.name), 'formatter': UpdatingDefaultsHelpFormatter(), 'add_help_option': False, 'name': self.name, 'description': self.__doc__, 'isolated': isolated, } self.parser = ConfigOptionParser(**parser_kw) # Commands should add options to this option group optgroup_name = '%s Options' % self.name.capitalize() self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) # Add the general options gen_opts = cmdoptions.make_option_group( cmdoptions.general_group, self.parser, ) self.parser.add_option_group(gen_opts) def _build_session(self, options, retries=None, timeout=None): session = PipSession( cache=(normalize_path(os.path.join(options.cache_dir, "http")) if options.cache_dir else None), retries=retries if retries is not None else options.retries, insecure_hosts=options.trusted_hosts, ) # Handle custom ca-bundles from the user if options.cert: session.verify = options.cert # Handle SSL client certificate if options.client_cert: session.cert = options.client_cert # Handle timeouts if options.timeout or timeout: session.timeout = (timeout if timeout is not None else options.timeout) # Handle configured proxies if options.proxy: session.proxies = { "http": options.proxy, "https": options.proxy, } # Determine if we can prompt the user for authentication or not session.auth.prompting = not options.no_input return session def parse_args(self, args): # factored out for testability return self.parser.parse_args(args) def main(self, args): options, args = self.parse_args(args) # Set verbosity so that it can be used elsewhere. self.verbosity = options.verbose - options.quiet setup_logging( verbosity=self.verbosity, no_color=options.no_color, user_log_file=options.log, ) # TODO: Try to get these passing down from the command? # without resorting to os.environ to hold these. # This also affects isolated builds and it should. if options.no_input: os.environ['PIP_NO_INPUT'] = '1' if options.exists_action: os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) if options.require_venv and not self.ignore_require_venv: # If a venv is required check if it can really be found if not running_under_virtualenv(): logger.critical( 'Could not find an activated virtualenv (required).') sys.exit(VIRTUALENV_NOT_FOUND) try: status = self.run(options, args) # FIXME: all commands should return an exit status # and when it is done, isinstance is not needed anymore if isinstance(status, int): return status except PreviousBuildDirError as exc: logger.critical(str(exc)) logger.debug('Exception information:', exc_info=True) return PREVIOUS_BUILD_DIR_ERROR except (InstallationError, UninstallationError, BadCommand) as exc: logger.critical(str(exc)) logger.debug('Exception information:', exc_info=True) return ERROR except CommandError as exc: logger.critical('ERROR: %s', exc) logger.debug('Exception information:', exc_info=True) return ERROR except KeyboardInterrupt: logger.critical('Operation cancelled by user') logger.debug('Exception information:', exc_info=True) return ERROR except BaseException: logger.critical('Exception:', exc_info=True) return UNKNOWN_ERROR finally: allow_version_check = ( # Does this command have the index_group options? hasattr(options, "no_index") and # Is this command allowed to perform this check? not (options.disable_pip_version_check or options.no_index)) # Check if we're using the latest version of pip available if allow_version_check: session = self._build_session(options, retries=0, timeout=min(5, options.timeout)) with session: pip_version_check(session, options) # Shutdown the logging module logging.shutdown() return SUCCESS
class Command(object): name = None # type: Optional[str] usage = None # type: Optional[str] hidden = False # type: bool ignore_require_venv = False # type: bool def __init__(self, isolated=False): # type: (bool) -> None parser_kw = { 'usage': self.usage, 'prog': '%s %s' % (get_prog(), self.name), 'formatter': UpdatingDefaultsHelpFormatter(), 'add_help_option': False, 'name': self.name, 'description': self.__doc__, 'isolated': isolated, } self.parser = ConfigOptionParser(**parser_kw) # Commands should add options to this option group optgroup_name = '%s Options' % self.name.capitalize() self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) # Add the general options gen_opts = cmdoptions.make_option_group( cmdoptions.general_group, self.parser, ) self.parser.add_option_group(gen_opts) def run(self, options, args): # type: (Values, List[Any]) -> Any raise NotImplementedError def _build_session(self, options, retries=None, timeout=None): # type: (Values, Optional[int], Optional[int]) -> PipSession session = PipSession( cache=(normalize_path(os.path.join(options.cache_dir, "http")) if options.cache_dir else None), retries=retries if retries is not None else options.retries, insecure_hosts=options.trusted_hosts, ) # Handle custom ca-bundles from the user if options.cert: session.verify = options.cert # Handle SSL client certificate if options.client_cert: session.cert = options.client_cert # Handle timeouts if options.timeout or timeout: session.timeout = (timeout if timeout is not None else options.timeout) # Handle configured proxies if options.proxy: session.proxies = { "http": options.proxy, "https": options.proxy, } # Determine if we can prompt the user for authentication or not session.auth.prompting = not options.no_input return session def parse_args(self, args): # type: (List[str]) -> Tuple # factored out for testability return self.parser.parse_args(args) def main(self, args): # type: (List[str]) -> int options, args = self.parse_args(args) # Set verbosity so that it can be used elsewhere. self.verbosity = options.verbose - options.quiet level_number = setup_logging( verbosity=self.verbosity, no_color=options.no_color, user_log_file=options.log, ) if sys.version_info[:2] == (3, 4): deprecated( "Python 3.4 support has been deprecated. pip 19.1 will be the " "last one supporting it. Please upgrade your Python as Python " "3.4 won't be maintained after March 2019 (cf PEP 429).", replacement=None, gone_in='19.2', ) elif sys.version_info[:2] == (2, 7): message = ( "A future version of pip will drop support for Python 2.7.") if platform.python_implementation() == "CPython": message = ( "Python 2.7 will reach the end of its life on January " "1st, 2020. Please upgrade your Python as Python 2.7 " "won't be maintained after that date. ") + message deprecated(message, replacement=None, gone_in=None) # TODO: Try to get these passing down from the command? # without resorting to os.environ to hold these. # This also affects isolated builds and it should. if options.no_input: os.environ['PIP_NO_INPUT'] = '1' if options.exists_action: os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) if options.require_venv and not self.ignore_require_venv: # If a venv is required check if it can really be found if not running_under_virtualenv(): logger.critical( 'Could not find an activated virtualenv (required).') sys.exit(VIRTUALENV_NOT_FOUND) try: status = self.run(options, args) # FIXME: all commands should return an exit status # and when it is done, isinstance is not needed anymore if isinstance(status, int): return status except PreviousBuildDirError as exc: logger.critical(str(exc)) logger.debug('Exception information:', exc_info=True) return PREVIOUS_BUILD_DIR_ERROR except (InstallationError, UninstallationError, BadCommand) as exc: logger.critical(str(exc)) logger.debug('Exception information:', exc_info=True) return ERROR except CommandError as exc: logger.critical('ERROR: %s', exc) logger.debug('Exception information:', exc_info=True) return ERROR except BrokenStdoutLoggingError: # Bypass our logger and write any remaining messages to stderr # because stdout no longer works. print('ERROR: Pipe to stdout was broken', file=sys.stderr) if level_number <= logging.DEBUG: traceback.print_exc(file=sys.stderr) return ERROR except KeyboardInterrupt: logger.critical('Operation cancelled by user') logger.debug('Exception information:', exc_info=True) return ERROR except BaseException: logger.critical('Exception:', exc_info=True) return UNKNOWN_ERROR finally: allow_version_check = ( # Does this command have the index_group options? hasattr(options, "no_index") and # Is this command allowed to perform this check? not (options.disable_pip_version_check or options.no_index)) # Check if we're using the latest version of pip available if allow_version_check: session = self._build_session(options, retries=0, timeout=min(5, options.timeout)) with session: pip_version_check(session, options) # Shutdown the logging module logging.shutdown() return SUCCESS
class Command(CommandContextMixIn): usage: str = "" ignore_require_venv: bool = False def __init__(self, name: str, summary: str, isolated: bool = False) -> None: super().__init__() self.name = name self.summary = summary self.parser = ConfigOptionParser( usage=self.usage, prog=f"{get_prog()} {name}", formatter=UpdatingDefaultsHelpFormatter(), add_help_option=False, name=name, description=self.__doc__, isolated=isolated, ) self.tempdir_registry: Optional[TempDirRegistry] = None # Commands should add options to this option group optgroup_name = f"{self.name.capitalize()} Options" self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) # Add the general options gen_opts = cmdoptions.make_option_group( cmdoptions.general_group, self.parser, ) self.parser.add_option_group(gen_opts) self.add_options() def add_options(self) -> None: pass def handle_pip_version_check(self, options: Values) -> None: """ This is a no-op so that commands by default do not do the pip version check. """ # Make sure we do the pip version check if the index_group options # are present. assert not hasattr(options, "no_index") def run(self, options: Values, args: List[str]) -> int: raise NotImplementedError def parse_args(self, args: List[str]) -> Tuple[Values, List[str]]: # factored out for testability return self.parser.parse_args(args) def main(self, args: List[str]) -> int: try: with self.main_context(): return self._main(args) finally: logging.shutdown() def _main(self, args: List[str]) -> int: # We must initialize this before the tempdir manager, otherwise the # configuration would not be accessible by the time we clean up the # tempdir manager. self.tempdir_registry = self.enter_context(tempdir_registry()) # Intentionally set as early as possible so globally-managed temporary # directories are available to the rest of the code. self.enter_context(global_tempdir_manager()) options, args = self.parse_args(args) # Set verbosity so that it can be used elsewhere. self.verbosity = options.verbose - options.quiet level_number = setup_logging( verbosity=self.verbosity, no_color=options.no_color, user_log_file=options.log, ) # TODO: Try to get these passing down from the command? # without resorting to os.environ to hold these. # This also affects isolated builds and it should. if options.no_input: os.environ["PIP_NO_INPUT"] = "1" if options.exists_action: os.environ["PIP_EXISTS_ACTION"] = " ".join(options.exists_action) if options.require_venv and not self.ignore_require_venv: # If a venv is required check if it can really be found if not running_under_virtualenv(): logger.critical( "Could not find an activated virtualenv (required).") sys.exit(VIRTUALENV_NOT_FOUND) if options.cache_dir: options.cache_dir = normalize_path(options.cache_dir) if not check_path_owner(options.cache_dir): logger.warning( "The directory '%s' or its parent directory is not owned " "or is not writable by the current user. The cache " "has been disabled. Check the permissions and owner of " "that directory. If executing pip with sudo, you should " "use sudo's -H flag.", options.cache_dir, ) options.cache_dir = None if "2020-resolver" in options.features_enabled: logger.warning( "--use-feature=2020-resolver no longer has any effect, " "since it is now the default dependency resolver in pip. " "This will become an error in pip 21.0.") def intercepts_unhandled_exc( run_func: Callable[..., int]) -> Callable[..., int]: @functools.wraps(run_func) def exc_logging_wrapper(*args: Any) -> int: try: status = run_func(*args) assert isinstance(status, int) return status except DiagnosticPipError as exc: logger.error("[present-diagnostic] %s", exc) logger.debug("Exception information:", exc_info=True) return ERROR except PreviousBuildDirError as exc: logger.critical(str(exc)) logger.debug("Exception information:", exc_info=True) return PREVIOUS_BUILD_DIR_ERROR except ( InstallationError, UninstallationError, BadCommand, NetworkConnectionError, ) as exc: logger.critical(str(exc)) logger.debug("Exception information:", exc_info=True) return ERROR except CommandError as exc: logger.critical("%s", exc) logger.debug("Exception information:", exc_info=True) return ERROR except BrokenStdoutLoggingError: # Bypass our logger and write any remaining messages to # stderr because stdout no longer works. print("ERROR: Pipe to stdout was broken", file=sys.stderr) if level_number <= logging.DEBUG: traceback.print_exc(file=sys.stderr) return ERROR except KeyboardInterrupt: logger.critical("Operation cancelled by user") logger.debug("Exception information:", exc_info=True) return ERROR except BaseException: logger.critical("Exception:", exc_info=True) return UNKNOWN_ERROR return exc_logging_wrapper try: if not options.debug_mode: run = intercepts_unhandled_exc(self.run) else: run = self.run rich_traceback.install(show_locals=True) return run(options, args) finally: self.handle_pip_version_check(options)