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)
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)
def test_invalid_container_multiple_packages(): graph = ImportGraph() contract = LayersContract( name="Layer contract", session_options={"root_packages": ["packageone", "packagetwo"]}, contract_options={"containers": ["notinpackages"], "layers": ["high", "medium", "low"]}, ) with pytest.raises( ValueError, match=( r"Invalid container 'notinpackages': a container must either be a root package, " r"or a subpackage of one of them. \(The root packages are: packageone, packagetwo.\)" ), ): contract.check(graph=graph)
def _build_contract(self): return LayersContract( name="Layer contract", session_options={"root_packages": ["mypackage"]}, contract_options={ "containers": ["mypackage.one", "mypackage.two", "mypackage.three"], "layers": ["high", "medium", "low"], }, )
def _build_contract(self, ignore_imports): return LayersContract( name="Layer contract", session_options={"root_packages": ["mypackage"]}, contract_options={ "containers": ["mypackage"], "layers": ["high", "medium", "low"], "ignore_imports": ignore_imports, }, )
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)
def _build_contract_without_containers(self, layers, root_packages=["mypackage"]): return LayersContract( name="Layer contract", session_options={"root_packages": root_packages}, contract_options={"layers": layers}, )
def test_render_broken_contract(): settings.configure(PRINTER=FakePrinter()) contract = LayersContract( name="Layers contract", session_options={"root_packages": ["mypackage"]}, contract_options={"containers": ["mypackage"], "layers": ["high", "medium", "low"]}, ) check = ContractCheck( kept=False, metadata={ "invalid_chains": [ { "higher_layer": "mypackage.high", "lower_layer": "mypackage.low", "chains": [ [ { "importer": "mypackage.low.blue", "imported": "mypackage.utils.red", "line_numbers": (8, 16), }, { "importer": "mypackage.utils.red", "imported": "mypackage.utils.yellow", "line_numbers": (1,), }, { "importer": "mypackage.utils.yellow", "imported": "mypackage.high.green", "line_numbers": (3,), }, ], [ { "importer": "mypackage.low.purple", "imported": "mypackage.high.brown", "line_numbers": (9,), } ], ], }, { "higher_layer": "mypackage.medium", "lower_layer": "mypackage.low", "chains": [ [ { "importer": "mypackage.low.blue", "imported": "mypackage.medium.yellow", "line_numbers": (6,), } ] ], }, { "higher_layer": "mypackage.high", "lower_layer": "mypackage.medium", "chains": [ [ { "importer": "mypackage.medium", "imported": "mypackage.high.cyan.alpha", "line_numbers": (2,), } ] ], }, ] }, ) contract.render_broken_contract(check) settings.PRINTER.pop_and_assert( """ mypackage.low is not allowed to import mypackage.high: - mypackage.low.blue -> mypackage.utils.red (l.8, l.16) mypackage.utils.red -> mypackage.utils.yellow (l.1) mypackage.utils.yellow -> mypackage.high.green (l.3) - mypackage.low.purple -> mypackage.high.brown (l.9) mypackage.low is not allowed to import mypackage.medium: - mypackage.low.blue -> mypackage.medium.yellow (l.6) mypackage.medium is not allowed to import mypackage.high: - mypackage.medium -> mypackage.high.cyan.alpha (l.2) """ )
def test_layer_contract_populates_metadata(): 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) graph.add_import( importer="mypackage.low.white.gamma", imported="mypackage.utils.foo", line_number=3, line_contents="-", ), graph.add_import( importer="mypackage.utils.foo", imported="mypackage.utils.bar", line_number=1, line_contents="-", ), graph.add_import( importer="mypackage.utils.foo", imported="mypackage.utils.bar", line_number=101, line_contents="-", ), graph.add_import( importer="mypackage.utils.bar", imported="mypackage.high.yellow.alpha", line_number=13, line_contents="-", ), graph.add_import( importer="mypackage.medium.orange.beta", imported="mypackage.high.blue", line_number=2, line_contents="-", ), graph.add_import( importer="mypackage.low.black", imported="mypackage.utils.baz", line_number=2, line_contents="-", ), graph.add_import( importer="mypackage.utils.baz", imported="mypackage.medium.red", line_number=3, line_contents="-", ), contract = LayersContract( name="Layer contract", session_options={"root_packages": ["mypackage"]}, contract_options={"containers": ["mypackage"], "layers": ["high", "medium", "low"]}, ) contract_check = contract.check(graph=graph) assert contract_check.kept is False assert contract_check.metadata == { "invalid_chains": [ { "higher_layer": "mypackage.high", "lower_layer": "mypackage.medium", "chains": [ [ { "importer": "mypackage.medium.orange.beta", "imported": "mypackage.high.blue", "line_numbers": (2,), } ] ], }, { "higher_layer": "mypackage.high", "lower_layer": "mypackage.low", "chains": [ [ { "importer": "mypackage.low.white.gamma", "imported": "mypackage.utils.foo", "line_numbers": (3,), }, { "importer": "mypackage.utils.foo", "imported": "mypackage.utils.bar", "line_numbers": (1, 101), }, { "importer": "mypackage.utils.bar", "imported": "mypackage.high.yellow.alpha", "line_numbers": (13,), }, ] ], }, { "higher_layer": "mypackage.medium", "lower_layer": "mypackage.low", "chains": [ [ { "importer": "mypackage.low.black", "imported": "mypackage.utils.baz", "line_numbers": (2,), }, { "importer": "mypackage.utils.baz", "imported": "mypackage.medium.red", "line_numbers": (3,), }, ] ], }, ] }