def handle(self, project: Project, options: argparse.Namespace) -> None: groups: list[str] = list(options.groups) if options.pyproject: options.hashes = False groups = translate_groups( project, options.default, options.dev, options.groups or (), ) requirements: dict[str, Requirement] = {} packages: Iterable[Requirement] | Iterable[Candidate] for group in groups: requirements.update(project.get_dependencies(group)) if options.pyproject: packages = requirements.values() else: project.core.ui.echo( "The exported requirements file is no longer cross-platform. " "Using it on other platforms may cause unexpected result.", fg="yellow", err=True, ) candidates = resolve_candidates_from_lockfile( project, requirements.values() ) packages = candidates.values() content = FORMATS[options.format].export( project, packages, options ) # type: ignore if options.output: Path(options.output).write_text(content) else: project.core.ui.echo(content)
def do_sync( project: Project, *, groups: Sequence[str] = (), dev: bool = True, default: bool = True, dry_run: bool = False, clean: bool = False, requirements: list[Requirement] | None = None, tracked_names: Sequence[str] | None = None, no_editable: bool = False, no_self: bool = False, reinstall: bool = False, ) -> None: """Synchronize project""" if requirements is None: if not project.lockfile_file.exists(): raise ProjectError("Lock file does not exist, nothing to sync") elif not project.is_lockfile_compatible(): project.core.ui.echo( "Lock file version is not compatible with PDM, " "install may fail, please regenerate the pdm.lock", err=True, ) elif not project.is_lockfile_hash_match(): project.core.ui.echo( "Lock file hash doesn't match pyproject.toml, packages may be outdated", err=True, ) groups = translate_groups(project, default, dev, groups or ()) requirements = [] for group in groups: requirements.extend(project.get_dependencies(group).values()) candidates = resolve_candidates_from_lockfile(project, requirements) if tracked_names and dry_run: candidates = { name: c for name, c in candidates.items() if name in tracked_names } handler = project.core.synchronizer_class( candidates, project.environment, clean, dry_run, no_editable=no_editable, install_self=not no_self and "default" in groups and bool(project.meta.name), use_install_cache=project.config["feature.install_cache"], reinstall=reinstall, ) handler.synchronize()
def do_sync( project: Project, *, groups: Collection[str] = (), dev: bool = True, default: bool = True, dry_run: bool = False, clean: bool = False, requirements: list[Requirement] | None = None, tracked_names: Collection[str] | None = None, no_editable: bool | Collection[str] = False, no_self: bool = False, reinstall: bool = False, ) -> None: """Synchronize project""" if requirements is None: groups = translate_groups(project, default, dev, groups or ()) requirements = [] for group in groups: requirements.extend(project.get_dependencies(group).values()) candidates = resolve_candidates_from_lockfile(project, requirements) if tracked_names and dry_run: candidates = { name: c for name, c in candidates.items() if name in tracked_names } handler = project.core.synchronizer_class( candidates, project.environment, clean, dry_run, no_editable=no_editable, install_self=not no_self and "default" in groups and bool(project.name), use_install_cache=project.config["install.cache"], reinstall=reinstall, ) signals.pre_install.send(project, candidates=candidates, dry_run=dry_run) handler.synchronize() signals.post_install.send(project, candidates=candidates, dry_run=dry_run)
def do_update( project: Project, *, dev: bool | None = None, groups: Sequence[str] = (), default: bool = True, strategy: str = "reuse", save: str = "compatible", unconstrained: bool = False, top: bool = False, dry_run: bool = False, packages: Collection[str] = (), sync: bool = True, no_editable: bool = False, no_self: bool = False, prerelease: bool = False, ) -> None: """Update specified packages or all packages""" check_project_file(project) if len(packages) > 0 and (top or len(groups) > 1 or not default): raise PdmUsageError( "packages argument can't be used together with multiple -G or " "--no-default and --top." ) all_dependencies = project.all_dependencies updated_deps: dict[str, dict[str, Requirement]] = defaultdict(dict) install_dev = True if dev is None else dev if not packages: if prerelease: raise PdmUsageError("--prerelease must be used with packages given") groups = translate_groups(project, default, install_dev, groups or ()) for group in groups: updated_deps[group] = all_dependencies[group] else: group = groups[0] if groups else ("dev" if dev else "default") dependencies = all_dependencies[group] for name in packages: matched_name = next( filter( lambda k: normalize_name(strip_extras(k)[0]) == normalize_name(name), dependencies.keys(), ), None, ) if not matched_name: raise ProjectError( "{} does not exist in {} {}dependencies.".format( termui.green(name, bold=True), group, "dev-" if dev else "" ) ) dependencies[matched_name].prerelease = prerelease updated_deps[group][matched_name] = dependencies[matched_name] project.core.ui.echo( "Updating packages: {}.".format( ", ".join( termui.green(v, bold=True) for v in chain.from_iterable(updated_deps.values()) ) ) ) if unconstrained: for deps in updated_deps.values(): for dep in deps.values(): dep.specifier = get_specifier("") reqs = [r for deps in all_dependencies.values() for r in deps.values()] resolved = do_lock( project, strategy, chain.from_iterable(updated_deps.values()), reqs, dry_run=dry_run, ) if sync or dry_run: do_sync( project, groups=groups, dev=install_dev, default=default, clean=False, dry_run=dry_run, requirements=[r for deps in updated_deps.values() for r in deps.values()], tracked_names=list(chain.from_iterable(updated_deps.values())) if top else None, no_editable=no_editable, no_self=no_self, ) if unconstrained and not dry_run: # Need to update version constraints save_version_specifiers(updated_deps, resolved, save) for group, deps in updated_deps.items(): project.add_dependencies(deps, group, dev or False) lockfile = project.lockfile project.write_lockfile(lockfile, False)
def test_prod_should_not_be_with_dev(project): setup_dependencies(project) with pytest.raises(PdmUsageError): cli_utils.translate_groups(project, True, False, ("test", ))
def test_dependency_group_selection(project, args, golden): setup_dependencies(project) target = cli_utils.translate_groups(project, *args) assert sorted(golden) == sorted(target)