# mccabe: the small complexity checker behind flake8's C901

> mccabe computes cyclomatic complexity for Python functions, either as a standalone command or as the flake8 plugin that reports C901. It is one module file with a long history of small corrections, and its configuration is a single threshold.

**PyCQA/mccabe** — McCabe complexity checker for Python

- Repository: https://github.com/PyCQA/mccabe
- Website: pypi.python.org/pypi/mccabe
- Stars: 682 · Forks: 70
- Language: Python
- License: NOASSERTION
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/pycqa-mccabe

## A single file checker that grew into a flake8 plugin

mccabe exists to answer one narrow question about Python code: how many distinct paths run through a given function. The project describes itself as a McCabe complexity checker and a plugin for flake8, the Python code checker, and its homepage points at the PyPI listing rather than a separate site. The audience is engineers who already accept that machine checked thresholds catch problems review sometimes misses, and who want that threshold to be a number rather than an opinion. The origin is visible in the changes list: version 0.2 from February 2013 renamed the project to mccabe and provided the flake8.extension setuptools entry point, and the first release a few days earlier was called something else. What ships today is still a single module file, mccabe.py, at the repository root, next to setup.py, setup.cfg, tox.ini and test_mccabe.py. That small surface is both the appeal and the limit.

## The graph builder walks the AST to count paths

The names visible in the standalone output reveal the internal structure. There is a McCabeChecker class whose run method is the entry point, a PathGraphingAstVisitor that subclasses an ASTVisitor and overrides methods such as visitIf and visitTryExcept, a PathGraph class with a to_dot method, and a get_code_complexity function that produces the number. The checker visits the abstract syntax tree of a function, builds a graph whose nodes are code blocks and whose edges are possible transitions, then reports the number of paths through that graph. The to_dot method suggests the graph can also be serialised for graphviz output. Complexity here is therefore derived from the structure of the code, not from a line count or a keyword heuristic. setup.py registers the plugin under the name C90 with an entry point pointing at mccabe:McCabeChecker, which is why every finding surfaces with the C901 code in flake8 output.

## Running the checker on a file without flake8

You do not need flake8 to use mccabe. Because the package ships as a module, it can be invoked directly, and the project documents the call with a minimum threshold of 5 against its own source file. The output is a list of tuples, each giving a line number, a column, the qualified name of a function and its complexity score:

```bash
  $ python -m mccabe --min 5 mccabe.py
  ("185:1: 'PathGraphingAstVisitor.visitIf'", 5)
  ("71:1: 'PathGraph.to_dot'", 5)
  ("245:1: 'McCabeChecker.run'", 5)
  ("283:1: 'main'", 7)
  ("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5)
  ("257:1: 'get_code_complexity'", 5)
```

Every entry has a score of 5 or more, which is what the threshold asked for. The names in the tuples are the same visitor and checker methods described above, so the output doubles as a map of the module's own structure. Note that the standalone flag is called --min while the plugin reads its value from the flake8 configuration file under the name max-complexity, an inconsistency inherited from the 0.2 release, which renamed the argument min_complexity to threshold.

## Installing the checker and the flake8 plugin together

The installation section gives the three package manager commands for a normal install, an upgrade and a removal. The upgrade matters in practice, because a stale copy of mccabe silently keeps reporting the old numbering scheme:

```bash
  $ pip install mccabe
  $ pip install --upgrade mccabe
  $ pip uninstall mccabe
```

Once flake8 and mccabe are both present, the plugin registers itself and shows up in the version banner. The banner in the documentation dates from an old release, but the format is what matters, since the third entry is the mccabe plugin:

```bash
  $ flake8 --version
  2.0 (pep8: 1.4.2, pyflakes: 0.6.1, mccabe: 0.2)
```

If that third item is missing, the entry point has not been picked up and no complexity violation will ever be reported. The plugin requires flake8 2 or later, and setup.py declares python_requires of 3.6 or newer, with classifiers covering Python 3.6 through 3.10.

## The plugin stays silent until you pass --max-complexity

This is the detail that trips up new users. The plugin is disabled by default and only becomes active when the --max-complexity switch is given on the flake8 command line, at which point flake8 emits a warning for any function whose complexity is higher than the value supplied. The example passes 10 against a directory called coolproject and the finding lands on a specific class method:

```bash
    $ flake8 --max-complexity 10 coolproject
    ...
    coolproject/mod.py:1204:1: C901 'CoolFactory.prepare' is too complex (14)
```

The reported value is 14 against a limit of 10, so the warning names both the function and its score. Silencing a finding works the same way as for other flake8 codes, with # noqa, and the project is specific about placement: put # noqa: C901 on the function definition line, since that is where the error is reported, which may be the decorator line rather than the def line. Getting that placement wrong is the usual reason a suppression does not take effect.

## Inclusive thresholds and a corrected starting value

Two corrections in the 0.3 release of December 2014 shaped how scores should be read, and both are easy to get wrong when comparing against older articles about complexity tooling. The first is that the mccabe complexity starts at 1, not 2, so a straight-line function with no branches scores 1 rather than 2. The second is that the max-complexity value is inclusive: if the limit is 10 and the reported complexity is 10, the function passes. Later releases tightened the details around this machinery, with 0.5.3 reporting the actual column of the violation instead of the start of the line, 0.6.1 fixing the signature of PathGraphingAstVisitor.default to match ASTVisitor, and 0.6.0 fixing handling for missing statement types. The 0.5.1 entry set the default maximum complexity to -1 on the class itself. The documentation also states the heuristic plainly, that according to McCabe anything going beyond 10 is too complex, which is why 10 shows up in every example.

## Support statements and licensing details do not fully line up

Two things to check before standardising on this package. First, Python version support: the changes list for 0.7.0, dated 2022-01-23, drops support for every Python version lower than 3.6 and adds support for 3.8, 3.9 and 3.10, while setup.py still declares python_requires of 3.6 or newer. Version 3.11 and 3.12 are not mentioned anywhere in the visible documentation, so a team running a newer interpreter has to confirm compatibility itself. Second, licensing: the repository license field is classified as a custom licence GitHub cannot categorise, pointing at the LICENSE file, yet setup.py declares the Expat license and carries a classifier for the MIT License. Those are normally the same permissive family, but the authoritative text for your use is the LICENSE file in the repository rather than the packaging metadata. The repository has no GitHub releases, so version history lives in the README changes list rather than in tagged release notes, and the last push was on 2026-10-12.

## Conclusion

mccabe fits Python teams that already run flake8 and want one threshold to expose sprawling functions, and it is a reasonable candidate for a pre-commit hook or a CI gate. It is the wrong tool if you want complexity metrics per class or per module, since it reports function level graphs only. Before adding it to a pipeline, check the threshold against your own codebase, because the documentation offers the McCabe figure of 10 as a starting point and the tool reports violations only above the value you pass to --max-complexity.

## FAQ

### How do I install mccabe and start using it with flake8?

Run pip install mccabe, and once flake8 is installed the plugin registers itself and appears in the flake8 --version banner. The plugin stays disabled until you pass the --max-complexity switch, which is what makes it report violations.

### What does the C901 code mean in flake8 output?

C901 is the mccabe complexity warning produced when a function's cyclomatic complexity is higher than the value given to --max-complexity. The message names the function and its score, for example 'CoolFactory.prepare' is too complex (14).

### How do I suppress a complexity warning for a single function?

Place # noqa: C901 on the function definition line, which is where the error is reported. It may be the decorator line rather than the def line, so check the reported line before adding the comment.

### Can mccabe be used without flake8 installed?

Yes. The package can be run directly as a module, for example python -m mccabe --min 5 mccabe.py, which prints tuples of line, column, function name and complexity score.

## Sources

- [Issues](https://github.com/PyCQA/mccabe/issues)
- [PyCQA/mccabe on GitHub](https://github.com/PyCQA/mccabe)
- [README](https://github.com/PyCQA/mccabe/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pycqa-mccabe
