Пример #1
0
def test_solver_chooses_from_correct_repository_if_forced_and_transitive_dependency(
    package, installed, locked, io
):
    package.python_versions = "^3.7"
    package.add_dependency("foo", "^1.0")
    package.add_dependency("tomlkit", {"version": "^0.5", "source": "legacy"})

    repo = Repository()
    foo = get_package("foo", "1.0.0")
    foo.add_dependency("tomlkit", "^0.5.0")
    repo.add_package(foo)
    pool = Pool([MockLegacyRepository(), repo, MockPyPIRepository()])

    solver = Solver(package, pool, installed, locked, io)

    ops = solver.solve()

    check_solver_result(
        ops,
        [
            {"job": "install", "package": get_package("tomlkit", "0.5.2")},
            {"job": "install", "package": foo},
        ],
    )

    assert "legacy" == ops[0].package.source_type
    assert "http://foo.bar" == ops[0].package.source_url

    assert "" == ops[1].package.source_type
    assert "" == ops[1].package.source_url
Пример #2
0
    def handle(self):
        from poetry.packages import Dependency
        from poetry.packages import ProjectPackage
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver import parse_constraint

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            requirements = self._determine_requirements(packages)
            requirements = self._format_requirements(requirements)

            # validate requirements format
            for constraint in requirements.values():
                parse_constraint(constraint)

            dependencies = []
            for name, constraint in requirements.items():
                dep = Dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

                dependencies.append(dep)

            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)

            package.python_versions = (self.option("python")
                                       or self.poetry.package.python_versions)
            for dep in dependencies:
                package.requires.append(dep)

        solver = Solver(package, self.poetry.pool, Repository(), Repository(),
                        self.output)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        for op in ops:
            package = op.package
            self.line("  - <info>{}</info> (<comment>{}</comment>)".format(
                package.name, package.version))
            if package.requirements:
                for req_name, req_value in package.requirements.items():
                    self.line("    - {}: {}".format(req_name, req_value))
Пример #3
0
def test_solver_does_not_raise_conflict_for_locked_conditional_dependencies(
    solver, repo, package
):
    package.python_versions = "~2.7 || ^3.4"
    package.add_dependency("A", {"version": "^1.0", "python": "^3.6"})
    package.add_dependency("B", "^1.0")

    package_a = get_package("A", "1.0.0")
    package_a.python_versions = ">=3.6"
    package_a.marker = parse_marker(
        'python_version >= "3.6" and python_version < "4.0"'
    )

    package_b = get_package("B", "1.0.0")

    repo.add_package(package_a)
    repo.add_package(package_b)

    solver._locked = Repository([package_a])
    ops = solver.solve(use_latest=[package_b.name])

    check_solver_result(
        ops,
        [
            {"job": "install", "package": package_a},
            {"job": "install", "package": package_b},
        ],
    )
Пример #4
0
    def handle(self):
        from poetry.packages import Dependency
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver.version_parser import VersionParser

        packages = self.argument('package')

        if not packages:
            package = self.poetry.package
            dependencies = package.requires + package.dev_requires
        else:
            requirements = self._determine_requirements(packages)
            requirements = self._format_requirements(requirements)

            # validate requirements format
            parser = VersionParser()
            for constraint in requirements.values():
                parser.parse_constraints(constraint)

            dependencies = []
            for name, constraint in requirements.items():
                dependencies.append(Dependency(name, constraint))

        solver = Solver(self.poetry.package, self.poetry.pool, Repository(),
                        Repository(), self.output)

        ops = solver.solve(dependencies)

        self.line('')
        self.line('Resolution results:')
        self.line('')

        for op in ops:
            package = op.package
            self.line('  - <info>{}</info> (<comment>{}</comment>)'.format(
                package.name, package.version))
Пример #5
0
def repository() -> Repository:
    return Repository()
Пример #6
0
def repo():
    return Repository()
Пример #7
0
def locked():
    return Repository()
Пример #8
0
    def handle(self):
        from poetry.packages import ProjectPackage
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver import parse_constraint
        from poetry.utils.env import Env

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)
            requirements = self._format_requirements(packages)

            for name, constraint in requirements.items():
                dep = package.add_dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions)

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self.output)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command = self.get_application().find("show")
            show_command.output = self.output
            show_command.init_styles()

            packages = [op.package for op in ops]
            repo = Repository(packages)

            requires = package.requires + package.dev_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(pkg, repo)
                        break

            return 0

        env = Env.get()
        current_python_version = parse_constraint(".".join(
            str(v) for v in env.version_info))
        for op in ops:
            pkg = op.package
            if self.option("install"):
                if not pkg.python_constraint.allows(
                        current_python_version) or not env.is_valid_for_marker(
                            pkg.marker):
                    continue

            self.line("  - <info>{}</info> (<comment>{}</comment>)".format(
                pkg.name, pkg.version))
            if not pkg.python_constraint.is_any():
                self.line("    - python: {}".format(pkg.python_versions))

            if not pkg.marker.is_any():
                self.line("    - marker: {}".format(pkg.marker))
Пример #9
0
def solve_pypi(
    pip_specs: Dict[str, src_parser.Dependency],
    use_latest: List[str],
    pip_locked: Dict[str, src_parser.LockedDependency],
    conda_locked: Dict[str, src_parser.LockedDependency],
    python_version: str,
    platform: str,
    verbose: bool = False,
) -> Dict[str, src_parser.LockedDependency]:
    """
    Solve pip dependencies for the given platform

    Parameters
    ----------
    conda :
        Path to conda, mamba, or micromamba
    use_latest :
        Names of packages to update to the latest version compatible with pip_specs
    pip_specs :
        PEP440 package specifications
    pip_locked :
        Previous solution for the given platform (pip packages only)
    conda_locked :
        Current solution of conda-only specs for the given platform
    python_version :
        Version of Python in conda_locked
    platform :
        Target platform
    verbose :
        Print chatter from solver

    """
    dummy_package = ProjectPackage("_dummy_package_", "0.0.0")
    dependencies = [get_dependency(spec) for spec in pip_specs.values()]
    for dep in dependencies:
        dummy_package.add_dependency(dep)

    pypi = PyPiRepository()
    pool = Pool(repositories=[pypi])

    installed = Repository()
    locked = Repository()

    python_packages = dict()
    for dep in conda_locked.values():
        if dep.name.startswith("__"):
            continue
        try:
            pypi_name = conda_name_to_pypi_name(dep.name).lower()
        except KeyError:
            continue
        # Prefer the Python package when its name collides with the Conda package
        # for the underlying library, e.g. python-xxhash (pypi: xxhash) over xxhash
        # (pypi: no equivalent)
        if pypi_name not in python_packages or pypi_name != dep.name:
            python_packages[pypi_name] = dep.version
    # treat conda packages as both locked and installed
    for name, version in python_packages.items():
        for repo in (locked, installed):
            repo.add_package(Package(name=name, version=version))
    # treat pip packages as locked only
    for spec in pip_locked.values():
        locked.add_package(get_package(spec))

    if verbose:
        io = ConsoleIO()
        io.set_verbosity(VERY_VERBOSE)
    else:
        io = NullIO()
    s = Solver(
        dummy_package,
        pool=pool,
        installed=installed,
        locked=locked,
        io=io,
    )
    to_update = list({spec.name
                      for spec in pip_locked.values()
                      }.intersection(use_latest))
    env = PlatformEnv(python_version, platform)
    # find platform-specific solution (e.g. dependencies conditioned on markers)
    with s.use_environment(env):
        result = s.solve(use_latest=to_update)

    chooser = Chooser(pool, env=env)

    # Extract distributions from Poetry package plan, ignoring uninstalls
    # (usually: conda package with no pypi equivalent) and skipped ops
    # (already installed)
    requirements: List[src_parser.LockedDependency] = []
    for op in result:
        if not isinstance(op, Uninstall) and not op.skipped:
            # Take direct references verbatim
            source: Optional[src_parser.DependencySource] = None
            if op.package.source_type == "url":
                url, fragment = urldefrag(op.package.source_url)
                hash_type, hash = fragment.split("=")
                hash = src_parser.HashModel(**{hash_type: hash})
                source = src_parser.DependencySource(type="url",
                                                     url=op.package.source_url)
            # Choose the most specific distribution for the target
            else:
                link = chooser.choose_for(op.package)
                url = link.url_without_fragment
                hash = src_parser.HashModel(**{link.hash_name: link.hash})

            requirements.append(
                src_parser.LockedDependency(
                    name=op.package.name,
                    version=str(op.package.version),
                    manager="pip",
                    source=source,
                    platform=platform,
                    dependencies={
                        dep.name: str(dep.constraint)
                        for dep in op.package.requires
                    },
                    url=url,
                    hash=hash,
                ))

    # use PyPI names of conda packages to walking the dependency tree and propagate
    # categories from explicit to transitive dependencies
    planned = {
        **{dep.name: dep
           for dep in requirements},
        # prefer conda packages so add them afterwards
    }

    for conda_name, dep in conda_locked.items():
        try:
            pypi_name = conda_name_to_pypi_name(conda_name).lower()
        except KeyError:
            # no conda-name found, assuming conda packages do NOT intersect with the pip package
            continue
        planned[pypi_name] = dep

    src_parser._apply_categories(requested=pip_specs, planned=planned)

    return {dep.name: dep for dep in requirements}
Пример #10
0
    def handle(self):
        from clikit.utils.terminal import Terminal

        from poetry.io.null_io import NullIO
        from poetry.puzzle.solver import Solver
        from poetry.repositories.installed_repository import InstalledRepository
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.helpers import get_package_version_display_string

        package = self.argument("package")

        if self.option("tree"):
            self.init_styles(self.io)

        if self.option("outdated"):
            self._args.set_option("latest", True)

        include_dev = not self.option("no-dev")
        locked_repo = self.poetry.locker.locked_repository(True)

        # Show tree view if requested
        if self.option("tree") and not package:
            requires = self.poetry.package.requires + self.poetry.package.dev_requires
            packages = locked_repo.packages
            for package in packages:
                for require in requires:
                    if package.name == require.name:
                        self.display_package_tree(self._io, package,
                                                  locked_repo)
                        break

            return 0

        table = self.table(style="compact")
        # table.style.line_vc_char = ""
        locked_packages = locked_repo.packages
        pool = Pool(ignore_repository_names=True)
        pool.add_repository(locked_repo)
        solver = Solver(
            self.poetry.package,
            pool=pool,
            installed=Repository(),
            locked=locked_repo,
            io=NullIO(),
        )
        solver.provider.load_deferred(False)
        with solver.use_environment(self.env):
            ops = solver.solve()

        required_locked_packages = set(
            [op.package for op in ops if not op.skipped])

        if self.option("no-dev"):
            required_locked_packages = [
                p for p in locked_packages if p.category == "main"
            ]

        if package:
            pkg = None
            for locked in locked_packages:
                if package.lower() == locked.name:
                    pkg = locked
                    break

            if not pkg:
                raise ValueError("Package {} not found".format(package))

            if self.option("tree"):
                self.display_package_tree(self.io, pkg, locked_repo)

                return 0

            rows = [
                ["<info>name</>", " : <c1>{}</>".format(pkg.pretty_name)],
                [
                    "<info>version</>",
                    " : <b>{}</b>".format(pkg.pretty_version)
                ],
                ["<info>description</>", " : {}".format(pkg.description)],
            ]

            table.add_rows(rows)
            table.render(self.io)

            if pkg.requires:
                self.line("")
                self.line("<info>dependencies</info>")
                for dependency in pkg.requires:
                    self.line(" - <c1>{}</c1> <b>{}</b>".format(
                        dependency.pretty_name, dependency.pretty_constraint))

            return 0

        show_latest = self.option("latest")
        show_all = self.option("all")
        terminal = Terminal()
        width = terminal.width
        name_length = version_length = latest_length = 0
        latest_packages = {}
        latest_statuses = {}
        installed_repo = InstalledRepository.load(self.env)

        # Computing widths
        for locked in locked_packages:
            if locked not in required_locked_packages and not show_all:
                continue

            current_length = len(locked.pretty_name)
            if not self._io.output.supports_ansi():
                installed_status = self.get_installed_status(
                    locked, installed_repo)

                if installed_status == "not-installed":
                    current_length += 4

            if show_latest:
                latest = self.find_latest_package(locked, include_dev)
                if not latest:
                    latest = locked

                latest_packages[locked.pretty_name] = latest
                update_status = latest_statuses[
                    locked.pretty_name] = self.get_update_status(
                        latest, locked)

                if not self.option(
                        "outdated") or update_status != "up-to-date":
                    name_length = max(name_length, current_length)
                    version_length = max(
                        version_length,
                        len(
                            get_package_version_display_string(
                                locked, root=self.poetry.file.parent)),
                    )
                    latest_length = max(
                        latest_length,
                        len(
                            get_package_version_display_string(
                                latest, root=self.poetry.file.parent)),
                    )
            else:
                name_length = max(name_length, current_length)
                version_length = max(
                    version_length,
                    len(
                        get_package_version_display_string(
                            locked, root=self.poetry.file.parent)),
                )

        write_version = name_length + version_length + 3 <= width
        write_latest = name_length + version_length + latest_length + 3 <= width
        write_description = name_length + version_length + latest_length + 24 <= width

        for locked in locked_packages:
            color = "cyan"
            name = locked.pretty_name
            install_marker = ""
            if locked not in required_locked_packages:
                if not show_all:
                    continue

                color = "black;options=bold"
            else:
                installed_status = self.get_installed_status(
                    locked, installed_repo)
                if installed_status == "not-installed":
                    color = "red"

                    if not self._io.output.supports_ansi():
                        # Non installed in non decorated mode
                        install_marker = " (!)"

            if (show_latest and self.option("outdated")
                    and latest_statuses[locked.pretty_name] == "up-to-date"):
                continue

            line = "<fg={}>{:{}}{}</>".format(
                color, name, name_length - len(install_marker), install_marker)
            if write_version:
                line += " <b>{:{}}</b>".format(
                    get_package_version_display_string(
                        locked, root=self.poetry.file.parent),
                    version_length,
                )
            if show_latest:
                latest = latest_packages[locked.pretty_name]
                update_status = latest_statuses[locked.pretty_name]

                if write_latest:
                    color = "green"
                    if update_status == "semver-safe-update":
                        color = "red"
                    elif update_status == "update-possible":
                        color = "yellow"

                    line += " <fg={}>{:{}}</>".format(
                        color,
                        get_package_version_display_string(
                            latest, root=self.poetry.file.parent),
                        latest_length,
                    )

            if write_description:
                description = locked.description
                remaining = width - name_length - version_length - 4
                if show_latest:
                    remaining -= latest_length

                if len(locked.description) > remaining:
                    description = description[:remaining - 3] + "..."

                line += " " + description

            self.line(line)
Пример #11
0
def test_self_update_does_not_update_non_recommended_installation(
    tester: CommandTester,
    http: type[httpretty.httpretty],
    mocker: MockerFixture,
    environ: None,
    tmp_venv: VirtualEnv,
):
    mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv)

    command = tester.command

    new_version = Version.parse(__version__).next_minor().text

    old_poetry = Package("poetry", __version__)
    old_poetry.add_dependency(Factory.create_dependency("cleo", "^0.8.2"))

    new_poetry = Package("poetry", new_version)
    new_poetry.add_dependency(Factory.create_dependency("cleo", "^1.0.0"))

    installed_repository = Repository()
    installed_repository.add_package(old_poetry)
    installed_repository.add_package(Package("cleo", "0.8.2"))

    repository = Repository()
    repository.add_package(new_poetry)
    repository.add_package(Package("cleo", "1.0.0"))

    pool = Pool()
    pool.add_repository(repository)

    command._pool = pool

    with pytest.raises(PoetrySimpleConsoleException):
        tester.execute()
Пример #12
0
def test_self_update_can_update_from_recommended_installation(
    tester: CommandTester,
    http: type[httpretty.httpretty],
    mocker: MockerFixture,
    environ: None,
    tmp_venv: VirtualEnv,
):
    mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv)

    command = tester.command
    command._data_dir = tmp_venv.path.parent

    new_version = Version.parse(__version__).next_minor().text

    old_poetry = Package("poetry", __version__)
    old_poetry.add_dependency(Factory.create_dependency("cleo", "^0.8.2"))

    new_poetry = Package("poetry", new_version)
    new_poetry.add_dependency(Factory.create_dependency("cleo", "^1.0.0"))

    installed_repository = Repository()
    installed_repository.add_package(old_poetry)
    installed_repository.add_package(Package("cleo", "0.8.2"))

    repository = Repository()
    repository.add_package(new_poetry)
    repository.add_package(Package("cleo", "1.0.0"))

    pool = Pool()
    pool.add_repository(repository)

    command._pool = pool

    mocker.patch.object(InstalledRepository,
                        "load",
                        return_value=installed_repository)

    tester.execute()

    expected_output = f"""\
Updating Poetry to 1.2.0

Updating dependencies
Resolving dependencies...

Package operations: 0 installs, 2 updates, 0 removals

  - Updating cleo (0.8.2 -> 1.0.0)
  - Updating poetry ({__version__} -> {new_version})

Updating the poetry script

Poetry ({new_version}) is installed now. Great!
"""

    assert tester.io.fetch_output() == expected_output
Пример #13
0
    def handle(self) -> int:
        from cleo.io.null_io import NullIO
        from poetry.core.packages.project_package import ProjectPackage

        from poetry.factory import Factory
        from poetry.puzzle.solver import Solver
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.env import EnvManager

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            # Using current pool for determine_requirements()
            self._pool = self.poetry.pool

            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)

            # Silencing output
            verbosity = self.io.output.verbosity
            self.io.output.set_verbosity(Verbosity.QUIET)

            requirements = self._determine_requirements(packages)

            self.io.output.set_verbosity(verbosity)

            for constraint in requirements:
                name = constraint.pop("name")
                assert isinstance(name, str)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                constraint["extras"] = extras

                package.add_dependency(
                    Factory.create_dependency(name, constraint))

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions)

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self._io)

        ops = solver.solve().calculate_operations()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command: ShowCommand = self.application.find("show")
            show_command.init_styles(self.io)

            packages = [op.package for op in ops]
            repo = Repository(packages=packages)

            requires = package.all_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(self.io, pkg, repo)
                        break

            return 0

        table = self.table(style="compact")
        table.style.set_vertical_border_chars("", " ")
        rows = []

        if self.option("install"):
            env = EnvManager(self.poetry).get()
            pool = Pool()
            locked_repository = Repository()
            for op in ops:
                locked_repository.add_package(op.package)

            pool.add_repository(locked_repository)

            solver = Solver(package, pool, Repository(), Repository(),
                            NullIO())
            with solver.use_environment(env):
                ops = solver.solve().calculate_operations()

        for op in ops:
            if self.option("install") and op.skipped:
                continue

            pkg = op.package
            row = [
                f"<c1>{pkg.complete_name}</c1>",
                f"<b>{pkg.version}</b>",
            ]

            if not pkg.marker.is_any():
                row[2] = str(pkg.marker)

            rows.append(row)

        table.set_rows(rows)
        table.render()

        return 0
Пример #14
0
    def handle(self) -> int | None:
        from cleo.io.null_io import NullIO
        from cleo.terminal import Terminal

        from poetry.puzzle.solver import Solver
        from poetry.repositories.installed_repository import InstalledRepository
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.helpers import get_package_version_display_string

        package = self.argument("package")

        if self.option("tree"):
            self.init_styles(self.io)

        if self.option("why"):
            if self.option("tree") and package is None:
                self.line_error(
                    "<error>Error: --why requires a package when combined with"
                    " --tree.</error>"
                )

                return 1

            if not self.option("tree") and package:
                self.line_error(
                    "<error>Error: --why cannot be used without --tree when displaying"
                    " a single package.</error>"
                )

                return 1

        if self.option("outdated"):
            self._io.input.set_option("latest", True)

        if not self.poetry.locker.is_locked():
            self.line_error(
                "<error>Error: poetry.lock not found. Run `poetry lock` to create"
                " it.</error>"
            )
            return 1

        locked_repo = self.poetry.locker.locked_repository()
        root = self.project_with_activated_groups_only()

        # Show tree view if requested
        if self.option("tree") and package is None:
            requires = root.all_requires
            packages = locked_repo.packages
            for p in packages:
                for require in requires:
                    if p.name == require.name:
                        self.display_package_tree(self._io, p, locked_repo)
                        break

            return 0

        table = self.table(style="compact")
        locked_packages = locked_repo.packages
        pool = Pool(ignore_repository_names=True)
        pool.add_repository(locked_repo)
        solver = Solver(
            root,
            pool=pool,
            installed=Repository(),
            locked=locked_repo,
            io=NullIO(),
        )
        solver.provider.load_deferred(False)
        with solver.use_environment(self.env):
            ops = solver.solve().calculate_operations()

        required_locked_packages = {op.package for op in ops if not op.skipped}

        if package:
            pkg = None
            for locked in locked_packages:
                if package.lower() == locked.name:
                    pkg = locked
                    break

            if not pkg:
                raise ValueError(f"Package {package} not found")

            required_by = reverse_deps(pkg, locked_repo)

            if self.option("tree"):
                if self.option("why"):
                    # The default case if there's no reverse dependencies is to query
                    # the subtree for pkg but if any rev-deps exist we'll query for each
                    # of them in turn
                    packages = [pkg]
                    if required_by:
                        packages = [
                            p
                            for p in locked_packages
                            for r in required_by.keys()
                            if p.name == r
                        ]
                    else:
                        # if no rev-deps exist we'll make this clear as it can otherwise
                        # look very odd for packages that also have no or few direct
                        # dependencies
                        self._io.write_line(
                            f"Package {package} is a direct dependency."
                        )

                    for p in packages:
                        self.display_package_tree(
                            self._io, p, locked_repo, why_package=pkg
                        )

                else:
                    self.display_package_tree(self._io, pkg, locked_repo)

                return 0

            rows = [
                ["<info>name</>", f" : <c1>{pkg.pretty_name}</>"],
                ["<info>version</>", f" : <b>{pkg.pretty_version}</b>"],
                ["<info>description</>", f" : {pkg.description}"],
            ]

            table.add_rows(rows)
            table.render()

            if pkg.requires:
                self.line("")
                self.line("<info>dependencies</info>")
                for dependency in pkg.requires:
                    self.line(
                        f" - <c1>{dependency.pretty_name}</c1>"
                        f" <b>{dependency.pretty_constraint}</b>"
                    )

            if required_by:
                self.line("")
                self.line("<info>required by</info>")
                for parent, requires_version in required_by.items():
                    self.line(f" - <c1>{parent}</c1> <b>{requires_version}</b>")

            return 0

        show_latest = self.option("latest")
        show_all = self.option("all")
        terminal = Terminal()
        width = terminal.width
        name_length = version_length = latest_length = required_by_length = 0
        latest_packages = {}
        latest_statuses = {}
        installed_repo = InstalledRepository.load(self.env)

        # Computing widths
        for locked in locked_packages:
            if locked not in required_locked_packages and not show_all:
                continue

            current_length = len(locked.pretty_name)
            if not self._io.output.is_decorated():
                installed_status = self.get_installed_status(locked, installed_repo)

                if installed_status == "not-installed":
                    current_length += 4

            if show_latest:
                latest = self.find_latest_package(locked, root)
                if not latest:
                    latest = locked

                latest_packages[locked.pretty_name] = latest
                update_status = latest_statuses[
                    locked.pretty_name
                ] = self.get_update_status(latest, locked)

                if not self.option("outdated") or update_status != "up-to-date":
                    name_length = max(name_length, current_length)
                    version_length = max(
                        version_length,
                        len(
                            get_package_version_display_string(
                                locked, root=self.poetry.file.parent
                            )
                        ),
                    )
                    latest_length = max(
                        latest_length,
                        len(
                            get_package_version_display_string(
                                latest, root=self.poetry.file.parent
                            )
                        ),
                    )

                    if self.option("why"):
                        required_by = reverse_deps(locked, locked_repo)
                        required_by_length = max(
                            required_by_length,
                            len(" from " + ",".join(required_by.keys())),
                        )
            else:
                name_length = max(name_length, current_length)
                version_length = max(
                    version_length,
                    len(
                        get_package_version_display_string(
                            locked, root=self.poetry.file.parent
                        )
                    ),
                )

                if self.option("why"):
                    required_by = reverse_deps(locked, locked_repo)
                    required_by_length = max(
                        required_by_length, len(" from " + ",".join(required_by.keys()))
                    )

        write_version = name_length + version_length + 3 <= width
        write_latest = name_length + version_length + latest_length + 3 <= width

        why_end_column = (
            name_length + version_length + latest_length + required_by_length
        )
        write_why = self.option("why") and (why_end_column + 3) <= width
        write_description = (why_end_column + 24) <= width

        for locked in locked_packages:
            color = "cyan"
            name = locked.pretty_name
            install_marker = ""
            if locked not in required_locked_packages:
                if not show_all:
                    continue

                color = "black;options=bold"
            else:
                installed_status = self.get_installed_status(locked, installed_repo)
                if installed_status == "not-installed":
                    color = "red"

                    if not self._io.output.is_decorated():
                        # Non installed in non decorated mode
                        install_marker = " (!)"

            if (
                show_latest
                and self.option("outdated")
                and latest_statuses[locked.pretty_name] == "up-to-date"
            ):
                continue

            line = (
                f"<fg={color}>"
                f"{name:{name_length - len(install_marker)}}{install_marker}</>"
            )
            if write_version:
                version = get_package_version_display_string(
                    locked, root=self.poetry.file.parent
                )
                line += f" <b>{version:{version_length}}</b>"
            if show_latest:
                latest = latest_packages[locked.pretty_name]
                update_status = latest_statuses[locked.pretty_name]

                if write_latest:
                    color = "green"
                    if update_status == "semver-safe-update":
                        color = "red"
                    elif update_status == "update-possible":
                        color = "yellow"

                    version = get_package_version_display_string(
                        latest, root=self.poetry.file.parent
                    )
                    line += f" <fg={color}>{version:{latest_length}}</>"

            if write_why:
                required_by = reverse_deps(locked, locked_repo)
                if required_by:
                    content = ",".join(required_by.keys())
                    # subtract 6 for ' from '
                    line += f" from {content:{required_by_length - 6}}"
                else:
                    line += " " * required_by_length

            if write_description:
                description = locked.description
                remaining = (
                    width - name_length - version_length - required_by_length - 4
                )

                if show_latest:
                    remaining -= latest_length

                if len(locked.description) > remaining:
                    description = description[: remaining - 3] + "..."

                line += " " + description

            self.line(line)

        return None
Пример #15
0
def _patch_repos(repo: TestRepository, installed: Repository) -> None:
    poetry = Package("poetry", __version__)
    repo.add_package(poetry)
    installed.add_package(poetry)
Пример #16
0
    def handle(self):
        from poetry.core.packages.project_package import ProjectPackage
        from poetry.io.null_io import NullIO
        from poetry.puzzle import Solver
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.env import EnvManager

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            # Using current pool for determine_requirements()
            self._pool = self.poetry.pool

            package = ProjectPackage(
                self.poetry.package.name, self.poetry.package.version
            )

            # Silencing output
            is_quiet = self.io.output.is_quiet()
            if not is_quiet:
                self.io.output.set_quiet(True)

            requirements = self._determine_requirements(packages)

            if not is_quiet:
                self.io.output.set_quiet(False)

            for constraint in requirements:
                name = constraint.pop("name")
                dep = package.add_dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions
        )

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self._io)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command = self.application.find("show")
            show_command.init_styles(self.io)

            packages = [op.package for op in ops]
            repo = Repository(packages)

            requires = package.requires + package.dev_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(self.io, pkg, repo)
                        break

            return 0

        table = self.table([], style="borderless")
        rows = []

        if self.option("install"):
            env = EnvManager(self.poetry).get()
            pool = Pool()
            locked_repository = Repository()
            for op in ops:
                locked_repository.add_package(op.package)

            pool.add_repository(locked_repository)

            solver = Solver(package, pool, Repository(), Repository(), NullIO())
            with solver.use_environment(env):
                ops = solver.solve()

        for op in ops:
            if self.option("install") and op.skipped:
                continue

            pkg = op.package
            row = [
                "<c1>{}</c1>".format(pkg.name),
                "<b>{}</b>".format(pkg.version),
                "",
            ]

            if not pkg.marker.is_any():
                row[2] = str(pkg.marker)

            rows.append(row)

        table.set_rows(rows)
        table.render(self.io)
Пример #17
0
    def handle(self):
        from poetry.packages import ProjectPackage
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver import parse_constraint
        from poetry.utils.env import EnvManager

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            # Using current pool for determine_requirements()
            self._pool = self.poetry.pool

            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)

            # Silencing output
            is_quiet = self.io.output.is_quiet()
            if not is_quiet:
                self.io.output.set_quiet(True)

            requirements = self._determine_requirements(packages)

            if not is_quiet:
                self.io.output.set_quiet(False)

            for constraint in requirements:
                name = constraint.pop("name")
                dep = package.add_dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions)

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self._io)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command = self.application.find("show")
            show_command.init_styles(self.io)

            packages = [op.package for op in ops]
            repo = Repository(packages)

            requires = package.requires + package.dev_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(self.io, pkg, repo)
                        break

            return 0

        env = EnvManager(self.poetry.config).get(self.poetry.file.parent)
        current_python_version = parse_constraint(".".join(
            str(v) for v in env.version_info))
        table = self.table([], style="borderless")
        rows = []
        for op in ops:
            pkg = op.package
            if self.option("install"):
                if not pkg.python_constraint.allows(
                        current_python_version) or not env.is_valid_for_marker(
                            pkg.marker):
                    continue
            row = [
                "<info>{}</info>".format(pkg.name),
                "<b>{}</b>".format(pkg.version),
                "",
            ]

            if not pkg.marker.is_any():
                row[2] = str(pkg.marker)

            rows.append(row)

        table.set_rows(rows)
        table.render(self.io)