Skip to content

Commit 49a4322

Browse files
committed
Change find_matching_direct_imports to expect an import expression
1 parent a7bb54a commit 49a4322

5 files changed

Lines changed: 39 additions & 37 deletions

File tree

docs/usage.rst

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,9 @@ Methods for analysing direct imports
194194
So if a module is imported twice from the same module, it will only be counted once.
195195
:rtype: Integer.
196196

197-
.. py:function:: ImportGraph.find_matching_direct_imports(importer_expression, imported_expression)
197+
.. py:function:: ImportGraph.find_matching_direct_imports(import_expression)
198198
199-
Find all direct imports matching the passed expressions (see :ref:`module_expressions`).
199+
Find all direct imports matching the passed import expression.
200200

201201
The imports are returned are in the following form::
202202

@@ -208,12 +208,13 @@ Methods for analysing direct imports
208208
# (additional imports here)
209209
]
210210

211-
:param str importer_expression: A module expression used for matching importing modules.
212-
:param str imported_expression: A module expression used for matching imported modules.
211+
:param str import_expression: An expression in the form "importer_expression -> imported_expression", where each
212+
expression is a module expression (see :ref:`module_expressions`).
213+
Example: ``"mypackage.*.blue -> mypackage.*.green"``.
213214
:return: An ordered list of direct imports matching the expressions (ordered alphabetically).
214215
:rtype: List of dictionaries with the structure shown above. If you want to use type annotations, you may use the
215216
``grimp.Import`` TypedDict for each dictionary.
216-
:raises: ``grimp.exceptions.InvalidModuleExpression`` if either of the module expressions is invalid.
217+
:raises: ``grimp.exceptions.InvalidImportExpression`` if the expression is not well-formed.
217218

218219
Methods for analysing import chains
219220
-----------------------------------

src/grimp/adaptors/graph.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from grimp.domain.analysis import PackageDependency, Route
55
from grimp.domain.valueobjects import Layer
66
from grimp import _rustgrimp as rust # type: ignore[attr-defined]
7-
from grimp.exceptions import ModuleNotPresent, NoSuchContainer, InvalidModuleExpression
7+
from grimp.exceptions import ModuleNotPresent, NoSuchContainer, InvalidModuleExpression, InvalidImportExpression
88
from grimp.application.ports import graph
99

1010

@@ -108,15 +108,18 @@ def get_import_details(self, *, importer: str, imported: str) -> List[DetailedIm
108108
imported=imported,
109109
)
110110

111-
def find_matching_direct_imports(
112-
self, *, importer_expression: str, imported_expression: str
113-
) -> List[Import]:
111+
def find_matching_direct_imports(self, import_expression: str) -> List[Import]:
112+
try:
113+
importer_expression, imported_expression = import_expression.split(" -> ")
114+
except ValueError:
115+
raise InvalidImportExpression(f"{import_expression} is not a valid import expression.")
116+
114117
try:
115118
return self._rustgraph.find_matching_direct_imports(
116119
importer_expression=importer_expression, imported_expression=imported_expression
117120
)
118121
except rust.InvalidModuleExpression as e:
119-
raise InvalidModuleExpression(str(e)) from e
122+
raise InvalidImportExpression(f"{import_expression} is not a valid import expression.") from e
120123

121124
def find_downstream_modules(self, module: str, as_package: bool = False) -> Set[str]:
122125
return self._rustgraph.find_downstream_modules(module, as_package)

src/grimp/application/ports/graph.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,7 @@ def get_import_details(self, *, importer: str, imported: str) -> List[DetailedIm
215215
raise NotImplementedError
216216

217217
@abc.abstractmethod
218-
def find_matching_direct_imports(
219-
self, *, importer_expression: str, imported_expression: str
220-
) -> List[Import]:
218+
def find_matching_direct_imports(self, *, import_expression: str) -> List[Import]:
221219
"""
222220
Find all direct imports matching the passed expressions.
223221
@@ -232,14 +230,15 @@ def find_matching_direct_imports(
232230
]
233231
234232
Args:
235-
importer_expression: A module expression used for matching importing modules.
236-
imported_expression: A module expression used for matching imported modules.
233+
import_expression: An expression used for matching importing modules, in the form
234+
"importer_expression -> imported_expression", where both expressions are
235+
module expressions.
237236
Returns:
238237
A list of direct imports matching the expressions, ordered alphabetically by importer,
239238
then imported.
240239
(We return a list rather than a set purely because dictionaries aren't hashable.)
241240
Raises:
242-
InvalidModuleExpression if either of the passed expressions are invalid.
241+
InvalidImportExpression if either of the passed expressions are invalid.
243242
244243
See `ImportGraph.find_matching_modules` for a description of module expressions.
245244
"""

src/grimp/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,7 @@ def __eq__(self, other):
6565

6666
class InvalidModuleExpression(GrimpException):
6767
pass
68+
69+
70+
class InvalidImportExpression(GrimpException):
71+
pass

tests/unit/adaptors/graph/test_direct_imports.py

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import pytest # type: ignore
22

33
from grimp.adaptors.graph import ImportGraph
4-
from grimp.exceptions import InvalidModuleExpression
4+
import re
5+
from grimp.exceptions import InvalidImportExpression
56

67

78
def test_find_modules_directly_imported_by():
@@ -318,9 +319,7 @@ def test_finds_matching_direct_imports(self, import_line_number, import_line_con
318319
line_contents=import_line_contents,
319320
)
320321

321-
assert graph.find_matching_direct_imports(
322-
importer_expression="pkg.animals.*", imported_expression="pkg.food.*"
323-
) == [
322+
assert graph.find_matching_direct_imports("pkg.animals.* -> pkg.food.*") == [
324323
{"importer": "pkg.animals.cat", "imported": "pkg.food.fish"},
325324
{"importer": "pkg.animals.dog", "imported": "pkg.food.chicken"},
326325
]
@@ -340,26 +339,22 @@ def test_deduplicates_imports(self):
340339
line_contents="...2",
341340
)
342341

343-
assert graph.find_matching_direct_imports(
344-
importer_expression="pkg.animals.*", imported_expression="pkg.colors.*"
345-
) == [
342+
assert graph.find_matching_direct_imports("pkg.animals.* -> pkg.colors.*") == [
346343
{"importer": "pkg.animals.dog", "imported": "pkg.colors.golden"},
347344
]
348345

349-
def test_raises_error_if_importer_expression_is_invalid(self):
350-
graph = ImportGraph()
351-
with pytest.raises(
352-
InvalidModuleExpression, match="foo.. is not a valid module expression."
353-
):
354-
graph.find_matching_direct_imports(
355-
importer_expression="foo..", imported_expression="bar"
356-
)
357-
358-
def test_raises_error_if_imported_expression_is_invalid(self):
346+
@pytest.mark.parametrize(
347+
"expression",
348+
[
349+
"foo.. -> bar",
350+
"foo -> bar..",
351+
"foo > bar",
352+
],
353+
)
354+
def test_raises_error_if_expression_is_invalid(self, expression):
359355
graph = ImportGraph()
360356
with pytest.raises(
361-
InvalidModuleExpression, match="bar.. is not a valid module expression."
357+
InvalidImportExpression,
358+
match=re.escape(f"{expression} is not a valid import expression."),
362359
):
363-
graph.find_matching_direct_imports(
364-
importer_expression="foo", imported_expression="bar.."
365-
)
360+
graph.find_matching_direct_imports(expression)

0 commit comments

Comments
 (0)