-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PLR0401 Cyclic import implementation #2914
Comments
👍 Related to the question that was just asked here: #970 (comment). Everything you've said above is correct. Right now, we use a single-file model, so every file is analyzed independently. We do some work upfront to determine the package hierarchy (e.g., to determine the package root for every file), which is the only part of the analysis pipeline that depends on "multiple files", so-to-speak. (And yeah -- I think you're right that we want the linter pass to return some kind of "dependency graph" for each module, which should include the members that the module "exports" (implicitly, or explicitly via We could start with a subset of that behavior, though, e.g., just the modules that a given module depends on, as you've described above. I'd be open to reviewing a PR or proposal to that effect! |
Thanks for the feedback, sounds good! I've not been as free as I'd like but I'll come up with something on the weekend. |
Sorry I took so long to getting round to having a stab at this. Do you think it would make sense for me just to return the |
How does the cyclic import rule work? Does it just detect cyclic imports at the top-level? I.e., are delayed or deferred imports (in function bodies) ignored? I think either approach (returning AST nodes, or making a custom type) could work. We'll probably convert to some kind of internal representation when we do the cycle detection either way. |
I can confirm that pylint doesn't detect cyclic imports in delayed/deferred imports and only in top-level imports. It also doesn't attribute the cyclic import to the correct module neither.
There are also the modules
Which I feel like is something we'd be able to avoid. |
Given a go at at least propagating the information on all the imports every module has in #3243 |
Given Ruff's sheer speed, it has a good shot at implementing cyclic import detection even better than pylint and pyright ! |
Oh interesting! Yeah we do track that info, we should be able to differentiate between typing-only imports when detecting cycles :) |
Any update on this? It's one of the main things I'd love to have given that my tests sometimes fail on circular imports and having the fast linter spot these before running the tests would be optimal. Thanks! |
There's an attempt here #3880 |
Lovely! Good luck with that then. I wish I could help but unfortunately my Rust knowledge is non-existent :c |
@charliermarsh CPython 3.12 now has low-overhead dynamic tracing, which could be used to trace imports and e.g., find cycles. https://docs.python.org/3.12/whatsnew/3.12.html#pep-669-low-impact-monitoring-for-cpython |
Hello fellow ruffians(?)
I was thinking of having a stab at implement pylint's R0401 cyclic import rule, but before I set off I thought it might be wise to ask your opinions and to clarify my current understanding of how ruff works.
Would I be correct to say that, all the python files to be linted are collected, then each one is linted individually in parallel?
It seems the expected output from
lint_path
is aResult<Diagnostics>
. If I wanted to track imports, I noticed there was animports.rs
module, but to the best of my knowledge this is called vialinter::check_path
which is also only run per file?My initial thoughts were perhaps to change the APIs somewhat to return a
Vec
of the imports, create a graph and then detect cycles.The text was updated successfully, but these errors were encountered: