diff --git a/pyproject.toml b/pyproject.toml index 73e16214..a1775a02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,6 +81,10 @@ namespaces = false [tool.ruff] line-length = 99 -exclude = ['tests/assets'] # These are sample packages for tests to run under - we don't want ruff to mess with them. -[tool.ruff.lint] -select = ["E4", "E7", "E9", "F", "UP"] +exclude = [ + 'tests/assets', # These are sample packages for tests to run under - we don't want ruff to mess with them. + 'docs/', # Documentation configuration scripts +] +lint.select = ["A", "C4", "E4", "E7", "E9", "F", "FLY", "FURB", "INP", "PLE", "PLR", "PT", "RUF", "SIM", "UP"] +lint.ignore = ["C408", "PLR2004", "PLR0913", "PT006", "PT007", "SIM108", "SIM118", "SIM300"] +lint.per-file-ignores."tests/**/*.py" = [ "RUF012", "RUF059" ] diff --git a/src/grimp/__init__.py b/src/grimp/__init__.py index 642e4040..e75000e1 100644 --- a/src/grimp/__init__.py +++ b/src/grimp/__init__.py @@ -6,13 +6,13 @@ from .main import build_graph __all__ = [ - "Module", "DetailedImport", "DirectImport", "Import", "ImportGraph", + "Layer", + "Module", "PackageDependency", "Route", "build_graph", - "Layer", ] diff --git a/src/grimp/adaptors/modulefinder.py b/src/grimp/adaptors/modulefinder.py index c38dc057..2fae2956 100644 --- a/src/grimp/adaptors/modulefinder.py +++ b/src/grimp/adaptors/modulefinder.py @@ -147,9 +147,10 @@ def _module_name_from_filename( """ internal_filename_and_path = filename_and_path[len(package_directory) :] internal_filename_and_path_without_extension = internal_filename_and_path[1:-3] - components = [package_name] + internal_filename_and_path_without_extension.split( - self.file_system.sep - ) + components = [ + package_name, + *internal_filename_and_path_without_extension.split(self.file_system.sep), + ] if components[-1] == "__init__": components.pop() return ".".join(components) diff --git a/src/grimp/adaptors/packagefinder.py b/src/grimp/adaptors/packagefinder.py index 55c5d28f..09d459f5 100644 --- a/src/grimp/adaptors/packagefinder.py +++ b/src/grimp/adaptors/packagefinder.py @@ -21,9 +21,14 @@ def determine_package_directories( logger.debug(f"sys.path: {sys.path}") raise ValueError(f"Could not find package '{package_name}' in your Python path.") - if spec.has_location and spec.origin: - if not self._is_a_package(spec, file_system) or self._has_a_non_namespace_parent(spec): - raise exceptions.NotATopLevelModule + if ( + spec.has_location + and spec.origin + and ( + not self._is_a_package(spec, file_system) or self._has_a_non_namespace_parent(spec) + ) + ): + raise exceptions.NotATopLevelModule assert spec.submodule_search_locations # This should be the case if spec.has_location. return set(spec.submodule_search_locations) diff --git a/src/grimp/application/usecases.py b/src/grimp/application/usecases.py index 4765b7ed..baa30b42 100644 --- a/src/grimp/application/usecases.py +++ b/src/grimp/application/usecases.py @@ -53,7 +53,7 @@ def build_graph( found_packages = _find_packages( file_system=file_system, - package_names=[package_name] + list(additional_package_names), + package_names=[package_name, *additional_package_names], ) imports_by_module = _scan_packages( diff --git a/tests/benchmarking/test_benchmarking.py b/tests/benchmarking/test_benchmarking.py index aece8dad..e5ce4167 100644 --- a/tests/benchmarking/test_benchmarking.py +++ b/tests/benchmarking/test_benchmarking.py @@ -54,18 +54,12 @@ def large_graph(): heads=frozenset({"mypackage.domain.7960519247.6215972208"}), middle=(), tails=frozenset( - { - "mypackage.application.7537183614.6928774480.5676105139.3275676604" - # noqa:E501 - } + {"mypackage.application.7537183614.6928774480.5676105139.3275676604"} ), ), Route( heads=frozenset( - { - "mypackage.domain.6928774480.5676105139.1330171288.7588443317.4661445087" - # noqa:E501 - } + {"mypackage.domain.6928774480.5676105139.1330171288.7588443317.4661445087"} ), middle=(), tails=frozenset({"mypackage.application.7537183614.3430454356.1518604543"}), @@ -84,10 +78,7 @@ def large_graph(): ), Route( heads=frozenset( - { - "mypackage.domain.6928774480.1028759677.7960519247.2888779155.7486857426" - # noqa:E501 - } + {"mypackage.domain.6928774480.1028759677.7960519247.2888779155.7486857426"} ), middle=(), tails=frozenset({"mypackage.application.7537183614.3430454356.1518604543"}), @@ -139,18 +130,14 @@ def large_graph(): heads=frozenset( { "mypackage.application.7537183614.2538372545.1153384736.6297289996", - # noqa:E501 "mypackage.application.7537183614.2538372545.1153384736.6404547812.6297289996", - # noqa:E501 } ), middle=("mypackage.6398020133.9075581450.6529869526.6297289996",), tails=frozenset( { "mypackage.plugins.5634303718.6180716911.7582995238.1039461003.2943193489", - # noqa:E501 "mypackage.plugins.5634303718.6180716911.7582995238.1039461003.6322703811", - # noqa:E501 } ), ) diff --git a/tests/unit/application/graph/test_chains.py b/tests/unit/application/graph/test_chains.py index 3cf207ae..3fa3039e 100644 --- a/tests/unit/application/graph/test_chains.py +++ b/tests/unit/application/graph/test_chains.py @@ -1,3 +1,4 @@ +import re import pytest # type: ignore from grimp.application.graph import ImportGraph @@ -112,14 +113,14 @@ def test_find_shortest_chain_returns_none_if_not_exists(self): def test_raises_value_error_if_importer_not_present(self): graph = ImportGraph() - with pytest.raises(ValueError, match="Module foo is not present in the graph."): + with pytest.raises(ValueError, match=re.escape("Module foo is not present in the graph.")): graph.find_shortest_chain(importer="foo", imported="bar") def test_raises_value_error_if_imported_not_present(self): graph = ImportGraph() graph.add_module("foo") - with pytest.raises(ValueError, match="Module bar is not present in the graph."): + with pytest.raises(ValueError, match=re.escape("Module bar is not present in the graph.")): graph.find_shortest_chain(importer="foo", imported="bar") def test_find_shortest_chain_copes_with_cycle(self): @@ -164,7 +165,7 @@ def test_demonstrate_nondeterminism_of_equal_chains(self): one_chain = (source, a, b, c, destination) other_chain = (source, d, e, f, destination) - assert (result == one_chain) or (result == other_chain) + assert result in (one_chain, other_chain) @pytest.mark.parametrize( "as_packages, expected_result", @@ -201,7 +202,7 @@ def test_modules_with_shared_descendants_raises_value_error_when_as_packages_tru graph.add_module(importer) graph.add_module(imported) - with pytest.raises(ValueError, match="Modules have shared descendants."): + with pytest.raises(ValueError, match=re.escape("Modules have shared descendants.")): graph.find_shortest_chains(importer=importer, imported=imported, as_packages=True) @pytest.mark.parametrize( diff --git a/tests/unit/application/graph/test_hierarchy.py b/tests/unit/application/graph/test_hierarchy.py index 10b8922a..ce373dab 100644 --- a/tests/unit/application/graph/test_hierarchy.py +++ b/tests/unit/application/graph/test_hierarchy.py @@ -1,3 +1,4 @@ +import re import pytest # type: ignore from grimp.application.graph import ImportGraph @@ -33,7 +34,7 @@ def test_find_children_raises_exception_for_squashed_module(): graph.add_module(module, is_squashed=True) - with pytest.raises(ValueError, match="Cannot find children of a squashed module."): + with pytest.raises(ValueError, match=re.escape("Cannot find children of a squashed module.")): graph.find_children(module) @@ -75,7 +76,9 @@ def test_find_descendants_raises_exception_for_squashed_module(): graph.add_module(module, is_squashed=True) - with pytest.raises(ValueError, match="Cannot find descendants of a squashed module."): + with pytest.raises( + ValueError, match=re.escape("Cannot find descendants of a squashed module.") + ): graph.find_descendants(module) diff --git a/tests/unit/application/graph/test_layers.py b/tests/unit/application/graph/test_layers.py index cb48d9b9..766ec2a3 100644 --- a/tests/unit/application/graph/test_layers.py +++ b/tests/unit/application/graph/test_layers.py @@ -83,7 +83,7 @@ def test_indirect_illegal_within_one_package( self, specify_container: bool, start: str, end: str, route_middle: list[str] ): graph = self._build_legal_graph() - import_pairs = _pairwise([start] + route_middle + [end]) + import_pairs = _pairwise([start, *route_middle, end]) for importer, imported in import_pairs: graph.add_import(importer=importer, imported=imported) @@ -342,7 +342,7 @@ def test_demonstrate_nondeterminism_with_equal_length_forked_routes(self): ), } - assert (result == first_option) or (result == second_option) + assert result in (first_option, second_option) def _build_legal_graph(self): graph = ImportGraph() @@ -479,7 +479,7 @@ def test_indirect_illegal_within_one_package( self, specify_container: bool, start: str, end: str, route_middle: list[str] ): graph = self._build_legal_graph() - import_pairs = _pairwise([start] + route_middle + [end]) + import_pairs = _pairwise([start, *route_middle, end]) for importer, imported in import_pairs: graph.add_import(importer=importer, imported=imported) @@ -668,7 +668,7 @@ def test_indirect_illegal_across_two_packages( self, start: str, end: str, route_middle: list[str] ): graph = self._build_legal_graph() - import_pairs = _pairwise([start] + route_middle + [end]) + import_pairs = _pairwise([start, *route_middle, end]) for importer, imported in import_pairs: graph.add_import(importer=importer, imported=imported) @@ -1104,12 +1104,12 @@ def _build_layers(self, layers: Iterable[Layer]): modules = [] for layer in layers: assert len(layer.module_tails) == 1 - module = list(layer.module_tails)[0] + module = next(iter(layer.module_tails)) graph.add_module(module) modules.append(module) # Legal imports, from higher layer to immediate lower layer - for higher_module, lower_module in zip(modules[:-1], modules[1:]): + for higher_module, lower_module in itertools.pairwise(modules): graph.add_import(importer=higher_module, imported=lower_module) return graph diff --git a/tests/unit/application/graph/test_manipulation.py b/tests/unit/application/graph/test_manipulation.py index 1f00218b..8824647c 100644 --- a/tests/unit/application/graph/test_manipulation.py +++ b/tests/unit/application/graph/test_manipulation.py @@ -1,3 +1,4 @@ +import re import pytest # type: ignore from grimp.application.graph import ImportGraph @@ -119,7 +120,7 @@ def test_cannot_add_squashed_module_if_already_same_unsquashed_module(self): with pytest.raises( ValueError, - match=( + match=re.escape( "Cannot add a squashed module when it is already present in the graph as an " "unsquashed module, or vice versa." ), @@ -134,7 +135,7 @@ def test_cannot_add_unsquashed_module_if_already_same_squashed_module(self): with pytest.raises( ValueError, - match=( + match=re.escape( "Cannot add a squashed module when it is already present in the graph as an " "unsquashed module, or vice versa." ), @@ -148,7 +149,7 @@ def test_cannot_add_descendant_of_squashed_module(self, module_name): graph.add_module("mypackage.foo", is_squashed=True) with pytest.raises( - ValueError, match="Module is a descendant of squashed module mypackage.foo." + ValueError, match=re.escape("Module is a descendant of squashed module mypackage.foo.") ): graph.add_module(module_name) diff --git a/tests/unit/application/test_scanning.py b/tests/unit/application/test_scanning.py index bc8d1f6b..c0c1447a 100644 --- a/tests/unit/application/test_scanning.py +++ b/tests/unit/application/test_scanning.py @@ -730,13 +730,6 @@ def my_function(): ("import namespace.foo.green.alpha.one", "namespace.foo.green"), ("from namespace.foo.green.alpha import one", "namespace.foo.green"), ("from ..green.alpha import one", "namespace.foo.green"), - ("from .. import green", "namespace.foo.green"), - ("import namespace.foo.green.alpha", "namespace.foo.green"), - ("from namespace.foo.green import alpha", "namespace.foo.green"), - ("from ..green import alpha", "namespace.foo.green"), - ("import namespace.foo.green.alpha.one", "namespace.foo.green"), - ("from namespace.foo.green.alpha import one", "namespace.foo.green"), - ("from ..green.alpha import one", "namespace.foo.green"), ), ) def test_external_package_imports_for_namespace_packages(statement, expected_module_name): diff --git a/tests/unit/application/test_usecases.py b/tests/unit/application/test_usecases.py index 932fb4d9..e7f2ae26 100644 --- a/tests/unit/application/test_usecases.py +++ b/tests/unit/application/test_usecases.py @@ -1,3 +1,4 @@ +import re from unittest.mock import sentinel import pytest # type: ignore @@ -63,7 +64,9 @@ class FakePackageFinder(BaseFakePackageFinder): # Check that the external packages are squashed modules. if include_external_packages: for module in ("external", "decimal"): - with pytest.raises(ValueError, match="Cannot find children of a squashed module."): + with pytest.raises( + ValueError, match=re.escape("Cannot find children of a squashed module.") + ): graph.find_children(module) def test_boolean_additional_package_raises_type_error(self): @@ -75,7 +78,7 @@ def test_boolean_additional_package_raises_type_error(self): as the second argument, and it's possible it might have been called as a positional argument. """ - with pytest.raises(TypeError, match="Package names must be strings, got bool."): + with pytest.raises(TypeError, match=re.escape("Package names must be strings, got bool.")): usecases.build_graph("mypackage", True) @pytest.mark.parametrize(