From 4feab56d25b1d8d90102977d9281878d54ca79e6 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Tue, 3 Dec 2024 22:02:57 +0000 Subject: [PATCH 1/4] update 3.10 -> 3.12 --- .devcontainer/Dockerfile | 4 ++-- .devcontainer/devcontainer.json | 2 +- .github/workflows/partial-backend.yml | 2 +- .github/workflows/scheduled-checks.yml | 2 +- docker/Dockerfile | 2 +- .../contributors/developers-guide/starting-dev-server.md | 2 +- pyproject.toml | 8 ++++---- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index cbac5071bd3..07fd5786ea0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,8 +1,8 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.224.2/containers/python-3/.devcontainer/base.Dockerfile # [Choice] Python version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.10, 3.9, 3.8, 3.7, 3.6, 3-bullseye, 3.10-bullseye, 3.9-bullseye, 3.8-bullseye, 3.7-bullseye, 3.6-bullseye, 3-buster, 3.10-buster, 3.9-buster, 3.8-buster, 3.7-buster, 3.6-buster -ARG VARIANT="3.10-bullseye" -FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} +ARG VARIANT="3.12-bullseye" +FROM mcr.microsoft.com/devcontainers/python:${VARIANT} # [Choice] Node.js version: none, lts/*, 16, 14, 12, 10 ARG NODE_VERSION="none" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fed52b1888e..31d8f34277e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,7 +9,7 @@ // Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6 // Append -bullseye or -buster to pin to an OS version. // Use -bullseye variants on local on arm64/Apple Silicon. - "VARIANT": "3.10-bullseye", + "VARIANT": "3.12-bullseye", // Options "NODE_VERSION": "16" } diff --git a/.github/workflows/partial-backend.yml b/.github/workflows/partial-backend.yml index fae5dfd8b61..b0772d18144 100644 --- a/.github/workflows/partial-backend.yml +++ b/.github/workflows/partial-backend.yml @@ -47,7 +47,7 @@ jobs: - name: Set up python uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - name: Install Poetry uses: snok/install-poetry@v1 diff --git a/.github/workflows/scheduled-checks.yml b/.github/workflows/scheduled-checks.yml index 0134d60cd51..3379074183b 100644 --- a/.github/workflows/scheduled-checks.yml +++ b/.github/workflows/scheduled-checks.yml @@ -18,7 +18,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - name: Set PY shell: bash diff --git a/docker/Dockerfile b/docker/Dockerfile index 6c9c09066ee..e91c6596255 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -17,7 +17,7 @@ RUN yarn generate ############################################### # Base Image - Python ############################################### -FROM python:3.10-slim as python-base +FROM python:3.12-slim as python-base ENV MEALIE_HOME="/app" diff --git a/docs/docs/contributors/developers-guide/starting-dev-server.md b/docs/docs/contributors/developers-guide/starting-dev-server.md index d17772473ab..4edac0b185c 100644 --- a/docs/docs/contributors/developers-guide/starting-dev-server.md +++ b/docs/docs/contributors/developers-guide/starting-dev-server.md @@ -32,7 +32,7 @@ Make sure the VSCode Dev Containers extension is installed, then select "Dev Con ### Prerequisites -- [Python 3.10](https://www.python.org/downloads/) +- [Python 3.12](https://www.python.org/downloads/) - [Poetry](https://python-poetry.org/docs/#installation) - [Node v16.x](https://nodejs.org/en/) - [yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable) diff --git a/pyproject.toml b/pyproject.toml index 73c86eca939..ecd15f6da60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ orjson = "^3.8.0" psycopg2-binary = { version = "^2.9.1", optional = true } pydantic = "^2.6.1" pyhumps = "^3.5.3" -python = "^3.10" +python = "^3.12" python-dateutil = "^2.8.2" python-dotenv = "^1.0.0" python-ldap = "^3.3.1" @@ -105,7 +105,7 @@ pgsql = ["psycopg2-binary"] follow_imports = "skip" ignore_missing_imports = true plugins = "pydantic.mypy" -python_version = "3.10" +python_version = "3.12" strict_optional = true [tool.ruff] @@ -135,8 +135,8 @@ exclude = [ "venv", ] -# Assume Python 3.10. -target-version = "py310" +# Assume Python 3.12. +target-version = "py312" [tool.ruff.lint] # Enable Pyflakes `E` and `F` codes by default. From de9b847b6b68f140899226c1ac855f8b33e641e5 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Tue, 3 Dec 2024 22:03:30 +0000 Subject: [PATCH 2/4] update lock --- poetry.lock | 117 +++++++++++++++++++--------------------------------- 1 file changed, 42 insertions(+), 75 deletions(-) diff --git a/poetry.lock b/poetry.lock index 45f414fa323..f4f4a951bcd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "aiofiles" @@ -67,7 +67,6 @@ files = [ ] [package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" @@ -117,9 +116,6 @@ files = [ {file = "astroid-3.3.5.tar.gz", hash = "sha256:5cfc40ae9f68311075d27ef68a4841bdc5cc7f6cf86671b49f00607d30188e2d"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - [[package]] name = "authlib" version = "1.3.2" @@ -565,13 +561,13 @@ graph = ["objgraph (>=1.7.2)"] [[package]] name = "distlib" -version = "0.3.6" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -585,20 +581,6 @@ files = [ {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, ] -[[package]] -name = "exceptiongroup" -version = "1.1.0" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "extruct" version = "0.18.0" @@ -645,18 +627,19 @@ standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "htt [[package]] name = "filelock" -version = "3.9.0" +version = "3.16.1" description = "A platform independent file lock." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, - {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "freezegun" @@ -1549,7 +1532,6 @@ files = [ [package.dependencies] mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = ">=4.6.0" [package.extras] @@ -1911,18 +1893,19 @@ tests-min = ["defusedxml", "packaging", "pytest"] [[package]] name = "platformdirs" -version = "2.6.2" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, - {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -2295,15 +2278,10 @@ files = [ [package.dependencies] astroid = ">=3.3.5,<=3.4.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] @@ -2371,11 +2349,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" -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"] @@ -2838,7 +2814,6 @@ files = [ [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] @@ -2872,19 +2847,23 @@ files = [ [[package]] name = "setuptools" -version = "67.1.0" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "setuptools-67.1.0-py3-none-any.whl", hash = "sha256:a7687c12b444eaac951ea87a9627c4f904ac757e7abdc5aac32833234af90378"}, - {file = "setuptools-67.1.0.tar.gz", hash = "sha256:e261cdf010c11a41cb5cb5f1bf3338a7433832029f559a6a7614bd42a967c300"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "six" @@ -3042,17 +3021,6 @@ files = [ {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, ] -[[package]] -name = "tomli" -version = "1.2.3" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.6" -files = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] - [[package]] name = "tomlkit" version = "0.11.6" @@ -3198,7 +3166,6 @@ h11 = ">=0.8" httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} @@ -3252,23 +3219,23 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" [[package]] name = "virtualenv" -version = "20.17.1" +version = "20.28.0" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.17.1-py3-none-any.whl", hash = "sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4"}, - {file = "virtualenv-20.17.1.tar.gz", hash = "sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058"}, + {file = "virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0"}, + {file = "virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa"}, ] [package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<3" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"] -testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "w3lib" @@ -3445,5 +3412,5 @@ pgsql = ["psycopg2-binary"] [metadata] lock-version = "2.0" -python-versions = "^3.10" -content-hash = "55dbb0d6a3e28964743f87ae1d3a4ead8428cf1051ea97839edb325f39c526ba" +python-versions = "^3.12" +content-hash = "70a06c4bc96fda6284e61a84db5770d969ea06e78caaa5860966b53768607929" From 58402372c46172011f9001f5b50d32bc530050d2 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Tue, 3 Dec 2024 22:12:48 +0000 Subject: [PATCH 3/4] lint datetime.timezone.utc -> datetime.UTC --- mealie/core/release_checker.py | 4 ++-- mealie/core/security/providers/auth_provider.py | 4 ++-- mealie/core/security/security.py | 4 ++-- mealie/core/settings/settings.py | 4 ++-- mealie/db/models/_model_utils/datetime.py | 10 +++++----- mealie/db/models/household/shopping_list.py | 4 ++-- mealie/db/models/household/webhooks.py | 4 ++-- mealie/db/models/recipe/recipe.py | 4 ++-- mealie/db/models/recipe/recipe_timeline.py | 4 ++-- mealie/db/models/recipe/shared.py | 4 ++-- mealie/repos/repository_generic.py | 4 ++-- mealie/repos/repository_meals.py | 4 ++-- mealie/repos/repository_recipes.py | 3 +-- mealie/routes/households/controller_webhooks.py | 4 ++-- mealie/schema/_mealie/datetime_parse.py | 8 ++++---- mealie/schema/_mealie/mealie_model.py | 7 +++---- mealie/schema/household/webhook.py | 2 +- mealie/schema/recipe/recipe_share_token.py | 4 ++-- mealie/schema/recipe/recipe_timeline_events.py | 4 ++-- mealie/schema/user/user.py | 4 ++-- mealie/services/backups_v2/backup_v2.py | 4 ++-- .../services/event_bus_service/event_bus_listeners.py | 6 +++--- mealie/services/event_bus_service/event_types.py | 4 ++-- mealie/services/exporter/exporter.py | 2 +- mealie/services/migrations/copymethat.py | 4 ++-- mealie/services/recipe/recipe_service.py | 4 ++-- mealie/services/scheduler/scheduler_service.py | 4 ++-- .../services/scheduler/tasks/create_timeline_events.py | 6 +++--- mealie/services/scheduler/tasks/post_webhooks.py | 8 ++++---- mealie/services/scheduler/tasks/purge_group_exports.py | 4 ++-- .../services/scheduler/tasks/purge_password_reset.py | 2 +- mealie/services/scheduler/tasks/purge_registration.py | 2 +- mealie/services/user_services/user_service.py | 4 ++-- 33 files changed, 71 insertions(+), 73 deletions(-) diff --git a/mealie/core/release_checker.py b/mealie/core/release_checker.py index 53afa3fba61..b5d2bf9e2e5 100644 --- a/mealie/core/release_checker.py +++ b/mealie/core/release_checker.py @@ -3,7 +3,7 @@ import requests -_LAST_RESET = None +_LAST_RESET: datetime.datetime | None = None @lru_cache(maxsize=1) @@ -32,7 +32,7 @@ def get_latest_version() -> str: global _LAST_RESET - now = datetime.datetime.now(datetime.timezone.utc) + now = datetime.datetime.now(datetime.UTC) if not _LAST_RESET or now - _LAST_RESET > datetime.timedelta(days=MAX_DAYS_OLD): _LAST_RESET = now diff --git a/mealie/core/security/providers/auth_provider.py b/mealie/core/security/providers/auth_provider.py index 4c98879eb09..ce10afd7d75 100644 --- a/mealie/core/security/providers/auth_provider.py +++ b/mealie/core/security/providers/auth_provider.py @@ -1,5 +1,5 @@ import abc -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from typing import Generic, TypeVar import jwt @@ -45,7 +45,7 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None) -> t to_encode = data.copy() expires_delta = expires_delta or timedelta(hours=settings.TOKEN_TIME) - expire = datetime.now(timezone.utc) + expires_delta + expire = datetime.now(UTC) + expires_delta to_encode["exp"] = expire to_encode["iss"] = ISS diff --git a/mealie/core/security/security.py b/mealie/core/security/security.py index 34893cc1233..bdc364e55d6 100644 --- a/mealie/core/security/security.py +++ b/mealie/core/security/security.py @@ -1,5 +1,5 @@ import secrets -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path import jwt @@ -34,7 +34,7 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None) -> s to_encode = data.copy() expires_delta = expires_delta or timedelta(hours=settings.TOKEN_TIME) - expire = datetime.now(timezone.utc) + expires_delta + expire = datetime.now(UTC) + expires_delta to_encode["exp"] = expire return jwt.encode(to_encode, settings.SECRET, algorithm=ALGORITHM) diff --git a/mealie/core/settings/settings.py b/mealie/core/settings/settings.py index a0fb6e800bf..7558a29c51b 100644 --- a/mealie/core/settings/settings.py +++ b/mealie/core/settings/settings.py @@ -1,7 +1,7 @@ import logging import os import secrets -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from typing import Annotated, Any, NamedTuple @@ -160,7 +160,7 @@ def DAILY_SCHEDULE_TIME_UTC(self) -> ScheduleTime: local_tz = tzlocal() now = datetime.now(local_tz) local_time = now.replace(hour=local_hour, minute=local_minute) - utc_time = local_time.astimezone(timezone.utc) + utc_time = local_time.astimezone(UTC) self.logger.debug(f"Local time: {local_hour}:{local_minute} | UTC time: {utc_time.hour}:{utc_time.minute}") return ScheduleTime(utc_time.hour, utc_time.minute) diff --git a/mealie/db/models/_model_utils/datetime.py b/mealie/db/models/_model_utils/datetime.py index 5c24d1d526e..69222f8388b 100644 --- a/mealie/db/models/_model_utils/datetime.py +++ b/mealie/db/models/_model_utils/datetime.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from sqlalchemy.types import DateTime, TypeDecorator @@ -7,14 +7,14 @@ def get_utc_now(): """ Returns the current time in UTC. """ - return datetime.now(timezone.utc) + return datetime.now(UTC) def get_utc_today(): """ Returns the current date in UTC. """ - return datetime.now(timezone.utc).date() + return datetime.now(UTC).date() class NaiveDateTime(TypeDecorator): @@ -35,7 +35,7 @@ def process_bind_param(self, value: datetime | None, dialect): try: if value.tzinfo is not None: - value = value.astimezone(timezone.utc) + value = value.astimezone(UTC) return value.replace(tzinfo=None) except Exception: return value @@ -43,7 +43,7 @@ def process_bind_param(self, value: datetime | None, dialect): def process_result_value(self, value: datetime | None, dialect): try: if value is not None: - value = value.replace(tzinfo=timezone.utc) + value = value.replace(tzinfo=UTC) except Exception: pass diff --git a/mealie/db/models/household/shopping_list.py b/mealie/db/models/household/shopping_list.py index 02f60a56a18..f076107429a 100644 --- a/mealie/db/models/household/shopping_list.py +++ b/mealie/db/models/household/shopping_list.py @@ -1,5 +1,5 @@ from contextvars import ContextVar -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import TYPE_CHECKING, Optional from pydantic import ConfigDict @@ -227,7 +227,7 @@ def update_shopping_lists(session: orm.Session, _): if not shopping_list: continue - shopping_list.updated_at = datetime.now(timezone.utc) + shopping_list.updated_at = datetime.now(UTC) local_session.commit() except Exception: local_session.rollback() diff --git a/mealie/db/models/household/webhooks.py b/mealie/db/models/household/webhooks.py index 5b52f8ec636..9c8c6e58faf 100644 --- a/mealie/db/models/household/webhooks.py +++ b/mealie/db/models/household/webhooks.py @@ -1,4 +1,4 @@ -from datetime import datetime, time, timezone +from datetime import UTC, datetime, time from typing import TYPE_CHECKING, Optional from sqlalchemy import Boolean, ForeignKey, String, Time, orm @@ -30,7 +30,7 @@ class GroupWebhooksModel(SqlAlchemyBase, BaseMixins): # New Fields webhook_type: Mapped[str | None] = mapped_column(String, default="") # Future use for different types of webhooks - scheduled_time: Mapped[time | None] = mapped_column(Time, default=lambda: datetime.now(timezone.utc).time()) + scheduled_time: Mapped[time | None] = mapped_column(Time, default=lambda: datetime.now(UTC).time()) # Column is no longer used but is kept for since it's super annoying to # delete a column in SQLite and it's not a big deal to keep it around diff --git a/mealie/db/models/recipe/recipe.py b/mealie/db/models/recipe/recipe.py index ebbb0bfc963..60dc8c86f5c 100644 --- a/mealie/db/models/recipe/recipe.py +++ b/mealie/db/models/recipe/recipe.py @@ -1,4 +1,4 @@ -from datetime import date, datetime, timezone +from datetime import UTC, date, datetime from typing import TYPE_CHECKING import sqlalchemy as sa @@ -207,7 +207,7 @@ def __init__( if notes: self.notes = [Note(**n) for n in notes] - self.date_updated = datetime.now(timezone.utc) + self.date_updated = datetime.now(UTC) # SQLAlchemy events do not seem to register things that are set during auto_init if name is not None: diff --git a/mealie/db/models/recipe/recipe_timeline.py b/mealie/db/models/recipe/recipe_timeline.py index 402606e50b4..57fdc9f2212 100644 --- a/mealie/db/models/recipe/recipe_timeline.py +++ b/mealie/db/models/recipe/recipe_timeline.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import TYPE_CHECKING from sqlalchemy import ForeignKey, String @@ -48,4 +48,4 @@ def __init__( timestamp=None, **_, ) -> None: - self.timestamp = timestamp or datetime.now(timezone.utc) + self.timestamp = timestamp or datetime.now(UTC) diff --git a/mealie/db/models/recipe/shared.py b/mealie/db/models/recipe/shared.py index 9d90bcc1772..7f2634a576f 100644 --- a/mealie/db/models/recipe/shared.py +++ b/mealie/db/models/recipe/shared.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from typing import TYPE_CHECKING from uuid import uuid4 @@ -15,7 +15,7 @@ def defaut_expires_at_time() -> datetime: - return datetime.now(timezone.utc) + timedelta(days=30) + return datetime.now(UTC) + timedelta(days=30) class RecipeShareTokenModel(SqlAlchemyBase, BaseMixins): diff --git a/mealie/repos/repository_generic.py b/mealie/repos/repository_generic.py index 87d406d3bb4..50dfa801c49 100644 --- a/mealie/repos/repository_generic.py +++ b/mealie/repos/repository_generic.py @@ -2,7 +2,7 @@ import random from collections.abc import Iterable -from datetime import datetime, timezone +from datetime import UTC, datetime from math import ceil from typing import Any, Generic, TypeVar @@ -70,7 +70,7 @@ def household_id(self) -> UUID4 | None: return self._household_id def _random_seed(self) -> str: - return str(datetime.now(tz=timezone.utc)) + return str(datetime.now(tz=UTC)) def _log_exception(self, e: Exception) -> None: self.logger.error(f"Error processing query for Repo model={self.model.__name__} schema={self.schema.__name__}") diff --git a/mealie/repos/repository_meals.py b/mealie/repos/repository_meals.py index 34187e35fb4..ec6a35076a5 100644 --- a/mealie/repos/repository_meals.py +++ b/mealie/repos/repository_meals.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from sqlalchemy import select @@ -13,7 +13,7 @@ def get_today(self) -> list[ReadPlanEntry]: if not self.household_id: raise Exception("household_id not set") - today = datetime.now(tz=timezone.utc).date() + today = datetime.now(tz=UTC).date() stmt = select(GroupMealPlan).filter( GroupMealPlan.date == today, GroupMealPlan.household_id == self.household_id ) diff --git a/mealie/repos/repository_recipes.py b/mealie/repos/repository_recipes.py index 4b907ee3f58..0997902504f 100644 --- a/mealie/repos/repository_recipes.py +++ b/mealie/repos/repository_recipes.py @@ -1,7 +1,7 @@ import re as re from collections.abc import Sequence from random import randint -from typing import cast +from typing import Self, cast from uuid import UUID import sqlalchemy as sa @@ -10,7 +10,6 @@ from slugify import slugify from sqlalchemy import orm from sqlalchemy.exc import IntegrityError -from typing_extensions import Self from mealie.db.models.household.household import Household from mealie.db.models.recipe.category import Category diff --git a/mealie/routes/households/controller_webhooks.py b/mealie/routes/households/controller_webhooks.py index 8c8c25600d7..251bb36175a 100644 --- a/mealie/routes/households/controller_webhooks.py +++ b/mealie/routes/households/controller_webhooks.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from functools import cached_property from fastapi import APIRouter, BackgroundTasks, Depends @@ -45,7 +45,7 @@ def rerun_webhooks(self): """Manually re-fires all previously scheduled webhooks for today""" start_time = datetime.min.time() - start_dt = datetime.combine(datetime.now(timezone.utc).date(), start_time) + start_dt = datetime.combine(datetime.now(UTC).date(), start_time) post_group_webhooks(start_dt=start_dt, group_id=self.group.id, household_id=self.household.id) @router.get("/{item_id}", response_model=ReadWebhook) diff --git a/mealie/schema/_mealie/datetime_parse.py b/mealie/schema/_mealie/datetime_parse.py index 0e482d9a875..9e0042bc615 100644 --- a/mealie/schema/_mealie/datetime_parse.py +++ b/mealie/schema/_mealie/datetime_parse.py @@ -3,7 +3,7 @@ """ import re -from datetime import date, datetime, time, timedelta, timezone +from datetime import UTC, date, datetime, time, timedelta, timezone date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" time_expr = ( @@ -39,7 +39,7 @@ r"$" ) -EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc) +EPOCH = datetime(1970, 1, 1, tzinfo=UTC) # if greater than this, the number is in ms, if less than or equal it's in seconds # (in seconds this is 11th October 2603, in ms it's 20th August 1970) MS_WATERSHED = int(2e10) @@ -87,12 +87,12 @@ def from_unix_seconds(seconds: int | float) -> datetime: while abs(seconds) > MS_WATERSHED: seconds /= 1000 dt = EPOCH + timedelta(seconds=seconds) - return dt.replace(tzinfo=timezone.utc) + return dt.replace(tzinfo=UTC) def _parse_timezone(value: str | None, error: type[Exception]) -> None | int | timezone: if value == "Z": - return timezone.utc + return UTC elif value is not None: offset_mins = int(value[-2:]) if len(value) > 3 else 0 offset = 60 * int(value[1:3]) + offset_mins diff --git a/mealie/schema/_mealie/mealie_model.py b/mealie/schema/_mealie/mealie_model.py index 4f670ba2242..d7d70a6dcba 100644 --- a/mealie/schema/_mealie/mealie_model.py +++ b/mealie/schema/_mealie/mealie_model.py @@ -2,16 +2,15 @@ import re from collections.abc import Sequence -from datetime import datetime, timezone +from datetime import UTC, datetime from enum import Enum -from typing import ClassVar, Protocol, TypeVar +from typing import ClassVar, Protocol, Self, TypeVar from humps.main import camelize from pydantic import UUID4, AliasChoices, BaseModel, ConfigDict, Field, model_validator from sqlalchemy import Select, desc, func, or_, text from sqlalchemy.orm import InstrumentedAttribute, Session from sqlalchemy.orm.interfaces import LoaderOption -from typing_extensions import Self from mealie.db.models._model_base import SqlAlchemyBase @@ -88,7 +87,7 @@ def set_tz_info(self) -> Self: if not isinstance(val, datetime): continue if not val.tzinfo: - setattr(self, field, val.replace(tzinfo=timezone.utc)) + setattr(self, field, val.replace(tzinfo=UTC)) return self diff --git a/mealie/schema/household/webhook.py b/mealie/schema/household/webhook.py index 6c6510b0aa8..f42054ed52f 100644 --- a/mealie/schema/household/webhook.py +++ b/mealie/schema/household/webhook.py @@ -32,7 +32,7 @@ def validate_scheduled_time(cls, v): type: datetime is treated as a value with a timezone """ parser_funcs = [ - lambda x: parse_datetime(x).astimezone(datetime.timezone.utc).time(), + lambda x: parse_datetime(x).astimezone(datetime.UTC).time(), parse_time, ] diff --git a/mealie/schema/recipe/recipe_share_token.py b/mealie/schema/recipe/recipe_share_token.py index fd4e376cf30..0e876a05a3b 100644 --- a/mealie/schema/recipe/recipe_share_token.py +++ b/mealie/schema/recipe/recipe_share_token.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pydantic import UUID4, ConfigDict, Field from sqlalchemy.orm import selectinload @@ -11,7 +11,7 @@ def defaut_expires_at_time() -> datetime: - return datetime.now(timezone.utc) + timedelta(days=30) + return datetime.now(UTC) + timedelta(days=30) class RecipeShareTokenCreate(MealieModel): diff --git a/mealie/schema/recipe/recipe_timeline_events.py b/mealie/schema/recipe/recipe_timeline_events.py index 02de699ceb8..88d1072f83c 100644 --- a/mealie/schema/recipe/recipe_timeline_events.py +++ b/mealie/schema/recipe/recipe_timeline_events.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from enum import Enum from pathlib import Path from typing import Annotated @@ -40,7 +40,7 @@ class RecipeTimelineEventIn(MealieModel): message: str | None = Field(None, alias="eventMessage") image: Annotated[TimelineEventImage | None, Field(validate_default=True)] = TimelineEventImage.does_not_have_image - timestamp: datetime = datetime.now(timezone.utc) + timestamp: datetime = datetime.now(UTC) model_config = ConfigDict(use_enum_values=True) diff --git a/mealie/schema/user/user.py b/mealie/schema/user/user.py index 8bada9194c6..f4e1228b4b5 100644 --- a/mealie/schema/user/user.py +++ b/mealie/schema/user/user.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path from typing import Annotated, Any, Generic, TypeVar from uuid import UUID @@ -218,7 +218,7 @@ def is_locked(self) -> bool: return False lockout_expires_at = self.locked_at + timedelta(hours=get_app_settings().SECURITY_USER_LOCKOUT_TIME) - return lockout_expires_at > datetime.now(timezone.utc) + return lockout_expires_at > datetime.now(UTC) def directory(self) -> Path: return PrivateUser.get_directory(self.id) diff --git a/mealie/services/backups_v2/backup_v2.py b/mealie/services/backups_v2/backup_v2.py index fe8289ed778..01c19244897 100644 --- a/mealie/services/backups_v2/backup_v2.py +++ b/mealie/services/backups_v2/backup_v2.py @@ -25,7 +25,7 @@ def _sqlite(self) -> None: db_file = self.settings.DB_URL.removeprefix("sqlite:///") # type: ignore # Create a backup of the SQLite database - timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y.%m.%d") + timestamp = datetime.datetime.now(datetime.UTC).strftime("%Y.%m.%d") shutil.copy(db_file, self.directories.DATA_DIR.joinpath(f"mealie_{timestamp}.bak.db")) def _postgres(self) -> None: @@ -37,7 +37,7 @@ def backup(self) -> Path: exclude_ext = {".zip"} exclude_dirs = {"backups", ".temp"} - timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y.%m.%d.%H.%M.%S") + timestamp = datetime.datetime.now(datetime.UTC).strftime("%Y.%m.%d.%H.%M.%S") backup_name = f"mealie_{timestamp}.zip" backup_file = self.directories.BACKUP_DIR / backup_name diff --git a/mealie/services/event_bus_service/event_bus_listeners.py b/mealie/services/event_bus_service/event_bus_listeners.py index dd19992d9e3..586876c6318 100644 --- a/mealie/services/event_bus_service/event_bus_listeners.py +++ b/mealie/services/event_bus_service/event_bus_listeners.py @@ -2,7 +2,7 @@ import json from abc import ABC, abstractmethod from collections.abc import Generator -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import cast from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit @@ -163,8 +163,8 @@ def get_scheduled_webhooks(self, start_dt: datetime, end_dt: datetime) -> list[R with self.ensure_session() as session: stmt = select(GroupWebhooksModel).where( GroupWebhooksModel.enabled == True, # noqa: E712 - required for SQLAlchemy comparison - GroupWebhooksModel.scheduled_time > start_dt.astimezone(timezone.utc).time(), - GroupWebhooksModel.scheduled_time <= end_dt.astimezone(timezone.utc).time(), + GroupWebhooksModel.scheduled_time > start_dt.astimezone(UTC).time(), + GroupWebhooksModel.scheduled_time <= end_dt.astimezone(UTC).time(), GroupWebhooksModel.group_id == self.group_id, GroupWebhooksModel.household_id == self.household_id, ) diff --git a/mealie/services/event_bus_service/event_types.py b/mealie/services/event_bus_service/event_types.py index 56bf6350d51..6e3e54b059e 100644 --- a/mealie/services/event_bus_service/event_types.py +++ b/mealie/services/event_bus_service/event_types.py @@ -1,5 +1,5 @@ import uuid -from datetime import date, datetime, timezone +from datetime import UTC, date, datetime from enum import Enum, auto from typing import Any @@ -193,4 +193,4 @@ class Event(MealieModel): def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.event_id = uuid.uuid4() - self.timestamp = datetime.now(timezone.utc) + self.timestamp = datetime.now(UTC) diff --git a/mealie/services/exporter/exporter.py b/mealie/services/exporter/exporter.py index 1b66cc54954..056f680fbcd 100644 --- a/mealie/services/exporter/exporter.py +++ b/mealie/services/exporter/exporter.py @@ -43,7 +43,7 @@ def run(self, db: AllRepositories) -> GroupDataExport: name="Data Export", size=pretty_size(export_path.stat().st_size), filename=export_path.name, - expires=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1), + expires=datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=1), ) db.group_exports.create(group_data_export) diff --git a/mealie/services/migrations/copymethat.py b/mealie/services/migrations/copymethat.py index 6b9c925c530..fd00e4266d9 100644 --- a/mealie/services/migrations/copymethat.py +++ b/mealie/services/migrations/copymethat.py @@ -1,6 +1,6 @@ import tempfile import zipfile -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from bs4 import BeautifulSoup @@ -35,7 +35,7 @@ def __init__(self, **kwargs): self.name = "copymethat" self.key_aliases = [ - MigrationAlias(key="last_made", alias="made_this", func=lambda x: datetime.now(timezone.utc)), + MigrationAlias(key="last_made", alias="made_this", func=lambda x: datetime.now(UTC)), MigrationAlias(key="notes", alias="recipeNotes"), MigrationAlias(key="orgURL", alias="original_link"), MigrationAlias(key="rating", alias="ratingValue"), diff --git a/mealie/services/recipe/recipe_service.py b/mealie/services/recipe/recipe_service.py index 8bf3f1bba5f..02eb2fa9a6c 100644 --- a/mealie/services/recipe/recipe_service.py +++ b/mealie/services/recipe/recipe_service.py @@ -1,7 +1,7 @@ import json import os import shutil -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from shutil import copytree, rmtree from typing import Any @@ -192,7 +192,7 @@ def create_one(self, create_data: Recipe | CreateRecipe) -> Recipe: recipe_id=new_recipe.id, subject=self.t("recipe.recipe-created"), event_type=TimelineEventType.system, - timestamp=new_recipe.created_at or datetime.now(timezone.utc), + timestamp=new_recipe.created_at or datetime.now(UTC), ) self.repos.recipe_timeline_events.create(timeline_event_data) diff --git a/mealie/services/scheduler/scheduler_service.py b/mealie/services/scheduler/scheduler_service.py index 893912205b7..5ee5eb1a34a 100644 --- a/mealie/services/scheduler/scheduler_service.py +++ b/mealie/services/scheduler/scheduler_service.py @@ -1,5 +1,5 @@ import asyncio -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path from mealie.core import root_logger @@ -28,7 +28,7 @@ async def start(): async def schedule_daily(): - now = datetime.now(timezone.utc) + now = datetime.now(UTC) daily_schedule_time = get_app_settings().DAILY_SCHEDULE_TIME_UTC logger.debug(f"Current time is {now} and DAILY_SCHEDULE_TIME (in UTC) is {daily_schedule_time}") diff --git a/mealie/services/scheduler/tasks/create_timeline_events.py b/mealie/services/scheduler/tasks/create_timeline_events.py index 3f08ba647e1..1806e1217f2 100644 --- a/mealie/services/scheduler/tasks/create_timeline_events.py +++ b/mealie/services/scheduler/tasks/create_timeline_events.py @@ -1,4 +1,4 @@ -from datetime import datetime, time, timedelta, timezone +from datetime import UTC, datetime, time, timedelta from pydantic import UUID4 from sqlalchemy.orm import Session @@ -45,7 +45,7 @@ def _create_mealplan_timeline_events_for_household( else: event_subject = f"{user.full_name} made this for {mealplan.entry_type.value}" - query_start_time = datetime.combine(datetime.now(timezone.utc).date(), time.min) + query_start_time = datetime.combine(datetime.now(UTC).date(), time.min) query_end_time = query_start_time + timedelta(days=1) query = PaginationQuery( query_filter=( @@ -116,7 +116,7 @@ def _create_mealplan_timeline_events_for_group(event_time: datetime, session: Se def create_mealplan_timeline_events() -> None: - event_time = datetime.now(timezone.utc) + event_time = datetime.now(UTC) with session_context() as session: repos = get_repositories(session) diff --git a/mealie/services/scheduler/tasks/post_webhooks.py b/mealie/services/scheduler/tasks/post_webhooks.py index e3a57459a16..5298fa2c8d3 100644 --- a/mealie/services/scheduler/tasks/post_webhooks.py +++ b/mealie/services/scheduler/tasks/post_webhooks.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from pydantic import UUID4 @@ -18,7 +18,7 @@ EventWebhookData, ) -last_ran = datetime.now(timezone.utc) +last_ran = datetime.now(UTC) def post_group_webhooks( @@ -32,7 +32,7 @@ def post_group_webhooks( start_dt = start_dt or last_ran # end the query at the current time - last_ran = end_dt = datetime.now(timezone.utc) + last_ran = end_dt = datetime.now(UTC) if group_id is None: # publish the webhook event to each group's event bus @@ -80,7 +80,7 @@ def post_group_webhooks( def post_single_webhook(webhook: ReadWebhook, message: str = "") -> None: - dt = datetime.min.replace(tzinfo=timezone.utc) + dt = datetime.min.replace(tzinfo=UTC) event_type = EventTypes.webhook_task event_document_data = EventWebhookData( diff --git a/mealie/services/scheduler/tasks/purge_group_exports.py b/mealie/services/scheduler/tasks/purge_group_exports.py index ea69821f151..a92dd2d5e1d 100644 --- a/mealie/services/scheduler/tasks/purge_group_exports.py +++ b/mealie/services/scheduler/tasks/purge_group_exports.py @@ -17,7 +17,7 @@ def purge_group_data_exports(max_minutes_old=ONE_DAY_AS_MINUTES): logger = root_logger.get_logger() logger.debug("purging group data exports") - limit = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(minutes=max_minutes_old) + limit = datetime.datetime.now(datetime.UTC) - datetime.timedelta(minutes=max_minutes_old) with session_context() as session: stmt = select(GroupDataExportsModel).filter(cast(GroupDataExportsModel.expires, NaiveDateTime) <= limit) @@ -39,7 +39,7 @@ def purge_excess_files() -> None: directories = get_app_dirs() logger = root_logger.get_logger() - limit = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(minutes=ONE_DAY_AS_MINUTES * 2) + limit = datetime.datetime.now(datetime.UTC) - datetime.timedelta(minutes=ONE_DAY_AS_MINUTES * 2) for file in directories.GROUPS_DIR.glob("**/export/*.zip"): # TODO: fix comparison types diff --git a/mealie/services/scheduler/tasks/purge_password_reset.py b/mealie/services/scheduler/tasks/purge_password_reset.py index f783e95913f..99aab0f6b5e 100644 --- a/mealie/services/scheduler/tasks/purge_password_reset.py +++ b/mealie/services/scheduler/tasks/purge_password_reset.py @@ -14,7 +14,7 @@ def purge_password_reset_tokens(): """Purges all events after x days""" logger.debug("purging password reset tokens") - limit = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=MAX_DAYS_OLD) + limit = datetime.datetime.now(datetime.UTC) - datetime.timedelta(days=MAX_DAYS_OLD) with session_context() as session: stmt = delete(PasswordResetModel).filter(PasswordResetModel.created_at <= limit) diff --git a/mealie/services/scheduler/tasks/purge_registration.py b/mealie/services/scheduler/tasks/purge_registration.py index 58e09c9eb65..855a0358191 100644 --- a/mealie/services/scheduler/tasks/purge_registration.py +++ b/mealie/services/scheduler/tasks/purge_registration.py @@ -14,7 +14,7 @@ def purge_group_registration(): """Purges all events after x days""" logger.debug("purging expired registration tokens") - limit = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=MAX_DAYS_OLD) + limit = datetime.datetime.now(datetime.UTC) - datetime.timedelta(days=MAX_DAYS_OLD) with session_context() as session: stmt = delete(GroupInviteToken).filter(GroupInviteToken.created_at <= limit) diff --git a/mealie/services/user_services/user_service.py b/mealie/services/user_services/user_service.py index 51db3f6e055..b73c1b41753 100644 --- a/mealie/services/user_services/user_service.py +++ b/mealie/services/user_services/user_service.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from mealie.repos.repository_factory import AllRepositories from mealie.schema.user.user import PrivateUser @@ -30,7 +30,7 @@ def reset_locked_users(self, force: bool = False) -> int: return unlocked def lock_user(self, user: PrivateUser) -> PrivateUser: - user.locked_at = datetime.now(timezone.utc) + user.locked_at = datetime.now(UTC) return self.repos.users.update(user.id, user) def unlock_user(self, user: PrivateUser) -> PrivateUser: From 8351504ec600df132d9e32fac4230227822dc00c Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Thu, 5 Dec 2024 04:08:00 +0000 Subject: [PATCH 4/4] lint fixes --- ....15_d7c6efd2de42_migrate_favorites_and_ratings_to_user_.py | 4 ++-- .../2024-07-12-16.16.29_feecc8ffb956_add_households.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mealie/alembic/versions/2024-03-18-02.28.15_d7c6efd2de42_migrate_favorites_and_ratings_to_user_.py b/mealie/alembic/versions/2024-03-18-02.28.15_d7c6efd2de42_migrate_favorites_and_ratings_to_user_.py index 8873532bcf6..6aa1c371f6b 100644 --- a/mealie/alembic/versions/2024-03-18-02.28.15_d7c6efd2de42_migrate_favorites_and_ratings_to_user_.py +++ b/mealie/alembic/versions/2024-03-18-02.28.15_d7c6efd2de42_migrate_favorites_and_ratings_to_user_.py @@ -6,7 +6,7 @@ """ -from datetime import datetime, timezone +from datetime import UTC, datetime from textwrap import dedent from typing import Any from uuid import uuid4 @@ -34,7 +34,7 @@ def new_user_rating(user_id: Any, recipe_id: Any, rating: float | None = None, i else: id = "%.32x" % uuid4().int # noqa: UP031 - now = datetime.now(timezone.utc).isoformat() + now = datetime.now(UTC).isoformat() return { "id": id, "user_id": user_id, diff --git a/mealie/alembic/versions/2024-07-12-16.16.29_feecc8ffb956_add_households.py b/mealie/alembic/versions/2024-07-12-16.16.29_feecc8ffb956_add_households.py index 0578a764302..7c4b2a2fcc9 100644 --- a/mealie/alembic/versions/2024-07-12-16.16.29_feecc8ffb956_add_households.py +++ b/mealie/alembic/versions/2024-07-12-16.16.29_feecc8ffb956_add_households.py @@ -6,7 +6,7 @@ """ -from datetime import datetime, timezone +from datetime import UTC, datetime from textwrap import dedent from typing import Any from uuid import uuid4 @@ -89,7 +89,7 @@ def dedupe_cookbook_slugs(): def create_household(session: orm.Session, group_id: str) -> str: # create/insert household household_id = generate_id() - timestamp = datetime.now(timezone.utc).isoformat() + timestamp = datetime.now(UTC).isoformat() household_data = { "id": household_id, "name": settings.DEFAULT_HOUSEHOLD,