def test_accepts_fails_with_python_versions_mismatch(): 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 _get_min(dependency: Dependency) -> 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 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 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 1 try: return len(self._provider.search_for(dependency)) except ValueError: return 0
def solve(self): # type: () -> 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(): 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 _non_empty_term(self, constraint, is_positive): if constraint.is_empty(): return dep = Dependency(self.dependency.name, constraint) dep.python_versions = str(self.dependency.python_versions) return Term(dep, is_positive)
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_to_pep_508_in_extras(): 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 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
def _update_with_new_method(self, version): from poetry.config.config import Config from poetry.core.packages.dependency import Dependency from poetry.core.packages.project_package import ProjectPackage 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.run()
def handle(self): from poetry.__version__ import __version__ from poetry.core.semver import Version from poetry.utils.env import EnvManager new_update_method = False try: self._check_recommended_installation() except RuntimeError as e: env = EnvManager.get_system_env(naive=True) try: env.path.relative_to(self.data_dir) except ValueError: raise e new_update_method = True 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 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 if release.version == Version.parse(__version__): self.line("You are using the latest version") return if new_update_method: return self.update_with_new_method(release.version) self.update(release)
def test_with_constraint(): dependency = Dependency( "foo", "^1.2.3", optional=True, category="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.category == "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 find_best_candidate( self, package_name, # type: str target_package_version=None, # type: Union[str, None] allow_prereleases=False, # type: bool source=None, # type: str ): # type: (...) -> Union[Package, bool] """ Given a package name and optional version, returns the latest Package that matches """ if target_package_version: constraint = parse_constraint(target_package_version) else: constraint = parse_constraint("*") candidates = self._pool.find_packages( package_name, constraint, allow_prereleases=True, repository=source ) only_prereleases = all([c.version.is_prerelease() for c in candidates]) if not candidates: return False dependency = Dependency(package_name, constraint) package = None for candidate in candidates: if ( candidate.is_prerelease() and not dependency.allows_prereleases() and not allow_prereleases and not only_prereleases ): continue # Select highest version of the two if package is None or package.version < candidate.version: package = candidate if package is None: return False return package
def test_get_package_information_chooses_correct_distribution(): repo = MockRepository() package = repo.package("isort", "4.3.4") assert package.name == "isort" assert package.version.text == "4.3.4" assert package.requires == [Dependency("futures", "*")] futures_dep = package.requires[0] assert futures_dep.python_versions == "~2.7"
def _get_locked(self, dependency: Dependency) -> Optional[Package]: if dependency.name in self._use_latest: return locked = self._locked.get(dependency.name) if not locked: return if not dependency.is_same_package_as(locked): return return locked
def get_dependency(name, constraint=None, category="main", optional=False, allows_prereleases=False): return Dependency( name, constraint or "*", category=category, optional=optional, allows_prereleases=allows_prereleases, )
def test_to_pep_508_combination(): dependency = Dependency("foo", "^1.2,!=1.3.5") assert "foo (>=1.2,<2.0,!=1.3.5)" == dependency.to_pep_508() dependency = Dependency("foo", "~1.2,!=1.2.5") assert "foo (>=1.2,<1.3,!=1.2.5)" == dependency.to_pep_508()
def test_fallback_can_read_setup_to_get_dependencies(): repo = MockRepository(fallback=True) package = repo.package("sqlalchemy", "1.2.12") assert package.name == "sqlalchemy" assert len(package.requires) == 0 assert package.extras == { "mssql_pymssql": [Dependency("pymssql", "*")], "mssql_pyodbc": [Dependency("pyodbc", "*")], "mysql": [Dependency("mysqlclient", "*")], "oracle": [Dependency("cx_oracle", "*")], "postgresql": [Dependency("psycopg2", "*")], "postgresql_pg8000": [Dependency("pg8000", "*")], "postgresql_psycopg2binary": [Dependency("psycopg2-binary", "*")], "postgresql_psycopg2cffi": [Dependency("psycopg2cffi", "*")], "pymysql": [Dependency("pymysql", "*")], }
def handle(self): # type: () -> None from poetry.__version__ import __version__ from poetry.core.semver import Version from poetry.repositories.pypi_repository import PyPiRepository self._check_recommended_installation() version = self.argument("version") if not version: version = ">=" + __version__ repo = PyPiRepository(fallback=False) 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 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 if release.version == Version.parse(__version__): self.line("You are using the latest version") return self.update(release)
def test_to_pep_508(): dependency = Dependency("Django", "^1.23") result = dependency.to_pep_508() assert result == "Django (>=1.23,<2.0)" dependency = Dependency("Django", "^1.23") 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"')
def get_dependency(dep: src_parser.Dependency) -> Dependency: # FIXME: how do deal with extras? extras: List[str] = [] if isinstance(dep, src_parser.VersionedDependency): return Dependency(name=dep.name, constraint=dep.version or "*", extras=dep.extras) elif isinstance(dep, src_parser.URLDependency): return URLDependency( name=dep.name, url=f"{dep.url}#{dep.hashes[0].replace(':','=')}", extras=extras, ) else: raise ValueError(f"Unknown requirement {dep}")
def test_get_package_information_fallback_read_setup(): repo = MockRepository() package = repo.package("jupyter", "1.0.0") assert package.source_type == "legacy" assert package.source_reference == repo.name assert package.source_url == repo.url assert package.name == "jupyter" assert package.version.text == "1.0.0" assert ( package.description == "Jupyter metapackage. Install all the Jupyter components in one go.") if PY35: assert package.requires == [ Dependency("notebook", "*"), Dependency("qtconsole", "*"), Dependency("jupyter-console", "*"), Dependency("nbconvert", "*"), Dependency("ipykernel", "*"), Dependency("ipywidgets", "*"), ]
def find_packages(self, dependency: Dependency) -> List[Package]: """ Find packages on the remote server. """ constraint = dependency.constraint if constraint is None: constraint = "*" if not isinstance(constraint, VersionConstraint): constraint = parse_constraint(constraint) allow_prereleases = dependency.allows_prereleases() if isinstance(constraint, VersionRange): if (constraint.max is not None and constraint.max.is_prerelease() or constraint.min is not None and constraint.min.is_prerelease()): allow_prereleases = True try: info = self.get_package_info(dependency.name) except PackageNotFound: self._log( "No packages found for {} {}".format(dependency.name, str(constraint)), level="debug", ) return [] packages = [] ignored_pre_release_packages = [] for version, release in info["releases"].items(): if not release: # Bad release self._log( "No release information found for {}-{}, skipping".format( dependency.name, version), level="debug", ) continue try: package = Package(info["info"]["name"], version) except ParseVersionError: self._log( 'Unable to parse version "{}" for the {} package, skipping' .format(version, dependency.name), level="debug", ) continue if package.is_prerelease() and not allow_prereleases: if constraint.is_any(): # we need this when all versions of the package are pre-releases ignored_pre_release_packages.append(package) continue if not constraint or (constraint and constraint.allows(package.version)): packages.append(package) self._log( "{} packages found for {} {}".format(len(packages), dependency.name, str(constraint)), level="debug", ) return packages or ignored_pre_release_packages
def test_accepts_fails_with_version_mismatch(): dependency = Dependency("A", "~1.0") package = Package("B", "1.4") assert not dependency.accepts(package)
def test_pypi_repository_supports_reading_bz2_files(): repo = MockRepository(fallback=True) package = repo.package("twisted", "18.9.0") assert package.name == "twisted" assert sorted(package.requires, key=lambda r: r.name) == [ Dependency("attrs", ">=17.4.0"), Dependency("Automat", ">=0.3.0"), Dependency("constantly", ">=15.1"), Dependency("hyperlink", ">=17.1.1"), Dependency("incremental", ">=16.10.1"), Dependency("PyHamcrest", ">=1.9.0"), Dependency("zope.interface", ">=4.4.2"), ] expected_extras = { "all_non_platform": [ Dependency("appdirs", ">=1.4.0"), Dependency("cryptography", ">=1.5"), Dependency("h2", ">=3.0,<4.0"), Dependency("idna", ">=0.6,!=2.3"), Dependency("priority", ">=1.1.0,<2.0"), Dependency("pyasn1", "*"), Dependency("pyopenssl", ">=16.0.0"), Dependency("pyserial", ">=3.0"), Dependency("service_identity", "*"), Dependency("soappy", "*"), ] } for name, deps in expected_extras.items(): assert expected_extras[name] == sorted(package.extras[name], key=lambda r: r.name)
def test_accepts_fails_with_prerelease_mismatch(): dependency = Dependency("A", "^1.0") package = Package("B", "1.4-beta.1") assert not dependency.accepts(package)
def test_get_package_information_skips_dependencies_with_invalid_constraints(): repo = MockRepository() package = repo.package("python-language-server", "0.21.2") assert package.name == "python-language-server" assert package.version.text == "0.21.2" assert ( package.description == "Python Language Server for the Language Server Protocol" ) assert 25 == len(package.requires) assert sorted( [r for r in package.requires if not r.is_optional()], key=lambda r: r.name ) == [ Dependency("configparser", "*"), Dependency("future", ">=0.14.0"), Dependency("futures", "*"), Dependency("jedi", ">=0.12"), Dependency("pluggy", "*"), Dependency("python-jsonrpc-server", "*"), ] all_extra = package.extras["all"] # rope>-0.10.5 should be discarded assert sorted(all_extra, key=lambda r: r.name) == [ Dependency("autopep8", "*"), Dependency("mccabe", "*"), Dependency("pycodestyle", "*"), Dependency("pydocstyle", ">=2.0.0"), Dependency("pyflakes", ">=1.6.0"), Dependency("yapf", "*"), ]
def test_get_package_with_dist_and_universal_py3_wheel(): repo = MockRepository() package = repo.package("ipython", "7.5.0") assert "ipython" == package.name assert "7.5.0" == package.version.text assert ">=3.5" == package.python_versions expected = [ Dependency("appnope", "*"), Dependency("backcall", "*"), Dependency("colorama", "*"), Dependency("decorator", "*"), Dependency("jedi", ">=0.10"), Dependency("pexpect", "*"), Dependency("pickleshare", "*"), Dependency("prompt-toolkit", ">=2.0.0,<2.1.0"), Dependency("pygments", "*"), Dependency("setuptools", ">=18.5"), Dependency("traitlets", ">=4.2"), Dependency("typing", "*"), Dependency("win-unicode-console", ">=0.5"), ] required = [r for r in package.requires if not r.is_optional()] assert expected == sorted(required, key=lambda dep: dep.name)
def test_get_package_from_both_py2_and_py3_specific_wheels(): repo = MockRepository() package = repo.package("ipython", "5.7.0") assert "ipython" == package.name assert "5.7.0" == package.version.text assert "*" == package.python_versions assert 41 == len(package.requires) expected = [ Dependency("appnope", "*"), Dependency("backports.shutil-get-terminal-size", "*"), Dependency("colorama", "*"), Dependency("decorator", "*"), Dependency("pathlib2", "*"), Dependency("pexpect", "*"), Dependency("pickleshare", "*"), Dependency("prompt-toolkit", ">=1.0.4,<2.0.0"), Dependency("pygments", "*"), Dependency("setuptools", ">=18.5"), Dependency("simplegeneric", ">0.8"), Dependency("traitlets", ">=4.2"), Dependency("win-unicode-console", ">=0.5"), ] required = [r for r in package.requires if not r.is_optional()] assert expected == required assert 'python_version == "2.7"' == str(required[1].marker) assert 'sys_platform == "win32" and python_version < "3.6"' == str( required[12].marker ) assert 'python_version == "2.7" or python_version == "3.3"' == str( required[4].marker ) assert 'sys_platform != "win32"' == str(required[5].marker)
def test_accepts(): dependency = Dependency("A", "^1.0") package = Package("A", "1.4") assert dependency.accepts(package)
def test_to_pep_508_wilcard(): dependency = Dependency("Django", "*") result = dependency.to_pep_508() assert result == "Django"