def test_to_pep_508(): dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git") expected = "poetry @ git+https://github.com/python-poetry/poetry.git@master" assert expected == dependency.to_pep_508()
def test_to_pep_508_ssh() -> None: dependency = VCSDependency("poetry", "git", "[email protected]:sdispater/poetry.git") expected = "poetry @ git+ssh://[email protected]/sdispater/poetry.git" assert dependency.to_pep_508() == expected
def search_for_vcs(self, dependency: VCSDependency) -> list[Package]: """ Search for the specifications that match the given VCS dependency. Basically, we clone the repository in a temporary directory and get the information we need by checking out the specified reference. """ if dependency in self._deferred_cache: return [self._deferred_cache[dependency]] package = self.get_package_from_vcs( dependency.vcs, dependency.source, branch=dependency.branch, tag=dependency.tag, rev=dependency.rev, name=dependency.name, ) package.develop = dependency.develop dependency._constraint = package.version dependency._pretty_constraint = package.version.text dependency._source_reference = package.source_reference dependency._source_resolved_reference = package.source_resolved_reference if hasattr(package, "source_subdirectory") and hasattr( dependency, "_source_subdirectory"): # this is supported only for poetry-core >= 1.1.0a7 dependency._source_subdirectory = package.source_subdirectory self._deferred_cache[dependency] = package return [package]
def test_to_pep_508_ssh(): dependency = VCSDependency("poetry", "git", "[email protected]:sdispater/poetry.git") expected = "poetry @ git+ssh://[email protected]/sdispater/poetry.git@master" assert expected == dependency.to_pep_508()
def search_for_vcs(self, dependency: VCSDependency) -> list[Package]: """ Search for the specifications that match the given VCS dependency. Basically, we clone the repository in a temporary directory and get the information we need by checking out the specified reference. """ if dependency in self._deferred_cache: return [self._deferred_cache[dependency]] package = self.get_package_from_vcs( dependency.vcs, dependency.source, branch=dependency.branch, tag=dependency.tag, rev=dependency.rev, source_root=self._source_root or (self._env.path.joinpath("src") if self._env else None), ) self.validate_package_for_dependency(dependency=dependency, package=package) package.develop = dependency.develop dependency._constraint = package.version dependency._pretty_constraint = package.version.text dependency._source_reference = package.source_reference dependency._source_resolved_reference = package.source_resolved_reference dependency._source_subdirectory = package.source_subdirectory self._deferred_cache[dependency] = package return [package]
def test_to_pep_508() -> None: dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git") expected = "poetry @ git+https://github.com/python-poetry/poetry.git" assert dependency.to_pep_508() == expected
def search_for_vcs(self, dependency: VCSDependency) -> List[Package]: """ Search for the specifications that match the given VCS dependency. Basically, we clone the repository in a temporary directory and get the information we need by checking out the specified reference. """ if dependency in self._deferred_cache: return [self._deferred_cache[dependency]] package = self.get_package_from_vcs( dependency.vcs, dependency.source, branch=dependency.branch, tag=dependency.tag, rev=dependency.rev, name=dependency.name, ) package.develop = dependency.develop dependency._constraint = package.version dependency._pretty_constraint = package.version.text self._deferred_cache[dependency] = package return [package]
def test_to_pep_508_with_extras(): dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git") dependency.extras.append("foo") expected = "poetry[foo] @ git+https://github.com/python-poetry/poetry.git@master" assert expected == dependency.to_pep_508()
def test_to_pep_508_in_extras(): dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git") dependency.in_extras.append("foo") expected = 'poetry @ git+https://github.com/python-poetry/poetry.git@master ; extra == "foo"' assert expected == dependency.to_pep_508() dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git") dependency.in_extras.append("foo") dependency.extras.append("bar") expected = 'poetry[bar] @ git+https://github.com/python-poetry/poetry.git@master ; extra == "foo"' assert expected == dependency.to_pep_508() dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git", "b;ar;") dependency.in_extras.append("foo;") expected = 'poetry @ git+https://github.com/python-poetry/poetry.git@b;ar; ; extra == "foo;"' assert expected == dependency.to_pep_508()
def test_to_pep_508_in_extras() -> None: dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git") dependency.in_extras.append("foo") expected = ( 'poetry @ git+https://github.com/python-poetry/poetry.git ; extra == "foo"' ) assert dependency.to_pep_508() == expected dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git", extras=["bar"]) dependency.in_extras.append("foo") expected = ( 'poetry[bar] @ git+https://github.com/python-poetry/poetry.git ; extra == "foo"' ) assert dependency.to_pep_508() == expected dependency = VCSDependency("poetry", "git", "https://github.com/python-poetry/poetry.git", "b;ar;") dependency.in_extras.append("foo;") expected = ( "poetry @ git+https://github.com/python-poetry/poetry.git@b;ar; ; extra ==" ' "foo;"') assert dependency.to_pep_508() == expected
def test_to_pep_508_with_extras() -> None: dependency = VCSDependency( "poetry", "git", "https://github.com/python-poetry/poetry.git", extras=["foo", "bar"], ) expected = "poetry[bar,foo] @ git+https://github.com/python-poetry/poetry.git" assert dependency.to_pep_508() == expected
def test_search_for_vcs_retains_develop_flag(provider: Provider, value: bool): dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git", develop=value) package = provider.search_for_vcs(dependency)[0] assert package.develop == value
def test_category(category): dependency = VCSDependency( "poetry", "git", "https://github.com/python-poetry/poetry.git", category=category, ) assert category == dependency.category
def test_category(groups: list[str]) -> None: dependency = VCSDependency( "poetry", "git", "https://github.com/python-poetry/poetry.git", groups=groups, ) assert dependency.groups == frozenset(groups)
def test_vcs_dependencies_are_equal_if_resolved_references_match() -> None: dependency1 = VCSDependency( "poetry", "git", "https://github.com/python-poetry/poetry.git", branch="develop", resolved_rev="123456", ) dependency2 = VCSDependency( "poetry", "git", "https://github.com/python-poetry/poetry.git", rev="123", resolved_rev="123456", ) assert dependency1 == dependency2
def test_search_for_vcs_read_setup_raises_error_if_no_version(provider, mocker): mocker.patch( "poetry.inspection.info.PackageInfo._pep517_metadata", return_value=PackageInfo(name="demo", version=None), ) dependency = VCSDependency("demo", "git", "https://github.com/demo/no-version.git") with pytest.raises(RuntimeError): provider.search_for_vcs(dependency)
def test_vcs_dependency_can_have_resolved_reference_specified() -> None: dependency = VCSDependency( "poetry", "git", "https://github.com/python-poetry/poetry.git", branch="develop", resolved_rev="123456", ) assert dependency.branch == "develop" assert dependency.source_reference == "develop" assert dependency.source_resolved_reference == "123456"
def test_search_for_vcs_setup_egg_info(provider): dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git") package = provider.search_for_vcs(dependency)[0] assert package.name == "demo" assert package.version.text == "0.1.2" assert package.requires == [get_dependency("pendulum", ">=1.4.4")] assert package.extras == { "foo": [get_dependency("cleo")], "bar": [get_dependency("tomlkit")], }
def test_search_for_vcs_read_setup(provider, mocker): mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv()) dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git") package = provider.search_for_vcs(dependency)[0] assert package.name == "demo" assert package.version.text == "0.1.2" assert package.requires == [get_dependency("pendulum", ">=1.4.4")] assert package.extras == { "foo": [get_dependency("cleo")], "bar": [get_dependency("tomlkit")], }
def test_search_for_vcs_read_setup_with_extras(provider, mocker): mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv()) dependency = VCSDependency( "demo", "git", "https://github.com/demo/demo.git", extras=["foo"] ) package = provider.search_for_vcs(dependency)[0] assert package.name == "demo" assert package.version.text == "0.1.2" required = [r for r in package.requires if not r.is_optional()] optional = [r for r in package.requires if r.is_optional()] assert required == [get_dependency("pendulum", ">=1.4.4")] assert optional == [get_dependency("tomlkit"), get_dependency("cleo")]
def test_search_for_vcs_setup_egg_info(provider: Provider): dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git") package = provider.search_for_direct_origin_dependency(dependency) assert package.name == "demo" assert package.version.text == "0.1.2" required = [r for r in package.requires if not r.is_optional()] optional = [r for r in package.requires if r.is_optional()] assert required == [get_dependency("pendulum", ">=1.4.4")] assert optional == [get_dependency("tomlkit"), get_dependency("cleo")] assert package.extras == { "foo": [get_dependency("cleo")], "bar": [get_dependency("tomlkit")], }
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)
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)
def test_convert_dependencies(): package = Package("foo", "1.2.3") result = SdistBuilder.convert_dependencies( package, [ Dependency("A", "^1.0"), Dependency("B", "~1.0"), Dependency("C", "1.2.3"), VCSDependency("D", "git", "https://github.com/sdispater/d.git"), Dependency("E", "^1.0"), Dependency("F", "^1.0,!=1.3"), ], ) main = [ "A>=1.0,<2.0", "B>=1.0,<1.1", "C==1.2.3", "D @ git+https://github.com/sdispater/d.git@master", "E>=1.0,<2.0", "F>=1.0,<2.0,!=1.3", ] extras = {} assert result == (main, extras) package = Package("foo", "1.2.3") package.extras = {"bar": [Dependency("A", "*")]} result = SdistBuilder.convert_dependencies( package, [ Dependency("A", ">=1.2", optional=True), Dependency("B", "~1.0"), Dependency("C", "1.2.3"), ], ) main = ["B>=1.0,<1.1", "C==1.2.3"] extras = {"bar": ["A>=1.2"]} assert result == (main, extras) c = Dependency("C", "1.2.3") c.python_versions = "~2.7 || ^3.6" d = Dependency("D", "3.4.5", optional=True) d.python_versions = "~2.7 || ^3.4" package.extras = {"baz": [Dependency("D", "*")]} result = SdistBuilder.convert_dependencies( package, [ Dependency("A", ">=1.2", optional=True), Dependency("B", "~1.0"), c, d ], ) main = ["B>=1.0,<1.1"] extra_python = (':python_version >= "2.7" and python_version < "2.8" ' 'or python_version >= "3.6" and python_version < "4.0"') extra_d_dependency = ( 'baz:python_version >= "2.7" and python_version < "2.8" ' 'or python_version >= "3.4" and python_version < "4.0"') extras = {extra_python: ["C==1.2.3"], extra_d_dependency: ["D==3.4.5"]} assert result == (main, extras)
def create_from_pep_508(cls, name: str, relative_to: Path | None = None) -> Dependency: """ Resolve a PEP-508 requirement string to a `Dependency` instance. If a `relative_to` path is specified, this is used as the base directory if the identified dependency is of file or directory type. """ from poetry.core.packages.url_dependency import URLDependency from poetry.core.packages.utils.link import Link from poetry.core.packages.utils.utils import is_archive_file from poetry.core.packages.utils.utils import is_installable_dir from poetry.core.packages.utils.utils import is_url from poetry.core.packages.utils.utils import path_to_url from poetry.core.packages.utils.utils import strip_extras from poetry.core.packages.utils.utils import url_to_path from poetry.core.packages.vcs_dependency import VCSDependency from poetry.core.utils.patterns import wheel_file_re from poetry.core.vcs.git import ParsedUrl from poetry.core.version.requirements import Requirement # Removing comments parts = name.split(" #", 1) name = parts[0].strip() if len(parts) > 1: rest = parts[1] if " ;" in rest: name += " ;" + rest.split(" ;", 1)[1] req = Requirement(name) name = req.name link = None if is_url(name): link = Link(name) elif req.url: link = Link(req.url) else: path_str = os.path.normpath(os.path.abspath(name)) p, extras = strip_extras(path_str) if os.path.isdir(p) and (os.path.sep in name or name.startswith(".")): if not is_installable_dir(p): raise ValueError( f"Directory {name!r} is not installable. File 'setup.py' " "not found.") link = Link(path_to_url(p)) elif is_archive_file(p): link = Link(path_to_url(p)) # it's a local file, dir, or url if link: is_file_uri = link.scheme == "file" is_relative_uri = is_file_uri and re.search(r"\.\./", link.url) # Handle relative file URLs if is_file_uri and is_relative_uri: path = Path(link.path) if relative_to: path = relative_to / path link = Link(path_to_url(path)) # wheel file version = None if link.is_wheel: m = wheel_file_re.match(link.filename) if not m: raise ValueError(f"Invalid wheel name: {link.filename}") name = m.group("name") version = m.group("ver") dep: Dependency | None = None if link.scheme.startswith("git+"): url = ParsedUrl.parse(link.url) dep = VCSDependency( name, "git", url.url, rev=url.rev, directory=url.subdirectory, extras=req.extras, ) elif link.scheme == "git": dep = VCSDependency(name, "git", link.url_without_fragment, extras=req.extras) elif link.scheme in ["http", "https"]: dep = URLDependency(name, link.url, extras=req.extras) elif is_file_uri: # handle RFC 8089 references path = url_to_path(req.url) dep = _make_file_or_dir_dep(name=name, path=path, base=relative_to, extras=req.extras) else: with suppress(ValueError): # this is a local path not using the file URI scheme dep = _make_file_or_dir_dep( name=name, path=Path(req.url), base=relative_to, extras=req.extras, ) if dep is None: dep = Dependency(name, version or "*", extras=req.extras) if version: dep._constraint = parse_constraint(version) else: constraint: VersionConstraint | str if req.pretty_constraint: constraint = req.constraint else: constraint = "*" dep = Dependency(name, constraint, extras=req.extras) if req.marker: dep.marker = req.marker return dep
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