Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 129 additions & 30 deletions tests/functional/ext/mccabe/mccabe.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
# pylint: disable=invalid-name,unnecessary-pass,no-else-return,useless-else-on-loop
# pylint: disable=undefined-variable,consider-using-sys-exit,unused-variable,too-many-return-statements
# pylint: disable=redefined-outer-name,using-constant-test,unused-argument
# pylint: disable=redefined-outer-name,using-constant-test,unused-argument,unnecessary-lambda-assignment
# pylint: disable=broad-except, not-context-manager, no-method-argument, unspecified-encoding, broad-exception-raised

"""Checks use of "too-complex" check"""


def f1(): # [too-complex]
def just_a_pass(): # [too-complex]
"""McCabe rating: 1"""
pass


def f2(n): # [too-complex]
def just_a_yield(): # [too-complex]
"""McCabe rating: 1"""
yield from range(10)


def just_a_return(): # [too-complex]
"""McCabe rating: 1"""
return 42


def just_a_raise(): # [too-complex]
"""McCabe rating: 1"""
raise ValueError("An error occurred")


def one_edge_multiple_operations(n): # [too-complex]
"""McCabe rating: 1"""
k = n + 4
s = k + n
return s


def f3(n): # [too-complex]
def if_elif_else(n): # [too-complex]
"""McCabe rating: 3"""
if n > 3:
return "bigger than three"
Expand All @@ -28,44 +43,83 @@ def f3(n): # [too-complex]
return "smaller than or equal to three"


def f4(): # [too-complex]
def if_with_conditionals(a, b, c): # [too-complex]
"""McCabe rating: 2"""
if ( # pylint: disable=too-many-boolean-expressions
a
and b
or c
or (a and not b)
or (b and not c)
or (c and not a)
or (a and b and c)
):
return True
return False


def for_loop(): # [too-complex]
"""McCabe rating: 2"""
for i in range(10):
print(i)


def f5(mylist): # [too-complex]
def for_loop_with_else(mylist): # [too-complex]
"""McCabe rating: 2"""
for i in mylist:
print(i)
else:
print(None)


def f6(n): # [too-complex]
def recursive_if_else(n): # [too-complex]
"""McCabe rating: 2"""
if n > 4:
return f(n - 1)
return recursive_if_else(n - 1)
else:
return n


def f7(): # [too-complex]
def for_loop_with_break(): # [too-complex]
"""McCabe rating: 3"""
for i in range(10):
if i == 5:
break


def for_loop_with_continue(): # [too-complex]
"""McCabe rating: 3"""
for i in range(10):
if i % 2 == 0:
continue
print(i)


def for_loop_with_continue_and_break(): # [too-complex]
"""McCabe rating: 4"""
for i in range(10):
if i % 2 == 0:
continue
if i % 5 == 0:
break


def inner_functions(): # [too-complex]
"""McCabe rating: 3"""

def b():
def inner_function(): # Known false negative ?
"""McCabe rating: 2"""

def c():
def innermost_function(): # Known false negative ?
"""McCabe rating: 1"""
pass

c()
innermost_function()

b()
inner_function()


def f8(): # [too-complex]
def try_with_multiple_except_and_else(): # [too-complex]
"""McCabe rating: 4"""
try:
print(1)
Expand All @@ -77,7 +131,44 @@ def f8(): # [too-complex]
print(4)


def f9(): # [too-complex]
def with_(fp): # [too-complex]
"""McCabe rating: 1"""
with open(fp) as f:
content = f.read()
return content


def lambda_with_if(lst): # [too-complex]
"""McCabe rating should be 4, but is 1 (known false negative ?)

See counterpart 'comprehension_with_if' below."""
f = lambda x: [x for x in lst if x % 2 == 0] or range(10)
return f(lst)


def comprehension_with_if(lst): # [too-complex]
"""McCabe rating: should be 4 but is 1 (known false negative ?)
https://github.com/PyCQA/mccabe/issues/69
"""
return [x for x in lst if x % 2 == 0] or range(10)


def comprehension_with_if_equivalent(lst): # [too-complex]
"""McCabe rating: 4

See counterpart 'comprehension_with_if' above.
"""
xs = []
for x in lst:
if x % 2 == 0:
xs.append(x)
if xs:
return xs
else:
return range(10)


def nested_ifs_elifs_elses(): # [too-complex]
"""McCabe rating: 9"""
myint = 2
if myint > 5:
Expand All @@ -103,7 +194,7 @@ def f9(): # [too-complex]
myint = 4


def f10(): # [too-complex]
def big_elif_chain_with_nested_ifs(): # [too-complex]
"""McCabe rating: 11"""
myint = 2
if myint == 5:
Expand All @@ -130,16 +221,16 @@ def f10(): # [too-complex]
return myint


class MyClass1:
class ExampleComplexityClass:
"""Class of example to test mccabe"""

_name = "MyClass" # To force a tail.node=None
_name = "ExampleComplexityKlass" # To force a tail.node=None

def method1(): # [too-complex]
def just_a_pass(self): # [too-complex]
"""McCabe rating: 1"""
pass

def method2(self, param1): # [too-complex, too-many-branches]
def highly_complex(self, param1): # [too-complex, too-many-branches]
"""McCabe rating: 15"""
if not param1:
pass
Expand All @@ -148,9 +239,7 @@ def method2(self, param1): # [too-complex, too-many-branches]
pass
else:
pass

pass

if param1:
pass
if param1:
Expand All @@ -166,7 +255,6 @@ def method2(self, param1): # [too-complex, too-many-branches]
if param1:
for value in range(5):
pass

pass
for count in range(6):
with open("myfile") as fp:
Expand Down Expand Up @@ -195,7 +283,8 @@ def method2(self, param1): # [too-complex, too-many-branches]
return param1


for count in range(10): # [too-complex]
for count in range(10): # [too-complex]
# McCabe rating: 4
if count == 1:
exit(0)
elif count == 2:
Expand All @@ -204,7 +293,7 @@ def method2(self, param1): # [too-complex, too-many-branches]
exit(2)


def method3(self): # [too-complex]
def try_finally_with_nested_ifs(): # [too-complex]
"""McCabe rating: 3"""
try:
if True:
Expand All @@ -215,23 +304,23 @@ def method3(self): # [too-complex]
pass
return True

def match_case_complexity(avg): # [too-complex]

def match_case(avg): # [too-complex]
"""McCabe rating: 4
See https://github.com/astral-sh/ruff/issues/11421
"""
# pylint: disable=bare-name-capture-pattern
match avg:
case avg if avg < .3:
case avg if avg < 0.3:
avg_grade = "F"
case avg if avg < .7:
case avg if avg < 0.7:
avg_grade = "E+"
case _:
raise ValueError(f"Unexpected average: {avg}")
return avg_grade



def nested_match(data): # [too-complex]
def nested_match_case(data): # [too-complex]
"""McCabe rating: 8

Nested match statements."""
Expand All @@ -251,3 +340,13 @@ def nested_match(data): # [too-complex]
return "Product with no price"
case _:
return "Unknown data type"


def yield_in_for_loop(a=None, b=None, c=None): # [too-complex]
"""McCabe rating: 4"""
yield from a or ()
for elt in b:
if elt is not None:
yield elt
if c is not None:
yield c
46 changes: 29 additions & 17 deletions tests/functional/ext/mccabe/mccabe.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
too-complex:9:0:9:6:f1:'f1' is too complex. The McCabe rating is 1:HIGH
too-complex:14:0:14:6:f2:'f2' is too complex. The McCabe rating is 1:HIGH
too-complex:21:0:21:6:f3:'f3' is too complex. The McCabe rating is 3:HIGH
too-complex:31:0:31:6:f4:'f4' is too complex. The McCabe rating is 2:HIGH
too-complex:37:0:37:6:f5:'f5' is too complex. The McCabe rating is 2:HIGH
too-complex:45:0:45:6:f6:'f6' is too complex. The McCabe rating is 2:HIGH
too-complex:53:0:53:6:f7:'f7' is too complex. The McCabe rating is 3:HIGH
too-complex:68:0:68:6:f8:'f8' is too complex. The McCabe rating is 4:HIGH
too-complex:80:0:80:6:f9:'f9' is too complex. The McCabe rating is 9:HIGH
too-complex:106:0:106:7:f10:'f10' is too complex. The McCabe rating is 11:HIGH
too-complex:138:4:138:15:MyClass1.method1:'method1' is too complex. The McCabe rating is 1:HIGH
too-complex:142:4:142:15:MyClass1.method2:'method2' is too complex. The McCabe rating is 15:HIGH
too-many-branches:142:4:142:15:MyClass1.method2:Too many branches (19/12):UNDEFINED
too-complex:198:0:204:15::This 'for' is too complex. The McCabe rating is 4:HIGH
too-complex:207:0:207:11:method3:'method3' is too complex. The McCabe rating is 3:HIGH
too-complex:218:0:218:25:match_case_complexity:'match_case_complexity' is too complex. The McCabe rating is 4:HIGH
too-complex:234:0:234:16:nested_match:'nested_match' is too complex. The McCabe rating is 8:HIGH
too-complex:9:0:9:15:just_a_pass:'just_a_pass' is too complex. The McCabe rating is 1:HIGH
too-complex:14:0:14:16:just_a_yield:'just_a_yield' is too complex. The McCabe rating is 1:HIGH
too-complex:19:0:19:17:just_a_return:'just_a_return' is too complex. The McCabe rating is 1:HIGH
too-complex:24:0:24:16:just_a_raise:'just_a_raise' is too complex. The McCabe rating is 1:HIGH
too-complex:29:0:29:32:one_edge_multiple_operations:'one_edge_multiple_operations' is too complex. The McCabe rating is 1:HIGH
too-complex:36:0:36:16:if_elif_else:'if_elif_else' is too complex. The McCabe rating is 3:HIGH
too-complex:46:0:46:24:if_with_conditionals:'if_with_conditionals' is too complex. The McCabe rating is 2:HIGH
too-complex:61:0:61:12:for_loop:'for_loop' is too complex. The McCabe rating is 2:HIGH
too-complex:67:0:67:22:for_loop_with_else:'for_loop_with_else' is too complex. The McCabe rating is 2:HIGH
too-complex:75:0:75:21:recursive_if_else:'recursive_if_else' is too complex. The McCabe rating is 2:HIGH
too-complex:83:0:83:23:for_loop_with_break:'for_loop_with_break' is too complex. The McCabe rating is 3:HIGH
too-complex:90:0:90:26:for_loop_with_continue:'for_loop_with_continue' is too complex. The McCabe rating is 3:HIGH
too-complex:98:0:98:36:for_loop_with_continue_and_break:'for_loop_with_continue_and_break' is too complex. The McCabe rating is 4:HIGH
too-complex:107:0:107:19:inner_functions:'inner_functions' is too complex. The McCabe rating is 3:HIGH
too-complex:122:0:122:37:try_with_multiple_except_and_else:'try_with_multiple_except_and_else' is too complex. The McCabe rating is 4:HIGH
too-complex:134:0:134:9:with_:'with_' is too complex. The McCabe rating is 1:HIGH
too-complex:141:0:141:18:lambda_with_if:'lambda_with_if' is too complex. The McCabe rating is 1:HIGH
too-complex:149:0:149:25:comprehension_with_if:'comprehension_with_if' is too complex. The McCabe rating is 1:HIGH
too-complex:156:0:156:36:comprehension_with_if_equivalent:'comprehension_with_if_equivalent' is too complex. The McCabe rating is 4:HIGH
too-complex:171:0:171:26:nested_ifs_elifs_elses:'nested_ifs_elifs_elses' is too complex. The McCabe rating is 9:HIGH
too-complex:197:0:197:34:big_elif_chain_with_nested_ifs:'big_elif_chain_with_nested_ifs' is too complex. The McCabe rating is 11:HIGH
too-complex:229:4:229:19:ExampleComplexityClass.just_a_pass:'just_a_pass' is too complex. The McCabe rating is 1:HIGH
too-complex:233:4:233:22:ExampleComplexityClass.highly_complex:'highly_complex' is too complex. The McCabe rating is 15:HIGH
too-many-branches:233:4:233:22:ExampleComplexityClass.highly_complex:Too many branches (19/12):UNDEFINED
too-complex:286:0:293:15::This 'for' is too complex. The McCabe rating is 4:HIGH
too-complex:296:0:296:31:try_finally_with_nested_ifs:'try_finally_with_nested_ifs' is too complex. The McCabe rating is 3:HIGH
too-complex:308:0:308:14:match_case:'match_case' is too complex. The McCabe rating is 4:HIGH
too-complex:323:0:323:21:nested_match_case:'nested_match_case' is too complex. The McCabe rating is 8:HIGH
too-complex:345:0:345:21:yield_in_for_loop:'yield_in_for_loop' is too complex. The McCabe rating is 4:HIGH
14 changes: 14 additions & 0 deletions tests/functional/ext/mccabe/not_too_complex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""The other functional file has a max-complexity so low that it doesn't cover the
case when the code is not too complex."""


def not_too_complex():
"""McCabe rating: 1"""
return True


def too_complex(condition): # [too-complex]
"""McCabe rating: 2"""
if condition is True:
return True
return False
4 changes: 4 additions & 0 deletions tests/functional/ext/mccabe/not_too_complex.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[MAIN]
load-plugins=pylint.extensions.mccabe,

max-complexity=1
1 change: 1 addition & 0 deletions tests/functional/ext/mccabe/not_too_complex.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
too-complex:10:0:10:15:too_complex:'too_complex' is too complex. The McCabe rating is 2:HIGH
Loading