Static analysis tool that detects errors in Python code without importing it.
—
Flexible output formatting system for presenting analysis results to users. The Reporter class can be customized to integrate Pyflakes into different development environments and workflows, supporting various output formats and destinations.
Main class for formatting and outputting Pyflakes analysis results, supporting separate streams for warnings and errors.
class Reporter:
"""Formats the results of pyflakes checks to users."""
def __init__(self, warningStream, errorStream):
"""
Construct a Reporter.
Parameters:
- warningStream: A file-like object where warnings will be written to.
The stream's write method must accept unicode. sys.stdout is a good value.
- errorStream: A file-like object where error output will be written to.
The stream's write method must accept unicode. sys.stderr is a good value.
"""
def unexpectedError(self, filename: str, msg: str):
"""
An unexpected error occurred trying to process filename.
Parameters:
- filename (str): The path to a file that we could not process
- msg (str): A message explaining the problem
"""
def syntaxError(self, filename: str, msg: str, lineno: int, offset: int, text: str):
"""
There was a syntax error in filename.
Parameters:
- filename (str): The path to the file with the syntax error
- msg (str): An explanation of the syntax error
- lineno (int): The line number where the syntax error occurred
- offset (int): The column on which the syntax error occurred, or None
- text (str): The source code containing the syntax error
"""
def flake(self, message):
"""
Pyflakes found something wrong with the code.
Parameters:
- message: A pyflakes.messages.Message instance
"""Usage:
import sys
import pyflakes.api
from pyflakes.reporter import Reporter
# Create custom reporter
reporter = Reporter(sys.stdout, sys.stderr)
# Use with pyflakes API
code = """
import os
print(undefined_var)
"""
warnings = pyflakes.api.check(code, 'test.py', reporter)Convenience function for creating a standard reporter using system stdout and stderr streams.
def _makeDefaultReporter():
"""
Make a reporter that can be used when no reporter is specified.
Returns:
Reporter: A Reporter instance using sys.stdout and sys.stderr
"""Usage:
from pyflakes.reporter import _makeDefaultReporter
import pyflakes.api
# Get default reporter
reporter = _makeDefaultReporter()
# Use with API functions
warnings = pyflakes.api.checkPath('myfile.py', reporter)Reporter that collects results in structured format rather than printing immediately.
import io
from pyflakes.reporter import Reporter
from pyflakes.messages import Message
class StructuredReporter(Reporter):
"""Reporter that collects structured results."""
def __init__(self):
# Use string buffers instead of real streams
super().__init__(io.StringIO(), io.StringIO())
self.messages = []
self.syntax_errors = []
self.unexpected_errors = []
def flake(self, message: Message):
"""Collect flake messages."""
self.messages.append({
'type': type(message).__name__,
'filename': message.filename,
'lineno': message.lineno,
'col': message.col,
'message': str(message)
})
def syntaxError(self, filename: str, msg: str, lineno: int, offset: int, text: str):
"""Collect syntax errors."""
self.syntax_errors.append({
'filename': filename,
'message': msg,
'lineno': lineno,
'offset': offset,
'text': text
})
def unexpectedError(self, filename: str, msg: str):
"""Collect unexpected errors."""
self.unexpected_errors.append({
'filename': filename,
'message': msg
})
def get_results(self):
"""Get all collected results."""
return {
'messages': self.messages,
'syntax_errors': self.syntax_errors,
'unexpected_errors': self.unexpected_errors,
'total_issues': len(self.messages) + len(self.syntax_errors) + len(self.unexpected_errors)
}
# Usage
import pyflakes.api
reporter = StructuredReporter()
code = """
import os
print(undefined_var
""" # Intentional syntax error
pyflakes.api.check(code, 'test.py', reporter)
results = reporter.get_results()
print(f"Found {results['total_issues']} issues:")
for msg in results['messages']:
print(f" {msg['type']}: {msg['message']}")
for err in results['syntax_errors']:
print(f" Syntax Error: {err['message']}")Reporter that formats output as JSON for integration with tools and IDEs.
import json
import sys
from pyflakes.reporter import Reporter
class JSONReporter(Reporter):
"""Reporter that outputs results as JSON."""
def __init__(self, output_stream=None):
self.output_stream = output_stream or sys.stdout
super().__init__(output_stream, sys.stderr)
self.results = []
def flake(self, message):
"""Add flake message to results."""
self.results.append({
'type': 'warning',
'category': type(message).__name__,
'filename': message.filename,
'line': message.lineno,
'column': message.col + 1, # Convert to 1-based
'message': str(message).split(': ', 1)[1] if ': ' in str(message) else str(message)
})
def syntaxError(self, filename: str, msg: str, lineno: int, offset: int, text: str):
"""Add syntax error to results."""
self.results.append({
'type': 'error',
'category': 'SyntaxError',
'filename': filename,
'line': lineno or 1,
'column': offset or 1,
'message': msg
})
def unexpectedError(self, filename: str, msg: str):
"""Add unexpected error to results."""
self.results.append({
'type': 'error',
'category': 'UnexpectedError',
'filename': filename,
'line': 1,
'column': 1,
'message': msg
})
def output_results(self):
"""Output all results as JSON."""
json.dump({
'tool': 'pyflakes',
'version': '3.4.0',
'results': self.results,
'summary': {
'total': len(self.results),
'errors': len([r for r in self.results if r['type'] == 'error']),
'warnings': len([r for r in self.results if r['type'] == 'warning'])
}
}, self.output_stream, indent=2)
# Usage
import pyflakes.api
reporter = JSONReporter()
code = """
import os
import sys
x = undefined_var
"""
pyflakes.api.check(code, 'test.py', reporter)
reporter.output_results()Reporter that adds color coding for different message types in terminal output.
import sys
from pyflakes.reporter import Reporter
class ColoredReporter(Reporter):
"""Reporter with colored terminal output."""
# ANSI color codes
RED = '\033[91m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
GREEN = '\033[92m'
RESET = '\033[0m'
BOLD = '\033[1m'
def __init__(self, use_colors=None):
super().__init__(sys.stdout, sys.stderr)
# Auto-detect color support
self.use_colors = use_colors if use_colors is not None else sys.stdout.isatty()
def _colorize(self, text: str, color: str) -> str:
"""Apply color to text if colors are enabled."""
if self.use_colors:
return f"{color}{text}{self.RESET}"
return text
def flake(self, message):
"""Output colored flake message."""
msg_str = str(message)
# Color code by message type
message_type = type(message).__name__
if 'Undefined' in message_type:
colored_msg = self._colorize(msg_str, self.RED)
elif 'Unused' in message_type:
colored_msg = self._colorize(msg_str, self.YELLOW)
else:
colored_msg = self._colorize(msg_str, self.BLUE)
self._stdout.write(colored_msg + '\n')
def syntaxError(self, filename: str, msg: str, lineno: int, offset: int, text: str):
"""Output colored syntax error."""
error_msg = f"{filename}:{lineno or 1}:{offset or 1}: {msg}"
colored_error = self._colorize(error_msg, self.RED + self.BOLD)
self._stderr.write(colored_error + '\n')
if text is not None:
lines = text.splitlines()
if lines:
line = lines[-1]
self._stderr.write(line + '\n')
if offset is not None and offset > 0:
pointer = ' ' * (offset - 1) + '^'
self._stderr.write(self._colorize(pointer, self.RED) + '\n')
def unexpectedError(self, filename: str, msg: str):
"""Output colored unexpected error."""
error_msg = f"{filename}: {msg}"
colored_error = self._colorize(error_msg, self.RED + self.BOLD)
self._stderr.write(colored_error + '\n')
# Usage
import pyflakes.api
reporter = ColoredReporter()
code = """
import os
unused_var = 1
print(undefined_var)
"""
pyflakes.api.check(code, 'test.py', reporter)Reporter that writes results to files instead of streams.
import os
from pyflakes.reporter import Reporter
class FileReporter(Reporter):
"""Reporter that writes to separate files."""
def __init__(self, base_path: str):
self.base_path = base_path
self.warning_file = open(f"{base_path}.warnings", 'w')
self.error_file = open(f"{base_path}.errors", 'w')
super().__init__(self.warning_file, self.error_file)
self.stats = {'warnings': 0, 'errors': 0}
def flake(self, message):
"""Write flake to warnings file."""
super().flake(message)
self.stats['warnings'] += 1
def syntaxError(self, filename: str, msg: str, lineno: int, offset: int, text: str):
"""Write syntax error to errors file."""
super().syntaxError(filename, msg, lineno, offset, text)
self.stats['errors'] += 1
def unexpectedError(self, filename: str, msg: str):
"""Write unexpected error to errors file."""
super().unexpectedError(filename, msg)
self.stats['errors'] += 1
def close(self):
"""Close files and write summary."""
self.warning_file.close()
self.error_file.close()
# Write summary file
with open(f"{self.base_path}.summary", 'w') as f:
f.write(f"Warnings: {self.stats['warnings']}\n")
f.write(f"Errors: {self.stats['errors']}\n")
f.write(f"Total: {sum(self.stats.values())}\n")
# Usage
import pyflakes.api
reporter = FileReporter('pyflakes_results')
try:
pyflakes.api.checkRecursive(['src/'], reporter)
finally:
reporter.close()
# Results are now in:
# - pyflakes_results.warnings
# - pyflakes_results.errors
# - pyflakes_results.summaryimport pyflakes.api
from pyflakes.reporter import Reporter
import io
class IDEReporter(Reporter):
"""Reporter optimized for IDE integration."""
def __init__(self, callback):
super().__init__(io.StringIO(), io.StringIO())
self.callback = callback # Function to call with each issue
def flake(self, message):
"""Send message to IDE via callback."""
self.callback({
'severity': 'warning',
'message': str(message),
'filename': message.filename,
'line': message.lineno,
'column': message.col,
'source': 'pyflakes'
})
def syntaxError(self, filename: str, msg: str, lineno: int, offset: int, text: str):
"""Send syntax error to IDE."""
self.callback({
'severity': 'error',
'message': msg,
'filename': filename,
'line': lineno or 1,
'column': offset or 1,
'source': 'pyflakes'
})
def ide_callback(issue):
"""Example IDE callback function."""
print(f"IDE: {issue['severity'].upper()} in {issue['filename']}:{issue['line']} - {issue['message']}")
# Usage
reporter = IDEReporter(ide_callback)
pyflakes.api.checkPath('myfile.py', reporter)import pyflakes.api
from pyflakes.reporter import Reporter
import os
import json
from collections import defaultdict
class BatchReporter(Reporter):
"""Reporter for batch processing multiple files."""
def __init__(self):
super().__init__(None, None)
self.file_results = defaultdict(list)
def flake(self, message):
"""Collect message by filename."""
self.file_results[message.filename].append({
'type': 'warning',
'line': message.lineno,
'column': message.col,
'message': str(message),
'category': type(message).__name__
})
def get_summary(self):
"""Get summary across all files."""
total_issues = sum(len(issues) for issues in self.file_results.values())
return {
'total_files': len(self.file_results),
'total_issues': total_issues,
'files_with_issues': list(self.file_results.keys()),
'average_issues_per_file': total_issues / len(self.file_results) if self.file_results else 0
}
def save_report(self, output_file: str):
"""Save complete report to JSON file."""
report = {
'summary': self.get_summary(),
'files': dict(self.file_results)
}
with open(output_file, 'w') as f:
json.dump(report, f, indent=2)
# Usage for batch processing
def batch_check_project(project_path: str, output_file: str):
"""Check entire project and generate report."""
reporter = BatchReporter()
# Find all Python files
python_files = []
for root, dirs, files in os.walk(project_path):
for file in files:
if file.endswith('.py'):
python_files.append(os.path.join(root, file))
# Check each file
for py_file in python_files:
pyflakes.api.checkPath(py_file, reporter)
# Generate report
reporter.save_report(output_file)
# Print summary
summary = reporter.get_summary()
print(f"Checked {summary['total_files']} files")
print(f"Found {summary['total_issues']} total issues")
print(f"Average {summary['average_issues_per_file']:.1f} issues per file")
# batch_check_project('my_project/', 'pyflakes_report.json')Install with Tessl CLI
npx tessl i tessl/pypi-pyflakes