Exemple #1
0
    def dependencies(self) -> List["Dependency"]:
        if self._dependencies is None:
            # avoid circular dependency when loading DirectoryDependency
            from poetry.core.packages.dependency import Dependency
            from poetry.core.packages.directory_dependency import DirectoryDependency
            from poetry.core.packages.file_dependency import FileDependency

            self._dependencies = []
            for requirement in self.requires:
                dependency = None
                try:
                    dependency = Dependency.create_from_pep_508(requirement)
                except ValueError:
                    # PEP 517 requires can be path if not PEP 508
                    path = Path(requirement)
                    try:
                        if path.is_file():
                            dependency = FileDependency(name=canonicalize_name(
                                path.name),
                                                        path=path)
                        elif path.is_dir():
                            dependency = DirectoryDependency(
                                name=canonicalize_name(path.name), path=path)
                    except OSError:
                        # compatibility Python < 3.8
                        # https://docs.python.org/3/library/pathlib.html#methods
                        pass

                if dependency is None:
                    # skip since we could not determine requirement
                    continue

                self._dependencies.append(dependency)

        return self._dependencies
Exemple #2
0
def test_search_for_file_sdist_with_extras(provider: Provider):
    dependency = FileDependency(
        "demo",
        Path(__file__).parent.parent / "fixtures" / "distributions" /
        "demo-0.1.0.tar.gz",
        extras=["foo"],
    )

    package = provider.search_for_file(dependency)[0]

    assert package.name == "demo"
    assert package.version.text == "0.1.0"

    required = [
        r for r in sorted(package.requires, key=lambda r: r.name)
        if not r.is_optional()
    ]
    optional = [
        r for r in sorted(package.requires, key=lambda r: r.name)
        if r.is_optional()
    ]
    assert required == [get_dependency("pendulum", ">=1.4.4")]
    assert optional == [
        get_dependency("cleo"),
        get_dependency("tomlkit"),
    ]
    assert package.extras == {
        "foo": [get_dependency("cleo")],
        "bar": [get_dependency("tomlkit")],
    }
Exemple #3
0
def test_search_for_file_wheel(provider: Provider):
    dependency = FileDependency(
        "demo",
        Path(__file__).parent.parent / "fixtures" / "distributions" /
        "demo-0.1.0-py2.py3-none-any.whl",
    )

    package = provider.search_for_direct_origin_dependency(dependency)

    assert package.name == "demo"
    assert package.version.text == "0.1.0"

    required = [
        r for r in sorted(package.requires, key=lambda r: r.name)
        if not r.is_optional()
    ]
    optional = [
        r for r in sorted(package.requires, key=lambda r: r.name)
        if r.is_optional()
    ]
    assert required == [get_dependency("pendulum", ">=1.4.4")]
    assert optional == [
        get_dependency("cleo"),
        get_dependency("tomlkit"),
    ]
    assert package.extras == {
        "foo": [get_dependency("cleo")],
        "bar": [get_dependency("tomlkit")],
    }
Exemple #4
0
    def _download_link(self, operation, link):
        package = operation.package

        archive = self._chef.get_cached_archive_for_link(link)
        if archive is link:
            # No cached distributions was found, so we download and prepare it
            try:
                archive = self._download_archive(operation, link)
            except BaseException:
                cache_directory = self._chef.get_cache_directory_for_link(link)
                cached_file = cache_directory.joinpath(link.filename)
                # We can't use unlink(missing_ok=True) because it's not available
                # in pathlib2 for Python 2.7
                if cached_file.exists():
                    cached_file.unlink()

                raise

            # TODO: Check readability of the created archive

            if not link.is_wheel:
                archive = self._chef.prepare(archive)

        if package.files:
            archive_hash = "sha256:" + FileDependency(package.name, archive).hash()
            if archive_hash not in {f["hash"] for f in package.files}:
                raise RuntimeError(
                    "Invalid hash for {} using archive {}".format(package, archive.name)
                )

        return archive
Exemple #5
0
    def _validate_archive_hash(archive: Union[Path, Link],
                               package: "Package") -> str:
        archive_path = (url_to_path(archive.url)
                        if isinstance(archive, Link) else archive)
        file_dep = FileDependency(
            package.name,
            archive_path,
        )
        archive_hash = "sha256:" + file_dep.hash()
        known_hashes = {f["hash"] for f in package.files}

        if archive_hash not in known_hashes:
            raise RuntimeError(
                f"Hash for {package} from archive {archive_path.name} not found in"
                f" known hashes (was: {archive_hash})")

        return archive_hash
Exemple #6
0
    def _search_for_file(self, dependency: FileDependency) -> Package:
        package = self.get_package_from_file(dependency.full_path)

        self.validate_package_for_dependency(dependency=dependency,
                                             package=package)

        if dependency.base is not None:
            package.root_dir = dependency.base

        package.files = [{
            "file": dependency.path.name,
            "hash": "sha256:" + dependency.hash()
        }]

        return package
Exemple #7
0
    def _download_link(self, operation, link):
        package = operation.package

        archive = self._chef.get_cached_archive_for_link(link)
        if archive is link:
            # No cached distributions was found, so we download and prepare it
            try:
                archive = self._download_archive(operation, link)
            except BaseException:
                cache_directory = self._chef.get_cache_directory_for_link(link)
                cached_file = cache_directory.joinpath(link.filename)
                # We can't use unlink(missing_ok=True) because it's not available
                # in pathlib2 for Python 2.7
                if cached_file.exists():
                    cached_file.unlink()

                raise

            # TODO: Check readability of the created archive

            if not link.is_wheel:
                archive = self._chef.prepare(archive)

        if package.files:
            hashes = {f["hash"] for f in package.files}
            hash_types = {h.split(":")[0] for h in hashes}
            archive_hashes = set()
            for hash_type in hash_types:
                archive_hashes.add("{}:{}".format(
                    hash_type,
                    FileDependency(
                        package.name,
                        Path(archive.path)
                        if isinstance(archive, Link) else archive,
                    ).hash(hash_type),
                ))

            if archive_hashes.isdisjoint(hashes):
                raise RuntimeError(
                    "Invalid hashes ({}) for {} using archive {}. Expected one of {}."
                    .format(
                        ", ".join(sorted(archive_hashes)),
                        package,
                        archive.name,
                        ", ".join(sorted(hashes)),
                    ))

        return archive
Exemple #8
0
def test_search_for_file_wheel(provider):
    dependency = FileDependency(
        "demo",
        Path(__file__).parent.parent / "fixtures" / "distributions" /
        "demo-0.1.0-py2.py3-none-any.whl",
    )

    package = provider.search_for_file(dependency)[0]

    assert package.name == "demo"
    assert package.version.text == "0.1.0"
    assert package.requires == [get_dependency("pendulum", ">=1.4.4")]
    assert package.extras == {
        "foo": [get_dependency("cleo")],
        "bar": [get_dependency("tomlkit")],
    }
Exemple #9
0
def test_search_for_file_sdist_with_extras(provider):
    dependency = FileDependency(
        "demo",
        Path(__file__).parent.parent / "fixtures" / "distributions" /
        "demo-0.1.0.tar.gz",
    )
    dependency.extras.append("foo")

    package = provider.search_for_file(dependency)[0]

    assert package.name == "demo"
    assert package.version.text == "0.1.0"
    assert package.requires == [
        get_dependency("pendulum", ">=1.4.4"),
        get_dependency("cleo", optional=True),
    ]
    assert package.extras == {
        "foo": [get_dependency("cleo")],
        "bar": [get_dependency("tomlkit")],
    }
def _make_file_or_dir_dep(
    name: str,
    path: Path,
    base: Path | None = None,
    extras: list[str] | None = None,
) -> FileDependency | DirectoryDependency | None:
    """
    Helper function to create a file or directoru dependency with the given arguments. If
    path is not a file or directory that exists, `None` is returned.
    """
    from poetry.core.packages.directory_dependency import DirectoryDependency
    from poetry.core.packages.file_dependency import FileDependency

    _path = path
    if not path.is_absolute() and base:
        # a base path was specified, so we should respect that
        _path = Path(base) / path

    if _path.is_file():
        return FileDependency(name, path, base=base, extras=extras)
    elif _path.is_dir():
        return DirectoryDependency(name, path, base=base, extras=extras)

    return None
Exemple #11
0
def _make_file_or_dir_dep(
    name: str,
    path: Path,
    base: Optional[Path] = None,
    extras: Optional[List[str]] = None,
) -> Optional[Union["FileDependency", "DirectoryDependency"]]:
    """
    Helper function to create a file or directoru dependency with the given arguments. If
    path is not a file or directory that exists, `None` is returned.
    """
    from .directory_dependency import DirectoryDependency
    from .file_dependency import FileDependency

    _path = path
    if not path.is_absolute() and base:
        # a base path was specified, so we should respect that
        _path = Path(base) / path

    if _path.is_file():
        return FileDependency(name, path, base=base, extras=extras)
    elif _path.is_dir():
        return DirectoryDependency(name, path, base=base, extras=extras)

    return None
Exemple #12
0
    def _export_requirements_txt(
        self,
        cwd,
        output,
        with_hashes=True,
        dev=False,
        extras=None,
        with_credentials=False,
    ):  # type: (Path, Union[IO, str], bool, bool, bool) -> None
        indexes = set()
        content = ""
        packages = self._poetry.locker.locked_repository(dev).packages

        # Build a set of all packages required by our selected extras
        extra_package_names = set(
            get_extra_package_names(
                packages, self._poetry.locker.lock_data.get("extras", {}),
                extras or ()))

        for package in sorted(packages, key=lambda p: p.name):
            # If a package is optional and we haven't opted in to it, continue
            if package.optional and package.name not in extra_package_names:
                continue

            if package.source_type == "git":
                dependency = VCSDependency(
                    package.name,
                    package.source_type,
                    package.source_url,
                    package.source_reference,
                )
                dependency.marker = package.marker
                line = "-e git+{}@{}#egg={}".format(package.source_url,
                                                    package.source_reference,
                                                    package.name)
            elif package.source_type in ["directory", "file", "url"]:
                url = package.source_url
                if package.source_type == "file":
                    dependency = FileDependency(
                        package.name,
                        Path(package.source_url),
                        base=self._poetry.locker.lock.path.parent,
                    )
                    url = Path(
                        os.path.relpath(
                            url, self._poetry.locker.lock.path.parent.as_posix(
                            ))).as_posix()
                elif package.source_type == "directory":
                    dependency = DirectoryDependency(
                        package.name,
                        Path(package.source_url),
                        base=self._poetry.locker.lock.path.parent,
                    )
                    url = Path(
                        os.path.relpath(
                            url, self._poetry.locker.lock.path.parent.as_posix(
                            ))).as_posix()
                else:
                    dependency = URLDependency(package.name,
                                               package.source_url)

                dependency.marker = package.marker

                line = "{}".format(url)
                if package.develop and package.source_type == "directory":
                    line = "-e " + line
            else:
                dependency = package.to_dependency()
                line = "{}=={}".format(package.name, package.version)

            requirement = dependency.to_pep_508()
            if ";" in requirement:
                line += "; {}".format(requirement.split(";")[1].strip())

            if (package.source_type not in {"git", "directory", "file", "url"}
                    and package.source_url):
                indexes.add(package.source_url)

            if package.files and with_hashes:
                hashes = []
                for f in package.files:
                    h = f["hash"]
                    algorithm = "sha256"
                    if ":" in h:
                        algorithm, h = h.split(":")

                        if algorithm not in self.ALLOWED_HASH_ALGORITHMS:
                            continue

                    hashes.append("{}:{}".format(algorithm, h))

                if hashes:
                    line += " \\\n"
                    for i, h in enumerate(hashes):
                        line += "    --hash={}{}".format(
                            h, " \\\n" if i < len(hashes) - 1 else "")

            line += "\n"
            content += line

        if indexes:
            # If we have extra indexes, we add them to the beginning of the output
            indexes_header = ""
            for index in sorted(indexes):
                repository = [
                    r for r in self._poetry.pool.repositories
                    if r.url == index.rstrip("/")
                ][0]
                if (self._poetry.pool.has_default()
                        and repository is self._poetry.pool.repositories[0]):
                    url = (repository.authenticated_url
                           if with_credentials else repository.url)
                    indexes_header = "--index-url {}\n".format(url)
                    continue

                url = (repository.authenticated_url
                       if with_credentials else repository.url)
                indexes_header += "--extra-index-url {}\n".format(url)

            content = indexes_header + "\n" + content

        self._output(content, cwd, output)
Exemple #13
0
    def to_dependency(self) -> Dependency:
        from pathlib import Path

        from poetry.core.packages.dependency import Dependency
        from poetry.core.packages.directory_dependency import DirectoryDependency
        from poetry.core.packages.file_dependency import FileDependency
        from poetry.core.packages.url_dependency import URLDependency
        from poetry.core.packages.vcs_dependency import VCSDependency

        dep: Dependency
        if self.source_type == "directory":
            dep = DirectoryDependency(
                self._name,
                Path(cast(str, self._source_url)),
                groups=list(self._dependency_groups.keys()),
                optional=self.optional,
                base=self.root_dir,
                develop=self.develop,
                extras=self.features,
            )
        elif self.source_type == "file":
            dep = FileDependency(
                self._name,
                Path(cast(str, self._source_url)),
                groups=list(self._dependency_groups.keys()),
                optional=self.optional,
                base=self.root_dir,
                extras=self.features,
            )
        elif self.source_type == "url":
            dep = URLDependency(
                self._name,
                cast(str, self._source_url),
                groups=list(self._dependency_groups.keys()),
                optional=self.optional,
                extras=self.features,
            )
        elif self.source_type == "git":
            dep = VCSDependency(
                self._name,
                self.source_type,
                cast(str, self.source_url),
                rev=self.source_reference,
                resolved_rev=self.source_resolved_reference,
                directory=self.source_subdirectory,
                groups=list(self._dependency_groups.keys()),
                optional=self.optional,
                develop=self.develop,
                extras=self.features,
            )
        else:
            dep = Dependency(self._name, self._version, extras=self.features)

        if not self.marker.is_any():
            dep.marker = self.marker

        if not self.python_constraint.is_any():
            dep.python_versions = self.python_versions

        if not self.is_direct_origin():
            return dep

        return dep.with_constraint(self._version)
Exemple #14
0
    def create_dependency(
        cls,
        name: str,
        constraint: DependencyConstraint,
        groups: list[str] | None = None,
        root_dir: Path | None = None,
    ) -> Dependency:
        from poetry.core.packages.constraints import (
            parse_constraint as parse_generic_constraint, )
        from poetry.core.packages.dependency import Dependency
        from poetry.core.packages.dependency_group import MAIN_GROUP
        from poetry.core.packages.directory_dependency import DirectoryDependency
        from poetry.core.packages.file_dependency import FileDependency
        from poetry.core.packages.url_dependency import URLDependency
        from poetry.core.packages.utils.utils import create_nested_marker
        from poetry.core.packages.vcs_dependency import VCSDependency
        from poetry.core.semver.helpers import parse_constraint
        from poetry.core.version.markers import AnyMarker
        from poetry.core.version.markers import parse_marker

        if groups is None:
            groups = [MAIN_GROUP]

        if constraint is None:
            constraint = "*"

        if isinstance(constraint, dict):
            optional = constraint.get("optional", False)
            python_versions = constraint.get("python")
            platform = constraint.get("platform")
            markers = constraint.get("markers")
            if "allows-prereleases" in constraint:
                message = (
                    f'The "{name}" dependency specifies '
                    'the "allows-prereleases" property, which is deprecated. '
                    'Use "allow-prereleases" instead.')
                warn(message, DeprecationWarning)
                logger.warning(message)

            allows_prereleases = constraint.get(
                "allow-prereleases", constraint.get("allows-prereleases",
                                                    False))

            dependency: Dependency
            if "git" in constraint:
                # VCS dependency
                dependency = VCSDependency(
                    name,
                    "git",
                    constraint["git"],
                    branch=constraint.get("branch", None),
                    tag=constraint.get("tag", None),
                    rev=constraint.get("rev", None),
                    directory=constraint.get("subdirectory", None),
                    groups=groups,
                    optional=optional,
                    develop=constraint.get("develop", False),
                    extras=constraint.get("extras", []),
                )
            elif "file" in constraint:
                file_path = Path(constraint["file"])

                dependency = FileDependency(
                    name,
                    file_path,
                    groups=groups,
                    base=root_dir,
                    extras=constraint.get("extras", []),
                )
            elif "path" in constraint:
                path = Path(constraint["path"])

                if root_dir:
                    is_file = root_dir.joinpath(path).is_file()
                else:
                    is_file = path.is_file()

                if is_file:
                    dependency = FileDependency(
                        name,
                        path,
                        groups=groups,
                        optional=optional,
                        base=root_dir,
                        extras=constraint.get("extras", []),
                    )
                else:
                    dependency = DirectoryDependency(
                        name,
                        path,
                        groups=groups,
                        optional=optional,
                        base=root_dir,
                        develop=constraint.get("develop", False),
                        extras=constraint.get("extras", []),
                    )
            elif "url" in constraint:
                dependency = URLDependency(
                    name,
                    constraint["url"],
                    groups=groups,
                    optional=optional,
                    extras=constraint.get("extras", []),
                )
            else:
                version = constraint["version"]

                dependency = Dependency(
                    name,
                    version,
                    optional=optional,
                    groups=groups,
                    allows_prereleases=allows_prereleases,
                    extras=constraint.get("extras", []),
                )

            marker = parse_marker(markers) if markers else AnyMarker()

            if python_versions:
                marker = marker.intersect(
                    parse_marker(
                        create_nested_marker(
                            "python_version",
                            parse_constraint(python_versions))))

            if platform:
                marker = marker.intersect(
                    parse_marker(
                        create_nested_marker(
                            "sys_platform",
                            parse_generic_constraint(platform))))

            if not marker.is_any():
                dependency.marker = marker

            dependency.source_name = constraint.get("source")
        else:
            dependency = Dependency(name, constraint, groups=groups)

        return dependency
def test_file_dependency_dir():
    with pytest.raises(ValueError):
        FileDependency("demo", DIST_PATH)
def test_file_dependency_wrong_path():
    with pytest.raises(ValueError):
        FileDependency("demo", DIST_PATH / "demo-0.2.0.tar.gz")
def test_default_hash():
    path = DIST_PATH / TEST_FILE
    dep = FileDependency("demo", path)
    SHA_256 = "72e8531e49038c5f9c4a837b088bfcb8011f4a9f76335c8f0654df6ac539b3d6"
    assert dep.hash() == SHA_256
def test_guaranteed_hash(hash_name, expected):
    path = DIST_PATH / TEST_FILE
    dep = FileDependency("demo", path)
    assert dep.hash(hash_name) == expected