Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Python 3.8 and 3.9 support, add 3.11 and 3.12 support #194

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
4 changes: 1 addition & 3 deletions composed_configuration/_allauth.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from ._base import ComposedConfiguration, ConfigMixin


Expand All @@ -11,7 +9,7 @@ class AllauthMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += [
'django.contrib.sites',
'allauth',
Expand Down
10 changes: 5 additions & 5 deletions composed_configuration/_allauth_support/createsuperuser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import ClassVar, List, Optional
from typing import ClassVar

from django.contrib.auth.management.commands import createsuperuser
from django.contrib.auth.models import User, UserManager
Expand Down Expand Up @@ -30,9 +30,9 @@ class EmailAsUsernameProxyUserManager(UserManager):
# This version of "create_superuser" makes the "username" argument optional
def create_superuser(
self,
username: Optional[str] = None,
email: Optional[str] = None,
password: Optional[str] = None,
username: str | None = None,
email: str | None = None,
password: str | None = None,
**extra_fields,
) -> EmailAsUsernameProxyUser:
# Practically, email will always be provided
Expand All @@ -55,7 +55,7 @@ class Meta(User.Meta):

# Don't include "email" in "REQUIRED_FIELDS", to prevent adding that field twice to the
# "createsuperuser.Command" argument parser
REQUIRED_FIELDS: ClassVar[List[str]] = []
REQUIRED_FIELDS: ClassVar[list[str]] = []

@classmethod
def normalize_username(cls, username: str) -> str:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Type, cast
from typing import cast

from allauth.account import app_settings as allauth_settings
from django.contrib.auth import get_user_model
Expand All @@ -20,13 +20,13 @@
# If using email as username
if not allauth_settings.USERNAME_REQUIRED:
# Expose the modified command
Command: Type[BaseCommand] = allauth_support_createsuperuser.Command
user_model: Type[AbstractUser] = allauth_support_createsuperuser.EmailAsUsernameProxyUser
Command: type[BaseCommand] = allauth_support_createsuperuser.Command
user_model: type[AbstractUser] = allauth_support_createsuperuser.EmailAsUsernameProxyUser

else:
# Expose the pristine upstream version of the command
Command = django_createsuperuser.Command
user_model = cast(Type[AbstractUser], get_user_model())
user_model = cast(type[AbstractUser], get_user_model())

# Always automatically verify email addresses of newly created superusers
post_save.connect(verify_email_address_on_user_post_save, sender=user_model)
3 changes: 1 addition & 2 deletions composed_configuration/_allauth_support/receiver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from typing import Type

from allauth.account.models import EmailAddress
from django.contrib.auth.models import AbstractUser
Expand All @@ -8,7 +7,7 @@


def verify_email_address_on_user_post_save(
sender: Type[AbstractUser],
sender: type[AbstractUser],
instance: AbstractUser,
created: bool,
**kwargs,
Expand Down
3 changes: 1 addition & 2 deletions composed_configuration/_base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import contextlib
from typing import Type
import warnings

from configurations import Configuration, values
Expand Down Expand Up @@ -62,7 +61,7 @@ class ConfigMixin:
"""Abstract mixin for composable Config sections."""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
"""
Mutate the configuration before values are fully bound with environment variables.
Expand Down
6 changes: 2 additions & 4 deletions composed_configuration/_configuration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import List, Optional, Tuple

from configurations import values

from ._allauth import AllauthMixin
Expand Down Expand Up @@ -68,7 +66,7 @@ class TestingBaseConfiguration(MinioStorageMixin, _BaseConfiguration):
SECRET_KEY = 'testingsecret'

# Testing will add 'testserver' to ALLOWED_HOSTS
ALLOWED_HOSTS: List[str] = []
ALLOWED_HOSTS: list[str] = []

MINIO_STORAGE_MEDIA_BUCKET_NAME = 'test-django-storage'

Expand Down Expand Up @@ -97,7 +95,7 @@ class _HerokuMixin:
environ_name='CLOUDAMQP_URL', environ_prefix=None, environ_required=True
)
# https://help.heroku.com/J2R1S4T8/can-heroku-force-an-application-to-use-ssl-tls
SECURE_PROXY_SSL_HEADER: Optional[Tuple[str, str]] = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_PROXY_SSL_HEADER: tuple[str, str] | None = ('HTTP_X_FORWARDED_PROTO', 'https')
# This may be provided by https://github.com/ianpurvis/heroku-buildpack-version or similar
# The commit SHA is the preferred release tag for Git-based projects:
# https://docs.sentry.io/platforms/python/configuration/releases/#bind-the-version
Expand Down
4 changes: 1 addition & 3 deletions composed_configuration/_cors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from configurations import values

from ._base import ComposedConfiguration, ConfigMixin
Expand All @@ -18,7 +16,7 @@ class CorsMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += ['corsheaders']

# CorsMiddleware must be added immediately before WhiteNoiseMiddleware, so this can
Expand Down
4 changes: 1 addition & 3 deletions composed_configuration/_database.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from configurations import values

from ._base import ComposedConfiguration, ConfigMixin
Expand All @@ -16,7 +14,7 @@ class DatabaseMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += ['django.contrib.postgres']

# This cannot have a default value, since the password and database
Expand Down
4 changes: 1 addition & 3 deletions composed_configuration/_debug.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from ._base import ComposedConfiguration, ConfigMixin


Expand All @@ -11,7 +9,7 @@ class DebugMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += ['debug_toolbar']

# Include Debug Toolbar middleware as early as possible in the list.
Expand Down
4 changes: 2 additions & 2 deletions composed_configuration/_django.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import NoReturn, Type
from typing import NoReturn

from configurations import values

Expand All @@ -21,7 +21,7 @@ class DjangoMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
# These are often extended, so update their values to avoid fragility due to mixin ordering
configuration.INSTALLED_APPS += [
'django.contrib.admin',
Expand Down
2 changes: 1 addition & 1 deletion composed_configuration/_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def _is_docker() -> bool:
return False


class _AlwaysContains(object):
class _AlwaysContains:
"""An object which always returns True for `x in _AlwaysContains()` operations."""

def __contains__(self, item) -> bool:
Expand Down
6 changes: 3 additions & 3 deletions composed_configuration/_email.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, Type, cast
from typing import cast

from configurations import values

Expand All @@ -23,9 +23,9 @@ class SmtpEmailMixin(_EmailMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
email = cast(
Dict[str, str],
dict[str, str],
values.EmailURLValue(
environ_name='EMAIL_URL',
environ_prefix='DJANGO',
Expand Down
4 changes: 1 addition & 3 deletions composed_configuration/_extensions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from ._base import ComposedConfiguration, ConfigMixin


Expand All @@ -11,7 +9,7 @@ class ExtensionsMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += ['django_extensions']

SHELL_PLUS_PRINT_SQL = True
Expand Down
4 changes: 1 addition & 3 deletions composed_configuration/_filter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from ._base import ComposedConfiguration, ConfigMixin


Expand All @@ -11,5 +9,5 @@ class FilterMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += ['django_filters']
4 changes: 1 addition & 3 deletions composed_configuration/_girder_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from ._base import ComposedConfiguration, ConfigMixin


Expand All @@ -11,5 +9,5 @@ class GirderUtilsMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += ['girder_utils']
4 changes: 1 addition & 3 deletions composed_configuration/_https.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Optional, Tuple

from ._base import ConfigMixin


Expand All @@ -9,7 +7,7 @@ class HttpsMixin(ConfigMixin):
SECURE_SSL_REDIRECT = True

# This must be set when deployed behind a proxy
SECURE_PROXY_SSL_HEADER: Optional[Tuple[str, str]] = None
SECURE_PROXY_SSL_HEADER: tuple[str, str] | None = None

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Expand Down
3 changes: 1 addition & 2 deletions composed_configuration/_logging.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from typing import Optional

from django.http import HttpRequest

Expand All @@ -8,7 +7,7 @@

def _filter_favicon_requests(record: logging.LogRecord) -> bool:
if record.name == 'django.request':
request: Optional[HttpRequest] = getattr(record, 'request', None)
request: HttpRequest | None = getattr(record, 'request', None)
if request and request.path == '/favicon.ico':
return False

Expand Down
8 changes: 4 additions & 4 deletions composed_configuration/_rest_framework.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Dict, Type
from typing import Any

from ._base import ComposedConfiguration, ConfigMixin

Expand All @@ -12,7 +12,7 @@ class RestFrameworkMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += [
'rest_framework',
'rest_framework.authtoken',
Expand Down Expand Up @@ -106,12 +106,12 @@ def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
'REFRESH_TOKEN_EXPIRE_SECONDS': 30 * 24 * 60 * 60,
}

SWAGGER_SETTINGS: Dict[str, Any] = {
SWAGGER_SETTINGS: dict[str, Any] = {
# The default security definition ("basic") is not supported by this DRF configuration,
# so expect all logins to come via the Django session, which there's no OpenAPI
# security definition for.
'SECURITY_DEFINITIONS': None,
'USE_SESSION_AUTH': True,
}

REDOC_SETTINGS: Dict[str, Any] = {}
REDOC_SETTINGS: dict[str, Any] = {}
4 changes: 1 addition & 3 deletions composed_configuration/_sentry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Type

from configurations import values

from ._base import ComposedConfiguration, ConfigMixin
Expand All @@ -18,7 +16,7 @@ class SentryMixin(ConfigMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += [
'composed_configuration.sentry.apps.SentryConfig',
]
Expand Down
5 changes: 2 additions & 3 deletions composed_configuration/_static.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from pathlib import Path
from typing import Type

from ._base import ComposedConfiguration, ConfigMixin
from ._values import DirectoryPathValue
Expand Down Expand Up @@ -41,7 +40,7 @@ def STATIC_ROOT(self): # noqa: N802
)

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
configuration.INSTALLED_APPS += ['django.contrib.staticfiles']


Expand All @@ -53,7 +52,7 @@ class WhitenoiseStaticFileMixin(StaticFileMixin):
"""

@staticmethod
def mutate_configuration(configuration: Type[ComposedConfiguration]) -> None:
def mutate_configuration(configuration: type[ComposedConfiguration]) -> None:
# Insert immediately before staticfiles app
staticfiles_index = configuration.INSTALLED_APPS.index('django.contrib.staticfiles')
configuration.INSTALLED_APPS.insert(staticfiles_index, 'whitenoise.runserver_nostatic')
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[tool.black]
line-length = 100
skip-string-normalization = true
target-version = ["py38"]
target-version = ["py310"]
exclude='\.eggs|\.git|\.mypy_cache|\.tox|\.venv|_build|buck-out|build|dist'

[tool.isort]
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@
'License :: OSI Approved :: Apache Software License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python',
],
python_requires='>=3.8',
python_requires='>=3.10',
install_requires=[
'django-configurations[database,email]',
],
Expand Down