astral-sh / astral-sh/ruff

False positive `C901` thrown for outer function in closure

Open
#4,384 2 comments 2 reactions 0 assignees View on GitHub
needs-decision rule
Dominant language
Rust
Stars
49.6k
Forks
2.4k
Avg merge
2d 1h
Merged PRs (30d)
458

Description

Please see this snippet:

```python
from functools import wraps

def wrapper(f):
@wraps(f)
def wrapped_f(*args, **kwargs):
if 1 == 1:
pass
if 1 == 1:
pass
if 1 == 1:
pass
return f(*args, **kwargs)

return wrapped_f
```

And the below `pyproject.toml`

```toml
[tool.ruff.mccabe]
max-complexity = 3

[tool.flake8]
max-complexity = 3
```

With `ruff==0.0.265` will print:

```bash
> ruff --select=C901 a.py
a.py:4:5: C901 `wrapper` is too complex (5 > 3)
a.py:6:9: C901 `wrapped_f` is too complex (4 > 3)
Found 2 errors.
> flake8 a.py
a.py:4:1: C901 'wrapper' is too complex (5)
```

The 2nd error about `wrapped_f` if correct, as its cyclomatic complexity is above 3. However, I think the 1st error about the `wrapper` (outer) function is a false positive, as it has a cyclomatic complexity ≤ 3.

In other words, I think `ruff` has a false positive `C901` for closures, only the inner should throw.

For what it's worth, `flake8==6.0.0` does not have this false positive, but I think they mark the extra complexity in the wrong place (at `wrapper`, not `wrapped_f`).

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the C901 result from the provided Python closure snippet with Ruff 0.0.265, then compare it with flake8's result. Trace the complexity calculation for the outer and inner functions; done means only `wrapped_f` reports C901 while `wrapper` does not when the configured limit is 3.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.