def _get_operations_from_lock( self, locked_repository: Repository ) -> Sequence[Operation]: installed_repo = self._installed_repository ops = [] extra_packages = self._get_extra_packages(locked_repository) for locked in locked_repository.packages: is_installed = False for installed in installed_repo.packages: if locked.name == installed.name: is_installed = True if locked.optional and locked.name not in extra_packages: # Installed but optional and not requested in extras ops.append(Uninstall(locked)) elif locked.version != installed.version: ops.append(Update(installed, locked)) # If it's optional and not in required extras # we do not install if locked.optional and locked.name not in extra_packages: continue op = Install(locked) if is_installed: op.skip("Already installed") ops.append(op) return ops
def test_execute_executes_a_batch_of_operations( config, pool, io, tmp_dir, mock_file_downloads ): config = Config() config.merge({"cache-dir": tmp_dir}) env = MockEnv(path=Path(tmp_dir)) executor = Executor(env, pool, config, io) file_package = Package("demo", "0.1.0") file_package.source_type = "file" file_package.source_url = str( Path(__file__) .parent.parent.joinpath( "fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl" ) .resolve() ) directory_package = Package("simple-project", "1.2.3") directory_package.source_type = "directory" directory_package.source_url = str( Path(__file__).parent.parent.joinpath("fixtures/simple_project").resolve() ) git_package = Package("demo", "0.1.0") git_package.source_type = "git" git_package.source_reference = "master" git_package.source_url = "https://github.com/demo/demo.git" assert 0 == executor.execute( [ Install(Package("pytest", "3.5.2")), Uninstall(Package("attrs", "17.4.0")), Update(Package("requests", "2.18.3"), Package("requests", "2.18.4")), Uninstall(Package("clikit", "0.2.3")).skip("Not currently installed"), Install(file_package), Install(directory_package), Install(git_package), ] ) expected = """ Package operations: 4 installs, 1 update, 1 removal • Installing pytest (3.5.2) • Removing attrs (17.4.0) • Updating requests (2.18.3 -> 2.18.4) • Installing demo (0.1.0 {}) • Installing simple-project (1.2.3 {}) • Installing demo (0.1.0 master) """.format( file_package.source_url, directory_package.source_url ) expected = set(expected.splitlines()) output = set(io.fetch_output().splitlines()) assert expected == output assert 5 == len(env.executed)
def test_execute_executes_a_batch_of_operations(mocker, config, pool, io, tmp_dir, mock_file_downloads, env): pip_editable_install = mocker.patch( "poetry.installation.executor.pip_editable_install", unsafe=not PY36) config = Config() config.merge({"cache-dir": tmp_dir}) executor = Executor(env, pool, config, io) file_package = Package( "demo", "0.1.0", source_type="file", source_url=Path(__file__).parent.parent.joinpath( "fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl").resolve( ).as_posix(), ) directory_package = Package( "simple-project", "1.2.3", source_type="directory", source_url=Path(__file__).parent.parent.joinpath( "fixtures/simple_project").resolve().as_posix(), ) git_package = Package( "demo", "0.1.0", source_type="git", source_reference="master", source_url="https://github.com/demo/demo.git", develop=True, ) return_code = executor.execute([ Install(Package("pytest", "3.5.2")), Uninstall(Package("attrs", "17.4.0")), Update(Package("requests", "2.18.3"), Package("requests", "2.18.4")), Uninstall(Package("clikit", "0.2.3")).skip("Not currently installed"), Install(file_package), Install(directory_package), Install(git_package), ]) expected = """ Package operations: 4 installs, 1 update, 1 removal • Installing pytest (3.5.2) • Removing attrs (17.4.0) • Updating requests (2.18.3 -> 2.18.4) • Installing demo (0.1.0 {}) • Installing simple-project (1.2.3 {}) • Installing demo (0.1.0 master) """.format(file_package.source_url, directory_package.source_url) expected = set(expected.splitlines()) output = set(io.fetch_output().splitlines()) assert expected == output assert 5 == len(env.executed) assert 0 == return_code pip_editable_install.assert_called_once()
def test_execute_executes_a_batch_of_operations( mocker: MockerFixture, config: Config, pool: Pool, io: BufferedIO, tmp_dir: str, mock_file_downloads: None, env: MockEnv, ): pip_install = mocker.patch("poetry.installation.executor.pip_install") config.merge({"cache-dir": tmp_dir}) executor = Executor(env, pool, config, io) file_package = Package( "demo", "0.1.0", source_type="file", source_url=Path(__file__).parent.parent.joinpath( "fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl").resolve( ).as_posix(), ) directory_package = Package( "simple-project", "1.2.3", source_type="directory", source_url=Path(__file__).parent.parent.joinpath( "fixtures/simple_project").resolve().as_posix(), ) git_package = Package( "demo", "0.1.0", source_type="git", source_reference="master", source_url="https://github.com/demo/demo.git", develop=True, ) return_code = executor.execute([ Install(Package("pytest", "3.5.2")), Uninstall(Package("attrs", "17.4.0")), Update(Package("requests", "2.18.3"), Package("requests", "2.18.4")), Uninstall(Package("clikit", "0.2.3")).skip("Not currently installed"), Install(file_package), Install(directory_package), Install(git_package), ]) expected = f""" Package operations: 4 installs, 1 update, 1 removal • Installing pytest (3.5.2) • Removing attrs (17.4.0) • Updating requests (2.18.3 -> 2.18.4) • Installing demo (0.1.0 {file_package.source_url}) • Installing simple-project (1.2.3 {directory_package.source_url}) • Installing demo (0.1.0 master) """ expected = set(expected.splitlines()) output = set(io.fetch_output().splitlines()) assert output == expected assert len(env.executed) == 1 assert return_code == 0 assert pip_install.call_count == 5 assert pip_install.call_args.kwargs.get("upgrade", False) assert pip_install.call_args.kwargs.get("editable", False)
def solve(self, use_latest=None): # type: (...) -> List[Operation] with self._provider.progress(): start = time.time() packages, depths = self._solve(use_latest=use_latest) end = time.time() if len(self._overrides) > 1: self._provider.debug( "Complete version solving took {:.3f} seconds with {} overrides" .format(end - start, len(self._overrides))) self._provider.debug("Resolved with overrides: {}".format( ", ".join("({})".format(b) for b in self._overrides))) operations = [] for i, package in enumerate(packages): installed = False for pkg in self._installed.packages: if package.name == pkg.name: installed = True if pkg.source_type == "git" and package.source_type == "git": from poetry.core.vcs.git import Git # Trying to find the currently installed version pkg_source_url = Git.normalize_url(pkg.source_url) package_source_url = Git.normalize_url( package.source_url) for locked in self._locked.packages: if locked.name != pkg.name or locked.source_type != "git": continue locked_source_url = Git.normalize_url( locked.source_url) if (locked.name == pkg.name and locked.source_type == pkg.source_type and locked_source_url == pkg_source_url and locked.source_reference == pkg.source_reference): pkg = Package(pkg.name, locked.version) pkg.source_type = "git" pkg.source_url = locked.source_url pkg.source_reference = locked.source_reference break if pkg_source_url != package_source_url or ( pkg.source_reference != package.source_reference and not pkg.source_reference.startswith( package.source_reference)): operations.append( Update(pkg, package, priority=depths[i])) else: operations.append( Install(package).skip("Already installed")) elif package.version != pkg.version: # Checking version operations.append( Update(pkg, package, priority=depths[i])) elif pkg.source_type and package.source_type != pkg.source_type: operations.append( Update(pkg, package, priority=depths[i])) else: operations.append( Install( package, priority=depths[i]).skip("Already installed")) break if not installed: operations.append(Install(package, priority=depths[i])) # Checking for removals for pkg in self._locked.packages: remove = True for package in packages: if pkg.name == package.name: remove = False break if remove: skip = True for installed in self._installed.packages: if installed.name == pkg.name: skip = False break op = Uninstall(pkg) if skip: op.skip("Not currently installed") operations.append(op) if self._remove_untracked: locked_names = {locked.name for locked in self._locked.packages} for installed in self._installed.packages: if installed.name == self._package.name: continue if installed.name in Provider.UNSAFE_PACKAGES: # Never remove pip, setuptools etc. continue if installed.name not in locked_names: operations.append(Uninstall(installed)) return sorted( operations, key=lambda o: ( -o.priority, o.package.name, o.package.version, ), )
def calculate_operations(self, with_uninstalls: bool = True, synchronize: bool = False) -> list[Operation]: from poetry.installation.operations import Install from poetry.installation.operations import Uninstall from poetry.installation.operations import Update operations: list[Operation] = [] for result_package, priority in self._result_packages: installed = False for installed_package in self._installed_packages: if result_package.name == installed_package.name: installed = True if result_package.version != installed_package.version or ( (installed_package.source_type or result_package.source_type != "legacy") and not result_package.is_same_package_as( installed_package)): operations.append( Update(installed_package, result_package, priority=priority)) else: operations.append( Install(result_package).skip("Already installed")) break if not installed: operations.append(Install(result_package, priority=priority)) if with_uninstalls: for current_package in self._current_packages: found = any(current_package.name == result_package.name for result_package, _ in self._result_packages) if not found: for installed_package in self._installed_packages: if installed_package.name == current_package.name: operations.append(Uninstall(current_package)) if synchronize: current_package_names = { current_package.name for current_package in self._current_packages } # We preserve pip/setuptools/wheel when not managed by poetry, this is # done to avoid externally managed virtual environments causing # unnecessary removals. preserved_package_names = { "pip", "setuptools", "wheel", } - current_package_names for installed_package in self._installed_packages: if (self._root_package and installed_package.name == self._root_package.name): continue if installed_package.name in preserved_package_names: continue if installed_package.name not in current_package_names: operations.append(Uninstall(installed_package)) return sorted( operations, key=lambda o: ( -o.priority, o.package.name, o.package.version, ), )
def calculate_operations(self, with_uninstalls: bool = True, synchronize: bool = False) -> list[Operation]: from poetry.installation.operations import Install from poetry.installation.operations import Uninstall from poetry.installation.operations import Update operations: list[Operation] = [] for result_package, priority in self._result_packages: installed = False for installed_package in self._installed_packages: if result_package.name == installed_package.name: installed = True # We have to perform an update if the version or another # attribute of the package has changed (source type, url, ref, ...). if result_package.version != installed_package.version or ( ( # This has to be done because installed packages cannot # have type "legacy". If a package with type "legacy" # is installed, the installed package has no source_type. # Thus, if installed_package has no source_type and # the result_package has source_type "legacy" (negation of # the following condition), update must not be performed. # This quirk has the side effect that when switching # from PyPI to legacy (or vice versa), # no update is performed. installed_package.source_type or result_package.source_type != "legacy") and not result_package.is_same_package_as( installed_package)): operations.append( Update(installed_package, result_package, priority=priority)) else: operations.append( Install(result_package).skip("Already installed")) break if not installed: operations.append(Install(result_package, priority=priority)) if with_uninstalls: for current_package in self._current_packages: found = any(current_package.name == result_package.name for result_package, _ in self._result_packages) if not found: for installed_package in self._installed_packages: if installed_package.name == current_package.name: operations.append(Uninstall(current_package)) if synchronize: current_package_names = { current_package.name for current_package in self._current_packages } # We preserve pip/setuptools/wheel when not managed by poetry, this is # done to avoid externally managed virtual environments causing # unnecessary removals. preserved_package_names = { "pip", "setuptools", "wheel", } - current_package_names for installed_package in self._installed_packages: if (self._root_package and installed_package.name == self._root_package.name): continue if installed_package.name in preserved_package_names: continue if installed_package.name not in current_package_names: operations.append(Uninstall(installed_package)) return sorted( operations, key=lambda o: ( -o.priority, o.package.name, o.package.version, ), )