示例#1
0
    def test_top_level_import(self):
        graph = ImportGraph()
        graph.add_import(importer="green", imported="blue")

        result = graph.find_shortest_chains(importer="green", imported="blue")

        assert result == {("green", "blue")}
示例#2
0
def test_add_module():
    graph = ImportGraph()
    module = "foo"

    graph.add_module(module)

    assert graph.modules == {module}
示例#3
0
def test_count_imports(imports, expected_count):
    graph = ImportGraph()

    for importer, imported in imports:
        graph.add_import(importer=importer, imported=imported)

    assert expected_count == graph.count_imports()
示例#4
0
def test_ignore_imports(ignore_imports, is_kept):
    graph = ImportGraph()
    graph.add_module("mypackage")
    graph.add_import(importer="mypackage.a",
                     imported="mypackage.irrelevant",
                     line_number=1,
                     line_contents="-")
    graph.add_import(importer="mypackage.a",
                     imported="mypackage.indirect",
                     line_number=1,
                     line_contents="-")
    graph.add_import(importer="mypackage.indirect",
                     imported="mypackage.b",
                     line_number=1,
                     line_contents="-")
    contract = IndependenceContract(
        name="Independence contract",
        session_options={"root_packages": ["mypackage"]},
        contract_options={
            "modules": ("mypackage.a", "mypackage.b"),
            "ignore_imports": ignore_imports,
        },
    )

    contract_check = contract.check(graph=graph)

    assert is_kept == contract_check.kept
示例#5
0
def test_invalid_container(container):
    graph = ImportGraph()
    for module in (
        "mypackage",
        "mypackage.foo",
        "mypackage.foo.high",
        "mypackage.foo.medium",
        "mypackage.foo.low",
        "notinpackage",
        "mypackagebeginscorrectly",
    ):
        graph.add_module(module)

    contract = LayersContract(
        name="Layer contract",
        session_options={"root_packages": ["mypackage"]},
        contract_options={
            "containers": ["mypackage.foo", container],
            "layers": ["high", "medium", "low"],
        },
    )

    with pytest.raises(
        ValueError,
        match=(
            f"Invalid container '{container}': a container must either be a subpackage of "
            "mypackage, or mypackage itself."
        ),
    ):
        contract.check(graph=graph)
示例#6
0
def test_optional_layers(include_parentheses, should_raise_exception):
    graph = ImportGraph()
    for module in (
        "mypackage",
        "mypackage.foo",
        "mypackage.foo.high",
        "mypackage.foo.high.blue",
        "mypackage.foo.low",
        "mypackage.foo.low.alpha",
    ):
        graph.add_module(module)

    contract = LayersContract(
        name="Layer contract",
        session_options={"root_packages": ["mypackage"]},
        contract_options={
            "containers": ["mypackage.foo"],
            "layers": ["high", "(medium)" if include_parentheses else "medium", "low"],
        },
    )

    if should_raise_exception:
        with pytest.raises(
            ValueError,
            match=(
                "Missing layer in container 'mypackage.foo': "
                "module mypackage.foo.medium does not exist."
            ),
        ):
            contract.check(graph=graph)
    else:
        contract.check(graph=graph)
示例#7
0
def test_find_shortest_chain_returns_none_if_not_exists():
    graph = ImportGraph()
    a, b, c = "foo", "bar", "baz"

    graph.add_import(importer=a, imported=b)
    graph.add_import(importer=b, imported=c)

    assert None is graph.find_shortest_chain(importer=c, imported=a)
示例#8
0
    def test_can_repeatedly_add_same_squashed_module(self):
        graph = ImportGraph()
        module = "foo"

        graph.add_module(module, is_squashed=True)
        graph.add_module(module, is_squashed=True)

        assert graph.modules == {module}
示例#9
0
    def test_returns_empty_list_when_import_but_no_available_details(self):
        graph = ImportGraph()

        importer, imported = "foo", "bar"
        graph.add_import(importer=importer, imported=imported),

        assert [] == graph.get_import_details(importer=importer,
                                              imported=imported)
示例#10
0
    def test_finds_two_step_path(self):
        graph = ImportGraph()
        self._add_chain(graph, "foo", "bar", "baz")

        result = tuple(
            graph.find_all_simple_chains(importer="foo", imported="baz"))

        assert (("foo", "bar", "baz"), ) == result
示例#11
0
    def test_finds_no_paths_if_wrong_direction(self):
        graph = ImportGraph()
        self._add_chain(graph, "foo", "bar")

        result = list(
            graph.find_all_simple_chains(importer="bar", imported="foo"))

        assert [] == result
示例#12
0
def test_find_children(module, expected_result):
    graph = ImportGraph()
    foo, bar = "foo", "bar"
    a, b, c = "foo.a", "foo.b", "foo.c"
    d, e, f = "foo.a.one", "foo.b.one", "bar.g"
    for module_to_add in (foo, bar, a, b, c, d, e, f):
        graph.add_module(module_to_add)

    assert expected_result == graph.find_children(module)
示例#13
0
    def test_finds_long_path(self):
        graph = ImportGraph()
        long_path = ("one", "two", "three", "four", "five")
        self._add_chain(graph, *long_path)

        result = tuple(
            graph.find_all_simple_chains(importer="one", imported="five"))

        assert (long_path, ) == result
示例#14
0
    def test_finds_no_paths_if_imported_but_not_importer(self):
        graph = ImportGraph()
        self._add_chain(graph, "foo", "bar")
        graph.add_module("baz")

        result = list(
            graph.find_all_simple_chains(importer="baz", imported="bar"))

        assert [] == result
示例#15
0
    def test_finds_no_paths_if_none_exist(self):
        graph = ImportGraph()
        graph.add_module("foo")
        graph.add_module("bar")

        result = list(
            graph.find_all_simple_chains(importer="foo", imported="bar"))

        assert [] == result
示例#16
0
    def test_does_nothing_if_module_is_already_squashed(self):
        graph = ImportGraph()
        graph.add_module("foo", is_squashed=True)
        graph.add_import(importer="foo", imported="bar")

        graph.squash_module("foo")

        assert graph.direct_import_exists(importer="foo", imported="bar")
示例#17
0
    def test_truncated(self):
        modules = ["one", "two", "three", "four", "five", "six"]
        graph = ImportGraph()
        for module in modules:
            graph.add_module(module)

        re_part = "(" + "|".join(modules) + ")"
        assert re.match(
            f"<ImportGraph: '{re_part}', '{re_part}', '{re_part}', "
            f"'{re_part}', '{re_part}', ...>",
            repr(graph),
        )
示例#18
0
    def test_no_results_in_reverse_direction(self):
        graph = ImportGraph()
        graph.add_module("green")
        graph.add_module("blue")
        graph.add_import(importer="green.foo", imported="blue.bar")

        result = graph.find_shortest_chains(importer="blue", imported="green")

        assert result == set()
示例#19
0
    def test_first_level_child_import(self):
        graph = ImportGraph()
        graph.add_module("green")
        graph.add_module("blue")
        graph.add_import(importer="green.foo", imported="blue.bar")

        result = graph.find_shortest_chains(importer="green", imported="blue")

        assert result == {("green.foo", "blue.bar")}
示例#20
0
    def test_grandchildren_import(self):
        graph = ImportGraph()
        graph.add_module("green")
        graph.add_module("blue")
        graph.add_import(importer="green.foo.one", imported="blue.bar.two")

        result = graph.find_shortest_chains(importer="green", imported="blue")

        assert result == {("green.foo.one", "blue.bar.two")}
示例#21
0
def test_missing_containerless_layers_raise_value_error():
    graph = ImportGraph()
    for module in ("foo", "foo.blue", "bar", "bar.green"):
        graph.add_module(module)

    contract = LayersContract(
        name="Layer contract",
        session_options={"root_packages": ["foo", "bar"]},
        contract_options={"containers": [], "layers": ["foo", "bar", "baz"]},
    )

    with pytest.raises(ValueError, match=("Missing layer 'baz': module baz does not exist.")):
        contract.check(graph=graph)
示例#22
0
    def test_untruncated(self):
        modules = ["one", "two", "three", "four", "five"]
        graph = ImportGraph()
        for module in modules:
            graph.add_module(module)

        # Assert something in the form <ImportGraph: 'one', 'two', 'three', 'four', 'five'>
        # (but not necessarily in that order).
        re_part = "(" + "|".join(modules) + ")"
        assert re.match(
            f"<ImportGraph: '{re_part}', '{re_part}', '{re_part}', '{re_part}', '{re_part}'>",
            repr(graph),
        )
示例#23
0
def test_remove_module():
    graph = ImportGraph()
    a, b = {"mypackage.blue", "mypackage.green"}

    graph.add_module(a)
    graph.add_module(b)
    graph.add_import(importer=a, imported=b)

    graph.remove_module(b)
    assert {a} == graph.modules

    # Removing a non-existent module doesn't cause an error.
    graph.remove_module("mypackage.yellow")
示例#24
0
def test_missing_module():
    graph = ImportGraph()
    for module in ("mypackage", "mypackage.foo"):
        graph.add_module(module)

    contract = IndependenceContract(
        name="Independence contract",
        session_options={"root_packages": ["mypackage"]},
        contract_options={"modules": ["mypackage.foo", "mypackage.bar"]},
    )

    with pytest.raises(ValueError,
                       match=("Module 'mypackage.bar' does not exist.")):
        contract.check(graph=graph)
示例#25
0
def test_ignore_imports_tolerates_duplicates():
    graph = ImportGraph()
    graph.add_module("mypackage")
    graph.add_import(importer="mypackage.a",
                     imported="mypackage.b",
                     line_number=1,
                     line_contents="-")
    graph.add_import(importer="mypackage.a",
                     imported="mypackage.c",
                     line_number=2,
                     line_contents="-")
    contract = IndependenceContract(
        name="Independence contract",
        session_options={"root_packages": ["mypackage"]},
        contract_options={
            "modules": ("mypackage.a", "mypackage.b"),
            "ignore_imports": [
                "mypackage.a -> mypackage.b",
                "mypackage.a -> mypackage.c",
                "mypackage.a -> mypackage.b",
            ],
        },
    )

    contract_check = contract.check(graph=graph)

    assert contract_check.kept
示例#26
0
    def test_finds_multiple_paths(self):
        graph = ImportGraph()
        paths = (
            ("foo", "blue", "bar"),
            ("foo", "green", "bar"),
            ("foo", "red", "yellow", "bar"),
            ("foo", "brown", "purple", "grey", "pink", "bar"),
        )
        for path in paths:
            self._add_chain(graph, *path)

        result = set(
            graph.find_all_simple_chains(importer="foo", imported="bar"))

        assert set(paths) == result
示例#27
0
def test_find_modules_that_directly_import():
    graph = ImportGraph()
    a, b, c = "foo", "bar", "baz"
    d, e, f = "foo.one", "bar.one", "baz.one"

    graph.add_import(importer=a, imported=b)
    graph.add_import(importer=a, imported=c)
    graph.add_import(importer=a, imported=d)
    graph.add_import(importer=b, imported=e)
    graph.add_import(importer=f, imported=b)

    assert {a, f} == graph.find_modules_that_directly_import("bar")
示例#28
0
def test_find_modules_directly_imported_by():
    graph = ImportGraph()
    a, b, c = "foo", "bar", "baz"
    d, e, f = "foo.one", "bar.one", "baz.one"

    graph.add_import(importer=a, imported=b)
    graph.add_import(importer=a, imported=c)
    graph.add_import(importer=a, imported=d)
    graph.add_import(importer=b, imported=e)
    graph.add_import(importer=f, imported=a)

    assert {b, c, d} == graph.find_modules_directly_imported_by("foo")
示例#29
0
    def test_includes_redundant_paths(self):
        # I'm not definitely sure we want this behaviour, but this is what networkx's
        # all_simple_paths gives us at the moment.
        graph = ImportGraph()
        paths = (
            ("foo", "blue", "bar"),
            ("foo", "green", "bar"),
            ("foo", "green", "blue", "bar"),
        )
        for path in paths:
            self._add_chain(graph, *path)

        result = set(
            graph.find_all_simple_chains(importer="foo", imported="bar"))

        assert set(paths) == result
示例#30
0
 def _build_default_graph(self):
     graph = ImportGraph()
     for module in (
             "mypackage",
             "mypackage.blue",
             "mypackage.blue.alpha",
             "mypackage.blue.beta",
             "mypackage.blue.beta.foo",
             "mypackage.green",
             "mypackage.yellow",
             "mypackage.yellow.gamma",
             "mypackage.yellow.delta",
             "mypackage.other",
     ):
         graph.add_module(module)
     return graph