Beispiel #1
0
def test_backjump_past_failed_package_on_disjoint_constraint(
        root: ProjectPackage, provider: Provider, repo: Repository):
    root.add_dependency(Factory.create_dependency("a", "*"))
    root.add_dependency(Factory.create_dependency("foo", ">2.0.0"))

    add_to_repo(repo, "a", "1.0.0", deps={"foo": "*"})  # ok
    add_to_repo(repo, "a", "2.0.0",
                deps={"foo":
                      "<1.0.0"})  # disjoint with myapp's constraint on foo

    add_to_repo(repo, "foo", "2.0.0")
    add_to_repo(repo, "foo", "2.0.1")
    add_to_repo(repo, "foo", "2.0.2")
    add_to_repo(repo, "foo", "2.0.3")
    add_to_repo(repo, "foo", "2.0.4")

    check_solver_result(root, provider, {"a": "1.0.0", "foo": "2.0.4"})
Beispiel #2
0
def test_with_incompatible_locked_dependencies(
    root: ProjectPackage, provider: Provider, repo: Repository
):
    root.add_dependency(Factory.create_dependency("foo", ">1.0.1"))

    add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
    add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"})
    add_to_repo(repo, "foo", "1.0.2", deps={"bar": "1.0.2"})
    add_to_repo(repo, "bar", "1.0.0")
    add_to_repo(repo, "bar", "1.0.1")
    add_to_repo(repo, "bar", "1.0.2")

    check_solver_result(
        root,
        provider,
        result={"foo": "1.0.2", "bar": "1.0.2"},
        locked={"foo": get_package("foo", "1.0.1"), "bar": get_package("bar", "1.0.1")},
    )
Beispiel #3
0
def test_shared_dependencies_with_overlapping_constraints(
        root: ProjectPackage, provider: Provider, repo: Repository):
    root.add_dependency(Factory.create_dependency("a", "1.0.0"))
    root.add_dependency(Factory.create_dependency("b", "1.0.0"))

    add_to_repo(repo, "a", "1.0.0", deps={"shared": ">=2.0.0 <4.0.0"})
    add_to_repo(repo, "b", "1.0.0", deps={"shared": ">=3.0.0 <5.0.0"})
    add_to_repo(repo, "shared", "2.0.0")
    add_to_repo(repo, "shared", "3.0.0")
    add_to_repo(repo, "shared", "3.6.9")
    add_to_repo(repo, "shared", "4.0.0")
    add_to_repo(repo, "shared", "5.0.0")

    check_solver_result(root, provider, {
        "a": "1.0.0",
        "b": "1.0.0",
        "shared": "3.6.9"
    })
Beispiel #4
0
def test_disjoint_constraints(root: ProjectPackage, provider: Provider,
                              repo: Repository):
    root.add_dependency(Factory.create_dependency("foo", "1.0.0"))
    root.add_dependency(Factory.create_dependency("bar", "1.0.0"))

    add_to_repo(repo, "foo", "1.0.0", deps={"shared": "<=2.0.0"})
    add_to_repo(repo, "bar", "1.0.0", deps={"shared": ">3.0.0"})
    add_to_repo(repo, "shared", "2.0.0")
    add_to_repo(repo, "shared", "4.0.0")

    error = """\
Because bar (1.0.0) depends on shared (>3.0.0)
 and foo (1.0.0) depends on shared (<=2.0.0),\
 bar (1.0.0) is incompatible with foo (1.0.0).
So, because myapp depends on both foo (1.0.0) and bar (1.0.0), version solving failed.\
"""

    check_solver_result(root, provider, error=error)
    check_solver_result(root, provider, error=error)
Beispiel #5
0
def poetry(tmp_dir: str, config: "Config") -> Poetry:
    poetry = Poetry(
        CWD / "pyproject.toml",
        {},
        ProjectPackage("simple-project", "1.2.3"),
        Locker(CWD / "poetry.lock", {}),
        config,
    )

    return poetry
Beispiel #6
0
def test_rolls_back_leaf_versions_first(root: ProjectPackage,
                                        provider: Provider, repo: Repository):
    # The latest versions of a and b disagree on c. An older version of either
    # will resolve the problem. This test validates that b, which is farther
    # in the dependency graph from myapp is downgraded first.
    root.add_dependency(Factory.create_dependency("a", "*"))

    add_to_repo(repo, "a", "1.0.0", deps={"b": "*"})
    add_to_repo(repo, "a", "2.0.0", deps={"b": "*", "c": "2.0.0"})
    add_to_repo(repo, "b", "1.0.0")
    add_to_repo(repo, "b", "2.0.0", deps={"c": "1.0.0"})
    add_to_repo(repo, "c", "1.0.0")
    add_to_repo(repo, "c", "2.0.0")

    check_solver_result(root, provider, {
        "a": "2.0.0",
        "b": "1.0.0",
        "c": "2.0.0"
    })
Beispiel #7
0
def test_shared_dependency_where_dependent_version_affects_other_dependencies(
        root: ProjectPackage, provider: Provider, repo: Repository):
    root.add_dependency(Factory.create_dependency("foo", "<=1.0.2"))
    root.add_dependency(Factory.create_dependency("bar", "1.0.0"))

    add_to_repo(repo, "foo", "1.0.0")
    add_to_repo(repo, "foo", "1.0.1", deps={"bang": "1.0.0"})
    add_to_repo(repo, "foo", "1.0.2", deps={"whoop": "1.0.0"})
    add_to_repo(repo, "foo", "1.0.3", deps={"zoop": "1.0.0"})
    add_to_repo(repo, "bar", "1.0.0", deps={"foo": "<=1.0.1"})
    add_to_repo(repo, "bang", "1.0.0")
    add_to_repo(repo, "whoop", "1.0.0")
    add_to_repo(repo, "zoop", "1.0.0")

    check_solver_result(root, provider, {
        "foo": "1.0.1",
        "bar": "1.0.0",
        "bang": "1.0.0"
    })
Beispiel #8
0
def test_diamond_dependency_graph(root: ProjectPackage, provider: Provider,
                                  repo: Repository):
    root.add_dependency(Factory.create_dependency("a", "*"))
    root.add_dependency(Factory.create_dependency("b", "*"))

    add_to_repo(repo, "a", "2.0.0", deps={"c": "^1.0.0"})
    add_to_repo(repo, "a", "1.0.0")

    add_to_repo(repo, "b", "2.0.0", deps={"c": "^3.0.0"})
    add_to_repo(repo, "b", "1.0.0", deps={"c": "^2.0.0"})

    add_to_repo(repo, "c", "3.0.0")
    add_to_repo(repo, "c", "2.0.0")
    add_to_repo(repo, "c", "1.0.0")

    check_solver_result(root, provider, {
        "a": "1.0.0",
        "b": "2.0.0",
        "c": "3.0.0"
    })
Beispiel #9
0
def test_no_valid_solution(root: ProjectPackage, provider: Provider,
                           repo: Repository):
    root.add_dependency(Factory.create_dependency("a", "*"))
    root.add_dependency(Factory.create_dependency("b", "*"))

    add_to_repo(repo, "a", "1.0.0", deps={"b": "1.0.0"})
    add_to_repo(repo, "a", "2.0.0", deps={"b": "2.0.0"})

    add_to_repo(repo, "b", "1.0.0", deps={"a": "2.0.0"})
    add_to_repo(repo, "b", "2.0.0", deps={"a": "1.0.0"})

    error = """\
Because no versions of b match <1.0.0 || >1.0.0,<2.0.0 || >2.0.0
 and b (1.0.0) depends on a (2.0.0), b (!=2.0.0) requires a (2.0.0).
And because a (2.0.0) depends on b (2.0.0), b is forbidden.
Because b (2.0.0) depends on a (1.0.0) which depends on b (1.0.0), b is forbidden.
Thus, b is forbidden.
So, because myapp depends on b (*), version solving failed."""

    check_solver_result(root, provider, error=error, tries=2)
Beispiel #10
0
def test_no_version_that_matches_combined_constraints(root: ProjectPackage,
                                                      provider: Provider,
                                                      repo: Repository):
    root.add_dependency(Factory.create_dependency("foo", "1.0.0"))
    root.add_dependency(Factory.create_dependency("bar", "1.0.0"))

    add_to_repo(repo, "foo", "1.0.0", deps={"shared": ">=2.0.0 <3.0.0"})
    add_to_repo(repo, "bar", "1.0.0", deps={"shared": ">=2.9.0 <4.0.0"})
    add_to_repo(repo, "shared", "2.5.0")
    add_to_repo(repo, "shared", "3.5.0")

    error = """\
Because foo (1.0.0) depends on shared (>=2.0.0 <3.0.0)
 and no versions of shared match >=2.9.0,<3.0.0,\
 foo (1.0.0) requires shared (>=2.0.0,<2.9.0).
And because bar (1.0.0) depends on shared (>=2.9.0 <4.0.0),\
 bar (1.0.0) is incompatible with foo (1.0.0).
So, because myapp depends on both foo (1.0.0) and bar (1.0.0), version solving failed.\
"""

    check_solver_result(root, provider, error=error)
Beispiel #11
0
def test_simple_transitive(root: ProjectPackage, provider: Provider,
                           repo: Repository):
    # Only one version of baz, so foo and bar will have to downgrade
    # until they reach it
    root.add_dependency(Factory.create_dependency("foo", "*"))

    add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
    add_to_repo(repo, "foo", "2.0.0", deps={"bar": "2.0.0"})
    add_to_repo(repo, "foo", "3.0.0", deps={"bar": "3.0.0"})

    add_to_repo(repo, "bar", "1.0.0", deps={"baz": "*"})
    add_to_repo(repo, "bar", "2.0.0", deps={"baz": "2.0.0"})
    add_to_repo(repo, "bar", "3.0.0", deps={"baz": "3.0.0"})

    add_to_repo(repo, "baz", "1.0.0")

    check_solver_result(root,
                        provider, {
                            "foo": "1.0.0",
                            "bar": "1.0.0",
                            "baz": "1.0.0"
                        },
                        tries=3)
Beispiel #12
0
def test_backjumps_after_partial_satisfier(root: ProjectPackage,
                                           provider: Provider,
                                           repo: Repository):
    # c 2.0.0 is incompatible with y 2.0.0 because it requires x 1.0.0, but that
    # requirement only exists because of both a and b. The solver should be able
    # to deduce c 2.0.0's incompatibility and select c 1.0.0 instead.
    root.add_dependency(Factory.create_dependency("c", "*"))
    root.add_dependency(Factory.create_dependency("y", "^2.0.0"))

    add_to_repo(repo, "a", "1.0.0", deps={"x": ">=1.0.0"})
    add_to_repo(repo, "b", "1.0.0", deps={"x": "<2.0.0"})

    add_to_repo(repo, "c", "1.0.0")
    add_to_repo(repo, "c", "2.0.0", deps={"a": "*", "b": "*"})

    add_to_repo(repo, "x", "0.0.0")
    add_to_repo(repo, "x", "1.0.0", deps={"y": "1.0.0"})
    add_to_repo(repo, "x", "2.0.0")

    add_to_repo(repo, "y", "1.0.0")
    add_to_repo(repo, "y", "2.0.0")

    check_solver_result(root, provider, {"c": "1.0.0", "y": "2.0.0"}, tries=2)
Beispiel #13
0
def test_simple_dependencies(root: ProjectPackage, provider: Provider,
                             repo: Repository):
    root.add_dependency(Factory.create_dependency("a", "1.0.0"))
    root.add_dependency(Factory.create_dependency("b", "1.0.0"))

    add_to_repo(repo, "a", "1.0.0", deps={"aa": "1.0.0", "ab": "1.0.0"})
    add_to_repo(repo, "b", "1.0.0", deps={"ba": "1.0.0", "bb": "1.0.0"})
    add_to_repo(repo, "aa", "1.0.0")
    add_to_repo(repo, "ab", "1.0.0")
    add_to_repo(repo, "ba", "1.0.0")
    add_to_repo(repo, "bb", "1.0.0")

    check_solver_result(
        root,
        provider,
        {
            "a": "1.0.0",
            "aa": "1.0.0",
            "ab": "1.0.0",
            "b": "1.0.0",
            "ba": "1.0.0",
            "bb": "1.0.0",
        },
    )
Beispiel #14
0
def test_backjump_to_nearer_unsatisfied_package(root: ProjectPackage,
                                                provider: Provider,
                                                repo: Repository):
    # This ensures it doesn't exhaustively search all versions of b when it's
    # a-2.0.0 whose dependency on c-2.0.0-nonexistent led to the problem. We
    # make sure b has more versions than a so that the solver tries a first
    # since it sorts sibling dependencies by number of versions.
    root.add_dependency(Factory.create_dependency("a", "*"))
    root.add_dependency(Factory.create_dependency("b", "*"))

    add_to_repo(repo, "a", "1.0.0", deps={"c": "1.0.0"})
    add_to_repo(repo, "a", "2.0.0", deps={"c": "2.0.0-1"})
    add_to_repo(repo, "b", "1.0.0")
    add_to_repo(repo, "b", "2.0.0")
    add_to_repo(repo, "b", "3.0.0")
    add_to_repo(repo, "c", "1.0.0")

    check_solver_result(root,
                        provider, {
                            "a": "1.0.0",
                            "b": "3.0.0",
                            "c": "1.0.0"
                        },
                        tries=2)
Beispiel #15
0
    def handle(self) -> int:
        from pathlib import Path

        import tomlkit

        from cleo.io.inputs.string_input import StringInput
        from cleo.io.io import IO
        from poetry.core.pyproject.toml import PyProjectTOML
        from poetry.core.semver.helpers import parse_constraint

        from poetry.factory import Factory
        from poetry.packages.project_package import ProjectPackage
        from poetry.repositories.installed_repository import InstalledRepository
        from poetry.utils.env import EnvManager

        plugins = self.argument("plugins")

        # Plugins should be installed in the system env to be globally available
        system_env = EnvManager.get_system_env(naive=True)

        env_dir = Path(os.getenv("POETRY_HOME") or system_env.path)

        # We check for the plugins existence first.
        if env_dir.joinpath("pyproject.toml").exists():
            pyproject = tomlkit.loads(
                env_dir.joinpath("pyproject.toml").read_text(encoding="utf-8"))
            poetry_content = pyproject["tool"]["poetry"]
            existing_packages = self.get_existing_packages_from_input(
                plugins, poetry_content, "dependencies")

            if existing_packages:
                self.notify_about_existing_packages(existing_packages)

            plugins = [
                plugin for plugin in plugins if plugin not in existing_packages
            ]

        if not plugins:
            return 0

        plugins = self._determine_requirements(plugins)

        # We retrieve the packages installed in the system environment.
        # We assume that this environment will be a self contained virtual environment
        # built by the official installer or by pipx.
        # If not, it might lead to side effects since other installed packages
        # might not be required by Poetry but still taken into account when resolving dependencies.
        installed_repository = InstalledRepository.load(system_env,
                                                        with_dependencies=True)

        root_package = None
        for package in installed_repository.packages:
            if package.name == "poetry":
                root_package = ProjectPackage(package.name, package.version)
                for dependency in package.requires:
                    root_package.add_dependency(dependency)

                break

        root_package.python_versions = ".".join(
            str(v) for v in system_env.version_info[:3])
        # We create a `pyproject.toml` file based on all the information
        # we have about the current environment.
        if not env_dir.joinpath("pyproject.toml").exists():
            Factory.create_pyproject_from_package(root_package, env_dir)

        # We add the plugins to the dependencies section of the previously
        # created `pyproject.toml` file
        pyproject = PyProjectTOML(env_dir.joinpath("pyproject.toml"))
        poetry_content = pyproject.poetry_config
        poetry_dependency_section = poetry_content["dependencies"]
        plugin_names = []
        for plugin in plugins:
            if "version" in plugin:
                # Validate version constraint
                parse_constraint(plugin["version"])

            constraint = tomlkit.inline_table()
            for name, value in plugin.items():
                if name == "name":
                    continue

                constraint[name] = value

            if len(constraint) == 1 and "version" in constraint:
                constraint = constraint["version"]

            poetry_dependency_section[plugin["name"]] = constraint
            plugin_names.append(plugin["name"])

        pyproject.save()

        # From this point forward, all the logic will be deferred to
        # the update command, by using the previously created `pyproject.toml`
        # file.
        application = cast(Application, self.application)
        update_command: UpdateCommand = cast(UpdateCommand,
                                             application.find("update"))
        # We won't go through the event dispatching done by the application
        # so we need to configure the command manually
        update_command.set_poetry(Factory().create_poetry(env_dir))
        update_command.set_env(system_env)
        application._configure_installer(update_command, self._io)

        argv = ["update"] + plugin_names
        if self.option("dry-run"):
            argv.append("--dry-run")

        return update_command.run(
            IO(
                StringInput(" ".join(argv)),
                self._io.output,
                self._io.error_output,
            ))
Beispiel #16
0
def root():
    return ProjectPackage('myapp', '0.0.0')
Beispiel #17
0
def root():
    return ProjectPackage("root", "1.2.3")
Beispiel #18
0
 def get_package(cls, name: str, version: str) -> ProjectPackage:
     return ProjectPackage(name, version, version)
def root():
    return ProjectPackage("myapp", "0.0.0")