Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .djlintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"blank_line_after_tag": "load,extends,include",
"blank_line_before_tag": "load,extends,include",
"close_void_tags": true,
"format_attribute_template_tags": true,
"format_css": true,
"format_js": true,
"ignore": "H006,H030,H031",
"include": "H017,H035",
"indent": 2,
"max_line_length": 120,
"profile": "django",
"preserve_blank_lines": true,
"preserve_leading_space": false,
"use_tabs": false,
"extension": "html"
}
137 changes: 134 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,141 @@
exclude: |
(?x)^(
.*/migrations/.*|
.*/static/.*|
.*/media/.*|
.*/node_modules/.*|
.*/venv/.*|
.*/\.venv/.*|
.*\.min\.(js|css)$|
vulture_allowlist\.py$
)$
repos:
# Basic file 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
- id: check-toml
- id: check-xml
- id: check-case-conflict
- id: check-merge-conflict
- id: check-docstring-first
- id: debug-statements
- id: check-executables-have-shebangs

# Secret detection
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
exclude: |
(?x)^(
.*/migrations/.*|
.*\.lock$|
.*\.min\.(js|css)$|
package-lock\.json$
)$
# Import sorting
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: ["--profile", "django", "--multi-line", "3", "--trailing-comma", "--force-grid-wrap", "0", "--combine-as", "--line-width", "88"]

# Code formatting and linting
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.12.1
hooks:
# Run the linter.
- id: ruff-check
args: [--fix]
# Run the formatter.
exclude: vulture_allowlist\.py$
- id: ruff-format
exclude: vulture_allowlist\.py$

# Type checking
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
additional_dependencies: [django-stubs, types-requests, psycopg2-binary]
args: [--config-file=mypy.ini, --ignore-missing-imports]

# Security analysis
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
additional_dependencies: [pbr]
args: ['-r', '.', '-f', 'json', '--skip', 'B101,B601']
exclude: |
(?x)^(
.*/migrations/.*|
.*/tests/.*|
.*/test_.*\.py$|
.*_test\.py$
)$
# Django-specific checks
- repo: https://github.com/adamchainz/django-upgrade
rev: 1.15.0
hooks:
- id: django-upgrade
args: [--target-version, "5.0"]

Comment on lines +84 to +90
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Confirm Django target before auto-upgrading.
Ensure the project targets Django 5.0; adjust if running 4.x or 5.1+.


🏁 Script executed:

#!/bin/bash
# Grep common dep files for Django version to validate django-upgrade target.
rg -nP '(?i)django[>=<~]*\s*[\d.]+' -g 'requirements*.txt' -g 'Pipfile' -g 'pyproject.toml' -n -C1 || true

Length of output: 215


Set django-upgrade target-version to 5.2
pyproject.toml declares Django>=5.2.3, so update the hook in .pre-commit-config.yaml (lines 84–90) to args: [--target-version, "5.2"].

🤖 Prompt for AI Agents
.pre-commit-config.yaml around lines 84 to 90: the django-upgrade hook is
configured with --target-version "5.0" but pyproject.toml requires
Django>=5.2.3; update the hook args to use --target-version "5.2" so the
pre-commit check matches the declared Django version.

# Template linting for Django
- repo: https://github.com/Riverside-Healthcare/djlint
rev: v1.34.1
hooks:
- id: djlint-reformat-django
- id: djlint-django

# Code complexity and quality
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-comprehensions
- flake8-django
- flake8-pie
- flake8-simplify
args: [--max-complexity=10, --max-line-length=88, --extend-ignore, E203,W503]

# Dead code detection
- repo: https://github.com/jendrikseipp/vulture
rev: v2.10
hooks:
- id: vulture
args: [--min-confidence, '80', --sort-by-size, vulture_allowlist.py]

Comment on lines +111 to +117
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Vulture allowlist not applied due to argument position.
Pre-commit appends filenames after args, so the allowlist won’t be last and will be ignored. Scan the repo and place the allowlist last.

   - repo: https://github.com/jendrikseipp/vulture
     rev: v2.10
     hooks:
       - id: vulture
-        args: [--min-confidence, '80', --sort-by-size, vulture_allowlist.py]
+        pass_filenames: false
+        args: [--min-confidence, '80', --sort-by-size, '.', 'vulture_allowlist.py']
🤖 Prompt for AI Agents
In .pre-commit-config.yaml around lines 111 to 117, the vulture hook's args
place the allowlist before filenames so it's ignored; reorder the args so the
allowlist filename (vulture_allowlist.py) is the final argument in the args
array (after --min-confidence and --sort-by-size) so pre-commit appends
filenames after it and the allowlist is applied.

# README and documentation checks
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
- id: rst-backticks
- id: rst-directive-colons
- id: rst-inline-touching-normal

# Markdown linting (Python-based alternative)
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.17
hooks:
- id: mdformat
additional_dependencies:
- mdformat-gfm
- mdformat-black
args: [--wrap=100]

# Python docstring formatting
- repo: https://github.com/pycqa/pydocstyle
rev: 6.3.0
hooks:
- id: pydocstyle
args: [--convention=google, --add-ignore=D100,D104,D105,D107]
112 changes: 112 additions & 0 deletions .secrets.baseline
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
{
"version": "1.4.0",
"plugins_used": [
{
"name": "ArtifactoryDetector"
},
{
"name": "AWSKeyDetector"
},
{
"name": "AzureStorageKeyDetector"
},
{
"name": "Base64HighEntropyString",
"limit": 4.5
},
{
"name": "BasicAuthDetector"
},
{
"name": "CloudantDetector"
},
{
"name": "DiscordBotTokenDetector"
},
{
"name": "GitHubTokenDetector"
},
{
"name": "HexHighEntropyString",
"limit": 3.0
},
{
"name": "IbmCloudIamDetector"
},
{
"name": "IbmCosHmacDetector"
},
{
"name": "JwtTokenDetector"
},
{
"name": "KeywordDetector",
"keyword_exclude": ""
},
{
"name": "MailchimpDetector"
},
{
"name": "NpmDetector"
},
{
"name": "PrivateKeyDetector"
},
{
"name": "SendGridDetector"
},
{
"name": "SlackDetector"
},
{
"name": "SoftlayerDetector"
},
{
"name": "SquareOAuthDetector"
},
{
"name": "StripeDetector"
},
{
"name": "TwilioKeyDetector"
}
],
"filters_used": [
{
"path": "detect_secrets.filters.allowlist.is_line_allowlisted"
},
{
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
"min_level": 2
},
{
"path": "detect_secrets.filters.heuristic.is_indirect_reference"
},
{
"path": "detect_secrets.filters.heuristic.is_likely_id_string"
},
{
"path": "detect_secrets.filters.heuristic.is_lock_file"
},
{
"path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
},
{
"path": "detect_secrets.filters.heuristic.is_potential_uuid"
},
{
"path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
},
{
"path": "detect_secrets.filters.heuristic.is_sequential_string"
},
{
"path": "detect_secrets.filters.heuristic.is_swagger_file"
},
{
"path": "detect_secrets.filters.heuristic.is_templated_secret"
}
],
"results": {},
"generated_at": "2024-01-01T00:00:00Z"
}
32 changes: 32 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[mypy]
python_version = 3.13
check_untyped_defs = true
disallow_any_generics = true
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
warn_unreachable = true
strict_equality = true
show_error_codes = true

# Django-specific settings
plugins = mypy_django_plugin.main

[mypy.plugins.django-stubs]
django_settings_module = "fables.settings"

# Ignore missing imports for third-party libraries
[mypy-*.migrations.*]
ignore_errors = true

[mypy-manage]
ignore_errors = true

# Third-party libraries without stubs
[mypy-psycopg2.*]
ignore_missing_imports = true
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@ dependencies = [
"psycopg2-binary>=2.9.0",
"ruff>=0.12.0",
]

[tool.ruff]
exclude = [
"vulture_allowlist.py",
"migrations",
".venv",
"venv",
]
Comment on lines +13 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use extend-exclude to preserve Ruff’s defaults.

Setting exclude resets Ruff’s built-in ignores (.git, pycache, node_modules, etc.), which can slow linting and create noise. Prefer extend-exclude so you keep defaults and only add project-specific paths.

-[tool.ruff]
-exclude = [
+[tool.ruff]
+extend-exclude = [
     "vulture_allowlist.py",
     "migrations",
     ".venv",
     "venv",
 ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[tool.ruff]
exclude = [
"vulture_allowlist.py",
"migrations",
".venv",
"venv",
]
[tool.ruff]
extend-exclude = [
"vulture_allowlist.py",
"migrations",
".venv",
"venv",
]
🤖 Prompt for AI Agents
In pyproject.toml around lines 13 to 19, replace the [tool.ruff] exclude = [...]
table with extend-exclude = [...] (keeping the same list entries) so Ruff’s
built-in ignores are preserved; update the key name only and leave the array
contents and formatting intact.

46 changes: 46 additions & 0 deletions vulture_allowlist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Vulture allowlist for Django project
# This file contains code that vulture should not report as dead code

# Django model fields that appear unused but are accessed via ORM
_.objects # Django model manager
_.DoesNotExist # Django model exception
_.MultipleObjectsReturned # Django model exception

# Django admin
_.admin # Django admin module imports

# Django URL patterns
_.urlpatterns # Django URL configuration
_.app_name # Django app namespace

# Django settings
_.DATABASES # Django database configuration
_.INSTALLED_APPS # Django installed applications
_.MIDDLEWARE # Django middleware
_.ROOT_URLCONF # Django root URL configuration
_.TEMPLATES # Django template configuration
_.STATIC_URL # Django static files URL
_.STATIC_ROOT # Django static files root
_.MEDIA_URL # Django media files URL
_.MEDIA_ROOT # Django media files root

# Django management commands
_.handle # Django management command method
_.add_arguments # Django management command method

# Django migrations
_.dependencies # Django migration dependencies
_.operations # Django migration operations

# Django forms
_.clean # Django form validation methods
_.save # Django form save method

# Django views
_.get_context_data # Django class-based view method
_.get_queryset # Django class-based view method
_.get_object # Django class-based view method

# Django tests
_.setUp # Django test setup method
_.tearDown # Django test teardown method