示例#1
0
    def _prepare_step_context() -> StepContext:
        """Prepare step context for test scenarios."""
        direct_dependencies = {}
        paths = {}
        source = Source("https://pypi.org/simple")

        for version_identifier in ("0.12.1", "1.0.1"):
            package_tuple = ("flask", version_identifier, source.url)
            direct_dependencies[package_tuple] = PackageVersion(
                name="flask",
                version="==" + version_identifier,
                index=source.url,
                develop=False,
            )

            paths[package_tuple] = [
                (package_tuple, ("werkzeug", "0.13",
                                 "https://pypi.org/simple")),
                (package_tuple, ("werkzeug", "0.14",
                                 "https://pypi.org/simple")),
                (("werkzeug", "0.13", "https://pypi.org/simple"),
                 ("six", "1.7.0", "https://pypi.org/simple")),
                (("werkzeug", "0.13", "https://pypi.org/simple"),
                 ("six", "1.8.0", "https://pypi.org/simple")),
                (("werkzeug", "0.14", "https://pypi.org/simple"),
                 ("six", "1.7.0", "https://pypi.org/simple")),
                (("werkzeug", "0.14", "https://pypi.org/simple"),
                 ("six", "1.8.0", "https://pypi.org/simple")),
            ]

        return StepContext.from_paths(direct_dependencies, paths)
示例#2
0
    def test_not_resolved(self) -> None:
        direct_dependencies = {
            ("flask", "1.12.0", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==1.12.0",
                index="https://pypi.org/simple",
                develop=False,
            )
        }
        paths = {
            ("flask", "1.12.0", "https://pypi.org/simple"):
            [(("flask", "1.12.0", "https://pypi.org/simple"), ("werkzeug",
                                                               "0.13", None))]
        }
        step_context = StepContext.from_paths(direct_dependencies, paths)
        assert ("werkzeug", "0.13",
                None) in step_context.iter_transitive_dependencies_tuple()
        assert ("werkzeug", "0.13", None) in step_context.unsolved_packages
        assert step_context.unsolved_packages.get(
            ("werkzeug", "0.13", None)) is not None

        assert len(
            list(step_context.iter_transitive_dependencies(develop=None))) == 1
        assert len(
            list(
                step_context.iter_transitive_dependencies(develop=False))) == 1
        assert len(
            list(step_context.iter_transitive_dependencies(develop=True))) == 0
        direct_dependencies = list(step_context.iter_direct_dependencies())
        assert len(direct_dependencies) == 1
        assert direct_dependencies[0].name == "flask"
示例#3
0
    def test_remove_package_tuple_transitive_error(self) -> None:
        """Remove a transitive dependency which will cause error during removal."""
        direct_dependencies = {
            ("flask", "0.12.1", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==0.12.1",
                index=Source("https://pypi.org/simple"),
                develop=False,
            )
        }

        paths = {
            ("flask", "0.12.1", "https://pypi.org/simple"): [
                (("flask", "0.12.1", "https://pypi.org/simple"),
                 ("werkzeug", "0.13", "https://pypi.org/simple")),
                (("werkzeug", "0.13", "https://pypi.org/simple"),
                 ("six", "1.0.0", "https://pypi.org/simple")),
            ]
        }

        step_context = StepContext.from_paths(direct_dependencies, paths=paths)

        with pytest.raises(CannotRemovePackage):
            with step_context.remove_package_tuples(
                ("six", "1.0.0", "https://pypi.org/simple")):
                pass
示例#4
0
    def test_remove_package_tuple_transitive_with_direct_diamond_error(
            self) -> None:
        """Test removal of a package which does not have any candidate of direct dependency."""
        direct_dependencies = {
            ("flask", "0.12.1", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==0.12.1",
                index=Source("https://pypi.org/simple"),
                develop=False,
            )
        }

        paths = {
            ("flask", "0.12.1", "https://pypi.org/simple"): [
                (("flask", "0.12.1", "https://pypi.org/simple"),
                 ("werkzeug", "0.13", "https://pypi.org/simple")),
                (("werkzeug", "0.13", "https://pypi.org/simple"),
                 ("six", "1.0.0", "https://pypi.org/simple")),
                (("flask", "0.12.1", "https://pypi.org/simple"),
                 ("werkzeug", "0.14", "https://pypi.org/simple")),
                (("werkzeug", "0.14", "https://pypi.org/simple"),
                 ("six", "1.0.0", "https://pypi.org/simple")),
            ],
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        with pytest.raises(CannotRemovePackage):
            with step_context.remove_package_tuples(
                ("six", "1.0.0", "https://pypi.org/simple")):
                pass
示例#5
0
    def test_no_remove(self):
        """Make sure packages which are not toolchain do not get removed."""
        direct_dependencies = {
            ("goblinoid", "1.0.0", "https://pypi.org/simple"): PackageVersion(
                name="goblinoid",
                version="==1.0.0",
                index=Source("https://pypi.org/simple"),
                develop=False,
            )
        }

        paths = {
            ("goblinoid", "1.0.0", "https://pypi.org/simple"): [
                (("goblinoid", "1.0.0", "https://pypi.org/simple"),
                 ("foo", "1.0.0", "https://pypi.org/simple")),
            ]
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        cut_toolchain = CutToolchain(
            graph=None,
            project=None,
            library_usage=None,
        )
        cut_toolchain.run(step_context)

        assert step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs() == [
            (0.0, (None, ('goblinoid', '1.0.0', 'https://pypi.org/simple'))),
            (0.0, (('goblinoid', '1.0.0', 'https://pypi.org/simple'),
                   ('foo', '1.0.0', 'https://pypi.org/simple'))),
        ]
示例#6
0
    def test_remove_package_tuple_transitive_with_direct_error(self) -> None:
        """Test removal of a package which does not have any candidate of direct dependency."""
        paths = {}
        direct_dependencies = {}
        source = Source("https://pypi.org/simple")
        for version_identifier in ("0.12.1", "1.0.1"):
            package_tuple = ("flask", version_identifier, source.url)

            direct_dependencies[package_tuple] = PackageVersion(
                name="flask",
                version="==" + version_identifier,
                index=source.url,
                develop=False,
            )

            paths[package_tuple] = [
                (package_tuple, ("werkzeug", "0.13",
                                 "https://pypi.org/simple")),
                (package_tuple, ("werkzeug", "0.14",
                                 "https://pypi.org/simple")),
                (("werkzeug", "0.13", "https://pypi.org/simple"),
                 ("six", "1.0.0", "https://pypi.org/simple")),
                (("werkzeug", "0.14", "https://pypi.org/simple"),
                 ("six", "1.0.0", "https://pypi.org/simple")),
            ]

        step_context = StepContext.from_paths(direct_dependencies, paths)

        with pytest.raises(CannotRemovePackage):
            with step_context.remove_package_tuples(
                ("six", "1.0.0", "https://pypi.org/simple")):
                pass
示例#7
0
    def test_remove_all_transitive_error(self):
        """Test raising of an error if all the transitive deps of a type were removed."""
        source = Source("https://pypi.org/simple")
        direct_dependencies = {
            ("tensorflow", "2.0.0", source.url):
            PackageVersion(
                name="tensorflow",
                version="==2.0.0",
                index=source,
                develop=False,
            )
        }

        paths = {
            ("tensorflow", "2.0.0", "https://pypi.org/simple"): [
                (("tensorflow", "2.0.0", "https://pypi.org/simple"),
                 ("numpy", "1.0.0rc1", "https://thoth-station.ninja/simple")),
            ]
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        project = Project.from_strings(self._CASE_PIPFILE)
        restrict_indexes = CutPreReleases(
            graph=None,
            project=project,
            library_usage=None,
        )

        with pytest.raises(CannotRemovePackage):
            restrict_indexes.run(step_context)
    def test_limit_transitive(self):
        """Test cutting of latest versions for transitive dependencies."""
        direct_dependencies = {
            ("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"):
            PackageVersion(
                name="tensorflow",
                version="==2.0.0",
                index=Source("https://thoth-station.ninja/simple"),
                develop=False,
            )
        }

        paths = {
            ("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"): [
                (("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"),
                 ("numpy", "1.0.0", "https://pypi.org/simple")),
            ],
            ("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"): [
                (("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"),
                 ("numpy", "2.0.0", "https://pypi.org/simple")),
            ],
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        limit_latest_versions = LimitLatestVersions(
            graph=None,
            project=None,
            library_usage=None,
        )
        limit_latest_versions.update_parameters({"limit_latest_versions": 1})
        limit_latest_versions.run(step_context)

        pairs = list(
            sorted(step_context.dependency_graph_adaptation.
                   to_scored_package_tuple_pairs(),
                   key=operator.itemgetter(0)))

        assert pairs == [(
            0.0,
            (
                None,
                ("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"),
            ),
        ),
                         (
                             0.0,
                             (
                                 ("tensorflow", "2.0.0",
                                  "https://thoth-station.ninja/simple"),
                                 ("numpy", "2.0.0", "https://pypi.org/simple"),
                             ),
                         )]
        assert list(pv.to_tuple()
                    for pv in step_context.iter_direct_dependencies()) == [
                        ("tensorflow", "2.0.0",
                         "https://thoth-station.ninja/simple")
                    ]
    def test_one_observation(self):
        """Test one observation and subsequent correct reduction."""
        source = Source("https://pypi.org/simple")
        direct_dependencies = {
            ("a", "2.0.0", source.url):
            PackageVersion(
                name="a",
                version="==2.0.0",
                index=source,
                develop=False,
            ),
            ("a", "1.0.0", source.url):
            PackageVersion(
                name="a",
                version="==1.0.0",
                index=source,
                develop=False,
            ),
        }

        paths = {
            ("a", "2.0.0", "https://pypi.org/simple"): [
                (("a", "2.0.0", "https://pypi.org/simple"),
                 ("b", "2.0.0", "https://pypi.org/simple")),
                (("a", "2.0.0", "https://pypi.org/simple"),
                 ("b", "1.0.0", "https://pypi.org/simple")),
            ],
            ("a", "1.0.0", "https://pypi.org/simple"): [
                (("a", "1.0.0", "https://pypi.org/simple"),
                 ("b", "2.0.0", "https://pypi.org/simple")),
                (("a", "1.0.0", "https://pypi.org/simple"),
                 ("b", "1.0.0", "https://pypi.org/simple")),
            ],
        }
        step_context = StepContext.from_paths(direct_dependencies, paths=paths)

        step_context.score_package_tuple(
            ("a", "1.0.0", "https://pypi.org/simple"), 2.0)

        observation_reduction = ObservationReduction(
            graph=None,
            project=None,
            library_usage=None,
        )
        observation_reduction.run(step_context)

        observation_reduced = step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs(
        )
        assert set(observation_reduced) == {
            (2.0, (None, ('a', '1.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '1.0.0', 'https://pypi.org/simple'),
                   ('b', '2.0.0', 'https://pypi.org/simple'))),
        }
    def test_no_observation_latest(self):
        """Test that we always end up with the latest version possible if no observations are found."""
        source = Source("https://pypi.org/simple")
        direct_dependencies = {
            ("tensorflow", "2.0.0", source.url):
            PackageVersion(
                name="tensorflow",
                version="==2.0.0",
                index=Source("https://pypi.org/simple"),
                develop=False,
            ),
            ("tensorflow", "1.9.0", source.url):
            PackageVersion(
                name="tensorflow",
                version="==1.9.0",
                index=Source("https://pypi.org/simple"),
                develop=False,
            ),
        }

        paths = {
            ("tensorflow", "1.9.0", "https://pypi.org/simple"): [
                (("tensorflow", "1.9.0", "https://pypi.org/simple"),
                 ("numpy", "1.0.0", "https://pypi.org/simple")),
                (("tensorflow", "1.9.0", "https://pypi.org/simple"),
                 ("numpy", "2.0.0", "https://pypi.org/simple")),
            ],
            ("tensorflow", "2.0.0", "https://pypi.org/simple"): [
                (("tensorflow", "2.0.0", "https://pypi.org/simple"),
                 ("numpy", "2.0.0", "https://pypi.org/simple")),
                (("tensorflow", "2.0.0", "https://pypi.org/simple"),
                 ("numpy", "1.0.0", "https://pypi.org/simple")),
            ],
        }

        step_context = StepContext.from_paths(direct_dependencies, paths=paths)

        observation_reduction = ObservationReduction(
            graph=None,
            project=None,
            library_usage=None,
        )

        observation_reduction.run(step_context)

        observation_reduced = step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs(
        )
        assert set(observation_reduced) == {
            (0.0, (None, ('tensorflow', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('tensorflow', '2.0.0', 'https://pypi.org/simple'),
                   ('numpy', '2.0.0', 'https://pypi.org/simple')))
        }
示例#11
0
    def test_remove_direct(self):
        """Test removal of direct dependencies which is not a pre-release."""
        source = Source("https://pypi.org/simple")
        direct_dependencies = {
            ("tensorflow", "2.0.0rc1", source.url):
            PackageVersion(
                name="tensorflow",
                version="==2.0.0rc1",
                index=source,
                develop=False,
            ),
            ("tensorflow", "2.0.0", source.url):
            PackageVersion(
                name="tensorflow",
                version="==2.0.0",
                index=source,
                develop=False,
            ),
        }

        paths = {
            ("tensorflow", "2.0.0", "https://pypi.org/simple"): [
                (("tensorflow", "2.0.0", "https://pypi.org/simple"),
                 ("numpy", "1.0.0", "https://pypi.org/simple")),
                (("tensorflow", "2.0.0", "https://pypi.org/simple"),
                 ("numpy", "2.0.0", "https://pypi.org/simple")),
            ],
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        project = Project.from_strings(self._CASE_PIPFILE)
        restrict_indexes = CutPreReleases(
            graph=None,
            project=project,
            library_usage=None,
        )
        restrict_indexes.run(step_context)

        assert step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs(
        ) == [(0.0, (None, ('tensorflow', '2.0.0',
                            'https://pypi.org/simple'))),
              (0.0, (('tensorflow', '2.0.0', 'https://pypi.org/simple'),
                     ('numpy', '1.0.0', 'https://pypi.org/simple'))),
              (0.0, (('tensorflow', '2.0.0', 'https://pypi.org/simple'),
                     ('numpy', '2.0.0', 'https://pypi.org/simple')))]
        assert (len(list(step_context.iter_direct_dependencies())) == 1
                ), "Wrong number of direct dependencies"
示例#12
0
    def test_remove_single22(self):
        """Test removing one single dependency from dependency paths, keep paths with same package of a type.

        In other words - always keep latest toolchain.
        """
        direct_dependencies = {
            ("flask", "0.12", "https://pypi.org/simple"): PackageVersion(
                name="flask",
                version="==0.12",
                index=Source("https://pypi.org/simple"),
                develop=False,
            )
        }

        paths = {
            ("flask", "0.12", "https://pypi.org/simple"): [
                (("flask", "0.12", "https://pypi.org/simple"),
                 ("werkzeug", "0.15.1", "https://pypi.org/simple")),
                (("werkzeug", "0.15.1", "https://pypi.org/simple"),
                 ("wheel", "1.12.0", "https://pypi.org/simple")),
                (("werkzeug", "0.15.1", "https://pypi.org/simple"),
                 ("six", "1.12.1", "https://pypi.org/simple")),
                (("werkzeug", "0.15.1", "https://pypi.org/simple"),
                 ("wheel", "1.12.1", "https://pypi.org/simple")),
            ],
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        cut_toolchain = CutToolchain(
            graph=None,
            project=None,
            library_usage=None,
        )
        cut_toolchain.run(step_context)

        # We always expect the latest one to be present.
        assert step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs() == [
            (0.0, (None, ('flask', '0.12', 'https://pypi.org/simple'))),
            (0.0, (('flask', '0.12', 'https://pypi.org/simple'),
                   ('werkzeug', '0.15.1', 'https://pypi.org/simple'))),
            (0.0, (('werkzeug', '0.15.1', 'https://pypi.org/simple'),
                   ('six', '1.12.1', 'https://pypi.org/simple'))),
            (0.0, (('werkzeug', '0.15.1', 'https://pypi.org/simple'),
                   ('wheel', '1.12.1', 'https://pypi.org/simple')))
        ]
示例#13
0
    def test_remove_multi(self):
        """Check all types of "toolchain" packages get removed."""
        direct_dependencies = {
            ("goblinoid", "1.0.0", "https://pypi.org/simple"): PackageVersion(
                name="goblinoid",
                version="==1.0.0",
                index=Source("https://pypi.org/simple"),
                develop=False,
            )
        }

        paths = {
            ("goblinoid", "1.0.0", "https://pypi.org/simple"): [
                (("goblinoid", "1.0.0", "https://pypi.org/simple"),
                 ("wheel", "1.0.0", "https://pypi.org/simple")),
                (("goblinoid", "1.0.0", "https://pypi.org/simple"),
                 ("wheel", "2.0.0", "https://pypi.org/simple")),
                (("goblinoid", "1.0.0", "https://pypi.org/simple"),
                 ("setuptools", "1.0.0", "https://pypi.org/simple")),
                (("goblinoid", "1.0.0", "https://pypi.org/simple"),
                 ("setuptools", "2.0.0", "https://pypi.org/simple")),
                (("goblinoid", "1.0.0", "https://pypi.org/simple"),
                 ("pip", "1.0.0", "https://pypi.org/simple")),
                (("goblinoid", "1.0.0", "https://pypi.org/simple"),
                 ("pip", "2.0.0", "https://pypi.org/simple")),
            ]
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        cut_toolchain = CutToolchain(
            graph=None,
            project=None,
            library_usage=None,
        )
        cut_toolchain.run(step_context)

        assert step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs() == [
            (0.0, (None, ('goblinoid', '1.0.0', 'https://pypi.org/simple'))),
            (0.0, (('goblinoid', '1.0.0', 'https://pypi.org/simple'),
                   ('wheel', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('goblinoid', '1.0.0', 'https://pypi.org/simple'),
                   ('setuptools', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('goblinoid', '1.0.0', 'https://pypi.org/simple'),
                   ('pip', '2.0.0', 'https://pypi.org/simple')))
        ]
    def test_cyclic(self):
        """Test cyclic dependencies - test we actually break cycles."""
        direct_dependencies = {
            ("a", "2.0.0", "https://pypi.org/simple"):
            PackageVersion(
                name="a",
                version="==2.0.0",
                index=Source("https://pypi.org/simple"),
                develop=False,
            ),
        }

        paths = {
            ("a", "2.0.0", "https://pypi.org/simple"): [
                (("a", "2.0.0", "https://pypi.org/simple"),
                 ("b", "2.0.0", "https://pypi.org/simple")),
                (("b", "2.0.0", "https://pypi.org/simple"),
                 ("c", "2.0.0", "https://pypi.org/simple")),
                (("c", "2.0.0", "https://pypi.org/simple"),
                 ("b", "2.0.0", "https://pypi.org/simple")),
                (("a", "2.0.0", "https://pypi.org/simple"),
                 ("b", "1.0.0", "https://pypi.org/simple")),
            ],
        }

        step_context = StepContext.from_paths(direct_dependencies, paths=paths)

        observation_reduction = ObservationReduction(
            graph=None,
            project=None,
            library_usage=None,
        )
        observation_reduction.run(step_context)

        observation_reduced = step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs(
        )
        assert set(observation_reduced) == {
            (0.0, (None, ('a', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '2.0.0', 'https://pypi.org/simple'),
                   ('b', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('b', '2.0.0', 'https://pypi.org/simple'),
                   ('c', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('c', '2.0.0', 'https://pypi.org/simple'),
                   ('b', '2.0.0', 'https://pypi.org/simple')))
        }
示例#15
0
    def _get_prepared_context():
        direct_dependencies = {
            ("flask", "0.12.0", "https://pypi.org/simple"): PackageVersion(
                name="flask",
                version="==0.12.0",
                index=Source("https://pypi.org/simple"),
                develop=False,
            )
        }

        paths = {
            ("flask", "0.12.0", "https://pypi.org/simple"): [
                (("flask", "0.12.0", "https://pypi.org/simple"), ("click", "2.0", "https://pypi.org/simple")),
                (("flask", "0.12.0", "https://pypi.org/simple"), ("click", "2.1", "https://pypi.org/simple")),
            ],
        }

        return StepContext.from_paths(direct_dependencies, paths)
示例#16
0
    def test_remove_package_tuple_direct_error(self) -> None:
        """Test removal of a package which is a direct dependency and causes issues."""
        direct_dependencies = {
            ("flask", "0.12.1", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==0.12.1",
                index=Source("https://pypi.org/simple"),
                develop=False,
            )
        }

        step_context = StepContext.from_paths(
            direct_dependencies,
            paths={("flask", "0.12.1", "https://pypi.org/simple"): []})

        with pytest.raises(CannotRemovePackage):
            with step_context.remove_package_tuples(
                ("flask", "0.12.1", "https://pypi.org/simple")):
                pass
示例#17
0
    def test_remove_package_tuple_transitive_with_direct_change(self) -> None:
        """Test removal of a transitive dependency which leads to removal of a direct dependency candidate."""
        paths = {}
        direct_dependencies = {}
        source = Source("https://pypi.org/simple")
        for version_identifier in ("0.12.1", "1.0.1"):
            package_tuple = ("flask", version_identifier, source.url)

            direct_dependencies[package_tuple] = PackageVersion(
                name="flask",
                version="==" + version_identifier,
                index=Source("https://pypi.org/simple"),
                develop=False,
            )

        paths[("flask", "0.12.1", "https://pypi.org/simple")] = [
            (("flask", "0.12.1", "https://pypi.org/simple"),
             ("werkzeug", "0.13", "https://pypi.org/simple"))
        ]
        paths[("flask", "1.0.1", "https://pypi.org/simple")] = [
            (("flask", "1.0.1", "https://pypi.org/simple"),
             ("werkzeug", "0.14", "https://pypi.org/simple"))
        ]

        step_context = StepContext.from_paths(direct_dependencies, paths)

        # Now remove werkzeug 0.14 which will lead to removal of flask 1.0.1.
        to_remove = ("werkzeug", "0.14", "https://pypi.org/simple")
        with step_context.remove_package_tuples(to_remove) as txn:
            txn.commit()

        assert len(list(step_context.iter_direct_dependencies())) == 1
        assert len(list(
            step_context.iter_transitive_dependencies_tuple())) == 1
        assert len(list(
            step_context.iter_transitive_dependencies_tuple())) == len(
                list(step_context.iter_transitive_dependencies()))
        assert to_remove not in list(
            step_context.iter_transitive_dependencies_tuple())
示例#18
0
    def _get_prepared_step_context() -> StepContext:
        source = Source("https://pypi.org/simple")
        direct_dependencies = {
            ("flask", "0.12.0", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==0.12.0",
                index=source,
                develop=False,
            ),
            ("flask", "0.13.0", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==0.13.0",
                index=source,
                develop=False,
            ),
        }

        paths = {
            ("flask", "0.12.0", "https://pypi.org/simple"): [
                (("flask", "0.12.0", "https://pypi.org/simple"),
                 ("click", "2.0", "https://pypi.org/simple")),
                (("click", "2.0", "https://pypi.org/simple"),
                 ("pyyaml", "3.12", "https://pypi.org/simple")),
            ],
            ("flask", "0.13.0", "https://pypi.org/simple"): [
                (("flask", "0.13.0", "https://pypi.org/simple"),
                 ("click", "2.0", "https://pypi.org/simple")),
                (("click", "2.0", "https://pypi.org/simple"),
                 ("pyyaml", "3.12", "https://pypi.org/simple")),
                (("click", "2.0", "https://pypi.org/simple"),
                 ("pyyaml", "4.0", "https://pypi.org/simple")),
            ],
        }

        return StepContext.from_paths(direct_dependencies, paths)
    def test_limit_no_change(self):
        """Test cutting off latest versions without any change."""
        source = Source("https://thoth-station.ninja/simple")
        direct_dependencies = {
            ("tensorflow", "1.9.0", source.url):
            PackageVersion(
                name="tensorflow",
                version="==1.9.0",
                index=source,
                develop=False,
            ),
            ("tensorflow", "2.0.0", source.url):
            PackageVersion(
                name="tensorflow",
                version="==2.0.0",
                index=source,
                develop=False,
            ),
        }

        paths = {
            ("tensorflow", "1.9.0", "https://thoth-station.ninja/simple"): [
                (("tensorflow", "1.9.0", "https://thoth-station.ninja/simple"),
                 ("numpy", "1.0.0", "https://pypi.org/simple")),
                (("tensorflow", "1.9.0", "https://thoth-station.ninja/simple"),
                 ("numpy", "2.0.0", "https://pypi.org/simple")),
            ],
            ("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"): {
                (("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"),
                 ("numpy", "1.0.0", "https://pypi.org/simple")),
                (("tensorflow", "2.0.0", "https://thoth-station.ninja/simple"),
                 ("numpy", "2.0.0", "https://pypi.org/simple")),
            }
        }

        step_context = StepContext.from_paths(direct_dependencies, paths)

        limit_latest_versions = LimitLatestVersions(
            graph=None,
            project=None,
            library_usage=None,
        )
        limit_latest_versions.update_parameters({"limit_latest_versions": 2})
        limit_latest_versions.run(step_context)

        pairs = step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs(
        )

        assert set(pairs) == {
            (0.0, (None, ('tensorflow', '1.9.0',
                          'https://thoth-station.ninja/simple'))),
            (0.0, (None, ('tensorflow', '2.0.0',
                          'https://thoth-station.ninja/simple'))),
            (0.0, (('tensorflow', '1.9.0',
                    'https://thoth-station.ninja/simple'),
                   ('numpy', '1.0.0', 'https://pypi.org/simple'))),
            (0.0, (('tensorflow', '1.9.0',
                    'https://thoth-station.ninja/simple'),
                   ('numpy', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('tensorflow', '2.0.0',
                    'https://thoth-station.ninja/simple'),
                   ('numpy', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('tensorflow', '2.0.0',
                    'https://thoth-station.ninja/simple'),
                   ('numpy', '1.0.0', 'https://pypi.org/simple'))),
        }

        assert set(pv.to_tuple()
                   for pv in step_context.iter_direct_dependencies()) == {
                       ("tensorflow", "1.9.0",
                        "https://thoth-station.ninja/simple"),
                       ("tensorflow", "2.0.0",
                        "https://thoth-station.ninja/simple"),
                   }
    def test_multiple_observation(self):
        """Test adjustment based on multiple observations.."""
        source = Source("https://pypi.org/simple")
        direct_dependencies = {
            ("a", "2.0.0", source.url):
            PackageVersion(
                name="a",
                version="==2.0.0",
                index=source,
                develop=False,
            ),
            ("a", "3.0.0", source.url):
            PackageVersion(
                name="a",
                version="==3.0.0",
                index=source,
                develop=False,
            ),
            ("a", "1.0.0", source.url):
            PackageVersion(
                name="a",
                version="==1.0.0",
                index=source,
                develop=False,
            ),
        }

        from itertools import product
        paths_long = list(
            product(
                (
                    ("a", "3.0.0", "https://pypi.org/simple"),
                    ("a", "2.0.0", "https://pypi.org/simple"),
                    ("a", "1.0.0", "https://pypi.org/simple"),
                ),
                (
                    ("b", "3.0.0", "https://pypi.org/simple"),
                    ("b", "2.0.0", "https://pypi.org/simple"),
                    ("b", "1.0.0", "https://pypi.org/simple"),
                ),
                (
                    ("c", "3.0.0", "https://pypi.org/simple"),
                    ("c", "2.0.0", "https://pypi.org/simple"),
                    ("c", "1.0.0", "https://pypi.org/simple"),
                ),
            ))
        paths = {}
        for item in paths_long:
            if item[0] not in paths:
                paths[item[0]] = []

            for idx in range(len(item) - 1):
                paths[item[0]].append((item[idx], item[idx + 1]))

        step_context = StepContext.from_paths(direct_dependencies, paths=paths)

        #       Possibly resolved  |   Score     |  A    B    C   |
        # =========================|=============|================|========================================
        # A1    a==1, b==1, c==1   |    -1.0     |  -             | Removed - no positive observations.
        # A2    a==1, b==1, c==2   |    -0.5     |  -         +   | Kept because of c.
        # A3    a==1, b==1, c==3   |    -1.0     |  -             | Removed - no positive observations.
        # A4    a==1, b==2, c==1   |     1.0     |  -    +        | Removed - c==2 is better.
        # A5    a==1, b==2, c==2   |     1.5     |  -    +    +   | Kept because of b and c.
        # A6    a==1, b==2, c==3   |     1.0     |  -    +        | Removed because c==2 is better.
        # A7    a==1, b==3, c==1   |    -1.0     |  -             | Removed - no positive observations.
        # A8    a==1, b==3, c==2   |    -0.5     |  -         +   | Kept because of c.
        # A9    a==1, b==3, c==3   |    -1.0     |  -             | Removed - c==2 is better.
        #
        # B1    a==2, b==1, c==1   |             |                | See A1.
        # B2    a==2, b==1, c==2   |     0.5     |            +   | See A2.
        # B3    a==2, b==1, c==3   |             |                | See A3.
        # B4    a==2, b==2, c==1   |     2.0     |       +        | See A4.
        # B5    a==2, b==2, c==2   |     2.5     |       +    +   | See A5.
        # B6    a==2, b==2, c==3   |     2.0     |       +        | See A6.
        # B7    a==2, b==3, c==1   |             |                | See A7.
        # B8    a==2, b==3, c==2   |     0.5     |            +   | See A8.
        # B9    a==2, b==3, c==3   |             |                | See A9.
        #
        # C1    a==3, b==1, c==1   |             |  +             | See B1.
        # C2    a==3, b==1, c==2   |     0.5     |  +         +   | See B2.
        # C3    a==3, b==1, c==3   |             |  +             | See B3.
        # C4    a==3, b==2, c==1   |     2.0     |  +    +        | See B4.
        # C5    a==3, b==2, c==2   |     2.5     |  +    +    +   | See B5.
        # C6    a==3, b==2, c==3   |     2.0     |  +    +        | See B6.
        # C7    a==3, b==3, c==1   |             |  +             | See B7.
        # C8    a==3, b==3, c==2   |     0.5     |  +         +   | See B8.
        # C9    a==3, b==3, c==3   |             |  +             | See B9.
        #
        #
        # Note sub-graphs are shared so B1-9 and C1-9 share reasoning with A1-9.
        #

        step_context.score_package_tuple(
            ("a", "1.0.0", "https://pypi.org/simple"), -1.0)
        step_context.score_package_tuple(
            ("a", "3.0.0", "https://pypi.org/simple"), 5.0)
        step_context.score_package_tuple(
            ("b", "2.0.0", "https://pypi.org/simple"), 2.0)
        step_context.score_package_tuple(
            ("c", "2.0.0", "https://pypi.org/simple"), 0.5)

        observation_reduction = ObservationReduction(
            graph=None,
            project=None,
            library_usage=None,
        )
        observation_reduction.run(step_context)

        observation_reduced = step_context.dependency_graph_adaptation.to_scored_package_tuple_pairs(
        )
        assert set(observation_reduced) == {
            (-1.0, (None, ('a', '1.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '1.0.0', 'https://pypi.org/simple'),
                   ('b', '1.0.0', 'https://pypi.org/simple'))),
            (2.0, (('a', '1.0.0', 'https://pypi.org/simple'),
                   ('b', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '1.0.0', 'https://pypi.org/simple'),
                   ('b', '3.0.0', 'https://pypi.org/simple'))),
            (0.0, (None, ('a', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '2.0.0', 'https://pypi.org/simple'),
                   ('b', '1.0.0', 'https://pypi.org/simple'))),
            (2.0, (('a', '2.0.0', 'https://pypi.org/simple'),
                   ('b', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '2.0.0', 'https://pypi.org/simple'),
                   ('b', '3.0.0', 'https://pypi.org/simple'))),
            (5.0, (None, ('a', '3.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '3.0.0', 'https://pypi.org/simple'),
                   ('b', '3.0.0', 'https://pypi.org/simple'))),
            (2.0, (('a', '3.0.0', 'https://pypi.org/simple'),
                   ('b', '2.0.0', 'https://pypi.org/simple'))),
            (0.0, (('a', '3.0.0', 'https://pypi.org/simple'),
                   ('b', '1.0.0', 'https://pypi.org/simple'))),
            (0.5, (('b', '2.0.0', 'https://pypi.org/simple'),
                   ('c', '2.0.0', 'https://pypi.org/simple'))),
            (0.5, (('b', '3.0.0', 'https://pypi.org/simple'),
                   ('c', '2.0.0', 'https://pypi.org/simple'))),
            (0.5, (('b', '1.0.0', 'https://pypi.org/simple'),
                   ('c', '2.0.0', 'https://pypi.org/simple'))),
        }
示例#21
0
    def test_iter_dependencies(self) -> None:
        source = Source("https://pypi.org/simple")

        direct_dependencies = {
            ("flask", "0.12.1", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==0.12.1",
                index=source,
                develop=False,
            ),
            ("pytest", "5.0.1", "https://pypi.org/simple"):
            PackageVersion(
                name="pytest",
                version="==5.0.1",
                index=source,
                develop=True,
            ),
            ("flask", "1.0.2", "https://pypi.org/simple"):
            PackageVersion(
                name="flask",
                version="==1.0.2",
                index=source,
                develop=False,
            ),
        }

        paths = {
            ("flask", "0.12.1", "https://pypi.org/simple"): [
                (("flask", "0.12.1", "https://pypi.org/simple"),
                 ("werkzeug", "0.15.5", "https://pypi.org/simple")),
            ],
            ("flask", "1.0.2", "https://pypi.org/simple"): [
                (("flask", "1.0.2", "https://pypi.org/simple"),
                 ("werkzeug", "0.15.5", "https://pypi.org/simple")),
            ],
            ("pytest", "5.0.1", "https://pypi.org/simple"): [
                (("pytest", "5.0.1", "https://pypi.org/simple"),
                 ("pytest-cov", "2.7.1", "https://pypi.org/simple")),
            ],
        }

        step_context = StepContext.from_paths(direct_dependencies, paths=paths)

        all_dependencies = set(
            pv.to_tuple()
            for pv in step_context.iter_all_dependencies(develop=None))
        assert len(all_dependencies) == 5
        assert all_dependencies == {
            ("flask", "0.12.1", "https://pypi.org/simple"),
            ("pytest", "5.0.1", "https://pypi.org/simple"),
            ("flask", "1.0.2", "https://pypi.org/simple"),
            ("werkzeug", "0.15.5", "https://pypi.org/simple"),
            ("pytest-cov", "2.7.1", "https://pypi.org/simple"),
        }

        all_develop_dependencies = set(
            pv.to_tuple()
            for pv in step_context.iter_all_dependencies(develop=True))
        assert all_develop_dependencies == {
            ("pytest", "5.0.1", "https://pypi.org/simple"),
            ("pytest-cov", "2.7.1", "https://pypi.org/simple"),
        }

        all_nondevelop_dependencies = set(
            pv.to_tuple()
            for pv in step_context.iter_all_dependencies(develop=False))
        assert all_nondevelop_dependencies == {
            ("flask", "0.12.1", "https://pypi.org/simple"),
            ("flask", "1.0.2", "https://pypi.org/simple"),
            ("werkzeug", "0.15.5", "https://pypi.org/simple"),
        }

        transitive_nondevelop_dependencies = set(
            pv.to_tuple()
            for pv in step_context.iter_transitive_dependencies(develop=False))
        assert transitive_nondevelop_dependencies == {
            ("werkzeug", "0.15.5", "https://pypi.org/simple"),
        }

        transitive_develop_dependencies = set(
            pv.to_tuple()
            for pv in step_context.iter_transitive_dependencies(develop=True))
        assert transitive_develop_dependencies == {
            ("pytest-cov", "2.7.1", "https://pypi.org/simple"),
        }

        direct_develop_dependencies = set(
            pv.to_tuple()
            for pv in step_context.iter_direct_dependencies(develop=True))
        assert direct_develop_dependencies == {
            ("pytest", "5.0.1", "https://pypi.org/simple"),
        }

        direct_nondevelop_dependencies = set(
            pv.to_tuple()
            for pv in step_context.iter_direct_dependencies(develop=False))
        assert direct_nondevelop_dependencies == {
            ("flask", "0.12.1", "https://pypi.org/simple"),
            ("flask", "1.0.2", "https://pypi.org/simple"),
        }