Fixit: Advanced Python Linting Framework with Autofixes
Fixit is an advanced Python linting framework developed by Meta, providing robust auto-fixing capabilities and hierarchical configuration. Built on LibCST, it allows for precise code modifications and makes it straightforward to write custom, in-repo lint rules. Fixit includes a wide array of built-in lint rules, optimizing for efficiency and ease of customization. The current version is 2.2.1, and it undergoes active development with a consistent release cadence.
Common errors
-
KeyError: 'rules' or similar when running fixit with custom rules after upgrade.
cause The configuration format for Fixit 2.x changed from YAML to TOML, and the way rules are enabled/disabled also changed. Older configuration files are no longer valid.fixMigrate your `.fixit.config.yaml` to `pyproject.toml` or `fixit.toml`. Rules are now enabled using `enable = ["mypackage.rules:CustomLintRule", "another_package.rules"]` in the `[tool.fixit]` section. -
AttributeError: 'module' object has no attribute 'LegacyRule' or 'BaseLintRule'
cause The base class for custom lint rules and other core API types were renamed or refactored in Fixit 2.x for conciseness.fixUpdate your custom lint rule definitions. The primary base class for new rules is now `fixit.LintRule`. Review the 'Upgrading' guide and API reference for specific class name changes. -
SyntaxError: invalid syntax (on newer Python features) or similar parsing errors.
cause Fixit relies on LibCST for parsing. If your Python environment's LibCST version is outdated, it might not support the latest Python syntax features.fixEnsure both `fixit` and `libcst` are updated to their latest versions compatible with your Python interpreter (`pip install --upgrade fixit libcst`). Fixit requires Python >=3.9.
Warnings
- breaking Fixit 2.0 (and newer) introduced a foundational rewrite from Fixit 1.x. Configuration files changed from YAML to TOML (e.g., `pyproject.toml` or `fixit.toml`), rule referencing syntax was updated, and the internal API for custom rules changed significantly.
- breaking Flake8-style suppression comments (`# noqa`) are no longer supported in Fixit 2.x. They have been replaced by `# lint-ignore` or `# lint-fixme` directives.
- gotcha Fixit's autofix functionality might not work as expected when integrated with external formatters like 'Black' if Black makes no changes to the file. This can lead to a state where `fixit fix` reports no changes, even if lint issues are present that Fixit *could* fix.
- gotcha When using `fixit_file()` or similar functions with `parallel=True` (for multiprocessing), Fixit currently does not support applying individual fixes interactively. Automated autofix (`autofix=True`) will still apply changes, but interactive selection is disabled.
- gotcha While Fixit offers per-file multiprocessing for performance, it may still be slow on very large codebases without caching or further optimizations.
Install
-
pip install fixit
Imports
- LintRule
from fixit import LintRule
- InvalidTestCase
from fixit import InvalidTestCase
- ValidTestCase
from fixit import ValidTestCase
- Configuration
from fixit.configuration import Configuration
from fixit.ftypes import Configuration
Quickstart
import os
import subprocess
# Create a dummy Python file
with open('my_module.py', 'w') as f:
f.write('x = 1\n')
f.write('def foo():\n')
f.write(' return 1 + 2 # Bad spacing\n')
f.write('class MyClass(object): # Inheriting from object is redundant in Python 3\n')
f.write(' pass\n')
# Run fixit lint to see issues
print('--- Running fixit lint ---')
subprocess.run(['fixit', 'lint', 'my_module.py'])
# Run fixit fix to apply autofixes
print('\n--- Running fixit fix ---')
subprocess.run(['fixit', 'fix', 'my_module.py'])
# Print the fixed file content
print('\n--- Fixed file content ---')
with open('my_module.py', 'r') as f:
print(f.read())
# Clean up
os.remove('my_module.py')