django-bananas 2.2__tar.gz → 2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django-bananas-2.2 → django_bananas-2.3}/LICENSE +1 -1
- {django-bananas-2.2 → django_bananas-2.3}/MANIFEST.in +1 -1
- {django-bananas-2.2/src/django_bananas.egg-info → django_bananas-2.3}/PKG-INFO +33 -11
- {django-bananas-2.2 → django_bananas-2.3}/README.rst +6 -6
- django_bananas-2.3/pyproject.toml +97 -0
- django_bananas-2.3/setup.cfg +73 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/__init__.py +1 -1
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/mixins.py +2 -2
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/schemas/base.py +1 -1
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/schemas/yasg.py +2 -1
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/v1_0/urls.py +2 -2
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/versioning.py +2 -3
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/views.py +9 -11
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/extension.py +17 -15
- {django-bananas-2.2/src/bananas/admin/api → django_bananas-2.3/src/bananas/admin}/i18n.py +0 -1
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/drf/fencing.py +13 -8
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/drf/utils.py +4 -4
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/environment.py +9 -12
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/management/commands/show_urls.py +2 -2
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/management/commands/syncpermissions.py +0 -1
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/models.py +5 -9
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/secrets.py +2 -2
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/url.py +5 -7
- {django-bananas-2.2 → django_bananas-2.3/src/django_bananas.egg-info}/PKG-INFO +33 -11
- {django-bananas-2.2 → django_bananas-2.3}/src/django_bananas.egg-info/SOURCES.txt +1 -1
- {django-bananas-2.2 → django_bananas-2.3}/src/django_bananas.egg-info/requires.txt +5 -3
- django-bananas-2.2/pyproject.toml +0 -3
- django-bananas-2.2/setup.cfg +0 -132
- {django-bananas-2.2 → django_bananas-2.3}/AUTHORS +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/setup.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/__init__.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/__init__.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/permissions.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/router.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/schemas/__init__.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/schemas/decorators.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/serializers.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/urls.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/admin/api/v1_0/__init__.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/drf/__init__.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/drf/errors.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/lazy.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/management/__init__.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/management/commands/__init__.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/py.typed +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/query.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/settings.py +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/static/admin/bananas/css/bananas.css +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/static/admin/bananas/css/banansive.css +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/static/admin/bananas/img/django.svg +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/static/admin/bananas/img/search.svg +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/static/admin/bananas/js/bananas.js +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/static/admin/css/responsive.css +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/templates/admin/base_site.html +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/bananas/templates/admin/view.html +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/django_bananas.egg-info/dependency_links.txt +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/django_bananas.egg-info/not-zip-safe +0 -0
- {django-bananas-2.2 → django_bananas-2.3}/src/django_bananas.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
include setup.py README.rst MANIFEST.in LICENSE AUTHORS
|
|
2
|
-
exclude
|
|
2
|
+
exclude tox.ini *.yml *.yaml Makefile Dockerfile .editorconfig
|
|
3
3
|
|
|
4
4
|
recursive-include src/bananas/templates *
|
|
5
5
|
recursive-include src/bananas/static *
|
|
@@ -1,27 +1,49 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: django-bananas
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3
|
|
4
4
|
Summary: Django Bananas - Django extensions the monkey way
|
|
5
5
|
Home-page: https://github.com/5monkeys/django-bananas
|
|
6
6
|
License: MIT License
|
|
7
7
|
Classifier: Development Status :: 5 - Production/Stable
|
|
8
8
|
Classifier: Programming Language :: Python
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
12
10
|
Classifier: Programming Language :: Python :: 3.8
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Framework :: Django
|
|
17
|
+
Classifier: Framework :: Django :: 3.2
|
|
18
|
+
Classifier: Framework :: Django :: 4.0
|
|
19
|
+
Classifier: Framework :: Django :: 4.1
|
|
20
|
+
Classifier: Framework :: Django :: 4.2
|
|
21
|
+
Classifier: Framework :: Django :: 5.0
|
|
22
|
+
Classifier: Framework :: Django :: 5.1
|
|
15
23
|
Classifier: Intended Audience :: Developers
|
|
16
24
|
Classifier: License :: OSI Approved :: MIT License
|
|
17
25
|
Classifier: Operating System :: OS Independent
|
|
18
26
|
Classifier: Framework :: Django
|
|
19
27
|
Requires-Python: >=3.6
|
|
20
28
|
Description-Content-Type: text/x-rst; charset=UTF-8
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: Django>=2.2
|
|
31
|
+
Requires-Dist: typing-extensions>=3.7.4.3
|
|
21
32
|
Provides-Extra: drf
|
|
33
|
+
Requires-Dist: djangorestframework>=3.10; extra == "drf"
|
|
34
|
+
Requires-Dist: drf-yasg>=1.20.0; extra == "drf"
|
|
22
35
|
Provides-Extra: test
|
|
36
|
+
Requires-Dist: tox; extra == "test"
|
|
37
|
+
Requires-Dist: coverage[toml]; extra == "test"
|
|
23
38
|
Provides-Extra: dev
|
|
24
|
-
|
|
39
|
+
Requires-Dist: mypy; extra == "dev"
|
|
40
|
+
Requires-Dist: types-setuptools; extra == "dev"
|
|
41
|
+
Requires-Dist: django-stubs; extra == "dev"
|
|
42
|
+
Requires-Dist: djangorestframework-stubs; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest; extra == "dev"
|
|
44
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-django; extra == "dev"
|
|
46
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
25
47
|
|
|
26
48
|
================================================================================
|
|
27
49
|
:banana: Django Bananas - Django extensions the monkey way
|
|
@@ -57,10 +79,12 @@ with the ``drf`` extra to keep those in sync:
|
|
|
57
79
|
|
|
58
80
|
Currently tested only for
|
|
59
81
|
|
|
60
|
-
- Django 3.2 under Python 3.
|
|
82
|
+
- Django 3.2 under Python 3.8-3.10
|
|
61
83
|
- Django 4.0 under Python 3.8-3.10
|
|
62
|
-
- Django 4.1 under Python 3.8-3.
|
|
63
|
-
- Django 4.2 under Python 3.8-3.
|
|
84
|
+
- Django 4.1 under Python 3.8-3.13
|
|
85
|
+
- Django 4.2 under Python 3.8-3.13
|
|
86
|
+
- Django 5.0 under Python 3.10-3.13
|
|
87
|
+
- Django 5.1 under Python 3.10-3.13
|
|
64
88
|
|
|
65
89
|
Pull requests welcome!
|
|
66
90
|
|
|
@@ -263,7 +287,6 @@ feature requires installation with the ``drf`` extra.
|
|
|
263
287
|
|
|
264
288
|
|
|
265
289
|
class CustomAdminAPI(BananasAdminAPI):
|
|
266
|
-
|
|
267
290
|
name = lazy_title(_("custom"))
|
|
268
291
|
|
|
269
292
|
@schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
|
|
@@ -272,7 +295,6 @@ feature requires installation with the ``drf`` extra.
|
|
|
272
295
|
|
|
273
296
|
|
|
274
297
|
class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
|
|
275
|
-
|
|
276
298
|
serializer_class = SomeModelSerializer
|
|
277
299
|
|
|
278
300
|
def list(self, request):
|
|
@@ -581,4 +603,4 @@ and select specific tests with the ``test`` argument to ``make test``:
|
|
|
581
603
|
|
|
582
604
|
.. code-block:: bash
|
|
583
605
|
|
|
584
|
-
make test test='
|
|
606
|
+
make test test='-k test_logout'
|
|
@@ -32,10 +32,12 @@ with the ``drf`` extra to keep those in sync:
|
|
|
32
32
|
|
|
33
33
|
Currently tested only for
|
|
34
34
|
|
|
35
|
-
- Django 3.2 under Python 3.
|
|
35
|
+
- Django 3.2 under Python 3.8-3.10
|
|
36
36
|
- Django 4.0 under Python 3.8-3.10
|
|
37
|
-
- Django 4.1 under Python 3.8-3.
|
|
38
|
-
- Django 4.2 under Python 3.8-3.
|
|
37
|
+
- Django 4.1 under Python 3.8-3.13
|
|
38
|
+
- Django 4.2 under Python 3.8-3.13
|
|
39
|
+
- Django 5.0 under Python 3.10-3.13
|
|
40
|
+
- Django 5.1 under Python 3.10-3.13
|
|
39
41
|
|
|
40
42
|
Pull requests welcome!
|
|
41
43
|
|
|
@@ -238,7 +240,6 @@ feature requires installation with the ``drf`` extra.
|
|
|
238
240
|
|
|
239
241
|
|
|
240
242
|
class CustomAdminAPI(BananasAdminAPI):
|
|
241
|
-
|
|
242
243
|
name = lazy_title(_("custom"))
|
|
243
244
|
|
|
244
245
|
@schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
|
|
@@ -247,7 +248,6 @@ feature requires installation with the ``drf`` extra.
|
|
|
247
248
|
|
|
248
249
|
|
|
249
250
|
class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
|
|
250
|
-
|
|
251
251
|
serializer_class = SomeModelSerializer
|
|
252
252
|
|
|
253
253
|
def list(self, request):
|
|
@@ -556,4 +556,4 @@ and select specific tests with the ``test`` argument to ``make test``:
|
|
|
556
556
|
|
|
557
557
|
.. code-block:: bash
|
|
558
558
|
|
|
559
|
-
make test test='
|
|
559
|
+
make test test='-k test_logout'
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=57.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.black]
|
|
6
|
+
target-version = ["py38", "py39", "py310", "py311", "py312"]
|
|
7
|
+
|
|
8
|
+
[tool.ruff]
|
|
9
|
+
src = ["src"]
|
|
10
|
+
fix = true
|
|
11
|
+
target-version = "py38"
|
|
12
|
+
select = [
|
|
13
|
+
"B",
|
|
14
|
+
"C4",
|
|
15
|
+
"I",
|
|
16
|
+
"RUF",
|
|
17
|
+
"T20",
|
|
18
|
+
"TID",
|
|
19
|
+
"UP",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[tool.ruff.per-file-ignores]
|
|
23
|
+
"tests/**" = ["RUF012"]
|
|
24
|
+
|
|
25
|
+
[tool.ruff.isort]
|
|
26
|
+
known-first-party = ["src/"]
|
|
27
|
+
combine-as-imports = true
|
|
28
|
+
|
|
29
|
+
[tool.pytest.ini_options]
|
|
30
|
+
python_files = "tests.py test_*.py *_tests.py"
|
|
31
|
+
testpaths = ["tests"]
|
|
32
|
+
norecursedirs = "migrations"
|
|
33
|
+
|
|
34
|
+
[tool.coverage.paths]
|
|
35
|
+
source = [
|
|
36
|
+
"src/bananas",
|
|
37
|
+
"*/.tox/*/lib/*/site-packages/bananas"
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[tool.coverage.run]
|
|
41
|
+
branch = true
|
|
42
|
+
source = ["src/", "tests/"]
|
|
43
|
+
|
|
44
|
+
[tool.coverage.report]
|
|
45
|
+
skip_covered = true
|
|
46
|
+
show_missing = true
|
|
47
|
+
fail_under= 94
|
|
48
|
+
exclude_lines = [
|
|
49
|
+
"pragma: no cover",
|
|
50
|
+
"if __name__ == .__main__.:",
|
|
51
|
+
# Ignore non-implementations
|
|
52
|
+
'^\s*\.\.\.',
|
|
53
|
+
"if TYPE_CHECKING:",
|
|
54
|
+
"raise NotImplementedError",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[tool.mypy]
|
|
58
|
+
python_version = "3.8"
|
|
59
|
+
show_error_codes = true
|
|
60
|
+
pretty = true
|
|
61
|
+
files = ["src", "tests", "setup.py"]
|
|
62
|
+
|
|
63
|
+
no_implicit_reexport = true
|
|
64
|
+
no_implicit_optional = true
|
|
65
|
+
strict_equality = true
|
|
66
|
+
strict_optional = true
|
|
67
|
+
check_untyped_defs = true
|
|
68
|
+
disallow_incomplete_defs = true
|
|
69
|
+
disallow_untyped_defs = true
|
|
70
|
+
ignore_missing_imports = false
|
|
71
|
+
|
|
72
|
+
warn_unused_configs = true
|
|
73
|
+
warn_redundant_casts = true
|
|
74
|
+
warn_unused_ignores = true
|
|
75
|
+
warn_return_any = true
|
|
76
|
+
warn_unreachable = true
|
|
77
|
+
|
|
78
|
+
plugins = [
|
|
79
|
+
"mypy_django_plugin.main",
|
|
80
|
+
"mypy_drf_plugin.main",
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
[tool.django-stubs]
|
|
84
|
+
django_settings_module = "tests.conftest"
|
|
85
|
+
|
|
86
|
+
[[tool.mypy.overrides]]
|
|
87
|
+
module = [
|
|
88
|
+
"tests.*",
|
|
89
|
+
]
|
|
90
|
+
disallow_untyped_defs = false
|
|
91
|
+
|
|
92
|
+
[[tool.mypy.overrides]]
|
|
93
|
+
module = [
|
|
94
|
+
"test.support.*",
|
|
95
|
+
"drf_yasg.*",
|
|
96
|
+
]
|
|
97
|
+
ignore_missing_imports = true
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = django-bananas
|
|
3
|
+
description = Django Bananas - Django extensions the monkey way
|
|
4
|
+
long_description = file: README.rst
|
|
5
|
+
long_description_content_type = text/x-rst; charset=UTF-8
|
|
6
|
+
url = https://github.com/5monkeys/django-bananas
|
|
7
|
+
version = attr: bananas.__version__
|
|
8
|
+
classifiers =
|
|
9
|
+
Development Status :: 5 - Production/Stable
|
|
10
|
+
Programming Language :: Python
|
|
11
|
+
Programming Language :: Python :: 3
|
|
12
|
+
Programming Language :: Python :: 3.8
|
|
13
|
+
Programming Language :: Python :: 3.9
|
|
14
|
+
Programming Language :: Python :: 3.10
|
|
15
|
+
Programming Language :: Python :: 3.11
|
|
16
|
+
Programming Language :: Python :: 3.12
|
|
17
|
+
Programming Language :: Python :: 3.13
|
|
18
|
+
Framework :: Django
|
|
19
|
+
Framework :: Django :: 3.2
|
|
20
|
+
Framework :: Django :: 4.0
|
|
21
|
+
Framework :: Django :: 4.1
|
|
22
|
+
Framework :: Django :: 4.2
|
|
23
|
+
Framework :: Django :: 5.0
|
|
24
|
+
Framework :: Django :: 5.1
|
|
25
|
+
Intended Audience :: Developers
|
|
26
|
+
License :: OSI Approved :: MIT License
|
|
27
|
+
Operating System :: OS Independent
|
|
28
|
+
Framework :: Django
|
|
29
|
+
license = MIT License
|
|
30
|
+
license_file = LICENSE
|
|
31
|
+
|
|
32
|
+
[options]
|
|
33
|
+
packages = find:
|
|
34
|
+
package_dir =
|
|
35
|
+
=src
|
|
36
|
+
python_requires = >=3.6
|
|
37
|
+
include_package_data = True
|
|
38
|
+
exclude =
|
|
39
|
+
tests
|
|
40
|
+
_*
|
|
41
|
+
example
|
|
42
|
+
zip_safe = False
|
|
43
|
+
install_requires =
|
|
44
|
+
Django>=2.2
|
|
45
|
+
typing-extensions>=3.7.4.3
|
|
46
|
+
|
|
47
|
+
[options.packages.find]
|
|
48
|
+
where = src
|
|
49
|
+
|
|
50
|
+
[options.extras_require]
|
|
51
|
+
drf =
|
|
52
|
+
djangorestframework>=3.10
|
|
53
|
+
drf-yasg>=1.20.0
|
|
54
|
+
test =
|
|
55
|
+
tox
|
|
56
|
+
coverage[toml]
|
|
57
|
+
dev =
|
|
58
|
+
mypy
|
|
59
|
+
types-setuptools
|
|
60
|
+
django-stubs
|
|
61
|
+
djangorestframework-stubs
|
|
62
|
+
pytest
|
|
63
|
+
pytest-cov
|
|
64
|
+
pytest-django
|
|
65
|
+
pre-commit
|
|
66
|
+
|
|
67
|
+
[options.package_data]
|
|
68
|
+
bananas = py.typed
|
|
69
|
+
|
|
70
|
+
[egg_info]
|
|
71
|
+
tag_build =
|
|
72
|
+
tag_date = 0
|
|
73
|
+
|
|
@@ -63,9 +63,9 @@ class BananasAPI:
|
|
|
63
63
|
if admin is not None:
|
|
64
64
|
meta.update(
|
|
65
65
|
{
|
|
66
|
-
key: getattr(admin, key)
|
|
66
|
+
key: getattr(admin, key)
|
|
67
67
|
for key in filter(
|
|
68
|
-
lambda key: key in meta,
|
|
68
|
+
lambda key: key in meta,
|
|
69
69
|
admin.__dict__.keys(),
|
|
70
70
|
)
|
|
71
71
|
}
|
|
@@ -13,7 +13,8 @@ from rest_framework.request import Request
|
|
|
13
13
|
from rest_framework.routers import SimpleRouter
|
|
14
14
|
from rest_framework.schemas.coreapi import is_custom_action
|
|
15
15
|
|
|
16
|
-
from
|
|
16
|
+
from bananas.admin.api.versioning import BananasVersioning
|
|
17
|
+
|
|
17
18
|
from .base import BananasBaseRouter
|
|
18
19
|
|
|
19
20
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from types import ModuleType
|
|
2
|
-
from typing import Dict, Sequence
|
|
2
|
+
from typing import ClassVar, Dict, Sequence
|
|
3
3
|
|
|
4
4
|
from rest_framework.request import Request
|
|
5
5
|
from rest_framework.versioning import NamespaceVersioning
|
|
@@ -10,12 +10,11 @@ __versions__ = [v1_0]
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class BananasVersioning(NamespaceVersioning):
|
|
13
|
-
|
|
14
13
|
default_version: str = v1_0.__version__
|
|
15
14
|
allowed_versions: Sequence[str] = tuple(
|
|
16
15
|
version.__version__ for version in __versions__
|
|
17
16
|
)
|
|
18
|
-
version_map: Dict[str, ModuleType] = {
|
|
17
|
+
version_map: ClassVar[Dict[str, ModuleType]] = {
|
|
19
18
|
version.__version__: version for version in __versions__
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import ClassVar, List
|
|
2
|
+
|
|
1
3
|
from django.contrib.auth import (
|
|
2
4
|
login as auth_login,
|
|
3
5
|
logout as auth_logout,
|
|
@@ -11,7 +13,8 @@ from rest_framework.permissions import AllowAny
|
|
|
11
13
|
from rest_framework.request import Request
|
|
12
14
|
from rest_framework.response import Response
|
|
13
15
|
|
|
14
|
-
from .i18n import RawTranslationCatalog
|
|
16
|
+
from bananas.admin.i18n import RawTranslationCatalog
|
|
17
|
+
|
|
15
18
|
from .mixins import BananasAPI
|
|
16
19
|
from .permissions import IsAnonymous
|
|
17
20
|
from .schemas import schema
|
|
@@ -29,7 +32,6 @@ class BananasAdminAPI(BananasAPI, viewsets.GenericViewSet):
|
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
class LoginAPI(BananasAdminAPI):
|
|
32
|
-
|
|
33
35
|
name = _("Log in") # type: ignore[assignment]
|
|
34
36
|
basename = "login"
|
|
35
37
|
permission_classes = (IsAnonymous,)
|
|
@@ -51,7 +53,7 @@ class LoginAPI(BananasAdminAPI):
|
|
|
51
53
|
login_form = AuthenticationForm(request, data=request.data)
|
|
52
54
|
|
|
53
55
|
if not login_form.is_valid():
|
|
54
|
-
raise serializers.ValidationError(login_form.errors)
|
|
56
|
+
raise serializers.ValidationError(login_form.errors) # type: ignore[arg-type]
|
|
55
57
|
|
|
56
58
|
auth_login(request, login_form.get_user())
|
|
57
59
|
|
|
@@ -60,7 +62,6 @@ class LoginAPI(BananasAdminAPI):
|
|
|
60
62
|
|
|
61
63
|
|
|
62
64
|
class LogoutAPI(BananasAPI, viewsets.ViewSet):
|
|
63
|
-
|
|
64
65
|
name = _("Log out") # type: ignore[assignment]
|
|
65
66
|
basename = "logout"
|
|
66
67
|
|
|
@@ -77,11 +78,10 @@ class LogoutAPI(BananasAPI, viewsets.ViewSet):
|
|
|
77
78
|
|
|
78
79
|
|
|
79
80
|
class MeAPI(BananasAdminAPI):
|
|
80
|
-
|
|
81
81
|
serializer_class = UserSerializer
|
|
82
82
|
|
|
83
83
|
class Admin:
|
|
84
|
-
exclude_tags = ["navigation"]
|
|
84
|
+
exclude_tags: ClassVar[List[str]] = ["navigation"]
|
|
85
85
|
|
|
86
86
|
@schema(responses={200: UserSerializer})
|
|
87
87
|
def list(self, request: Request) -> Response:
|
|
@@ -93,7 +93,6 @@ class MeAPI(BananasAdminAPI):
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
class ChangePasswordAPI(BananasAdminAPI):
|
|
96
|
-
|
|
97
96
|
name = _("Change password") # type: ignore[assignment]
|
|
98
97
|
basename = "change_password"
|
|
99
98
|
serializer_class = PasswordChangeSerializer # Placeholder for schema
|
|
@@ -112,22 +111,21 @@ class ChangePasswordAPI(BananasAdminAPI):
|
|
|
112
111
|
password_form = PasswordChangeForm(request.user, data=request.data)
|
|
113
112
|
|
|
114
113
|
if not password_form.is_valid():
|
|
115
|
-
raise serializers.ValidationError(password_form.errors)
|
|
114
|
+
raise serializers.ValidationError(password_form.errors) # type: ignore[arg-type]
|
|
116
115
|
|
|
117
116
|
password_form.save()
|
|
118
|
-
update_session_auth_hash(request, password_form.user)
|
|
117
|
+
update_session_auth_hash(request, password_form.user) # type: ignore[arg-type]
|
|
119
118
|
|
|
120
119
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
|
121
120
|
|
|
122
121
|
|
|
123
122
|
class TranslationAPI(BananasAdminAPI):
|
|
124
|
-
|
|
125
123
|
name = _("Translation catalog") # type: ignore[assignment]
|
|
126
124
|
basename = "i18n"
|
|
127
125
|
permission_classes = (AllowAny,)
|
|
128
126
|
|
|
129
127
|
class Admin:
|
|
130
|
-
exclude_tags = ["navigation"]
|
|
128
|
+
exclude_tags: ClassVar[List[str]] = ["navigation"]
|
|
131
129
|
|
|
132
130
|
@schema(responses={200: ""})
|
|
133
131
|
def list(self, request: Request) -> Response:
|
|
@@ -2,6 +2,7 @@ import re
|
|
|
2
2
|
from typing import (
|
|
3
3
|
Any,
|
|
4
4
|
Callable,
|
|
5
|
+
ClassVar,
|
|
5
6
|
Dict,
|
|
6
7
|
List,
|
|
7
8
|
Optional,
|
|
@@ -31,7 +32,7 @@ from django.utils.safestring import SafeText, mark_safe
|
|
|
31
32
|
from django.utils.translation import gettext_lazy as _
|
|
32
33
|
from django.views.generic import View
|
|
33
34
|
|
|
34
|
-
from
|
|
35
|
+
from bananas.environment import env
|
|
35
36
|
|
|
36
37
|
__all__ = ["ModelAdminView", "ViewTool", "AdminView", "register", "site"]
|
|
37
38
|
|
|
@@ -41,7 +42,7 @@ MT = TypeVar("MT", bound=Model)
|
|
|
41
42
|
|
|
42
43
|
class ExtendedAdminSite(AdminSite):
|
|
43
44
|
enable_nav_sidebar = False
|
|
44
|
-
default_settings = {
|
|
45
|
+
default_settings: ClassVar[Dict[str, Any]] = {
|
|
45
46
|
"INHERIT_REGISTERED_MODELS": env.get_bool(
|
|
46
47
|
"DJANGO_ADMIN_INHERIT_REGISTERED_MODELS", True
|
|
47
48
|
),
|
|
@@ -84,10 +85,8 @@ class ModelAdminView(ModelAdmin):
|
|
|
84
85
|
@cached_property
|
|
85
86
|
def access_permission(self) -> str:
|
|
86
87
|
meta = self.model._meta
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
codename=meta.permissions[0][0], # First perm codename
|
|
90
|
-
)
|
|
88
|
+
codename = meta.permissions[0][0] # First perm codename
|
|
89
|
+
return f"{meta.app_label}.{codename}"
|
|
91
90
|
|
|
92
91
|
def get_urls(self) -> List[URLPattern]:
|
|
93
92
|
app_label = self.model._meta.app_label
|
|
@@ -122,7 +121,8 @@ class ModelAdminView(ModelAdmin):
|
|
|
122
121
|
|
|
123
122
|
admin_login_url = reverse_lazy("admin:login")
|
|
124
123
|
view = user_passes_test(
|
|
125
|
-
lambda u: u.is_active and hasattr(u, "is_staff") and u.is_staff,
|
|
124
|
+
lambda u: u.is_active and hasattr(u, "is_staff") and u.is_staff,
|
|
125
|
+
login_url=admin_login_url,
|
|
126
126
|
)(view)
|
|
127
127
|
view = permission_required(perm, login_url=admin_login_url)(view)
|
|
128
128
|
return view
|
|
@@ -241,9 +241,9 @@ def register(
|
|
|
241
241
|
)
|
|
242
242
|
# The first permission here is expected to be
|
|
243
243
|
# the general access permission.
|
|
244
|
-
permissions =
|
|
245
|
-
|
|
246
|
-
|
|
244
|
+
permissions = (
|
|
245
|
+
(access_perm_codename, access_perm_name),
|
|
246
|
+
*list(getattr(inner_view, "permissions", [])),
|
|
247
247
|
)
|
|
248
248
|
|
|
249
249
|
model = type(
|
|
@@ -303,9 +303,11 @@ class ViewTool:
|
|
|
303
303
|
|
|
304
304
|
|
|
305
305
|
class AdminView(View):
|
|
306
|
-
tools:
|
|
307
|
-
|
|
308
|
-
|
|
306
|
+
tools: ClassVar[
|
|
307
|
+
Optional[List[Union[Tuple[str, str], Tuple[str, str, str], ViewTool]]]
|
|
308
|
+
] = None
|
|
309
|
+
action: ClassVar[Optional[str]] = None
|
|
310
|
+
admin: ClassVar[Optional[ModelAdminView]] = None
|
|
309
311
|
|
|
310
312
|
label: str
|
|
311
313
|
verbose_name: str
|
|
@@ -354,8 +356,8 @@ class AdminView(View):
|
|
|
354
356
|
# Mypy doesn't change type on a len(...) call
|
|
355
357
|
# See: https://github.com/python/mypy/issues/1178
|
|
356
358
|
if len(tool) == 3:
|
|
357
|
-
tool, perm =
|
|
358
|
-
text, link =
|
|
359
|
+
tool, perm = tool[:-1], tool[-1]
|
|
360
|
+
text, link = tool
|
|
359
361
|
tool = ViewTool(text, link, perm=perm)
|
|
360
362
|
else:
|
|
361
363
|
# Assume ViewTool
|
|
@@ -5,6 +5,7 @@ from functools import wraps
|
|
|
5
5
|
from typing import (
|
|
6
6
|
Any,
|
|
7
7
|
Callable,
|
|
8
|
+
Final,
|
|
8
9
|
FrozenSet,
|
|
9
10
|
Generic,
|
|
10
11
|
List,
|
|
@@ -24,7 +25,7 @@ from rest_framework.request import Request
|
|
|
24
25
|
from rest_framework.response import Response
|
|
25
26
|
from rest_framework.serializers import BaseSerializer, ModelSerializer
|
|
26
27
|
from rest_framework.viewsets import GenericViewSet
|
|
27
|
-
from typing_extensions import
|
|
28
|
+
from typing_extensions import Protocol, final
|
|
28
29
|
|
|
29
30
|
from bananas.admin.api.schemas.yasg import BananasSwaggerSchema
|
|
30
31
|
from bananas.models import TimeStampedModel
|
|
@@ -55,14 +56,18 @@ class Fence(abc.ABC, Generic[InstanceType, TokenType]):
|
|
|
55
56
|
compare: Callable[[TokenType, TokenType], bool],
|
|
56
57
|
get_version: Callable[[InstanceType], Optional[TokenType]],
|
|
57
58
|
openapi_parameter: openapi.Parameter,
|
|
58
|
-
rejection: Exception =
|
|
59
|
-
"The resource does not fulfill the given preconditions"
|
|
60
|
-
),
|
|
59
|
+
rejection: Optional[Exception] = None,
|
|
61
60
|
) -> None:
|
|
62
61
|
self._get_token: Final = get_token
|
|
63
62
|
self._compare: Final = compare
|
|
64
63
|
self._get_version: Final = get_version
|
|
65
|
-
self._rejection: Final =
|
|
64
|
+
self._rejection: Final = (
|
|
65
|
+
rejection
|
|
66
|
+
if rejection is not None
|
|
67
|
+
else errors.PreconditionFailed(
|
|
68
|
+
"The resource does not fulfill the given preconditions"
|
|
69
|
+
)
|
|
70
|
+
)
|
|
66
71
|
self.openapi_parameter: Final = openapi_parameter
|
|
67
72
|
|
|
68
73
|
def check(self, request: Request, instance: InstanceType) -> bool:
|
|
@@ -93,7 +98,7 @@ class FenceAwareSwaggerAutoSchema(BananasSwaggerSchema):
|
|
|
93
98
|
isinstance(self.view, FencedUpdateModelMixin)
|
|
94
99
|
and self.method in self.update_methods
|
|
95
100
|
):
|
|
96
|
-
return parameters
|
|
101
|
+
return [*parameters, self.view.fence.openapi_parameter]
|
|
97
102
|
return parameters
|
|
98
103
|
|
|
99
104
|
|
|
@@ -141,7 +146,7 @@ def header_date_parser(header: str) -> Callable[[Request], datetime.datetime]:
|
|
|
141
146
|
try:
|
|
142
147
|
return parse_header_datetime(request, header)
|
|
143
148
|
except HeaderError as e:
|
|
144
|
-
raise e.as_api_error()
|
|
149
|
+
raise e.as_api_error() from e
|
|
145
150
|
|
|
146
151
|
return parse
|
|
147
152
|
|
|
@@ -183,7 +188,7 @@ def header_etag_parser(header: str) -> Callable[[Request], FrozenSet[str]]:
|
|
|
183
188
|
try:
|
|
184
189
|
return parse_header_etags(request, header)
|
|
185
190
|
except HeaderError as e:
|
|
186
|
-
raise e.as_api_error()
|
|
191
|
+
raise e.as_api_error() from e
|
|
187
192
|
|
|
188
193
|
return parse
|
|
189
194
|
|
|
@@ -39,8 +39,8 @@ class InvalidHeader(HeaderError):
|
|
|
39
39
|
def parse_header_datetime(request: Request, header: str) -> datetime.datetime:
|
|
40
40
|
try:
|
|
41
41
|
value = request.headers[header]
|
|
42
|
-
except KeyError:
|
|
43
|
-
raise MissingHeader(header)
|
|
42
|
+
except KeyError as exc:
|
|
43
|
+
raise MissingHeader(header) from exc
|
|
44
44
|
try:
|
|
45
45
|
return datetime.datetime.fromtimestamp(
|
|
46
46
|
parse_http_date(value), tz=datetime.timezone.utc
|
|
@@ -60,8 +60,8 @@ def clean_tags(tags: Iterable[str]) -> Iterable[str]:
|
|
|
60
60
|
def parse_header_etags(request: Request, header: str) -> FrozenSet[str]:
|
|
61
61
|
try:
|
|
62
62
|
parts = request.headers[header].split(",")
|
|
63
|
-
except KeyError:
|
|
64
|
-
raise MissingHeader(header)
|
|
63
|
+
except KeyError as exc:
|
|
64
|
+
raise MissingHeader(header) from exc
|
|
65
65
|
tags = frozenset(clean_tags(parts))
|
|
66
66
|
if not tags:
|
|
67
67
|
raise InvalidHeader(header)
|
|
@@ -5,6 +5,7 @@ from typing import (
|
|
|
5
5
|
Any,
|
|
6
6
|
Callable,
|
|
7
7
|
Dict,
|
|
8
|
+
Final,
|
|
8
9
|
Generic,
|
|
9
10
|
Iterable,
|
|
10
11
|
List,
|
|
@@ -18,7 +19,7 @@ from typing import (
|
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
from django.conf import global_settings
|
|
21
|
-
from typing_extensions import
|
|
22
|
+
from typing_extensions import Protocol, overload
|
|
22
23
|
|
|
23
24
|
__all__ = ["env", "parse_bool", "parse_int", "parse_tuple", "parse_list", "parse_set"]
|
|
24
25
|
|
|
@@ -165,8 +166,8 @@ def get_parser(typ: Type[P]) -> Callable[[str], P]:
|
|
|
165
166
|
set: parse_set,
|
|
166
167
|
}[typ],
|
|
167
168
|
)
|
|
168
|
-
except KeyError:
|
|
169
|
-
raise NotImplementedError("Unsupported setting type: %r", typ)
|
|
169
|
+
except KeyError as exc:
|
|
170
|
+
raise NotImplementedError("Unsupported setting type: %r", typ) from exc
|
|
170
171
|
|
|
171
172
|
|
|
172
173
|
def get_settings() -> Dict[str, Any]:
|
|
@@ -189,8 +190,8 @@ def get_settings() -> Dict[str, Any]:
|
|
|
189
190
|
if key:
|
|
190
191
|
if key in UNSUPPORTED_ENV_SETTINGS:
|
|
191
192
|
raise ValueError(
|
|
192
|
-
'Django setting "{}" can not be '
|
|
193
|
-
"configured through environment."
|
|
193
|
+
f'Django setting "{key}" can not be '
|
|
194
|
+
"configured through environment."
|
|
194
195
|
)
|
|
195
196
|
|
|
196
197
|
default_value = getattr(global_settings, key, UNDEFINED)
|
|
@@ -201,9 +202,9 @@ def get_settings() -> Dict[str, Any]:
|
|
|
201
202
|
parse = get_parser(SETTINGS_TYPES[key])
|
|
202
203
|
else:
|
|
203
204
|
# Determine parser by django setting type
|
|
204
|
-
parse = get_parser(type(default_value))
|
|
205
|
+
parse = get_parser(type(default_value)) # type: ignore[type-var]
|
|
205
206
|
|
|
206
|
-
value = parse(value)
|
|
207
|
+
value = parse(value) # type: ignore[assignment]
|
|
207
208
|
|
|
208
209
|
settings[key] = value
|
|
209
210
|
|
|
@@ -253,11 +254,7 @@ class EnvironWrapper:
|
|
|
253
254
|
try:
|
|
254
255
|
return parser(value)
|
|
255
256
|
except ValueError:
|
|
256
|
-
log.warning(
|
|
257
|
-
"Unable to parse environment variable {key}={value}".format(
|
|
258
|
-
key=key, value=value
|
|
259
|
-
)
|
|
260
|
-
)
|
|
257
|
+
log.warning(f"Unable to parse environment variable {key}={value}")
|
|
261
258
|
return default
|
|
262
259
|
|
|
263
260
|
@overload
|
|
@@ -19,7 +19,7 @@ def collect_urls(
|
|
|
19
19
|
pattern = urls.pattern.regex.pattern
|
|
20
20
|
for x in urls.url_patterns:
|
|
21
21
|
res += collect_urls(
|
|
22
|
-
x, namespace=urls.namespace or namespace, prefix=prefix
|
|
22
|
+
x, namespace=urls.namespace or namespace, prefix=[*prefix, pattern]
|
|
23
23
|
)
|
|
24
24
|
return res
|
|
25
25
|
elif isinstance(urls, URLPattern):
|
|
@@ -30,7 +30,7 @@ def collect_urls(
|
|
|
30
30
|
[
|
|
31
31
|
("namespace", namespace),
|
|
32
32
|
("name", urls.name),
|
|
33
|
-
("pattern", prefix
|
|
33
|
+
("pattern", [*prefix, pattern]),
|
|
34
34
|
("lookup_str", lookup_str),
|
|
35
35
|
("default_args", dict(urls.default_args or {})),
|
|
36
36
|
]
|
|
@@ -4,12 +4,11 @@ import math
|
|
|
4
4
|
import os
|
|
5
5
|
import uuid
|
|
6
6
|
from itertools import chain
|
|
7
|
-
from typing import Any, Dict, Mapping, Optional, Sized
|
|
7
|
+
from typing import Any, ClassVar, Dict, Final, Mapping, Optional, Sized
|
|
8
8
|
|
|
9
9
|
from django.core.exceptions import ValidationError
|
|
10
10
|
from django.db import models
|
|
11
11
|
from django.utils.translation import gettext_lazy as _
|
|
12
|
-
from typing_extensions import Final
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class Missing:
|
|
@@ -20,7 +19,6 @@ MISSING: Final = Missing()
|
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
class ModelDict(Dict[str, Any]):
|
|
23
|
-
|
|
24
22
|
_nested: Optional[Dict[str, "ModelDict"]] = None
|
|
25
23
|
|
|
26
24
|
def __getattr__(self, item: str) -> Any:
|
|
@@ -120,9 +118,7 @@ class ModelDict(Dict[str, Any]):
|
|
|
120
118
|
)
|
|
121
119
|
else:
|
|
122
120
|
raise AttributeError(
|
|
123
|
-
"{!r} does not have {!r} attribute"
|
|
124
|
-
previous_value, _field
|
|
125
|
-
)
|
|
121
|
+
f"{previous_value!r} does not have {_field!r} attribute"
|
|
126
122
|
)
|
|
127
123
|
|
|
128
124
|
elif value is None:
|
|
@@ -180,9 +176,9 @@ class UUIDModel(models.Model):
|
|
|
180
176
|
class SecretField(models.CharField):
|
|
181
177
|
description = _("Generates and stores a random key.")
|
|
182
178
|
|
|
183
|
-
default_error_messages = {
|
|
184
|
-
"random-is-none": _("%(cls)s.get_random_bytes returned None"),
|
|
185
|
-
"random-too-short": _(
|
|
179
|
+
default_error_messages = { # noqa: RUF012
|
|
180
|
+
"random-is-none": _("%(cls)s.get_random_bytes returned None"),
|
|
181
|
+
"random-too-short": _(
|
|
186
182
|
"Too few random bytes received from "
|
|
187
183
|
"get_random_bytes. Number of"
|
|
188
184
|
" bytes=%(num_bytes)s,"
|
|
@@ -27,11 +27,9 @@ Currently supported engines are:
|
|
|
27
27
|
You can add your own by running ``register(scheme, module_name)`` before
|
|
28
28
|
parsing.
|
|
29
29
|
"""
|
|
30
|
-
from typing import Any, Dict, List, Mapping, NamedTuple, Optional, Tuple, Union
|
|
30
|
+
from typing import Any, Dict, Final, List, Mapping, NamedTuple, Optional, Tuple, Union
|
|
31
31
|
from urllib.parse import parse_qs, unquote_plus, urlsplit
|
|
32
32
|
|
|
33
|
-
from typing_extensions import Final
|
|
34
|
-
|
|
35
33
|
|
|
36
34
|
class Alias:
|
|
37
35
|
"""
|
|
@@ -97,8 +95,8 @@ def resolve(
|
|
|
97
95
|
), "Multiple levels of aliases are not supported"
|
|
98
96
|
|
|
99
97
|
return result
|
|
100
|
-
except KeyError:
|
|
101
|
-
raise KeyError("No matches for engine %s" % key)
|
|
98
|
+
except KeyError as exc:
|
|
99
|
+
raise KeyError("No matches for engine %s" % key) from exc
|
|
102
100
|
|
|
103
101
|
|
|
104
102
|
def get_engine(scheme: str) -> str:
|
|
@@ -128,12 +126,12 @@ def get_engine(scheme: str) -> str:
|
|
|
128
126
|
|
|
129
127
|
try:
|
|
130
128
|
engine, extra = engine
|
|
131
|
-
except ValueError:
|
|
129
|
+
except ValueError as exc:
|
|
132
130
|
# engine was not a list of length 2
|
|
133
131
|
raise ValueError(
|
|
134
132
|
"django-bananas.url' engine "
|
|
135
133
|
"configuration is invalid: %r" % ENGINE_MAPPING
|
|
136
|
-
)
|
|
134
|
+
) from exc
|
|
137
135
|
|
|
138
136
|
assert isinstance(
|
|
139
137
|
extra, Mapping
|
|
@@ -1,27 +1,49 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: django-bananas
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3
|
|
4
4
|
Summary: Django Bananas - Django extensions the monkey way
|
|
5
5
|
Home-page: https://github.com/5monkeys/django-bananas
|
|
6
6
|
License: MIT License
|
|
7
7
|
Classifier: Development Status :: 5 - Production/Stable
|
|
8
8
|
Classifier: Programming Language :: Python
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
12
10
|
Classifier: Programming Language :: Python :: 3.8
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Framework :: Django
|
|
17
|
+
Classifier: Framework :: Django :: 3.2
|
|
18
|
+
Classifier: Framework :: Django :: 4.0
|
|
19
|
+
Classifier: Framework :: Django :: 4.1
|
|
20
|
+
Classifier: Framework :: Django :: 4.2
|
|
21
|
+
Classifier: Framework :: Django :: 5.0
|
|
22
|
+
Classifier: Framework :: Django :: 5.1
|
|
15
23
|
Classifier: Intended Audience :: Developers
|
|
16
24
|
Classifier: License :: OSI Approved :: MIT License
|
|
17
25
|
Classifier: Operating System :: OS Independent
|
|
18
26
|
Classifier: Framework :: Django
|
|
19
27
|
Requires-Python: >=3.6
|
|
20
28
|
Description-Content-Type: text/x-rst; charset=UTF-8
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: Django>=2.2
|
|
31
|
+
Requires-Dist: typing-extensions>=3.7.4.3
|
|
21
32
|
Provides-Extra: drf
|
|
33
|
+
Requires-Dist: djangorestframework>=3.10; extra == "drf"
|
|
34
|
+
Requires-Dist: drf-yasg>=1.20.0; extra == "drf"
|
|
22
35
|
Provides-Extra: test
|
|
36
|
+
Requires-Dist: tox; extra == "test"
|
|
37
|
+
Requires-Dist: coverage[toml]; extra == "test"
|
|
23
38
|
Provides-Extra: dev
|
|
24
|
-
|
|
39
|
+
Requires-Dist: mypy; extra == "dev"
|
|
40
|
+
Requires-Dist: types-setuptools; extra == "dev"
|
|
41
|
+
Requires-Dist: django-stubs; extra == "dev"
|
|
42
|
+
Requires-Dist: djangorestframework-stubs; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest; extra == "dev"
|
|
44
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-django; extra == "dev"
|
|
46
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
25
47
|
|
|
26
48
|
================================================================================
|
|
27
49
|
:banana: Django Bananas - Django extensions the monkey way
|
|
@@ -57,10 +79,12 @@ with the ``drf`` extra to keep those in sync:
|
|
|
57
79
|
|
|
58
80
|
Currently tested only for
|
|
59
81
|
|
|
60
|
-
- Django 3.2 under Python 3.
|
|
82
|
+
- Django 3.2 under Python 3.8-3.10
|
|
61
83
|
- Django 4.0 under Python 3.8-3.10
|
|
62
|
-
- Django 4.1 under Python 3.8-3.
|
|
63
|
-
- Django 4.2 under Python 3.8-3.
|
|
84
|
+
- Django 4.1 under Python 3.8-3.13
|
|
85
|
+
- Django 4.2 under Python 3.8-3.13
|
|
86
|
+
- Django 5.0 under Python 3.10-3.13
|
|
87
|
+
- Django 5.1 under Python 3.10-3.13
|
|
64
88
|
|
|
65
89
|
Pull requests welcome!
|
|
66
90
|
|
|
@@ -263,7 +287,6 @@ feature requires installation with the ``drf`` extra.
|
|
|
263
287
|
|
|
264
288
|
|
|
265
289
|
class CustomAdminAPI(BananasAdminAPI):
|
|
266
|
-
|
|
267
290
|
name = lazy_title(_("custom"))
|
|
268
291
|
|
|
269
292
|
@schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
|
|
@@ -272,7 +295,6 @@ feature requires installation with the ``drf`` extra.
|
|
|
272
295
|
|
|
273
296
|
|
|
274
297
|
class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
|
|
275
|
-
|
|
276
298
|
serializer_class = SomeModelSerializer
|
|
277
299
|
|
|
278
300
|
def list(self, request):
|
|
@@ -581,4 +603,4 @@ and select specific tests with the ``test`` argument to ``make test``:
|
|
|
581
603
|
|
|
582
604
|
.. code-block:: bash
|
|
583
605
|
|
|
584
|
-
make test test='
|
|
606
|
+
make test test='-k test_logout'
|
|
@@ -16,8 +16,8 @@ src/bananas/settings.py
|
|
|
16
16
|
src/bananas/url.py
|
|
17
17
|
src/bananas/admin/__init__.py
|
|
18
18
|
src/bananas/admin/extension.py
|
|
19
|
+
src/bananas/admin/i18n.py
|
|
19
20
|
src/bananas/admin/api/__init__.py
|
|
20
|
-
src/bananas/admin/api/i18n.py
|
|
21
21
|
src/bananas/admin/api/mixins.py
|
|
22
22
|
src/bananas/admin/api/permissions.py
|
|
23
23
|
src/bananas/admin/api/router.py
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
Django>=2.2
|
|
2
2
|
typing-extensions>=3.7.4.3
|
|
3
|
-
drf-yasg>=1.20.0
|
|
4
3
|
|
|
5
4
|
[dev]
|
|
6
5
|
mypy
|
|
6
|
+
types-setuptools
|
|
7
7
|
django-stubs
|
|
8
8
|
djangorestframework-stubs
|
|
9
|
-
pytest
|
|
9
|
+
pytest
|
|
10
|
+
pytest-cov
|
|
11
|
+
pytest-django
|
|
10
12
|
pre-commit
|
|
11
13
|
|
|
12
14
|
[drf]
|
|
@@ -15,4 +17,4 @@ drf-yasg>=1.20.0
|
|
|
15
17
|
|
|
16
18
|
[test]
|
|
17
19
|
tox
|
|
18
|
-
coverage
|
|
20
|
+
coverage[toml]
|
django-bananas-2.2/setup.cfg
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
[metadata]
|
|
2
|
-
name = django-bananas
|
|
3
|
-
description = Django Bananas - Django extensions the monkey way
|
|
4
|
-
long_description = file: README.rst
|
|
5
|
-
long_description_content_type = text/x-rst; charset=UTF-8
|
|
6
|
-
url = https://github.com/5monkeys/django-bananas
|
|
7
|
-
version = attr: bananas.__version__
|
|
8
|
-
classifiers =
|
|
9
|
-
Development Status :: 5 - Production/Stable
|
|
10
|
-
Programming Language :: Python
|
|
11
|
-
Programming Language :: Python :: 3
|
|
12
|
-
Programming Language :: Python :: 3.6
|
|
13
|
-
Programming Language :: Python :: 3.7
|
|
14
|
-
Programming Language :: Python :: 3.8
|
|
15
|
-
Programming Language :: Python :: 3.9
|
|
16
|
-
Programming Language :: Python :: 3.10
|
|
17
|
-
Intended Audience :: Developers
|
|
18
|
-
License :: OSI Approved :: MIT License
|
|
19
|
-
Operating System :: OS Independent
|
|
20
|
-
Framework :: Django
|
|
21
|
-
license = MIT License
|
|
22
|
-
license_file = LICENSE
|
|
23
|
-
|
|
24
|
-
[options]
|
|
25
|
-
packages = find:
|
|
26
|
-
package_dir =
|
|
27
|
-
=src
|
|
28
|
-
python_requires = >=3.6
|
|
29
|
-
include_package_data = True
|
|
30
|
-
exclude =
|
|
31
|
-
tests
|
|
32
|
-
_*
|
|
33
|
-
example
|
|
34
|
-
zip_safe = False
|
|
35
|
-
install_requires =
|
|
36
|
-
Django>=2.2
|
|
37
|
-
typing-extensions>=3.7.4.3
|
|
38
|
-
drf-yasg>=1.20.0
|
|
39
|
-
|
|
40
|
-
[options.packages.find]
|
|
41
|
-
where = src
|
|
42
|
-
|
|
43
|
-
[options.extras_require]
|
|
44
|
-
drf =
|
|
45
|
-
djangorestframework>=3.10
|
|
46
|
-
drf-yasg>=1.20.0
|
|
47
|
-
test =
|
|
48
|
-
tox
|
|
49
|
-
coverage
|
|
50
|
-
dev =
|
|
51
|
-
mypy
|
|
52
|
-
django-stubs
|
|
53
|
-
djangorestframework-stubs
|
|
54
|
-
pytest-mypy-plugins
|
|
55
|
-
pre-commit
|
|
56
|
-
|
|
57
|
-
[options.package_data]
|
|
58
|
-
bananas = py.typed
|
|
59
|
-
|
|
60
|
-
[flake8]
|
|
61
|
-
max-line-length = 88
|
|
62
|
-
ignore = E501,E266,E731,W503,E203,B008,B024
|
|
63
|
-
exclude = .eggs,.tox,.git,docs,migrations,node_modules,manage.py
|
|
64
|
-
show-source = true
|
|
65
|
-
max-complexity = 10
|
|
66
|
-
|
|
67
|
-
[coverage:run]
|
|
68
|
-
source = src
|
|
69
|
-
branch = True
|
|
70
|
-
parallel = True
|
|
71
|
-
|
|
72
|
-
[coverage:report]
|
|
73
|
-
fail_under = 90
|
|
74
|
-
skip_covered = True
|
|
75
|
-
show_missing = True
|
|
76
|
-
exclude_lines =
|
|
77
|
-
pragma: no cover
|
|
78
|
-
if __name__ == .__main__.:
|
|
79
|
-
^\s*\.\.\.
|
|
80
|
-
if TYPE_CHECKING:
|
|
81
|
-
raise NotImplementedError
|
|
82
|
-
|
|
83
|
-
[isort]
|
|
84
|
-
line_length = 88
|
|
85
|
-
known_first_party = bananas
|
|
86
|
-
multi_line_output = 3
|
|
87
|
-
combine_as_imports = true
|
|
88
|
-
include_trailing_comma = true
|
|
89
|
-
force_grid_wrap = 0
|
|
90
|
-
skip = migrations
|
|
91
|
-
src_paths = src, tests
|
|
92
|
-
|
|
93
|
-
[mypy]
|
|
94
|
-
python_version = 3.7
|
|
95
|
-
show_error_codes = True
|
|
96
|
-
pretty = True
|
|
97
|
-
files = src,tests,runtests.py,setup.py
|
|
98
|
-
no_implicit_reexport = True
|
|
99
|
-
no_implicit_optional = True
|
|
100
|
-
strict_equality = True
|
|
101
|
-
strict_optional = True
|
|
102
|
-
check_untyped_defs = True
|
|
103
|
-
disallow_incomplete_defs = True
|
|
104
|
-
disallow_untyped_defs = True
|
|
105
|
-
ignore_missing_imports = False
|
|
106
|
-
warn_unused_configs = True
|
|
107
|
-
warn_redundant_casts = True
|
|
108
|
-
warn_unused_ignores = True
|
|
109
|
-
warn_return_any = True
|
|
110
|
-
warn_unreachable = True
|
|
111
|
-
plugins =
|
|
112
|
-
mypy_django_plugin.main
|
|
113
|
-
|
|
114
|
-
[mypy.plugins.django-stubs]
|
|
115
|
-
django_settings_module = tests.project.settings
|
|
116
|
-
|
|
117
|
-
[mypy-tests.tests.*]
|
|
118
|
-
disallow_untyped_defs = False
|
|
119
|
-
|
|
120
|
-
[mypy-test.support]
|
|
121
|
-
ignore_missing_imports = True
|
|
122
|
-
|
|
123
|
-
[mypy-drf_yasg.*]
|
|
124
|
-
ignore_missing_imports = True
|
|
125
|
-
|
|
126
|
-
[mypy-setuptools.*]
|
|
127
|
-
ignore_missing_imports = True
|
|
128
|
-
|
|
129
|
-
[egg_info]
|
|
130
|
-
tag_build =
|
|
131
|
-
tag_date = 0
|
|
132
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django-bananas-2.2 → django_bananas-2.3}/src/bananas/static/admin/bananas/css/banansive.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|