testsAndMisc/meta/lint_python.sh
Krzysztof kuhy Rudnicki 97a722d2b2 Split lint_python.sh: output helpers and the full-mode linters
353 -> 175 + 116 + 96. The print_* helpers, run_tool, check_tool and the
--help text move to lib/lint_output.sh; everything that runs after
--quick would have exited moves to lib/lint_full_tools.sh as
run_full_mode_linters. The output lib is sourced before argument parsing
because --help now calls usage() from it.

Verified on the path that actually contains the change: a full-mode run
diffed byte-identical against a detached worktree at the pre-split
commit, with pylint, flake8 and pycodestyle in the output proving the run
entered the extracted block. The --quick comparison is also identical but
exits before that block, so it alone would have proved little. The
failure path returns 1 on an unformatted file, confirming OVERALL_STATUS
still propagates out of the function.

Two shellcheck findings fixed rather than suppressed: SC2034 on
OVERALL_STATUS (the lib is analysed standalone, so the cross-seam
variables are now declared with a comment), and a pre-existing unquoted
`exit ${OVERALL_STATUS}` that the commit hook's stricter settings
surfaced. lint_python.sh was shfmt-clean before and still is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-16 23:08:02 +02:00

176 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# ==============================================================================
# Python Linting Script - Run ALL linters with aggressive settings
# ==============================================================================
# Usage:
# ./lint_python.sh # Lint all Python files
# ./lint_python.sh --fix # Lint and auto-fix where possible
# ./lint_python.sh <file.py> # Lint specific file
# ./lint_python.sh --quick # Quick lint (ruff + mypy only)
# ./lint_python.sh --report # Generate detailed reports
# ==============================================================================
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
BOLD='\033[1m'
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="${SCRIPT_DIR}"
# Sourced before argument parsing: --help calls usage() from here.
# shellcheck source=./lib/lint_output.sh
source "${SCRIPT_DIR}/lib/lint_output.sh"
PYTHON_PATHS=(
"PYTHON"
"articles"
"poker-modifier-app"
"tests"
)
EXCLUDE_PATHS=(
".venv"
"__pycache__"
".git"
"Bash/ffmpeg-build"
".pytest_cache"
".ruff_cache"
".mypy_cache"
)
# Build exclude pattern for find
EXCLUDE_PATTERN=""
for path in "${EXCLUDE_PATHS[@]}"; do
EXCLUDE_PATTERN="${EXCLUDE_PATTERN} -path '*/${path}/*' -prune -o"
done
# Parse arguments
FIX_MODE=false
QUICK_MODE=false
REPORT_MODE=false
# Kept as BOTH a string and an array on purpose: run_tool() takes a single
# command STRING (it evals it), so the string form has to stay, while the
# handful of direct invocations below need proper argument splitting that
# only an array gives -- an unquoted "${TARGET_FILES}" there would also glob.
TARGET_FILES=""
TARGET_FILES_ARR=()
while [[ $# -gt 0 ]]; do
case $1 in
--fix | -f)
FIX_MODE=true
shift
;;
--quick | -q)
QUICK_MODE=true
shift
;;
--report | -r)
REPORT_MODE=true
shift
;;
--help | -h)
usage "$0"
exit 0
;;
*)
TARGET_FILES="${TARGET_FILES} $1"
TARGET_FILES_ARR+=("$1")
shift
;;
esac
done
# If no target specified, use default paths
if [[ -z "${TARGET_FILES}" ]]; then
TARGET_FILES="${PYTHON_PATHS[*]}"
TARGET_FILES_ARR=("${PYTHON_PATHS[@]}")
fi
# Create reports directory if needed
if [[ "${REPORT_MODE}" == true ]]; then
mkdir -p "${PROJECT_ROOT}/lint-reports"
fi
# Track overall status
OVERALL_STATUS=0
FAILED_TOOLS=()
# ==============================================================================
# Main linting process
# ==============================================================================
print_header "Python Linting Suite - Aggressive Mode"
echo ""
print_info "Target: ${TARGET_FILES}"
print_info "Fix mode: ${FIX_MODE}"
print_info "Quick mode: ${QUICK_MODE}"
print_info "Report mode: ${REPORT_MODE}"
cd "${PROJECT_ROOT}"
# ==============================================================================
# RUFF - Primary linter and formatter
# ==============================================================================
if check_tool ruff; then
if [[ "${FIX_MODE}" == true ]]; then
run_tool "ruff-lint" "ruff check --fix --show-fixes ${TARGET_FILES}" || OVERALL_STATUS=1
run_tool "ruff-format" "ruff format ${TARGET_FILES}" || OVERALL_STATUS=1
else
run_tool "ruff-lint" "ruff check ${TARGET_FILES}" || OVERALL_STATUS=1
run_tool "ruff-format-check" "ruff format --check ${TARGET_FILES}" || OVERALL_STATUS=1
fi
fi
# ==============================================================================
# MYPY - Static type checking
# ==============================================================================
if check_tool mypy; then
run_tool "mypy" "mypy --strict --ignore-missing-imports ${TARGET_FILES}" || OVERALL_STATUS=1
fi
# Quick mode exits here
if [[ "${QUICK_MODE}" == true ]]; then
print_header "Quick Lint Complete"
if [[ ${#FAILED_TOOLS[@]} -gt 0 ]]; then
print_error "Failed tools: ${FAILED_TOOLS[*]}"
exit 1
else
print_success "All quick checks passed!"
exit 0
fi
fi
# shellcheck source=./lib/lint_full_tools.sh
source "${SCRIPT_DIR}/lib/lint_full_tools.sh"
run_full_mode_linters
# ==============================================================================
# Summary
# ==============================================================================
print_header "Linting Summary"
echo ""
if [[ ${OVERALL_STATUS} -ne 0 ]]; then
print_error "The following tools reported issues:"
for tool in "${FAILED_TOOLS[@]}"; do
echo " - ${tool}"
done
echo ""
if [[ "${REPORT_MODE}" == true ]]; then
print_info "Detailed reports saved to: ${PROJECT_ROOT}/lint-reports/"
fi
print_info "Run with --fix to auto-fix issues where possible"
exit "${OVERALL_STATUS}"
else
print_success "All linting checks passed!"
exit 0
fi