or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

formatting.mdframe-analysis.mdindex.mdserialization.md

frame-analysis.mddocs/

0

# Stack Frame Analysis

1

2

Core functionality for analyzing Python stack frames and extracting detailed information including source code context, variable values, execution state, and AST-based code understanding. This module provides the foundation for all stack_data functionality.

3

4

## Capabilities

5

6

### FrameInfo Creation

7

8

Central class that extracts rich information from stack frames, providing access to source code, variables, execution context, and formatting options.

9

10

```python { .api }

11

class FrameInfo:

12

def __init__(self, frame_or_tb: Union[FrameType, TracebackType],

13

options: Optional[Options] = None):

14

"""

15

Create FrameInfo from a frame or traceback object.

16

17

Args:

18

frame_or_tb: Frame or traceback object to analyze

19

options: Configuration for analysis and display

20

"""

21

22

@classmethod

23

def stack_data(cls, frame_or_tb: Union[FrameType, TracebackType],

24

options: Optional[Options] = None,

25

*, collapse_repeated_frames: bool = True) -> Iterator[Union['FrameInfo', RepeatedFrames]]:

26

"""

27

Create iterator of FrameInfo objects for entire stack.

28

29

Args:

30

frame_or_tb: Starting frame or traceback

31

options: Configuration for analysis

32

collapse_repeated_frames: Whether to collapse recursive frames

33

34

Yields:

35

FrameInfo or RepeatedFrames objects for each stack level

36

"""

37

```

38

39

**Key Properties:**

40

- `frame: FrameType` - The actual frame object

41

- `options: Options` - Configuration options

42

- `code: CodeType` - Frame code object

43

- `source: Source` - Enhanced source object

44

- `filename: str` - Absolute file path

45

- `scope: Optional[ast.AST]` - Innermost function/class/module AST

46

- `lines: List[Union[Line, LineGap, BlankLineRange]]` - Lines to display

47

- `executing: executing.Executing` - Executing object from executing library

48

- `lineno: int` - Line number being executed

49

- `variables: List[Variable]` - All variables in scope

50

- `variables_in_lines: List[Variable]` - Variables in displayed lines

51

- `variables_by_lineno: Mapping[int, List[Tuple[Variable, ast.AST]]]` - Variables organized by line number

52

- `variables_in_executing_piece: List[Variable]` - Variables in currently executing piece

53

- `scope_pieces: List[range]` - All pieces (line ranges) in the scope

54

- `included_pieces: List[range]` - Pieces to display determined by options

55

- `executing_piece: range` - Currently executing piece

56

57

### Display Configuration

58

59

Configuration system for controlling how stack frames are analyzed and displayed, including context size, formatting preferences, and display options.

60

61

```python { .api }

62

class Options:

63

def __init__(self, *,

64

before: int = 3,

65

after: int = 1,

66

include_signature: bool = False,

67

max_lines_per_piece: int = 6,

68

pygments_formatter = None,

69

blank_lines: BlankLines = BlankLines.HIDDEN):

70

"""

71

Configuration for FrameInfo analysis and display.

72

73

Args:

74

before: Number of context pieces before executing piece

75

after: Number of context pieces after executing piece

76

include_signature: Whether to include function signature

77

max_lines_per_piece: Max lines per piece before truncation

78

pygments_formatter: Pygments formatter for syntax highlighting

79

blank_lines: How to handle blank lines in output

80

"""

81

```

82

83

### Enhanced Source Code Analysis

84

85

Enhanced source code representation with AST parsing, tokenization, and metadata extraction for rich code analysis and display.

86

87

```python { .api }

88

class Source:

89

"""

90

Enhanced source code of a single file with associated metadata.

91

Inherits from executing.Source with additional features.

92

"""

93

94

@property

95

def pieces(self) -> List[range]:

96

"""List of code piece ranges for logical grouping."""

97

98

@property

99

def tokens_by_lineno(self) -> Mapping[int, List[Token]]:

100

"""Tokens grouped by line number for detailed analysis."""

101

102

def line_range(self, node: ast.AST) -> Tuple[int, int]:

103

"""

104

Get line range for AST node.

105

106

Args:

107

node: AST node to analyze

108

109

Returns:

110

Tuple of (start_line, end_line)

111

"""

112

```

113

114

### Variable Inspection

115

116

Safe expression evaluation and variable inspection using pure_eval for extracting variable values and expressions from stack frames.

117

118

```python { .api }

119

class Variable(NamedTuple):

120

"""

121

An expression that appears in source code and its evaluated value.

122

123

Fields:

124

name: Source text of the expression

125

nodes: List of equivalent AST nodes representing the expression

126

value: Safely evaluated value of the expression

127

"""

128

name: str

129

nodes: Sequence[ast.AST]

130

value: Any

131

```

132

133

### Line-Level Analysis

134

135

Detailed analysis of individual source code lines with token information, variable ranges, and rendering capabilities.

136

137

```python { .api }

138

class Line:

139

def __init__(self, frame_info: 'FrameInfo', lineno: int):

140

"""

141

Create Line object for specific line in frame.

142

143

Args:

144

frame_info: Parent FrameInfo object

145

lineno: 1-based line number

146

"""

147

148

def render(self, markers: Iterable[MarkerInLine] = (), *,

149

strip_leading_indent: bool = True,

150

pygmented: bool = False,

151

escape_html: bool = False) -> str:

152

"""

153

Render line with optional markers and formatting.

154

155

Args:

156

markers: Markers to insert in the line

157

strip_leading_indent: Whether to strip leading whitespace

158

pygmented: Whether to apply syntax highlighting

159

escape_html: Whether to escape HTML characters

160

161

Returns:

162

Formatted line string

163

"""

164

165

@property

166

def variable_ranges(self) -> List[RangeInLine]:

167

"""Get ranges for variables in this line."""

168

169

@property

170

def executing_node_ranges(self) -> List[RangeInLine]:

171

"""Get ranges for the executing node in this line."""

172

173

@property

174

def token_ranges(self) -> List[RangeInLine]:

175

"""Get ranges for each token in this line."""

176

```

177

178

**Key Properties:**

179

- `text: str` - Raw source text of the line

180

- `lineno: int` - 1-based line number

181

- `is_current: bool` - Whether this is the currently executing line

182

- `tokens: List[Token]` - Source tokens in this line

183

- `leading_indent: Optional[int]` - Leading spaces to strip

184

185

### Repeated Frame Handling

186

187

Management of repeated stack frames that occur in deep recursion or loops, providing condensed representation.

188

189

```python { .api }

190

class RepeatedFrames:

191

def __init__(self, frames: List[Union[FrameType, TracebackType]],

192

frame_keys: List[Tuple[CodeType, int]]):

193

"""

194

Sequence of repeated stack frames.

195

196

Args:

197

frames: Raw frame objects

198

frame_keys: Extracted frame information

199

"""

200

201

@property

202

def description(self) -> str:

203

"""Brief description of the repeated frames."""

204

```

205

206

### Marker System

207

208

System for inserting markers and annotations into source code lines for highlighting, formatting, and visual enhancement.

209

210

```python { .api }

211

def markers_from_ranges(ranges: Iterable[RangeInLine],

212

converter: Callable[[RangeInLine], Optional[Tuple[str, str]]]) -> List[MarkerInLine]:

213

"""

214

Convert RangeInLine objects to MarkerInLine objects.

215

216

Args:

217

ranges: Iterable of RangeInLine objects defining character ranges

218

converter: Function that converts range to start/end marker strings or None

219

220

Returns:

221

List of MarkerInLine objects for insertion

222

"""

223

224

class RangeInLine(NamedTuple):

225

"""

226

Represents a range of characters within one line of source code.

227

228

Fields:

229

start: Start position in the line

230

end: End position in the line

231

data: Associated data for this range

232

"""

233

start: int

234

end: int

235

data: Any

236

237

class MarkerInLine(NamedTuple):

238

"""

239

A string meant to be inserted at a given position in a line.

240

241

Fields:

242

position: Position in the line to insert the marker

243

is_start: True if this is the opening marker of a pair

244

string: The marker string to insert (ANSI codes, HTML tags, etc.)

245

"""

246

position: int

247

is_start: bool

248

string: str

249

```

250

251

### Syntax Highlighting Integration

252

253

Integration with Pygments for syntax highlighting with custom styles for highlighting executing nodes.

254

255

```python { .api }

256

def style_with_executing_node(style, modifier):

257

"""

258

Create a Pygments style that highlights executing nodes.

259

260

Args:

261

style: Pygments style name or class

262

modifier: CSS-like modifier string for highlighting

263

264

Returns:

265

Modified Pygments style class

266

"""

267

```

268

269

### Blank Line Handling

270

271

Configuration and management of blank lines in source code display.

272

273

```python { .api }

274

class BlankLines(Enum):

275

"""

276

Configuration for blank line display behavior.

277

278

Values:

279

HIDDEN: Blank lines are not shown in output

280

VISIBLE: Blank lines are visible in output

281

SINGLE: Consecutive blank lines shown as single blank line

282

"""

283

HIDDEN = 1

284

VISIBLE = 2

285

SINGLE = 3

286

287

class BlankLineRange:

288

def __init__(self, begin_lineno: int, end_lineno: int):

289

"""

290

Records line number range for blank line gaps.

291

292

Args:

293

begin_lineno: Start line number of blank range

294

end_lineno: End line number of blank range

295

"""

296

297

begin_lineno: int

298

end_lineno: int

299

```

300

301

## Usage Examples

302

303

### Basic Frame Analysis

304

305

```python

306

import inspect

307

from stack_data import FrameInfo, Options

308

309

# Analyze current frame

310

frame = inspect.currentframe()

311

frame_info = FrameInfo(frame)

312

313

# Access frame information

314

print(f"File: {frame_info.filename}")

315

print(f"Line: {frame_info.lineno}")

316

print(f"Variables: {len(frame_info.variables)}")

317

318

# Display source lines with context

319

for line in frame_info.lines:

320

if hasattr(line, 'text'):

321

marker = ">>>" if line.is_current else " "

322

print(f"{marker} {line.lineno}: {line.text}")

323

```

324

325

### Stack Analysis with Options

326

327

```python

328

from stack_data import FrameInfo, Options, BlankLines

329

330

# Configure analysis options

331

options = Options(

332

before=5, # Show 5 pieces before current

333

after=2, # Show 2 pieces after current

334

include_signature=True, # Include function signatures

335

blank_lines=BlankLines.SINGLE # Collapse consecutive blank lines

336

)

337

338

# Analyze entire stack

339

for item in FrameInfo.stack_data(frame, options=options):

340

if isinstance(item, FrameInfo):

341

print(f"\nFrame: {item.filename}:{item.lineno}")

342

for line in item.lines:

343

if hasattr(line, 'text'):

344

print(f" {line.lineno}: {line.text}")

345

```

346

347

### Variable Inspection

348

349

```python

350

from stack_data import FrameInfo

351

352

frame_info = FrameInfo(frame)

353

354

# Inspect variables in frame

355

for var in frame_info.variables:

356

print(f"Variable: {var.name} = {var.value}")

357

358

# Variables in displayed lines only

359

for var in frame_info.variables_in_lines:

360

print(f"Line variable: {var.name} = {var.value}")

361

```

362

363

### Custom Line Rendering

364

365

```python

366

from stack_data import FrameInfo, markers_from_ranges, RangeInLine, MarkerInLine

367

368

frame_info = FrameInfo(frame)

369

370

for line in frame_info.lines:

371

if hasattr(line, 'text'):

372

# Get variable ranges for highlighting

373

var_ranges = line.variable_ranges()

374

375

# Convert to markers

376

markers = markers_from_ranges(

377

var_ranges,

378

lambda r: ("[VAR]", "[/VAR]") if r.data else None

379

)

380

381

# Render with markers

382

rendered = line.render(markers, pygmented=True)

383

print(rendered)

384

```