or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-parsing.mderror-handling.mdgrammar-system.mdindex.mdpython-elements.mdtokenization.mdtree-navigation.mdutilities.md

python-elements.mddocs/

0

# Python Syntax Elements

1

2

Python-specific node types that represent all language constructs including modules, functions, classes, statements, expressions, and literals. These specialized classes provide Python-aware methods for code analysis and manipulation.

3

4

## Capabilities

5

6

### Base Python Classes

7

8

Foundation classes that provide Python-specific functionality to all syntax tree elements.

9

10

```python { .api }

11

class PythonMixin:

12

"""

13

Mixin providing Python-specific functionality to nodes and leaves.

14

"""

15

16

class PythonLeaf(PythonMixin, Leaf):

17

"""

18

Base class for Python leaf nodes (tokens).

19

20

Inherits all functionality from Leaf with Python-specific enhancements.

21

"""

22

23

class PythonBaseNode(PythonMixin, BaseNode):

24

"""

25

Base class for Python nodes with children.

26

27

Inherits all functionality from BaseNode with Python-specific enhancements.

28

"""

29

30

class PythonNode(PythonMixin, Node):

31

"""

32

Standard Python node implementation.

33

34

Used for most Python syntax constructs.

35

"""

36

37

class PythonErrorNode(PythonMixin, ErrorNode):

38

"""

39

Error node for invalid Python syntax.

40

41

Contains partial or invalid syntax with error recovery.

42

"""

43

44

class PythonErrorLeaf(ErrorLeaf, PythonLeaf):

45

"""

46

Error leaf for invalid Python tokens.

47

48

Contains partial or invalid tokens with error recovery.

49

"""

50

```

51

52

### Module and Scope Classes

53

54

Top-level containers and scoped constructs that organize Python code.

55

56

```python { .api }

57

class Module(Scope):

58

"""

59

The top-level module node representing a Python file.

60

61

Attributes:

62

type (str): Always 'file_input'

63

"""

64

65

def get_used_names(self):

66

"""

67

Get all name usages in this module.

68

69

Returns:

70

UsedNamesMapping: Immutable mapping from name strings to lists of Name nodes

71

"""

72

73

def iter_imports(self):

74

"""

75

Get all import statements in this module.

76

77

Yields:

78

Import: ImportName and ImportFrom nodes

79

"""

80

81

def iter_funcdefs(self):

82

"""

83

Get all function definitions in this module.

84

85

Yields:

86

Function: Function definition nodes

87

"""

88

89

def iter_classdefs(self):

90

"""

91

Get all class definitions in this module.

92

93

Yields:

94

Class: Class definition nodes

95

"""

96

```

97

98

```python { .api }

99

class Scope(PythonBaseNode):

100

"""

101

Base class for scoped constructs (functions, classes, modules).

102

"""

103

104

def iter_funcdefs(self):

105

"""Get function definitions within this scope."""

106

107

def iter_classdefs(self):

108

"""Get class definitions within this scope."""

109

110

def iter_imports(self):

111

"""Get import statements within this scope."""

112

113

def get_suite(self):

114

"""

115

Get the executable body of this scope.

116

117

Returns:

118

BaseNode: Suite node containing the body statements

119

"""

120

```

121

122

#### Usage Examples

123

124

```python

125

import parso

126

127

code = '''

128

import os

129

import sys

130

from pathlib import Path

131

132

def function1():

133

pass

134

135

class MyClass:

136

def method(self):

137

pass

138

139

def function2():

140

return 42

141

'''

142

143

module = parso.parse(code)

144

145

# Get all imports

146

imports = list(module.iter_imports())

147

print(f"Found {len(imports)} import statements")

148

for imp in imports:

149

if imp.type == 'import_name':

150

names = [path[-1].value for path in imp.get_paths()]

151

print(f"Import: {', '.join(names)}")

152

elif imp.type == 'import_from':

153

from_names = [n.value for n in imp.get_from_names()]

154

defined = [n.value for n in imp.get_defined_names()]

155

print(f"From {'.'.join(from_names)} import {', '.join(defined)}")

156

157

# Get all functions

158

functions = list(module.iter_funcdefs())

159

print(f"Found {len(functions)} functions:")

160

for func in functions:

161

print(f" {func.name.value}() at line {func.start_pos[0]}")

162

163

# Get all classes

164

classes = list(module.iter_classdefs())

165

print(f"Found {len(classes)} classes:")

166

for cls in classes:

167

print(f" {cls.name.value} at line {cls.start_pos[0]}")

168

169

# Analyze name usage

170

used_names = module.get_used_names()

171

print(f"Name 'os' used {len(used_names.get('os', []))} times")

172

```

173

174

### Function and Class Definitions

175

176

Definitions for functions, methods, and classes with specialized analysis methods.

177

178

```python { .api }

179

class Function(ClassOrFunc):

180

"""

181

Function definition node.

182

183

Attributes:

184

type (str): 'funcdef'

185

name (Name): Function name node

186

"""

187

188

def get_params(self):

189

"""

190

Get function parameters.

191

192

Returns:

193

list[Param]: List of parameter objects

194

"""

195

196

def iter_yield_exprs(self):

197

"""

198

Find yield expressions in function body.

199

200

Yields:

201

YieldExpr: Yield expression nodes

202

"""

203

204

def iter_return_stmts(self):

205

"""

206

Find return statements in function body.

207

208

Yields:

209

ReturnStmt: Return statement nodes

210

"""

211

212

def iter_raise_stmts(self):

213

"""

214

Find raise statements in function body.

215

216

Yields:

217

KeywordStatement: Raise statement nodes

218

"""

219

220

def is_generator(self):

221

"""

222

Check if function is a generator.

223

224

Returns:

225

bool: True if function contains yield expressions

226

"""

227

228

@property

229

def annotation(self):

230

"""

231

Get return type annotation.

232

233

Returns:

234

NodeOrLeaf | None: Return annotation or None

235

"""

236

```

237

238

```python { .api }

239

class Class(ClassOrFunc):

240

"""

241

Class definition node.

242

243

Attributes:

244

type (str): 'classdef'

245

name (Name): Class name node

246

"""

247

248

def get_super_arglist(self):

249

"""

250

Get superclass argument list.

251

252

Returns:

253

BaseNode | None: Arglist node with superclasses or None

254

"""

255

```

256

257

```python { .api }

258

class Lambda(Function):

259

"""

260

Lambda expression node.

261

262

Attributes:

263

type (str): 'lambdef'

264

"""

265

266

@property

267

def name(self):

268

"""

269

Lambda name property.

270

271

Raises:

272

AttributeError: Lambdas don't have names

273

"""

274

275

@property

276

def annotation(self):

277

"""

278

Lambda annotation property.

279

280

Returns:

281

None: Lambdas don't have return annotations

282

"""

283

```

284

285

#### Usage Examples

286

287

```python

288

import parso

289

290

code = '''

291

def regular_func(a: int, b: str = "default") -> str:

292

"""A regular function."""

293

return f"{a}: {b}"

294

295

def generator_func():

296

yield 1

297

yield 2

298

return "done"

299

300

class Parent:

301

pass

302

303

class Child(Parent, dict):

304

def method(self, x, y=None):

305

if x:

306

return x

307

raise ValueError("Invalid input")

308

309

lambda_expr = lambda x, y: x + y

310

'''

311

312

module = parso.parse(code)

313

314

# Analyze function definitions

315

for func in module.iter_funcdefs():

316

print(f"\nFunction: {func.name.value}")

317

318

# Check if it's a generator

319

if func.is_generator():

320

print(" Type: Generator")

321

yields = list(func.iter_yield_exprs())

322

print(f" Yield expressions: {len(yields)}")

323

else:

324

print(" Type: Regular function")

325

326

# Get parameters

327

params = func.get_params()

328

print(f" Parameters: {len(params)}")

329

for param in params:

330

param_info = [param.name.value]

331

if param.annotation:

332

param_info.append(f"annotation={param.annotation.get_code()}")

333

if param.default:

334

param_info.append(f"default={param.default.get_code()}")

335

if param.star_count:

336

param_info.append(f"star_count={param.star_count}")

337

print(f" {', '.join(param_info)}")

338

339

# Check return annotation

340

if func.annotation:

341

print(f" Return annotation: {func.annotation.get_code()}")

342

343

# Count return statements

344

returns = list(func.iter_return_stmts())

345

print(f" Return statements: {len(returns)}")

346

347

# Analyze class definitions

348

for cls in module.iter_classdefs():

349

print(f"\nClass: {cls.name.value}")

350

351

# Get superclasses

352

super_arglist = cls.get_super_arglist()

353

if super_arglist:

354

# Extract superclass names

355

superclasses = []

356

for child in super_arglist.children:

357

if hasattr(child, 'value') and child.value not in (',', ):

358

superclasses.append(child.value)

359

if superclasses:

360

print(f" Inherits from: {', '.join(superclasses)}")

361

else:

362

print(" No explicit superclasses")

363

364

# Get methods in class

365

methods = list(cls.iter_funcdefs())

366

print(f" Methods: {len(methods)}")

367

for method in methods:

368

print(f" {method.name.value}()")

369

370

# Find lambda expressions

371

def find_lambdas(node):

372

"""Find all lambda expressions in a tree."""

373

lambdas = []

374

if hasattr(node, 'type') and node.type == 'lambdef':

375

lambdas.append(node)

376

if hasattr(node, 'children'):

377

for child in node.children:

378

lambdas.extend(find_lambdas(child))

379

return lambdas

380

381

lambdas = find_lambdas(module)

382

print(f"\nFound {len(lambdas)} lambda expressions")

383

for lam in lambdas:

384

params = lam.get_params()

385

param_names = [p.name.value for p in params]

386

print(f" lambda {', '.join(param_names)}: ...")

387

```

388

389

### Parameter Handling

390

391

Specialized parameter objects for function analysis.

392

393

```python { .api }

394

class Param(PythonBaseNode):

395

"""

396

Function parameter node.

397

398

Attributes:

399

type (str): 'param'

400

name (Name): Parameter name node

401

"""

402

403

@property

404

def star_count(self):

405

"""

406

Number of stars in parameter.

407

408

Returns:

409

int: 0 for normal, 1 for *args, 2 for **kwargs

410

"""

411

412

@property

413

def default(self):

414

"""

415

Parameter default value.

416

417

Returns:

418

NodeOrLeaf | None: Default value expression or None

419

"""

420

421

@property

422

def annotation(self):

423

"""

424

Parameter type annotation.

425

426

Returns:

427

NodeOrLeaf | None: Type annotation or None

428

"""

429

430

@property

431

def position_index(self):

432

"""

433

Positional index of parameter.

434

435

Returns:

436

int: Position index in parameter list

437

"""

438

439

def get_parent_function(self):

440

"""

441

Get the function containing this parameter.

442

443

Returns:

444

Function | Lambda: Parent function or lambda

445

"""

446

```

447

448

#### Usage Examples

449

450

```python

451

import parso

452

453

code = '''

454

def complex_func(pos_only, /, normal, *args, kw_only, **kwargs):

455

pass

456

457

def annotated_func(a: int, b: str = "default", c: list[int] = None):

458

pass

459

'''

460

461

module = parso.parse(code)

462

463

for func in module.iter_funcdefs():

464

print(f"\nFunction: {func.name.value}")

465

params = func.get_params()

466

467

for i, param in enumerate(params):

468

print(f" Parameter {i}: {param.name.value}")

469

print(f" Position index: {param.position_index}")

470

print(f" Star count: {param.star_count}")

471

472

if param.annotation:

473

print(f" Annotation: {param.annotation.get_code()}")

474

475

if param.default:

476

print(f" Default: {param.default.get_code()}")

477

478

parent_func = param.get_parent_function()

479

print(f" Parent function: {parent_func.name.value}")

480

```

481

482

### Name and Identifier Handling

483

484

Name nodes representing identifiers, variables, and function names.

485

486

```python { .api }

487

class Name(PythonLeaf):

488

"""

489

Identifier/name node.

490

491

Attributes:

492

type (str): 'name'

493

value (str): The identifier string

494

"""

495

496

def is_definition(self, include_setitem=False):

497

"""

498

Check if this name is being defined.

499

500

Args:

501

include_setitem (bool): Include item assignments like obj[key] = value

502

503

Returns:

504

bool: True if this is a definition

505

"""

506

507

def get_definition(self, import_name_always=False, include_setitem=False):

508

"""

509

Get the definition node for this name.

510

511

Args:

512

import_name_always (bool): Always consider import names as definitions

513

include_setitem (bool): Include item assignments

514

515

Returns:

516

NodeOrLeaf | None: Definition node or None

517

"""

518

```

519

520

#### Usage Examples

521

522

```python

523

import parso

524

525

code = '''

526

import os

527

from sys import path

528

529

x = 42

530

def func(param):

531

global x

532

x = param

533

local_var = "hello"

534

return local_var

535

536

class MyClass:

537

def __init__(self):

538

self.attr = "value"

539

'''

540

541

module = parso.parse(code)

542

543

# Analyze all name usages

544

used_names = module.get_used_names()

545

546

for name_str, name_nodes in used_names.items():

547

print(f"\nName '{name_str}' appears {len(name_nodes)} times:")

548

549

for name_node in name_nodes:

550

print(f" At {name_node.start_pos}: ", end="")

551

552

if name_node.is_definition():

553

print("DEFINITION", end="")

554

definition = name_node.get_definition()

555

if definition:

556

print(f" (in {definition.type})", end="")

557

else:

558

print("USAGE", end="")

559

definition = name_node.get_definition()

560

if definition:

561

print(f" (defined in {definition.type})", end="")

562

563

print()

564

565

# Focus on specific names

566

if 'x' in used_names:

567

print(f"\nVariable 'x' analysis:")

568

for x_node in used_names['x']:

569

if x_node.is_definition():

570

def_node = x_node.get_definition()

571

print(f" Defined at {x_node.start_pos} in {def_node.type}")

572

else:

573

print(f" Used at {x_node.start_pos}")

574

```

575

576

### Literal and Token Classes

577

578

Nodes representing Python literals and operators.

579

580

```python { .api }

581

class String(Literal):

582

"""

583

String literal node.

584

585

Attributes:

586

type (str): 'string'

587

value (str): Complete string including quotes and prefix

588

"""

589

590

@property

591

def string_prefix(self):

592

"""

593

Get string prefix (r, f, b, u, etc.).

594

595

Returns:

596

str: String prefix characters

597

"""

598

599

class Number(Literal):

600

"""

601

Numeric literal node.

602

603

Attributes:

604

type (str): 'number'

605

value (str): Number as string (preserves format)

606

"""

607

608

class Keyword(PythonLeaf):

609

"""

610

Python keyword node.

611

612

Attributes:

613

type (str): 'keyword'

614

value (str): Keyword string

615

"""

616

617

class Operator(PythonLeaf):

618

"""

619

Operator node.

620

621

Attributes:

622

type (str): 'operator'

623

value (str): Operator string

624

"""

625

```

626

627

#### Usage Examples

628

629

```python

630

import parso

631

632

code = '''

633

x = 42

634

y = 3.14

635

z = "hello"

636

w = r"raw string"

637

f_str = f"formatted {x}"

638

binary = 0b1010

639

hex_num = 0xFF

640

641

if x > 0:

642

print("positive")

643

'''

644

645

module = parso.parse(code)

646

647

def analyze_literals(node):

648

"""Find and analyze all literals in the tree."""

649

literals = {'strings': [], 'numbers': [], 'keywords': [], 'operators': []}

650

651

def walk(n):

652

if hasattr(n, 'type'):

653

if n.type == 'string':

654

prefix = n.string_prefix if hasattr(n, 'string_prefix') else ''

655

literals['strings'].append((n.value, prefix, n.start_pos))

656

elif n.type == 'number':

657

literals['numbers'].append((n.value, n.start_pos))

658

elif n.type == 'keyword':

659

literals['keywords'].append((n.value, n.start_pos))

660

elif n.type == 'operator':

661

literals['operators'].append((n.value, n.start_pos))

662

663

if hasattr(n, 'children'):

664

for child in n.children:

665

walk(child)

666

667

walk(node)

668

return literals

669

670

literals = analyze_literals(module)

671

672

print("String literals:")

673

for value, prefix, pos in literals['strings']:

674

print(f" {value} (prefix: '{prefix}') at {pos}")

675

676

print("\nNumber literals:")

677

for value, pos in literals['numbers']:

678

print(f" {value} at {pos}")

679

680

print("\nKeywords:")

681

for value, pos in literals['keywords']:

682

print(f" {value} at {pos}")

683

684

print("\nOperators:")

685

for value, pos in literals['operators']:

686

if value not in (',', ':', '(', ')', '[', ']'): # Skip common punctuation

687

print(f" {value} at {pos}")

688

```

689

690

### Control Flow Statements

691

692

Nodes representing Python control flow constructs.

693

694

```python { .api }

695

class IfStmt(Flow):

696

"""

697

If statement node.

698

699

Attributes:

700

type (str): 'if_stmt'

701

"""

702

703

def get_test_nodes(self):

704

"""

705

Get test expressions for if/elif clauses.

706

707

Yields:

708

NodeOrLeaf: Test expressions

709

"""

710

711

def is_node_after_else(self, node):

712

"""

713

Check if a node is in the else clause.

714

715

Args:

716

node (NodeOrLeaf): Node to check

717

718

Returns:

719

bool: True if node is after else

720

"""

721

722

class ForStmt(Flow):

723

"""

724

For loop node.

725

726

Attributes:

727

type (str): 'for_stmt'

728

"""

729

730

def get_testlist(self):

731

"""

732

Get the iteration target expression.

733

734

Returns:

735

NodeOrLeaf: Expression being iterated over

736

"""

737

738

def get_defined_names(self, include_setitem=False):

739

"""

740

Get names defined by loop variable.

741

742

Args:

743

include_setitem (bool): Include item assignments

744

745

Returns:

746

list[Name]: Names defined in loop target

747

"""

748

749

class WithStmt(Flow):

750

"""

751

With statement node.

752

753

Attributes:

754

type (str): 'with_stmt'

755

"""

756

757

def get_defined_names(self, include_setitem=False):

758

"""

759

Get names defined in 'as' clauses.

760

761

Args:

762

include_setitem (bool): Include item assignments

763

764

Returns:

765

list[Name]: Names defined by 'as' clauses

766

"""

767

768

class TryStmt(Flow):

769

"""

770

Try statement node.

771

772

Attributes:

773

type (str): 'try_stmt'

774

"""

775

776

def get_except_clause_tests(self):

777

"""

778

Get exception types from except clauses.

779

780

Yields:

781

NodeOrLeaf | None: Exception type expressions or None for bare except

782

"""

783

```

784

785

#### Usage Examples

786

787

```python

788

import parso

789

790

code = '''

791

if x > 0:

792

print("positive")

793

elif x < 0:

794

print("negative")

795

else:

796

print("zero")

797

798

for item in items:

799

process(item)

800

801

for i, value in enumerate(data):

802

print(f"{i}: {value}")

803

804

with open("file.txt") as f:

805

content = f.read()

806

807

with lock, open("file") as f:

808

data = f.read()

809

810

try:

811

result = risky_operation()

812

except ValueError as e:

813

print(f"ValueError: {e}")

814

except (TypeError, AttributeError):

815

print("Type or attribute error")

816

except:

817

print("Unknown error")

818

'''

819

820

module = parso.parse(code)

821

822

# Analyze control flow statements

823

def find_control_flow(node):

824

"""Find all control flow statements."""

825

control_flow = []

826

827

def walk(n):

828

if hasattr(n, 'type'):

829

if n.type in ('if_stmt', 'for_stmt', 'while_stmt', 'try_stmt', 'with_stmt'):

830

control_flow.append(n)

831

832

if hasattr(n, 'children'):

833

for child in n.children:

834

walk(child)

835

836

walk(node)

837

return control_flow

838

839

statements = find_control_flow(module)

840

841

for stmt in statements:

842

print(f"\n{stmt.type} at line {stmt.start_pos[0]}:")

843

844

if stmt.type == 'if_stmt':

845

tests = list(stmt.get_test_nodes())

846

print(f" Test conditions: {len(tests)}")

847

for i, test in enumerate(tests):

848

print(f" {i+1}: {test.get_code().strip()}")

849

850

elif stmt.type == 'for_stmt':

851

target = stmt.get_testlist()

852

defined_names = stmt.get_defined_names()

853

print(f" Iterating over: {target.get_code().strip()}")

854

print(f" Loop variables: {[n.value for n in defined_names]}")

855

856

elif stmt.type == 'with_stmt':

857

defined_names = stmt.get_defined_names()

858

if defined_names:

859

print(f" Context variables: {[n.value for n in defined_names]}")

860

861

elif stmt.type == 'try_stmt':

862

except_tests = list(stmt.get_except_clause_tests())

863

print(f" Exception handlers: {len(except_tests)}")

864

for i, test in enumerate(except_tests):

865

if test is None:

866

print(f" {i+1}: bare except")

867

else:

868

print(f" {i+1}: {test.get_code().strip()}")

869

```

870

871

### Import Statement Analysis

872

873

Specialized nodes for analyzing import statements and dependencies.

874

875

```python { .api }

876

class ImportName(Import):

877

"""

878

Regular import statement (import foo).

879

880

Attributes:

881

type (str): 'import_name'

882

"""

883

884

def get_defined_names(self, include_setitem=False):

885

"""Get names defined by this import."""

886

887

def get_paths(self):

888

"""Get import paths as lists of names."""

889

890

def is_nested(self):

891

"""Check if import defines nested names."""

892

893

class ImportFrom(Import):

894

"""

895

From import statement (from foo import bar).

896

897

Attributes:

898

type (str): 'import_from'

899

"""

900

901

def get_defined_names(self, include_setitem=False):

902

"""Get names defined by this import."""

903

904

def get_from_names(self):

905

"""Get the module names being imported from."""

906

907

def get_paths(self):

908

"""Get complete import paths."""

909

910

@property

911

def level(self):

912

"""

913

Get relative import level.

914

915

Returns:

916

int: Number of dots in relative import

917

"""

918

919

def is_star_import(self):

920

"""Check if this is a star import."""

921

```

922

923

#### Usage Examples

924

925

```python

926

import parso

927

928

code = '''

929

import os

930

import sys

931

from pathlib import Path

932

from . import local_module

933

from ..parent import parent_func

934

from foo import bar as baz

935

from typing import List, Dict, Optional

936

import numpy as np

937

from collections import *

938

'''

939

940

module = parso.parse(code)

941

942

imports = list(module.iter_imports())

943

944

for imp in imports:

945

print(f"\n{imp.type} at line {imp.start_pos[0]}:")

946

947

if imp.type == 'import_name':

948

defined = [n.value for n in imp.get_defined_names()]

949

paths = imp.get_paths()

950

951

print(f" Defines: {defined}")

952

print(f" Paths: {[[n.value for n in path] for path in paths]}")

953

print(f" Nested: {imp.is_nested()}")

954

955

elif imp.type == 'import_from':

956

from_names = [n.value for n in imp.get_from_names()]

957

defined = [n.value for n in imp.get_defined_names()]

958

level = imp.level

959

960

print(f" From: {'.'.join(from_names) if from_names else '(current)'}")

961

print(f" Level: {level} ({'absolute' if level == 0 else 'relative'})")

962

print(f" Defines: {defined}")

963

print(f" Star import: {imp.is_star_import()}")

964

965

paths = imp.get_paths()

966

print(f" Full paths: {[[n.value for n in path] for path in paths]}")

967

```