예제 #1
0
def do_lock(
    project: Project,
    strategy: str = "all",
    tracked_names: Optional[Iterable[str]] = None,
    requirements: Optional[List[Requirement]] = None,
) -> Dict[str, Candidate]:
    """Performs the locking process and update lockfile.

    :param project: the project instance
    :param strategy: update stratege: reuse/eager/all
    :param tracked_names: required when using eager strategy
    :param requirements: An optional dictionary of requirements, read from pyproject
        if not given.
    """
    check_project_file(project)
    # TODO: multiple dependency definitions for the same package.
    provider = project.get_provider(strategy, tracked_names)
    if not requirements:
        requirements = [
            r for deps in project.all_dependencies.values()
            for r in deps.values()
        ]

    with stream.open_spinner(title="Resolving dependencies",
                             spinner="dots") as spin, stream.logging("lock"):
        reporter = project.get_reporter(requirements, tracked_names, spin)
        resolver = project.core.resolver_class(provider, reporter)
        mapping, dependencies, summaries = resolve(
            resolver, requirements, project.environment.python_requires)
        data = format_lockfile(mapping, dependencies, summaries)
        spin.succeed("Resolution success")
    project.write_lockfile(data)

    return mapping
예제 #2
0
def resolve_requirements(
    repository,
    lines,
    requires_python="",
    allow_prereleases=None,
    strategy="all",
    preferred_pins=None,
    tracked_names=None,
):
    requirements = []
    for line in lines:
        if line.startswith("-e "):
            requirements.append(parse_requirement(line[3:], True))
        else:
            requirements.append(parse_requirement(line))
    requires_python = PySpecSet(requires_python)
    if not preferred_pins:
        provider = BaseProvider(repository, requires_python, allow_prereleases)
    else:
        provider_class = (ReusePinProvider
                          if strategy == "reuse" else EagerUpdateProvider)
        provider = provider_class(
            preferred_pins,
            tracked_names or (),
            repository,
            requires_python,
            allow_prereleases,
        )
    ui = termui.UI()
    with ui.open_spinner("Resolving dependencies") as spin, ui.logging("lock"):
        reporter = SpinnerReporter(spin, requirements)
        resolver = Resolver(provider, reporter)
        mapping, *_ = resolve(resolver, requirements, requires_python)
        return mapping
예제 #3
0
파일: test_resolve.py 프로젝트: pcskys/pdm
def resolve_requirements(
    repository,
    lines,
    requires_python="",
    allow_prereleases=None,
    strategy="reuse",
    preferred_pins=None,
    tracked_names=None,
):
    requirements = {}
    if isinstance(lines, list):
        lines = {"default": lines}
    for k, v in lines.items():
        for line in v:
            req = parse_requirement(line)
            requirements.setdefault(k, {})[identify(req)] = req
    requires_python = PySpecSet(requires_python)
    if not preferred_pins:
        provider = BaseProvider(repository, requires_python, allow_prereleases)
    else:
        provider_class = (ReusePinProvider
                          if strategy == "reuse" else EagerUpdateProvider)
        provider = provider_class(
            preferred_pins,
            tracked_names or (),
            repository,
            requires_python,
            allow_prereleases,
        )
    flat_reqs = list(
        itertools.chain(*[deps.values() for _, deps in requirements.items()]))
    reporter = SimpleReporter(flat_reqs)
    resolver = Resolver(provider, reporter)
    mapping, *_ = resolve(resolver, requirements, requires_python)
    return mapping
예제 #4
0
파일: actions.py 프로젝트: ulwlu/pdm
def do_lock(
    project: Project,
    strategy: str = "all",
    tracked_names: Optional[Iterable[str]] = None,
    requirements: Optional[List[Requirement]] = None,
) -> Dict[str, Candidate]:
    """Performs the locking process and update lockfile.

    :param project: the project instance
    :param strategy: update strategy: reuse/eager/all
    :param tracked_names: required when using eager strategy
    :param requirements: An optional dictionary of requirements, read from pyproject
        if not given.
    """
    check_project_file(project)
    # TODO: multiple dependency definitions for the same package.
    provider = project.get_provider(strategy, tracked_names)
    if not requirements:
        requirements = [
            r for deps in project.all_dependencies.values()
            for r in deps.values()
        ]
    resolve_max_rounds = int(project.config["strategy.resolve_max_rounds"])
    ui = project.core.ui
    with ui.logging("lock"):
        # The context managers are nested to ensure the spinner is stopped before
        # any message is thrown to the output.
        with ui.open_spinner(title="Resolving dependencies",
                             spinner="dots") as spin:
            reporter = project.get_reporter(requirements, tracked_names, spin)
            resolver = project.core.resolver_class(provider, reporter)
            try:
                mapping, dependencies, summaries = resolve(
                    resolver,
                    requirements,
                    project.environment.python_requires,
                    resolve_max_rounds,
                )
            except ResolutionTooDeep:
                spin.fail(f"{termui.Emoji.LOCK} Lock failed")
                ui.echo(
                    "The dependency resolution exceeds the maximum loop depth of "
                    f"{resolve_max_rounds}, there may be some circular dependencies "
                    "in your project. Try to solve them or increase the "
                    f"{termui.green('`strategy.resolve_max_rounds`')} config.",
                    err=True,
                )
                raise
            except ResolutionImpossible as err:
                spin.fail(f"{termui.Emoji.LOCK} Lock failed")
                ui.echo(format_resolution_impossible(err), err=True)
                raise
            else:
                data = format_lockfile(mapping, dependencies, summaries)
                spin.succeed(f"{termui.Emoji.LOCK} Lock successful")
    project.write_lockfile(data)

    return mapping
예제 #5
0
파일: actions.py 프로젝트: stacklens/pdm
def do_lock(
    project: Project,
    strategy: str = "all",
    tracked_names: Optional[Iterable[str]] = None,
    requirements: Optional[Dict[str, Dict[str, Requirement]]] = None,
) -> Dict[str, Candidate]:
    """Performs the locking process and update lockfile.

    :param project: the project instance
    :param strategy: update stratege: reuse/eager/all
    :param tracked_names: required when using eager strategy
    :param requirements: An optional dictionary of requirements, read from pyproject
        if not given.
    """
    check_project_file(project)
    # TODO: multiple dependency definitions for the same package.
    repository = project.get_repository()
    requirements = requirements or project.all_dependencies
    allow_prereleases = project.allow_prereleases
    requires_python = project.python_requires
    if strategy == "all":
        provider = BaseProvider(repository, requires_python, allow_prereleases)
    else:
        provider_class = (ReusePinProvider
                          if strategy == "reuse" else EagerUpdateProvider)
        preferred_pins = project.get_locked_candidates("__all__")
        provider = provider_class(
            preferred_pins,
            tracked_names or (),
            repository,
            requires_python,
            allow_prereleases,
        )
    flat_reqs = list(
        itertools.chain(*[deps.values() for _, deps in requirements.items()]))
    # TODO: switch reporter at io level.
    with halo.Halo(text="Resolving dependencies", spinner="dots") as spin:
        reporter = SpinnerReporter(flat_reqs, spin)
        mapping, dependencies, summaries = resolve(provider, reporter,
                                                   requirements,
                                                   requires_python)
        data = format_lockfile(mapping, dependencies, summaries)
        spin.succeed("Resolution success")
    project.write_lockfile(data)

    return mapping
예제 #6
0
def resolve_candidates_from_lockfile(
    project: Project, requirements: Iterable[Requirement]
) -> dict[str, Candidate]:
    ui = project.core.ui
    resolve_max_rounds = int(project.config["strategy.resolve_max_rounds"])
    reqs = [
        req
        for req in requirements
        if not req.marker or req.marker.evaluate(project.environment.marker_environment)
    ]
    with ui.logging("install-resolve"):
        with ui.open_spinner("Resolving packages from lockfile..."):
            reporter = BaseReporter()
            provider = project.get_provider(for_install=True)
            resolver: Resolver = project.core.resolver_class(provider, reporter)
            mapping, *_ = resolve(
                resolver,
                reqs,
                project.environment.python_requires,
                resolve_max_rounds,
            )
    return mapping
예제 #7
0
def do_lock(
    project: Project,
    strategy: str = "all",
    tracked_names: Iterable[str] | None = None,
    requirements: list[Requirement] | None = None,
    dry_run: bool = False,
    refresh: bool = False,
) -> dict[str, Candidate]:
    """Performs the locking process and update lockfile."""
    check_project_file(project)
    if refresh:
        locked_repo = project.locked_repository
        repo = project.get_repository()
        mapping: dict[str, Candidate] = {}
        dependencies: dict[str, list[Requirement]] = {}
        with project.core.ui.open_spinner("Re-calculating hashes..."):
            for key, candidate in locked_repo.packages.items():
                reqs, python_requires, summary = locked_repo.candidate_info[key]
                candidate.hashes = repo.get_hashes(candidate)
                candidate.summary = summary
                candidate.requires_python = python_requires
                ident = cast(str, key[0])
                mapping[ident] = candidate
                dependencies[ident] = list(map(parse_requirement, reqs))
            lockfile = format_lockfile(project, mapping, dependencies)
        project.write_lockfile(lockfile)
        return mapping
    # TODO: multiple dependency definitions for the same package.
    provider = project.get_provider(strategy, tracked_names)
    if not requirements:
        requirements = [
            r for deps in project.all_dependencies.values() for r in deps.values()
        ]
    resolve_max_rounds = int(project.config["strategy.resolve_max_rounds"])
    ui = project.core.ui
    with ui.logging("lock"):
        # The context managers are nested to ensure the spinner is stopped before
        # any message is thrown to the output.
        with ui.open_spinner(title="Resolving dependencies", spinner="dots") as spin:
            reporter = project.get_reporter(requirements, tracked_names, spin)
            resolver: Resolver = project.core.resolver_class(provider, reporter)
            signals.pre_lock.send(project, requirements=requirements, dry_run=dry_run)
            try:
                mapping, dependencies = resolve(
                    resolver,
                    requirements,
                    project.environment.python_requires,
                    resolve_max_rounds,
                )
            except ResolutionTooDeep:
                spin.fail(f"{termui.Emoji.LOCK} Lock failed")
                ui.echo(
                    "The dependency resolution exceeds the maximum loop depth of "
                    f"{resolve_max_rounds}, there may be some circular dependencies "
                    "in your project. Try to solve them or increase the "
                    f"{termui.green('`strategy.resolve_max_rounds`')} config.",
                    err=True,
                )
                raise
            except ResolutionImpossible as err:
                spin.fail(f"{termui.Emoji.LOCK} Lock failed")
                ui.echo(format_resolution_impossible(err), err=True)
                raise ResolutionImpossible("Unable to find a resolution") from None
            else:
                data = format_lockfile(project, mapping, dependencies)
                spin.succeed(f"{termui.Emoji.LOCK} Lock successful")
            signals.post_lock.send(project, resolution=mapping, dry_run=dry_run)

    project.write_lockfile(data, write=not dry_run)

    return mapping