-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
C901, PLR0912 and PLR0915 treat match/case as one statement #11421
Comments
I think it is intentional as Pylint doesn't detect it either.
Personally, I wouldn't count it as I find the |
I feel like the same complexity and maintainability arguments apply to This issue should probably be converted to a discussion. |
It's fine, we can discuss here. I don't have any arguments against this, and it does make sense (I think?) to include the |
Thank you for the ping @charliermarsh :) I see no reason for match to behave differently than if. I think it's an oversight when we added the match statement for python 3.10 we did not think to test the consequences on the already implemented "too-complex" (assumed the "too-complex" code was generic enough). |
So, I did some light research and there might be a point for 'too-complex" behaving the way it does right now. It is based on Mc Cabe and:
https://web.archive.org/web/20210908120324/https://www.mccabe.com/pdf/mccabe-nist235r.pdf (page 15, notice also that McCabe himself is one of the authors) Also on page 26 we can see:
Imo, the match case in python adds complexity because it's not a simple "case labels", it's behaving more like an if, or even a regex. |
I agree with @Pierre-Sassoulas. For the Mccabe plugin, I believe one of the primary motivations for the rule is to ensure that each function is testable in isolation. If a function has too many branches, it becomes hard to write a unit test for it. I think this is just as much a concern for |
Thank you @Pierre-Sassoulas for chiming in! I agree with the conclusion. I think we should update all three rules to consider |
I can take a stab at this if that's ok. |
Go for it -- thanks!
|
Thanks everyone! |
I wish the consideration for match-case statement for PLR rules was configurable to be turned off with lint.pylint setting. Long match-case statements are very common while walking abstract syntax trees and are arguably way less complex than any other solution. See usage, e.g. at https://github.com/CQCL/pytket-phir/blob/main/pytket/phir/phirgen.py#L102-L148 which now raises both PLR 912 and 915. @jaap3, @blueraft, @dhruvmanila what do you think? If there is agreement, I can file a separate issue. |
I'd agree that match/case statements are more readable for this purpose, and arguably more idiomatic, but I don't think there's any fewer branches than if you walked the tree using if/elif/else, and the number of branches is what these rules are concerned with. I don't see a strong reason to make match/case statements configurable here specifically. I think I'd find it just as difficult to write comprehensive unit tests for a function with many |
The only thing to add is there is no simpler way to process an enumeration than pattern matching (such as those that show up in AST walks as mentioned) and for those cases, I'd argue complexity considerations covered by these rules do not apply. With current change, any parsers/compilers processing a grammar could be full of ruff ignores for each such match construct (or in each file, but then missing several other cases) or we can let users choose whether they want these code complexity heuristics to apply to match-case. |
To me that just seems to be arbitrarily favouring some language constructs at the expense of others in the name of readability and style, which isn't what this rule is meant to be ultimately concerned about. If the argument is that there are many cases where writing a more complex function is in fact more maintainable and redable than splitting the function into several smaller functions, then I'd agree that that's a valid critique. But to me, that seems like a flaw of the rule in general rather than a flaw of the rule as specifically applied to |
The exhaustive match/case pattern for all possible values in an enumeration is actually promoted by the rust compiler, it is a good practice to replicate in other languages such as python but that triggers the complexity warning. It does make a difference to have if/elif/... statements vs match/case/... because in an if/elif/... scenario you can have any kind of conditional while on the match/case scenario is only values for the same variable. Anyway, a config setting to revert the rule to the previous behavior would be the best of both worlds. |
Using ruff 0.4.4 the following code triggers
C901
,PLR0912
andPLR0915
:The equivalent code that uses
match
/case
however does not:Is this intentional? Should each
case
count as a conditional?The text was updated successfully, but these errors were encountered: