django-resonant-settings 0.29__tar.gz → 0.32.1__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 (31) hide show
  1. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/PKG-INFO +5 -3
  2. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/pyproject.toml +36 -5
  3. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth_support/createsuperuser.py +9 -5
  4. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth_support/management/commands/createsuperuser.py +5 -1
  5. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth_support/receiver.py +3 -2
  6. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth_support/utils.py +3 -1
  7. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/celery.py +7 -3
  8. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/development/celery.py +5 -0
  9. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/testing/minio_storage.py +3 -1
  10. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/.gitignore +0 -0
  11. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/LICENSE +0 -0
  12. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/README.md +0 -0
  13. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/__init__.py +0 -0
  14. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/_env.py +0 -0
  15. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth.py +0 -0
  16. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth_support/__init__.py +0 -0
  17. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth_support/adapter.py +0 -0
  18. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/allauth_support/apps.py +0 -0
  19. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/development/__init__.py +0 -0
  20. {django_resonant_settings-0.29/resonant_settings → django_resonant_settings-0.32.1/resonant_settings/development}/debug_toolbar.py +0 -0
  21. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/django.py +0 -0
  22. /django_resonant_settings-0.29/resonant_settings/development/extensions.py → /django_resonant_settings-0.32.1/resonant_settings/django_extensions.py +0 -0
  23. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/logging.py +0 -0
  24. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/oauth_toolkit.py +0 -0
  25. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/production/__init__.py +0 -0
  26. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/production/email.py +0 -0
  27. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/production/https.py +0 -0
  28. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/production/s3_storage.py +0 -0
  29. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/py.typed +0 -0
  30. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/rest_framework.py +0 -0
  31. {django_resonant_settings-0.29 → django_resonant_settings-0.32.1}/resonant_settings/testing/__init__.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-resonant-settings
3
- Version: 0.29
3
+ Version: 0.32.1
4
4
  Summary: Shared Django settings for Resonant applications.
5
5
  Project-URL: Repository, https://github.com/kitware-resonant/cookiecutter-resonant
6
6
  Project-URL: Bug Reports, https://github.com/kitware-resonant/cookiecutter-resonant/issues
7
7
  Maintainer-email: "Kitware, Inc." <kitware@kitware.com>
8
- License: Apache 2.0
8
+ License-Expression: Apache-2.0
9
9
  License-File: LICENSE
10
10
  Keywords: django,resonant,setting,settings
11
11
  Classifier: Development Status :: 3 - Alpha
@@ -13,8 +13,8 @@ Classifier: Environment :: Web Environment
13
13
  Classifier: Framework :: Django
14
14
  Classifier: Framework :: Django :: 5
15
15
  Classifier: Framework :: Django :: 5.1
16
+ Classifier: Framework :: Django :: 5.2
16
17
  Classifier: Intended Audience :: Developers
17
- Classifier: License :: OSI Approved :: Apache Software License
18
18
  Classifier: Operating System :: OS Independent
19
19
  Classifier: Programming Language :: Python
20
20
  Classifier: Programming Language :: Python :: 3
@@ -26,6 +26,8 @@ Requires-Python: >=3.10
26
26
  Requires-Dist: django-environ
27
27
  Provides-Extra: allauth
28
28
  Requires-Dist: django-allauth; extra == 'allauth'
29
+ Provides-Extra: celery
30
+ Requires-Dist: celery; extra == 'celery'
29
31
  Description-Content-Type: text/markdown
30
32
 
31
33
  # django-resonant-settings
@@ -7,7 +7,8 @@ name = "django-resonant-settings"
7
7
  description = "Shared Django settings for Resonant applications."
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.10"
10
- license = { text = "Apache 2.0" }
10
+ license = "Apache-2.0"
11
+ license-files = ["LICENSE"]
11
12
  maintainers = [{ name = "Kitware, Inc.", email = "kitware@kitware.com" }]
12
13
  keywords = [
13
14
  "django",
@@ -20,9 +21,9 @@ classifiers = [
20
21
  "Environment :: Web Environment",
21
22
  "Framework :: Django :: 5",
22
23
  "Framework :: Django :: 5.1",
24
+ "Framework :: Django :: 5.2",
23
25
  "Framework :: Django",
24
26
  "Intended Audience :: Developers",
25
- "License :: OSI Approved :: Apache Software License",
26
27
  "Operating System :: OS Independent",
27
28
  "Programming Language :: Python :: 3",
28
29
  "Programming Language :: Python :: 3.10",
@@ -36,14 +37,40 @@ dependencies = [
36
37
  ]
37
38
  dynamic = ["version"]
38
39
 
40
+ [project.urls]
41
+ Repository = "https://github.com/kitware-resonant/cookiecutter-resonant"
42
+ "Bug Reports" = "https://github.com/kitware-resonant/cookiecutter-resonant/issues"
43
+
39
44
  [project.optional-dependencies]
40
45
  allauth = [
41
46
  "django-allauth",
42
47
  ]
48
+ celery = [
49
+ "celery",
50
+ ]
43
51
 
44
- [project.urls]
45
- Repository = "https://github.com/kitware-resonant/cookiecutter-resonant"
46
- "Bug Reports" = "https://github.com/kitware-resonant/cookiecutter-resonant/issues"
52
+ [dependency-groups]
53
+ dev = [
54
+ "tox",
55
+ "tox-uv",
56
+ ]
57
+ lint = [
58
+ "flake8",
59
+ "flake8-black",
60
+ "flake8-bugbear",
61
+ "flake8-docstrings",
62
+ "flake8-isort",
63
+ "pep8-naming",
64
+ ]
65
+ format = [
66
+ "black",
67
+ "isort",
68
+ ]
69
+ type = [
70
+ "mypy",
71
+ "celery-types",
72
+ "django-stubs[compatible-mypy]",
73
+ ]
47
74
 
48
75
  [tool.hatch.build]
49
76
  packages = [
@@ -70,7 +97,11 @@ combine_as_imports = true
70
97
  files = [
71
98
  "resonant_settings",
72
99
  ]
100
+ check_untyped_defs = true
73
101
  show_error_codes = true
102
+ warn_redundant_casts = true
103
+ warn_unused_configs = true
104
+ warn_unused_ignores = true
74
105
 
75
106
  [[tool.mypy.overrides]]
76
107
  module = [
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import ClassVar
3
+ from typing import Any, ClassVar
4
4
 
5
5
  from django.contrib.auth.management.commands import createsuperuser
6
6
  from django.contrib.auth.models import User, UserManager
@@ -9,12 +9,14 @@ from resonant_settings.allauth_support.utils import temporarily_change_attribute
9
9
 
10
10
 
11
11
  class Command(createsuperuser.Command):
12
- def __init__(self, *args, **kwargs):
12
+ def __init__(self, *args: Any, **kwargs: Any):
13
13
  super().__init__(*args, **kwargs)
14
14
  self.UserModel = EmailAsUsernameProxyUser
15
15
  self.username_field = self.UserModel._meta.get_field(self.UserModel.USERNAME_FIELD)
16
16
 
17
- def _validate_username(self, username, verbose_field_name, database):
17
+ def _validate_username(
18
+ self, username: str, verbose_field_name: str, database: str
19
+ ) -> str | None:
18
20
  # Since "username" is actually unique, "email" (i.e. "self.username_field") is logically
19
21
  # unique too. Explicitly setting the "_unique" attribute ensures that app-level duplicate
20
22
  # checking is done by "_validate_username", which produces better, earlier error messages.
@@ -23,7 +25,9 @@ class Command(createsuperuser.Command):
23
25
  with temporarily_change_attributes(self.username_field, _unique=True):
24
26
  # Normalize (as it would be done before saving) for better duplicate detection
25
27
  username = self.UserModel.normalize_username(username)
26
- return super()._validate_username(username, verbose_field_name, database)
28
+ return super()._validate_username( # type: ignore[misc]
29
+ username, verbose_field_name, database
30
+ )
27
31
 
28
32
 
29
33
  class EmailAsUsernameProxyUserManager(UserManager):
@@ -33,7 +37,7 @@ class EmailAsUsernameProxyUserManager(UserManager):
33
37
  username: str | None = None,
34
38
  email: str | None = None,
35
39
  password: str | None = None,
36
- **extra_fields,
40
+ **extra_fields: Any,
37
41
  ) -> EmailAsUsernameProxyUser:
38
42
  # Practically, email will always be provided
39
43
  assert email
@@ -15,8 +15,12 @@ When Allauth is configured to use a User's `email` as the `username`, override t
15
15
  management command to only prompt for an email address.
16
16
  """
17
17
 
18
+ username_required: bool | None = allauth_settings.SIGNUP_FIELDS.get("username", {}).get(
19
+ "required", None
20
+ )
21
+
18
22
  # If using email as username
19
- if not allauth_settings.USERNAME_REQUIRED:
23
+ if not username_required:
20
24
  # Expose the modified command
21
25
  Command: type[BaseCommand] = allauth_support_createsuperuser.Command
22
26
  user_model: type[AbstractUser] = allauth_support_createsuperuser.EmailAsUsernameProxyUser
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from typing import Any
2
3
 
3
4
  from allauth.account.models import EmailAddress
4
5
  from django.contrib.auth.models import AbstractUser
@@ -10,8 +11,8 @@ def verify_email_address_on_user_post_save(
10
11
  sender: type[AbstractUser],
11
12
  instance: AbstractUser,
12
13
  created: bool,
13
- **kwargs,
14
- ):
14
+ **kwargs: Any,
15
+ ) -> None:
15
16
  """Automatically verify email addresses of newly created superusers."""
16
17
  # These should always be true, but it's a final sanity check
17
18
  if created and instance.is_superuser:
@@ -1,9 +1,11 @@
1
+ from collections.abc import Generator
1
2
  from contextlib import contextmanager
3
+ from typing import Any
2
4
 
3
5
 
4
6
  # From https://stackoverflow.com/a/38532086
5
7
  @contextmanager
6
- def temporarily_change_attributes(something, **kwargs):
8
+ def temporarily_change_attributes(something: object, **kwargs: Any) -> Generator[None]:
7
9
  previous_values = {k: getattr(something, k) for k in kwargs}
8
10
  for k, v in kwargs.items():
9
11
  setattr(something, k, v)
@@ -7,6 +7,8 @@ Configure Celery with the following features:
7
7
  This requires the `celery` package to be installed.
8
8
  """
9
9
 
10
+ import celery.app.trace # type: ignore[import-not-found]
11
+
10
12
  from resonant_settings._env import env
11
13
 
12
14
  # Assume AMQP.
@@ -45,9 +47,6 @@ CELERY_TASK_ACKS_ON_FAILURE_OR_TIMEOUT = True
45
47
  # and this will be Celery's default in 6.0.
46
48
  CELERY_WORKER_CANCEL_LONG_RUNNING_TASKS_ON_CONNECTION_LOSS = True
47
49
 
48
- # This is the default, but is necessary to suppress warnings in Celery
49
- CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
50
-
51
50
  # CloudAMQP-suggested settings
52
51
  # https://www.cloudamqp.com/docs/celery.html
53
52
  CELERY_BROKER_POOL_LIMIT = 1
@@ -65,3 +64,8 @@ CELERY_WORKER_PREFETCH_MULTIPLIER = 1
65
64
  # Accept the default of the number of CPU cores.
66
65
  # Workers running memory-intensive tasks may need to decrease this.
67
66
  CELERY_WORKER_CONCURRENCY: int | None = None
67
+
68
+ # Make the task received log message include the task's arguments.
69
+ celery.app.trace.LOG_RECEIVED = """\
70
+ Task %(name)s[%(id)s] received: (%(args)s, %(kwargs)s)\
71
+ """
@@ -1,7 +1,12 @@
1
+ from resonant_settings._env import env
2
+
1
3
  # Acknowledge early in development, which will help prevent failing or
2
4
  # long-running tasks from being started automatically every time the worker
3
5
  # process restarts; this more aggressively flushes the task queue.
4
6
  CELERY_TASK_ACKS_LATE = False
5
7
 
8
+ CELERY_TASK_ALWAYS_EAGER: bool = env.bool("DJANGO_CELERY_TASK_ALWAYS_EAGER", default=False)
9
+ CELERY_TASK_EAGER_PROPAGATES = CELERY_TASK_ALWAYS_EAGER
10
+
6
11
  # In development, run without concurrency.
7
12
  CELERY_WORKER_CONCURRENCY: int | None = 1
@@ -22,5 +22,7 @@ MINIO_STORAGE_MEDIA_BUCKET_NAME = minio_url.path.lstrip("/")
22
22
  MINIO_STORAGE_MEDIA_URL: str | None = env.str("DJANGO_MINIO_STORAGE_MEDIA_URL", default=None)
23
23
 
24
24
  MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True
25
- MINIO_STORAGE_AUTO_CREATE_MEDIA_POLICY = "READ_WRITE"
25
+ # Make the bucket private to the public
26
+ MINIO_STORAGE_AUTO_CREATE_MEDIA_POLICY = "NONE"
27
+ # Issue signed URLs to provide any read access
26
28
  MINIO_STORAGE_MEDIA_USE_PRESIGNED = True