Prospector is a tool to analyse Python code by aggregating the result of other tools.
—
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.
class Formatter(ABC):
def __init__(self, summary: dict[str, Any], messages: list[Message], profile: ProspectorProfile, relative_to: Optional[Path]) -> NoneBase class for all output formatters.
Parameters:
summary: dict[str, Any] - Analysis summary informationmessages: list[Message] - List of analysis messagesprofile: ProspectorProfile - Configuration profile usedrelative_to: Optional[Path] - Base path for relativizing file paths in output@abstractmethod
def render(self, summary: bool = True, messages: bool = True, profile: bool = False) -> strRenders the analysis results in the formatter's specific format.
Parameters:
summary: bool - Whether to include summary information in outputmessages: bool - Whether to include individual messages in outputprofile: bool - Whether to include profile information in outputReturns:
str - Formatted output stringFORMATTERS: dict[str, type[Formatter]]Registry of all available output formatters.
Available Formatters:
class TextFormatter(Formatter):
passHuman-readable text output format. Default formatter that provides clean, readable output for console display.
class GroupedFormatter(Formatter):
passGroups messages by file and displays them in a hierarchical format. Good for understanding issues per file.
class EmacsFormatter(Formatter):
passOutput format compatible with Emacs compilation mode. Allows Emacs users to jump directly to issue locations.
class JsonFormatter(Formatter):
passJSON output format for programmatic consumption and API integration. Includes complete message and summary information.
class YamlFormatter(Formatter):
passYAML output format for human-readable structured data. Alternative to JSON with better readability.
class XunitFormatter(Formatter):
passXML output in xUnit/JUnit format for CI/CD integration. Compatible with test reporting systems.
class VSCodeFormatter(Formatter):
passOutput format optimized for Visual Studio Code integration. Compatible with VS Code problem matcher patterns.
class GitlabFormatter(Formatter):
passGitLab CI/CD compatible output format for merge request integration and code quality reporting.
class PylintFormatter(Formatter):
passOutput format that mimics Pylint's default output. Useful for tools expecting Pylint-style output.
class PylintParseableFormatter(Formatter):
passPylint-compatible parseable output format. Machine-readable format following Pylint conventions.
from prospector.formatters import FORMATTERS
from prospector.config import ProspectorConfig
from prospector.run import Prospector
# Run analysis
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
# Get results
messages = prospector.get_messages()
summary = prospector.get_summary()
# Create formatter
formatter_class = FORMATTERS["json"]
formatter = formatter_class(summary, messages, config.profile, None)
# Render output
output = formatter.render(summary=True, messages=True, profile=False)
print(output)from prospector.formatters import FORMATTERS
from prospector.config import ProspectorConfig
from prospector.run import Prospector
# Run analysis once
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
messages = prospector.get_messages()
summary = prospector.get_summary()
# Generate multiple output formats
formats_to_generate = ["json", "text", "yaml"]
for format_name in formats_to_generate:
formatter_class = FORMATTERS[format_name]
formatter = formatter_class(summary, messages, config.profile, None)
output = formatter.render()
# Save to file
with open(f"analysis_results.{format_name}", "w") as f:
f.write(output)
print(f"Generated {format_name} output")from prospector.formatters import FORMATTERS
from prospector.config import ProspectorConfig
from prospector.run import Prospector
from pathlib import Path
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
messages = prospector.get_messages()
summary = prospector.get_summary()
# Text formatter with relative paths
base_path = Path("/home/user/project")
text_formatter = FORMATTERS["text"](summary, messages, config.profile, base_path)
print("=== Text Output (with relative paths) ===")
print(text_formatter.render())
# JSON formatter with full information
json_formatter = FORMATTERS["json"](summary, messages, config.profile, None)
print("\n=== JSON Output (full info) ===")
print(json_formatter.render(summary=True, messages=True, profile=True))
# Messages only (no summary)
text_messages_only = FORMATTERS["text"](summary, messages, config.profile, None)
print("\n=== Messages Only ===")
print(text_messages_only.render(summary=False, messages=True, profile=False))from prospector.formatters import FORMATTERS
from prospector.config import ProspectorConfig
from prospector.run import Prospector
import json
def generate_ci_reports():
"""Generate reports for CI/CD pipeline"""
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
messages = prospector.get_messages()
summary = prospector.get_summary()
# GitLab CI format
gitlab_formatter = FORMATTERS["gitlab"](summary, messages, config.profile, None)
with open("gitlab-code-quality.json", "w") as f:
f.write(gitlab_formatter.render())
# JUnit XML format for test reporting
xunit_formatter = FORMATTERS["xunit"](summary, messages, config.profile, None)
with open("prospector-results.xml", "w") as f:
f.write(xunit_formatter.render())
# JSON for further processing
json_formatter = FORMATTERS["json"](summary, messages, config.profile, None)
with open("prospector-results.json", "w") as f:
f.write(json_formatter.render())
# Summary for build logs
print(f"Analysis complete: {len(messages)} issues found")
if summary:
print(f"Time taken: {summary['time_taken']} seconds")
print(f"Tools run: {', '.join(summary['tools'])}")
generate_ci_reports()from prospector.formatters import FORMATTERS
from prospector.config import ProspectorConfig
from prospector.run import Prospector
import subprocess
import json
def vscode_integration():
"""Generate VS Code compatible output"""
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
messages = prospector.get_messages()
summary = prospector.get_summary()
# VS Code format
vscode_formatter = FORMATTERS["vscode"](summary, messages, config.profile, None)
output = vscode_formatter.render()
# VS Code can parse this output when configured with appropriate problem matcher
print(output)
def emacs_integration():
"""Generate Emacs compilation mode compatible output"""
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
messages = prospector.get_messages()
summary = prospector.get_summary()
# Emacs format
emacs_formatter = FORMATTERS["emacs"](summary, messages, config.profile, None)
output = emacs_formatter.render()
# Emacs can jump to locations when this output is in compilation buffer
print(output)
# Run based on environment
import os
if os.environ.get("INSIDE_EMACS"):
emacs_integration()
elif os.environ.get("VSCODE_PID"):
vscode_integration()from prospector.formatters import FORMATTERS
from prospector.config import ProspectorConfig
from prospector.run import Prospector
import json
def analyze_by_tool():
"""Analyze results grouped by tool"""
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
messages = prospector.get_messages()
summary = prospector.get_summary()
# Get raw JSON data
json_formatter = FORMATTERS["json"](summary, messages, config.profile, None)
json_output = json_formatter.render()
data = json.loads(json_output)
# Group messages by tool
by_tool = {}
for message in data.get("messages", []):
tool = message["source"]
if tool not in by_tool:
by_tool[tool] = []
by_tool[tool].append(message)
# Report by tool
print("Issues by tool:")
for tool, tool_messages in by_tool.items():
print(f" {tool}: {len(tool_messages)} issues")
# Show most common issue types
codes = [msg["code"] for msg in tool_messages]
from collections import Counter
common_codes = Counter(codes).most_common(3)
for code, count in common_codes:
print(f" {code}: {count} occurrences")
analyze_by_tool()from prospector.formatters.base import Formatter
from prospector.message import Message
from prospector.profiles.profile import ProspectorProfile
from pathlib import Path
from typing import Any, Optional
class CustomFormatter(Formatter):
"""Example custom formatter"""
def render(self, summary: bool = True, messages: bool = True, profile: bool = False) -> str:
output_lines = []
if summary and self.summary:
output_lines.append("=== ANALYSIS SUMMARY ===")
output_lines.append(f"Messages: {self.summary.get('message_count', 0)}")
output_lines.append(f"Time: {self.summary.get('time_taken', 'unknown')}")
output_lines.append("")
if messages:
output_lines.append("=== ISSUES ===")
for message in self.messages:
location = message.location
if location.path:
file_path = location.path
if self.relative_to:
try:
file_path = location.path.relative_to(self.relative_to)
except ValueError:
pass
line_info = f":{location.line}" if location.line else ""
output_lines.append(f"{file_path}{line_info} [{message.source}] {message.message}")
return "\n".join(output_lines)
# Usage
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
custom_formatter = CustomFormatter(
prospector.get_summary(),
prospector.get_messages(),
config.profile,
Path(".")
)
print(custom_formatter.render())Install with Tessl CLI
npx tessl i tessl/pypi-prospector