or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analysis-runner.mdconfiguration.mdexceptions.mdfile-finding.mdformatters.mdindex.mdmessages.mdprofiles.mdtools.md

formatters.mddocs/

0

# Formatters

1

2

Output formatting system supporting multiple formats including JSON, text, XML, and IDE integrations. Formatters convert analysis results into various output formats for different use cases.

3

4

## Capabilities

5

6

### Formatter Base Class

7

8

```python { .api }

9

class Formatter(ABC):

10

def __init__(self, summary: dict[str, Any], messages: list[Message], profile: ProspectorProfile, relative_to: Optional[Path]) -> None

11

```

12

13

Base class for all output formatters.

14

15

**Parameters:**

16

- `summary`: dict[str, Any] - Analysis summary information

17

- `messages`: list[Message] - List of analysis messages

18

- `profile`: ProspectorProfile - Configuration profile used

19

- `relative_to`: Optional[Path] - Base path for relativizing file paths in output

20

21

```python { .api }

22

@abstractmethod

23

def render(self, summary: bool = True, messages: bool = True, profile: bool = False) -> str

24

```

25

26

Renders the analysis results in the formatter's specific format.

27

28

**Parameters:**

29

- `summary`: bool - Whether to include summary information in output

30

- `messages`: bool - Whether to include individual messages in output

31

- `profile`: bool - Whether to include profile information in output

32

33

**Returns:**

34

- `str` - Formatted output string

35

36

### Available Formatters

37

38

```python { .api }

39

FORMATTERS: dict[str, type[Formatter]]

40

```

41

42

Registry of all available output formatters.

43

44

**Available Formatters:**

45

46

#### Text-Based Formatters

47

48

```python { .api }

49

class TextFormatter(Formatter):

50

pass

51

```

52

53

Human-readable text output format. Default formatter that provides clean, readable output for console display.

54

55

```python { .api }

56

class GroupedFormatter(Formatter):

57

pass

58

```

59

60

Groups messages by file and displays them in a hierarchical format. Good for understanding issues per file.

61

62

```python { .api }

63

class EmacsFormatter(Formatter):

64

pass

65

```

66

67

Output format compatible with Emacs compilation mode. Allows Emacs users to jump directly to issue locations.

68

69

#### Machine-Readable Formatters

70

71

```python { .api }

72

class JsonFormatter(Formatter):

73

pass

74

```

75

76

JSON output format for programmatic consumption and API integration. Includes complete message and summary information.

77

78

```python { .api }

79

class YamlFormatter(Formatter):

80

pass

81

```

82

83

YAML output format for human-readable structured data. Alternative to JSON with better readability.

84

85

```python { .api }

86

class XunitFormatter(Formatter):

87

pass

88

```

89

90

XML output in xUnit/JUnit format for CI/CD integration. Compatible with test reporting systems.

91

92

#### IDE and Tool Integration

93

94

```python { .api }

95

class VSCodeFormatter(Formatter):

96

pass

97

```

98

99

Output format optimized for Visual Studio Code integration. Compatible with VS Code problem matcher patterns.

100

101

```python { .api }

102

class GitlabFormatter(Formatter):

103

pass

104

```

105

106

GitLab CI/CD compatible output format for merge request integration and code quality reporting.

107

108

#### Pylint Compatibility

109

110

```python { .api }

111

class PylintFormatter(Formatter):

112

pass

113

```

114

115

Output format that mimics Pylint's default output. Useful for tools expecting Pylint-style output.

116

117

```python { .api }

118

class PylintParseableFormatter(Formatter):

119

pass

120

```

121

122

Pylint-compatible parseable output format. Machine-readable format following Pylint conventions.

123

124

## Usage Examples

125

126

### Using Formatters Directly

127

128

```python

129

from prospector.formatters import FORMATTERS

130

from prospector.config import ProspectorConfig

131

from prospector.run import Prospector

132

133

# Run analysis

134

config = ProspectorConfig()

135

prospector = Prospector(config)

136

prospector.execute()

137

138

# Get results

139

messages = prospector.get_messages()

140

summary = prospector.get_summary()

141

142

# Create formatter

143

formatter_class = FORMATTERS["json"]

144

formatter = formatter_class(summary, messages, config.profile, None)

145

146

# Render output

147

output = formatter.render(summary=True, messages=True, profile=False)

148

print(output)

149

```

150

151

### Multiple Output Formats

152

153

```python

154

from prospector.formatters import FORMATTERS

155

from prospector.config import ProspectorConfig

156

from prospector.run import Prospector

157

158

# Run analysis once

159

config = ProspectorConfig()

160

prospector = Prospector(config)

161

prospector.execute()

162

163

messages = prospector.get_messages()

164

summary = prospector.get_summary()

165

166

# Generate multiple output formats

167

formats_to_generate = ["json", "text", "yaml"]

168

169

for format_name in formats_to_generate:

170

formatter_class = FORMATTERS[format_name]

171

formatter = formatter_class(summary, messages, config.profile, None)

172

173

output = formatter.render()

174

175

# Save to file

176

with open(f"analysis_results.{format_name}", "w") as f:

177

f.write(output)

178

179

print(f"Generated {format_name} output")

180

```

181

182

### Formatter Configuration Examples

183

184

```python

185

from prospector.formatters import FORMATTERS

186

from prospector.config import ProspectorConfig

187

from prospector.run import Prospector

188

from pathlib import Path

189

190

config = ProspectorConfig()

191

prospector = Prospector(config)

192

prospector.execute()

193

194

messages = prospector.get_messages()

195

summary = prospector.get_summary()

196

197

# Text formatter with relative paths

198

base_path = Path("/home/user/project")

199

text_formatter = FORMATTERS["text"](summary, messages, config.profile, base_path)

200

print("=== Text Output (with relative paths) ===")

201

print(text_formatter.render())

202

203

# JSON formatter with full information

204

json_formatter = FORMATTERS["json"](summary, messages, config.profile, None)

205

print("\n=== JSON Output (full info) ===")

206

print(json_formatter.render(summary=True, messages=True, profile=True))

207

208

# Messages only (no summary)

209

text_messages_only = FORMATTERS["text"](summary, messages, config.profile, None)

210

print("\n=== Messages Only ===")

211

print(text_messages_only.render(summary=False, messages=True, profile=False))

212

```

213

214

### CI/CD Integration

215

216

```python

217

from prospector.formatters import FORMATTERS

218

from prospector.config import ProspectorConfig

219

from prospector.run import Prospector

220

import json

221

222

def generate_ci_reports():

223

"""Generate reports for CI/CD pipeline"""

224

config = ProspectorConfig()

225

prospector = Prospector(config)

226

prospector.execute()

227

228

messages = prospector.get_messages()

229

summary = prospector.get_summary()

230

231

# GitLab CI format

232

gitlab_formatter = FORMATTERS["gitlab"](summary, messages, config.profile, None)

233

with open("gitlab-code-quality.json", "w") as f:

234

f.write(gitlab_formatter.render())

235

236

# JUnit XML format for test reporting

237

xunit_formatter = FORMATTERS["xunit"](summary, messages, config.profile, None)

238

with open("prospector-results.xml", "w") as f:

239

f.write(xunit_formatter.render())

240

241

# JSON for further processing

242

json_formatter = FORMATTERS["json"](summary, messages, config.profile, None)

243

with open("prospector-results.json", "w") as f:

244

f.write(json_formatter.render())

245

246

# Summary for build logs

247

print(f"Analysis complete: {len(messages)} issues found")

248

if summary:

249

print(f"Time taken: {summary['time_taken']} seconds")

250

print(f"Tools run: {', '.join(summary['tools'])}")

251

252

generate_ci_reports()

253

```

254

255

### IDE Integration Examples

256

257

```python

258

from prospector.formatters import FORMATTERS

259

from prospector.config import ProspectorConfig

260

from prospector.run import Prospector

261

import subprocess

262

import json

263

264

def vscode_integration():

265

"""Generate VS Code compatible output"""

266

config = ProspectorConfig()

267

prospector = Prospector(config)

268

prospector.execute()

269

270

messages = prospector.get_messages()

271

summary = prospector.get_summary()

272

273

# VS Code format

274

vscode_formatter = FORMATTERS["vscode"](summary, messages, config.profile, None)

275

output = vscode_formatter.render()

276

277

# VS Code can parse this output when configured with appropriate problem matcher

278

print(output)

279

280

def emacs_integration():

281

"""Generate Emacs compilation mode compatible output"""

282

config = ProspectorConfig()

283

prospector = Prospector(config)

284

prospector.execute()

285

286

messages = prospector.get_messages()

287

summary = prospector.get_summary()

288

289

# Emacs format

290

emacs_formatter = FORMATTERS["emacs"](summary, messages, config.profile, None)

291

output = emacs_formatter.render()

292

293

# Emacs can jump to locations when this output is in compilation buffer

294

print(output)

295

296

# Run based on environment

297

import os

298

if os.environ.get("INSIDE_EMACS"):

299

emacs_integration()

300

elif os.environ.get("VSCODE_PID"):

301

vscode_integration()

302

```

303

304

### Custom Output Processing

305

306

```python

307

from prospector.formatters import FORMATTERS

308

from prospector.config import ProspectorConfig

309

from prospector.run import Prospector

310

import json

311

312

def analyze_by_tool():

313

"""Analyze results grouped by tool"""

314

config = ProspectorConfig()

315

prospector = Prospector(config)

316

prospector.execute()

317

318

messages = prospector.get_messages()

319

summary = prospector.get_summary()

320

321

# Get raw JSON data

322

json_formatter = FORMATTERS["json"](summary, messages, config.profile, None)

323

json_output = json_formatter.render()

324

data = json.loads(json_output)

325

326

# Group messages by tool

327

by_tool = {}

328

for message in data.get("messages", []):

329

tool = message["source"]

330

if tool not in by_tool:

331

by_tool[tool] = []

332

by_tool[tool].append(message)

333

334

# Report by tool

335

print("Issues by tool:")

336

for tool, tool_messages in by_tool.items():

337

print(f" {tool}: {len(tool_messages)} issues")

338

339

# Show most common issue types

340

codes = [msg["code"] for msg in tool_messages]

341

from collections import Counter

342

common_codes = Counter(codes).most_common(3)

343

for code, count in common_codes:

344

print(f" {code}: {count} occurrences")

345

346

analyze_by_tool()

347

```

348

349

### Custom Formatting

350

351

```python

352

from prospector.formatters.base import Formatter

353

from prospector.message import Message

354

from prospector.profiles.profile import ProspectorProfile

355

from pathlib import Path

356

from typing import Any, Optional

357

358

class CustomFormatter(Formatter):

359

"""Example custom formatter"""

360

361

def render(self, summary: bool = True, messages: bool = True, profile: bool = False) -> str:

362

output_lines = []

363

364

if summary and self.summary:

365

output_lines.append("=== ANALYSIS SUMMARY ===")

366

output_lines.append(f"Messages: {self.summary.get('message_count', 0)}")

367

output_lines.append(f"Time: {self.summary.get('time_taken', 'unknown')}")

368

output_lines.append("")

369

370

if messages:

371

output_lines.append("=== ISSUES ===")

372

for message in self.messages:

373

location = message.location

374

if location.path:

375

file_path = location.path

376

if self.relative_to:

377

try:

378

file_path = location.path.relative_to(self.relative_to)

379

except ValueError:

380

pass

381

382

line_info = f":{location.line}" if location.line else ""

383

output_lines.append(f"{file_path}{line_info} [{message.source}] {message.message}")

384

385

return "\n".join(output_lines)

386

387

# Usage

388

config = ProspectorConfig()

389

prospector = Prospector(config)

390

prospector.execute()

391

392

custom_formatter = CustomFormatter(

393

prospector.get_summary(),

394

prospector.get_messages(),

395

config.profile,

396

Path(".")

397

)

398

399

print(custom_formatter.render())

400

```