예제 #1
0
 def make_self_candidate(self, editable: bool = True) -> Candidate:
     req = parse_requirement(pip_shims.path_to_url(self.root.as_posix()),
                             editable)
     req.name = self.meta.name
     return Candidate(req,
                      self.environment,
                      name=self.meta.name,
                      version=self.meta.version)
예제 #2
0
 def _identify_candidate(self, candidate: Candidate) -> tuple:
     url = getattr(candidate.req, "url", None)
     return (
         candidate.identify(),
         candidate.version,
         url_without_fragments(url) if url else None,
         candidate.req.editable,
     )
예제 #3
0
 def get_locked_candidates(
     self, section: Optional[str] = None
 ) -> Dict[str, Candidate]:
     if not self.lockfile_file.is_file():
         return {}
     section = section or "default"
     result = {}
     for package in [dict(p) for p in self.lockfile.get("package", [])]:
         if section != "__all__" and section not in package["sections"]:
             continue
         version = package.get("version")
         if version:
             package["version"] = f"=={version}"
         package_name = package.pop("name")
         summary = package.pop("summary", None)
         dependencies = [
             Requirement.from_req_dict(k, v)
             for k, v in package.pop("dependencies", {}).items()
         ]
         req = Requirement.from_req_dict(package_name, dict(package))
         can = Candidate(req, self.environment, name=package_name, version=version)
         can.marker = req.marker
         can.requires_python = str(req.requires_python)
         can.dependencies = dependencies
         can.summary = summary
         can.hashes = {
             item["file"]: item["hash"]
             for item in self.lockfile["metadata"].get(
                 f"{package_name} {version}", []
             )
         } or None
         result[identify(req)] = can
     if section in ("default", "__all__") and self.meta.name:
         result[safe_name(self.meta.name).lower()] = self.make_self_candidate(True)
     return result
예제 #4
0
파일: providers.py 프로젝트: shalevy1/pdm
 def is_satisfied_by(self, requirement: Requirement, candidate: Candidate) -> bool:
     if not requirement.is_named:
         return not candidate.req.is_named and candidate.req.url == requirement.url
     if not candidate.version:
         candidate.get_metadata()
     if getattr(candidate, "_preferred", False) and not candidate._requires_python:
         candidate.requires_python = str(
             self.repository.get_dependencies(candidate)[1]
         )
     allow_prereleases = requirement.allow_prereleases
     if allow_prereleases is None:
         allow_prereleases = self.allow_prereleases
     if allow_prereleases is None:
         # if not specified, should allow what `find_candidates()` returns
         allow_prereleases = True
     return requirement.specifier.contains(
         candidate.version, allow_prereleases
     ) and self.requires_python.is_subset(candidate.requires_python)
예제 #5
0
파일: manager.py 프로젝트: danieleades/pdm
 def install(self, candidate: Candidate) -> None:
     if (self.use_install_cache and candidate.req.is_named
             and candidate.name not in self.NO_CACHE_PACKAGES):
         # Only cache wheels from PyPI
         installer = install_wheel_with_cache
     else:
         installer = install_wheel
     prepared = candidate.prepare(self.environment)
     installer(prepared.build(), self.environment, prepared.direct_url())
예제 #6
0
def editables_candidate(environment: Environment) -> Candidate | None:
    """Return a candidate for `editables` package"""
    with environment.get_finder() as finder:
        best_match = finder.find_best_candidate("editables")
        if best_match.best_candidate is None:
            return None
        return Candidate.from_installation_candidate(
            best_match.best_candidate, parse_requirement("editables"),
            environment)
예제 #7
0
def test_install_with_file_existing(project):
    req = parse_requirement("demo")
    candidate = Candidate(
        req,
        link=Link(
            "http://fixtures.test/artifacts/demo-0.0.1-py2.py3-none-any.whl"),
    )
    (project.environment.packages_path / "lib/demo.py").touch()
    installer = InstallManager(project.environment)
    installer.install(candidate)
예제 #8
0
파일: conftest.py 프로젝트: shalevy1/pdm
    def find_candidates(
        self,
        requirement: Requirement,
        requires_python: PySpecSet = PySpecSet(),
        allow_prereleases: Optional[bool] = None,
        allow_all: bool = False,
    ) -> List[Candidate]:
        if allow_prereleases is None:
            allow_prereleases = requirement.allow_prereleases

        cans = []
        for version, candidate in self._pypi_data.get(requirement.key,
                                                      {}).items():
            c = Candidate(
                requirement,
                self.environment,
                name=requirement.project_name,
                version=version,
            )
            c.requires_python = candidate.get("requires_python", "")
            cans.append(c)

        sorted_cans = sorted(
            (c for c in cans
             if requirement.specifier.contains(c.version, allow_prereleases)),
            key=lambda c: c.version,
            reverse=True,
        )
        if not allow_all:
            sorted_cans = [
                can for can in sorted_cans
                if requires_python.is_subset(can.requires_python)
            ]
        if not sorted_cans and allow_prereleases is None:
            # No non-pre-releases is found, force pre-releases now
            sorted_cans = sorted(
                (c for c in cans
                 if requirement.specifier.contains(c.version, True)),
                key=lambda c: c.version,
                reverse=True,
            )
        return sorted_cans
예제 #9
0
def test_install_wheel_with_inconsistent_dist_info(project):
    req = parse_requirement("pyfunctional")
    candidate = Candidate(
        req,
        link=Link(
            "http://fixtures.test/artifacts/PyFunctional-1.4.3-py3-none-any.whl"
        ),
    )
    installer = InstallManager(project.environment)
    installer.install(candidate)
    assert "pyfunctional" in project.environment.get_working_set()
예제 #10
0
 def _find_candidates(self, requirement: Requirement) -> Iterable[Candidate]:
     sources = self.get_filtered_sources(requirement)
     with self.environment.get_finder(sources, True) as finder, allow_all_wheels():
         cans = [
             Candidate.from_installation_candidate(c, requirement)
             for c in finder.find_all_candidates(requirement.project_name)
         ]
     if not cans:
         raise CandidateNotFound(
             f"Unable to find candidates for {requirement.project_name}. There may "
             "exist some issues with the package name or network condition."
         )
     return cans
예제 #11
0
def test_url_requirement_is_not_cached(project):
    req = parse_requirement("future-fstrings @ http://fixtures.test/artifacts/"
                            "future_fstrings-1.2.0-py2.py3-none-any.whl")
    candidate = Candidate(req)
    installer = InstallManager(project.environment, use_install_cache=True)
    installer.install(candidate)
    cache_path = project.cache(
        "packages") / "future_fstrings-1.2.0-py2.py3-none-any"
    assert not cache_path.is_dir()
    lib_path = project.environment.get_paths()["purelib"]
    assert os.path.isfile(os.path.join(lib_path, "future_fstrings.py"))
    assert os.path.isfile(os.path.join(lib_path, "aaaaa_future_fstrings.pth"))
    dist = project.environment.get_working_set()["future-fstrings"]
    assert dist.read_text("direct_url.json")
예제 #12
0
def test_cache_vcs_immutable_revision(project):
    req = parse_requirement(
        "git+https://github.com/test-root/demo.git@master#egg=demo")
    candidate = Candidate(req)
    wheel = candidate.prepare(project.environment).build()
    with pytest.raises(ValueError):
        Path(wheel).relative_to(project.cache_dir)
    assert candidate.get_revision() == "1234567890abcdef"

    req = parse_requirement(
        "git+https://github.com/test-root/demo.git@1234567890abcdef#egg=demo")
    candidate = Candidate(req)
    wheel = candidate.prepare(project.environment).build()
    assert Path(wheel).relative_to(project.cache_dir)
    assert candidate.get_revision() == "1234567890abcdef"

    # test the revision can be got correctly after cached
    prepared = Candidate(req).prepare(project.environment)
    assert not prepared.ireq.source_dir
    assert prepared.revision == "1234567890abcdef"
예제 #13
0
 def find_matches(
     self,
     identifier: str,
     requirements: Mapping[str, Iterator[Requirement]],
     incompatibilities: Mapping[str, Iterator[Candidate]],
 ) -> Iterable[Candidate]:
     reqs = list(requirements[identifier])
     file_req = next((req for req in reqs if not req.is_named), None)
     incompat = list(incompatibilities[identifier])
     if file_req:
         can = Candidate(file_req, self.repository.environment)
         can.get_metadata()
         candidates = [can]
     else:
         candidates = self.repository.find_candidates(
             reqs[0],
             self.requires_python,
             self.allow_prereleases,
         )
     return [
         can for can in candidates
         if all(self.is_satisfied_by(r, can)
                for r in reqs) and can not in incompat
     ]
예제 #14
0
 def is_satisfied_by(self, requirement: Requirement,
                     candidate: Candidate) -> bool:
     if isinstance(requirement, PythonRequirement):
         return is_python_satisfied_by(requirement, candidate)
     elif candidate.identify() in self.overrides:
         return True
     if not requirement.is_named:
         return not candidate.req.is_named and url_without_fragments(
             candidate.req.url) == url_without_fragments(requirement.url)
     version = candidate.version or candidate.metadata.version
     # Allow prereleases if: 1) it is not specified in the tool settings or
     # 2) the candidate doesn't come from PyPI index.
     allow_prereleases = (self.allow_prereleases in (True, None)
                          or not candidate.req.is_named)
     return requirement.specifier.contains(version, allow_prereleases)
예제 #15
0
    def find_matches(
        self,
        requirement: Requirement,
        requires_python: PySpecSet = PySpecSet(),
        allow_prereleases: Optional[bool] = None,
        allow_all: bool = False,
    ) -> List[Candidate]:
        """Find matching candidates of a requirement.

        :param requirement: the given requirement.
        :param requires_python: the Python version constraint.
        :param allow_prereleases: whether allow prerelease versions, or let us determine
            if not given. If no non-prerelease is available, prereleases will be used.
        :param allow_all: whether allow all wheels.
        :returns: a list of candidates.
        """
        if requirement.is_named:
            return self._find_named_matches(requirement, requires_python,
                                            allow_prereleases)
        else:
            # Fetch metadata so that resolver can know the candidate's name.
            can = Candidate(requirement, self.environment)
            can.get_metadata()
            return [can]
예제 #16
0
def test_invalidate_incompatible_wheel_link(project, index):
    req = parse_requirement("demo")
    prepared = Candidate(req, name="demo",
                         version="0.0.1").prepare(project.environment)
    prepared.obtain(True)
    assert (Path(prepared.wheel).name == prepared.ireq.link.filename ==
            "demo-0.0.1-cp36-cp36m-win_amd64.whl")

    prepared.obtain(False)
    assert (Path(prepared.wheel).name == prepared.ireq.link.filename ==
            "demo-0.0.1-py2.py3-none-any.whl")
예제 #17
0
파일: environment.py 프로젝트: shalevy1/pdm
    def ensure_essential_packages(self) -> None:
        """Ensure wheel and setuptools are available and install if not"""
        from pdm.installers import Installer
        from pdm.models.requirements import parse_requirement
        from pdm.models.candidates import Candidate

        if self._essential_installed:
            return
        installer = Installer(self)
        working_set = self.get_working_set()
        for package in ("setuptools", "wheel"):
            if package in working_set:
                continue
            req = parse_requirement(package)
            candidate = Candidate(req, self, package)
            installer.install(candidate)
        self._essential_installed = True
예제 #18
0
def test_uninstall_commit_rollback(project):
    req = parse_requirement("demo")
    candidate = Candidate(
        req,
        link=Link(
            "http://fixtures.test/artifacts/demo-0.0.1-py2.py3-none-any.whl"),
    )
    installer = InstallManager(project.environment)
    lib_path = project.environment.get_paths()["purelib"]
    installer.install(candidate)
    lib_file = os.path.join(lib_path, "demo.py")
    assert os.path.exists(lib_file)
    remove_paths = installer.get_paths_to_remove(
        project.environment.get_working_set()["demo"])
    remove_paths.remove()
    assert not os.path.exists(lib_file)
    remove_paths.rollback()
    assert os.path.exists(lib_file)
예제 #19
0
def test_uninstall_with_console_scripts(project, use_install_cache):
    req = parse_requirement("celery")
    candidate = Candidate(
        req,
        link=Link(
            "http://fixtures.test/artifacts/celery-4.4.2-py2.py3-none-any.whl"
        ),
    )
    installer = InstallManager(project.environment,
                               use_install_cache=use_install_cache)
    installer.install(candidate)
    celery_script = os.path.join(
        project.environment.get_paths()["scripts"],
        "celery.exe" if os.name == "nt" else "celery",
    )
    assert os.path.exists(celery_script)
    installer.uninstall(project.environment.get_working_set()["celery"])
    assert not os.path.exists(celery_script)
예제 #20
0
def test_invalidate_incompatible_wheel_link(project, index):
    req = parse_requirement("demo")
    candidate = Candidate(req,
                          project.environment,
                          name="demo",
                          version="0.0.1")
    candidate.prepare(True)
    assert (Path(candidate.wheel).name == candidate.link.filename ==
            "demo-0.0.1-cp36-cp36m-win_amd64.whl")

    candidate.prepare()
    assert (Path(candidate.wheel).name == candidate.link.filename ==
            "demo-0.0.1-py2.py3-none-any.whl")
예제 #21
0
def test_vcs_candidate_in_subdirectory(project, is_editable):
    line = ("git+https://github.com/test-root/demo-parent-package.git"
            "@master#egg=package-a&subdirectory=package-a")
    req = parse_requirement(line, is_editable)
    candidate = Candidate(req, project.environment)
    assert candidate.get_dependencies_from_metadata() == ["flask"]
    assert candidate.version == "0.1.0"

    line = ("git+https://github.com/test-root/demo-parent-package.git"
            "@master#egg=package-b&subdirectory=package-b")
    req = parse_requirement(line, is_editable)
    candidate = Candidate(req, project.environment)
    assert candidate.get_dependencies_from_metadata() == ["django"]
    assert candidate.version == "0.1.0"
예제 #22
0
    def find_candidates(
        self,
        requirement: Requirement,
        requires_python: PySpecSet = PySpecSet(),
        allow_prereleases: Optional[bool] = None,
        allow_all: bool = False,
    ) -> Iterable[Candidate]:
        sources = self.get_filtered_sources(requirement)
        # `allow_prereleases` is None means leave it to specifier to decide whether to
        # include prereleases
        if allow_prereleases is None:
            allow_prereleases = requirement.allow_prereleases

        with self.environment.get_finder(sources) as finder, allow_all_wheels():
            cans = [
                Candidate.from_installation_candidate(c, requirement, self.environment)
                for c in finder.find_all_candidates(requirement.project_name)
            ]
        sorted_cans = sorted(
            (
                c
                for c in cans
                if requirement.specifier.contains(c.version, allow_prereleases)
                and (allow_all or requires_python.is_subset(c.requires_python))
            ),
            key=lambda c: (c.version, c.link.is_wheel),
            reverse=True,
        )

        if not sorted_cans and allow_prereleases is None:
            # No non-pre-releases is found, force pre-releases now
            sorted_cans = sorted(
                (
                    c
                    for c in cans
                    if requirement.specifier.contains(c.version, True)
                    and (allow_all or requires_python.is_subset(c.requires_python))
                ),
                key=lambda c: c.version,
                reverse=True,
            )
        return sorted_cans
예제 #23
0
def test_install_wheel_with_data_scripts(project, use_install_cache):
    req = parse_requirement("jmespath")
    candidate = Candidate(
        req,
        link=Link(
            "http://fixtures.test/artifacts/jmespath-0.10.0-py2.py3-none-any.whl"
        ),
    )
    installer = InstallManager(project.environment,
                               use_install_cache=use_install_cache)
    installer.install(candidate)
    bin_path = os.path.join(project.environment.get_paths()["scripts"],
                            "jp.py")
    assert os.path.isfile(bin_path)
    if os.name != "nt":
        assert os.stat(bin_path).st_mode & 0o100

    dist = project.environment.get_working_set()["jmespath"]
    installer.uninstall(dist)
    assert not os.path.exists(bin_path)
예제 #24
0
def test_install_wheel_with_cache(project, invoke):
    supports_symlink = fs_supports_symlink()
    req = parse_requirement("future-fstrings")
    candidate = Candidate(
        req,
        link=Link(
            "http://fixtures.test/artifacts/future_fstrings-1.2.0-py2.py3-none-any.whl"
        ),
    )
    installer = InstallManager(project.environment, use_install_cache=True)
    installer.install(candidate)

    lib_path = project.environment.get_paths()["purelib"]
    if supports_symlink:
        assert os.path.islink(os.path.join(lib_path, "future_fstrings.py"))
        assert os.path.islink(
            os.path.join(lib_path, "aaaaa_future_fstrings.pth"))
    else:
        assert os.path.isfile(os.path.join(lib_path, "future_fstrings.pth"))
        assert os.path.isfile(
            os.path.join(lib_path, "aaaaa_future_fstrings.pth"))

    cache_path = project.cache(
        "packages") / "future_fstrings-1.2.0-py2.py3-none-any"
    assert cache_path.is_dir()
    r = invoke(["run", "python", "-c", "import future_fstrings"], obj=project)
    assert r.exit_code == 0

    dist = project.environment.get_working_set()["future-fstrings"]
    installer.uninstall(dist)
    if supports_symlink:
        assert not os.path.exists(os.path.join(lib_path, "future_fstrings.py"))
        assert not os.path.exists(
            os.path.join(lib_path, "aaaaa_future_fstrings.pth"))
    else:
        assert not os.path.isfile(os.path.join(lib_path,
                                               "future_fstrings.pth"))
        assert not os.path.isfile(
            os.path.join(lib_path, "aaaaa_future_fstrings.pth"))
    assert not dist.read_text("direct_url.json")
    assert not cache_path.exists()
예제 #25
0
def test_sdist_candidate_with_wheel_cache(project, mocker):
    file_link = Link(
        path_to_url((FIXTURES / "artifacts/demo-0.0.1.tar.gz").as_posix()))
    built_path = (FIXTURES /
                  "artifacts/demo-0.0.1-py2.py3-none-any.whl").as_posix()
    wheel_cache = project.make_wheel_cache()
    cache_path = wheel_cache.get_path_for_link(file_link)
    if not Path(cache_path).exists():
        Path(cache_path).mkdir(parents=True)
    shutil.copy2(built_path, cache_path)
    req = parse_requirement(file_link.url)
    candidate = Candidate(req, project.environment)
    downloader = mocker.patch("pdm.models.pip_shims.unpack_url")
    candidate.prepare(True)
    downloader.assert_not_called()
    assert Path(candidate.wheel) == Path(cache_path) / Path(built_path).name

    candidate.wheel = None
    builder = mocker.patch("pdm.builders.WheelBuilder.build")
    candidate.build()
    builder.assert_not_called()
    assert Path(candidate.wheel) == Path(cache_path) / Path(built_path).name
예제 #26
0
def ireq_as_line(ireq: InstallRequirement, environment: Environment) -> str:
    """Formats an `InstallRequirement` instance as a
    PEP 508 dependency string.

    Generic formatter for pretty printing InstallRequirements to the terminal
    in a less verbose way than using its `__str__` method.

    :param :class:`InstallRequirement` ireq: A pip **InstallRequirement** instance.
    :return: A formatted string for prettyprinting
    :rtype: str
    """
    if ireq.editable:
        line = "-e {}".format(ireq.link)
    else:
        if not ireq.req:
            req = parse_requirement("dummy @" + ireq.link.url)  # type: ignore
            req.name = Candidate(req).prepare(environment).metadata.metadata["Name"]
            ireq.req = req  # type: ignore

        line = _requirement_to_str_lowercase_name(ireq)
    if ireq.markers:
        line = f"{line}; {ireq.markers}"

    return line
예제 #27
0
def test_rollback_after_commit(project, caplog):
    caplog.set_level(logging.ERROR, logger="pdm.termui")
    req = parse_requirement("demo")
    candidate = Candidate(
        req,
        link=Link(
            "http://fixtures.test/artifacts/demo-0.0.1-py2.py3-none-any.whl"),
    )
    installer = InstallManager(project.environment)
    lib_path = project.environment.get_paths()["purelib"]
    installer.install(candidate)
    lib_file = os.path.join(lib_path, "demo.py")
    assert os.path.exists(lib_file)
    remove_paths = installer.get_paths_to_remove(
        project.environment.get_working_set()["demo"])
    remove_paths.remove()
    remove_paths.commit()
    assert not os.path.exists(lib_file)
    caplog.clear()
    remove_paths.rollback()
    assert not os.path.exists(lib_file)

    assert any(record.message == "Can't rollback, not uninstalled yet"
               for record in caplog.records)
예제 #28
0
 def _get_dependencies_from_metadata(self, candidate: Candidate) -> CandidateInfo:
     prepared = candidate.prepare(self.environment)
     deps = prepared.get_dependencies_from_metadata()
     requires_python = candidate.requires_python
     summary = prepared.metadata.metadata["Summary"]
     return deps, requires_python, summary
예제 #29
0
def test_parse_project_file_on_build_error_no_dep(project):
    req = parse_requirement(f"{(FIXTURES / 'projects/demo-failure-no-dep').as_posix()}")
    candidate = Candidate(req, project.environment)
    assert candidate.get_dependencies_from_metadata() == []
    assert candidate.name == "demo"
    assert candidate.version == "0.0.1"
예제 #30
0
def test_parse_abnormal_specifiers(project):
    req = parse_requirement(
        "http://fixtures.test/artifacts/celery-4.4.2-py2.py3-none-any.whl"
    )
    candidate = Candidate(req, project.environment)
    assert candidate.get_dependencies_from_metadata()