diff --git a/.tool-versions b/.tool-versions index 94ec5a45..abb528da 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ -python 3.10.14 +python 3.12.4 poetry 1.8.3 nodejs 16.20.2 diff --git a/Dockerfile b/Dockerfile index 5de70dd4..59435394 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # TODO: -# - Consider python:3.10-slim +# - Consider python:3.12-slim # - Once dropping legacy AngularJS, build FE bundles separately # Things needed to use this in production: @@ -7,7 +7,7 @@ # - Ensure that Celery works as well # - Run WSGI with an ENTRYPOINT -FROM ubuntu:22.04 AS build +FROM ubuntu:24.04 AS build WORKDIR /app/ @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ locales \ # Postgres client (for accessing RDS in production) \ postgresql-client postgresql-contrib libpq-dev \ - python3.10 python3-dev python3-pip \ + python3.12 python3-dev python3-pip \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/poetry.lock b/poetry.lock index 79c7c518..96061899 100644 --- a/poetry.lock +++ b/poetry.lock @@ -26,10 +26,8 @@ files = [ ] [package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] @@ -47,9 +45,6 @@ files = [ {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, ] -[package.dependencies] -typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} - [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] @@ -64,9 +59,6 @@ files = [ {file = "astroid-3.2.2.tar.gz", hash = "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - [[package]] name = "asttokens" version = "2.4.1" @@ -729,7 +721,6 @@ files = [ asgiref = "*" django = "*" django-stubs-ext = ">=5.0.2" -tomli = {version = "*", markers = "python_version < \"3.11\""} types-PyYAML = "*" typing-extensions = ">=4.11.0" @@ -764,20 +755,6 @@ files = [ {file = "django_webpack_loader-1.8.1-py2.py3-none-any.whl", hash = "sha256:2d50a902256cf94bdd87eac3e7687989c9aa757a63af21db68773115216cedee"}, ] -[[package]] -name = "exceptiongroup" -version = "1.2.1" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "executing" version = "2.0.1" @@ -1005,9 +982,8 @@ files = [ ] [package.dependencies] -decorator = {version = "*", markers = "python_version > \"3.6\""} -ipython = {version = ">=7.31.1", markers = "python_version > \"3.6\""} -tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < \"3.11\""} +decorator = {version = "*", markers = "python_version >= \"3.11\""} +ipython = {version = ">=7.31.1", markers = "python_version >= \"3.11\""} [[package]] name = "ipython" @@ -1023,7 +999,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} @@ -1031,7 +1006,6 @@ prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5.13.0" -typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} [package.extras] all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] @@ -1360,7 +1334,6 @@ files = [ [package.dependencies] mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = ">=4.1.0" [package.extras] @@ -1642,15 +1615,10 @@ files = [ [package.dependencies] astroid = ">=3.2.2,<=3.3.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, -] +dill = {version = ">=0.3.7", markers = "python_version >= \"3.12\""} isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" [package.extras] @@ -1670,11 +1638,9 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2.0" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -2012,17 +1978,6 @@ pure-eval = "*" [package.extras] tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "tomlkit" version = "0.12.5" @@ -2159,5 +2114,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.10.0" -content-hash = "7f6798435fbec82b834c582b9420cf70299b6daba3241e24757d35e1eea904f0" +python-versions = "^3.12.0" +content-hash = "efead7d5698bac8f07fdea95e1b02cb6a3d02c8fd562d126a5f64b355d377328" diff --git a/pyproject.toml b/pyproject.toml index fecf3764..e373068e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -134,7 +134,7 @@ ignore-names = [ # When poetry full supports PEP 621, should migrate more information here! # See: https://github.com/python-poetry/roadmap/issues/3 name = "ws" -requires-python = "~=3.10" # Keep in sync with Poetry +requires-python = "~=3.12" # Keep in sync with Poetry [tool.poetry] name = "ws" @@ -147,7 +147,7 @@ repository = "https://github.com/DavidCain/mitoc-trips/" authors = ["David Cain "] [tool.poetry.dependencies] -python = "^3.10.0" +python = "^3.12.0" [tool.poetry.group.prod.dependencies] Django = "^4.2" @@ -171,7 +171,6 @@ pwned-passwords-django = "*" requests = "*" sentry-sdk = "^1.30.0" setuptools = "^69.5.1" # Required by django-pipeline in prod! -typing-extensions = "^4.11.0" # Can remove after Python 3.11 [tool.poetry.group.test.dependencies] @@ -209,7 +208,7 @@ ipdb = { version = "*" } [tool.mypy] -python_version = "3.10" +python_version = "3.12" plugins = ["mypy_django_plugin.main"] # Better errors diff --git a/ws/api_views.py b/ws/api_views.py index 2894bc77..8f4542be 100644 --- a/ws/api_views.py +++ b/ws/api_views.py @@ -1,7 +1,7 @@ import json from collections.abc import Collection, Iterable, Iterator from datetime import date -from typing import Any, TypedDict, cast +from typing import Any, NotRequired, TypedDict, cast from zoneinfo import ZoneInfo import jwt @@ -18,7 +18,6 @@ from django.views.decorators.csrf import csrf_exempt from django.views.generic import DetailView, ListView, View from django.views.generic.detail import SingleObjectMixin -from typing_extensions import NotRequired import ws.utils.geardb as geardb_utils import ws.utils.membership as membership_utils diff --git a/ws/models.py b/ws/models.py index 9c223475..0ec24711 100644 --- a/ws/models.py +++ b/ws/models.py @@ -1,7 +1,7 @@ import re from collections.abc import Collection, Iterable, Iterator from datetime import date, datetime, timedelta -from typing import Any, Optional, cast +from typing import Any, Optional, Self, cast from urllib.parse import urlencode, urljoin from zoneinfo import ZoneInfo @@ -24,7 +24,6 @@ from mitoc_const import affiliations from mitoc_const.membership import RENEWAL_ALLOWED_WITH_DAYS_LEFT from phonenumber_field.modelfields import PhoneNumberField -from typing_extensions import Self import ws.utils.dates as date_utils from ws import enums diff --git a/ws/tasks.py b/ws/tasks.py index 6aee05d9..aae2ca90 100644 --- a/ws/tasks.py +++ b/ws/tasks.py @@ -1,7 +1,7 @@ import contextlib import logging from collections.abc import Iterator -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from time import monotonic import requests @@ -150,7 +150,7 @@ def update_member_stats( ) -> models.MembershipStats: cached = models.MembershipStats.load() acceptable_staleness = timedelta(seconds=acceptable_staleness_seconds) - now = datetime.now(timezone.utc) + now = datetime.now(UTC) if (now - cached.retrieved_at) > acceptable_staleness or not cached.response: response = geardb.query_api("/api-auth/v1/stats") diff --git a/ws/utils/member_stats.py b/ws/utils/member_stats.py index ed9ba491..1948f7a1 100644 --- a/ws/utils/member_stats.py +++ b/ws/utils/member_stats.py @@ -3,13 +3,12 @@ import enum import logging from datetime import datetime, timedelta -from typing import TYPE_CHECKING, Any, NamedTuple +from typing import TYPE_CHECKING, Any, NamedTuple, assert_never from allauth.account.models import EmailAddress from django.db.models import Count, Exists, OuterRef from django.db.models.functions import Lower from mitoc_const import affiliations -from typing_extensions import assert_never from ws import models, tasks