Loading...
Automatically runs pylint on Python files after editing to enforce code quality standards
{
"hookConfig": {
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/python-linter-integration.sh",
"matchers": [
"write",
"edit"
]
}
}
},
"scriptContent": "#!/bin/bash\n\n# Read the tool input from stdin\nINPUT=$(cat)\nTOOL_NAME=$(echo \"$INPUT\" | jq -r '.tool_name')\nFILE_PATH=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path // \"\"')\n\nif [ -z \"$FILE_PATH\" ]; then\n exit 0\nfi\n\n# Check if this is a Python file\nif [[ \"$FILE_PATH\" == *.py ]]; then\n echo \"đ Python Linter Integration - Analyzing code quality...\"\n echo \"đ File: $FILE_PATH\"\n \n # Check if file exists\n if [ ! -f \"$FILE_PATH\" ]; then\n echo \"â ī¸ File not found: $FILE_PATH\"\n exit 1\n fi\n \n # Check if pylint is available\n if command -v pylint >/dev/null 2>&1; then\n echo \"đ Running pylint analysis...\"\n \n # Run pylint with custom formatting\n PYLINT_OUTPUT=$(pylint \"$FILE_PATH\" --score=yes --reports=no --msg-template=\"{line:3d},{column:2d}: {category}: {msg} ({symbol})\" 2>/dev/null)\n PYLINT_EXIT_CODE=$?\n \n if [ $PYLINT_EXIT_CODE -eq 0 ]; then\n echo \"â
Pylint analysis passed - No issues found\"\n else\n echo \"đ Pylint Analysis Results:\"\n echo \"$PYLINT_OUTPUT\" | head -20 # Limit output to first 20 lines\n \n # Show summary if there are many issues\n ISSUE_COUNT=$(echo \"$PYLINT_OUTPUT\" | wc -l)\n if [ \"$ISSUE_COUNT\" -gt 20 ]; then\n echo \"... and $((ISSUE_COUNT - 20)) more issues\"\n fi\n \n # Extract score if available\n SCORE=$(echo \"$PYLINT_OUTPUT\" | grep \"Your code has been rated\" | grep -o '[0-9]\\+\\.[0-9]\\+' | head -1)\n if [ -n \"$SCORE\" ]; then\n echo \"đ Code Quality Score: $SCORE/10\"\n fi\n fi\n \n elif command -v flake8 >/dev/null 2>&1; then\n echo \"đ Running flake8 analysis (fallback)...\"\n \n if flake8 \"$FILE_PATH\" --max-line-length=88; then\n echo \"â
Flake8 analysis passed - No style issues found\"\n else\n echo \"â ī¸ Flake8 found style issues (non-blocking)\"\n fi\n \n elif command -v pycodestyle >/dev/null 2>&1; then\n echo \"đ Running pycodestyle analysis (fallback)...\"\n \n if pycodestyle \"$FILE_PATH\" --max-line-length=88; then\n echo \"â
Pycodestyle analysis passed - No style issues found\"\n else\n echo \"â ī¸ Pycodestyle found style issues (non-blocking)\"\n fi\n \n else\n echo \"â ī¸ No Python linters found\"\n echo \"đĄ Install options:\"\n echo \" âĸ pip install pylint (recommended)\"\n echo \" âĸ pip install flake8 (lightweight)\"\n echo \" âĸ pip install pycodestyle (basic)\"\n fi\n \n # Additional code quality checks\n echo \"\"\n echo \"đ Quick Code Analysis:\"\n \n # Count lines of code (excluding comments and empty lines)\n LOC=$(grep -v '^[[:space:]]*#' \"$FILE_PATH\" | grep -v '^[[:space:]]*$' | wc -l)\n echo \" âĸ Lines of Code: $LOC\"\n \n # Check for potential issues\n if grep -q \"print(\" \"$FILE_PATH\"; then\n echo \" âĸ đĄ Consider using logging instead of print statements\"\n fi\n \n if grep -q \"TODO\\|FIXME\\|XXX\" \"$FILE_PATH\"; then\n echo \" âĸ đ TODOs/FIXMEs found - consider addressing them\"\n fi\n \n # Check function complexity (rough estimate)\n FUNCTION_COUNT=$(grep -c \"^def \" \"$FILE_PATH\")\n if [ \"$FUNCTION_COUNT\" -gt 0 ]; then\n AVG_LINES_PER_FUNC=$((LOC / FUNCTION_COUNT))\n echo \" âĸ Functions: $FUNCTION_COUNT (avg ~$AVG_LINES_PER_FUNC lines each)\"\n \n if [ \"$AVG_LINES_PER_FUNC\" -gt 20 ]; then\n echo \" âĸ đĄ Consider breaking down large functions\"\n fi\n fi\n \n echo \"\"\n echo \"đĄ Python Code Quality Tips:\"\n echo \" âĸ Follow PEP 8 style guidelines\"\n echo \" âĸ Use meaningful variable and function names\"\n echo \" âĸ Add docstrings to functions and classes\"\n echo \" âĸ Keep functions small and focused\"\n echo \" âĸ Use type hints for better code clarity\"\n \n echo \"\"\n echo \"đ¯ Code quality analysis complete!\"\n \nelse\n echo \"âšī¸ File is not a Python file: $FILE_PATH\"\nfi\n\nexit 0"
}.claude/hooks/~/.claude/hooks/{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/python-linter-integration.sh",
"matchers": [
"write",
"edit"
]
}
}
}#!/bin/bash
# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# Check if this is a Python file
if [[ "$FILE_PATH" == *.py ]]; then
echo "đ Python Linter Integration - Analyzing code quality..."
echo "đ File: $FILE_PATH"
# Check if file exists
if [ ! -f "$FILE_PATH" ]; then
echo "â ī¸ File not found: $FILE_PATH"
exit 1
fi
# Check if pylint is available
if command -v pylint >/dev/null 2>&1; then
echo "đ Running pylint analysis..."
# Run pylint with custom formatting
PYLINT_OUTPUT=$(pylint "$FILE_PATH" --score=yes --reports=no --msg-template="{line:3d},{column:2d}: {category}: {msg} ({symbol})" 2>/dev/null)
PYLINT_EXIT_CODE=$?
if [ $PYLINT_EXIT_CODE -eq 0 ]; then
echo "â
Pylint analysis passed - No issues found"
else
echo "đ Pylint Analysis Results:"
echo "$PYLINT_OUTPUT" | head -20 # Limit output to first 20 lines
# Show summary if there are many issues
ISSUE_COUNT=$(echo "$PYLINT_OUTPUT" | wc -l)
if [ "$ISSUE_COUNT" -gt 20 ]; then
echo "... and $((ISSUE_COUNT - 20)) more issues"
fi
# Extract score if available
SCORE=$(echo "$PYLINT_OUTPUT" | grep "Your code has been rated" | grep -o '[0-9]\+\.[0-9]\+' | head -1)
if [ -n "$SCORE" ]; then
echo "đ Code Quality Score: $SCORE/10"
fi
fi
elif command -v flake8 >/dev/null 2>&1; then
echo "đ Running flake8 analysis (fallback)..."
if flake8 "$FILE_PATH" --max-line-length=88; then
echo "â
Flake8 analysis passed - No style issues found"
else
echo "â ī¸ Flake8 found style issues (non-blocking)"
fi
elif command -v pycodestyle >/dev/null 2>&1; then
echo "đ Running pycodestyle analysis (fallback)..."
if pycodestyle "$FILE_PATH" --max-line-length=88; then
echo "â
Pycodestyle analysis passed - No style issues found"
else
echo "â ī¸ Pycodestyle found style issues (non-blocking)"
fi
else
echo "â ī¸ No Python linters found"
echo "đĄ Install options:"
echo " âĸ pip install pylint (recommended)"
echo " âĸ pip install flake8 (lightweight)"
echo " âĸ pip install pycodestyle (basic)"
fi
# Additional code quality checks
echo ""
echo "đ Quick Code Analysis:"
# Count lines of code (excluding comments and empty lines)
LOC=$(grep -v '^[[:space:]]*#' "$FILE_PATH" | grep -v '^[[:space:]]*$' | wc -l)
echo " âĸ Lines of Code: $LOC"
# Check for potential issues
if grep -q "print(" "$FILE_PATH"; then
echo " âĸ đĄ Consider using logging instead of print statements"
fi
if grep -q "TODO\|FIXME\|XXX" "$FILE_PATH"; then
echo " âĸ đ TODOs/FIXMEs found - consider addressing them"
fi
# Check function complexity (rough estimate)
FUNCTION_COUNT=$(grep -c "^def " "$FILE_PATH")
if [ "$FUNCTION_COUNT" -gt 0 ]; then
AVG_LINES_PER_FUNC=$((LOC / FUNCTION_COUNT))
echo " âĸ Functions: $FUNCTION_COUNT (avg ~$AVG_LINES_PER_FUNC lines each)"
if [ "$AVG_LINES_PER_FUNC" -gt 20 ]; then
echo " âĸ đĄ Consider breaking down large functions"
fi
fi
echo ""
echo "đĄ Python Code Quality Tips:"
echo " âĸ Follow PEP 8 style guidelines"
echo " âĸ Use meaningful variable and function names"
echo " âĸ Add docstrings to functions and classes"
echo " âĸ Keep functions small and focused"
echo " âĸ Use type hints for better code clarity"
echo ""
echo "đ¯ Code quality analysis complete!"
else
echo "âšī¸ File is not a Python file: $FILE_PATH"
fi
exit 0Hook reports no linters found despite installation
Ensure linters are in your PATH. Use 'which pylint' or 'which flake8' to verify. Install globally with 'pip install pylint' or activate your virtual environment before running hooks.
Pylint output is truncated showing only first 20 lines
This is intentional to prevent overwhelming output. For full analysis, run 'pylint <file>' directly. The hook shows summary statistics including total issue count and quality score.
Hook shows warnings but doesn't block file operations
This is by design - linting runs post-modification as feedback. To block writes, move the hook to preToolUse and add 'exit 1' for failing scores. Consider your workflow before enforcing strict blocks.
False positives or style conflicts with project standards
Create a .pylintrc or .flake8 config file in your project root to customize rules. Use '--disable=<rule>' for specific suppressions. The hook respects project-level configuration files.
Virtual environment packages cause import errors in pylint
Ensure the hook runs in the same environment where Python packages are installed. Set 'export VIRTUAL_ENV=/path/to/venv' or activate venv before Claude Code session starts.
Loading reviews...
Join our community of Claude power users. No spam, unsubscribe anytime.
Automated accessibility testing and compliance checking for web applications following WCAG guidelines
Automatically generates or updates API documentation when endpoint files are modified
Automatically formats code files after Claude writes or edits them using Prettier, Black, or other formatters