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_with_compatible_locked_dependencies_with_extras( root: ProjectPackage, provider: Provider, repo: Repository ): root.add_dependency(Factory.create_dependency("foo", "^1.0")) package_foo_0 = get_package("foo", "1.0.0") package_foo_1 = get_package("foo", "1.0.1") bar_extra_dep = Factory.create_dependency( "bar", {"version": "^1.0", "extras": "extra"} ) for package_foo in (package_foo_0, package_foo_1): package_foo.add_dependency(bar_extra_dep) repo.add_package(package_foo) bar_deps = {"baz": {"version": "^1.0", "extras": ["extra"]}} add_to_repo(repo, "bar", "1.0.0", bar_deps) add_to_repo(repo, "bar", "1.0.1", bar_deps) add_to_repo(repo, "baz", "1.0.0") add_to_repo(repo, "baz", "1.0.1") check_solver_result( root, provider, result={"foo": "1.0.0", "bar": "1.0.0", "baz": "1.0.0"}, locked={ "foo": get_package("foo", "1.0.0"), "bar": get_package("bar", "1.0.0"), "baz": get_package("baz", "1.0.0"), }, )
def test_remove_without_specific_group_removes_from_specific_groups( tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, command_tester_factory: CommandTesterFactory, installed: Repository, ): """ Removing with a specific group given removes packages only from this group. """ installed.add_package(Package("foo", "2.0.0")) repo.add_package(Package("foo", "2.0.0")) repo.add_package(Package("baz", "1.0.0")) content = app.poetry.file.read() groups_content = tomlkit.parse("""\ [tool.poetry.group.bar.dependencies] foo = "^2.0.0" baz = "^1.0.0" """) content["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" content["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"][ "group"] app.poetry.file.write(content) app.poetry.package.add_dependency( Factory.create_dependency("foo", "^2.0.0")) app.poetry.package.add_dependency( Factory.create_dependency("foo", "^2.0.0", groups=["bar"])) app.poetry.package.add_dependency( Factory.create_dependency("baz", "^1.0.0", groups=["bar"])) tester.execute("foo --group bar") content = app.poetry.file.read()["tool"]["poetry"] assert "foo" in content["dependencies"] assert "foo" not in content["group"]["bar"]["dependencies"] assert "baz" in content["group"]["bar"]["dependencies"] expected = """\ [tool.poetry.group.bar.dependencies] baz = "^1.0.0" """ string_content = content.as_string() if "\r\n" in string_content: # consistent line endings expected = expected.replace("\n", "\r\n") assert expected in string_content
def test_remove_canonicalized_named_removes_dependency_correctly( tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, command_tester_factory: CommandTesterFactory, installed: Repository, ): """ Removing a dependency using a canonicalized named removes the dependency. """ installed.add_package(Package("foo-bar", "2.0.0")) repo.add_package(Package("foo-bar", "2.0.0")) repo.add_package(Package("baz", "1.0.0")) content = app.poetry.file.read() groups_content = tomlkit.parse("""\ [tool.poetry.group.bar.dependencies] foo-bar = "^2.0.0" baz = "^1.0.0" """) content["tool"]["poetry"]["dependencies"]["foo-bar"] = "^2.0.0" content["tool"]["poetry"].value._insert_after( "dependencies", "group", groups_content["tool"]["poetry"]["group"]) app.poetry.file.write(content) app.poetry.package.add_dependency( Factory.create_dependency("foo-bar", "^2.0.0")) app.poetry.package.add_dependency( Factory.create_dependency("foo-bar", "^2.0.0", groups=["bar"])) app.poetry.package.add_dependency( Factory.create_dependency("baz", "^1.0.0", groups=["bar"])) tester.execute("Foo_Bar") content = app.poetry.file.read()["tool"]["poetry"] assert "foo-bar" not in content["dependencies"] assert "foo-bar" not in content["group"]["bar"]["dependencies"] assert "baz" in content["group"]["bar"]["dependencies"] expected = """\ [tool.poetry.group.bar.dependencies] baz = "^1.0.0" """ string_content = content.as_string() if "\r\n" in string_content: # consistent line endings expected = expected.replace("\n", "\r\n") assert expected in string_content
def _populate_local_repo(self, local_repo: Repository, ops: Sequence["Operation"]) -> None: for op in ops: if isinstance(op, Uninstall): continue elif isinstance(op, Update): package = op.target_package else: package = op.package if not local_repo.has_package(package): local_repo.add_package(package)
def test_show_displays_installed_plugins_with_multiple_plugins( app: PoetryTestApplication, tester: CommandTester, installed: Repository, mocker: MockerFixture, plugin_package: Package, plugin_distro: Distribution, ): mocker.patch( "entrypoints.get_group_all", side_effect=[ [ EntryPoint( "poetry-plugin", "poetry_plugin.plugins:ApplicationPlugin", "FirstApplicationPlugin", distro=plugin_distro, ), EntryPoint( "poetry-plugin", "poetry_plugin.plugins:ApplicationPlugin", "SecondApplicationPlugin", distro=plugin_distro, ), ], [ EntryPoint( "poetry-plugin", "poetry_plugin.plugins:Plugin", "FirstPlugin", distro=plugin_distro, ), EntryPoint( "poetry-plugin", "poetry_plugin.plugins:Plugin", "SecondPlugin", distro=plugin_distro, ), ], ], ) installed.add_package(plugin_package) tester.execute("") expected = """ • poetry-plugin (1.2.3) 2 plugins and 2 application plugins """ assert tester.io.fetch_output() == expected
def mock_metadata_entry_points( plugin_package: Package, plugin_distro: metadata.Distribution, installed: Repository, mocker: MockerFixture, tmp_venv: Env, entry_points: Callable[[...], metadata.EntryPoint], ) -> None: installed.add_package(plugin_package) mocker.patch.object(tmp_venv.site_packages, "find_distribution", return_value=plugin_distro) mocker.patch.object(metadata, "entry_points", entry_points)
def test_remove_without_specific_group_removes_from_all_groups( tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, command_tester_factory: CommandTesterFactory, installed: Repository, ): """ Removing without specifying a group removes packages from all groups. """ installed.add_package(Package("foo", "2.0.0")) repo.add_package(Package("foo", "2.0.0")) repo.add_package(Package("baz", "1.0.0")) content = app.poetry.file.read() groups_content = tomlkit.parse("""\ [tool.poetry.group.bar.dependencies] foo = "^2.0.0" baz = "^1.0.0" """) content["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" content["tool"]["poetry"].value._insert_after( "dependencies", "group", groups_content["tool"]["poetry"]["group"]) app.poetry.file.write(content) app.poetry.package.add_dependency( Factory.create_dependency("foo", "^2.0.0")) app.poetry.package.add_dependency( Factory.create_dependency("foo", "^2.0.0", groups=["bar"])) app.poetry.package.add_dependency( Factory.create_dependency("baz", "^1.0.0", groups=["bar"])) tester.execute("foo") content = app.poetry.file.read()["tool"]["poetry"] assert "foo" not in content["dependencies"] assert "foo" not in content["group"]["bar"]["dependencies"] assert "baz" in content["group"]["bar"]["dependencies"] expected = """\ [tool.poetry.group.bar.dependencies] baz = "^1.0.0" """ assert expected in content.as_string()
def test_add_existing_plugin_warns_about_no_operation( app: PoetryTestApplication, repo: TestRepository, tester: CommandTester, env: MockEnv, installed: Repository, ): env.path.joinpath("pyproject.toml").write_text( """\ [tool.poetry] name = "poetry" version = "1.2.0" description = "Python dependency management and packaging made easy." authors = [ "Sébastien Eustace <*****@*****.**>" ] [tool.poetry.dependencies] python = "^3.6" poetry-plugin = "^1.2.3" """, encoding="utf-8", ) installed.add_package(Package("poetry-plugin", "1.2.3")) repo.add_package(Package("poetry-plugin", "1.2.3")) tester.execute("poetry-plugin") expected = """\ The following plugins are already present in the pyproject.toml file and will be\ skipped: • poetry-plugin If you want to update it to the latest compatible version,\ you can use `poetry plugin update package`. If you prefer to upgrade it to the latest available version,\ you can use `poetry plugin add package@latest`. """ assert tester.io.fetch_output() == expected update_command: UpdateCommand = app.find("update") # The update command should not have been called assert update_command.poetry.file.parent != env.path
def add_to_repo( repository: Repository, name: str, version: str, deps: dict[str, str] | None = None, python: str | None = None, ) -> None: package = Package(name, version) if python: package.python_versions = python if deps: for dep_name, dep_constraint in deps.items(): package.add_dependency(Factory.create_dependency(dep_name, dep_constraint)) repository.add_package(package)
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 _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_show_displays_installed_plugins_with_dependencies( app: PoetryTestApplication, tester: CommandTester, installed: Repository, mocker: MockerFixture, plugin_package: Package, plugin_distro: Distribution, ): mocker.patch( "entrypoints.get_group_all", side_effect=[ [ EntryPoint( "poetry-plugin", "poetry_plugin.plugins:ApplicationPlugin", "FirstApplicationPlugin", distro=plugin_distro, ) ], [ EntryPoint( "poetry-plugin", "poetry_plugin.plugins:Plugin", "FirstPlugin", distro=plugin_distro, ) ], ], ) plugin_package.add_dependency(Factory.create_dependency("foo", ">=1.2.3")) plugin_package.add_dependency(Factory.create_dependency("bar", "<4.5.6")) installed.add_package(plugin_package) tester.execute("") expected = """ • poetry-plugin (1.2.3) 1 plugin and 1 application plugin Dependencies - foo (>=1.2.3) - bar (<4.5.6) """ assert tester.io.fetch_output() == expected
def locked_repository(self, with_dev_reqs: bool = False) -> Repository: """ Searches and returns a repository of locked packages. """ if not self.is_locked(): return Repository() lock_data = self.lock_data packages = Repository() if with_dev_reqs: locked_packages = lock_data['package'] else: locked_packages = [ p for p in lock_data['package'] if p['category'] == 'main' ] if not locked_packages: return packages for info in locked_packages: package = poetry.packages.Package( info['name'], info['version'], info['version'] ) package.description = info.get('description', '') package.category = info['category'] package.optional = info['optional'] package.hashes = lock_data['metadata']['hashes'][info['name']] package.python_versions = info['python-versions'] for dep_name, constraint in info.get('dependencies', {}).items(): package.add_dependency(dep_name, constraint) if 'requirements' in info: package.requirements = info['requirements'] if 'source' in info: package.source_type = info['source']['type'] package.source_url = info['source']['url'] package.source_reference = info['source']['reference'] packages.add_package(package) return packages
def test_add_existing_plugin_updates_if_requested( app: PoetryTestApplication, repo: TestRepository, tester: CommandTester, env: MockEnv, installed: Repository, mocker: MockerFixture, ): env.path.joinpath("pyproject.toml").write_text( """\ [tool.poetry] name = "poetry" version = "1.2.0" description = "Python dependency management and packaging made easy." authors = [ "Sébastien Eustace <*****@*****.**>" ] [tool.poetry.dependencies] python = "^3.6" poetry-plugin = "^1.2.3" """, encoding="utf-8", ) installed.add_package(Package("poetry-plugin", "1.2.3")) repo.add_package(Package("poetry-plugin", "1.2.3")) repo.add_package(Package("poetry-plugin", "2.3.4")) tester.execute("poetry-plugin@latest") expected = """\ Using version ^2.3.4 for poetry-plugin Updating dependencies Resolving dependencies... Writing lock file Package operations: 0 installs, 1 update, 0 removals • Updating poetry-plugin (1.2.3 -> 2.3.4) """ assert_plugin_add_result(tester, app, env, expected, "^2.3.4")
def test_remove_does_not_live_empty_groups( tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, command_tester_factory: CommandTesterFactory, installed: Repository, ): """ Empty groups are automatically discarded after package removal. """ installed.add_package(Package("foo", "2.0.0")) repo.add_package(Package("foo", "2.0.0")) repo.add_package(Package("baz", "1.0.0")) content = app.poetry.file.read() groups_content = tomlkit.parse("""\ [tool.poetry.group.bar.dependencies] foo = "^2.0.0" baz = "^1.0.0" """) content["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" content["tool"]["poetry"].value._insert_after( "dependencies", "group", groups_content["tool"]["poetry"]["group"]) app.poetry.file.write(content) app.poetry.package.add_dependency( Factory.create_dependency("foo", "^2.0.0")) app.poetry.package.add_dependency( Factory.create_dependency("foo", "^2.0.0", groups=["bar"])) app.poetry.package.add_dependency( Factory.create_dependency("baz", "^1.0.0", groups=["bar"])) tester.execute("foo baz --group bar") content = app.poetry.file.read()["tool"]["poetry"] assert "foo" in content["dependencies"] assert "foo" not in content["group"]["bar"]["dependencies"] assert "baz" not in content["group"]["bar"]["dependencies"] assert "[tool.poetry.group.bar]" not in content.as_string() assert "[tool.poetry.group]" not in content.as_string()
def run(self): # Force update if there is no lock file present if not self._update and not self._locker.is_locked(): self._update = True if self.is_dry_run(): self.verbose(True) self._write_lock = False self._execute_operations = False local_repo = Repository() return self._do_install(local_repo)
def _do_refresh(self): # Checking extras for extra in self._extras: if extra not in self._package.extras: raise ValueError("Extra [{}] is not specified.".format(extra)) ops = self._get_operations_from_lock(self._locker.locked_repository(True)) local_repo = Repository() self._populate_local_repo(local_repo, ops) self._write_lock_file(local_repo, force=True) return 0
def test_adding_a_plugin_can_update_poetry_dependencies_if_needed( app: PoetryTestApplication, repo: TestRepository, tester: CommandTester, env: MockEnv, installed: Repository, ): poetry_package = Package("poetry", "1.2.0") poetry_package.add_dependency( Factory.create_dependency("tomlkit", "^0.7.0")) plugin_package = Package("poetry-plugin", "1.2.3") plugin_package.add_dependency( Factory.create_dependency("tomlkit", "^0.7.2")) installed.add_package(poetry_package) installed.add_package(Package("tomlkit", "0.7.1")) repo.add_package(plugin_package) repo.add_package(Package("tomlkit", "0.7.1")) repo.add_package(Package("tomlkit", "0.7.2")) tester.execute("poetry-plugin") expected = """\ Using version ^1.2.3 for poetry-plugin Updating dependencies Resolving dependencies... Writing lock file Package operations: 1 install, 1 update, 0 removals • Updating tomlkit (0.7.1 -> 0.7.2) • Installing poetry-plugin (1.2.3) """ assert_plugin_add_result(tester, app, env, expected, "^1.2.3")
def install_plugin(env: MockEnv, installed: Repository, pyproject: None) -> None: 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": [] }, }, } env.path.joinpath("poetry.lock").write_text(tomlkit.dumps(lock_content), encoding="utf-8") pyproject_toml = tomlkit.loads( env.path.joinpath("pyproject.toml").read_text(encoding="utf-8")) content = pyproject_toml["tool"]["poetry"] dependency_section = content["dependencies"] dependency_section["poetry-plugin"] = "^1.2.3" env.path.joinpath("pyproject.toml").write_text( tomlkit.dumps(pyproject_toml), encoding="utf-8") installed.add_package(Package("poetry-plugin", "1.2.3"))
def test_show_displays_installed_plugins( app: PoetryTestApplication, tester: CommandTester, installed: Repository, mocker: MockerFixture, ): mocker.patch( "entrypoints.get_group_all", side_effect=[ [ EntryPoint( "poetry-plugin", "poetry_plugin.plugins:ApplicationPlugin", "FirstApplicationPlugin", ) ], [ EntryPoint( "poetry-plugin", "poetry_plugin.plugins:Plugin", "FirstPlugin", ) ], ], ) installed.add_package(Package("poetry-plugin", "1.2.3")) tester.execute("") expected = """ • poetry-plugin (1.2.3) 1 plugin and 1 application plugin """ assert tester.io.fetch_output() == expected
def setup(mocker, installer): # Set Installer's installer p = mocker.patch('poetry.installation.installer.Installer._get_installer') p.return_value = installer p = mocker.patch('poetry.installation.installer.Installer._get_installed') p.return_value = Repository() # Patch git module to not actually clone projects mocker.patch('poetry.vcs.git.Git.clone', new=mock_clone) mocker.patch('poetry.vcs.git.Git.checkout', new=lambda *_: None) p = mocker.patch('poetry.vcs.git.Git.rev_parse') p.return_value = '9cf87a285a2d3fbb0b9fa621997b3acc3631ed24' # Patch provider progress rate to have a consistent # dependency resolution output p = mocker.patch('poetry.puzzle.provider.Provider.progress_rate', new_callable=mocker.PropertyMock) p.return_value = 3600
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 installed() -> Repository: return Repository()
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 test_pool_raises_package_not_found_when_no_package_is_found(): pool = Pool() pool.add_repository(Repository()) with pytest.raises(PackageNotFound): pool.package("foo", "1.0.0")
def test_pool_with_initial_repositories(): repo = Repository() pool = Pool([repo]) assert len(pool.repositories) == 1 assert not pool.has_default()
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 repo(): return Repository()
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): 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)