or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# flake8-simplify

1

2

A flake8 plugin that helps simplify Python code by detecting patterns that can be improved for readability and maintainability. It provides over 40 different rules that analyze Python AST and suggest code simplifications, including combining isinstance calls, using context managers, replacing nested if statements, utilizing built-in functions, and modernizing Python constructs.

3

4

## Package Information

5

6

- **Package Name**: flake8-simplify

7

- **Language**: Python

8

- **Installation**: `pip install flake8-simplify`

9

- **Python Version**: 3.6.1+

10

- **Dependencies**: `astor>=0.1`, `flake8>=3.7`, `importlib-metadata>=0.9` (Python < 3.8)

11

12

## Core Imports

13

14

The plugin automatically registers with flake8 through entry points (registered as "SIM") and doesn't require explicit imports in typical usage scenarios. Users simply install the package and run flake8.

15

16

For direct programmatic access to the plugin class (advanced usage only):

17

18

```python

19

from flake8_simplify import Plugin

20

```

21

22

However, the standard workflow requires no imports - the plugin integrates automatically via the entry point defined in pyproject.toml:

23

24

```toml

25

[project.entry-points]

26

"flake8.extension" = {SIM = "flake8_simplify:Plugin"}

27

```

28

29

## Basic Usage

30

31

flake8-simplify integrates seamlessly with flake8. After installation, it automatically analyzes your code when running flake8:

32

33

```bash

34

# Install the plugin

35

pip install flake8-simplify

36

37

# Run flake8 on your code

38

flake8 your_file.py

39

40

# Or run on entire directory

41

flake8 .

42

```

43

44

Example output:

45

```

46

./foo.py:10:12: SIM101 Multiple isinstance-calls which can be merged into a single call for variable 'value'

47

./bar.py:25:8: SIM108 Use ternary operator instead of if-else-assignment

48

./baz.py:42:1: SIM115 Use context handler for opening files

49

```

50

51

## Architecture

52

53

The plugin follows flake8's standard plugin architecture:

54

55

- **Plugin**: Main entry point that flake8 discovers and instantiates

56

- **Visitor**: AST visitor that traverses Python code and applies all rules

57

- **Rule Functions**: Individual functions implementing specific simplification checks

58

- **Utility Classes**: Extended AST node classes with metadata for rule analysis

59

60

Each rule function analyzes specific AST node types and returns violations as tuples containing line number, column offset, and error message. This design allows the plugin to efficiently check multiple simplification patterns in a single AST traversal.

61

62

## Capabilities

63

64

### Core Plugin API

65

66

The main plugin interface for flake8 integration, providing the entry point for code analysis and rule execution.

67

68

```python { .api }

69

class Plugin:

70

"""Main flake8 plugin class."""

71

name = __name__ # Class attribute: Plugin identifier (__name__ resolves to "flake8_simplify")

72

version = importlib_metadata.version(__name__) # Class attribute: Plugin version from package metadata

73

74

def __init__(self, tree: ast.AST):

75

"""

76

Initialize plugin with AST tree to analyze.

77

78

Parameters:

79

- tree: ast.AST - Python AST tree to analyze

80

"""

81

82

def run(self) -> Generator[Tuple[int, int, str, Type[Any]], None, None]:

83

"""

84

Execute analysis and yield violations.

85

86

Returns:

87

Generator yielding tuples of (line, column, message, plugin_type)

88

"""

89

90

class Visitor(ast.NodeVisitor):

91

"""AST visitor implementing all simplification rules."""

92

errors: List[Tuple[int, int, str]] # Collected violations

93

94

def __init__(self):

95

"""Initialize visitor with empty error list."""

96

97

# Visit methods for each AST node type

98

def visit_Assign(self, node: ast.Assign) -> Any: ...

99

def visit_Call(self, node: ast.Call) -> Any: ...

100

def visit_With(self, node: ast.With) -> Any: ...

101

def visit_Expr(self, node: ast.Expr) -> None: ...

102

def visit_BoolOp(self, node: ast.BoolOp) -> None: ...

103

def visit_If(self, node: ast.If) -> None: ...

104

def visit_For(self, node: ast.For) -> None: ...

105

def visit_Subscript(self, node: ast.Subscript) -> None: ...

106

def visit_Try(self, node: ast.Try) -> None: ...

107

def visit_UnaryOp(self, node_v: ast.UnaryOp) -> None: ...

108

def visit_IfExp(self, node: ast.IfExp) -> None: ...

109

def visit_Compare(self, node: ast.Compare) -> None: ...

110

def visit_ClassDef(self, node: ast.ClassDef) -> None: ...

111

112

def add_meta(root: ast.AST, level: int = 0) -> None:

113

"""

114

Add parent and sibling metadata to AST nodes.

115

116

Adds parent, previous_sibling, and next_sibling attributes to all AST nodes

117

to enable rule analysis that requires knowledge of node relationships.

118

119

Parameters:

120

- root: ast.AST - Root AST node to process

121

- level: int - Recursion depth (default: 0)

122

"""

123

```

124

125

### Assignment Rules

126

127

Rules for detecting and simplifying variable assignment patterns.

128

129

```python { .api }

130

def get_sim904(node: ast.Assign) -> List[Tuple[int, int, str]]:

131

"""

132

SIM904: Dict assignment that can be simplified.

133

134

Detects: a = {}; a['key'] = 'value'

135

Suggests: a = {'key': 'value'}

136

137

Parameters:

138

- node: ast.Assign - Assignment node to analyze

139

140

Returns:

141

List of (line, column, message) tuples

142

"""

143

144

def get_sim909(node: Assign) -> List[Tuple[int, int, str]]:

145

"""

146

SIM909: Remove reflexive assignments.

147

148

Detects: foo = foo

149

Suggests: Remove redundant assignment

150

151

Parameters:

152

- node: Assign - Extended assignment node with metadata

153

154

Returns:

155

List of (line, column, message) tuples

156

"""

157

```

158

159

### Boolean Operation Rules

160

161

Rules for simplifying boolean expressions and logical operations.

162

163

```python { .api }

164

def get_sim101(node: ast.BoolOp) -> List[Tuple[int, int, str]]:

165

"""

166

SIM101: Merge multiple isinstance calls.

167

168

Detects: isinstance(a, int) or isinstance(a, float)

169

Suggests: isinstance(a, (int, float))

170

171

Parameters:

172

- node: ast.BoolOp - Boolean operation node

173

174

Returns:

175

List of (line, column, message) tuples

176

"""

177

178

def get_sim109(node: ast.BoolOp) -> List[Tuple[int, int, str]]:

179

"""

180

SIM109: Use tuple for multiple equality checks.

181

182

Detects: value == a or value == b or value == c

183

Suggests: value in (a, b, c)

184

185

Parameters:

186

- node: ast.BoolOp - Boolean operation node

187

188

Returns:

189

List of (line, column, message) tuples

190

"""

191

192

def get_sim220(node: ast.BoolOp) -> List[Tuple[int, int, str]]:

193

"""

194

SIM220: Replace contradictory expressions with False.

195

196

Detects: a and not a

197

Suggests: False

198

199

Parameters:

200

- node: ast.BoolOp - Boolean operation node

201

202

Returns:

203

List of (line, column, message) tuples

204

"""

205

206

def get_sim221(node: ast.BoolOp) -> List[Tuple[int, int, str]]:

207

"""

208

SIM221: Replace tautological expressions with True.

209

210

Detects: a or not a

211

Suggests: True

212

213

Parameters:

214

- node: ast.BoolOp - Boolean operation node

215

216

Returns:

217

List of (line, column, message) tuples

218

"""

219

220

def get_sim222(node: ast.BoolOp) -> List[Tuple[int, int, str]]:

221

"""

222

SIM222: Simplify OR with True.

223

224

Detects: ... or True

225

Suggests: True

226

227

Parameters:

228

- node: ast.BoolOp - Boolean operation node

229

230

Returns:

231

List of (line, column, message) tuples

232

"""

233

234

def get_sim223(node: ast.BoolOp) -> List[Tuple[int, int, str]]:

235

"""

236

SIM223: Simplify AND with False.

237

238

Detects: ... and False

239

Suggests: False

240

241

Parameters:

242

- node: ast.BoolOp - Boolean operation node

243

244

Returns:

245

List of (line, column, message) tuples

246

"""

247

```

248

249

### Function Call Rules

250

251

Rules for optimizing function calls and method invocations.

252

253

```python { .api }

254

def get_sim115(node: Call) -> List[Tuple[int, int, str]]:

255

"""

256

SIM115: Use context manager for file operations.

257

258

Detects: f = open('file.txt'); ...

259

Suggests: with open('file.txt') as f: ...

260

261

Parameters:

262

- node: Call - Extended call node with metadata

263

264

Returns:

265

List of (line, column, message) tuples

266

"""

267

268

def get_sim901(node: ast.Call) -> List[Tuple[int, int, str]]:

269

"""

270

SIM901: Remove unnecessary bool() wrapper.

271

272

Detects: bool(a == b)

273

Suggests: a == b

274

275

Parameters:

276

- node: ast.Call - Function call node

277

278

Returns:

279

List of (line, column, message) tuples

280

"""

281

282

def get_sim905(node: ast.Call) -> List[Tuple[int, int, str]]:

283

"""

284

SIM905: Use list literal instead of string split.

285

286

Detects: "a,b,c".split(",")

287

Suggests: ["a", "b", "c"]

288

289

Parameters:

290

- node: ast.Call - Function call node

291

292

Returns:

293

List of (line, column, message) tuples

294

"""

295

296

def get_sim906(node: ast.Call) -> List[Tuple[int, int, str]]:

297

"""

298

SIM906: Merge nested os.path.join calls.

299

300

Detects: os.path.join(os.path.join(a, b), c)

301

Suggests: os.path.join(a, b, c)

302

303

Parameters:

304

- node: ast.Call - Function call node

305

306

Returns:

307

List of (line, column, message) tuples

308

"""

309

310

def get_sim910(node: Call) -> List[Tuple[int, int, str]]:

311

"""

312

SIM910: Remove explicit None default from dict.get.

313

314

Detects: dict.get(key, None)

315

Suggests: dict.get(key)

316

317

Parameters:

318

- node: Call - Extended call node with metadata

319

320

Returns:

321

List of (line, column, message) tuples

322

"""

323

324

def get_sim911(node: ast.Call) -> List[Tuple[int, int, str]]:

325

"""

326

SIM911: Use dict.items() instead of zip(keys(), values()).

327

328

Detects: zip(dict.keys(), dict.values())

329

Suggests: dict.items()

330

331

Parameters:

332

- node: ast.Call - Function call node

333

334

Returns:

335

List of (line, column, message) tuples

336

"""

337

```

338

339

### Control Flow Rules

340

341

Rules for simplifying if statements, loops, and conditional expressions.

342

343

```python { .api }

344

def get_sim102(node: ast.If) -> List[Tuple[int, int, str]]:

345

"""

346

SIM102: Combine nested if statements.

347

348

Detects: if a: if b: ...

349

Suggests: if a and b: ...

350

351

Parameters:

352

- node: ast.If - If statement node

353

354

Returns:

355

List of (line, column, message) tuples

356

"""

357

358

def get_sim103(node: ast.If) -> List[Tuple[int, int, str]]:

359

"""

360

SIM103: Return boolean condition directly.

361

362

Detects: if condition: return True else: return False

363

Suggests: return condition

364

365

Parameters:

366

- node: ast.If - If statement node

367

368

Returns:

369

List of (line, column, message) tuples

370

"""

371

372

def get_sim108(node: If) -> List[Tuple[int, int, str]]:

373

"""

374

SIM108: Use ternary operator for assignments.

375

376

Detects: if condition: x = a else: x = b

377

Suggests: x = a if condition else b

378

379

Parameters:

380

- node: If - Extended if node with metadata

381

382

Returns:

383

List of (line, column, message) tuples

384

"""

385

386

def get_sim114(node: ast.If) -> List[Tuple[int, int, str]]:

387

"""

388

SIM114: Combine if-elif with same body using OR.

389

390

Detects: if a: body elif b: body

391

Suggests: if a or b: body

392

393

Parameters:

394

- node: ast.If - If statement node

395

396

Returns:

397

List of (line, column, message) tuples

398

"""

399

400

def get_sim116(node: ast.If) -> List[Tuple[int, int, str]]:

401

"""

402

SIM116: Use dictionary instead of if-elif equality checks.

403

404

Detects: Long if-elif chains with equality comparisons

405

Suggests: Dictionary lookup pattern

406

407

Parameters:

408

- node: ast.If - If statement node

409

410

Returns:

411

List of (line, column, message) tuples

412

"""

413

414

def get_sim401(node: ast.If) -> List[Tuple[int, int, str]]:

415

"""

416

SIM401: Use dict.get() with default instead of if-else.

417

418

Detects: if key in dict: x = dict[key] else: x = default

419

Suggests: x = dict.get(key, default)

420

421

Parameters:

422

- node: ast.If - If statement node

423

424

Returns:

425

List of (line, column, message) tuples

426

"""

427

428

def get_sim908(node: ast.If) -> List[Tuple[int, int, str]]:

429

"""

430

SIM908: Use dict.get() for key existence checks.

431

432

Detects: if key in dict: dict[key]

433

Suggests: dict.get(key)

434

435

Parameters:

436

- node: ast.If - If statement node

437

438

Returns:

439

List of (line, column, message) tuples

440

"""

441

```

442

443

### Loop Rules

444

445

Rules for optimizing for loops and replacing them with more Pythonic constructs.

446

447

```python { .api }

448

def get_sim104(node: ast.For) -> List[Tuple[int, int, str]]:

449

"""

450

SIM104: Use yield from for generator delegation.

451

452

Detects: for item in iterable: yield item

453

Suggests: yield from iterable

454

455

Parameters:

456

- node: ast.For - For loop node

457

458

Returns:

459

List of (line, column, message) tuples

460

"""

461

462

def get_sim110_sim111(node: ast.For) -> List[Tuple[int, int, str]]:

463

"""

464

SIM110/SIM111: Use any() or all() for loop patterns.

465

466

SIM110 - Detects: for x in iterable: if condition: return True

467

SIM110 - Suggests: return any(condition for x in iterable)

468

469

SIM111 - Detects: for x in iterable: if condition: return False

470

SIM111 - Suggests: return all(not condition for x in iterable)

471

472

Parameters:

473

- node: ast.For - For loop node

474

475

Returns:

476

List of (line, column, message) tuples

477

"""

478

479

def get_sim113(node: For) -> List[Tuple[int, int, str]]:

480

"""

481

SIM113: Use enumerate instead of manual counter.

482

483

Detects: i = 0; for item in iterable: ...; i += 1

484

Suggests: for i, item in enumerate(iterable): ...

485

486

Parameters:

487

- node: For - Extended for node with metadata

488

489

Returns:

490

List of (line, column, message) tuples

491

"""

492

```

493

494

### Comparison and Unary Operation Rules

495

496

Rules for simplifying comparison operations and unary expressions.

497

498

```python { .api }

499

def get_sim118(node: ast.Compare) -> List[Tuple[int, int, str]]:

500

"""

501

SIM118: Use 'key in dict' instead of 'key in dict.keys()'.

502

503

Detects: key in dict.keys()

504

Suggests: key in dict

505

506

Parameters:

507

- node: ast.Compare - Comparison node

508

509

Returns:

510

List of (line, column, message) tuples

511

"""

512

513

def get_sim300(node: ast.Compare) -> List[Tuple[int, int, str]]:

514

"""

515

SIM300: Use natural comparison order (avoid Yoda conditions).

516

517

Detects: 42 == age

518

Suggests: age == 42

519

520

Parameters:

521

- node: ast.Compare - Comparison node

522

523

Returns:

524

List of (line, column, message) tuples

525

"""

526

527

def get_sim201(node: UnaryOp) -> List[Tuple[int, int, str]]:

528

"""

529

SIM201: Use '!=' instead of 'not =='.

530

531

Detects: not (a == b)

532

Suggests: a != b

533

534

Parameters:

535

- node: UnaryOp - Extended unary operation node

536

537

Returns:

538

List of (line, column, message) tuples

539

"""

540

541

def get_sim202(node: UnaryOp) -> List[Tuple[int, int, str]]:

542

"""

543

SIM202: Use '==' instead of 'not !='.

544

545

Detects: not (a != b)

546

Suggests: a == b

547

548

Parameters:

549

- node: UnaryOp - Extended unary operation node

550

551

Returns:

552

List of (line, column, message) tuples

553

"""

554

555

def get_sim203(node: UnaryOp) -> List[Tuple[int, int, str]]:

556

"""

557

SIM203: Use 'not in' instead of 'not (in)'.

558

559

Detects: not (a in b)

560

Suggests: a not in b

561

562

Parameters:

563

- node: UnaryOp - Extended unary operation node

564

565

Returns:

566

List of (line, column, message) tuples

567

"""

568

569

def get_sim208(node: UnaryOp) -> List[Tuple[int, int, str]]:

570

"""

571

SIM208: Remove double negation.

572

573

Detects: not (not a)

574

Suggests: a

575

576

Parameters:

577

- node: UnaryOp - Extended unary operation node

578

579

Returns:

580

List of (line, column, message) tuples

581

"""

582

```

583

584

### Ternary Expression Rules

585

586

Rules for simplifying conditional expressions (ternary operators).

587

588

```python { .api }

589

def get_sim210(node: ast.IfExp) -> List[Tuple[int, int, str]]:

590

"""

591

SIM210: Use bool() instead of True if condition else False.

592

593

Detects: True if condition else False

594

Suggests: bool(condition)

595

596

Parameters:

597

- node: ast.IfExp - Ternary expression node

598

599

Returns:

600

List of (line, column, message) tuples

601

"""

602

603

def get_sim211(node: ast.IfExp) -> List[Tuple[int, int, str]]:

604

"""

605

SIM211: Use 'not condition' instead of False if condition else True.

606

607

Detects: False if condition else True

608

Suggests: not condition

609

610

Parameters:

611

- node: ast.IfExp - Ternary expression node

612

613

Returns:

614

List of (line, column, message) tuples

615

"""

616

617

def get_sim212(node: ast.IfExp) -> List[Tuple[int, int, str]]:

618

"""

619

SIM212: Use natural order for ternary expressions.

620

621

Detects: b if not a else a

622

Suggests: a if a else b

623

624

Parameters:

625

- node: ast.IfExp - Ternary expression node

626

627

Returns:

628

List of (line, column, message) tuples

629

"""

630

```

631

632

### Exception Handling and Context Manager Rules

633

634

Rules for improving exception handling and resource management patterns.

635

636

```python { .api }

637

def get_sim105(node: ast.Try) -> List[Tuple[int, int, str]]:

638

"""

639

SIM105: Use contextlib.suppress for try-except-pass.

640

641

Detects: try: risky_operation() except SomeException: pass

642

Suggests: from contextlib import suppress; with suppress(SomeException): risky_operation()

643

644

Parameters:

645

- node: ast.Try - Try statement node

646

647

Returns:

648

List of (line, column, message) tuples

649

"""

650

651

def get_sim107(node: ast.Try) -> List[Tuple[int, int, str]]:

652

"""

653

SIM107: Avoid return in try/except and finally.

654

655

Detects: return statements in both try/except and finally blocks

656

Suggests: Restructure control flow to avoid confusing returns

657

658

Parameters:

659

- node: ast.Try - Try statement node

660

661

Returns:

662

List of (line, column, message) tuples

663

"""

664

665

def get_sim117(node: ast.With) -> List[Tuple[int, int, str]]:

666

"""

667

SIM117: Merge nested with statements.

668

669

Detects: with a: with b: ...

670

Suggests: with a, b: ...

671

672

Parameters:

673

- node: ast.With - With statement node

674

675

Returns:

676

List of (line, column, message) tuples

677

"""

678

```

679

680

### Class and Type Rules

681

682

Rules for modernizing class definitions and type annotations.

683

684

```python { .api }

685

def get_sim120(node: ast.ClassDef) -> List[Tuple[int, int, str]]:

686

"""

687

SIM120: Use modern class definition syntax.

688

689

Detects: class FooBar(object):

690

Suggests: class FooBar:

691

692

Parameters:

693

- node: ast.ClassDef - Class definition node

694

695

Returns:

696

List of (line, column, message) tuples

697

"""

698

699

def get_sim907(node: ast.Subscript) -> List[Tuple[int, int, str]]:

700

"""

701

SIM907: Use Optional[Type] instead of Union[Type, None].

702

703

Detects: Union[str, None]

704

Suggests: Optional[str]

705

706

Parameters:

707

- node: ast.Subscript - Subscript node (for type annotations)

708

709

Returns:

710

List of (line, column, message) tuples

711

"""

712

```

713

714

### Environment and Expression Rules

715

716

Rules for improving environment variable usage and expression patterns.

717

718

```python { .api }

719

def get_sim112(node: ast.Expr) -> List[Tuple[int, int, str]]:

720

"""

721

SIM112: Use CAPITAL environment variable names.

722

723

Detects: os.environ['path']

724

Suggests: os.environ['PATH']

725

726

Parameters:

727

- node: ast.Expr - Expression node

728

729

Returns:

730

List of (line, column, message) tuples

731

"""

732

```

733

734

## Utility Classes and Functions

735

736

### Extended AST Node Classes

737

738

Enhanced AST node classes that include parent and sibling relationships for rule analysis.

739

740

```python { .api }

741

class UnaryOp(ast.UnaryOp):

742

"""Extended UnaryOp with parent tracking."""

743

parent: ast.Expr # Parent node reference

744

745

def __init__(self, orig: ast.UnaryOp):

746

"""Copy constructor from original UnaryOp node."""

747

748

class Call(ast.Call):

749

"""Extended Call with parent tracking."""

750

parent: ast.Expr # Parent node reference

751

752

def __init__(self, orig: ast.Call):

753

"""Copy constructor from original Call node."""

754

755

class If(ast.If):

756

"""Extended If with parent tracking."""

757

parent: ast.Expr # Parent node reference

758

759

def __init__(self, orig: ast.If):

760

"""Copy constructor from original If node."""

761

762

class For(ast.For):

763

"""Extended For with parent/sibling tracking."""

764

parent: ast.AST # Parent node reference

765

previous_sibling: ast.AST # Previous sibling node

766

767

def __init__(self, orig: ast.For):

768

"""Copy constructor from original For node."""

769

770

class Assign(ast.Assign):

771

"""Extended Assign with parent/sibling tracking."""

772

parent: ast.AST # Parent node reference

773

previous_sibling: ast.AST # Previous sibling node

774

orig: ast.Assign # Original node reference

775

776

def __init__(self, orig: ast.Assign):

777

"""Copy constructor from original Assign node."""

778

```

779

780

### Code Analysis Utilities

781

782

Helper functions for analyzing and transforming AST nodes.

783

784

```python { .api }

785

def to_source(node: Union[None, ast.expr, ast.Expr, ast.withitem, ast.slice, ast.Assign]) -> str:

786

"""

787

Convert AST node to source code string.

788

789

Parameters:

790

- node: AST node or None

791

792

Returns:

793

Source code string representation

794

"""

795

796

def strip_parenthesis(string: str) -> str:

797

"""

798

Remove surrounding parentheses from string.

799

800

Parameters:

801

- string: String to process

802

803

Returns:

804

String without outer parentheses

805

"""

806

807

def strip_triple_quotes(string: str) -> str:

808

"""

809

Convert triple quotes to double quotes.

810

811

Parameters:

812

- string: String with potential triple quotes

813

814

Returns:

815

String with normalized quotes

816

"""

817

818

def use_double_quotes(string: str) -> str:

819

"""

820

Convert single quotes to double quotes.

821

822

Parameters:

823

- string: String with potential single quotes

824

825

Returns:

826

String with double quotes

827

"""

828

829

def is_body_same(body1: List[ast.stmt], body2: List[ast.stmt]) -> bool:

830

"""

831

Check if two statement lists are equivalent.

832

833

Parameters:

834

- body1: First list of AST statements

835

- body2: Second list of AST statements

836

837

Returns:

838

True if equivalent, False otherwise

839

"""

840

841

def is_stmt_equal(a: ast.stmt, b: ast.stmt) -> bool:

842

"""

843

Deep comparison of AST statements.

844

845

Parameters:

846

- a: First AST statement

847

- b: Second AST statement

848

849

Returns:

850

True if equal, False otherwise

851

"""

852

853

def get_if_body_pairs(node: ast.If) -> List[Tuple[ast.expr, List[ast.stmt]]]:

854

"""

855

Extract condition-body pairs from if-elif chain.

856

857

Parameters:

858

- node: If statement node

859

860

Returns:

861

List of (condition, body) tuples

862

"""

863

864

def is_constant_increase(expr: ast.AugAssign) -> bool:

865

"""

866

Check if augmented assignment increments by constant 1.

867

868

Parameters:

869

- expr: Augmented assignment node

870

871

Returns:

872

True if increments by 1, False otherwise

873

"""

874

875

def is_exception_check(node: ast.If) -> bool:

876

"""

877

Check if if-statement is an exception check pattern.

878

879

Parameters:

880

- node: If statement node

881

882

Returns:

883

True if raises exception, False otherwise

884

"""

885

886

def is_same_expression(a: ast.expr, b: ast.expr) -> bool:

887

"""

888

Check if two expressions are identical.

889

890

Parameters:

891

- a: First expression node

892

- b: Second expression node

893

894

Returns:

895

True if same, False otherwise

896

"""

897

898

def expression_uses_variable(expr: ast.expr, var: str) -> bool:

899

"""

900

Check if expression references a variable.

901

902

Parameters:

903

- expr: Expression node

904

- var: Variable name to check

905

906

Returns:

907

True if variable is used, False otherwise

908

"""

909

910

def body_contains_continue(stmts: List[ast.stmt]) -> bool:

911

"""

912

Check if statement list contains continue statements.

913

914

Parameters:

915

- stmts: List of statements

916

917

Returns:

918

True if contains continue, False otherwise

919

"""

920

921

def _get_duplicated_isinstance_call_by_node(node: ast.BoolOp) -> List[str]:

922

"""

923

Get a list of isinstance arguments which could be shortened (used by SIM101).

924

925

Analyzes boolean operations to find isinstance calls that can be combined.

926

For example: isinstance(a, int) or isinstance(a, float) can become isinstance(a, (int, float))

927

928

Parameters:

929

- node: ast.BoolOp - Boolean operation node containing isinstance calls

930

931

Returns:

932

List of variable names that have multiple isinstance calls

933

"""

934

```

935

936

## Constants

937

938

Python version compatibility constants for different AST node types. These constants handle differences between Python versions in AST node representation.

939

940

```python { .api }

941

# ast.Constant in Python 3.8+, ast.NameConstant in Python 3.6-3.7

942

if hasattr(ast, 'NameConstant'):

943

BOOL_CONST_TYPES = (ast.Constant, ast.NameConstant)

944

AST_CONST_TYPES = (ast.Constant, ast.NameConstant, ast.Str, ast.Num)

945

STR_TYPES = (ast.Constant, ast.Str)

946

else:

947

BOOL_CONST_TYPES = (ast.Constant,)

948

AST_CONST_TYPES = (ast.Constant,)

949

STR_TYPES = (ast.Constant,)

950

```

951

952

## Types

953

954

```python { .api }

955

from typing import Any, Generator, List, Tuple, Type, Union, DefaultDict

956

from collections import defaultdict

957

import ast

958

import itertools

959

import astor

960

import importlib_metadata # For Python < 3.8 compatibility

961

962

# Type aliases for rule function return values

963

RuleViolation = Tuple[int, int, str] # (line, column, message)

964

RuleResult = List[RuleViolation]

965

966

# Extended AST node types with metadata

967

ExtendedASTNode = Union[UnaryOp, Call, If, For, Assign]

968

```