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

feat: Upgrade to Python 3.12 #4675

Merged
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
4 changes: 2 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/partial-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scheduled-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions mealie/core/release_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import requests

_LAST_RESET = None
_LAST_RESET: datetime.datetime | None = None


@lru_cache(maxsize=1)
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mealie/core/security/providers/auth_provider.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mealie/core/security/security.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import secrets
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta
from pathlib import Path

import jwt
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions mealie/core/settings/settings.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions mealie/db/models/_model_utils/datetime.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import UTC, datetime

from sqlalchemy.types import DateTime, TypeDecorator

Expand All @@ -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):
Expand All @@ -35,15 +35,15 @@ 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

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

Expand Down
4 changes: 2 additions & 2 deletions mealie/db/models/household/shopping_list.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions mealie/db/models/household/webhooks.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mealie/db/models/recipe/recipe.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions mealie/db/models/recipe/recipe_timeline.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import UTC, datetime
from typing import TYPE_CHECKING

from sqlalchemy import ForeignKey, String
Expand Down Expand Up @@ -48,4 +48,4 @@ def __init__(
timestamp=None,
**_,
) -> None:
self.timestamp = timestamp or datetime.now(timezone.utc)
self.timestamp = timestamp or datetime.now(UTC)
4 changes: 2 additions & 2 deletions mealie/db/models/recipe/shared.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions mealie/repos/repository_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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__}")
Expand Down
4 changes: 2 additions & 2 deletions mealie/repos/repository_meals.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import UTC, datetime

from sqlalchemy import select

Expand All @@ -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
)
Expand Down
3 changes: 1 addition & 2 deletions mealie/repos/repository_recipes.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mealie/routes/households/controller_webhooks.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions mealie/schema/_mealie/datetime_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -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<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})"
time_expr = (
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
7 changes: 3 additions & 4 deletions mealie/schema/_mealie/mealie_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
Loading
Loading