def test_pool_raises_connection_error_when_offline(): pool = Pool() pool.add_repository( LegacyRepository(url="http://fake.url/simple", name="fake")) with pytest.raises(ConnectionError): pool.package("foo", "1.0.0")
def test_installer_required_extras_should_be_installed( locker, repo, package, installed, env, mocker ): pool = Pool() pool.add_repository(MockRepository()) installer = Installer(NullIO(), env, package, locker, pool, installed=installed) package.add_dependency( "cachecontrol", {"version": "^0.12.5", "extras": ["filecache"]} ) installer.update(True) installer.run() assert len(installer.installer.installs) == 2 assert len(installer.installer.updates) == 0 assert len(installer.installer.removals) == 0 locker.locked(True) locker.mock_lock_data(locker.written_data) installer = Installer(NullIO(), env, package, locker, pool, installed=installed) installer.update(True) installer.run() assert len(installer.installer.installs) == 2 assert len(installer.installer.updates) == 0 assert len(installer.installer.removals) == 0
def __init__(self, file, local_config, package, locker, config): self._file = TomlFile(file) self._package = package self._local_config = local_config self._locker = Locker(locker.lock.path, locker._local_config) self._config = config # Configure sources self._pool = Pool()
def _factory( name=None, dependencies=None, dev_dependencies=None, pyproject_content=None, poetry_lock_content=None, install_deps=True, ): project_dir = workspace / "poetry-fixture-{}".format(name) dependencies = dependencies or {} dev_dependencies = dev_dependencies or {} if pyproject_content: project_dir.mkdir(parents=True, exist_ok=True) with project_dir.joinpath("pyproject.toml").open( "w", encoding="utf-8" ) as f: f.write(pyproject_content) else: layout("src")( name, "0.1.0", author="PyTest Tester <*****@*****.**>", readme_format="md", python=default_python, dependencies=dependencies, dev_dependencies=dev_dependencies, ).create(project_dir, with_tests=False) if poetry_lock_content: lock_file = project_dir / "poetry.lock" lock_file.write_text(data=poetry_lock_content, encoding="utf-8") poetry = Factory().create_poetry(project_dir) locker = TestLocker( poetry.locker.lock.path, poetry.locker._local_config ) # noqa locker.write() poetry.set_locker(locker) poetry.set_config(config) pool = Pool() pool.add_repository(repo) poetry.set_pool(pool) if install_deps: for deps in [dependencies, dev_dependencies]: for name, version in deps.items(): pkg = get_package(name, version) repo.add_package(pkg) installed.add_package(pkg) return poetry
def __init__(self, file, local_config, package, locker): self._file = TomlFile(file) self._package = package self._local_config = local_config self._locker = Locker(locker.lock.path, locker._local_config) self._config = Config.create("config.toml") self._auth_config = Config.create("auth.toml") # Configure sources self._pool = Pool()
def _get_pool(self) -> "Pool": from poetry.repositories import Pool from poetry.repositories.pypi_repository import PyPiRepository if isinstance(self, EnvCommand): return self.poetry.pool if self._pool is None: self._pool = Pool() self._pool.add_repository(PyPiRepository()) return self._pool
def test_installer_can_handle_old_lock_files(installer, locker, package, repo, installed, config): pool = Pool() pool.add_repository(MockRepository()) package.add_dependency("pytest", "^3.5", category="dev") locker.locked() locker.mock_lock_data(fixture("old-lock")) installer = Installer(NullIO(), MockEnv(), package, locker, pool, config, installed=installed) installer.run() assert 6 == len(installer.installer.installs) installer = Installer( NullIO(), MockEnv(version_info=(2, 7, 18)), package, locker, pool, config, installed=installed, ) installer.run() # funcsigs will be added assert 7 == len(installer.installer.installs) installer = Installer( NullIO(), MockEnv(version_info=(2, 7, 18), platform="win32"), package, locker, pool, config, installed=installed, ) installer.run() # colorama will be added assert 8 == len(installer.installer.installs)
def test_installer_with_pypi_repository(package, locker, installed): pool = Pool() pool.add_repository(MockRepository()) installer = Installer( NullIO(), NullEnv(), package, locker, pool, installed=installed ) package.add_dependency("pytest", "^3.5", category="dev") installer.run() expected = fixture("with-pypi-repository") assert locker.written_data == expected
def test_installer_required_extras_should_not_be_removed_when_updating_single_dependency_pypi_repository( locker, repo, package, installed, env, mocker, config): mocker.patch("sys.platform", "darwin") pool = Pool() pool.add_repository(MockRepository()) installer = Installer(NullIO(), env, package, locker, pool, config, installed=installed) package.add_dependency("poetry", {"version": "^0.12.0"}) installer.update(True) installer.run() assert len(installer.installer.installs) == 3 assert len(installer.installer.updates) == 0 assert len(installer.installer.removals) == 0 package.add_dependency("pytest", "^3.5") locker.locked(True) locker.mock_lock_data(locker.written_data) for pkg in installer.installer.installs: installed.add_package(pkg) installer = Installer(NullIO(), env, package, locker, pool, config, installed=installed) installer.update(True) installer.whitelist(["pytest"]) installer.run() assert len(installer.installer.installs) == 6 if not PY2 else 7 assert len(installer.installer.updates) == 0 assert len(installer.installer.removals) == 0
def test_installer_with_pypi_repository(package, locker, installed): pool = Pool() pool.add_repository(MockRepository()) installer = Installer(NullIO(), NullVenv(), package, locker, pool, installed=installed) package.add_dependency('pytest', '^3.5', category='dev') installer.run() expected = fixture('with-pypi-repository') assert locker.written_data == expected
def test_repository_with_normal_default_and_secondary_repositories(): secondary = LegacyRepository("secondary", "https://secondary.com") default = LegacyRepository("default", "https://default.com") repo1 = LegacyRepository("foo", "https://foo.bar") repo2 = LegacyRepository("bar", "https://bar.baz") pool = Pool() pool.add_repository(repo1) pool.add_repository(secondary, secondary=True) pool.add_repository(repo2) pool.add_repository(default, default=True) assert pool.repository("secondary") is secondary assert pool.repository("default") is default assert pool.repository("foo") is repo1 assert pool.repository("bar") is repo2 assert pool.has_default()
def poetry(repo, project_directory, config): p = Factory().create_poetry( Path(__file__).parent.parent / "fixtures" / project_directory) p.set_locker(TestLocker(p.locker.lock.path, p.locker._local_config)) with p.file.path.open(encoding="utf-8") as f: content = f.read() p.set_config(config) pool = Pool() pool.add_repository(repo) p.set_pool(pool) yield p with p.file.path.open("w", encoding="utf-8") as f: f.write(content)
def test_pool_fallback_through_repos(): pool = Pool() pool.add_repository( LegacyRepository(url="http://fake.url/simple", name="fake")) pool.add_repository(MockRepository()) package = pool.package("requests", "2.18.4") assert package.name == "requests" assert len(package.requires) == 4 assert len(package.extras["security"]) == 3 assert len(package.extras["socks"]) == 2 win_inet = package.extras["socks"][0] assert win_inet.name == "win-inet-pton" assert win_inet.python_versions == "~2.7 || ~2.6" assert str(win_inet.marker) == ( 'sys_platform == "win32" and (python_version == "2.7" ' 'or python_version == "2.6") and extra == "socks"')
def test_installer_can_install_dependencies_from_forced_source( locker, package, installed, env ): package.python_versions = "^3.7" package.add_dependency("tomlkit", {"version": "^0.5", "source": "legacy"}) pool = Pool() pool.add_repository(MockLegacyRepository()) pool.add_repository(MockRepository()) installer = Installer(NullIO(), env, package, locker, pool, installed=installed) installer.update(True) installer.run() assert len(installer.installer.installs) == 1 assert len(installer.installer.updates) == 0 assert len(installer.installer.removals) == 0
def test_repository_from_secondary_pool(): repo = LegacyRepository("foo", "https://foo.bar") pool = Pool() pool.add_repository(repo, secondary=True) assert pool.repository("foo") is repo
def test_repository_from_normal_pool(): repo = LegacyRepository("foo", "https://foo.bar") pool = Pool() pool.add_repository(repo) assert pool.repository("foo") is repo
def test_repository_no_repository(): pool = Pool() with pytest.raises(ValueError): pool.repository("foo")
def test_pool_with_initial_repositories(): repo = Repository() pool = Pool([repo]) assert len(pool.repositories) == 1 assert not pool.has_default()
def test_pool(): pool = Pool() assert len(pool.repositories) == 0 assert not pool.has_default()
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 pool(repo): pool = Pool() pool.add_repository(repo) return pool
def pool(repo: TestRepository) -> Pool: return Pool([repo])
def handle(self) -> Optional[int]: from poetry.factory import Factory from poetry.repositories import Pool name = self.argument("name") url = self.argument("url") is_default = self.option("default") is_secondary = self.option("secondary") if is_default and is_secondary: self.line_error( "Cannot configure a source as both <c1>default</c1> and <c1>secondary</c1>." ) return 1 new_source = Source(name=name, url=url, default=is_default, secondary=is_secondary) existing_sources = self.poetry.get_sources() sources = AoT([]) for source in existing_sources: if source == new_source: self.line( f"Source with name <c1>{name}</c1> already exits. Skipping addition." ) return 0 elif source.default and is_default: self.line_error( f"<error>Source with name <c1>{source.name}</c1> is already set to default. " f"Only one default source can be configured at a time.</error>" ) return 1 if source.name == name: self.line( f"Source with name <c1>{name}</c1> already exits. Updating." ) source = new_source new_source = None sources.append(self.source_to_table(source)) if new_source is not None: self.line(f"Adding source with name <c1>{name}</c1>.") sources.append(self.source_to_table(new_source)) # ensure new source is valid. eg: invalid name etc. self.poetry._pool = Pool() try: Factory.configure_sources(self.poetry, sources, self.poetry.config, NullIO()) self.poetry.pool.repository(name) except ValueError as e: self.line_error( f"<error>Failed to validate addition of <c1>{name}</c1>: {e}</error>" ) return 1 self.poetry.pyproject.poetry_config["source"] = sources self.poetry.pyproject.save() return 0
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 patches(mocker: "MockerFixture", source_dir: Path, repo: "TestRepository") -> None: mocker.patch("pathlib.Path.cwd", return_value=source_dir) mocker.patch("poetry.console.commands.init.InitCommand._get_pool", return_value=Pool([repo]))
def patches(mocker, source_dir, repo): mocker.patch("pathlib.Path.cwd", return_value=source_dir) mocker.patch("poetry.console.commands.init.InitCommand._get_pool", return_value=Pool([repo]))
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 _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() 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 _factory( name: str | None = None, dependencies: dict[str, str] | None = None, dev_dependencies: dict[str, str] | None = None, pyproject_content: str | None = None, poetry_lock_content: str | None = None, install_deps: bool = True, source: Path | None = None, locker_config: dict[str, Any] | None = None, ) -> Poetry: project_dir = workspace / f"poetry-fixture-{name}" dependencies = dependencies or {} dev_dependencies = dev_dependencies or {} if pyproject_content or source: if source: project_dir.parent.mkdir(parents=True, exist_ok=True) shutil.copytree(source, project_dir) else: project_dir.mkdir(parents=True, exist_ok=True) if pyproject_content: with project_dir.joinpath("pyproject.toml").open( "w", encoding="utf-8") as f: f.write(pyproject_content) else: layout("src")( name, "0.1.0", author="PyTest Tester <*****@*****.**>", readme_format="md", python=default_python, dependencies=dependencies, dev_dependencies=dev_dependencies, ).create(project_dir, with_tests=False) if poetry_lock_content: lock_file = project_dir / "poetry.lock" lock_file.write_text(data=poetry_lock_content, encoding="utf-8") poetry = Factory().create_poetry(project_dir) locker = TestLocker(poetry.locker.lock.path, locker_config or poetry.locker._local_config) locker.write() poetry.set_locker(locker) poetry.set_config(config) pool = Pool() pool.add_repository(repo) poetry.set_pool(pool) if install_deps: for deps in [dependencies, dev_dependencies]: for name, version in deps.items(): pkg = get_package(name, version) repo.add_package(pkg) installed.add_package(pkg) return poetry