Skip to content

Add module expressions#188

Merged
seddonym merged 5 commits intopython-grimp:add-module-expressionsfrom
Peter554:module-expressions
Feb 25, 2025
Merged

Add module expressions#188
seddonym merged 5 commits intopython-grimp:add-module-expressionsfrom
Peter554:module-expressions

Conversation

@Peter554
Copy link
Collaborator

@Peter554 Peter554 commented Feb 13, 2025

Context: seddonym/import-linter#252

This PR adds module expressions to grimp. By moving module expressions into grimp, in particular into the rust code, we will be able to speed up lots of the import linter code that works with module expressions (import linter now supports module expressions in quite a few places).

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 14, 2025

CodSpeed Performance Report

Merging #188 will not alter performance

Comparing Peter554:module-expressions (eb43939) with master (8c1bb5d)

Summary

✅ 17 untouched benchmarks
🆕 2 new benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
🆕 test_find_matching_direct_imports N/A 36.1 ms N/A
🆕 test_find_matching_modules N/A 9.2 ms N/A

@Peter554 Peter554 force-pushed the module-expressions branch 5 times, most recently from c8456dd to 4ac6d87 Compare February 22, 2025 06:17
@Peter554 Peter554 marked this pull request as ready for review February 22, 2025 06:25
Comment on lines 121 to 129
def test_finds_matching_modules(self):
graph = ImportGraph()
graph.add_module("foo")
graph.add_module("foo.bar")
graph.add_module("foo.bar.baz")

assert graph.find_matching_modules("foo") == {"foo"}
assert graph.find_matching_modules("foo.*") == {"foo.bar"}
assert graph.find_matching_modules("foo.**") == {"foo.bar", "foo.bar.baz"}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍷 This test basically duplicates the rust test. For me it's okay to keep both.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a good rule of thumb is that the Python tests should be comprehensive, and if we want to add some Rust tests to help too (even if they duplicate) then that's fine. Do you agree?

Copy link
Collaborator Author

@Peter554 Peter554 Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you agree?

I think I could be persuaded either way. In the sense of a testing pyramid, one might argue that the rust tests should be the most comprehensive, since this is the closest we have to a unit test. All the python tests integrate the rust code, so by definition are higher up the pyramid, so we'd expect less comprehensive tests there.

That said, this isn't a normal testing pyramid, and the preexisting code puts most of the tests in python so there is definitely precedent to follow your suggestion.

In summary I think it's good to have both, certainly with comprehensive python tests. I'll flesh out the python tests a bit more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking back to when we swapped in your Rust implementation, it was a really useful property of the test suite that there was thorough test coverage of the Python API - we just deleted all the Rust tests and still felt confident. If coverage had been split across the two languages then we wouldn't have been able to do that.

So I think focusing on the Python tests is worthwhile - we can treat the Rust tests more lightly as tests to help us as we go along, but more disposable.

Arguably the Python unit tests are still at the base of the testing pyramid - they're fast and give us lots of signal about granular behaviour.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes okay I think you're right 👍

@seddonym seddonym self-requested a review February 24, 2025 08:38
Copy link
Collaborator

@seddonym seddonym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just leaving some early feedback - I haven't yet gone over everything in detail.

graph.add_module("foo.bar")
graph.add_module("foo.bar.baz")

assert graph.find_matching_modules("foo") == {"foo"}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My immediate reaction to the Python tests is they don't seem as thorough as what we have in import linter (i.e. here and here). But I see there are also Rust tests. How close do you think we are to equivalent test coverage as in Import Linter?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reasonably confident that we have similar coverage - the rust test cases within module_expressions.rs cover all of that I think. There aren't many tests at the level of find_matching_modules and find_matching_direct_imports. Most of the testing is done as unit tests on the ModuleExpression i.e. test_parse and test_is_match.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the other discussion, would you mind making sure the behaviour is covered by the Python tests, too? Or I can do it once everything else is ready on the PR.

Comment on lines 121 to 129
def test_finds_matching_modules(self):
graph = ImportGraph()
graph.add_module("foo")
graph.add_module("foo.bar")
graph.add_module("foo.bar.baz")

assert graph.find_matching_modules("foo") == {"foo"}
assert graph.find_matching_modules("foo.*") == {"foo.bar"}
assert graph.find_matching_modules("foo.**") == {"foo.bar", "foo.bar.baz"}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a good rule of thumb is that the Python tests should be comprehensive, and if we want to add some Rust tests to help too (even if they duplicate) then that's fine. Do you agree?

Copy link
Collaborator

@seddonym seddonym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another round of comments.

The commits are on the large side for reviewing, by the way...

@Peter554 Peter554 force-pushed the module-expressions branch 7 times, most recently from 41ccd51 to 2e526a3 Compare February 24, 2025 21:02
@Peter554 Peter554 force-pushed the module-expressions branch 2 times, most recently from 33f42f4 to 41aa83e Compare February 24, 2025 21:09
@Peter554 Peter554 requested a review from seddonym February 24, 2025 21:10
@Peter554
Copy link
Collaborator Author

@seddonym I've spent some time working through your comments. I'm not sure if I quite got them all, there's quite a few - perhaps you can take a look and close off the ones you are happy with?

Remove the "bidirectional" from the function name,
since this is the only path finding function we have.

The "bidirectional" part is just an implementation detail.
Copy link
Collaborator

@seddonym seddonym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I've finished the full review. It's looking great in general, thanks for your efforts!

I don't think there's much more to do on this, mainly it's just a few tweaks to comments.

Before merging to master, there are two blockers:

  • Making sure the Python test coverage is comprehensive.
  • Figuring out whether to represent import expressions as two-tuples or arrow-strings (let's discuss).

I'd be happy to merge this into a branch in my repo if it would help - then we could both work on the remainder. Let me know what you prefer.

Comment on lines 121 to 129
def test_finds_matching_modules(self):
graph = ImportGraph()
graph.add_module("foo")
graph.add_module("foo.bar")
graph.add_module("foo.bar.baz")

assert graph.find_matching_modules("foo") == {"foo"}
assert graph.find_matching_modules("foo.*") == {"foo.bar"}
assert graph.find_matching_modules("foo.**") == {"foo.bar", "foo.bar.baz"}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking back to when we swapped in your Rust implementation, it was a really useful property of the test suite that there was thorough test coverage of the Python API - we just deleted all the Rust tests and still felt confident. If coverage had been split across the two languages then we wouldn't have been able to do that.

So I think focusing on the Python tests is worthwhile - we can treat the Rust tests more lightly as tests to help us as we go along, but more disposable.

Arguably the Python unit tests are still at the base of the testing pyramid - they're fast and give us lots of signal about granular behaviour.

graph.add_module("foo.bar")
graph.add_module("foo.bar.baz")

assert graph.find_matching_modules("foo") == {"foo"}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the other discussion, would you mind making sure the behaviour is covered by the Python tests, too? Or I can do it once everything else is ready on the PR.

@seddonym seddonym changed the base branch from master to add-module-expressions February 25, 2025 10:48
Copy link
Collaborator

@seddonym seddonym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merging to the add-module-expressions working branch in the origin repo.

@seddonym seddonym merged commit 90ad8cf into python-grimp:add-module-expressions Feb 25, 2025
18 checks passed
@seddonym seddonym mentioned this pull request Feb 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants