Example #1
0
 def update_editable(self):
     # type: () -> None
     if not self.link:
         logger.debug(
             "Cannot update repository at %s; repository location is "
             "unknown",
             self.source_dir,
         )
         return
     assert self.editable
     assert self.source_dir
     if self.link.scheme == 'file':
         # Static paths don't get updated
         return
     assert '+' in self.link.url, \
         "bad url: {self.link.url!r}".format(**locals())
     vc_type, url = self.link.url.split('+', 1)
     vcs_backend = vcs.get_backend(vc_type)
     if vcs_backend:
         if not self.link.is_vcs:
             reason = (
                 "This form of VCS requirement is being deprecated: {}."
             ).format(self.link.url)
             replacement = None
             if self.link.url.startswith("git+git@"):
                 replacement = (
                     "git+https://[email protected]/..., "
                     "git+ssh://[email protected]/..., "
                     "or the insecure git+git://[email protected]/...")
             deprecated(reason, replacement, gone_in="21.0", issue=7554)
         hidden_url = hide_url(self.link.url)
         vcs_backend.obtain(self.source_dir, url=hidden_url)
     else:
         assert 0, ('Unexpected version control type (in {}): {}'.format(
             self.link, vc_type))
Example #2
0
def check_invalid_constraint_type(req):
    # type: (InstallRequirement) -> str

    # Check for unsupported forms
    problem = ""
    if not req.name:
        problem = "Unnamed requirements are not allowed as constraints"
    elif req.link:
        problem = "Links are not allowed as constraints"
    elif req.extras:
        problem = "Constraints cannot have extras"

    if problem:
        deprecated(
            reason=(
                "Constraints are only allowed to take the form of a package "
                "name and a version specifier. Other forms were originally "
                "permitted as an accident of the implementation, but were "
                "undocumented. The new implementation of the resolver no "
                "longer supports these forms."),
            replacement=("replacing the constraint with a requirement."),
            # No plan yet for when the new resolver becomes default
            gone_in=None,
            issue=8210)

    return problem
def unpack_url(
        link,  # type: Link
        location,  # type: str
        download,  # type: Downloader
        download_dir=None,  # type: Optional[str]
        hashes=None,  # type: Optional[Hashes]
):
    # type: (...) -> Optional[File]
    """Unpack link into location, downloading if required.

    :param hashes: A Hashes object, one of whose embedded hashes must match,
        or HashMismatch will be raised. If the Hashes is empty, no matches are
        required, and unhashable types of requirements (like VCS ones, which
        would ordinarily raise HashUnsupported) are allowed.
    """
    # non-editable vcs urls
    if link.is_vcs:
        unpack_vcs_link(link, location)
        return None

    # Once out-of-tree-builds are no longer supported, could potentially
    # replace the below condition with `assert not link.is_existing_dir`
    # - unpack_url does not need to be called for in-tree-builds.
    #
    # As further cleanup, _copy_source_tree and accompanying tests can
    # be removed.
    if link.is_existing_dir():
        deprecated(
            "A future pip version will change local packages to be built "
            "in-place without first copying to a temporary directory. "
            "We recommend you use --use-feature=in-tree-build to test "
            "your packages with this new behavior before it becomes the "
            "default.\n",
            replacement=None,
            gone_in="21.3",
            issue=7555)
        if os.path.isdir(location):
            rmtree(location)
        _copy_source_tree(link.file_path, location)
        return None

    # file urls
    if link.is_file:
        file = get_file_url(link, download_dir, hashes=hashes)

    # http urls
    else:
        file = get_http_url(
            link,
            download,
            download_dir,
            hashes=hashes,
        )

    # unpack the archive to the build dir location. even when only downloading
    # archives, they have to be unpacked to parse dependencies, except wheels
    if not link.is_wheel:
        unpack_file(file.path, location, file.content_type)

    return file
Example #4
0
    def run(self, options, args):
        # type: (Values, List[str]) -> int
        skip = set(stdlib_pkgs)
        if not options.freeze_all:
            skip.update(DEV_PKGS)

        if options.excludes:
            skip.update(options.excludes)

        cmdoptions.check_list_path_option(options)

        if options.find_links:
            deprecated(
                "--find-links option in pip freeze is deprecated.",
                replacement=None,
                gone_in="21.2",
                issue=9069,
            )

        for line in freeze(
                requirement=options.requirements,
                find_links=options.find_links,
                local_only=options.local,
                user_only=options.user,
                paths=options.path,
                isolated=options.isolated_mode,
                skip=skip,
                exclude_editable=options.exclude_editable,
        ):
            sys.stdout.write(line + "\n")
        return SUCCESS
def warn_deprecated_install_options(requirement_set, options):
    # type: (RequirementSet, Optional[List[str]]) -> None
    """If any location-changing --install-option arguments were passed for
    requirements or on the command-line, then show a deprecation warning.
    """

    def format_options(option_names):
        # type: (Iterable[str]) -> List[str]
        return ["--{}".format(name.replace("_", "-")) for name in option_names]

    requirements = (
            requirement_set.unnamed_requirements +
            list(requirement_set.requirements.values())
    )

    offenders = []

    for requirement in requirements:
        install_options = requirement.options.get("install_options", [])
        location_options = parse_distutils_args(install_options)
        if location_options:
            offenders.append(
                "{!r} from {}".format(
                    format_options(location_options.keys()), requirement
                )
            )

    if options:
        location_options = parse_distutils_args(options)
        if location_options:
            offenders.append(
                "{!r} from command line".format(
                    format_options(location_options.keys())
                )
            )

    if not offenders:
        return

    deprecated(
        reason=(
            "Location-changing options found in --install-option: {}. "
            "This configuration may cause unexpected behavior and is "
            "unsupported.".format(
                "; ".join(offenders)
            )
        ),
        replacement=(
            "using pip-level options like --user, --prefix, --root, and "
            "--target"
        ),
        gone_in="20.2",
        issue=7309,
    )
Example #6
0
File: index.py Project: jaraco/pip
 def add_dependency_links(self, links):
     # FIXME: this shouldn't be global list this, it should only
     # apply to requirements of the package that specifies the
     # dependency_links value
     # FIXME: also, we should track comes_from (i.e., use Link)
     if self.process_dependency_links:
         deprecated(
             "Dependency Links processing has been deprecated and will be "
             "removed in a future release.",
             replacement="PEP 508 URL dependencies",
             gone_in="19.0",
             issue=4187,
         )
         self.dependency_links.extend(links)
Example #7
0
 def add_dependency_links(self, links):
     # FIXME: this shouldn't be global list this, it should only
     # apply to requirements of the package that specifies the
     # dependency_links value
     # FIXME: also, we should track comes_from (i.e., use Link)
     if self.process_dependency_links:
         deprecated(
             "Dependency Links processing has been deprecated and will be "
             "removed in a future release.",
             replacement="PEP 508 URL dependencies",
             gone_in="19.0",
             issue=4187,
         )
         self.dependency_links.extend(links)
Example #8
0
def test_deprecated_message_reads_well():
    with pytest.raises(PipDeprecationWarning) as exception:
        deprecated(
            "Stop doing this!",
            gone_in="1.0",  # this matches the patched version.
            replacement="to be nicer",
            issue="100000",  # I hope we never reach this number.
        )

    message = exception.value.args[0]

    assert message == ("DEPRECATION: Stop doing this! "
                       "pip 1.0 will remove support for this functionality. "
                       "A possible replacement is to be nicer. "
                       "You can find discussion regarding this at "
                       "https://github.com/pypa/pip/issues/100000.")
Example #9
0
def test_deprecated_message_reads_well():
    with pytest.raises(PipDeprecationWarning) as exception:
        deprecated(
            "Stop doing this!",
            gone_in="1.0",  # this matches the patched version.
            replacement="to be nicer",
            issue="100000",  # I hope we never reach this number.
        )

    message = exception.value.args[0]

    assert message == ("DEPRECATION: Stop doing this! "
                       "This behavior change has been enforced since pip 1.0. "
                       "A possible replacement is to be nicer. "
                       "Discussion can be found at "
                       "https://github.com/pypa/pip/issues/100000.")
Example #10
0
def test_deprecated_message_reads_well_past() -> None:
    with pytest.raises(PipDeprecationWarning) as exception:
        deprecated(
            reason="Stop doing this!",
            gone_in="1.0",  # this matches the patched version.
            replacement="to be nicer",
            feature_flag="magic-8-ball",
            issue=100000,
        )

    message = exception.value.args[0]

    assert message == (
        "DEPRECATION: Stop doing this! "
        "Since pip 1.0, this is no longer supported. "
        "A possible replacement is to be nicer. "
        "Discussion can be found at https://github.com/pypa/pip/issues/100000")
Example #11
0
def test_deprecated_message_contains_information(gone_in, replacement, issue):
    with pytest.warns(PipDeprecationWarning) as record:
        deprecated(
            "Stop doing this!",
            replacement=replacement,
            gone_in=gone_in,
            issue=issue,
        )

    assert len(record) == 1
    message = record[0].message.args[0]

    assert "DEPRECATION: Stop doing this!" in message
    # Ensure non-None values are mentioned.
    for item in [gone_in, replacement, issue]:
        if item is not None:
            assert str(item) in message
Example #12
0
def test_deprecated_raises_error_if_too_old(replacement, issue):
    with pytest.raises(PipDeprecationWarning) as exception:
        deprecated(
            "Stop doing this!",
            gone_in="1.0",  # this matches the patched version.
            replacement=replacement,
            issue=issue,
        )

    message = exception.value.args[0]

    assert "DEPRECATION: Stop doing this!" in message
    assert "1.0" in message
    # Ensure non-None values are mentioned.
    for item in [replacement, issue]:
        if item is not None:
            assert str(item) in message
Example #13
0
    def get_pep_518_info(self):
        """Get PEP 518 build-time requirements.

        Returns the list of the packages required to build the project,
        specified as per PEP 518 within the package. If `pyproject.toml` is not
        present, returns None to signify not using the same.
        """
        if not os.path.isfile(self.pyproject_toml):
            return None

        with io.open(self.pyproject_toml, encoding="utf-8") as f:
            pp_toml = pytoml.load(f)

        # Extract the build requirements
        requires = pp_toml.get("build-system", {}).get("requires", None)

        template = (
            "%s does not comply with PEP 518 since pyproject.toml "
            "does not contain a valid '[build-system].requires' key: %s")

        if requires is None:
            logging.warn(template, self, "it is missing.")
            deprecated(
                "Future versions of pip may reject packages with "
                "pyproject.toml files that do not contain the [build-system]"
                "table and the requires key, as specified in PEP 518.",
                replacement=None,
                gone_in="18.2",
                issue=5416,
            )

            # Currently, we're isolating the build based on the presence of the
            # pyproject.toml file. If the user doesn't specify
            # build-system.requires, assume they intended to use setuptools and
            # wheel for now.
            return ["setuptools", "wheel"]
        else:
            # Error out if it's not a list of strings
            is_list_of_str = isinstance(requires, list) and all(
                isinstance(req, six.string_types) for req in requires)
            if not is_list_of_str:
                raise InstallationError(template %
                                        (self, "it is not a list of strings."))

        # If control flow reaches here, we're good to go.
        return requires
Example #14
0
def parse_links(page: "HTMLPage",
                use_deprecated_html5lib: bool) -> Iterable[Link]:
    """
    Parse an HTML document, and yield its anchor elements as Link objects.
    """
    encoding = page.encoding or "utf-8"

    # Check if the page starts with a valid doctype, to decide whether to use
    # http.parser or (deprecated) html5lib for parsing -- unless explicitly
    # requested to use html5lib.
    if not use_deprecated_html5lib:
        expected_doctype = "<!doctype html>".encode(encoding)
        actual_start = page.content[:len(expected_doctype)]
        if actual_start.decode(encoding).lower() != "<!doctype html>":
            deprecated(
                reason=
                (f"The HTML index page being used ({page.url}) is not a proper "
                 "HTML 5 document. This is in violation of PEP 503 which requires "
                 "these pages to be well-formed HTML 5 documents. Please reach out "
                 "to the owners of this index page, and ask them to update this "
                 "index page to a valid HTML 5 document."),
                replacement=None,
                gone_in="22.2",
                issue=10825,
            )
            use_deprecated_html5lib = True

    if use_deprecated_html5lib:
        yield from _parse_links_html5lib(page)
        return

    parser = HTMLLinkParser()
    parser.feed(page.content.decode(encoding))

    url = page.url
    base_url = parser.base_url or url
    for anchor in parser.anchors:
        link = _create_link_from_element(
            anchor,
            page_url=url,
            base_url=base_url,
        )
        if link is None:
            continue
        yield link
Example #15
0
def get_prefixed_libs(prefix: str) -> List[str]:
    """Return the lib locations under ``prefix``."""
    new_pure, new_plat = _sysconfig.get_prefixed_libs(prefix)
    if _USE_SYSCONFIG:
        return _deduplicated(new_pure, new_plat)

    from . import _distutils

    old_pure, old_plat = _distutils.get_prefixed_libs(prefix)
    old_lib_paths = _deduplicated(old_pure, old_plat)

    # Apple's Python (shipped with Xcode and Command Line Tools) hard-code
    # platlib and purelib to '/Library/Python/X.Y/site-packages'. This will
    # cause serious build isolation bugs when Apple starts shipping 3.10 because
    # pip will install build backends to the wrong location. This tells users
    # who is at fault so Apple may notice it and fix the issue in time.
    if all(_looks_like_apple_library(p) for p in old_lib_paths):
        deprecated(
            reason=(
                "Python distributed by Apple's Command Line Tools incorrectly "
                "patches sysconfig to always point to '/Library/Python'. This "
                "will cause build isolation to operate incorrectly on Python "
                "3.10 or later. Please help report this to Apple so they can "
                "fix this. https://developer.apple.com/bug-reporting/"),
            replacement=None,
            gone_in=None,
        )
        return old_lib_paths

    warned = [
        _warn_if_mismatch(
            pathlib.Path(old_pure),
            pathlib.Path(new_pure),
            key="prefixed-purelib",
        ),
        _warn_if_mismatch(
            pathlib.Path(old_plat),
            pathlib.Path(new_plat),
            key="prefixed-platlib",
        ),
    ]
    if any(warned):
        _log_context(prefix=prefix)

    return old_lib_paths
Example #16
0
    def _determine_file(self, options, need_value):
        # Convert legacy venv_file option to site_file or error
        if options.venv_file and not options.site_file:
            if running_under_virtualenv():
                options.site_file = True
                deprecated(
                    "The --venv option has been deprecated.",
                    replacement="--site",
                    gone_in="19.3",
                )
            else:
                raise PipError(
                    "Legacy --venv option requires a virtual environment. "
                    "Use --site instead."
                )

        file_options = [
            key
            for key, value in (
                (kinds.USER, options.user_file),
                (kinds.GLOBAL, options.global_file),
                (kinds.SITE, options.site_file),
            )
            if value
        ]

        if not file_options:
            if not need_value:
                return None
            # Default to user, unless there's a site file.
            elif any(
                os.path.exists(site_config_file)
                for site_config_file in get_configuration_files()[kinds.SITE]
            ):
                return kinds.SITE
            else:
                return kinds.USER
        elif len(file_options) == 1:
            return file_options[0]

        raise PipError(
            "Need exactly one file to operate upon "
            "(--user, --site, --global) to perform."
        )
Example #17
0
def test_deprecated_message_reads_well_future() -> None:
    with pytest.warns(PipDeprecationWarning) as record:
        deprecated(
            reason="Stop doing this!",
            gone_in="2.0",  # this is greater than the patched version.
            replacement="to be nicer",
            feature_flag="crisis",
            issue=100000,
        )

    assert len(record) == 1
    assert isinstance(record[0].message, PipDeprecationWarning)
    message = record[0].message.args[0]

    assert message == (
        "DEPRECATION: Stop doing this! "
        "pip 2.0 will enforce this behaviour change. "
        "A possible replacement is to be nicer. "
        "You can use the flag --use-feature=crisis to test the upcoming behaviour. "
        "Discussion can be found at https://github.com/pypa/pip/issues/100000")
    def determine_build_failure_suppression(options: Values) -> bool:
        """Determines whether build failures should be suppressed and backtracked on."""
        if "backtrack-on-build-failures" not in options.deprecated_features_enabled:
            return False

        if "legacy-resolver" in options.deprecated_features_enabled:
            raise CommandError("Cannot backtrack with legacy resolver.")

        deprecated(
            reason=
            ("Backtracking on build failures can mask issues related to how "
             "a package generates metadata or builds a wheel. This flag will "
             "be removed in pip 22.2."),
            gone_in=None,
            replacement=
            ("avoiding known-bad versions by explicitly telling pip to ignore them "
             "(either directly as requirements, or via a constraints file)"),
            feature_flag=None,
            issue=10655,
        )
        return True
Example #19
0
 def update_editable(self, obtain=True):
     # type: (bool) -> None
     if not self.link:
         logger.debug(
             "Cannot update repository at %s; repository location is " "unknown",
             self.source_dir,
         )
         return
     assert self.editable
     assert self.source_dir
     if self.link.scheme == "file":
         # Static paths don't get updated
         return
     assert "+" in self.link.url, "bad url: %r" % self.link.url
     vc_type, url = self.link.url.split("+", 1)
     vcs_backend = vcs.get_backend(vc_type)
     if vcs_backend:
         if not self.link.is_vcs:
             reason = (
                 "This form of VCS requirement is being deprecated: {}."
             ).format(self.link.url)
             replacement = None
             if self.link.url.startswith("git+git@"):
                 replacement = (
                     "git+https://[email protected]/..., "
                     "git+ssh://[email protected]/..., "
                     "or the insecure git+git://[email protected]/..."
                 )
             deprecated(reason, replacement, gone_in="21.0", issue=7554)
         hidden_url = hide_url(self.link.url)
         if obtain:
             vcs_backend.obtain(self.source_dir, url=hidden_url)
         else:
             vcs_backend.export(self.source_dir, url=hidden_url)
     else:
         assert 0, "Unexpected version control type (in %s): %s" % (
             self.link,
             vc_type,
         )
    def _determine_file(self, options, need_value):
        # Convert legacy venv_file option to site_file or error
        if options.venv_file and not options.site_file:
            if running_under_virtualenv():
                options.site_file = True
                deprecated(
                    "The --venv option has been deprecated.",
                    replacement="--site",
                    gone_in="19.3",
                )
            else:
                raise PipError(
                    "Legacy --venv option requires a virtual environment. "
                    "Use --site instead."
                )

        file_options = [key for key, value in (
            (kinds.USER, options.user_file),
            (kinds.GLOBAL, options.global_file),
            (kinds.SITE, options.site_file),
        ) if value]

        if not file_options:
            if not need_value:
                return None
            # Default to user, unless there's a site file.
            elif os.path.exists(site_config_file):
                return kinds.SITE
            else:
                return kinds.USER
        elif len(file_options) == 1:
            return file_options[0]

        raise PipError(
            "Need exactly one file to operate upon "
            "(--user, --site, --global) to perform."
        )
Example #21
0
def test_deprecated_message_contains_information(
    gone_in: Optional[str],
    replacement: Optional[str],
    issue: Optional[int],
    feature_flag: Optional[str],
) -> None:
    with pytest.warns(PipDeprecationWarning) as record:
        deprecated(
            reason="Stop doing this!",
            replacement=replacement,
            gone_in=gone_in,
            feature_flag=feature_flag,
            issue=issue,
        )

    assert len(record) == 1
    assert isinstance(record[0].message, PipDeprecationWarning)
    message = record[0].message.args[0]

    assert "DEPRECATION: Stop doing this!" in message
    # Ensure non-None values are mentioned.
    for item in [gone_in, replacement, issue, feature_flag]:
        if item is not None:
            assert str(item) in message
Example #22
0
    def run(self, options, args):
        # type: (Values, List[str]) -> int
        format_control = FormatControl(set(), set())
        wheel_cache = WheelCache(options.cache_dir, format_control)
        skip = set(stdlib_pkgs)
        if not options.freeze_all:
            skip.update(DEV_PKGS)

        if options.excludes:
            skip.update(options.excludes)

        cmdoptions.check_list_path_option(options)

        if options.find_links:
            deprecated(
                "--find-links option in pip freeze is deprecated.",
                replacement=None,
                gone_in="21.2",
                issue=9069,
            )

        freeze_kwargs = dict(
            requirement=options.requirements,
            find_links=options.find_links,
            local_only=options.local,
            user_only=options.user,
            paths=options.path,
            isolated=options.isolated_mode,
            wheel_cache=wheel_cache,
            skip=skip,
            exclude_editable=options.exclude_editable,
        )

        for line in freeze(**freeze_kwargs):
            sys.stdout.write(line + '\n')
        return SUCCESS
Example #23
0
    def resolve(self, root_reqs, check_supported_wheels):

        # type: (List[InstallRequirement], bool) -> RequirementSet

        constraints = {}  # type: Dict[str, Constraint]

        user_requested = set()  # type: Set[str]

        requirements = []

        for req in root_reqs:

            if req.constraint:

                # Ensure we only accept valid constraints

                problem = check_invalid_constraint_type(req)

                if problem:

                    raise InstallationError(problem)

                if not req.match_markers():

                    continue

                name = canonicalize_name(req.name)

                if name in constraints:

                    constraints[name] &= req

                else:

                    constraints[name] = Constraint.from_ireq(req)

            else:

                if req.user_supplied and req.name:

                    user_requested.add(canonicalize_name(req.name))

                r = self.factory.make_requirement_from_install_req(
                    req,
                    requested_extras=(),
                )

                if r is not None:

                    requirements.append(r)

        provider = PipProvider(
            factory=self.factory,
            constraints=constraints,
            ignore_dependencies=self.ignore_dependencies,
            upgrade_strategy=self.upgrade_strategy,
            user_requested=user_requested,
        )

        if "PIP_RESOLVER_DEBUG" in os.environ:

            reporter = PipDebuggingReporter()

        else:

            reporter = PipReporter()

        resolver = RLResolver(provider, reporter)

        try:

            try_to_avoid_resolution_too_deep = 2000000

            self._result = resolver.resolve(
                requirements,
                max_rounds=try_to_avoid_resolution_too_deep,
            )

        except ResolutionImpossible as e:

            error = self.factory.get_installation_error(e)

            six.raise_from(error, e)

        req_set = RequirementSet(check_supported_wheels=check_supported_wheels)

        for candidate in self._result.mapping.values():

            ireq = candidate.get_install_requirement()

            if ireq is None:

                continue

            # Check if there is already an installation under the same name,

            # and set a flag for later stages to uninstall it, if needed.

            installed_dist = self.factory.get_dist_to_uninstall(candidate)

            if installed_dist is None:

                # There is no existing installation -- nothing to uninstall.

                ireq.should_reinstall = False

            elif self.factory.force_reinstall:

                # The --force-reinstall flag is set -- reinstall.

                ireq.should_reinstall = True

            elif installed_dist.parsed_version != candidate.version:

                # The installation is different in version -- reinstall.

                ireq.should_reinstall = True

            elif candidate.is_editable or dist_is_editable(installed_dist):

                # The incoming distribution is editable, or different in

                # editable-ness to installation -- reinstall.

                ireq.should_reinstall = True

            elif candidate.source_link.is_file:

                # The incoming distribution is under file://

                if candidate.source_link.is_wheel:

                    # is a local wheel -- do nothing.

                    logger.info(
                        "%s is already installed with the same version as the "
                        "provided wheel. Use --force-reinstall to force an "
                        "installation of the wheel.",
                        ireq.name,
                    )

                    continue

                looks_like_sdist = (is_archive_file(
                    candidate.source_link.file_path)
                                    and candidate.source_link.ext != ".zip")

                if looks_like_sdist:

                    # is a local sdist -- show a deprecation warning!

                    reason = (
                        "Source distribution is being reinstalled despite an "
                        "installed package having the same name and version as "
                        "the installed package.")

                    replacement = "use --force-reinstall"

                    deprecated(
                        reason=reason,
                        replacement=replacement,
                        gone_in="21.1",
                        issue=8711,
                    )

                # is a local sdist or path -- reinstall

                ireq.should_reinstall = True

            else:

                continue

            link = candidate.source_link

            if link and link.is_yanked:

                # The reason can contain non-ASCII characters, Unicode

                # is required for Python 2.

                msg = ('The candidate selected for download or install is a '
                       'yanked version: {name!r} candidate (version {version} '
                       'at {link})\nReason for being yanked: {reason}').format(
                           name=candidate.name,
                           version=candidate.version,
                           link=link,
                           reason=link.yanked_reason or '<none given>',
                       )

                logger.warning(msg)

            req_set.add_named_requirement(ireq)

        reqs = req_set.all_requirements

        self.factory.preparer.prepare_linked_requirements_more(reqs)

        return req_set
Example #24
0
def parse_req_from_line(name, line_source):
    # type: (str, Optional[str]) -> RequirementParts
    if is_url(name):
        marker_sep = "; "
    else:
        marker_sep = ";"
    if marker_sep in name:
        name, markers_as_string = name.split(marker_sep, 1)
        markers_as_string = markers_as_string.strip()
        if not markers_as_string:
            markers = None
        else:
            markers = Marker(markers_as_string)
    else:
        markers = None
    name = name.strip()
    req_as_string = None
    path = os.path.normpath(os.path.abspath(name))
    link = None
    extras_as_string = None

    if is_url(name):
        link = Link(name)
    else:
        p, extras_as_string = _strip_extras(path)
        url = _get_url_from_path(p, name)
        if url is not None:
            link = Link(url)

    # it's a local file, dir, or url
    if link:
        # Handle relative file URLs
        if link.scheme == "file" and re.search(r"\.\./", link.url):
            link = Link(path_to_url(os.path.normpath(os.path.abspath(link.path))))
        # wheel file
        if link.is_wheel:
            wheel = Wheel(link.filename)  # can raise InvalidWheelFilename
            req_as_string = "{wheel.name}=={wheel.version}".format(**locals())
        else:
            # set the req to the egg fragment.  when it's not there, this
            # will become an 'unnamed' requirement
            req_as_string = link.egg_fragment

    # a requirement specifier
    else:
        req_as_string = name

    extras = convert_extras(extras_as_string)

    def with_source(text):
        # type: (str) -> str
        if not line_source:
            return text
        return "{} (from {})".format(text, line_source)

    if req_as_string is not None:
        try:
            req = Requirement(req_as_string)
        except InvalidRequirement:
            if os.path.sep in req_as_string:
                add_msg = "It looks like a path."
                add_msg += deduce_helpful_msg(req_as_string)
            elif "=" in req_as_string and not any(
                op in req_as_string for op in operators
            ):
                add_msg = "= is not a valid operator. Did you mean == ?"
            else:
                add_msg = ""
            msg = with_source("Invalid requirement: {!r}".format(req_as_string))
            if add_msg:
                msg += "\nHint: {}".format(add_msg)
            raise InstallationError(msg)
        else:
            # Deprecate extras after specifiers: "name>=1.0[extras]"
            # This currently works by accident because _strip_extras() parses
            # any extras in the end of the string and those are saved in
            # RequirementParts
            for spec in req.specifier:
                spec_str = str(spec)
                if spec_str.endswith("]"):
                    msg = "Extras after version '{}'.".format(spec_str)
                    replace = "moving the extras before version specifiers"
                    deprecated(msg, replacement=replace, gone_in="21.0")
    else:
        req = None

    return RequirementParts(req, link, markers, extras)
    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)
Example #26
0
def _emit_egg_deprecation(location: Optional[str]) -> None:
    deprecated(
        reason=f"Loading egg at {location} is deprecated.",
        replacement="to use pip for package installation.",
        gone_in=None,
    )
Example #27
0
def get_scheme(
    dist_name: str,
    user: bool = False,
    home: Optional[str] = None,
    root: Optional[str] = None,
    isolated: bool = False,
    prefix: Optional[str] = None,
) -> Scheme:
    old = _distutils.get_scheme(
        dist_name,
        user=user,
        home=home,
        root=root,
        isolated=isolated,
        prefix=prefix,
    )
    new = _sysconfig.get_scheme(
        dist_name,
        user=user,
        home=home,
        root=root,
        isolated=isolated,
        prefix=prefix,
    )

    base = prefix or home or _default_base(user=user)
    warning_contexts = []
    for k in SCHEME_KEYS:
        # Extra join because distutils can return relative paths.
        old_v = pathlib.Path(base, getattr(old, k))
        new_v = pathlib.Path(getattr(new, k))

        if old_v == new_v:
            continue

        # distutils incorrectly put PyPy packages under ``site-packages/python``
        # in the ``posix_home`` scheme, but PyPy devs said they expect the
        # directory name to be ``pypy`` instead. So we treat this as a bug fix
        # and not warn about it. See bpo-43307 and python/cpython#24628.
        skip_pypy_special_case = (sys.implementation.name == "pypy"
                                  and home is not None
                                  and k in ("platlib", "purelib")
                                  and old_v.parent == new_v.parent
                                  and old_v.name.startswith("python")
                                  and new_v.name.startswith("pypy"))
        if skip_pypy_special_case:
            continue

        # sysconfig's ``osx_framework_user`` does not include ``pythonX.Y`` in
        # the ``include`` value, but distutils's ``headers`` does. We'll let
        # CPython decide whether this is a bug or feature. See bpo-43948.
        skip_osx_framework_user_special_case = (
            user and is_osx_framework() and k == "headers"
            and old_v.parent.parent == new_v.parent
            and old_v.parent.name.startswith("python"))
        if skip_osx_framework_user_special_case:
            continue

        # On Red Hat and derived Linux distributions, distutils is patched to
        # use "lib64" instead of "lib" for platlib.
        if k == "platlib" and _looks_like_red_hat_patched():
            continue

        # Both Debian and Red Hat patch Python to place the system site under
        # /usr/local instead of /usr. Debian also places lib in dist-packages
        # instead of site-packages, but the /usr/local check should cover it.
        skip_linux_system_special_case = (
            not (user or home or prefix)
            and old_v.parts[1:3] == ("usr", "local") and len(new_v.parts) > 1
            and new_v.parts[1] == "usr"
            and (len(new_v.parts) < 3 or new_v.parts[2] != "local") and
            (_looks_like_red_hat_patched() or _looks_like_debian_patched()))
        if skip_linux_system_special_case:
            continue

        # On Python 3.7 and earlier, sysconfig does not include sys.abiflags in
        # the "pythonX.Y" part of the path, but distutils does.
        skip_sysconfig_abiflag_bug = (
            sys.version_info < (3, 8) and not WINDOWS
            and k in ("headers", "platlib", "purelib")
            and tuple(_fix_abiflags(old_v.parts)) == new_v.parts)
        if skip_sysconfig_abiflag_bug:
            continue

        warning_contexts.append((old_v, new_v, f"scheme.{k}"))

    if not warning_contexts:
        return old

    # Check if this path mismatch is caused by distutils config files. Those
    # files will no longer work once we switch to sysconfig, so this raises a
    # deprecation message for them.
    default_old = _distutils.distutils_scheme(
        dist_name,
        user,
        home,
        root,
        isolated,
        prefix,
        ignore_config_files=True,
    )
    if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS):
        deprecated(
            "Configuring installation scheme with distutils config files "
            "is deprecated and will no longer work in the near future. If you "
            "are using a Homebrew or Linuxbrew Python, please see discussion "
            "at https://github.com/Homebrew/homebrew-core/issues/76621",
            replacement=None,
            gone_in=None,
        )
        return old

    # Post warnings about this mismatch so user can report them back.
    for old_v, new_v, key in warning_contexts:
        _warn_mismatched(old_v, new_v, key=key)
    _log_context(user=user, home=home, root=root, prefix=prefix)

    return old
    def main(self, args):
        # type: (List[str]) -> int
        options, args = self.parse_args(args)

        # Set verbosity so that it can be used elsewhere.
        self.verbosity = options.verbose - options.quiet

        level_number = setup_logging(
            verbosity=self.verbosity,
            no_color=options.no_color,
            user_log_file=options.log,
        )

        if sys.version_info[:2] == (3, 4):
            deprecated(
                "Python 3.4 support has been deprecated. pip 19.1 will be the "
                "last one supporting it. Please upgrade your Python as Python "
                "3.4 won't be maintained after March 2019 (cf PEP 429).",
                replacement=None,
                gone_in='19.2',
            )
        elif sys.version_info[:2] == (2, 7):
            message = (
                "A future version of pip will drop support for Python 2.7."
            )
            if platform.python_implementation() == "CPython":
                message = (
                    "Python 2.7 will reach the end of its life on January "
                    "1st, 2020. Please upgrade your Python as Python 2.7 "
                    "won't be maintained after that date. "
                ) + message
            deprecated(message, replacement=None, gone_in=None)

        # TODO: Try to get these passing down from the command?
        #       without resorting to os.environ to hold these.
        #       This also affects isolated builds and it should.

        if options.no_input:
            os.environ['PIP_NO_INPUT'] = '1'

        if options.exists_action:
            os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action)

        if options.require_venv and not self.ignore_require_venv:
            # If a venv is required check if it can really be found
            if not running_under_virtualenv():
                logger.critical(
                    'Could not find an activated virtualenv (required).'
                )
                sys.exit(VIRTUALENV_NOT_FOUND)

        try:
            status = self.run(options, args)
            # FIXME: all commands should return an exit status
            # and when it is done, isinstance is not needed anymore
            if isinstance(status, int):
                return status
        except PreviousBuildDirError as exc:
            logger.critical(str(exc))
            logger.debug('Exception information:', exc_info=True)

            return PREVIOUS_BUILD_DIR_ERROR
        except (InstallationError, UninstallationError, BadCommand) as exc:
            logger.critical(str(exc))
            logger.debug('Exception information:', exc_info=True)

            return ERROR
        except CommandError as exc:
            logger.critical('%s', exc)
            logger.debug('Exception information:', exc_info=True)

            return ERROR
        except BrokenStdoutLoggingError:
            # Bypass our logger and write any remaining messages to stderr
            # because stdout no longer works.
            print('ERROR: Pipe to stdout was broken', file=sys.stderr)
            if level_number <= logging.DEBUG:
                traceback.print_exc(file=sys.stderr)

            return ERROR
        except KeyboardInterrupt:
            logger.critical('Operation cancelled by user')
            logger.debug('Exception information:', exc_info=True)

            return ERROR
        except BaseException:
            logger.critical('Exception:', exc_info=True)

            return UNKNOWN_ERROR
        finally:
            allow_version_check = (
                # Does this command have the index_group options?
                hasattr(options, "no_index") and
                # Is this command allowed to perform this check?
                not (options.disable_pip_version_check or options.no_index)
            )
            # Check if we're using the latest version of pip available
            if allow_version_check:
                session = self._build_session(
                    options,
                    retries=0,
                    timeout=min(5, options.timeout)
                )
                with session:
                    pip_version_check(session, options)

            # Shutdown the logging module
            logging.shutdown()

        return SUCCESS
Example #29
0
 def from_dist(cls, dist, dependency_links):
     location = os.path.normcase(os.path.abspath(dist.location))
     comments = []
     from pip._internal.vcs import vcs, get_src_requirement
     if dist_is_editable(dist) and vcs.get_backend_name(location):
         editable = True
         try:
             req = get_src_requirement(dist, location)
         except InstallationError as exc:
             logger.warning(
                 "Error when trying to get requirement for VCS system %s, "
                 "falling back to uneditable format", exc)
             req = None
         if req is None:
             logger.warning('Could not determine repository location of %s',
                            location)
             comments.append(
                 '## !! Could not determine repository location')
             req = dist.as_requirement()
             editable = False
     else:
         editable = False
         req = dist.as_requirement()
         specs = req.specs
         assert len(specs) == 1 and specs[0][0] in ["==", "==="], \
             'Expected 1 spec with == or ===; specs = %r; dist = %r' % \
             (specs, dist)
         version = specs[0][1]
         ver_match = cls._rev_re.search(version)
         date_match = cls._date_re.search(version)
         if ver_match or date_match:
             svn_backend = vcs.get_backend('svn')
             if svn_backend:
                 svn_location = svn_backend().get_location(
                     dist,
                     dependency_links,
                 )
             if not svn_location:
                 logger.warning(
                     'Warning: cannot find svn location for %s',
                     req,
                 )
                 comments.append(
                     '## FIXME: could not find svn URL in dependency_links '
                     'for this package:')
             else:
                 deprecated(
                     "SVN editable detection based on dependency links "
                     "will be dropped in the future.",
                     replacement=None,
                     gone_in="18.2",
                     issue=4187,
                 )
                 comments.append(
                     '# Installing as editable to satisfy requirement %s:' %
                     req)
                 if ver_match:
                     rev = ver_match.group(1)
                 else:
                     rev = '{%s}' % date_match.group(1)
                 editable = True
                 req = '%s@%s#egg=%s' % (svn_location, rev,
                                         cls.egg_name(dist))
     return cls(dist.project_name, req, editable, comments)
Example #30
0
 def from_dist(cls, dist, dependency_links):
     location = os.path.normcase(os.path.abspath(dist.location))
     comments = []
     from pip._internal.vcs import vcs, get_src_requirement
     if dist_is_editable(dist) and vcs.get_backend_name(location):
         editable = True
         try:
             req = get_src_requirement(dist, location)
         except InstallationError as exc:
             logger.warning(
                 "Error when trying to get requirement for VCS system %s, "
                 "falling back to uneditable format", exc
             )
             req = None
         if req is None:
             logger.warning(
                 'Could not determine repository location of %s', location
             )
             comments.append(
                 '## !! Could not determine repository location'
             )
             req = dist.as_requirement()
             editable = False
     else:
         editable = False
         req = dist.as_requirement()
         specs = req.specs
         assert len(specs) == 1 and specs[0][0] in ["==", "==="], \
             'Expected 1 spec with == or ===; specs = %r; dist = %r' % \
             (specs, dist)
         version = specs[0][1]
         ver_match = cls._rev_re.search(version)
         date_match = cls._date_re.search(version)
         if ver_match or date_match:
             svn_backend = vcs.get_backend('svn')
             if svn_backend:
                 svn_location = svn_backend().get_location(
                     dist,
                     dependency_links,
                 )
             if not svn_location:
                 logger.warning(
                     'Warning: cannot find svn location for %s', req,
                 )
                 comments.append(
                     '## FIXME: could not find svn URL in dependency_links '
                     'for this package:'
                 )
             else:
                 deprecated(
                     "SVN editable detection based on dependency links "
                     "will be dropped in the future.",
                     replacement=None,
                     gone_in="18.2",
                     issue=4187,
                 )
                 comments.append(
                     '# Installing as editable to satisfy requirement %s:' %
                     req
                 )
                 if ver_match:
                     rev = ver_match.group(1)
                 else:
                     rev = '{%s}' % date_match.group(1)
                 editable = True
                 req = '%s@%s#egg=%s' % (
                     svn_location,
                     rev,
                     cls.egg_name(dist)
                 )
     return cls(dist.project_name, req, editable, comments)
Example #31
0
def install(
        install_req,  # type: InstallRequirement
        install_options,  # type: List[str]
        global_options,  # type: Sequence[str]
        root,  # type: Optional[str]
        home,  # type: Optional[str]
        prefix,  # type: Optional[str]
        use_user_site,  # type: bool
        pycompile,  # type: bool
        scheme,  # type: Scheme
):
    # type: (...) -> None
    # Extend the list of global and install options passed on to
    # the setup.py call with the ones from the requirements file.
    # Options specified in requirements file override those
    # specified on the command line, since the last option given
    # to setup.py is the one that is used.
    global_options = list(global_options) + install_req.options.get(
        "global_options", [])
    install_options = list(install_options) + install_req.options.get(
        "install_options", [])

    header_dir = scheme.headers

    with TempDirectory(kind="record") as temp_dir:
        record_filename = os.path.join(temp_dir.path, "install-record.txt")
        install_args = make_setuptools_install_args(
            install_req.setup_py_path,
            global_options=global_options,
            install_options=install_options,
            record_filename=record_filename,
            root=root,
            prefix=prefix,
            header_dir=header_dir,
            home=home,
            use_user_site=use_user_site,
            no_user_config=install_req.isolated,
            pycompile=pycompile,
        )

        runner = runner_with_spinner_message(
            "Running setup.py install for {}".format(install_req.name))
        with indent_log(), install_req.build_env:
            runner(
                cmd=install_args,
                cwd=install_req.unpacked_source_directory,
            )

        if not os.path.exists(record_filename):
            logger.debug("Record file %s not found", record_filename)
            return
        install_req.install_succeeded = True

        # We intentionally do not use any encoding to read the file because
        # setuptools writes the file using distutils.file_util.write_file,
        # which does not specify an encoding.
        with open(record_filename) as f:
            record_lines = f.read().splitlines()

    def prepend_root(path):
        # type: (str) -> str
        if root is None or not os.path.isabs(path):
            return path
        else:
            return change_root(root, path)

    for line in record_lines:
        directory = os.path.dirname(line)
        if directory.endswith(".egg-info"):
            egg_info_dir = prepend_root(directory)
            break
    else:
        deprecated(
            reason=("{} did not indicate that it installed an "
                    ".egg-info directory. Only setup.py projects "
                    "generating .egg-info directories are supported."
                    ).format(install_req),
            replacement=("for maintainers: updating the setup.py of {0}. "
                         "For users: contact the maintainers of {0} to let "
                         "them know to update their setup.py.".format(
                             install_req.name)),
            gone_in="20.2",
            issue=6998,
        )
        # FIXME: put the record somewhere
        return
    new_lines = []
    for line in record_lines:
        filename = line.strip()
        if os.path.isdir(filename):
            filename += os.path.sep
        new_lines.append(os.path.relpath(prepend_root(filename), egg_info_dir))
    new_lines.sort()
    ensure_dir(egg_info_dir)
    inst_files_path = os.path.join(egg_info_dir, "installed-files.txt")
    with open(inst_files_path, "w") as f:
        f.write("\n".join(new_lines) + "\n")
Example #32
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)
Example #33
0
    def install(
            self,
            install_options,  # type: List[str]
            global_options=None,  # type: Optional[Sequence[str]]
            root=None,  # type: Optional[str]
            home=None,  # type: Optional[str]
            prefix=None,  # type: Optional[str]
            warn_script_location=True,  # type: bool
            use_user_site=False,  # type: bool
            pycompile=True  # type: bool
    ):
        # type: (...) -> None
        scheme = get_scheme(
            self.name,
            user=use_user_site,
            home=home,
            root=root,
            isolated=self.isolated,
            prefix=prefix,
        )

        global_options = global_options if global_options is not None else []
        if self.editable:
            install_editable_legacy(
                install_options,
                global_options,
                prefix=prefix,
                home=home,
                use_user_site=use_user_site,
                name=self.name,
                setup_py_path=self.setup_py_path,
                isolated=self.isolated,
                build_env=self.build_env,
                unpacked_source_directory=self.unpacked_source_directory,
            )
            self.install_succeeded = True
            return

        if self.is_wheel:
            assert self.local_file_path
            direct_url = None
            if self.original_link:
                direct_url = direct_url_from_link(
                    self.original_link,
                    self.source_dir,
                    self.original_link_is_in_wheel_cache,
                )
            install_wheel(
                self.name,
                self.local_file_path,
                scheme=scheme,
                req_description=str(self.req),
                pycompile=pycompile,
                warn_script_location=warn_script_location,
                direct_url=direct_url,
                requested=self.user_supplied,
            )
            self.install_succeeded = True
            return

        # TODO: Why don't we do this for editable installs?

        # Extend the list of global and install options passed on to
        # the setup.py call with the ones from the requirements file.
        # Options specified in requirements file override those
        # specified on the command line, since the last option given
        # to setup.py is the one that is used.
        global_options = list(global_options) + self.global_options
        install_options = list(install_options) + self.install_options

        try:
            success = install_legacy(
                install_options=install_options,
                global_options=global_options,
                root=root,
                home=home,
                prefix=prefix,
                use_user_site=use_user_site,
                pycompile=pycompile,
                scheme=scheme,
                setup_py_path=self.setup_py_path,
                isolated=self.isolated,
                req_name=self.name,
                build_env=self.build_env,
                unpacked_source_directory=self.unpacked_source_directory,
                req_description=str(self.req),
            )
        except LegacyInstallFailure as exc:
            self.install_succeeded = False
            six.reraise(*exc.parent)
        except Exception:
            self.install_succeeded = True
            raise

        self.install_succeeded = success

        if success and self.legacy_install_reason == 8368:
            deprecated(
                reason=("{} was installed using the legacy 'setup.py install' "
                        "method, because a wheel could not be built for it.".
                        format(self.name)),
                replacement="to fix the wheel build issue reported above",
                gone_in=None,
                issue=8368,
            )
Example #34
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)
            # 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