def test_accepts_fails_with_python_versions_mismatch() -> None: dependency = Dependency("A", "^1.0") dependency.python_versions = "^3.6" package = Package("B", "1.4") package.python_versions = "~3.5" assert not dependency.accepts(package)
def solve(self) -> SolverResult: """ Finds a set of dependencies that match the root package's constraints, or raises an error if no such set is available. """ start = time.time() root_dependency = Dependency(self._root.name, self._root.version) root_dependency.is_root = True self._add_incompatibility( Incompatibility([Term(root_dependency, False)], RootCause())) try: next = self._root.name while next is not None: self._propagate(next) next = self._choose_package_version() return self._result() except Exception: raise finally: self._log("Version solving took {:.3f} seconds.\n" "Tried {} solutions.".format( time.time() - start, self._solution.attempted_solutions))
def test_accepts_python_versions() -> None: dependency = Dependency("A", "^1.0") dependency.python_versions = "^3.6" package = Package("A", "1.4") package.python_versions = "~3.6" assert dependency.accepts(package)
def dependency_to_specification(dependency: Dependency, specification: BaseSpec) -> BaseSpec: if dependency.is_vcs(): dependency = cast("VCSDependency", dependency) assert dependency.source_url is not None specification[dependency.vcs] = dependency.source_url if dependency.reference: specification["rev"] = dependency.reference elif dependency.is_file() or dependency.is_directory(): assert dependency.source_url is not None specification["path"] = dependency.source_url elif dependency.is_url(): assert dependency.source_url is not None specification["url"] = dependency.source_url elif dependency.pretty_constraint != "*" and not dependency.constraint.is_empty( ): specification["version"] = dependency.pretty_constraint if not dependency.marker.is_any(): specification["markers"] = str(dependency.marker) if dependency.extras: specification["extras"] = sorted(dependency.extras) return specification
def _get_min(dependency: Dependency) -> Tuple[bool, int]: if dependency.name in self._use_latest: # If we're forced to use the latest version of a package, it effectively # only has one version to choose from. return not dependency.marker.is_any(), 1 locked = self._get_locked(dependency) if locked and (dependency.constraint.allows(locked.version) or locked.is_prerelease() and dependency.constraint.allows( locked.version.next_patch())): return not dependency.marker.is_any(), 1 # VCS, URL, File or Directory dependencies # represent a single version if (dependency.is_vcs() or dependency.is_url() or dependency.is_file() or dependency.is_directory()): return not dependency.marker.is_any(), 1 try: return ( not dependency.marker.is_any(), len(self._provider.search_for(dependency)), ) except ValueError: return not dependency.marker.is_any(), 0
def _get_min(dependency: Dependency) -> tuple[bool, int]: if dependency.name in self._use_latest: # If we're forced to use the latest version of a package, it effectively # only has one version to choose from. return not dependency.marker.is_any(), 1 locked = self._get_locked(dependency) if locked: return not dependency.marker.is_any(), 1 # VCS, URL, File or Directory dependencies # represent a single version if ( dependency.is_vcs() or dependency.is_url() or dependency.is_file() or dependency.is_directory() ): return not dependency.marker.is_any(), 1 try: return ( not dependency.marker.is_any(), len(self._dependency_cache.search_for(dependency)), ) except ValueError: return not dependency.marker.is_any(), 0
def test_to_pep_508_with_patch_python_version(python_versions, marker): dependency = Dependency("Django", "^1.23") dependency.python_versions = python_versions expected = "Django (>=1.23,<2.0); {}".format(marker) assert expected == dependency.to_pep_508() assert marker == str(dependency.marker)
def test_marker_properly_unsets_python_constraint() -> None: dependency = Dependency("foo", "^1.2.3") dependency.marker = 'python_version >= "3.6"' # type: ignore[assignment] assert str(dependency.python_constraint) == ">=3.6" dependency.marker = "*" # type: ignore[assignment] assert str(dependency.python_constraint) == "*"
def test_to_pep_508_with_patch_python_version(python_versions: str, marker: str) -> None: dependency = Dependency("Django", "^1.23") dependency.python_versions = python_versions expected = f"Django (>=1.23,<2.0); {marker}" assert dependency.to_pep_508() == expected assert str(dependency.marker) == marker
def test_single_page_repository_find_packages(): repo = MockSinglePageRepository("jax_releases") dep = Dependency("jaxlib", "0.3.7") packages = repo.find_packages(dep) assert len(packages) == 1 package = packages[0] assert package.name == dep.name assert package.to_dependency().to_pep_508() == dep.to_pep_508()
def _compatible_dependency(self, other: Dependency) -> bool: return ( self.dependency.is_root or other.is_root or other.is_same_package_as(self.dependency) or ( # we do this here to indicate direct origin dependencies are # compatible with NVR dependencies self.dependency.complete_name == other.complete_name and self.dependency.is_direct_origin() != other.is_direct_origin() ) )
def test_to_pep_508_in_extras() -> None: dependency = Dependency("Django", "^1.23") dependency.in_extras.append("foo") result = dependency.to_pep_508() assert result == 'Django (>=1.23,<2.0); extra == "foo"' result = dependency.to_pep_508(with_extras=False) assert result == "Django (>=1.23,<2.0)" dependency.in_extras.append("bar") result = dependency.to_pep_508() assert result == 'Django (>=1.23,<2.0); extra == "foo" or extra == "bar"' dependency.python_versions = "~2.7 || ^3.6" result = dependency.to_pep_508() assert (result == "Django (>=1.23,<2.0); " "(" 'python_version >= "2.7" and python_version < "2.8" ' 'or python_version >= "3.6" and python_version < "4.0"' ") " 'and (extra == "foo" or extra == "bar")') result = dependency.to_pep_508(with_extras=False) assert (result == "Django (>=1.23,<2.0); " 'python_version >= "2.7" and python_version < "2.8" ' 'or python_version >= "3.6" and python_version < "4.0"')
def install_plugin(installed: Repository) -> None: package = ProjectPackage("poetry-instance", __version__) plugin = Package("poetry-plugin", "1.2.3") package.add_dependency( Dependency(plugin.name, "^1.2.3", groups=[SelfCommand.ADDITIONAL_PACKAGE_GROUP]) ) content = Factory.create_pyproject_from_package(package) system_pyproject_file = SelfCommand.get_default_system_pyproject_file() system_pyproject_file.write_text(content.as_string(), encoding="utf-8") lock_content = { "package": [ { "name": "poetry-plugin", "version": "1.2.3", "category": "main", "optional": False, "platform": "*", "python-versions": "*", "checksum": [], }, ], "metadata": { "python-versions": "^3.6", "platform": "*", "content-hash": "123456789", "hashes": {"poetry-plugin": []}, }, } system_pyproject_file.parent.joinpath("poetry.lock").write_text( tomlkit.dumps(lock_content), encoding="utf-8" ) installed.add_package(plugin)
def test_it_provides_the_correct_solution(): from poetry.mixology.solutions.solutions import PythonRequirementSolution incompatibility = Incompatibility( [Term(Dependency("foo", "^1.0"), True)], PythonCause("^3.5", ">=3.6") ) exception = SolverProblemError(SolveFailure(incompatibility)) solution = PythonRequirementSolution(exception) title = "Check your dependencies Python requirement." description = """\ The Python requirement can be specified via the `python` or `markers` properties For foo, a possible solution would be to set the `python` property to ">=3.6,<4.0"\ """ links = [ "https://python-poetry.org/docs/dependency-specification/#python-restricted-dependencies", "https://python-poetry.org/docs/dependency-specification/#using-environment-markers", ] assert title == solution.solution_title assert ( description == BufferedIO().remove_format(solution.solution_description).strip() ) assert links == solution.documentation_links
def resolve_source_deps(poetry, package, reqs, frozen=False): # find any source path dev deps and them and their recursive # deps to reqs if poetry.local_config['name'] not in (package.name, package.pretty_name): return source_deps = [] for dep_name, info in poetry.local_config.get('dev-dependencies', {}).items(): if isinstance(info, dict) and 'path' in info: source_deps.append(dep_name) if not source_deps: return from poetry.core.packages.dependency import Dependency dep_map = {d['name']: d for d in poetry.locker.lock_data['package']} seen = set(source_deps) seen.add('setuptools') prefix = '' if frozen else '^' while source_deps: dep = source_deps.pop() if dep not in dep_map: dep = dep.replace('_', '-') version = dep_map[dep]['version'] reqs.append( Dependency(dep, '{}{}'.format(prefix, version)).to_pep_508()) for cdep, cversion in dep_map[dep].get('dependencies', {}).items(): if cdep in seen: continue source_deps.append(cdep) seen.add(cdep)
def test_deprecation_warning(tester: CommandTester, repo: TestRepository) -> None: plugin = Package("poetry-plugin", "1.2.3") repo.add_package(Package("poetry", __version__)) repo.add_package(plugin) package = ProjectPackage("poetry-instance", __version__) package.add_dependency( Dependency(plugin.name, "^1.2.3", groups=[SelfCommand.ADDITIONAL_PACKAGE_GROUP])) content = Factory.create_pyproject_from_package(package) system_pyproject_file = SelfCommand.get_default_system_pyproject_file() system_pyproject_file.write_text(content.as_string(), encoding="utf-8") dependencies = get_self_command_dependencies(locked=False) assert "poetry-plugin" in dependencies tester.execute("poetry-plugin") assert (tester.io.fetch_error() == "This command is deprecated. Use self remove command instead.\n") dependencies = get_self_command_dependencies() assert "poetry-plugin" not in dependencies assert not dependencies
def test_dependency_platform_in(): name = "requests (==2.18.0); sys_platform in 'win32 darwin'" dep = Dependency.create_from_pep_508(name) assert dep.name == "requests" assert str(dep.constraint) == "2.18.0" assert str(dep.marker) == 'sys_platform in "win32 darwin"'
def plugin_package(plugin_package_requires_dist: list[str]) -> Package: package = Package("poetry-plugin", "1.2.3") for requirement in plugin_package_requires_dist: package.add_dependency(Dependency.create_from_pep_508(requirement)) return package
def search_for(self, dependency: Dependency) -> list[DependencyPackage]: """ Search for the specifications that match the given dependency. The specifications in the returned list will be considered in reverse order, so the latest version ought to be last. """ if dependency.is_root: return PackageCollection(dependency, [self._package]) if dependency.is_direct_origin(): packages = [self.search_for_direct_origin_dependency(dependency)] else: packages = self._pool.find_packages(dependency) packages.sort( key=lambda p: ( not p.is_prerelease() and not dependency. allows_prereleases(), p.version, ), reverse=True, ) if not packages: packages = self.search_for_installed_packages(dependency) return PackageCollection(dependency, packages)
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) # compatibility Python < 3.8 # https://docs.python.org/3/library/pathlib.html#methods with suppress(OSError): 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) if dependency is None: # skip since we could not determine requirement continue self._dependencies.append(dependency) return self._dependencies
def _update(self, version: Version) -> None: from poetry.core.packages.dependency import Dependency from poetry.core.packages.project_package import ProjectPackage from poetry.config.config import Config from poetry.installation.installer import Installer from poetry.packages.locker import NullLocker from poetry.repositories.installed_repository import InstalledRepository from poetry.utils.env import EnvManager env = EnvManager.get_system_env(naive=True) installed = InstalledRepository.load(env) root = ProjectPackage("poetry-updater", "0.0.0") root.python_versions = ".".join(str(c) for c in env.version_info[:3]) root.add_dependency(Dependency("poetry", version.text)) installer = Installer( self.io, env, root, NullLocker(self.data_dir.joinpath("poetry.lock"), {}), self.pool, Config(), installed=installed, ) installer.update(True) installer.dry_run(self.option("dry-run")) installer.run()
def test_dependency_from_pep_508_with_python_full_version_pep440_compatible_release_tilde(): name = 'pathlib2 ; python_version ~= "3.4" or python_version < "3"' dep = Dependency.create_from_pep_508(name) assert dep.name == "pathlib2" assert str(dep.constraint) == "*" assert dep.python_versions == "~=3.4 || <3"
def handle(self) -> int: from poetry.__version__ import __version__ from poetry.core.packages.dependency import Dependency from poetry.core.semver.version import Version version = self.argument("version") if not version: version = ">=" + __version__ repo = self.pool.repositories[0] packages = repo.find_packages( Dependency("poetry", version, allows_prereleases=self.option("preview")) ) if not packages: self.line("No release found for the specified version") return 1 packages.sort( key=cmp_to_key( lambda x, y: 0 if x.version == y.version else int(x.version < y.version or -1) ) ) release = None for package in packages: if package.is_prerelease(): if self.option("preview"): release = package break continue release = package break if release is None: self.line("No new release found") return 1 if release.version == Version.parse(__version__): self.line("You are using the latest version") return 0 self.line("Updating <c1>Poetry</c1> to <c2>{}</c2>".format(release.version)) self.line("") self.update(release) self.line("") self.line( "<c1>Poetry</c1> (<c2>{}</c2>) is installed now. Great!".format( release.version ) ) return 0
def test_dependency_python_version_in(): name = "requests (==2.18.0); python_version in '3.3 3.4 3.5'" dep = Dependency.create_from_pep_508(name) assert dep.name == "requests" assert str(dep.constraint) == "2.18.0" assert dep.python_versions == "3.3.* || 3.4.* || 3.5.*" assert str(dep.marker) == 'python_version in "3.3 3.4 3.5"'
def test_dependency_from_pep_508_with_python_full_version_pep440_compatible_release_astrix( ) -> None: name = 'pathlib2 ; python_version == "3.4.*" or python_version < "3"' dep = Dependency.create_from_pep_508(name) assert dep.name == "pathlib2" assert str(dep.constraint) == "*" assert dep.python_versions == "==3.4.* || <3"
def test_dependency_from_pep_508_with_extras(): name = 'requests==2.18.0; extra == "foo" or extra == "bar"' dep = Dependency.create_from_pep_508(name) assert dep.name == "requests" assert str(dep.constraint) == "2.18.0" assert dep.in_extras == ["foo", "bar"] assert str(dep.marker) == 'extra == "foo" or extra == "bar"'
def test_dependency_from_pep_508_with_url(): name = "django-utils @ https://example.com/django-utils-1.0.0.tar.gz" dep = Dependency.create_from_pep_508(name) assert "django-utils" == dep.name assert dep.is_url() assert "https://example.com/django-utils-1.0.0.tar.gz" == dep.url
def test_with_constraint() -> None: dependency = Dependency( "foo", "^1.2.3", optional=True, groups=["dev"], allows_prereleases=True, extras=["bar", "baz"], ) dependency.marker = parse_marker( 'python_version >= "3.6" and python_version < "4.0"') dependency.transitive_marker = parse_marker( 'python_version >= "3.7" and python_version < "4.0"') dependency.python_versions = "^3.6" dependency.transitive_python_versions = "^3.7" new = dependency.with_constraint("^1.2.6") assert new.name == dependency.name assert str(new.constraint) == ">=1.2.6,<2.0.0" assert new.is_optional() assert new.groups == frozenset(["dev"]) assert new.allows_prereleases() assert set(new.extras) == {"bar", "baz"} assert new.marker == dependency.marker assert new.transitive_marker == dependency.transitive_marker assert new.python_constraint == dependency.python_constraint assert new.transitive_python_constraint == dependency.transitive_python_constraint
def test_dependency_from_pep_508_with_single_python_version(): name = 'requests (==2.18.0); python_version == "2.7"' dep = Dependency.create_from_pep_508(name) assert dep.name == "requests" assert str(dep.constraint) == "2.18.0" assert dep.extras == frozenset() assert dep.python_versions == "~2.7" assert str(dep.marker) == 'python_version == "2.7"'
def test_dependency_from_pep_508_with_wheel_url(): name = ( "example_wheel @ https://example.com/example_wheel-14.0.2-py2.py3-none-any.whl" ) dep = Dependency.create_from_pep_508(name) assert "example-wheel" == dep.name assert str(dep.constraint) == "14.0.2"