or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/pypi-mccabe

McCabe cyclomatic complexity checker that functions as a plugin for flake8

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/mccabe@0.7.x

To install, run

npx @tessl/cli install tessl/pypi-mccabe@0.7.0

0

# McCabe

1

2

A McCabe cyclomatic complexity checker that functions as a plugin for flake8, the Python code quality tool. This package analyzes Python code to measure cyclomatic complexity, helping developers identify overly complex functions that may be difficult to maintain and test.

3

4

## Package Information

5

6

- **Package Name**: mccabe

7

- **Language**: Python

8

- **Installation**: `pip install mccabe`

9

10

## Core Imports

11

12

```python

13

import mccabe

14

```

15

16

For specific functionality:

17

18

```python

19

from mccabe import get_code_complexity, get_module_complexity, McCabeChecker

20

```

21

22

## Basic Usage

23

24

### Analyzing Code Complexity

25

26

```python

27

from mccabe import get_code_complexity

28

29

# Analyze a code string

30

code = '''

31

def complex_function(x):

32

if x > 10:

33

if x > 20:

34

return "very high"

35

else:

36

return "high"

37

elif x > 5:

38

return "medium"

39

else:

40

return "low"

41

'''

42

43

# Check complexity with threshold of 5

44

violations = get_code_complexity(code, threshold=5)

45

print(f"Found {violations} complexity violations")

46

```

47

48

### Analyzing Python Files

49

50

```python

51

from mccabe import get_module_complexity

52

53

# Analyze a Python file

54

violations = get_module_complexity("my_module.py", threshold=7)

55

print(f"Found {violations} complexity violations in my_module.py")

56

```

57

58

### Using as Flake8 Plugin

59

60

The package integrates seamlessly with flake8:

61

62

```bash

63

# Enable McCabe checking with max complexity threshold

64

flake8 --max-complexity 10 my_project/

65

66

# Example output:

67

# my_project/complex_module.py:15:1: C901 'complex_function' is too complex (12)

68

```

69

70

## Capabilities

71

72

### Code Complexity Analysis

73

74

Analyzes Python source code strings for McCabe cyclomatic complexity violations.

75

76

```python { .api }

77

def get_code_complexity(code, threshold=7, filename='stdin'):

78

"""

79

Analyze code string for McCabe complexity violations.

80

81

Parameters:

82

- code (str): Python source code to analyze

83

- threshold (int): Complexity threshold, default 7

84

- filename (str): Filename for error reporting, default 'stdin'

85

86

Returns:

87

int: Number of complexity violations found

88

89

Side effects:

90

Prints violations to stdout in format:

91

"filename:line:col: C901 'function_name' is too complex (N)"

92

"""

93

```

94

95

### Module Complexity Analysis

96

97

Analyzes Python module files for McCabe cyclomatic complexity violations.

98

99

```python { .api }

100

def get_module_complexity(module_path, threshold=7):

101

"""

102

Analyze Python module file for McCabe complexity violations.

103

104

Parameters:

105

- module_path (str): Path to Python module file

106

- threshold (int): Complexity threshold, default 7

107

108

Returns:

109

int: Number of complexity violations found

110

"""

111

```

112

113

### Command Line Interface

114

115

Provides standalone command-line complexity analysis with optional Graphviz output.

116

117

```python { .api }

118

def main(argv=None):

119

"""

120

Command-line interface for standalone complexity analysis.

121

122

Parameters:

123

- argv (list): Command-line arguments, default sys.argv[1:]

124

125

Command-line options:

126

--dot, -d: Output Graphviz DOT format for visualization

127

--min, -m: Minimum complexity threshold for output (default 1)

128

129

Side effects:

130

Prints analysis results or DOT graph to stdout

131

"""

132

```

133

134

### Flake8 Plugin Integration

135

136

McCabe checker class that integrates with flake8 for automated code quality checking.

137

138

```python { .api }

139

class McCabeChecker:

140

"""

141

McCabe cyclomatic complexity checker for flake8 integration.

142

143

Class attributes:

144

- name (str): Plugin name 'mccabe'

145

- version (str): Plugin version

146

- max_complexity (int): Complexity threshold (-1 = disabled)

147

"""

148

149

def __init__(self, tree, filename):

150

"""

151

Initialize checker with AST and filename.

152

153

Parameters:

154

- tree: Python AST tree to analyze

155

- filename (str): Source filename

156

"""

157

158

@classmethod

159

def add_options(cls, parser):

160

"""

161

Add command-line options to flake8 parser.

162

163

Parameters:

164

- parser: Flake8 option parser

165

166

Adds --max-complexity option with config file support

167

"""

168

169

@classmethod

170

def parse_options(cls, options):

171

"""

172

Parse and store flake8 options.

173

174

Parameters:

175

- options: Parsed options object

176

177

Sets cls.max_complexity from options.max_complexity

178

"""

179

180

def run(self):

181

"""

182

Run complexity check and yield violations.

183

184

Yields:

185

tuple: (line_number, column, message, checker_class)

186

187

Message format: "C901 'function_name' is too complex (N)"

188

Only yields if complexity > max_complexity threshold

189

"""

190

```

191

192

### Control Flow Graph Classes

193

194

Core classes for building and analyzing control flow graphs used in complexity calculation.

195

196

```python { .api }

197

class ASTVisitor:

198

"""

199

Base class for performing depth-first walk of Python AST.

200

"""

201

202

def __init__(self):

203

"""Initialize visitor with empty cache."""

204

205

def default(self, node, *args):

206

"""

207

Default visit method that dispatches to child nodes.

208

209

Parameters:

210

- node: AST node to visit

211

- *args: Additional arguments passed to visitor methods

212

"""

213

214

def dispatch(self, node, *args):

215

"""

216

Dispatch to appropriate visitor method based on node type.

217

218

Parameters:

219

- node: AST node to dispatch

220

- *args: Additional arguments

221

222

Returns:

223

Result of visitor method call

224

"""

225

226

def preorder(self, tree, visitor, *args):

227

"""

228

Perform preorder walk of AST tree using visitor.

229

230

Parameters:

231

- tree: AST tree to walk

232

- visitor: Visitor object with visit methods

233

- *args: Additional arguments passed to visitor methods

234

"""

235

236

class PathNode:

237

"""

238

Represents a node in the control flow graph.

239

"""

240

241

def __init__(self, name, look="circle"):

242

"""

243

Initialize node with name and optional shape.

244

245

Parameters:

246

- name (str): Node name/label

247

- look (str): Node shape for DOT output, default "circle"

248

"""

249

250

def to_dot(self):

251

"""Output node in Graphviz DOT format to stdout."""

252

253

def dot_id(self):

254

"""

255

Return unique ID for DOT output.

256

257

Returns:

258

int: Unique node identifier

259

"""

260

261

class PathGraph:

262

"""

263

Represents a control flow graph for complexity calculation.

264

"""

265

266

def __init__(self, name, entity, lineno, column=0):

267

"""

268

Initialize graph with metadata.

269

270

Parameters:

271

- name (str): Graph name

272

- entity (str): Associated code entity (function/class name)

273

- lineno (int): Line number in source

274

- column (int): Column number in source, default 0

275

"""

276

277

def connect(self, n1, n2):

278

"""

279

Connect two nodes in the graph.

280

281

Parameters:

282

- n1 (PathNode): Source node

283

- n2 (PathNode): Destination node

284

"""

285

286

def to_dot(self):

287

"""Output graph in Graphviz DOT format to stdout."""

288

289

def complexity(self):

290

"""

291

Calculate McCabe complexity using V-E+2 formula.

292

293

Returns:

294

int: McCabe complexity score

295

"""

296

297

class PathGraphingAstVisitor(ASTVisitor):

298

"""

299

AST visitor that builds control flow graphs for complexity analysis.

300

Inherits from ASTVisitor.

301

"""

302

303

def __init__(self):

304

"""Initialize visitor with empty state and graphs dictionary."""

305

306

def reset(self):

307

"""Reset visitor state for new analysis."""

308

309

def dispatch_list(self, node_list):

310

"""

311

Process list of AST nodes.

312

313

Parameters:

314

- node_list (list): List of AST nodes to process

315

"""

316

317

def visitFunctionDef(self, node):

318

"""

319

Process function definitions to build control flow graphs.

320

321

Parameters:

322

- node: FunctionDef AST node

323

"""

324

325

def visitAsyncFunctionDef(self, node):

326

"""

327

Process async function definitions.

328

329

Parameters:

330

- node: AsyncFunctionDef AST node

331

"""

332

333

def visitClassDef(self, node):

334

"""

335

Process class definitions.

336

337

Parameters:

338

- node: ClassDef AST node

339

"""

340

341

def visitIf(self, node):

342

"""

343

Process if statements for branching complexity.

344

345

Parameters:

346

- node: If AST node

347

"""

348

349

def visitLoop(self, node):

350

"""

351

Process loop constructs for cyclomatic complexity.

352

353

Parameters:

354

- node: Loop AST node (For, While, AsyncFor)

355

"""

356

357

def visitFor(self, node):

358

"""Process for loops. Alias for visitLoop."""

359

360

def visitAsyncFor(self, node):

361

"""Process async for loops. Alias for visitLoop."""

362

363

def visitWhile(self, node):

364

"""Process while loops. Alias for visitLoop."""

365

366

def visitTryExcept(self, node):

367

"""

368

Process try/except blocks for exception handling complexity.

369

370

Parameters:

371

- node: Try AST node

372

"""

373

374

def visitTry(self, node):

375

"""Process try blocks. Alias for visitTryExcept."""

376

377

def visitWith(self, node):

378

"""

379

Process with statements.

380

381

Parameters:

382

- node: With AST node

383

"""

384

385

def visitAsyncWith(self, node):

386

"""

387

Process async with statements.

388

389

Parameters:

390

- node: AsyncWith AST node

391

"""

392

```

393

394

## Constants

395

396

```python { .api }

397

__version__ = '0.7.0' # Package version string

398

```

399

400

## Error Codes

401

402

- **C901**: McCabe complexity violation - function exceeds complexity threshold

403

- Format: `"C901 'function_name' is too complex (N)"`

404

- Reported at function definition line

405

- Can be suppressed with `# noqa: C901` comment

406

407

## Usage Patterns

408

409

### McCabe Complexity Guidelines

410

411

According to McCabe's original research:

412

- **1-10**: Simple, well-structured code

413

- **11-20**: Moderately complex, may need refactoring

414

- **21-50**: Complex, difficult to test and maintain

415

- **>50**: Extremely complex, high risk of defects

416

417

### Standalone Script Usage

418

419

```bash

420

# Basic complexity analysis

421

python -m mccabe my_script.py

422

423

# Set minimum complexity threshold

424

python -m mccabe --min 5 my_script.py

425

426

# Generate Graphviz DOT output for visualization

427

python -m mccabe --dot --min 3 my_script.py > complexity.dot

428

dot -Tpng complexity.dot -o complexity.png

429

```

430

431

### Integration with Development Workflow

432

433

```bash

434

# Add to pre-commit hooks

435

flake8 --max-complexity 10 src/

436

437

# Configure in setup.cfg or tox.ini

438

[flake8]

439

max-complexity = 10

440

441

# Configure in pyproject.toml (for flake8 5.0+)

442

[tool.flake8]

443

max-complexity = 10

444

```