django-bananas 2.1__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.
Files changed (58) hide show
  1. {django-bananas-2.1 → django_bananas-2.3}/LICENSE +1 -1
  2. {django-bananas-2.1 → django_bananas-2.3}/MANIFEST.in +1 -1
  3. {django-bananas-2.1/src/django_bananas.egg-info → django_bananas-2.3}/PKG-INFO +33 -10
  4. {django-bananas-2.1 → django_bananas-2.3}/README.rst +6 -5
  5. django_bananas-2.3/pyproject.toml +97 -0
  6. django_bananas-2.3/setup.cfg +73 -0
  7. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/__init__.py +1 -1
  8. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/mixins.py +2 -2
  9. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/schemas/base.py +1 -1
  10. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/schemas/yasg.py +2 -1
  11. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/v1_0/urls.py +2 -2
  12. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/versioning.py +2 -3
  13. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/views.py +13 -15
  14. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/extension.py +17 -15
  15. {django-bananas-2.1/src/bananas/admin/api → django_bananas-2.3/src/bananas/admin}/i18n.py +0 -1
  16. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/drf/fencing.py +13 -8
  17. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/drf/utils.py +4 -4
  18. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/environment.py +9 -12
  19. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/management/commands/show_urls.py +2 -2
  20. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/management/commands/syncpermissions.py +4 -3
  21. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/models.py +3 -7
  22. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/query.py +1 -1
  23. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/secrets.py +2 -2
  24. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/url.py +5 -7
  25. {django-bananas-2.1 → django_bananas-2.3/src/django_bananas.egg-info}/PKG-INFO +33 -10
  26. {django-bananas-2.1 → django_bananas-2.3}/src/django_bananas.egg-info/SOURCES.txt +1 -1
  27. {django-bananas-2.1 → django_bananas-2.3}/src/django_bananas.egg-info/requires.txt +5 -3
  28. django-bananas-2.1/pyproject.toml +0 -3
  29. django-bananas-2.1/setup.cfg +0 -132
  30. {django-bananas-2.1 → django_bananas-2.3}/AUTHORS +0 -0
  31. {django-bananas-2.1 → django_bananas-2.3}/setup.py +0 -0
  32. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/__init__.py +0 -0
  33. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/__init__.py +0 -0
  34. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/permissions.py +0 -0
  35. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/router.py +0 -0
  36. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/schemas/__init__.py +0 -0
  37. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/schemas/decorators.py +0 -0
  38. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/serializers.py +0 -0
  39. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/urls.py +0 -0
  40. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/admin/api/v1_0/__init__.py +0 -0
  41. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/drf/__init__.py +0 -0
  42. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/drf/errors.py +0 -0
  43. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/lazy.py +0 -0
  44. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/management/__init__.py +0 -0
  45. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/management/commands/__init__.py +0 -0
  46. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/py.typed +0 -0
  47. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/settings.py +0 -0
  48. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/static/admin/bananas/css/bananas.css +0 -0
  49. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/static/admin/bananas/css/banansive.css +0 -0
  50. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/static/admin/bananas/img/django.svg +0 -0
  51. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/static/admin/bananas/img/search.svg +0 -0
  52. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/static/admin/bananas/js/bananas.js +0 -0
  53. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/static/admin/css/responsive.css +0 -0
  54. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/templates/admin/base_site.html +0 -0
  55. {django-bananas-2.1 → django_bananas-2.3}/src/bananas/templates/admin/view.html +0 -0
  56. {django-bananas-2.1 → django_bananas-2.3}/src/django_bananas.egg-info/dependency_links.txt +0 -0
  57. {django-bananas-2.1 → django_bananas-2.3}/src/django_bananas.egg-info/not-zip-safe +0 -0
  58. {django-bananas-2.1 → django_bananas-2.3}/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,49 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: django-bananas
3
- Version: 2.1
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
- License-File: LICENSE
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,9 +79,12 @@ with the ``drf`` extra to keep those in sync:
57
79
 
58
80
  Currently tested only for
59
81
 
60
- - Django 2.2 under Python 3.7-3.9
61
- - Django 3.2 under Python 3.7-3.9
82
+ - Django 3.2 under Python 3.8-3.10
62
83
  - Django 4.0 under Python 3.8-3.10
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
63
88
 
64
89
  Pull requests welcome!
65
90
 
@@ -262,7 +287,6 @@ feature requires installation with the ``drf`` extra.
262
287
 
263
288
 
264
289
  class CustomAdminAPI(BananasAdminAPI):
265
-
266
290
  name = lazy_title(_("custom"))
267
291
 
268
292
  @schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
@@ -271,7 +295,6 @@ feature requires installation with the ``drf`` extra.
271
295
 
272
296
 
273
297
  class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
274
-
275
298
  serializer_class = SomeModelSerializer
276
299
 
277
300
  def list(self, request):
@@ -580,4 +603,4 @@ and select specific tests with the ``test`` argument to ``make test``:
580
603
 
581
604
  .. code-block:: bash
582
605
 
583
- make test test='tests.test_admin.APITest.test_logout'
606
+ make test test='-k test_logout'
@@ -32,9 +32,12 @@ with the ``drf`` extra to keep those in sync:
32
32
 
33
33
  Currently tested only for
34
34
 
35
- - Django 2.2 under Python 3.7-3.9
36
- - Django 3.2 under Python 3.7-3.9
35
+ - Django 3.2 under Python 3.8-3.10
37
36
  - Django 4.0 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
38
41
 
39
42
  Pull requests welcome!
40
43
 
@@ -237,7 +240,6 @@ feature requires installation with the ``drf`` extra.
237
240
 
238
241
 
239
242
  class CustomAdminAPI(BananasAdminAPI):
240
-
241
243
  name = lazy_title(_("custom"))
242
244
 
243
245
  @schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
@@ -246,7 +248,6 @@ feature requires installation with the ``drf`` extra.
246
248
 
247
249
 
248
250
  class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
249
-
250
251
  serializer_class = SomeModelSerializer
251
252
 
252
253
  def list(self, request):
@@ -555,4 +556,4 @@ and select specific tests with the ``test`` argument to ``make test``:
555
556
 
556
557
  .. code-block:: bash
557
558
 
558
- make test test='tests.test_admin.APITest.test_logout'
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
+
@@ -1,4 +1,4 @@
1
- VERSION = (2, 1, 0, "final", 0)
1
+ VERSION = (2, 3, 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,8 +32,7 @@ class BananasAdminAPI(BananasAPI, viewsets.GenericViewSet):
29
32
 
30
33
 
31
34
  class LoginAPI(BananasAdminAPI):
32
-
33
- name = _("Log in")
35
+ name = _("Log in") # type: ignore[assignment]
34
36
  basename = "login"
35
37
  permission_classes = (IsAnonymous,)
36
38
  serializer_class = AuthenticationSerializer # Placeholder for schema
@@ -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,8 +62,7 @@ class LoginAPI(BananasAdminAPI):
60
62
 
61
63
 
62
64
  class LogoutAPI(BananasAPI, viewsets.ViewSet):
63
-
64
- name = _("Log out")
65
+ name = _("Log out") # type: ignore[assignment]
65
66
  basename = "logout"
66
67
 
67
68
  class Admin:
@@ -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,8 +93,7 @@ class MeAPI(BananasAdminAPI):
93
93
 
94
94
 
95
95
  class ChangePasswordAPI(BananasAdminAPI):
96
-
97
- name = _("Change password")
96
+ name = _("Change password") # type: ignore[assignment]
98
97
  basename = "change_password"
99
98
  serializer_class = PasswordChangeSerializer # Placeholder for schema
100
99
 
@@ -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
- name = _("Translation catalog")
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 u.is_staff, login_url=admin_login_url
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 = tuple(
245
- [(access_perm_codename, access_perm_name)]
246
- + list(getattr(inner_view, "permissions", []))
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: Optional[List[Union[Tuple[str, str], Tuple[str, str, str], ViewTool]]] = None
307
- action: Optional[str] = None
308
- admin: Optional[ModelAdminView] = None
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 = cast(Tuple[str, str, str], tool)[:-1], tool[-1]
358
- text, link = cast(Tuple[str, str], tool)
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
@@ -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]
@@ -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 Final, Protocol, final
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 = errors.PreconditionFailed(
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 = rejection
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 + [self.view.fence.openapi_parameter]
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 Final, Protocol, overload
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.".format(key)
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 + [pattern]
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 + [pattern]),
33
+ ("pattern", [*prefix, pattern]),
34
34
  ("lookup_str", lookup_str),
35
35
  ("default_args", dict(urls.default_args or {})),
36
36
  ]
@@ -3,7 +3,6 @@ from django.core.management.base import BaseCommand, CommandError
3
3
 
4
4
 
5
5
  class Command(BaseCommand):
6
-
7
6
  help = "Create admin permissions"
8
7
 
9
8
  def handle(self, *args: object, **options: object) -> None:
@@ -29,11 +28,13 @@ class Command(BaseCommand):
29
28
  )
30
29
 
31
30
  if created:
32
- print(f"Found new admin view: {ct.name} [{ct.app_label}]")
31
+ self.stdout.write(
32
+ f"Found new admin view: {ct.name} [{ct.app_label}]"
33
+ )
33
34
 
34
35
  for codename, name in model._meta.permissions:
35
36
  p, created = Permission.objects.update_or_create(
36
37
  codename=codename, content_type=ct, defaults={"name": name}
37
38
  )
38
39
  if created:
39
- print(f"Created permission: {name}")
40
+ self.stdout.write(f"Created permission: {name}")
@@ -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".format(
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,7 +176,7 @@ 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 = {
179
+ default_error_messages = { # noqa: RUF012
184
180
  "random-is-none": _("%(cls)s.get_random_bytes returned None"),
185
181
  "random-too-short": _(
186
182
  "Too few random bytes received from "
@@ -74,7 +74,7 @@ class ModelDictQuerySetMixin:
74
74
  fields += tuple(named_fields.values())
75
75
 
76
76
  clone = self.values(*fields)
77
- clone._iterable_class = ModelDictIterable # type: ignore[attr-defined]
77
+ clone._iterable_class = ModelDictIterable # type: ignore[assignment]
78
78
 
79
79
  # QuerySet._hints is a dict object used by db router
80
80
  # to aid deciding which db should get a request. Currently
@@ -1,7 +1,7 @@
1
1
  import os
2
- from typing import Optional
2
+ from typing import Final, Optional
3
3
 
4
- from typing_extensions import Final, overload
4
+ from typing_extensions import overload
5
5
 
6
6
  from .environment import env
7
7
 
@@ -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
1
+ Metadata-Version: 2.2
2
2
  Name: django-bananas
3
- Version: 2.1
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
- License-File: LICENSE
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,9 +79,12 @@ with the ``drf`` extra to keep those in sync:
57
79
 
58
80
  Currently tested only for
59
81
 
60
- - Django 2.2 under Python 3.7-3.9
61
- - Django 3.2 under Python 3.7-3.9
82
+ - Django 3.2 under Python 3.8-3.10
62
83
  - Django 4.0 under Python 3.8-3.10
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
63
88
 
64
89
  Pull requests welcome!
65
90
 
@@ -262,7 +287,6 @@ feature requires installation with the ``drf`` extra.
262
287
 
263
288
 
264
289
  class CustomAdminAPI(BananasAdminAPI):
265
-
266
290
  name = lazy_title(_("custom"))
267
291
 
268
292
  @schema(query_serializer=SomeSerializer, responses={200: SomeSerializer})
@@ -271,7 +295,6 @@ feature requires installation with the ``drf`` extra.
271
295
 
272
296
 
273
297
  class SomeModelAdminAPI(BananasAPI, viewsets.ModelViewSet):
274
-
275
298
  serializer_class = SomeModelSerializer
276
299
 
277
300
  def list(self, request):
@@ -580,4 +603,4 @@ and select specific tests with the ``test`` argument to ``make test``:
580
603
 
581
604
  .. code-block:: bash
582
605
 
583
- make test test='tests.test_admin.APITest.test_logout'
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-mypy-plugins
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]
@@ -1,3 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=57.0.0", "wheel"]
3
- build-backend = "setuptools.build_meta"
@@ -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