Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Линтеры для Python: полный обзор опыта
Линтеры - критичны для качества кода. За 10+ лет использовал разные инструменты. Вот мой текущий stack и рекомендации.
1. Ruff - современный выбор (суперфастный)
Реши использовать Ruff (Rust + Python) вместо всех остальных:
# pyproject.toml
[tool.ruff]
line-length = 100
target-version = "py311"
include = ["*.py", "*.pyi"]
exclude = [".git", "__pycache__", "migrations"]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"B", # flake8-bugbear
"D", # pydocstyle
"C90", # mccabe
"RUF", # Ruff-specific
]
ignore = [
"E501", # line too long (обрабатываем в formatter)
"D100", # Missing module docstring
"D104", # Missing package docstring
]
[tool.ruff.lint.isort]
known-first-party = ["myapp"]
known-django = ["django"]
lines-after-imports = 2
lines-between-types = 1
single-line-exclusions = ["typing"]
[tool.ruff.lint.mccabe]
max-complexity = 10
[tool.ruff.lint.pydocstyle]
convention = "google"
# pyproject.toml - конец
# CLI команды
# ruff check . # Проверить весь код
# ruff check --fix . # Исправить автоматически
# ruff check --select E501 # Проверить только линию длиной
# ruff format . # Форматировать (вместо Black)
Плюсы Ruff:
- Суперфастный (написан на Rust)
- Заменяет 10+ инструментов
- Автофиксы для большинства ошибок
- Отличная документация
- Активно развивается
Минусы:
- Относительно новый (но уже используют гиганты)
2. MyPy - type checking
Обязателен для production кода:
# pyproject.toml
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_calls = true
no_implicit_optional = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
# Per-module настройки
[[tool.mypy.overrides]]
module = "tests.*"
ignore_errors = true
# CLI команды
# mypy myapp/ # Проверить папку
# mypy myapp/file.py # Проверить файл
# mypy --strict . # Максимум строгости
Пример кода:
from typing import Optional, List, Dict
def process_users(users: List[Dict[str, str]]) -> Optional[int]:
"""Обработать пользователей.
Args:
users: Список пользователей
Returns:
Количество обработанных пользователей или None
"""
if not users:
return None
for user in users:
name: str = user["name"] # Type hints
email: str = user["email"]
# Обработка
return len(users)
# Ошибки которые найдёт mypy:
result: int = process_users([]) # Error: Can't assign None to int
process_users("users") # Error: Argument 1 has wrong type
3. Pylint - всеобъемлющий анализатор
Использовал раньше, сейчас на Ruff + MyPy:
# .pylintrc
[MASTER]
max-line-length = 100
limit-inference-results = 100
disable =
C0103, # Invalid name
C0111, # Missing docstring
W0212, # Protected access
R0903, # Too few public methods
[DESIGN]
max-attributes = 7
max-arguments = 6
max-branches = 12
max-locals = 15
max-statements = 50
# CLI
# pylint myapp/
Минусы:
- Медленный
- Много false positives
- Verbose конфиг
4. Flake8 - классический выбор
Эра flake8 прошла, но всё ещё используется:
# setup.cfg
[flake8]
max-line-length = 100
ignore = E203, W503
exclude = .git, __pycache__, migrations
# CLI
# flake8 .
5. Black - форматтер (теперь используем Ruff)
Любимый мной форматтер, но теперь использую ruff format:
# pyproject.toml
[tool.black]
line-length = 100
target-version = ['py311']
include = '\.pyi?$'
# CLI
# black .
# black --check . # Проверить без изменений
6. Isort - сортировка импортов
Теперь встроен в Ruff, но отдельно используется так:
# pyproject.toml
[tool.isort]
profile = "black"
line_length = 100
known_first_party = ["myapp"]
known_django = ["django"]
default_section = "THIRDPARTY"
sections = ["FUTURE", "STDLIB", "THIRDPARTY", "DJANGO", "FIRSTPARTY", "LOCALFOLDER"]
# CLI
# isort .
7. Bandit - проверка безопасности
Для поиска уязвимостей:
# .bandit
[bandit]
exclude_dirs = ["tests", ".venv"]
skips = [B101] # assert_used - ок для тестов
# CLI
# bandit -r myapp/
# bandit -f csv myapp/ > report.csv
Пример проблем:
# Опасно
import pickle
data = pickle.loads(untrusted_data) # Bandit will warn
# Опасно
import subprocess
subprocess.call("rm -rf /" + user_input) # Shell injection
# Опасно
import hashlib
hashlib.md5(password) # Use bcrypt instead!
# Опасно
sql = f"SELECT * FROM users WHERE id = {user_id}" # SQL injection
8. Radon - метрики сложности
Для отслеживания усложнения кода:
# radon commands
# radon cc myapp/ # Cyclomatic complexity
# radon mi myapp/ # Maintainability index
# radon hal myapp/ # Halstead metrics
# radon mi myapp/ -a -nb # A=average, nb=no rank
# Пример:
# radon cc myapp/ -a
# myapp/utils.py
# process_data: B (8) # Too complex!
# format_output: A (2) # Good
9. Pylint и Pyflakes - какой выбрать
| Инструмент | Скорость | Охват | Точность | Конфигурируемость |
|---|---|---|---|---|
| Ruff | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| MyPy | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Pylint | ⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| Flake8 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| Black | N/A | Форматирование | ⭐⭐⭐⭐⭐ | ⭐ |
10. Мой текущий stack (2024)
# requirements-dev.txt
ruff>=0.1.0
mypy>=1.0
bandit>=1.7
pytest>=7.0
pytest-cov>=4.0
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install -r requirements-dev.txt
- name: Ruff check
run: ruff check . && ruff format --check .
- name: MyPy type check
run: mypy .
- name: Bandit security check
run: bandit -r myapp/
- name: Tests with coverage
run: pytest --cov=myapp --cov-report=term --cov-fail-under=85
11. Pre-commit hooks (обязательно!)
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.0.0
hooks:
- id: mypy
args: [--strict]
additional_dependencies: [pydantic]
- repo: https://github.com/PyCQA/bandit
rev: 1.7.4
hooks:
- id: bandit
args: [-r, myapp/]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-yaml
- id: check-json
- id: end-of-file-fixer
- id: trailing-whitespace
# Установка
pre-commit install
pre-commit run --all-files
12. IDE интеграция (PyCharm example)
# PyCharm автоматически интегрируется с:
# - Ruff (Settings > Languages > Python > Linter)
# - MyPy (Settings > Languages > Python > Type Checker)
# - Black (Settings > Languages > Python > Formatter)
# VS Code
# Требует расширений:
# - Ruff
# - Pylance (встроенный mypy)
# - Python
Best Practices
- Используй Ruff вместо 5+ инструментов
- Всегда включай mypy на strict mode
- Настрой pre-commit hooks
- Запускай в CI/CD pipeline
- Не игнорируй ошибки, исправляй их
- Постепенно увеличивай strictness
- Обучай команду стандартам
Линтеры - это инвестиция в будущее проекта. Хороший код сегодня = меньше багов завтра.