django-bananas 2.2__tar.gz → 2.4__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.
Files changed (58) hide show
  1. {django-bananas-2.2 → django_bananas-2.4}/LICENSE +1 -1
  2. {django-bananas-2.2 → django_bananas-2.4}/MANIFEST.in +1 -1
  3. {django-bananas-2.2/src/django_bananas.egg-info → django_bananas-2.4}/PKG-INFO +36 -11
  4. {django-bananas-2.2 → django_bananas-2.4}/README.rst +7 -6
  5. django_bananas-2.4/pyproject.toml +97 -0
  6. django_bananas-2.4/setup.cfg +74 -0
  7. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/__init__.py +1 -1
  8. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/mixins.py +2 -2
  9. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/schemas/base.py +1 -1
  10. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/schemas/yasg.py +2 -1
  11. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/v1_0/urls.py +2 -2
  12. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/versioning.py +2 -3
  13. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/views.py +6 -8
  14. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/extension.py +23 -23
  15. {django-bananas-2.2/src/bananas/admin/api → django_bananas-2.4/src/bananas/admin}/i18n.py +0 -1
  16. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/drf/fencing.py +17 -14
  17. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/drf/utils.py +4 -4
  18. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/environment.py +32 -50
  19. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/management/commands/show_urls.py +2 -2
  20. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/management/commands/syncpermissions.py +0 -1
  21. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/models.py +6 -11
  22. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/query.py +13 -10
  23. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/secrets.py +4 -6
  24. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/static/admin/bananas/css/bananas.css +48 -28
  25. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/static/admin/bananas/css/banansive.css +17 -4
  26. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/templates/admin/base_site.html +4 -1
  27. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/url.py +6 -7
  28. {django-bananas-2.2 → django_bananas-2.4/src/django_bananas.egg-info}/PKG-INFO +36 -11
  29. {django-bananas-2.2 → django_bananas-2.4}/src/django_bananas.egg-info/SOURCES.txt +1 -1
  30. {django-bananas-2.2 → django_bananas-2.4}/src/django_bananas.egg-info/requires.txt +5 -3
  31. django-bananas-2.2/pyproject.toml +0 -3
  32. django-bananas-2.2/setup.cfg +0 -132
  33. {django-bananas-2.2 → django_bananas-2.4}/AUTHORS +0 -0
  34. {django-bananas-2.2 → django_bananas-2.4}/setup.py +0 -0
  35. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/__init__.py +0 -0
  36. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/__init__.py +0 -0
  37. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/permissions.py +0 -0
  38. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/router.py +0 -0
  39. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/schemas/__init__.py +0 -0
  40. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/schemas/decorators.py +0 -0
  41. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/serializers.py +0 -0
  42. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/urls.py +0 -0
  43. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/admin/api/v1_0/__init__.py +0 -0
  44. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/drf/__init__.py +0 -0
  45. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/drf/errors.py +0 -0
  46. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/lazy.py +0 -0
  47. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/management/__init__.py +0 -0
  48. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/management/commands/__init__.py +0 -0
  49. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/py.typed +0 -0
  50. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/settings.py +0 -0
  51. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/static/admin/bananas/img/django.svg +0 -0
  52. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/static/admin/bananas/img/search.svg +0 -0
  53. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/static/admin/bananas/js/bananas.js +0 -0
  54. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/static/admin/css/responsive.css +0 -0
  55. {django-bananas-2.2 → django_bananas-2.4}/src/bananas/templates/admin/view.html +0 -0
  56. {django-bananas-2.2 → django_bananas-2.4}/src/django_bananas.egg-info/dependency_links.txt +0 -0
  57. {django-bananas-2.2 → django_bananas-2.4}/src/django_bananas.egg-info/not-zip-safe +0 -0
  58. {django-bananas-2.2 → django_bananas-2.4}/src/django_bananas.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014-2021 5 Monkeys
3
+ Copyright (c) 2014-2025 5 Monkeys
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  include setup.py README.rst MANIFEST.in LICENSE AUTHORS
2
- exclude runtests.py tox.ini *.yml *.yaml Makefile Dockerfile .editorconfig
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,51 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: django-bananas
3
- Version: 2.2
3
+ Version: 2.4
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
23
+ Classifier: Framework :: Django :: 5.2
15
24
  Classifier: Intended Audience :: Developers
16
25
  Classifier: License :: OSI Approved :: MIT License
17
26
  Classifier: Operating System :: OS Independent
18
27
  Classifier: Framework :: Django
19
28
  Requires-Python: >=3.6
20
29
  Description-Content-Type: text/x-rst; charset=UTF-8
30
+ License-File: LICENSE
31
+ Requires-Dist: Django>=2.2
32
+ Requires-Dist: typing-extensions>=3.7.4.3
21
33
  Provides-Extra: drf
34
+ Requires-Dist: djangorestframework>=3.10; extra == "drf"
35
+ Requires-Dist: drf-yasg>=1.20.0; extra == "drf"
22
36
  Provides-Extra: test
37
+ Requires-Dist: tox; extra == "test"
38
+ Requires-Dist: coverage[toml]; extra == "test"
23
39
  Provides-Extra: dev
24
- License-File: LICENSE
40
+ Requires-Dist: mypy; extra == "dev"
41
+ Requires-Dist: types-setuptools; extra == "dev"
42
+ Requires-Dist: django-stubs; extra == "dev"
43
+ Requires-Dist: djangorestframework-stubs; extra == "dev"
44
+ Requires-Dist: pytest; extra == "dev"
45
+ Requires-Dist: pytest-cov; extra == "dev"
46
+ Requires-Dist: pytest-django; extra == "dev"
47
+ Requires-Dist: pre-commit; extra == "dev"
48
+ Dynamic: license-file
25
49
 
26
50
  ================================================================================
27
51
  :banana: Django Bananas - Django extensions the monkey way
@@ -57,10 +81,13 @@ with the ``drf`` extra to keep those in sync:
57
81
 
58
82
  Currently tested only for
59
83
 
60
- - Django 3.2 under Python 3.7-3.9
84
+ - Django 3.2 under Python 3.8-3.10
61
85
  - Django 4.0 under Python 3.8-3.10
62
- - Django 4.1 under Python 3.8-3.10
63
- - Django 4.2 under Python 3.8-3.10
86
+ - Django 4.1 under Python 3.8-3.13
87
+ - Django 4.2 under Python 3.8-3.13
88
+ - Django 5.0 under Python 3.10-3.13
89
+ - Django 5.1 under Python 3.10-3.13
90
+ - Django 5.2 under Python 3.10-3.13
64
91
 
65
92
  Pull requests welcome!
66
93
 
@@ -263,7 +290,6 @@ feature requires installation with the ``drf`` extra.
263
290
 
264
291
 
265
292
  class CustomAdminAPI(BananasAdminAPI):
266
-
267
293
  name = lazy_title(_("custom"))
268
294
 
269
295
  @schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
@@ -272,7 +298,6 @@ feature requires installation with the ``drf`` extra.
272
298
 
273
299
 
274
300
  class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
275
-
276
301
  serializer_class = SomeModelSerializer
277
302
 
278
303
  def list(self, request):
@@ -581,4 +606,4 @@ and select specific tests with the ``test`` argument to ``make test``:
581
606
 
582
607
  .. code-block:: bash
583
608
 
584
- make test test='tests.test_admin.APITest.test_logout'
609
+ make test test='-k test_logout'
@@ -32,10 +32,13 @@ 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.7-3.9
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.10
38
- - Django 4.2 under Python 3.8-3.10
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
41
+ - Django 5.2 under Python 3.10-3.13
39
42
 
40
43
  Pull requests welcome!
41
44
 
@@ -238,7 +241,6 @@ feature requires installation with the ``drf`` extra.
238
241
 
239
242
 
240
243
  class CustomAdminAPI(BananasAdminAPI):
241
-
242
244
  name = lazy_title(_("custom"))
243
245
 
244
246
  @schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
@@ -247,7 +249,6 @@ feature requires installation with the ``drf`` extra.
247
249
 
248
250
 
249
251
  class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
250
-
251
252
  serializer_class = SomeModelSerializer
252
253
 
253
254
  def list(self, request):
@@ -556,4 +557,4 @@ and select specific tests with the ``test`` argument to ``make test``:
556
557
 
557
558
  .. code-block:: bash
558
559
 
559
- make test test='tests.test_admin.APITest.test_logout'
560
+ 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", "py313"]
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,74 @@
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
+ Framework :: Django :: 5.2
26
+ Intended Audience :: Developers
27
+ License :: OSI Approved :: MIT License
28
+ Operating System :: OS Independent
29
+ Framework :: Django
30
+ license = MIT License
31
+ license_file = LICENSE
32
+
33
+ [options]
34
+ packages = find:
35
+ package_dir =
36
+ =src
37
+ python_requires = >=3.6
38
+ include_package_data = True
39
+ exclude =
40
+ tests
41
+ _*
42
+ example
43
+ zip_safe = False
44
+ install_requires =
45
+ Django>=2.2
46
+ typing-extensions>=3.7.4.3
47
+
48
+ [options.packages.find]
49
+ where = src
50
+
51
+ [options.extras_require]
52
+ drf =
53
+ djangorestframework>=3.10
54
+ drf-yasg>=1.20.0
55
+ test =
56
+ tox
57
+ coverage[toml]
58
+ dev =
59
+ mypy
60
+ types-setuptools
61
+ django-stubs
62
+ djangorestframework-stubs
63
+ pytest
64
+ pytest-cov
65
+ pytest-django
66
+ pre-commit
67
+
68
+ [options.package_data]
69
+ bananas = py.typed
70
+
71
+ [egg_info]
72
+ tag_build =
73
+ tag_date = 0
74
+
@@ -1,4 +1,4 @@
1
- VERSION = (2, 2, 0, "final", 0)
1
+ VERSION = (2, 4, 0, "final", 0)
2
2
 
3
3
 
4
4
  def get_version() -> str:
@@ -63,9 +63,9 @@ class BananasAPI:
63
63
  if admin is not None:
64
64
  meta.update(
65
65
  {
66
- key: getattr(admin, key) # type: ignore[misc, call-overload]
66
+ key: getattr(admin, key)
67
67
  for key in filter(
68
- lambda key: key in meta, # type: ignore[arg-type]
68
+ lambda key: key in meta,
69
69
  admin.__dict__.keys(),
70
70
  )
71
71
  }
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any, Type, cast
3
3
  from rest_framework.viewsets import ViewSetMixin
4
4
 
5
5
  if TYPE_CHECKING:
6
- from ..mixins import BananasAPI
6
+ from bananas.admin.api.mixins import BananasAPI
7
7
 
8
8
 
9
9
  class BananasBaseRouter:
@@ -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 ..versioning import BananasVersioning
16
+ from bananas.admin.api.versioning import BananasVersioning
17
+
17
18
  from .base import BananasBaseRouter
18
19
 
19
20
 
@@ -1,7 +1,7 @@
1
1
  from django.urls import include, re_path
2
2
 
3
- from .. import views
4
- from ..router import register, router
3
+ from bananas.admin.api import views
4
+ from bananas.admin.api.router import register, router
5
5
 
6
6
  register(views.LoginAPI)
7
7
  register(views.LogoutAPI)
@@ -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,)
@@ -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
@@ -121,13 +120,12 @@ class ChangePasswordAPI(BananasAdminAPI):
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 ..environment import env
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
- return "{app_label}.{codename}".format(
88
- app_label=meta.app_label,
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, login_url=admin_login_url # type: ignore[arg-type, return-value]
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
@@ -133,12 +133,12 @@ class ModelAdminView(ModelAdmin):
133
133
  return perm
134
134
 
135
135
  def has_module_permission(self, request: HttpRequest) -> bool:
136
- return request.user.has_perm(self.access_permission)
136
+ return bool(request.user.has_perm(self.access_permission))
137
137
 
138
138
  def has_change_permission(
139
139
  self, request: HttpRequest, obj: Optional[MT] = None
140
140
  ) -> bool:
141
- return request.user.has_perm(self.access_permission)
141
+ return bool(request.user.has_perm(self.access_permission))
142
142
 
143
143
  # TODO: Remove obj?
144
144
  def has_add_permission(
@@ -175,8 +175,7 @@ def register(
175
175
  *,
176
176
  admin_site: Optional[AdminSite] = None,
177
177
  admin_class: Type[ModelAdmin] = ModelAdminView,
178
- ) -> Type["AdminView"]:
179
- ...
178
+ ) -> Type["AdminView"]: ...
180
179
 
181
180
 
182
181
  # Call with parenthesis: @register()
@@ -186,8 +185,7 @@ def register(
186
185
  *,
187
186
  admin_site: Optional[AdminSite] = None,
188
187
  admin_class: Type[ModelAdmin] = ModelAdminView,
189
- ) -> Callable[[Type["AdminView"]], Type["AdminView"]]:
190
- ...
188
+ ) -> Callable[[Type["AdminView"]], Type["AdminView"]]: ...
191
189
 
192
190
 
193
191
  def register(
@@ -236,14 +234,14 @@ def register(
236
234
  inner_view.verbose_name = verbose_name
237
235
 
238
236
  access_perm_codename = "can_access_" + model_name.lower()
239
- access_perm_name = _("Can access {verbose_name}").format(
237
+ access_perm_name = str(_("Can access {verbose_name}")).format(
240
238
  verbose_name=verbose_name
241
239
  )
242
240
  # The first permission here is expected to be
243
241
  # the general access permission.
244
- permissions = tuple(
245
- [(access_perm_codename, access_perm_name)]
246
- + list(getattr(inner_view, "permissions", []))
242
+ permissions = (
243
+ (access_perm_codename, access_perm_name),
244
+ *list(getattr(inner_view, "permissions", [])),
247
245
  )
248
246
 
249
247
  model = type(
@@ -303,9 +301,11 @@ class ViewTool:
303
301
 
304
302
 
305
303
  class AdminView(View):
306
- tools: Optional[List[Union[Tuple[str, str], Tuple[str, str, str], ViewTool]]] = None
307
- action: Optional[str] = None
308
- admin: Optional[ModelAdminView] = None
304
+ tools: ClassVar[
305
+ Optional[List[Union[Tuple[str, str], Tuple[str, str, str], ViewTool]]]
306
+ ] = None
307
+ action: ClassVar[Optional[str]] = None
308
+ admin: ClassVar[Optional[ModelAdminView]] = None
309
309
 
310
310
  label: str
311
311
  verbose_name: str
@@ -354,8 +354,8 @@ class AdminView(View):
354
354
  # Mypy doesn't change type on a len(...) call
355
355
  # See: https://github.com/python/mypy/issues/1178
356
356
  if len(tool) == 3:
357
- tool, perm = cast(Tuple[str, str, str], tool)[:-1], tool[-1]
358
- text, link = cast(Tuple[str, str], tool)
357
+ tool, perm = tool[:-1], tool[-1]
358
+ text, link = tool
359
359
  tool = ViewTool(text, link, perm=perm)
360
360
  else:
361
361
  # Assume ViewTool
@@ -385,7 +385,7 @@ class AdminView(View):
385
385
 
386
386
  def has_permission(self, perm: str) -> bool:
387
387
  perm = self.get_permission(perm)
388
- return self.request.user.has_perm(perm)
388
+ return bool(self.request.user.has_perm(perm))
389
389
 
390
390
  def has_access(self) -> bool:
391
391
  assert self.admin is not None
@@ -4,7 +4,6 @@ from django.views.i18n import JavaScriptCatalog
4
4
 
5
5
 
6
6
  class RawTranslationCatalog(JavaScriptCatalog):
7
-
8
7
  domain = "django"
9
8
 
10
9
  def render_to_response(self, context: Dict[str, Any], **response_kwargs: Any) -> Dict[str, Any]: # type: ignore[override]