Comprehensive pre-commit hooks for Frappe Framework projects to enforce coding standards, security practices, and best practices automatically.
- π‘οΈ SQL Injection Prevention - Detect and prevent SQL injection vulnerabilities
- π Coding Standards - Enforce Frappe-specific coding conventions and best practices
- π DocType Naming - Validate DocType and field naming conventions
- β‘ Fast Execution - Lightweight checks with minimal dependencies
- π― Customizable - Pick and choose hooks based on your project needs
- Python: 3.8 or higher
- pip: Latest version
- pre-commit: Will be installed automatically
- Git: For version control
If you encounter "Executable python
not found" errors, ensure Python is properly configured:
# Check Python installation
python3 --version
# Create python symlink if needed (Linux/macOS)
sudo ln -s /usr/bin/python3 /usr/bin/python
# Or add alias to your shell profile (~/.bashrc, ~/.zshrc)
echo 'alias python=python3' >> ~/.bashrc
source ~/.bashrc
# 1. Initialize new Frappe app
bench new-app my_custom_app
cd apps/my_custom_app
# 2. Create .pre-commit-config.yaml
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/.pre-commit-config.yaml
# 3. Install and run
pip install pre-commit
pre-commit install
pre-commit run --all-files
# 1. Navigate to your app directory
cd apps/your_app
# 2. Add .pre-commit-config.yaml (see configuration below)
# 3. Install pre-commit
pip install pre-commit
pre-commit install
# 4. Run on existing code
pre-commit run --all-files
Hook ID | Description | Files | Dependencies |
---|---|---|---|
frappe-coding-standards |
General coding standards and best practices | *.py |
None |
frappe-sql-security |
SQL injection and security checks | *.py |
None |
frappe-doctype-naming |
DocType and field naming conventions | *.py , *.js , *.json |
pyyaml |
Create .pre-commit-config.yaml
in your project root:
repos:
# Frappe-specific hooks
- repo: https://github.com/dhwani-ris/frappe-pre-commit
rev: v1.0.0 # Use latest tag
hooks:
- id: frappe-translation-check
- id: frappe-sql-security
- id: frappe-coding-standards
# Code formatting (recommended)
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
hooks:
- id: ruff
args: ["--select=I", "--fix"] # Import sorting
- id: ruff-format # Code formatting
# Additional quality checks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
repos:
# Python formatting and linting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
hooks:
- id: ruff
name: "Ruff import sorter"
args: ["--select=I", "--fix"]
- id: ruff
name: "Ruff linter"
args: ["--extend-ignore=E501"]
- id: ruff-format
name: "Ruff formatter"
# JavaScript/CSS/JSON formatting
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0-alpha.8
hooks:
- id: prettier
files: \.(js|jsx|ts|tsx|css|scss|json|md|yml|yaml)$
exclude: |
(?x)^(
.*\.min\.(js|css)$|
node_modules/.*|
.*/static/.*
)$
# Basic file checks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
exclude: \.(md|rst)$
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-merge-conflict
- id: debug-statements
# Frappe-specific coding standards
- repo: https://github.com/dhwani-ris/frappe-pre-commit
rev: v1.0.0
hooks:
- id: frappe-coding-standards
# Exclude patterns
exclude: |
(?x)^(
.*/migrations/.*|
.*/patches/.*|
.*\.min\.(js|css)$|
node_modules/.*|
__pycache__/.*
)$
# Use only specific hooks you need
repos:
- repo: https://github.com/dhwani-ris/frappe-pre-commit
rev: v1.0.0
hooks:
- id: frappe-sql-security # Only SQL security checks
- id: frappe-translation-check # Only translation checks
Detects:
- SQL injection vulnerabilities using
.format()
or f-strings - String concatenation in SQL queries
- Unencrypted storage of sensitive data (passwords, API keys)
# β Will be flagged
frappe.db.sql("SELECT * FROM tabUser WHERE name = '{}'".format(user_name))
frappe.db.set_value("User", user, "password", plain_password)
# β
Correct approach
frappe.db.sql("SELECT * FROM tabUser WHERE name = %s", user_name)
frappe.db.set_value("User", user, "password", frappe.utils.password.encrypt(plain_password))
Enforces:
- Function length (β€20 lines recommended)
- Proper indentation (tabs, not spaces)
- Naming conventions (snake_case for functions, PascalCase for classes)
- Import organization
- Complexity limits (max nesting depth)
Validates:
- DocType names: Title Case with spaces (
"Sales Order"
) - Field names: snake_case (
"customer_name"
) - Field labels: Title Case (
"Customer Name"
)
# For bench-managed projects
cd frappe-bench/apps/your_app
# Add pre-commit config
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/.pre-commit-config.yaml
# Install globally in bench environment
~/frappe-bench/env/bin/pip install pre-commit
~/frappe-bench/env/bin/pre-commit install
Create .github/workflows/code-quality.yml
:
name: Code Quality
on: [push, pull_request]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install pre-commit
run: pip install pre-commit
- name: Run pre-commit
run: pre-commit run --all-files
Add to .vscode/settings.json
:
{
"python.linting.enabled": true,
"python.linting.flake8Enabled": true,
"python.formatting.provider": "black",
"editor.formatOnSave": true,
"python.sortImports.args": ["--profile", "black"],
"[python]": {
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}
}
# Clone the repository
git clone https://github.com/dhwani-ris/frappe-pre-commit.git
cd frappe-pre-commit
# Create virtual environment
python -m venv dev_env
source dev_env/bin/activate # On Windows: dev_env\Scripts\activate
# Install development dependencies
pip install -r requirements-dev.txt
pip install pre-commit
# Install pre-commit hooks for this repository
pre-commit install
# Test individual scripts
python scripts/check_coding_standards.py test_files/sample.py
python scripts/check_sql_security.py test_files/sample.py
python scripts/check_translations.py test_files/sample.py
# Test all hooks
python test_scripts/test_all_hooks.py
# Test with pre-commit
pre-commit run --all-files
# Create test files with issues
mkdir test_project && cd test_project
# Create Python file with intentional issues
cat > bad_example.py << 'EOF'
import frappe
def very_long_function_that_violates_standards():
frappe.msgprint("Missing translation wrapper")
result = frappe.db.sql("SELECT * FROM tabUser WHERE name = '{}'".format("test"))
return result
EOF
# Test your hooks
cd ../
python scripts/check_translations.py test_project/bad_example.py
python scripts/check_sql_security.py test_project/bad_example.py
# Test with ERPNext
cd path/to/erpnext
git clone https://github.com/dhwani-ris/frappe-pre-commit.git .pre-commit-hooks
cp .pre-commit-hooks/examples/.pre-commit-config.yaml .
pre-commit install
pre-commit run --all-files
# Test with custom app
cd path/to/your_custom_app
# Same process as above
- Fork the repository
- Create feature branch:
git checkout -b feature/new-check
- Add your hook script in
scripts/
- Update
.pre-commit-hooks.yaml
- Add tests in
test_scripts/
- Update documentation
- Submit pull request
# Create new app
cd frappe-bench
bench new-app inventory_management
cd apps/inventory_management
# Add pre-commit
cat > .pre-commit-config.yaml << 'EOF'
repos:
- repo: https://github.com/dhwani-ris/frappe-pre-commit
rev: v1.0.0
hooks:
- id: frappe-quick-check
EOF
# Install and test
pip install pre-commit
pre-commit install
pre-commit run --all-files
# For ERPNext customizations
cd frappe-bench/apps/erpnext
# Use comprehensive config
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/erpnext-config.yaml
pre-commit install
pre-commit run --all-files
# .github/workflows/quality-check.yml
name: Quality Check
on:
pull_request:
branches: [main, develop]
jobs:
code-quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install pre-commit
pip install -r requirements.txt
- name: Run pre-commit
run: pre-commit run --all-files
- name: Comment PR
if: failure()
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'β Code quality checks failed. Please run `pre-commit run --all-files` locally and fix the issues.'
})
Pre-commit hooks not running:
pre-commit uninstall
pre-commit install
pre-commit run --all-files
Python executable not found error:
# Error: Executable `python` not found
# Solution: Create a python symlink or alias
# Option 1: Create symlink (Linux/macOS)
sudo ln -s /usr/bin/python3 /usr/bin/python
# Option 2: Create alias (add to ~/.bashrc or ~/.zshrc)
alias python=python3
# Option 3: Use python3 explicitly in PATH
export PATH="/usr/bin:$PATH"
# Option 4: Install python-is-python3 package (Ubuntu/Debian)
sudo apt install python-is-python3
# After fixing, reinstall pre-commit hooks
pre-commit uninstall
pre-commit install
Hooks failing on large files:
# Skip hooks for specific commit
git commit -m "Large file update" --no-verify
# Or exclude large files in config
# Add to .pre-commit-config.yaml:
exclude: |
(?x)^(
large_files/.*|
.*\.min\.js$
)$
Import errors in scripts:
# Make sure Python can find the scripts
export PYTHONPATH="${PYTHONPATH}:$(pwd)"
Package installation issues:
# If frappe-pre-commit package fails to install automatically
pip install frappe-pre-commit
# Clear pre-commit cache and reinstall
pre-commit clean
pre-commit install
# Cache pre-commit environments
export PRE_COMMIT_HOME=~/.cache/pre-commit
# Run only on changed files
pre-commit run
# Skip slow hooks during development
PRE_COMMIT_SKIP=frappe-all-checks git commit -m "Quick fix"
We welcome contributions!
- Fork the repository
- Clone your fork:
git clone https://github.com/yourusername/frappe-pre-commit.git
- Create branch:
git checkout -b feature/improvement
- Make changes and test thoroughly
- Submit pull request
If you want to contribute to the package development, testing, or publishing, see DEVELOPER.md for detailed instructions on:
- Setting up the development environment
- Testing changes locally
- Publishing updates to PyPI
- Version management
- Troubleshooting
This project is licensed under the MIT License - see the LICENSE file for details.
Maintained by Dhwani RIS
- π Website: dhwaniris.com
- π GitHub: @dhwani-ris
Ready to improve your Frappe code quality? Get started with Frappe-Pre-commit today! π
# Install pre-commit
pip install pre-commit
# Download the pre-commit configuration
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/.pre-commit-config.yaml
# Install the pre-commit hooks (frappe-pre-commit package will be installed automatically)
pre-commit install
# Run all checks
pre-commit run --all-files
Note: If you encounter "Executable
python
not found" errors, see the Python Path Setup section above.