def _do_refresh(self): from poetry.puzzle import Solver # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError("Extra [{}] is not specified.".format(extra)) locked_repository = self._locker.locked_repository(True) solver = Solver( self._package, self._pool, locked_repository, locked_repository, self._io, # noqa ) ops = solver.solve(use_latest=[]) local_repo = Repository() self._populate_local_repo(local_repo, ops) self._write_lock_file(local_repo, force=True) return 0
def test_solver_chooses_from_correct_repository_if_forced_and_transitive_dependency( package, installed, locked, io ): package.python_versions = "^3.7" package.add_dependency("foo", "^1.0") package.add_dependency("tomlkit", {"version": "^0.5", "source": "legacy"}) repo = Repository() foo = get_package("foo", "1.0.0") foo.add_dependency("tomlkit", "^0.5.0") repo.add_package(foo) pool = Pool([MockLegacyRepository(), repo, MockPyPIRepository()]) solver = Solver(package, pool, installed, locked, io) ops = solver.solve() check_solver_result( ops, [ {"job": "install", "package": get_package("tomlkit", "0.5.2")}, {"job": "install", "package": foo}, ], ) assert "legacy" == ops[0].package.source_type assert "http://foo.bar" == ops[0].package.source_url assert "" == ops[1].package.source_type assert "" == ops[1].package.source_url
def test_solver_chooses_from_secondary_if_explicit(package, installed, locked, io): package.python_versions = "^3.7" package.add_dependency("clikit", {"version": "^0.2.0", "source": "PyPI"}) pool = Pool() pool.add_repository(MockPyPIRepository(), secondary=True) pool.add_repository(MockLegacyRepository()) solver = Solver(package, pool, installed, locked, io) ops = solver.solve() check_solver_result( ops, [ {"job": "install", "package": get_package("pastel", "0.1.0")}, {"job": "install", "package": get_package("pylev", "1.3.0")}, {"job": "install", "package": get_package("clikit", "0.2.4")}, ], ) assert "legacy" == ops[0].package.source_type assert "http://foo.bar" == ops[0].package.source_url assert "" == ops[1].package.source_type assert "" == ops[1].package.source_url assert "" == ops[2].package.source_type assert "" == ops[2].package.source_url
def test_solver_discards_packages_with_empty_markers( package, installed, locked, io, pool, repo ): package.python_versions = "~2.7 || ^3.4" package.add_dependency( "a", {"version": "^0.1.0", "markers": "python_version >= '3.4'"} ) package_a = get_package("a", "0.1.0") package_a.add_dependency( "b", {"version": "^0.1.0", "markers": "python_version < '3.2'"} ) package_a.add_dependency("c", "^0.2.0") package_b = get_package("b", "0.1.0") package_c = get_package("c", "0.2.0") repo.add_package(package_a) repo.add_package(package_b) repo.add_package(package_c) solver = Solver(package, pool, installed, locked, io) ops = solver.solve() check_solver_result( ops, [ {"job": "install", "package": package_c}, {"job": "install", "package": package_a}, ], )
def test_solver_can_solve_with_legacy_repository_using_proper_dists( package, installed, locked, io): repo = MockLegacyRepository() pool = Pool([repo]) solver = Solver(package, pool, installed, locked, io) package.add_dependency("isort", "4.3.4") ops = solver.solve() check_solver_result( ops, [ { "job": "install", "package": get_package("futures", "3.2.0") }, { "job": "install", "package": get_package("isort", "4.3.4") }, ], ) futures = ops[0].package assert futures.python_versions == ">=2.6, <3"
def _do_refresh(self) -> int: from poetry.puzzle import Solver # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError(f"Extra [{extra}] is not specified.") locked_repository = self._locker.locked_repository() solver = Solver( self._package, self._pool, locked_repository, locked_repository, self._io, ) with solver.provider.use_source_root( source_root=self._env.path.joinpath("src") ): ops = solver.solve(use_latest=[]).calculate_operations() local_repo = Repository() self._populate_local_repo(local_repo, ops) self._write_lock_file(local_repo, force=True) return 0
def handle(self): from poetry.packages import Dependency from poetry.packages import ProjectPackage from poetry.puzzle import Solver from poetry.repositories.repository import Repository from poetry.semver import parse_constraint packages = self.argument("package") if not packages: package = self.poetry.package else: requirements = self._determine_requirements(packages) requirements = self._format_requirements(requirements) # validate requirements format for constraint in requirements.values(): parse_constraint(constraint) dependencies = [] for name, constraint in requirements.items(): dep = Dependency(name, constraint) extras = [] for extra in self.option("extras"): if " " in extra: extras += [e.strip() for e in extra.split(" ")] else: extras.append(extra) for ex in extras: dep.extras.append(ex) dependencies.append(dep) package = ProjectPackage(self.poetry.package.name, self.poetry.package.version) package.python_versions = (self.option("python") or self.poetry.package.python_versions) for dep in dependencies: package.requires.append(dep) solver = Solver(package, self.poetry.pool, Repository(), Repository(), self.output) ops = solver.solve() self.line("") self.line("Resolution results:") self.line("") for op in ops: package = op.package self.line(" - <info>{}</info> (<comment>{}</comment>)".format( package.name, package.version)) if package.requirements: for req_name, req_value in package.requirements.items(): self.line(" - {}: {}".format(req_name, req_value))
def test_solver_skips_invalid_versions(package, installed, locked, io): package.python_versions = "^3.7" repo = MockPyPIRepository() pool = Pool([repo]) solver = Solver(package, pool, installed, locked, io) package.add_dependency("trackpy", "^0.4") ops = solver.solve() check_solver_result( ops, [{"job": "install", "package": get_package("trackpy", "0.4.1")}] )
def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_dists( package, installed, locked, io ): package.python_versions = "^3.7" repo = MockLegacyRepository() pool = Pool([repo]) solver = Solver(package, pool, installed, locked, io) package.add_dependency("isort", "4.3.4") ops = solver.solve() check_solver_result( ops, [{"job": "install", "package": get_package("isort", "4.3.4")}] )
def test_solver_chooses_most_recent_version_amongst_repositories( package, installed, locked, io ): package.python_versions = "^3.7" package.add_dependency("tomlkit", {"version": "^0.5"}) repo = MockLegacyRepository() pool = Pool([repo, MockPyPIRepository()]) solver = Solver(package, pool, installed, locked, io) ops = solver.solve() check_solver_result( ops, [{"job": "install", "package": get_package("tomlkit", "0.5.3")}] ) assert "" == ops[0].package.source_type assert "" == ops[0].package.source_url
def test_solver_chooses_from_correct_repository_if_forced( package, installed, locked, io ): package.python_versions = "^3.7" package.add_dependency("tomlkit", {"version": "^0.5", "source": "legacy"}) repo = MockLegacyRepository() pool = Pool([repo, MockPyPIRepository()]) solver = Solver(package, pool, installed, locked, io) ops = solver.solve() check_solver_result( ops, [{"job": "install", "package": get_package("tomlkit", "0.5.2")}] ) assert "legacy" == ops[0].package.source_type assert "http://foo.bar" == ops[0].package.source_url
def handle(self): packages = self.argument('package') if not packages: package = self.poetry.package dependencies = package.requires + package.dev_requires else: requirements = self._determine_requirements(packages) requirements = self._format_requirements(requirements) # validate requirements format parser = VersionParser() for constraint in requirements.values(): parser.parse_constraints(constraint) dependencies = [] for name, constraint in requirements.items(): dependencies.append( Dependency(name, constraint) ) solver = Solver( self.poetry.package, self.poetry.pool, Repository(), self.output ) ops = solver.solve(dependencies) self.line('') self.line('Resolution results:') self.line('') for op in ops: package = op.package self.line(f' - <info>{package.name}</info> ' f'(<comment>{package.version}</comment>)')
def handle(self): from poetry.packages import ProjectPackage from poetry.puzzle import Solver from poetry.repositories.repository import Repository from poetry.semver import parse_constraint from poetry.utils.env import EnvManager packages = self.argument("package") if not packages: package = self.poetry.package else: # Using current pool for determine_requirements() self._pool = self.poetry.pool package = ProjectPackage(self.poetry.package.name, self.poetry.package.version) # Silencing output is_quiet = self.io.output.is_quiet() if not is_quiet: self.io.output.set_quiet(True) requirements = self._determine_requirements(packages) if not is_quiet: self.io.output.set_quiet(False) for constraint in requirements: name = constraint.pop("name") dep = package.add_dependency(name, constraint) extras = [] for extra in self.option("extras"): if " " in extra: extras += [e.strip() for e in extra.split(" ")] else: extras.append(extra) for ex in extras: dep.extras.append(ex) package.python_versions = self.option("python") or ( self.poetry.package.python_versions) pool = self.poetry.pool solver = Solver(package, pool, Repository(), Repository(), self._io) ops = solver.solve() self.line("") self.line("Resolution results:") self.line("") if self.option("tree"): show_command = self.application.find("show") show_command.init_styles(self.io) packages = [op.package for op in ops] repo = Repository(packages) requires = package.requires + package.dev_requires for pkg in repo.packages: for require in requires: if pkg.name == require.name: show_command.display_package_tree(self.io, pkg, repo) break return 0 env = EnvManager(self.poetry.config).get(self.poetry.file.parent) current_python_version = parse_constraint(".".join( str(v) for v in env.version_info)) table = self.table([], style="borderless") rows = [] for op in ops: pkg = op.package if self.option("install"): if not pkg.python_constraint.allows( current_python_version) or not env.is_valid_for_marker( pkg.marker): continue row = [ "<info>{}</info>".format(pkg.name), "<b>{}</b>".format(pkg.version), "", ] if not pkg.marker.is_any(): row[2] = str(pkg.marker) rows.append(row) table.set_rows(rows) table.render(self.io)
def handle(self): from poetry.packages import ProjectPackage from poetry.puzzle import Solver from poetry.repositories.repository import Repository from poetry.semver import parse_constraint from poetry.utils.env import Env packages = self.argument("package") if not packages: package = self.poetry.package else: package = ProjectPackage(self.poetry.package.name, self.poetry.package.version) requirements = self._format_requirements(packages) for name, constraint in requirements.items(): dep = package.add_dependency(name, constraint) extras = [] for extra in self.option("extras"): if " " in extra: extras += [e.strip() for e in extra.split(" ")] else: extras.append(extra) for ex in extras: dep.extras.append(ex) package.python_versions = self.option("python") or ( self.poetry.package.python_versions) pool = self.poetry.pool solver = Solver(package, pool, Repository(), Repository(), self.output) ops = solver.solve() self.line("") self.line("Resolution results:") self.line("") if self.option("tree"): show_command = self.get_application().find("show") show_command.output = self.output show_command.init_styles() packages = [op.package for op in ops] repo = Repository(packages) requires = package.requires + package.dev_requires for pkg in repo.packages: for require in requires: if pkg.name == require.name: show_command.display_package_tree(pkg, repo) break return 0 env = Env.get() current_python_version = parse_constraint(".".join( str(v) for v in env.version_info)) for op in ops: pkg = op.package if self.option("install"): if not pkg.python_constraint.allows( current_python_version) or not env.is_valid_for_marker( pkg.marker): continue self.line(" - <info>{}</info> (<comment>{}</comment>)".format( pkg.name, pkg.version)) if not pkg.python_constraint.is_any(): self.line(" - python: {}".format(pkg.python_versions)) if not pkg.marker.is_any(): self.line(" - marker: {}".format(pkg.marker))
def solve_pypi( pip_specs: Dict[str, src_parser.Dependency], use_latest: List[str], pip_locked: Dict[str, src_parser.LockedDependency], conda_locked: Dict[str, src_parser.LockedDependency], python_version: str, platform: str, verbose: bool = False, ) -> Dict[str, src_parser.LockedDependency]: """ Solve pip dependencies for the given platform Parameters ---------- conda : Path to conda, mamba, or micromamba use_latest : Names of packages to update to the latest version compatible with pip_specs pip_specs : PEP440 package specifications pip_locked : Previous solution for the given platform (pip packages only) conda_locked : Current solution of conda-only specs for the given platform python_version : Version of Python in conda_locked platform : Target platform verbose : Print chatter from solver """ dummy_package = ProjectPackage("_dummy_package_", "0.0.0") dependencies = [get_dependency(spec) for spec in pip_specs.values()] for dep in dependencies: dummy_package.add_dependency(dep) pypi = PyPiRepository() pool = Pool(repositories=[pypi]) installed = Repository() locked = Repository() python_packages = dict() for dep in conda_locked.values(): if dep.name.startswith("__"): continue try: pypi_name = conda_name_to_pypi_name(dep.name).lower() except KeyError: continue # Prefer the Python package when its name collides with the Conda package # for the underlying library, e.g. python-xxhash (pypi: xxhash) over xxhash # (pypi: no equivalent) if pypi_name not in python_packages or pypi_name != dep.name: python_packages[pypi_name] = dep.version # treat conda packages as both locked and installed for name, version in python_packages.items(): for repo in (locked, installed): repo.add_package(Package(name=name, version=version)) # treat pip packages as locked only for spec in pip_locked.values(): locked.add_package(get_package(spec)) if verbose: io = ConsoleIO() io.set_verbosity(VERY_VERBOSE) else: io = NullIO() s = Solver( dummy_package, pool=pool, installed=installed, locked=locked, io=io, ) to_update = list({spec.name for spec in pip_locked.values() }.intersection(use_latest)) env = PlatformEnv(python_version, platform) # find platform-specific solution (e.g. dependencies conditioned on markers) with s.use_environment(env): result = s.solve(use_latest=to_update) chooser = Chooser(pool, env=env) # Extract distributions from Poetry package plan, ignoring uninstalls # (usually: conda package with no pypi equivalent) and skipped ops # (already installed) requirements: List[src_parser.LockedDependency] = [] for op in result: if not isinstance(op, Uninstall) and not op.skipped: # Take direct references verbatim source: Optional[src_parser.DependencySource] = None if op.package.source_type == "url": url, fragment = urldefrag(op.package.source_url) hash_type, hash = fragment.split("=") hash = src_parser.HashModel(**{hash_type: hash}) source = src_parser.DependencySource(type="url", url=op.package.source_url) # Choose the most specific distribution for the target else: link = chooser.choose_for(op.package) url = link.url_without_fragment hash = src_parser.HashModel(**{link.hash_name: link.hash}) requirements.append( src_parser.LockedDependency( name=op.package.name, version=str(op.package.version), manager="pip", source=source, platform=platform, dependencies={ dep.name: str(dep.constraint) for dep in op.package.requires }, url=url, hash=hash, )) # use PyPI names of conda packages to walking the dependency tree and propagate # categories from explicit to transitive dependencies planned = { **{dep.name: dep for dep in requirements}, # prefer conda packages so add them afterwards } for conda_name, dep in conda_locked.items(): try: pypi_name = conda_name_to_pypi_name(conda_name).lower() except KeyError: # no conda-name found, assuming conda packages do NOT intersect with the pip package continue planned[pypi_name] = dep src_parser._apply_categories(requested=pip_specs, planned=planned) return {dep.name: dep for dep in requirements}
def handle(self): from poetry.packages import Dependency from poetry.packages import ProjectPackage from poetry.puzzle import Solver from poetry.repositories.repository import Repository from poetry.semver import parse_constraint packages = self.argument("package") if not packages: package = self.poetry.package else: requirements = self._determine_requirements(packages) requirements = self._format_requirements(requirements) # validate requirements format for constraint in requirements.values(): parse_constraint(constraint) dependencies = [] for name, constraint in requirements.items(): dep = Dependency(name, constraint) extras = [] for extra in self.option("extras"): if " " in extra: extras += [e.strip() for e in extra.split(" ")] else: extras.append(extra) for ex in extras: dep.extras.append(ex) dependencies.append(dep) package = ProjectPackage( self.poetry.package.name, self.poetry.package.version ) package.python_versions = ( self.option("python") or self.poetry.package.python_versions ) for dep in dependencies: package.requires.append(dep) solver = Solver( package, self.poetry.pool, Repository(), Repository(), self.output ) ops = solver.solve() self.line("") self.line("Resolution results:") self.line("") for op in ops: package = op.package self.line( " - <info>{}</info> (<comment>{}</comment>)".format( package.name, package.version ) ) if package.requirements: for req_name, req_value in package.requirements.items(): self.line(" - {}: {}".format(req_name, req_value))
def _do_install(self, local_repo): locked_repository = Repository() if self._update: if self._locker.is_locked() and self._whitelist: # If we update with a lock file present and # we have whitelisted packages (the ones we want to update) # we get the lock file packages to only update # what is strictly needed. # # Otherwise, the lock file information is irrelevant # since we want to update everything. locked_repository = self._locker.locked_repository(True) # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError( "Extra [{}] is not specified.".format(extra)) self._io.writeln("<info>Updating dependencies</>") solver = Solver( self._package, self._pool, self._installed_repository, locked_repository, self._io, ) ops = solver.solve(use_latest=self._whitelist) else: self._io.writeln("<info>Installing dependencies from lock file</>") locked_repository = self._locker.locked_repository(True) if not self._locker.is_fresh(): self._io.writeln( "<warning>" "Warning: The lock file is not up to date with " "the latest changes in pyproject.toml. " "You may be getting outdated dependencies. " "Run update to update them." "</warning>") for extra in self._extras: if extra not in self._locker.lock_data.get("extras", {}): raise ValueError( "Extra [{}] is not specified.".format(extra)) # If we are installing from lock # Filter the operations by comparing it with what is # currently installed ops = self._get_operations_from_lock(locked_repository) self._populate_local_repo(local_repo, ops, locked_repository) # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped self._filter_operations(ops, local_repo) self._io.new_line() # Execute operations actual_ops = [op for op in ops if not op.skipped] if not actual_ops and (self._execute_operations or self._dry_run): self._io.writeln("Nothing to install or update") if actual_ops and (self._execute_operations or self._dry_run): installs = [] updates = [] uninstalls = [] skipped = [] for op in ops: if op.skipped: skipped.append(op) continue if op.job_type == "install": installs.append("{}:{}".format( op.package.pretty_name, op.package.full_pretty_version)) elif op.job_type == "update": updates.append("{}:{}".format( op.target_package.pretty_name, op.target_package.full_pretty_version, )) elif op.job_type == "uninstall": uninstalls.append(op.package.pretty_name) self._io.new_line() self._io.writeln("Package operations: " "<info>{}</> install{}, " "<info>{}</> update{}, " "<info>{}</> removal{}" "{}".format( len(installs), "" if len(installs) == 1 else "s", len(updates), "" if len(updates) == 1 else "s", len(uninstalls), "" if len(uninstalls) == 1 else "s", ", <info>{}</> skipped".format(len(skipped)) if skipped and self.is_verbose() else "", )) # Writing lock before installing if self._update and self._write_lock: updated_lock = self._locker.set_lock_data(self._package, local_repo.packages) if updated_lock: self._io.writeln("") self._io.writeln("<info>Writing lock file</>") self._io.writeln("") for op in ops: self._execute(op)
def _do_install(self, local_repo: Repository) -> int: from poetry.puzzle import Solver locked_repository = Repository() if self._update: if self._locker.is_locked() and not self._lock: locked_repository = self._locker.locked_repository(True) # If no packages have been whitelisted (The ones we want to update), # we whitelist every package in the lock file. if not self._whitelist: for pkg in locked_repository.packages: self._whitelist.append(pkg.name) # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError(f"Extra [{extra}] is not specified.") self._io.write_line("<info>Updating dependencies</>") solver = Solver( self._package, self._pool, self._installed_repository, locked_repository, self._io, remove_untracked=self._remove_untracked, ) ops = solver.solve(use_latest=self._whitelist) else: self._io.write_line( "<info>Installing dependencies from lock file</>") locked_repository = self._locker.locked_repository(True) if not self._locker.is_fresh(): self._io.write_line( "<warning>" "Warning: The lock file is not up to date with " "the latest changes in pyproject.toml. " "You may be getting outdated dependencies. " "Run update to update them." "</warning>") for extra in self._extras: if extra not in self._locker.lock_data.get("extras", {}): raise ValueError(f"Extra [{extra}] is not specified.") # If we are installing from lock # Filter the operations by comparing it with what is # currently installed ops = self._get_operations_from_lock(locked_repository) self._populate_local_repo(local_repo, ops) if self._update: self._write_lock_file(local_repo) if self._lock: # If we are only in lock mode, no need to go any further return 0 if self._without_groups or self._with_groups or self._only_groups: if self._with_groups: # Default dependencies and opted-in optional dependencies root = self._package.with_dependency_groups(self._with_groups) elif self._without_groups: # Default dependencies without selected groups root = self._package.without_dependency_groups( self._without_groups) else: # Only selected groups root = self._package.with_dependency_groups(self._only_groups, only=True) else: root = self._package.without_optional_dependency_groups() if self._io.is_verbose(): self._io.write_line("") self._io.write_line( "<info>Finding the necessary packages for the current system</>" ) # We resolve again by only using the lock file pool = Pool(ignore_repository_names=True) # Making a new repo containing the packages # newly resolved and the ones from the current lock file repo = Repository() for package in local_repo.packages + locked_repository.packages: if not repo.has_package(package): repo.add_package(package) pool.add_repository(repo) solver = Solver( root, pool, self._installed_repository, locked_repository, NullIO(), remove_untracked=self._remove_untracked, ) # Everything is resolved at this point, so we no longer need # to load deferred dependencies (i.e. VCS, URL and path dependencies) solver.provider.load_deferred(False) with solver.use_environment(self._env): ops = solver.solve(use_latest=self._whitelist) # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped self._filter_operations(ops, local_repo) # Execute operations return self._execute(ops)
def handle(self) -> Optional[int]: from cleo.io.null_io import NullIO from poetry.core.packages.project_package import ProjectPackage from poetry.factory import Factory from poetry.puzzle import Solver from poetry.repositories.pool import Pool from poetry.repositories.repository import Repository from poetry.utils.env import EnvManager packages = self.argument("package") if not packages: package = self.poetry.package else: # Using current pool for determine_requirements() self._pool = self.poetry.pool package = ProjectPackage(self.poetry.package.name, self.poetry.package.version) # Silencing output verbosity = self.io.output.verbosity self.io.output.set_verbosity(Verbosity.QUIET) requirements = self._determine_requirements(packages) self.io.output.set_verbosity(verbosity) for constraint in requirements: name = constraint.pop("name") extras = [] for extra in self.option("extras"): if " " in extra: extras += [e.strip() for e in extra.split(" ")] else: extras.append(extra) constraint["extras"] = extras package.add_dependency( Factory.create_dependency(name, constraint)) package.python_versions = self.option("python") or ( self.poetry.package.python_versions) pool = self.poetry.pool solver = Solver(package, pool, Repository(), Repository(), self._io) ops = solver.solve().calculate_operations() self.line("") self.line("Resolution results:") self.line("") if self.option("tree"): show_command: ShowCommand = self.application.find("show") show_command.init_styles(self.io) packages = [op.package for op in ops] repo = Repository(packages) requires = package.all_requires for pkg in repo.packages: for require in requires: if pkg.name == require.name: show_command.display_package_tree(self.io, pkg, repo) break return 0 table = self.table(style="compact") table.style.set_vertical_border_chars("", " ") rows = [] if self.option("install"): env = EnvManager(self.poetry).get() pool = Pool() locked_repository = Repository() for op in ops: locked_repository.add_package(op.package) pool.add_repository(locked_repository) solver = Solver(package, pool, Repository(), Repository(), NullIO()) with solver.use_environment(env): ops = solver.solve().calculate_operations() for op in ops: if self.option("install") and op.skipped: continue pkg = op.package row = [ "<c1>{}</c1>".format(pkg.complete_name), "<b>{}</b>".format(pkg.version), ] if not pkg.marker.is_any(): row[2] = str(pkg.marker) rows.append(row) table.set_rows(rows) table.render() return None
def _do_install(self, local_repo: Repository) -> int: from poetry.puzzle import Solver locked_repository = Repository() if self._update: if self._locker.is_locked() and not self._lock: locked_repository = self._locker.locked_repository() # If no packages have been whitelisted (The ones we want to update), # we whitelist every package in the lock file. if not self._whitelist: for pkg in locked_repository.packages: self._whitelist.append(pkg.name) # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError(f"Extra [{extra}] is not specified.") self._io.write_line("<info>Updating dependencies</>") solver = Solver( self._package, self._pool, self._installed_repository, locked_repository, self._io, ) with solver.provider.use_source_root( source_root=self._env.path.joinpath("src") ): ops = solver.solve(use_latest=self._whitelist).calculate_operations() else: self._io.write_line("<info>Installing dependencies from lock file</>") locked_repository = self._locker.locked_repository() if not self._locker.is_fresh(): self._io.write_error_line( "<warning>" "Warning: poetry.lock is not consistent with pyproject.toml. " "You may be getting improper dependencies. " "Run `poetry lock [--no-update]` to fix it." "</warning>" ) for extra in self._extras: if extra not in self._locker.lock_data.get("extras", {}): raise ValueError(f"Extra [{extra}] is not specified.") # If we are installing from lock # Filter the operations by comparing it with what is # currently installed ops = self._get_operations_from_lock(locked_repository) self._populate_local_repo(local_repo, ops) if self._update: self._write_lock_file(local_repo) if self._lock: # If we are only in lock mode, no need to go any further return 0 if self._groups is not None: root = self._package.with_dependency_groups(list(self._groups), only=True) else: root = self._package.without_optional_dependency_groups() if self._io.is_verbose(): self._io.write_line("") self._io.write_line( "<info>Finding the necessary packages for the current system</>" ) # We resolve again by only using the lock file pool = Pool(ignore_repository_names=True) # Making a new repo containing the packages # newly resolved and the ones from the current lock file repo = Repository() for package in local_repo.packages + locked_repository.packages: if not repo.has_package(package): repo.add_package(package) pool.add_repository(repo) solver = Solver( root, pool, self._installed_repository, locked_repository, NullIO() ) # Everything is resolved at this point, so we no longer need # to load deferred dependencies (i.e. VCS, URL and path dependencies) solver.provider.load_deferred(False) with solver.use_environment(self._env): ops = solver.solve(use_latest=self._whitelist).calculate_operations( with_uninstalls=self._requires_synchronization, synchronize=self._requires_synchronization, ) if not self._requires_synchronization: # If no packages synchronisation has been requested we need # to calculate the uninstall operations from poetry.puzzle.transaction import Transaction transaction = Transaction( locked_repository.packages, [(package, 0) for package in local_repo.packages], installed_packages=self._installed_repository.packages, root_package=root, ) ops = [ op for op in transaction.calculate_operations(with_uninstalls=True) if op.job_type == "uninstall" ] + ops # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped self._filter_operations(ops, local_repo) # Execute operations return self._execute(ops)
def _do_install(self, local_repo): locked_repository = Repository() if self._update: if self._locker.is_locked(): locked_repository = self._locker.locked_repository(True) # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError( 'Extra [{}] is not specified.'.format(extra)) self._io.writeln('<info>Updating dependencies</>') fixed = [] # If the whitelist is enabled, packages not in it are fixed # to the version specified in the lock if self._whitelist: # collect packages to fixate from root requirements candidates = [] for package in locked_repository.packages: candidates.append(package) # fix them to the version in lock if they are not updateable for candidate in candidates: to_fix = True for require in self._whitelist.keys(): if require == candidate.name: to_fix = False if to_fix: dependency = Dependency( candidate.name, candidate.version, optional=candidate.optional, category=candidate.category, allows_prereleases=candidate.is_prerelease()) fixed.append(dependency) solver = Solver(self._package, self._pool, self._installed_repository, locked_repository, self._io) request = self._package.requires request += self._package.dev_requires ops = solver.solve(request, fixed=fixed) else: self._io.writeln('<info>Installing dependencies from lock file</>') locked_repository = self._locker.locked_repository(True) if not self._locker.is_fresh(): self._io.writeln( '<warning>' 'Warning: The lock file is not up to date with ' 'the latest changes in pyproject.toml. ' 'You may be getting outdated dependencies. ' 'Run update to update them.' '</warning>') for extra in self._extras: if extra not in self._locker.lock_data.get('extras', {}): raise ValueError( 'Extra [{}] is not specified.'.format(extra)) # If we are installing from lock # Filter the operations by comparing it with what is # currently installed ops = self._get_operations_from_lock(locked_repository) self._populate_local_repo(local_repo, ops, locked_repository) # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped self._filter_operations(ops, local_repo) self._io.new_line() # Execute operations actual_ops = [op for op in ops if not op.skipped] if not actual_ops and (self._execute_operations or self._dry_run): self._io.writeln('Nothing to install or update') if actual_ops and (self._execute_operations or self._dry_run): installs = [] updates = [] uninstalls = [] skipped = [] for op in ops: if op.skipped: skipped.append(op) continue if op.job_type == 'install': installs.append('{}:{}'.format( op.package.pretty_name, op.package.full_pretty_version)) elif op.job_type == 'update': updates.append('{}:{}'.format( op.target_package.pretty_name, op.target_package.full_pretty_version)) elif op.job_type == 'uninstall': uninstalls.append(op.package.pretty_name) self._io.new_line() self._io.writeln( 'Package operations: ' '<info>{}</> install{}, ' '<info>{}</> update{}, ' '<info>{}</> removal{}' '{}'.format( len(installs), '' if len(installs) == 1 else 's', len(updates), '' if len(updates) == 1 else 's', len(uninstalls), '' if len(uninstalls) == 1 else 's', ', <info>{}</> skipped'.format(len(skipped)) if skipped and self.is_verbose() else '')) # Writing lock before installing if self._update and self._write_lock: updated_lock = self._locker.set_lock_data(self._package, local_repo.packages) if updated_lock: self._io.writeln('') self._io.writeln('<info>Writing lock file</>') self._io.writeln('') for op in ops: self._execute(op)
def handle(self): from poetry.core.packages.project_package import ProjectPackage from poetry.io.null_io import NullIO from poetry.puzzle import Solver from poetry.repositories.pool import Pool from poetry.repositories.repository import Repository from poetry.utils.env import EnvManager packages = self.argument("package") if not packages: package = self.poetry.package else: # Using current pool for determine_requirements() self._pool = self.poetry.pool package = ProjectPackage( self.poetry.package.name, self.poetry.package.version ) # Silencing output is_quiet = self.io.output.is_quiet() if not is_quiet: self.io.output.set_quiet(True) requirements = self._determine_requirements(packages) if not is_quiet: self.io.output.set_quiet(False) for constraint in requirements: name = constraint.pop("name") dep = package.add_dependency(name, constraint) extras = [] for extra in self.option("extras"): if " " in extra: extras += [e.strip() for e in extra.split(" ")] else: extras.append(extra) for ex in extras: dep.extras.append(ex) package.python_versions = self.option("python") or ( self.poetry.package.python_versions ) pool = self.poetry.pool solver = Solver(package, pool, Repository(), Repository(), self._io) ops = solver.solve() self.line("") self.line("Resolution results:") self.line("") if self.option("tree"): show_command = self.application.find("show") show_command.init_styles(self.io) packages = [op.package for op in ops] repo = Repository(packages) requires = package.requires + package.dev_requires for pkg in repo.packages: for require in requires: if pkg.name == require.name: show_command.display_package_tree(self.io, pkg, repo) break return 0 table = self.table([], style="borderless") rows = [] if self.option("install"): env = EnvManager(self.poetry).get() pool = Pool() locked_repository = Repository() for op in ops: locked_repository.add_package(op.package) pool.add_repository(locked_repository) solver = Solver(package, pool, Repository(), Repository(), NullIO()) with solver.use_environment(env): ops = solver.solve() for op in ops: if self.option("install") and op.skipped: continue pkg = op.package row = [ "<c1>{}</c1>".format(pkg.name), "<b>{}</b>".format(pkg.version), "", ] if not pkg.marker.is_any(): row[2] = str(pkg.marker) rows.append(row) table.set_rows(rows) table.render(self.io)
def _do_install(self, local_repo): locked_repository = Repository() if self._update: if self._locker.is_locked() and not self._lock: locked_repository = self._locker.locked_repository(True) # If no packages have been whitelisted (The ones we want to update), # we whitelist every package in the lock file. if not self._whitelist: for pkg in locked_repository.packages: self._whitelist.append(pkg.name) # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError( "Extra [{}] is not specified.".format(extra)) self._io.writeln("<info>Updating dependencies</>") solver = Solver( self._package, self._pool, self._installed_repository, locked_repository, self._io, ) ops = solver.solve(use_latest=self._whitelist) else: self._io.writeln("<info>Installing dependencies from lock file</>") locked_repository = self._locker.locked_repository(True) if not self._locker.is_fresh(): self._io.writeln( "<warning>" "Warning: The lock file is not up to date with " "the latest changes in pyproject.toml. " "You may be getting outdated dependencies. " "Run update to update them." "</warning>") for extra in self._extras: if extra not in self._locker.lock_data.get("extras", {}): raise ValueError( "Extra [{}] is not specified.".format(extra)) # If we are installing from lock # Filter the operations by comparing it with what is # currently installed ops = self._get_operations_from_lock(locked_repository) self._populate_local_repo(local_repo, ops) if self._update: self._write_lock_file(local_repo) if self._lock: # If we are only in lock mode, no need to go any further return 0 root = self._package if not self.is_dev_mode(): root = root.clone() del root.dev_requires[:] with root.with_python_versions(".".join( [str(i) for i in self._env.version_info[:3]])): # We resolve again by only using the lock file pool = Pool() # Making a new repo containing the packages # newly resolved and the ones from the current lock file locked_repository = self._locker.locked_repository(True) repo = Repository() for package in local_repo.packages + locked_repository.packages: if not repo.has_package(package): repo.add_package(package) pool.add_repository(repo) # We whitelist all packages to be sure # that the latest ones are picked up whitelist = [] for pkg in locked_repository.packages: whitelist.append(pkg.name) solver = Solver(root, pool, self._installed_repository, locked_repository, NullIO()) ops = solver.solve(use_latest=whitelist) # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped self._filter_operations(ops, local_repo) self._io.new_line() # Execute operations actual_ops = [op for op in ops if not op.skipped] if not actual_ops and (self._execute_operations or self._dry_run): self._io.writeln("Nothing to install or update") if actual_ops and (self._execute_operations or self._dry_run): installs = [] updates = [] uninstalls = [] skipped = [] for op in ops: if op.skipped: skipped.append(op) continue if op.job_type == "install": installs.append("{}:{}".format( op.package.pretty_name, op.package.full_pretty_version)) elif op.job_type == "update": updates.append("{}:{}".format( op.target_package.pretty_name, op.target_package.full_pretty_version, )) elif op.job_type == "uninstall": uninstalls.append(op.package.pretty_name) self._io.new_line() self._io.writeln("Package operations: " "<info>{}</> install{}, " "<info>{}</> update{}, " "<info>{}</> removal{}" "{}".format( len(installs), "" if len(installs) == 1 else "s", len(updates), "" if len(updates) == 1 else "s", len(uninstalls), "" if len(uninstalls) == 1 else "s", ", <info>{}</> skipped".format(len(skipped)) if skipped and self.is_verbose() else "", )) self._io.writeln("") for op in ops: self._execute(op)
def _do_install(self, local_repo): from poetry.puzzle import Solver locked_repository = Repository() if self._update: if self._locker.is_locked() and not self._lock: locked_repository = self._locker.locked_repository(True) # If no packages have been whitelisted (The ones we want to update), # we whitelist every package in the lock file. if not self._whitelist: for pkg in locked_repository.packages: self._whitelist.append(pkg.name) # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError( "Extra [{}] is not specified.".format(extra)) self._io.write_line("<info>Updating dependencies</>") solver = Solver( self._package, self._pool, self._installed_repository, locked_repository, self._io, remove_untracked=self._remove_untracked, ) ops = solver.solve(use_latest=self._whitelist) else: self._io.write_line( "<info>Installing dependencies from lock file</>") locked_repository = self._locker.locked_repository(True) if not self._locker.is_fresh(): self._io.write_line( "<warning>" "Warning: The lock file is not up to date with " "the latest changes in pyproject.toml. " "You may be getting outdated dependencies. " "Run update to update them." "</warning>") for extra in self._extras: if extra not in self._locker.lock_data.get("extras", {}): raise ValueError( "Extra [{}] is not specified.".format(extra)) # If we are installing from lock # Filter the operations by comparing it with what is # currently installed ops = self._get_operations_from_lock(locked_repository) self._populate_local_repo(local_repo, ops) if self._update: self._write_lock_file(local_repo) if self._lock: # If we are only in lock mode, no need to go any further return 0 root = self._package if not self.is_dev_mode(): root = root.clone() del root.dev_requires[:] elif self.is_dev_only(): root = root.clone() del root.requires[:] if self._io.is_verbose(): self._io.write_line("") self._io.write_line( "<info>Finding the necessary packages for the current system</>" ) # We resolve again by only using the lock file pool = Pool(ignore_repository_names=True) # Making a new repo containing the packages # newly resolved and the ones from the current lock file repo = Repository() for package in local_repo.packages + locked_repository.packages: if not repo.has_package(package): repo.add_package(package) pool.add_repository(repo) # We whitelist all packages to be sure # that the latest ones are picked up whitelist = [] for pkg in locked_repository.packages: whitelist.append(pkg.name) solver = Solver( root, pool, self._installed_repository, locked_repository, NullIO(), remove_untracked=self._remove_untracked, ) with solver.use_environment(self._env): ops = solver.solve(use_latest=whitelist) # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped self._filter_operations(ops, local_repo) # Execute operations return self._execute(ops)
def _do_install(self, local_repo): locked_repository = Repository() if self._update: if self._locker.is_locked(): locked_repository = self._locker.locked_repository(True) # If no packages have been whitelisted (The ones we want to update), # we whitelist every package in the lock file. if not self._whitelist: for pkg in locked_repository.packages: self._whitelist.append(pkg.name) # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError("Extra [{}] is not specified.".format(extra)) self._io.writeln("<info>Updating dependencies</>") solver = Solver( self._package, self._pool, self._installed_repository, locked_repository, self._io, ) ops = solver.solve(use_latest=self._whitelist) else: self._io.writeln("<info>Installing dependencies from lock file</>") locked_repository = self._locker.locked_repository(True) if not self._locker.is_fresh(): self._io.writeln( "<warning>" "Warning: The lock file is not up to date with " "the latest changes in pyproject.toml. " "You may be getting outdated dependencies. " "Run update to update them." "</warning>" ) for extra in self._extras: if extra not in self._locker.lock_data.get("extras", {}): raise ValueError("Extra [{}] is not specified.".format(extra)) # If we are installing from lock # Filter the operations by comparing it with what is # currently installed ops = self._get_operations_from_lock(locked_repository) self._populate_local_repo(local_repo, ops, locked_repository) with self._package.with_python_versions( ".".join([str(i) for i in self._venv.version_info[:3]]) ): # We resolve again by only using the lock file pool = Pool() # Making a new repo containing the packages # newly resolved and the ones from the current lock file locked_repository = self._locker.locked_repository(True) repo = Repository() for package in local_repo.packages + locked_repository.packages: if not repo.has_package(package): repo.add_package(package) pool.add_repository(repo) # We whitelist all packages to be sure # that the latest ones are picked up whitelist = [] for pkg in locked_repository.packages: whitelist.append(pkg.name) solver = Solver( self._package, pool, self._installed_repository, locked_repository, NullIO(), ) ops = solver.solve(use_latest=whitelist) # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped self._filter_operations(ops, local_repo) self._io.new_line() # Execute operations actual_ops = [op for op in ops if not op.skipped] if not actual_ops and (self._execute_operations or self._dry_run): self._io.writeln("Nothing to install or update") if actual_ops and (self._execute_operations or self._dry_run): installs = [] updates = [] uninstalls = [] skipped = [] for op in ops: if op.skipped: skipped.append(op) continue if op.job_type == "install": installs.append( "{}:{}".format( op.package.pretty_name, op.package.full_pretty_version ) ) elif op.job_type == "update": updates.append( "{}:{}".format( op.target_package.pretty_name, op.target_package.full_pretty_version, ) ) elif op.job_type == "uninstall": uninstalls.append(op.package.pretty_name) self._io.new_line() self._io.writeln( "Package operations: " "<info>{}</> install{}, " "<info>{}</> update{}, " "<info>{}</> removal{}" "{}".format( len(installs), "" if len(installs) == 1 else "s", len(updates), "" if len(updates) == 1 else "s", len(uninstalls), "" if len(uninstalls) == 1 else "s", ", <info>{}</> skipped".format(len(skipped)) if skipped and self.is_verbose() else "", ) ) # Writing lock before installing if self._update and self._write_lock: updated_lock = self._locker.set_lock_data( self._package, local_repo.packages ) if updated_lock: self._io.writeln("") self._io.writeln("<info>Writing lock file</>") self._io.writeln("") for op in ops: self._execute(op)