Pylama
Pylama is a comprehensive code audit tool for Python. It acts as a wrapper, integrating various popular linters and checkers such as pycodestyle, pydocstyle, PyFlakes, Mccabe, Pylint, Radon, Mypy, and Vulture, to provide a unified interface for checking code quality. The current version is 8.4.1, and it receives updates periodically to support newer Python versions and linter functionalities.
Common errors
-
Pylint doesn't exist
cause The Pylint linter, while wrapped by Pylama, is not installed by default and needs to be installed separately or via the `pylama_pylint` module for Pylama to use it.fixInstall Pylint alongside Pylama: `pip install pylama pylint` or `pip install pylama_pylint` if a dedicated integration package is preferred/required. -
Incorrectly sorted imports. [isort]
cause The `isort` linter is available through Pylama but is not enabled by default. If `isort` is installed and you expect Pylama to report on import sorting, it needs to be explicitly configured.fixEnable `isort` in your Pylama configuration file (`pylama.ini`) by adding `linters = isort` or specifying it on the command line: `pylama --linters=isort <path>`. -
mypy output is visible in the "Output tab", but not in the "Problems" tab.
cause This often occurs when using Pylama with IDE extensions (like in VS Code) where the parsing of Pylama's aggregated output for specific linters (like Mypy) is not correctly mapped to the IDE's 'Problems' panel.fixCheck the documentation for your IDE's Python extension for Pylama output parsing configurations. Sometimes, updating the extension or using a specific output format for Pylama (e.g., `--format pep8` or `--format pylint`) might resolve the issue. -
FileNotFoundError: [Errno 2] No such file or directory: 'some/path/file.py'
cause This typically happens when Pylama is configured to check a path that does not exist or is inaccessible in the current environment, often due to incorrect relative paths in configuration files or CI/CD pipelines.fixVerify that all paths specified in Pylama commands or configuration files (`pylama.ini`, `setup.cfg`, etc.) are correct and accessible from where Pylama is being executed. Use absolute paths if there's ambiguity with relative paths.
Warnings
- breaking Pylama dropped support for Python 2.x. It now requires Python 3.7 or newer. Older Python versions need Pylama 7.7.1 or earlier.
- breaking The `--force` option, which allowed Pylama to check non-Python files, was removed. By default, Pylama now only checks Python files.
- gotcha When using the 'mccabe' linter, the argument for complexity was renamed from `complexity` to `max-complexity`.
- gotcha Pylama's integration with Pylint can be sensitive to Pylint's internal changes. Specifically, Pylint 2.8.0 temporarily removed `__pkginfo__.numversion`, causing issues with Pylama. While `numversion` was temporarily re-added in Pylint 2.8.1, ensure compatibility.
Install
-
pip install pylama -
pip install pylama[toml] -
pip install pylama[mypy] -
pip install pylama pylint
Imports
- check_path
from pylama.main import check_path
- parse_options
from pylama.main import parse_options
- Linter
from pylama.lint import Linter
Quickstart
import os
import textwrap
from pylama.main import check_path, parse_options
# Create a dummy Python file to check
file_content = textwrap.dedent('''
import os, sys
def my_function():
x=10 # E225 missing whitespace around operator
if x > 5:
print("Hello")
return "world"
my_function() # W0612 unused variable 'x'
''')
file_path = "./temp_pylama_test.py"
with open(file_path, "w") as f:
f.write(file_content)
# Run pylama programmatically
# Options can be passed as a dictionary
options_dict = {
'linters': ['pycodestyle', 'pyflakes'], # Specify linters to use
'ignore': ['W0611'], # Ignore specific warnings, e.g., unused imports
'select': []
}
# parse_options processes paths and dictionary options into an options object
options = parse_options([file_path], **options_dict)
errors = check_path(options)
if errors:
print(f"Found {len(errors)} issues in {file_path}:")
for error in errors:
print(f" {error.filename}:{error.lnum}:{error.col} [{error.type}] {error.text} [{error.linter}]")
else:
print(f"No issues found in {file_path}.")
# Clean up the dummy file
os.remove(file_path)