예제 #1
0
    def _build_graph(self):
        graph = ImportGraph()
        for module in (
            "mypackage",
            "mypackage.high",
            "mypackage.high.green",
            "mypackage.high.blue",
            "mypackage.high.yellow",
            "mypackage.high.yellow.alpha",
            "mypackage.medium",
            "mypackage.medium.orange",
            "mypackage.medium.orange.beta",
            "mypackage.medium.red",
            "mypackage.low",
            "mypackage.low.black",
            "mypackage.low.white",
            "mypackage.low.white.gamma",
        ):
            graph.add_module(module)

        # Add some 'legal' imports.
        graph.add_import(importer="mypackage.high.green", imported="mypackage.medium.orange")
        graph.add_import(importer="mypackage.high.green", imported="mypackage.low.white.gamma")
        graph.add_import(importer="mypackage.medium.orange", imported="mypackage.low.white")
        graph.add_import(importer="mypackage.high.blue", imported="mypackage.utils")
        graph.add_import(importer="mypackage.utils", imported="mypackage.medium.red")

        return graph
예제 #2
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
예제 #3
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")}
예제 #4
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()
예제 #5
0
    def _build_legal_graph(self, container=None):
        graph = ImportGraph()
        if container:
            graph.add_module(container)
            namespace = f"{container}."
        else:
            namespace = ""

        for module in (
            f"{namespace}high",
            f"{namespace}high.green",
            f"{namespace}high.blue",
            f"{namespace}high.yellow",
            f"{namespace}high.yellow.alpha",
            f"{namespace}medium",
            f"{namespace}medium.orange",
            f"{namespace}medium.orange.beta",
            f"{namespace}medium.red",
            f"{namespace}low",
            f"{namespace}low.black",
            f"{namespace}low.white",
            f"{namespace}low.white.gamma",
        ):
            graph.add_module(module)

        # Add some 'legal' imports.
        graph.add_import(importer=f"{namespace}high.green", imported=f"{namespace}medium.orange")
        graph.add_import(importer=f"{namespace}high.green", imported=f"{namespace}low.white.gamma")
        graph.add_import(importer=f"{namespace}medium.orange", imported=f"{namespace}low.white")
        graph.add_import(importer=f"{namespace}high.blue", imported=f"{namespace}utils")
        graph.add_import(importer=f"{namespace}utils", imported=f"{namespace}medium.red")

        return graph
예제 #6
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)
예제 #7
0
    def test_import_between_top_level_and_child(self):
        graph = ImportGraph()
        graph.add_module("blue")
        graph.add_import(importer="green", imported="blue.foo")

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

        assert result == {("green", "blue.foo")}
예제 #8
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)
예제 #9
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")
예제 #10
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")}
예제 #11
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()
예제 #12
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")}
예제 #13
0
    def test_short_indirect_import(self):
        graph = ImportGraph()
        graph.add_module("green")
        graph.add_module("blue")
        graph.add_import(importer="green.indirect", imported="purple")
        graph.add_import(importer="purple", imported="blue.foo")

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

        assert result == {("green.indirect", "purple", "blue.foo")}
예제 #14
0
def test_remove_import():
    graph = ImportGraph()
    a, b, c = "foo", "bar", "baz"
    graph.add_import(importer=a, imported=b)
    graph.add_import(importer=a, imported=c)

    graph.remove_import(importer=a, imported=b)

    assert {a, b, c} == graph.modules
    assert {c} == graph.find_modules_directly_imported_by(a)
예제 #15
0
    def test_doesnt_error_if_imports_within_module(self):
        graph = ImportGraph()
        for module in [
                "foo",
                "foo.green",
                "foo.blue",
        ]:
            graph.add_module(module)
        graph.add_import(importer="foo.blue", imported="foo.green")

        graph.squash_module("foo")
예제 #16
0
    def test_keeps_import_of_squashed_root(self):
        graph = ImportGraph()
        for module in [
                "foo",
                "foo.green",
                "bar.blue",
        ]:
            graph.add_module(module)
        graph.add_import(importer="bar.blue", imported="foo")

        graph.squash_module("foo")

        assert graph.direct_import_exists(importer="bar.blue", imported="foo")
예제 #17
0
    def test_contracts_import_to_descendant(self):
        graph = ImportGraph()
        for module in [
                "foo",
                "foo.green",
                "bar.blue",
        ]:
            graph.add_module(module)
        graph.add_import(importer="bar.blue", imported="foo.green")

        graph.squash_module("foo")

        assert graph.direct_import_exists(importer="bar.blue", imported="foo")
예제 #18
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")
예제 #19
0
def test_add_import(add_module):
    graph = ImportGraph()
    a, b = "foo", "bar"

    # Adding the module should make no difference to the result.
    if add_module:
        graph.add_module(a)

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

    assert {a, b} == graph.modules
    assert {b} == graph.find_modules_directly_imported_by(a)
    assert set() == graph.find_modules_directly_imported_by(b)
예제 #20
0
    def _build_default_graph(self):
        graph = ImportGraph()

        # Add 26 modules.
        for letter in string.ascii_lowercase:
            graph.add_module(f"mypackage.{letter}")

        # Add 10 imports in total.
        for imported in ("d", "e", "f"):
            for importer in ("a", "b", "c"):
                graph.add_import(
                    importer=f"mypackage.{importer}", imported=f"mypackage.{imported}"
                )  # 3 * 3 = 9 imports.
        graph.add_import(importer="mypackage.d", imported="mypackage.f")  # 1 extra import.
        return graph
예제 #21
0
 def _build_graph(self):
     graph = ImportGraph()
     for module in (
             "one",
             "one.alpha",
             "two",
             "three",
             "blue",
             "green",
             "green.beta",
             "yellow",
             "purple",
             "utils",
     ):
         graph.add_module(f"mypackage.{module}")
     for external_module in ("sqlalchemy", "requests"):
         graph.add_module(external_module, is_squashed=True)
     graph.add_import(
         importer="mypackage.one.alpha",
         imported="mypackage.green.beta",
         line_number=3,
         line_contents="foo",
     )
     graph.add_import(
         importer="mypackage.three",
         imported="mypackage.green",
         line_number=4,
         line_contents="foo",
     )
     graph.add_import(
         importer="mypackage.two",
         imported="mypackage.utils",
         line_number=9,
         line_contents="foo",
     )
     graph.add_import(
         importer="mypackage.utils",
         imported="mypackage.purple",
         line_number=1,
         line_contents="foo",
     )
     graph.add_import(importer="mypackage.three",
                      imported="sqlalchemy",
                      line_number=1,
                      line_contents="foo")
     return graph
예제 #22
0
    def test_graph_can_be_mutated_without_affecting_other_contracts(self):
        # The MutationCheckContract checks that there are a certain number of modules and imports
        # in the graph, then adds one more module and one more import. We can check two such
        # contracts and the second one will fail, if the graph gets mutated by other contracts.
        session_options = {
            "root_package": "mypackage",
            "contract_types": ["mutation_check: tests.helpers.contracts.MutationCheckContract"],
        }

        reader = FakeUserOptionReader(
            UserOptions(
                session_options=session_options,
                contracts_options=[
                    {
                        "type": "mutation_check",
                        "name": "Contract one",
                        "number_of_modules": "5",
                        "number_of_imports": "2",
                    },
                    {
                        "type": "mutation_check",
                        "name": "Contract two",
                        "number_of_modules": "5",
                        "number_of_imports": "2",
                    },
                ],
            )
        )
        settings.configure(
            USER_OPTION_READERS=[reader], GRAPH_BUILDER=FakeGraphBuilder(), PRINTER=FakePrinter()
        )

        graph = ImportGraph()

        # Create a graph with five modules and two imports.
        for module in ("one", "two", "three", "four", "five"):
            graph.add_module(module)
        graph.add_import(importer="one", imported="two")
        graph.add_import(importer="one", imported="three")

        settings.GRAPH_BUILDER.inject_graph(graph)

        result = lint_imports(is_debug_mode=True)

        assert result == SUCCESS
예제 #23
0
    def test_import_details_to_descendant_are_lost(self):
        graph = ImportGraph()
        for module in [
                "foo",
                "foo.green",
                "bar.blue",
        ]:
            graph.add_module(module)

        graph.add_import(
            importer="bar.blue",
            imported="foo.green",
            line_number=1,
            line_contents="from foo import green",
        )

        graph.squash_module("foo")

        assert [] == graph.get_import_details(importer="bar.blue",
                                              imported="foo")
예제 #24
0
    def test_long_indirect_import(self):
        graph = ImportGraph()
        graph.add_module("green")
        graph.add_module("blue")
        graph.add_import(importer="green.baz", imported="yellow.three")
        graph.add_import(importer="yellow.three", imported="yellow.two")
        graph.add_import(importer="yellow.two", imported="yellow.one")
        graph.add_import(importer="yellow.one", imported="blue.foo")

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

        assert result == {("green.baz", "yellow.three", "yellow.two",
                           "yellow.one", "blue.foo")}
예제 #25
0
    def test_import_details_from_squashed_root_are_preserved(self):
        graph = ImportGraph()
        for module in [
                "foo",
                "foo.green",
                "bar.blue",
        ]:
            graph.add_module(module)
        import_details = dict(
            importer="foo",
            imported="bar.blue",
            line_number=1,
            line_contents="from . import bar",
        )
        graph.add_import(**import_details)

        graph.squash_module("foo")

        assert [import_details
                ] == graph.get_import_details(importer="foo",
                                              imported="bar.blue")
예제 #26
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
예제 #27
0
    def test_happy_path(self):
        graph = ImportGraph()

        imports_info = [
            dict(
                importer="mypackage.foo",
                imported="mypackage.bar",
                line_number=1,
                line_contents="from . import bar",
            ),
            dict(
                importer="mypackage.foo",
                imported="mypackage.bar",
                line_number=10,
                line_contents="from .bar import a_function",
            ),
        ]
        for import_info in imports_info:
            graph.add_import(**import_info)

        assert imports_info == graph.get_import_details(
            importer="mypackage.foo", imported="mypackage.bar")
예제 #28
0
    def test_returns_only_relevant_imports(self):
        graph = ImportGraph()

        imports_info = [
            dict(
                importer="mypackage.foo",
                imported="mypackage.bar",
                line_number=1,
                line_contents="from . import bar",
            )
        ]
        graph.add_import(**imports_info[0])

        # Also add a different import in the same module.
        graph.add_import(
            importer="mypackage.foo",
            imported="mypackage.baz",
            line_number=2,
            line_contents="from . import baz",
        )

        assert imports_info == graph.get_import_details(
            importer="mypackage.foo", imported="mypackage.bar")
예제 #29
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")
예제 #30
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")