Esempio n. 1
0
    def test_resolve_symlinks(self, tmpdir):
        print(type(tmpdir))
        print(dir(tmpdir))
        orig_working_dir = os.getcwd()
        os.chdir(tmpdir)
        try:
            d = os.path.join('foo', 'bar')
            f = os.path.join(d, 'file1')
            os.makedirs(d)
            with open(f, 'w'):  # Create the file
                pass

            os.symlink(d, 'dir_link')
            os.symlink(f, 'file_link')

            assert normalize_path(
                'dir_link/file1', resolve_symlinks=True
            ) == os.path.join(tmpdir, f)
            assert normalize_path(
                'dir_link/file1', resolve_symlinks=False
            ) == os.path.join(tmpdir, 'dir_link', 'file1')

            assert normalize_path(
                'file_link', resolve_symlinks=True
            ) == os.path.join(tmpdir, f)
            assert normalize_path(
                'file_link', resolve_symlinks=False
            ) == os.path.join(tmpdir, 'file_link')
        finally:
            os.chdir(orig_working_dir)
Esempio n. 2
0
    def __init__(self, build_dir, download_dir, src_dir, wheel_download_dir,
                 progress_bar, build_isolation):
        super(RequirementPreparer, self).__init__()

        self.src_dir = src_dir
        self.build_dir = build_dir

        # Where still packed archives should be written to. If None, they are
        # not saved, and are deleted immediately after unpacking.
        self.download_dir = download_dir

        # Where still-packed .whl files should be written to. If None, they are
        # written to the download_dir parameter. Separate to download_dir to
        # permit only keeping wheel archives for pip wheel.
        if wheel_download_dir:
            wheel_download_dir = normalize_path(wheel_download_dir)
        self.wheel_download_dir = wheel_download_dir

        # NOTE
        # download_dir and wheel_download_dir overlap semantically and may
        # be combined if we're willing to have non-wheel archives present in
        # the wheelhouse output by 'pip wheel'.

        self.progress_bar = progress_bar

        # Is build isolation allowed?
        self.build_isolation = build_isolation
Esempio n. 3
0
    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
Esempio n. 4
0
    def _build_session(options, retries=None, timeout=None):
        session = PipSession(
            cache=(
                normalize_path(os.path.join(options.get('cache_dir'), 'http'))
                if options.get('cache_dir') else None
            ),
            retries=retries if retries is not None else options.get('retries'),
            insecure_hosts=options.get('trusted_hosts'),
        )

        # Handle custom ca-bundles from the user
        if options.get('cert'):
            session.verify = options.get('cert')

        # Handle SSL client certificate
        if options.get('client_cert'):
            session.cert = options.get('client_cert')

        # Handle timeouts
        if options.get('timeout') or timeout:
            session.timeout = (
                timeout if timeout is not None else options.get('timeout')
            )

        # Handle configured proxies
        if options.get('proxy'):
            session.proxies = {
                'http': options.get('proxy'),
                'https': options.get('proxy'),
            }

        # Determine if we can prompt the user for authentication or not
        session.auth.prompting = not options.get('no_input')

        return session
 def add_pth(self, pth_file, entry):
     pth_file = normalize_path(pth_file)
     if self._permitted(pth_file):
         if pth_file not in self.pth:
             self.pth[pth_file] = UninstallPthEntries(pth_file)
         self.pth[pth_file].add(entry)
     else:
         self._refuse.add(pth_file)
    def add(self, path):
        head, tail = os.path.split(path)

        # we normalize the head to resolve parent directory symlinks, but not
        # the tail, since we only want to uninstall symlinks, not their targets
        path = os.path.join(normalize_path(head), os.path.normcase(tail))

        if not os.path.exists(path):
            return
        if self._permitted(path):
            self.paths.add(path)
        else:
            self._refuse.add(path)

        # __pycache__ files can show up after 'installed-files.txt' is created,
        # due to imports
        if os.path.splitext(path)[1] == '.py' and uses_pycache:
            self.add(cache_from_source(path))
Esempio n. 7
0
    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)
Esempio n. 8
0
 def in_usersite(self) -> bool:
     if self.installed_location is None or user_site is None:
         return False
     return self.installed_location.startswith(normalize_path(user_site))
Esempio n. 9
0
 def in_site_packages(self) -> bool:
     if self.installed_location is None or site_packages is None:
         return False
     return self.installed_location.startswith(
         normalize_path(site_packages))
Esempio n. 10
0
    def run(self, options, args):
        options.ignore_installed = True
        # editable doesn't really make sense for `pip download`, but the bowels
        # of the RequirementSet code require that property.
        options.editables = []

        if options.python_version:
            python_versions = [options.python_version]
        else:
            python_versions = None

        cmdoptions.check_dist_restriction(options)

        options.src_dir = os.path.abspath(options.src_dir)
        options.download_dir = normalize_path(options.download_dir)

        ensure_dir(options.download_dir)

        with self._build_session(options) as session:
            finder = self._build_package_finder(
                options=options,
                session=session,
                platform=options.platform,
                python_versions=python_versions,
                abi=options.abi,
                implementation=options.implementation,
            )
            build_delete = (not (options.no_clean or options.build_dir))
            if options.cache_dir and not check_path_owner(options.cache_dir):
                logger.warning(
                    "The directory '%s' or its parent directory is not owned "
                    "by the current user and caching wheels 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

            with RequirementTracker() as req_tracker, TempDirectory(
                    options.build_dir, delete=build_delete, kind="download"
            ) as directory:

                requirement_set = RequirementSet(
                    require_hashes=options.require_hashes,
                )
                self.populate_requirement_set(
                    requirement_set,
                    args,
                    options,
                    finder,
                    session,
                    self.name,
                    None
                )

                preparer = RequirementPreparer(
                    build_dir=directory.path,
                    src_dir=options.src_dir,
                    download_dir=options.download_dir,
                    wheel_download_dir=None,
                    progress_bar=options.progress_bar,
                    build_isolation=options.build_isolation,
                    req_tracker=req_tracker,
                )

                resolver = Resolver(
                    preparer=preparer,
                    finder=finder,
                    session=session,
                    wheel_cache=None,
                    use_user_site=False,
                    upgrade_strategy="to-satisfy-only",
                    force_reinstall=False,
                    ignore_dependencies=options.ignore_dependencies,
                    ignore_requires_python=False,
                    ignore_installed=True,
                    isolated=options.isolated_mode,
                )
                resolver.resolve(requirement_set)

                downloaded = ' '.join([
                    req.name for req in requirement_set.successfully_downloaded
                ])
                if downloaded:
                    logger.info('Successfully downloaded %s', downloaded)

                # Clean up
                if not options.no_clean:
                    requirement_set.cleanup_files()

        return requirement_set
Esempio n. 11
0
    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)
Esempio n. 12
0
    def from_dist(cls, dist):
        dist_path = normalize_path(dist.location)
        if not dist_is_local(dist):
            logger.info(
                "Not uninstalling %s at %s, outside environment %s",
                dist.key,
                dist_path,
                sys.prefix,
            )
            return cls(dist)

        if dist_path in {
                p
                for p in
            {sysconfig.get_path("stdlib"),
             sysconfig.get_path("platstdlib")} if p
        }:
            logger.info(
                "Not uninstalling %s at %s, as it is in the standard library.",
                dist.key,
                dist_path,
            )
            return cls(dist)

        paths_to_remove = cls(dist)
        develop_egg_link = egg_link_path(dist)
        develop_egg_link_egg_info = '{}.egg-info'.format(
            pkg_resources.to_filename(dist.project_name))
        egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info)
        # Special case for distutils installed package
        distutils_egg_info = getattr(dist._provider, 'path', None)

        # Uninstall cases order do matter as in the case of 2 installs of the
        # same package, pip needs to uninstall the currently detected version
        if (egg_info_exists and dist.egg_info.endswith('.egg-info')
                and not dist.egg_info.endswith(develop_egg_link_egg_info)):
            # if dist.egg_info.endswith(develop_egg_link_egg_info), we
            # are in fact in the develop_egg_link case
            paths_to_remove.add(dist.egg_info)
            if dist.has_metadata('installed-files.txt'):
                for installed_file in dist.get_metadata(
                        'installed-files.txt').splitlines():
                    path = os.path.normpath(
                        os.path.join(dist.egg_info, installed_file))
                    paths_to_remove.add(path)
            # FIXME: need a test for this elif block
            # occurs with --single-version-externally-managed/--record outside
            # of pip
            elif dist.has_metadata('top_level.txt'):
                if dist.has_metadata('namespace_packages.txt'):
                    namespaces = dist.get_metadata('namespace_packages.txt')
                else:
                    namespaces = []
                for top_level_pkg in [
                        p for p in dist.get_metadata(
                            'top_level.txt').splitlines()
                        if p and p not in namespaces
                ]:
                    path = os.path.join(dist.location, top_level_pkg)
                    paths_to_remove.add(path)
                    paths_to_remove.add(path + '.py')
                    paths_to_remove.add(path + '.pyc')
                    paths_to_remove.add(path + '.pyo')

        elif distutils_egg_info:
            raise UninstallationError(
                "Cannot uninstall {!r}. It is a distutils installed project "
                "and thus we cannot accurately determine which files belong "
                "to it which would lead to only a partial uninstall.".format(
                    dist.project_name, ))

        elif dist.location.endswith('.egg'):
            # package installed by easy_install
            # We cannot match on dist.egg_name because it can slightly vary
            # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg
            paths_to_remove.add(dist.location)
            easy_install_egg = os.path.split(dist.location)[1]
            easy_install_pth = os.path.join(os.path.dirname(dist.location),
                                            'easy-install.pth')
            paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg)

        elif egg_info_exists and dist.egg_info.endswith('.dist-info'):
            for path in uninstallation_paths(dist):
                paths_to_remove.add(path)

        elif develop_egg_link:
            # develop egg
            with open(develop_egg_link, 'r') as fh:
                link_pointer = os.path.normcase(fh.readline().strip())
            assert (link_pointer == dist.location), (
                'Egg-link %s does not match installed location of %s '
                '(at %s)' % (link_pointer, dist.project_name, dist.location))
            paths_to_remove.add(develop_egg_link)
            easy_install_pth = os.path.join(os.path.dirname(develop_egg_link),
                                            'easy-install.pth')
            paths_to_remove.add_pth(easy_install_pth, dist.location)

        else:
            logger.debug(
                'Not sure how to uninstall: %s - Check: %s',
                dist,
                dist.location,
            )

        # find distutils scripts= scripts
        if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'):
            for script in dist.metadata_listdir('scripts'):
                if dist_in_usersite(dist):
                    bin_dir = bin_user
                else:
                    bin_dir = bin_py
                paths_to_remove.add(os.path.join(bin_dir, script))
                if WINDOWS:
                    paths_to_remove.add(os.path.join(bin_dir, script) + '.bat')

        # find console_scripts
        _scripts_to_remove = []
        console_scripts = dist.get_entry_map(group='console_scripts')
        for name in console_scripts.keys():
            _scripts_to_remove.extend(_script_names(dist, name, False))
        # find gui_scripts
        gui_scripts = dist.get_entry_map(group='gui_scripts')
        for name in gui_scripts.keys():
            _scripts_to_remove.extend(_script_names(dist, name, True))

        for s in _scripts_to_remove:
            paths_to_remove.add(s)

        return paths_to_remove
Esempio n. 13
0
    def run(self, options, args):
        options.ignore_installed = True
        # editable doesn't really make sense for `pip download`, but the bowels
        # of the RequirementSet code require that property.
        options.editables = []

        cmdoptions.check_dist_restriction(options)

        options.src_dir = os.path.abspath(options.src_dir)
        options.download_dir = normalize_path(options.download_dir)

        ensure_dir(options.download_dir)

        session = self.get_default_session(options)

        target_python = make_target_python(options)
        finder = self._build_package_finder(
            options=options,
            session=session,
            target_python=target_python,
        )
        build_delete = (not (options.no_clean or options.build_dir))
        if options.cache_dir and not check_path_owner(options.cache_dir):
            logger.warning(
                "The directory '%s' or its parent directory is not owned "
                "by the current user and caching wheels 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

        with RequirementTracker() as req_tracker, TempDirectory(
                options.build_dir, delete=build_delete, kind="download"
        ) as directory:

            requirement_set = RequirementSet(
                require_hashes=options.require_hashes,
            )
            self.populate_requirement_set(
                requirement_set,
                args,
                options,
                finder,
                session,
                None
            )

            preparer = self.make_requirement_preparer(
                temp_build_dir=directory,
                options=options,
                req_tracker=req_tracker,
                download_dir=options.download_dir,
            )

            resolver = self.make_resolver(
                preparer=preparer,
                finder=finder,
                session=session,
                options=options,
                py_version_info=options.python_version,
            )
            resolver.resolve(requirement_set)

            downloaded = ' '.join([
                req.name for req in requirement_set.successfully_downloaded
            ])
            if downloaded:
                write_output('Successfully downloaded %s', downloaded)

            # Clean up
            if not options.no_clean:
                requirement_set.cleanup_files()

        return requirement_set
Esempio n. 14
0
 def is_local(self, path) -> bool:
     return misc.normalize_path(path).startswith(
         misc.normalize_path(self.get_paths()["prefix"]))
Esempio n. 15
0
        # Where still-packed archives should be written to. If None, they are
=======

        # Where still packed archives should be written to. If None, they are
>>>>>>> 71358189c5e72ee2ac9883b408a2f540a7f5745e
        # not saved, and are deleted immediately after unpacking.
        self.download_dir = download_dir

        # Where still-packed .whl files should be written to. If None, they are
        # written to the download_dir parameter. Separate to download_dir to
        # permit only keeping wheel archives for pip wheel.
<<<<<<< HEAD
=======
        if wheel_download_dir:
            wheel_download_dir = normalize_path(wheel_download_dir)
>>>>>>> 71358189c5e72ee2ac9883b408a2f540a7f5745e
        self.wheel_download_dir = wheel_download_dir

        # NOTE
        # download_dir and wheel_download_dir overlap semantically and may
        # be combined if we're willing to have non-wheel archives present in
        # the wheelhouse output by 'pip wheel'.

<<<<<<< HEAD
        # Is build isolation allowed?
        self.build_isolation = build_isolation

        # Should hash-checking be required?
        self.require_hashes = require_hashes
Esempio n. 16
0
    def run(self, options, args):
        options.ignore_installed = True
        # editable doesn't really make sense for `pip download`, but the bowels
        # of the RequirementSet code require that property.
        options.editables = []

        cmdoptions.check_dist_restriction(options)

        options.download_dir = normalize_path(options.download_dir)

        ensure_dir(options.download_dir)

        session = self.get_default_session(options)

        target_python = make_target_python(options)
        finder = self._build_package_finder(
            options=options,
            session=session,
            target_python=target_python,
        )
        build_delete = (not (options.no_clean or options.build_dir))

        with get_requirement_tracker() as req_tracker, TempDirectory(
            options.build_dir, delete=build_delete, kind="download"
        ) as directory:

            requirement_set = RequirementSet()
            self.populate_requirement_set(
                requirement_set,
                args,
                options,
                finder,
                session,
                None
            )

            preparer = self.make_requirement_preparer(
                temp_build_dir=directory,
                options=options,
                req_tracker=req_tracker,
                session=session,
                finder=finder,
                download_dir=options.download_dir,
                use_user_site=False,
            )

            resolver = self.make_resolver(
                preparer=preparer,
                finder=finder,
                options=options,
                py_version_info=options.python_version,
            )

            self.trace_basic_info(finder)

            resolver.resolve(requirement_set)

            downloaded = ' '.join([
                req.name for req in requirement_set.successfully_downloaded
            ])
            if downloaded:
                write_output('Successfully downloaded %s', downloaded)

            # Clean up
            if not options.no_clean:
                requirement_set.cleanup_files()

        return requirement_set
Esempio n. 17
0
 def is_local(self, path) -> bool:
     """PEP 582 version of ``is_local()`` function."""
     return misc.normalize_path(path).startswith(
         misc.normalize_path(self.packages_path.as_posix()))
Esempio n. 18
0
    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. "
                "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)

        # 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
Esempio n. 19
0
 def installed_location(self) -> Optional[str]:
     if self._installed_location is None:
         return None
     return normalize_path(str(self._installed_location))
Esempio n. 20
0
    def run(self, options, args):
        options.ignore_installed = True
        # editable doesn't really make sense for `pip download`, but the bowels
        # of the RequirementSet code require that property.
        options.editables = []

        if options.python_version:
            python_versions = [options.python_version]
        else:
            python_versions = None

        dist_restriction_set = any([
            options.python_version,
            options.platform,
            options.abi,
            options.implementation,
        ])
        binary_only = FormatControl(set(), {':all:'})
        no_sdist_dependencies = (
            options.format_control != binary_only and
            not options.ignore_dependencies
        )
        if dist_restriction_set and no_sdist_dependencies:
            raise CommandError(
                "When restricting platform and interpreter constraints using "
                "--python-version, --platform, --abi, or --implementation, "
                "either --no-deps must be set, or --only-binary=:all: must be "
                "set and --no-binary must not be set (or must be set to "
                ":none:)."
            )

        options.src_dir = os.path.abspath(options.src_dir)
        options.download_dir = normalize_path(options.download_dir)

        ensure_dir(options.download_dir)

        with self._build_session(options) as session:
            finder = self._build_package_finder(
                options=options,
                session=session,
                platform=options.platform,
                python_versions=python_versions,
                abi=options.abi,
                implementation=options.implementation,
            )
            build_delete = (not (options.no_clean or options.build_dir))
            if options.cache_dir and not check_path_owner(options.cache_dir):
                logger.warning(
                    "The directory '%s' or its parent directory is not owned "
                    "by the current user and caching wheels 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

            with RequirementTracker() as req_tracker, TempDirectory(
                options.build_dir, delete=build_delete, kind="download"
            ) as directory:

                requirement_set = RequirementSet(
                    require_hashes=options.require_hashes,
                )
                self.populate_requirement_set(
                    requirement_set,
                    args,
                    options,
                    finder,
                    session,
                    self.name,
                    None
                )

                preparer = RequirementPreparer(
                    build_dir=directory.path,
                    src_dir=options.src_dir,
                    download_dir=options.download_dir,
                    wheel_download_dir=None,
                    progress_bar=options.progress_bar,
                    build_isolation=options.build_isolation,
                    req_tracker=req_tracker,
                )

                resolver = Resolver(
                    preparer=preparer,
                    finder=finder,
                    session=session,
                    wheel_cache=None,
                    use_user_site=False,
                    upgrade_strategy="to-satisfy-only",
                    force_reinstall=False,
                    ignore_dependencies=options.ignore_dependencies,
                    ignore_requires_python=False,
                    ignore_installed=True,
                    isolated=options.isolated_mode,
                )
                resolver.resolve(requirement_set)

                downloaded = ' '.join([
                    req.name for req in requirement_set.successfully_downloaded
                ])
                if downloaded:
                    logger.info('Successfully downloaded %s', downloaded)

                # Clean up
                if not options.no_clean:
                    requirement_set.cleanup_files()

        return requirement_set
Esempio n. 21
0
    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. "
                "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 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."),
                replacement=("use the TMPDIR/TEMP/TMP environment variable, "
                             "possibly combined with --no-clean"),
                gone_in="20.3",
                issue=8333,
            )

        if 'resolver' in options.unstable_features:
            logger.critical(
                "--unstable-feature=resolver is no longer supported, and "
                "has been replaced with --use-feature=2020-resolver instead.")
            sys.exit(ERROR)

        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,
                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:
            self.handle_pip_version_check(options)
Esempio n. 22
0
    def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet":
        dist_location = dist.location
        info_location = dist.info_location
        if dist_location is None:
            logger.info(
                "Not uninstalling %s since it is not installed",
                dist.canonical_name,
            )
            return cls(dist)

        normalized_dist_location = normalize_path(dist_location)
        if not dist.local:
            logger.info(
                "Not uninstalling %s at %s, outside environment %s",
                dist.canonical_name,
                normalized_dist_location,
                sys.prefix,
            )
            return cls(dist)

        if normalized_dist_location in {
                p
                for p in
            {sysconfig.get_path("stdlib"),
             sysconfig.get_path("platstdlib")} if p
        }:
            logger.info(
                "Not uninstalling %s at %s, as it is in the standard library.",
                dist.canonical_name,
                normalized_dist_location,
            )
            return cls(dist)

        paths_to_remove = cls(dist)
        develop_egg_link = egg_link_path_from_location(dist.raw_name)

        # Distribution is installed with metadata in a "flat" .egg-info
        # directory. This means it is not a modern .dist-info installation, an
        # egg, or legacy editable.
        setuptools_flat_installation = (
            dist.installed_with_setuptools_egg_info
            and info_location is not None and os.path.exists(info_location)
            # If dist is editable and the location points to a ``.egg-info``,
            # we are in fact in the legacy editable case.
            and
            not info_location.endswith(f"{dist.setuptools_filename}.egg-info"))

        # Uninstall cases order do matter as in the case of 2 installs of the
        # same package, pip needs to uninstall the currently detected version
        if setuptools_flat_installation:
            if info_location is not None:
                paths_to_remove.add(info_location)
            installed_files = dist.iter_declared_entries()
            if installed_files is not None:
                for installed_file in installed_files:
                    paths_to_remove.add(
                        os.path.join(dist_location, installed_file))
            # FIXME: need a test for this elif block
            # occurs with --single-version-externally-managed/--record outside
            # of pip
            elif dist.is_file("top_level.txt"):
                try:
                    namespace_packages = dist.read_text(
                        "namespace_packages.txt")
                except FileNotFoundError:
                    namespaces = []
                else:
                    namespaces = namespace_packages.splitlines(keepends=False)
                for top_level_pkg in [
                        p
                        for p in dist.read_text("top_level.txt").splitlines()
                        if p and p not in namespaces
                ]:
                    path = os.path.join(dist_location, top_level_pkg)
                    paths_to_remove.add(path)
                    paths_to_remove.add(f"{path}.py")
                    paths_to_remove.add(f"{path}.pyc")
                    paths_to_remove.add(f"{path}.pyo")

        elif dist.installed_by_distutils:
            raise UninstallationError(
                "Cannot uninstall {!r}. It is a distutils installed project "
                "and thus we cannot accurately determine which files belong "
                "to it which would lead to only a partial uninstall.".format(
                    dist.raw_name, ))

        elif dist.installed_as_egg:
            # package installed by easy_install
            # We cannot match on dist.egg_name because it can slightly vary
            # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg
            paths_to_remove.add(dist_location)
            easy_install_egg = os.path.split(dist_location)[1]
            easy_install_pth = os.path.join(
                os.path.dirname(dist_location),
                "easy-install.pth",
            )
            paths_to_remove.add_pth(easy_install_pth, "./" + easy_install_egg)

        elif dist.installed_with_dist_info:
            for path in uninstallation_paths(dist):
                paths_to_remove.add(path)

        elif develop_egg_link:
            # PEP 660 modern editable is handled in the ``.dist-info`` case
            # above, so this only covers the setuptools-style editable.
            with open(develop_egg_link) as fh:
                link_pointer = os.path.normcase(fh.readline().strip())
                normalized_link_pointer = normalize_path(link_pointer)
            assert os.path.samefile(
                normalized_link_pointer, normalized_dist_location
            ), (f"Egg-link {link_pointer} does not match installed location of "
                f"{dist.raw_name} (at {dist_location})")
            paths_to_remove.add(develop_egg_link)
            easy_install_pth = os.path.join(os.path.dirname(develop_egg_link),
                                            "easy-install.pth")
            paths_to_remove.add_pth(easy_install_pth, dist_location)

        else:
            logger.debug(
                "Not sure how to uninstall: %s - Check: %s",
                dist,
                dist_location,
            )

        if dist.in_usersite:
            bin_dir = get_bin_user()
        else:
            bin_dir = get_bin_prefix()

        # find distutils scripts= scripts
        try:
            for script in dist.iterdir("scripts"):
                paths_to_remove.add(os.path.join(bin_dir, script.name))
                if WINDOWS:
                    paths_to_remove.add(
                        os.path.join(bin_dir, f"{script.name}.bat"))
        except (FileNotFoundError, NotADirectoryError):
            pass

        # find console_scripts and gui_scripts
        def iter_scripts_to_remove(
            dist: BaseDistribution,
            bin_dir: str,
        ) -> Generator[str, None, None]:
            for entry_point in dist.iter_entry_points():
                if entry_point.group == "console_scripts":
                    yield from _script_names(bin_dir, entry_point.name, False)
                elif entry_point.group == "gui_scripts":
                    yield from _script_names(bin_dir, entry_point.name, True)

        for s in iter_scripts_to_remove(dist, bin_dir):
            paths_to_remove.add(s)

        return paths_to_remove
Esempio n. 23
0
    def run(self, options: Values, args: List[str]) -> int:
        cmdoptions.check_install_build_global(options)

        session = self.get_default_session(options)

        finder = self._build_package_finder(options, session)
        wheel_cache = WheelCache(options.cache_dir, options.format_control)

        options.wheel_dir = normalize_path(options.wheel_dir)
        ensure_dir(options.wheel_dir)

        build_tracker = self.enter_context(get_build_tracker())

        directory = TempDirectory(
            delete=not options.no_clean,
            kind="wheel",
            globally_managed=True,
        )

        reqs = self.get_requirements(args, options, finder, session)

        preparer = self.make_requirement_preparer(
            temp_build_dir=directory,
            options=options,
            build_tracker=build_tracker,
            session=session,
            finder=finder,
            download_dir=options.wheel_dir,
            use_user_site=False,
            verbosity=self.verbosity,
        )

        resolver = self.make_resolver(
            preparer=preparer,
            finder=finder,
            options=options,
            wheel_cache=wheel_cache,
            ignore_requires_python=options.ignore_requires_python,
            use_pep517=options.use_pep517,
        )

        self.trace_basic_info(finder)

        requirement_set = resolver.resolve(reqs, check_supported_wheels=True)

        reqs_to_build: List[InstallRequirement] = []
        for req in requirement_set.requirements.values():
            if req.is_wheel:
                preparer.save_linked_requirement(req)
            elif should_build_for_wheel_command(req):
                reqs_to_build.append(req)

        # build wheels
        build_successes, build_failures = build(
            reqs_to_build,
            wheel_cache=wheel_cache,
            verify=(not options.no_verify),
            build_options=options.build_options or [],
            global_options=options.global_options or [],
        )
        for req in build_successes:
            assert req.link and req.link.is_wheel
            assert req.local_file_path
            # copy from cache to target directory
            try:
                shutil.copy(req.local_file_path, options.wheel_dir)
            except OSError as e:
                logger.warning(
                    "Building wheel for %s failed: %s",
                    req.name,
                    e,
                )
                build_failures.append(req)
        if len(build_failures) != 0:
            raise CommandError("Failed to build one or more wheels")

        return SUCCESS
Esempio n. 24
0
    @with_cleanup
    def run(self, options, args):
        # type: (Values, List[str]) -> int
        cmdoptions.check_install_build_global(options)

        session = self.get_default_session(options)

        finder = self._build_package_finder(options, session)
<<<<<<< HEAD
=======
        build_delete = (not (options.no_clean or options.build_dir))
>>>>>>> 74c061954d5e927be4caafbd793e96a50563c265
        wheel_cache = WheelCache(options.cache_dir, options.format_control)

        options.wheel_dir = normalize_path(options.wheel_dir)
        ensure_dir(options.wheel_dir)

        req_tracker = self.enter_context(get_requirement_tracker())

        directory = TempDirectory(
<<<<<<< HEAD
            delete=not options.no_clean,
=======
            options.build_dir,
            delete=build_delete,
>>>>>>> 74c061954d5e927be4caafbd793e96a50563c265
            kind="wheel",
            globally_managed=True,
        )
Esempio n. 25
0
    def __init__(
            self,
            find_links,  # type: List[str]
            index_urls,  # type: List[str]
            allow_all_prereleases=False,  # type: bool
            trusted_hosts=None,  # type: Optional[Iterable[str]]
            process_dependency_links=False,  # type: bool
            session=None,  # type: Optional[PipSession]
            format_control=None,  # type: Optional[FormatControl]
            platform=None,  # type: Optional[str]
            versions=None,  # type: Optional[List[str]]
            abi=None,  # type: Optional[str]
            implementation=None,  # type: Optional[str]
            prefer_binary=False  # type: bool
    ):
        # type: (...) -> None
        """Create a PackageFinder.

        :param format_control: A FormatControl object or None. Used to control
            the selection of source packages / binary packages when consulting
            the index and links.
        :param platform: A string or None. If None, searches for packages
            that are supported by the current system. Otherwise, will find
            packages that can be built on the platform passed in. These
            packages will only be downloaded for distribution: they will
            not be built locally.
        :param versions: A list of strings or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        :param abi: A string or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        :param implementation: A string or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        """
        if session is None:
            raise TypeError(
                "PackageFinder() missing 1 required keyword argument: "
                "'session'")

        # Build find_links. If an argument starts with ~, it may be
        # a local file relative to a home directory. So try normalizing
        # it and if it exists, use the normalized version.
        # This is deliberately conservative - it might be fine just to
        # blindly normalize anything starting with a ~...
        self.find_links = []  # type: List[str]
        for link in find_links:
            if link.startswith('~'):
                new_link = normalize_path(link)
                if os.path.exists(new_link):
                    link = new_link
            self.find_links.append(link)

        self.index_urls = index_urls
        self.dependency_links = []  # type: List[str]

        # These are boring links that have already been logged somehow:
        self.logged_links = set()  # type: Set[Link]

        self.format_control = format_control or FormatControl(set(), set())

        # Domains that we won't emit warnings for when not using HTTPS
        self.secure_origins = [
            ("*", host, "*")
            for host in (trusted_hosts if trusted_hosts else [])
        ]  # type: List[SecureOrigin]

        # Do we want to allow _all_ pre-releases?
        self.allow_all_prereleases = allow_all_prereleases

        # Do we process dependency links?
        self.process_dependency_links = process_dependency_links

        # The Session we'll use to make requests
        self.session = session

        # The valid tags to check potential found wheel candidates against
        self.valid_tags = get_supported(
            versions=versions,
            platform=platform,
            abi=abi,
            impl=implementation,
        )

        # Do we prefer old, but valid, binary dist over new source dist
        self.prefer_binary = prefer_binary

        # If we don't have TLS enabled, then WARN if anyplace we're looking
        # relies on TLS.
        if not HAS_TLS:
            for link in itertools.chain(self.index_urls, self.find_links):
                parsed = urllib_parse.urlparse(link)
                if parsed.scheme == "https":
                    logger.warning(
                        "pip is configured with locations that require "
                        "TLS/SSL, however the ssl module in Python is not "
                        "available.")
                    break
Esempio n. 26
0
        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

<<<<<<< HEAD
        if getattr(options, "build_dir", None):
            deprecated(
                reason=(
Esempio n. 27
0
    def run(self, options, args):
        # type: (Values, List[Any]) -> None
        cmdoptions.check_install_build_global(options)

        session = self.get_default_session(options)

        finder = self._build_package_finder(options, session)
        build_delete = (not (options.no_clean or options.build_dir))
        wheel_cache = WheelCache(options.cache_dir, options.format_control)

        options.wheel_dir = normalize_path(options.wheel_dir)
        ensure_dir(options.wheel_dir)

        with get_requirement_tracker() as req_tracker, TempDirectory(
                options.build_dir, delete=build_delete,
                kind="wheel") as directory:

            requirement_set = RequirementSet()

            try:
                self.populate_requirement_set(requirement_set, args, options,
                                              finder, session, wheel_cache)

                preparer = self.make_requirement_preparer(
                    temp_build_dir=directory,
                    options=options,
                    req_tracker=req_tracker,
                    session=session,
                    finder=finder,
                    wheel_download_dir=options.wheel_dir,
                    use_user_site=False,
                )

                resolver = self.make_resolver(
                    preparer=preparer,
                    finder=finder,
                    options=options,
                    wheel_cache=wheel_cache,
                    ignore_requires_python=options.ignore_requires_python,
                    use_pep517=options.use_pep517,
                )

                self.trace_basic_info(finder)

                resolver.resolve(requirement_set)

                reqs_to_build = [
                    r for r in requirement_set.requirements.values()
                    if should_build_for_wheel_command(r)
                ]

                # build wheels
                build_successes, build_failures = build(
                    reqs_to_build,
                    wheel_cache=wheel_cache,
                    build_options=options.build_options or [],
                    global_options=options.global_options or [],
                )
                for req in build_successes:
                    assert req.link and req.link.is_wheel
                    assert req.local_file_path
                    # copy from cache to target directory
                    try:
                        shutil.copy(req.local_file_path, options.wheel_dir)
                    except OSError as e:
                        logger.warning(
                            "Building wheel for %s failed: %s",
                            req.name,
                            e,
                        )
                        build_failures.append(req)
                if len(build_failures) != 0:
                    raise CommandError("Failed to build one or more wheels")
            except PreviousBuildDirError:
                options.no_clean = True
                raise
            finally:
                if not options.no_clean:
                    requirement_set.cleanup_files()
                    wheel_cache.cleanup()
Esempio n. 28
0
    def create(
            cls,
            find_links,  # type: List[str]
            index_urls,  # type: List[str]
            allow_all_prereleases=False,  # type: bool
            trusted_hosts=None,  # type: Optional[Iterable[str]]
            session=None,  # type: Optional[PipSession]
            format_control=None,  # type: Optional[FormatControl]
            platform=None,  # type: Optional[str]
            versions=None,  # type: Optional[List[str]]
            abi=None,  # type: Optional[str]
            implementation=None,  # type: Optional[str]
            prefer_binary=False,  # type: bool
            ignore_requires_python=None,  # type: Optional[bool]
    ):
        # type: (...) -> PackageFinder
        """Create a PackageFinder.

        :param trusted_hosts: Domains that we won't emit warnings for when
            not using HTTPS.
        :param session: The Session to use to make requests.
        :param format_control: A FormatControl object or None. Used to control
            the selection of source packages / binary packages when consulting
            the index and links.
        :param platform: A string or None. If None, searches for packages
            that are supported by the current system. Otherwise, will find
            packages that can be built on the platform passed in. These
            packages will only be downloaded for distribution: they will
            not be built locally.
        :param versions: A list of strings or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        :param abi: A string or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        :param implementation: A string or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        :param prefer_binary: Whether to prefer an old, but valid, binary
            dist over a new source dist.
        :param ignore_requires_python: Whether to ignore incompatible
            "Requires-Python" values in links. Defaults to False.
        """
        if session is None:
            raise TypeError(
                "PackageFinder.create() missing 1 required keyword argument: "
                "'session'")

        # Build find_links. If an argument starts with ~, it may be
        # a local file relative to a home directory. So try normalizing
        # it and if it exists, use the normalized version.
        # This is deliberately conservative - it might be fine just to
        # blindly normalize anything starting with a ~...
        built_find_links = []  # type: List[str]
        for link in find_links:
            if link.startswith('~'):
                new_link = normalize_path(link)
                if os.path.exists(new_link):
                    link = new_link
            built_find_links.append(link)

        secure_origins = [("*", host, "*")
                          for host in (trusted_hosts if trusted_hosts else [])
                          ]  # type: List[SecureOrigin]

        # The valid tags to check potential found wheel candidates against
        valid_tags = get_supported(
            versions=versions,
            platform=platform,
            abi=abi,
            impl=implementation,
        )
        candidate_evaluator = CandidateEvaluator(
            valid_tags=valid_tags,
            prefer_binary=prefer_binary,
            allow_all_prereleases=allow_all_prereleases,
            ignore_requires_python=ignore_requires_python,
        )

        # If we don't have TLS enabled, then WARN if anyplace we're looking
        # relies on TLS.
        if not HAS_TLS:
            for link in itertools.chain(index_urls, built_find_links):
                parsed = urllib_parse.urlparse(link)
                if parsed.scheme == "https":
                    logger.warning(
                        "pip is configured with locations that require "
                        "TLS/SSL, however the ssl module in Python is not "
                        "available.")
                    break

        return cls(
            candidate_evaluator=candidate_evaluator,
            find_links=built_find_links,
            index_urls=index_urls,
            secure_origins=secure_origins,
            session=session,
            format_control=format_control,
        )
Esempio n. 29
0
    def run(self, options, args):
        # type: (Values, List[str]) -> int

        options.ignore_installed = True
        # editable doesn't really make sense for `pip download`, but the bowels
        # of the RequirementSet code require that property.
        options.editables = []

        cmdoptions.check_dist_restriction(options)

        options.download_dir = normalize_path(options.download_dir)

        ensure_dir(options.download_dir)

        session = self.get_default_session(options)

        target_python = make_target_python(options)
        finder = self._build_package_finder(
            options=options,
            session=session,
            target_python=target_python,
        )
        build_delete = (not (options.no_clean or options.build_dir))

        req_tracker = self.enter_context(get_requirement_tracker())

        directory = TempDirectory(
            options.build_dir,
            delete=build_delete,
            kind="download",
            globally_managed=True,
        )

        reqs = self.get_requirements(args, options, finder, session)

        preparer = self.make_requirement_preparer(
            temp_build_dir=directory,
            options=options,
            req_tracker=req_tracker,
            session=session,
            finder=finder,
            download_dir=options.download_dir,
            use_user_site=False,
        )

        resolver = self.make_resolver(
            preparer=preparer,
            finder=finder,
            options=options,
            py_version_info=options.python_version,
        )

        self.trace_basic_info(finder)

        requirement_set = resolver.resolve(
            reqs, check_supported_wheels=True
        )

        downloaded = ' '.join([req.name  # type: ignore
                               for req in requirement_set.requirements.values()
                               if req.successfully_downloaded])
        if downloaded:
            write_output('Successfully downloaded %s', downloaded)

        return SUCCESS
Esempio n. 30
0
    def run(self, options, args):
        options.ignore_installed = True
        # editable doesn't really make sense for `pip download`, but the bowels
        # of the RequirementSet code require that property.
        options.editables = []

        if options.python_version:
            python_versions = [options.python_version]
        else:
            python_versions = None

        dist_restriction_set = any([
            options.python_version,
            options.platform,
            options.abi,
            options.implementation,
        ])
        binary_only = FormatControl(set(), {':all:'})
        no_sdist_dependencies = (options.format_control != binary_only
                                 and not options.ignore_dependencies)
        if dist_restriction_set and no_sdist_dependencies:
            raise CommandError(
                "When restricting platform and interpreter constraints using "
                "--python-version, --platform, --abi, or --implementation, "
                "either --no-deps must be set, or --only-binary=:all: must be "
                "set and --no-binary must not be set (or must be set to "
                ":none:).")

        options.src_dir = os.path.abspath(options.src_dir)
        options.download_dir = normalize_path(options.download_dir)

        ensure_dir(options.download_dir)

        with self._build_session(options) as session:
            finder = self._build_package_finder(
                options=options,
                session=session,
                platform=options.platform,
                python_versions=python_versions,
                abi=options.abi,
                implementation=options.implementation,
            )
            build_delete = (not (options.no_clean or options.build_dir))
            if options.cache_dir and not check_path_owner(options.cache_dir):
                logger.warning(
                    "The directory '%s' or its parent directory is not owned "
                    "by the current user and caching wheels 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

            with TempDirectory(options.build_dir,
                               delete=build_delete,
                               kind="download") as directory:

                requirement_set = RequirementSet(
                    require_hashes=options.require_hashes, )
                self.populate_requirement_set(requirement_set, args, options,
                                              finder, session, self.name, None)

                preparer = RequirementPreparer(
                    build_dir=directory.path,
                    src_dir=options.src_dir,
                    download_dir=options.download_dir,
                    wheel_download_dir=None,
                    progress_bar=options.progress_bar,
                    build_isolation=options.build_isolation,
                )

                resolver = Resolver(
                    preparer=preparer,
                    finder=finder,
                    session=session,
                    wheel_cache=None,
                    use_user_site=False,
                    upgrade_strategy="to-satisfy-only",
                    force_reinstall=False,
                    ignore_dependencies=options.ignore_dependencies,
                    ignore_requires_python=False,
                    ignore_installed=True,
                    isolated=options.isolated_mode,
                )
                resolver.resolve(requirement_set)

                downloaded = SPACE.join([
                    req.name for req in requirement_set.successfully_downloaded
                ])
                if downloaded:
                    logger.info('Successfully downloaded %s', downloaded)

                # Clean up
                if not options.no_clean:
                    requirement_set.cleanup_files()

        return requirement_set
    def from_dist(cls, dist):
        dist_path = normalize_path(dist.location)
        if not dist_is_local(dist):
            logger.info(
                "Not uninstalling %s at %s, outside environment %s",
                dist.key,
                dist_path,
                sys.prefix,
            )
            return cls(dist)

        if dist_path in {p for p in {sysconfig.get_path("stdlib"),
                                     sysconfig.get_path("platstdlib")}
                         if p}:
            logger.info(
                "Not uninstalling %s at %s, as it is in the standard library.",
                dist.key,
                dist_path,
            )
            return cls(dist)

        paths_to_remove = cls(dist)
        develop_egg_link = egg_link_path(dist)
        develop_egg_link_egg_info = '{}.egg-info'.format(
            pkg_resources.to_filename(dist.project_name))
        egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info)
        # Special case for distutils installed package
        distutils_egg_info = getattr(dist._provider, 'path', None)

        # Uninstall cases order do matter as in the case of 2 installs of the
        # same package, pip needs to uninstall the currently detected version
        if (egg_info_exists and dist.egg_info.endswith('.egg-info') and
                not dist.egg_info.endswith(develop_egg_link_egg_info)):
            # if dist.egg_info.endswith(develop_egg_link_egg_info), we
            # are in fact in the develop_egg_link case
            paths_to_remove.add(dist.egg_info)
            if dist.has_metadata('installed-files.txt'):
                for installed_file in dist.get_metadata(
                        'installed-files.txt').splitlines():
                    path = os.path.normpath(
                        os.path.join(dist.egg_info, installed_file)
                    )
                    paths_to_remove.add(path)
            # FIXME: need a test for this elif block
            # occurs with --single-version-externally-managed/--record outside
            # of pip
            elif dist.has_metadata('top_level.txt'):
                if dist.has_metadata('namespace_packages.txt'):
                    namespaces = dist.get_metadata('namespace_packages.txt')
                else:
                    namespaces = []
                for top_level_pkg in [
                        p for p
                        in dist.get_metadata('top_level.txt').splitlines()
                        if p and p not in namespaces]:
                    path = os.path.join(dist.location, top_level_pkg)
                    paths_to_remove.add(path)
                    paths_to_remove.add(path + '.py')
                    paths_to_remove.add(path + '.pyc')
                    paths_to_remove.add(path + '.pyo')

        elif distutils_egg_info:
            raise UninstallationError(
                "Cannot uninstall {!r}. It is a distutils installed project "
                "and thus we cannot accurately determine which files belong "
                "to it which would lead to only a partial uninstall.".format(
                    dist.project_name,
                )
            )

        elif dist.location.endswith('.egg'):
            # package installed by easy_install
            # We cannot match on dist.egg_name because it can slightly vary
            # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg
            paths_to_remove.add(dist.location)
            easy_install_egg = os.path.split(dist.location)[1]
            easy_install_pth = os.path.join(os.path.dirname(dist.location),
                                            'easy-install.pth')
            paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg)

        elif egg_info_exists and dist.egg_info.endswith('.dist-info'):
            for path in uninstallation_paths(dist):
                paths_to_remove.add(path)

        elif develop_egg_link:
            # develop egg
            with open(develop_egg_link, 'r') as fh:
                link_pointer = os.path.normcase(fh.readline().strip())
            assert (link_pointer == dist.location), (
                'Egg-link %s does not match installed location of %s '
                '(at %s)' % (link_pointer, dist.project_name, dist.location)
            )
            paths_to_remove.add(develop_egg_link)
            easy_install_pth = os.path.join(os.path.dirname(develop_egg_link),
                                            'easy-install.pth')
            paths_to_remove.add_pth(easy_install_pth, dist.location)

        else:
            logger.debug(
                'Not sure how to uninstall: %s - Check: %s',
                dist, dist.location,
            )

        # find distutils scripts= scripts
        if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'):
            for script in dist.metadata_listdir('scripts'):
                if dist_in_usersite(dist):
                    bin_dir = bin_user
                else:
                    bin_dir = bin_py
                paths_to_remove.add(os.path.join(bin_dir, script))
                if WINDOWS:
                    paths_to_remove.add(os.path.join(bin_dir, script) + '.bat')

        # find console_scripts
        _scripts_to_remove = []
        console_scripts = dist.get_entry_map(group='console_scripts')
        for name in console_scripts.keys():
            _scripts_to_remove.extend(_script_names(dist, name, False))
        # find gui_scripts
        gui_scripts = dist.get_entry_map(group='gui_scripts')
        for name in gui_scripts.keys():
            _scripts_to_remove.extend(_script_names(dist, name, True))

        for s in _scripts_to_remove:
            paths_to_remove.add(s)

        return paths_to_remove
Esempio n. 32
0
    def run(self, options: Values, args: List[str]) -> int:

        options.ignore_installed = True
        # editable doesn't really make sense for `pip download`, but the bowels
        # of the RequirementSet code require that property.
        options.editables = []

        cmdoptions.check_dist_restriction(options)

        options.download_dir = normalize_path(options.download_dir)
        ensure_dir(options.download_dir)

        session = self.get_default_session(options)

        target_python = make_target_python(options)
        finder = self._build_package_finder(
            options=options,
            session=session,
            target_python=target_python,
            ignore_requires_python=options.ignore_requires_python,
        )

        build_tracker = self.enter_context(get_build_tracker())

        directory = TempDirectory(
            delete=not options.no_clean,
            kind="download",
            globally_managed=True,
        )

        reqs = self.get_requirements(args, options, finder, session)

        preparer = self.make_requirement_preparer(
            temp_build_dir=directory,
            options=options,
            build_tracker=build_tracker,
            session=session,
            finder=finder,
            download_dir=options.download_dir,
            use_user_site=False,
            verbosity=self.verbosity,
        )

        resolver = self.make_resolver(
            preparer=preparer,
            finder=finder,
            options=options,
            ignore_requires_python=options.ignore_requires_python,
            use_pep517=options.use_pep517,
            py_version_info=options.python_version,
        )

        self.trace_basic_info(finder)

        requirement_set = resolver.resolve(reqs, check_supported_wheels=True)

        downloaded: List[str] = []
        for req in requirement_set.requirements.values():
            if req.satisfied_by is None:
                assert req.name is not None
                preparer.save_linked_requirement(req)
                downloaded.append(req.name)
        if downloaded:
            write_output("Successfully downloaded %s", " ".join(downloaded))

        return SUCCESS
Esempio n. 33
0
    def __init__(self, find_links, index_urls, allow_all_prereleases=False,
                 trusted_hosts=None, process_dependency_links=False,
                 session=None, format_control=None, platform=None,
                 versions=None, abi=None, implementation=None):
        """Create a PackageFinder.

        :param format_control: A FormatControl object or None. Used to control
            the selection of source packages / binary packages when consulting
            the index and links.
        :param platform: A string or None. If None, searches for packages
            that are supported by the current system. Otherwise, will find
            packages that can be built on the platform passed in. These
            packages will only be downloaded for distribution: they will
            not be built locally.
        :param versions: A list of strings or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        :param abi: A string or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        :param implementation: A string or None. This is passed directly
            to pep425tags.py in the get_supported() method.
        """
        if session is None:
            raise TypeError(
                "PackageFinder() missing 1 required keyword argument: "
                "'session'"
            )

        # Build find_links. If an argument starts with ~, it may be
        # a local file relative to a home directory. So try normalizing
        # it and if it exists, use the normalized version.
        # This is deliberately conservative - it might be fine just to
        # blindly normalize anything starting with a ~...
        self.find_links = []
        for link in find_links:
            if link.startswith('~'):
                new_link = normalize_path(link)
                if os.path.exists(new_link):
                    link = new_link
            self.find_links.append(link)

        self.index_urls = index_urls
        self.dependency_links = []

        # These are boring links that have already been logged somehow:
        self.logged_links = set()

        self.format_control = format_control or FormatControl(set(), set())

        # Domains that we won't emit warnings for when not using HTTPS
        self.secure_origins = [
            ("*", host, "*")
            for host in (trusted_hosts if trusted_hosts else [])
        ]

        # Do we want to allow _all_ pre-releases?
        self.allow_all_prereleases = allow_all_prereleases

        # Do we process dependency links?
        self.process_dependency_links = process_dependency_links

        # The Session we'll use to make requests
        self.session = session

        # The valid tags to check potential found wheel candidates against
        self.valid_tags = get_supported(
            versions=versions,
            platform=platform,
            abi=abi,
            impl=implementation,
        )

        # If we don't have TLS enabled, then WARN if anyplace we're looking
        # relies on TLS.
        if not HAS_TLS:
            for link in itertools.chain(self.index_urls, self.find_links):
                parsed = urllib_parse.urlparse(link)
                if parsed.scheme == "https":
                    logger.warning(
                        "pip is configured with locations that require "
                        "TLS/SSL, however the ssl module in Python is not "
                        "available."
                    )
                    break
Esempio n. 34
0
    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-rich] %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)