-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
239 lines (223 loc) · 9.69 KB
/
pyproject.toml
File metadata and controls
239 lines (223 loc) · 9.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
[tool.poetry]
name = "django-admin-react"
version = "1.13.0"
description = "A drop-in React single-page admin for Django, driven entirely by ModelAdmin."
authors = ["django-admin-react contributors"]
license = "MIT"
readme = "README.md"
homepage = "https://github.com/MartinCastroAlvarez/django-admin-react"
repository = "https://github.com/MartinCastroAlvarez/django-admin-react"
documentation = "https://github.com/MartinCastroAlvarez/django-admin-react#readme"
keywords = ["django", "admin", "react", "spa", "tailwind"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"Framework :: Django :: 5.2",
"Framework :: Django :: 6.0",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP :: Site Management",
"Topic :: Software Development :: Libraries :: Python Modules",
]
packages = [{ include = "django_admin_react" }]
# `format = ["sdist", "wheel"]` is required for the wheel to include
# data files; Poetry's default scope for `include` is sdist-only.
include = [
{ path = "django_admin_react/templates/**/*", format = ["sdist", "wheel"] },
{ path = "django_admin_react/static/**/*", format = ["sdist", "wheel"] },
{ path = "LICENSE", format = ["sdist", "wheel"] },
]
[tool.poetry.dependencies]
python = "^3.10"
# Django 4.2 LTS → 5.2 LTS → 6.x (#622). Bump the upper bound when 7.0
# ships and we've verified the package still passes its test matrix on
# it. The dependent ``django-admin-rest-api`` package also supports 4.2
# (since its 1.1.0).
django = ">=4.2,<7.0"
# The JSON REST API surface (every list / detail / create / update /
# delete / action / history / autocomplete endpoint) lives in this
# sibling package — same `ModelAdmin` source of truth, same permissions,
# no new features. **This repo implements no API of its own**; it is the
# React SPA super-layer over `django-admin-rest-api`. The package's URLs
# are included by `django_admin_react.urls`, and consumers add
# `"django_admin_rest_api"` to `INSTALLED_APPS` alongside this package.
# Floor raised to 1.4.0 in v1.9.0 (#659): the change form consumes the
# `form-spec` endpoint that ships in rest-api 1.4.0 (#59). The SPA degrades
# gracefully on an older backend, but the documented parity needs 1.4.0+.
# Raised to 1.5.0 in v1.10.0: the form-spec `legacy-iframe` fallback now
# covers request-driven custom views (a `change_view` override that renders
# a non-standard template), which the `examples/jobs` fixture exercises.
# Raised to 1.6.0 in v1.11.0 (#664): the form-spec wire now emits
# `prepopulated_fields` and autocomplete hints, which the SPA's widget-kind
# rendering consumes (slugify-on-keystroke + autocomplete widget).
# Raised to 1.7.0 in v1.12.0 (#679): the form-spec endpoint now renders a
# custom `change_form_template` admin SERVER-SIDE and returns
# `renderer: "html-fragment"` (html / csrf_token / submit_url / method /
# messages) plus a POST round-trip route (another html-fragment for
# validation errors, or `{renderer: "redirect", to}`); the SPA injects the
# fragment in-shell. The `legacy-iframe` renderer is gone (no more iframe).
django-admin-rest-api = "^1.7.0"
# `django-admin-mcp-api` — MCP-protocol adapter over the same REST API
# so agents reach the SAME `ModelAdmin`-driven surface. Wire-protocol-only
# layer; adds NO new functionality, permissions, or validation.
# Constraint widened in v1.4.4 (#605) from the original `^0.1.0a0`
# to `>=1.0.0,<2.0.0`; raised again in v1.5.0 (#622) to `>=1.1.0,<2.0.0`
# so a consumer on Django 4.2 actually gets a Django-4.2-compatible MCP
# (the 1.0.x line pins ``django>=5.0``, which would refuse to install
# alongside Django 4.2).
django-admin-mcp-api = ">=1.3.0,<2.0.0"
[tool.poetry.group.dev.dependencies]
# Dependabot #5: pytest's tmpdir handled symlinks unsafely
# (CVE-2025-71176). The advisory's first-patched version is 9.0.3;
# we pin to that minimum so ``poetry lock --update`` cannot resolve
# back to the vulnerable 9.0.0–9.0.2 series even though the lockfile
# is already on 9.0.3. ``pytest 9`` is a clean major bump for our use
# (no pre-9 internals are pinned). ``pytest-django`` and
# ``pytest-cov`` were bumped to releases that declare pytest 9
# compatibility at the same time.
pytest = "^9.0.3"
pytest-django = "^4.8"
pytest-cov = "^5.0"
# Single Python lint stack (#651/#652): Ruff owns lint + format +
# import sorting (the `I` rules), mypy owns typing, bandit owns
# security. Black, standalone isort, and flake8 were removed — their
# pycodestyle/pyflakes/isort coverage is subsumed by Ruff's `E/W/F/I`
# selectors, and running them alongside ruff-format produced the
# three-way formatter conflict tracked in #452.
ruff = "^0.6"
mypy = "^1.10"
django-stubs = { version = "^5.0", extras = ["compatible-mypy"] }
bandit = "^1.7"
pip-audit = "^2.7"
pylint = "^3.2"
pylint-django = "^2.5"
[build-system]
requires = ["poetry-core>=1.6.0"]
build-backend = "poetry.core.masonry.api"
# --------------------------------------------------------------------------- #
# Ruff — lint + format
# --------------------------------------------------------------------------- #
[tool.ruff]
line-length = 100
target-version = "py310"
extend-exclude = ["frontend", "examples/*/migrations", "tests/test_project/migrations"]
[tool.ruff.lint]
select = [
"E", "W", # pycodestyle
"F", # pyflakes
"I", # isort
"B", # bugbear
"S", # bandit-style security
"DJ", # django-specific
"UP", # pyupgrade
"SIM", # simplify
"RET", # returns
"PIE", # misc
]
ignore = [
"S101", # asserts are fine in tests
"DJ001", # nullable charfield warning — opt-in elsewhere
]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101", "S106", "S107"]
"examples/**/*.py" = ["S101", "DJ001"]
[tool.ruff.lint.isort]
# One import per line (repo policy).
force-single-line = true
known-first-party = ["django_admin_react", "tests"]
# --------------------------------------------------------------------------- #
# Pytest
# --------------------------------------------------------------------------- #
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "tests.test_project.settings"
python_files = ["test_*.py", "*_test.py"]
addopts = [
"-ra",
"--strict-markers",
"--strict-config",
"--cov=django_admin_react",
"--cov-report=term-missing",
]
testpaths = ["tests"]
filterwarnings = [
"error",
"ignore::DeprecationWarning:django.*",
]
# --------------------------------------------------------------------------- #
# MyPy — strict subset on the package (#655). Full ``strict = true`` would
# also require typing the test suite (gaps tracked in #318); instead we
# enable the high-value strict flags that the ~740-LOC package already
# satisfies, so typing coverage can't regress. ``scripts/lint.sh`` runs
# ``mypy django_admin_react`` as the blocking gate.
# --------------------------------------------------------------------------- #
[tool.mypy]
python_version = "3.10"
strict = false
disallow_untyped_defs = true
warn_return_any = true
warn_unused_ignores = true
warn_redundant_casts = true
ignore_missing_imports = true
plugins = ["mypy_django_plugin.main"]
[tool.django-stubs]
django_settings_module = "tests.test_project.settings"
# --------------------------------------------------------------------------- #
# pylint — used in `--errors-only` mode for additional checks not in
# ruff. Style + formatting + import order are owned by ruff.
# --------------------------------------------------------------------------- #
[tool.pylint.main]
load-plugins = ["pylint_django"]
django-settings-module = "tests.test_project.settings"
ignore-paths = [
"frontend/.*",
"examples/.*/migrations/.*",
"tests/test_project/migrations/.*",
"dist/.*",
]
[tool.pylint."messages control"]
disable = [
"missing-module-docstring", # docs/agents/decisions.md: docstrings optional
"missing-class-docstring",
"missing-function-docstring",
"too-few-public-methods",
"import-outside-toplevel", # we intentionally do lazy imports
"line-too-long", # ruff owns line length
"fixme",
"duplicate-code",
]
[tool.pylint.format]
max-line-length = 100
# --------------------------------------------------------------------------- #
# Coverage
# --------------------------------------------------------------------------- #
[tool.coverage.run]
branch = true
source = ["django_admin_react"]
omit = ["*/migrations/*", "*/tests/*"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"raise NotImplementedError",
"if TYPE_CHECKING:",
"if __name__ == .__main__.:",
]
# --------------------------------------------------------------------------- #
# Bandit — Python security linter (single source of truth for its scope).
# Read via `bandit -c pyproject.toml ...` (scripts/lint.sh + the pre-commit
# hook). The shipped package is the security-relevant code; tests, the
# frontend, and example apps are excluded — their `assert` use (B101) and
# intentional test-only passwords (B106) are not production risks and would
# otherwise be noise. Runtime code must stay clean: 0 findings is the gate.
# --------------------------------------------------------------------------- #
[tool.bandit]
exclude_dirs = ["tests", "frontend", "examples", ".venv", "node_modules", "build", "dist"]