def get_dependencies(self, ireq: InstallRequirement) -> Set[InstallRequirement]: """ Given a pinned, URL, or editable InstallRequirement, returns a set of dependencies (also InstallRequirements, but not necessarily pinned). They indicate the secondary dependencies for the given requirement. """ if not ( ireq.editable or is_url_requirement(ireq) or is_pinned_requirement(ireq) ): raise TypeError( f"Expected url, pinned or editable InstallRequirement, got {ireq}" ) if ireq not in self._dependencies_cache: if ireq.editable and (ireq.source_dir and os.path.exists(ireq.source_dir)): # No download_dir for locally available editable requirements. # If a download_dir is passed, pip will unnecessarily archive # the entire source directory download_dir = None elif ireq.link and ireq.link.is_vcs: # No download_dir for VCS sources. This also works around pip # using git-checkout-index, which gets rid of the .git dir. download_dir = None else: download_dir = self._get_download_path(ireq) os.makedirs(download_dir, exist_ok=True) with global_tempdir_manager(): wheel_cache = WheelCache(self._cache_dir, self.options.format_control) self._dependencies_cache[ireq] = self.resolve_reqs( download_dir, ireq, wheel_cache ) return self._dependencies_cache[ireq]
def scoped_global_tempdir_manager(): """Make unit tests with globally-managed tempdirs easier Each test function gets its own individual scope for globally-managed temporary directories in the application. """ with global_tempdir_manager(): yield
def build(self, ireq: shims.InstallRequirement, hashes: Optional[Dict[str, str]] = None) -> str: """Build egg_info directory for editable candidates and a wheel for others. :param ireq: the InstallRequirment of the candidate. :param hashes: a dictionary of filename: hash_value to check against downloaded artifacts. :returns: The full path of the built artifact. """ from pip._internal.utils.temp_dir import global_tempdir_manager from pdm.builders import EditableBuilder from pdm.builders import WheelBuilder kwargs = self._make_building_args(ireq) with self.get_finder() as finder: with allow_all_wheels(): # temporarily allow all wheels to get a link. ireq.populate_link(finder, False, bool(hashes)) if not ireq.editable and not ireq.req.name: ireq.source_dir = kwargs["build_dir"] else: ireq.ensure_has_source_dir(kwargs["build_dir"]) download_dir = kwargs["download_dir"] only_download = False if ireq.link.is_wheel: download_dir = kwargs["wheel_download_dir"] only_download = True if hashes: ireq.options["hashes"] = convert_hashes(hashes) if not (ireq.editable and ireq.req.is_local_dir): with global_tempdir_manager(): downloaded = shims.shim_unpack( link=ireq.link, download_dir=download_dir, location=ireq.source_dir, hashes=ireq.hashes(False), only_download=only_download, session=finder.session, ) # Preserve the downloaded file so that it won't be cleared. if downloaded and only_download: try: shutil.copy(downloaded, download_dir) except shutil.SameFileError: pass # Now all source is prepared, build it. if ireq.link.is_wheel: return (context.cache("wheels") / ireq.link.filename).as_posix() builder_class = EditableBuilder if ireq.editable else WheelBuilder kwargs["finder"] = finder with builder_class(ireq) as builder: return builder.build(**kwargs)
def get_dependencies(self, ireq): """ Given a pinned, URL, or editable InstallRequirement, returns a set of dependencies (also InstallRequirements, but not necessarily pinned). They indicate the secondary dependencies for the given requirement. """ if not ( ireq.editable or is_url_requirement(ireq) or is_pinned_requirement(ireq) ): raise TypeError( "Expected url, pinned or editable InstallRequirement, got {}".format( ireq ) ) if ireq not in self._dependencies_cache: if ireq.editable and (ireq.source_dir and os.path.exists(ireq.source_dir)): # No download_dir for locally available editable requirements. # If a download_dir is passed, pip will unnecessarely # archive the entire source directory download_dir = None elif ireq.link and ireq.link.is_vcs: # No download_dir for VCS sources. This also works around pip # using git-checkout-index, which gets rid of the .git dir. download_dir = None else: download_dir = self._download_dir if not os.path.isdir(download_dir): os.makedirs(download_dir) if not os.path.isdir(self._wheel_download_dir): os.makedirs(self._wheel_download_dir) with global_tempdir_manager(): wheel_cache = WheelCache(self._cache_dir, self.options.format_control) prev_tracker = os.environ.get("PIP_REQ_TRACKER") try: self._dependencies_cache[ireq] = self.resolve_reqs( download_dir, ireq, wheel_cache ) finally: if "PIP_REQ_TRACKER" in os.environ: if prev_tracker: os.environ["PIP_REQ_TRACKER"] = prev_tracker else: del os.environ["PIP_REQ_TRACKER"] if PIP_VERSION[:2] <= (20, 0): wheel_cache.cleanup() return self._dependencies_cache[ireq]
def preparer(finder): session = PipSession() rc = InstallCommand("x", "y") o = rc.parse_args([]) with global_tempdir_manager(): with TempDirectory() as tmp: with get_requirement_tracker() as tracker: preparer = RequirementCommand.make_requirement_preparer( tmp, options=o[0], req_tracker=tracker, session=session, finder=finder, use_user_site=False) yield preparer
def preparer(finder: PackageFinder) -> Iterator[RequirementPreparer]: session = PipSession() rc = InstallCommand("x", "y") o = rc.parse_args([]) with global_tempdir_manager(): with TempDirectory() as tmp: with get_build_tracker() as tracker: preparer = RequirementCommand.make_requirement_preparer( tmp, options=o[0], build_tracker=tracker, session=session, finder=finder, use_user_site=False, verbosity=0, ) yield preparer
def _main(self, args): # type: (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, ) if ( sys.version_info[:2] == (2, 7) and not options.no_python_version_warning ): message = ( "pip 21.0 will drop support for Python 2.7 in January 2021. " <<<<<<< HEAD "More details about Python 2 support in pip can be found at " ======= "More details about Python 2 support in pip, can be found at " >>>>>>> b66a76afa15ab74019740676a52a071b85ed8f71 "https://pip.pypa.io/en/latest/development/release-process/#python-2-support" # noqa ) if platform.python_implementation() == "CPython": message = ( "Python 2.7 reached the end of its life on January " "1st, 2020. Please upgrade your Python as Python 2.7 " "is no longer maintained. " ) + message
def pip_download_link(resconfig, url: str, destdir: str): with redirect_stdout(sys.stderr): netloc = urlsplit(resconfig['source']['repository']['index_url'])[1] hostname = netloc.split(':')[0] with PipSession(retries=RETRIES, trusted_hosts=[ hostname, ]) as session: session.timeout = TIMEOUT session.auth.prompting = False session.auth.passwords[netloc] = ( resconfig['source']['repository'].get('username', None), resconfig['source']['repository'].get('password', None)) # pip internals hardcode global tempdir manager. # need to copy to destdir before tempdir gets blown away. with global_tempdir_manager(): file = unpack_url( Link(url), destdir, Downloader(session, "pretty"), ) shutil.copy(file.path, destdir)
def main(self, args=None, prog_name=None, obj=None, **extra): """The main entry function""" from pip._internal.utils.temp_dir import global_tempdir_manager self.init_parser() self.load_plugins() self.parser.set_defaults(global_project=None) options = self.parser.parse_args(args or None) stream.set_verbosity(options.verbose) if obj is not None: options.project = obj if options.global_project: options.project = options.global_project if not getattr(options, "project", None): options.project = self.project_class() # Add reverse reference for core object options.project.core = self try: f = options.handler except AttributeError: self.parser.print_help() sys.exit(1) else: try: with global_tempdir_manager(): f(options.project, options) except Exception: etype, err, traceback = sys.exc_info() if stream.verbosity > stream.NORMAL: raise err.with_traceback(traceback) stream.echo("[{}]: {}".format(etype.__name__, err), err=True) sys.exit(1)
def test_global_tempdir_manager() -> None: with global_tempdir_manager(): d = TempDirectory(globally_managed=True) path = d.path assert os.path.exists(path) assert not os.path.exists(path)
def _main(self, args): # type: (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. tempdir_registry = enter_context(tempdir_registry()) # Intentionally set as early as possible so globally-managed temporary # directories are available to the rest of the code. enter_context(global_tempdir_manager()) options, args = parse_args(args) # Set verbosity so that it can be used elsewhere. verbosity = options.verbose - options.quiet level_number = setup_logging( verbosity=verbosity, no_color=options.no_color, user_log_file=options.log, ) if (sys.version_info[:2] == (2, 7) and not options.no_python_version_warning): message = ( "pip 21.0 will drop support for Python 2.7 in January 2021. " "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 reached the end of its life on January " "1st, 2020. Please upgrade your Python as Python 2.7 " "is no longer maintained. ") + message deprecated(message, replacement=None, gone_in="21.0") if (sys.version_info[:2] == (3, 5) and not options.no_python_version_warning): message = ("Python 3.5 reached the end of its life on September " "13th, 2020. Please upgrade your Python as Python 3.5 " "is no longer maintained. pip 21.0 will drop support " "for Python 3.5 in January 2021.") deprecated(message, replacement=None, gone_in="21.0") # 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 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 may want " "sudo's -H flag.", options.cache_dir, ) options.cache_dir = None if '2020-resolver' in options.features_enabled and not PY2: 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.") try: status = run(options, args) assert 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, SubProcessError, 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 finally: handle_pip_version_check(options)
def _main(self, args): # type: (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 may want " "sudo's -H flag.", options.cache_dir, ) options.cache_dir = None if getattr(options, "build_dir", None): deprecated( reason=( "The -b/--build/--build-dir/--build-directory " "option is deprecated and has no effect anymore." ), replacement=( "use the TMPDIR/TEMP/TMP environment variable, " "possibly combined with --no-clean" ), gone_in="21.1", issue=8333, ) 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." ) try: status = self.run(options, args) assert 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, 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 finally: self.handle_pip_version_check(options)
def _main(self, args): # type: (List[str]) -> int # 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, ) if (sys.version_info[:2] == (2, 7) and not options.no_python_version_warning): 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 reached the end of its life on January " "1st, 2020. Please upgrade your Python as Python 2.7 " "is no longer maintained. ") + message deprecated(message, replacement=None, gone_in=None) if options.skip_requirements_regex: deprecated( "--skip-requirements-regex is unsupported and will be removed", replacement=( "manage requirements/constraints files explicitly, " "possibly generating them from metadata"), gone_in="20.1", issue=7297, ) # 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 may want " "sudo's -H flag.", options.cache_dir, ) options.cache_dir = None 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
def _main(self, args): # type: (List[str]) -> int # 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, ) if ( sys.version_info[:2] == (2, 7) and not options.no_python_version_warning ): 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 reached the end of its life on January " "1st, 2020. Please upgrade your Python as Python 2.7 " "is no longer maintained. " ) + message deprecated(message, replacement=None, gone_in=None) if options.skip_requirements_regex: deprecated( "--skip-requirements-regex is unsupported and will be removed", replacement=( "manage requirements/constraints files explicitly, " "possibly generating them from metadata" ), gone_in="20.1", issue=7297, ) # 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 may want " "sudo's -H flag.", options.cache_dir, ) options.cache_dir = None try: status = self.run(options, args)
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 PreviousBuildDirError as exc: logger.critical(str(exc)) logger.debug("Exception information:", exc_info=True) return PREVIOUS_BUILD_DIR_ERROR except DiagnosticPipError as exc: logger.critical(str(exc)) logger.debug("Exception information:", exc_info=True) return 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 return run(options, args) finally: self.handle_pip_version_check(options)
def pip_global_tempdir_manager(): from pip._internal.utils.temp_dir import global_tempdir_manager with global_tempdir_manager(): yield