From c2a2fee50fe5c6b3e71ee05a45996a939e5d00de Mon Sep 17 00:00:00 2001 From: Stijn De Clercq Date: Fri, 7 Jul 2023 16:16:33 +0200 Subject: [PATCH] Update all dependencies, move to pydantic 2.x and sqlalchemy 2.x --- .pre-commit-config.yaml | 8 +- database/engine.py | 7 +- database/schemas.py | 256 ++++++++++++------------- didier/data/apis/disease_sh.py | 4 +- didier/data/apis/hydra.py | 2 +- didier/data/apis/urban_dictionary.py | 2 +- didier/data/apis/xkcd.py | 2 +- didier/data/embeds/disease_sh.py | 4 +- didier/data/embeds/free_games.py | 10 +- didier/data/embeds/urban_dictionary.py | 6 +- didier/data/rss_feeds/free_games.py | 2 +- requirements-dev.txt | 37 ++-- requirements.txt | 18 +- 13 files changed, 173 insertions(+), 185 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ba38355..acdc6a2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,12 +3,12 @@ default_language_version: repos: - repo: https://github.com/ambv/black - rev: 22.3.0 + rev: 23.3.0 hooks: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: check-json - id: end-of-file-fixer @@ -21,7 +21,7 @@ repos: - id: isort - repo: https://github.com/PyCQA/autoflake - rev: v1.4 + rev: v2.2.0 hooks: - id: autoflake name: autoflake (python) @@ -31,7 +31,7 @@ repos: - "--ignore-init-module-imports" - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: 6.0.0 hooks: - id: flake8 exclude: ^(alembic|.github) diff --git a/database/engine.py b/database/engine.py index 23e5b89..ec81bfb 100644 --- a/database/engine.py +++ b/database/engine.py @@ -1,8 +1,7 @@ from urllib.parse import quote_plus from sqlalchemy.engine import URL -from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine -from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine import settings @@ -22,6 +21,4 @@ postgres_engine = create_async_engine( future=True, ) -DBSession = sessionmaker( - autocommit=False, autoflush=False, bind=postgres_engine, class_=AsyncSession, expire_on_commit=False -) +DBSession = async_sessionmaker(autocommit=False, autoflush=False, bind=postgres_engine, expire_on_commit=False) diff --git a/database/schemas.py b/database/schemas.py index 34efcbc..b92b2a2 100644 --- a/database/schemas.py +++ b/database/schemas.py @@ -1,27 +1,14 @@ from __future__ import annotations from datetime import date, datetime -from typing import Optional +from typing import List, Optional -from sqlalchemy import ( - BigInteger, - Boolean, - Column, - Date, - DateTime, - Enum, - ForeignKey, - Integer, - Text, - UniqueConstraint, -) -from sqlalchemy.orm import declarative_base, relationship +from sqlalchemy import BigInteger, ForeignKey, UniqueConstraint +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship +from sqlalchemy.types import DateTime from database import enums -Base = declarative_base() - - __all__ = [ "Base", "Bank", @@ -48,27 +35,34 @@ __all__ = [ ] +class Base(DeclarativeBase): + """Required base class for all tables""" + + # Make all DateTimes timezone-aware + type_annotation_map = {datetime: DateTime(timezone=True)} + + class Bank(Base): """A user's currency information""" __tablename__ = "bank" - bank_id: int = Column(Integer, primary_key=True) - user_id: int = Column(BigInteger, ForeignKey("users.user_id")) + bank_id: Mapped[int] = mapped_column(primary_key=True) + user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id")) - dinks: int = Column(BigInteger, server_default="0", nullable=False) - invested: int = Column(BigInteger, server_default="0", nullable=False) + dinks: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False) + invested: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False) # Interest rate - interest_level: int = Column(Integer, server_default="1", nullable=False) + interest_level: Mapped[int] = mapped_column(server_default="1", nullable=False) # Maximum amount that can be stored in the bank - capacity_level: int = Column(Integer, server_default="1", nullable=False) + capacity_level: Mapped[int] = mapped_column(server_default="1", nullable=False) # Maximum amount that can be robbed - rob_level: int = Column(Integer, server_default="1", nullable=False) + rob_level: Mapped[int] = mapped_column(server_default="1", nullable=False) - user: User = relationship("User", uselist=False, back_populates="bank", lazy="selectin") + user: Mapped[User] = relationship(uselist=False, back_populates="bank", lazy="selectin") class Birthday(Base): @@ -76,11 +70,11 @@ class Birthday(Base): __tablename__ = "birthdays" - birthday_id: int = Column(Integer, primary_key=True) - user_id: int = Column(BigInteger, ForeignKey("users.user_id")) - birthday: date = Column(Date, nullable=False) + birthday_id: Mapped[int] = mapped_column(primary_key=True) + user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id")) + birthday: Mapped[date] = mapped_column(nullable=False) - user: User = relationship("User", uselist=False, back_populates="birthday", lazy="selectin") + user: Mapped[User] = relationship(uselist=False, back_populates="birthday", lazy="selectin") class Bookmark(Base): @@ -89,26 +83,26 @@ class Bookmark(Base): __tablename__ = "bookmarks" __table_args__ = (UniqueConstraint("user_id", "label"),) - bookmark_id: int = Column(Integer, primary_key=True) - label: str = Column(Text, nullable=False) - jump_url: str = Column(Text, nullable=False) - user_id: int = Column(BigInteger, ForeignKey("users.user_id")) + bookmark_id: Mapped[int] = mapped_column(primary_key=True) + label: Mapped[str] = mapped_column(nullable=False) + jump_url: Mapped[str] = mapped_column(nullable=False) + user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id")) - user: User = relationship("User", back_populates="bookmarks", uselist=False, lazy="selectin") + user: Mapped[User] = relationship(back_populates="bookmarks", uselist=False, lazy="selectin") class CommandStats(Base): """Metrics on how often commands are used""" __tablename__ = "command_stats" - command_stats_id: int = Column(Integer, primary_key=True) - command: str = Column(Text, nullable=False) - timestamp: datetime = Column(DateTime(timezone=True), nullable=False) - user_id: int = Column(BigInteger, ForeignKey("users.user_id")) - slash: bool = Column(Boolean, nullable=False) - context_menu: bool = Column(Boolean, nullable=False) + command_stats_id: Mapped[int] = mapped_column(primary_key=True) + command: Mapped[str] = mapped_column(nullable=False) + timestamp: Mapped[datetime] = mapped_column(nullable=False) + user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id")) + slash: Mapped[bool] = mapped_column(nullable=False) + context_menu: Mapped[bool] = mapped_column(nullable=False) - user: User = relationship("User", back_populates="command_stats", uselist=False, lazy="selectin") + user: Mapped[User] = relationship(back_populates="command_stats", uselist=False, lazy="selectin") class CustomCommand(Base): @@ -116,13 +110,13 @@ class CustomCommand(Base): __tablename__ = "custom_commands" - command_id: int = Column(Integer, primary_key=True) - name: str = Column(Text, nullable=False, unique=True) - indexed_name: str = Column(Text, nullable=False, index=True) - response: str = Column(Text, nullable=False) + command_id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(nullable=False, unique=True) + indexed_name: Mapped[str] = mapped_column(nullable=False, index=True) + response: Mapped[str] = mapped_column(nullable=False) - aliases: list[CustomCommandAlias] = relationship( - "CustomCommandAlias", back_populates="command", uselist=True, cascade="all, delete-orphan", lazy="selectin" + aliases: Mapped[List[CustomCommandAlias]] = relationship( + back_populates="command", uselist=True, cascade="all, delete-orphan", lazy="selectin" ) @@ -131,12 +125,12 @@ class CustomCommandAlias(Base): __tablename__ = "custom_command_aliases" - alias_id: int = Column(Integer, primary_key=True) - alias: str = Column(Text, nullable=False, unique=True) - indexed_alias: str = Column(Text, nullable=False, index=True) - command_id: int = Column(Integer, ForeignKey("custom_commands.command_id")) + alias_id: Mapped[int] = mapped_column(primary_key=True) + alias: Mapped[str] = mapped_column(nullable=False, unique=True) + indexed_alias: Mapped[str] = mapped_column(nullable=False, index=True) + command_id: Mapped[int] = mapped_column(ForeignKey("custom_commands.command_id")) - command: CustomCommand = relationship("CustomCommand", back_populates="aliases", uselist=False, lazy="selectin") + command: Mapped[CustomCommand] = relationship(back_populates="aliases", uselist=False, lazy="selectin") class DadJoke(Base): @@ -144,8 +138,8 @@ class DadJoke(Base): __tablename__ = "dad_jokes" - dad_joke_id: int = Column(Integer, primary_key=True) - joke: str = Column(Text, nullable=False) + dad_joke_id: Mapped[int] = mapped_column(primary_key=True) + joke: Mapped[str] = mapped_column(nullable=False) class Deadline(Base): @@ -153,12 +147,12 @@ class Deadline(Base): __tablename__ = "deadlines" - deadline_id: int = Column(Integer, primary_key=True) - course_id: int = Column(Integer, ForeignKey("ufora_courses.course_id")) - name: str = Column(Text, nullable=False) - deadline: datetime = Column(DateTime(timezone=True), nullable=False) + deadline_id: Mapped[int] = mapped_column(primary_key=True) + course_id: Mapped[int] = mapped_column(ForeignKey("ufora_courses.course_id")) + name: Mapped[str] = mapped_column(nullable=False) + deadline: Mapped[datetime] = mapped_column(nullable=False) - course: UforaCourse = relationship("UforaCourse", back_populates="deadlines", uselist=False, lazy="selectin") + course: Mapped[UforaCourse] = relationship(back_populates="deadlines", uselist=False, lazy="selectin") class EasterEgg(Base): @@ -166,11 +160,11 @@ class EasterEgg(Base): __tablename__ = "easter_eggs" - easter_egg_id: int = Column(Integer, primary_key=True) - match: str = Column(Text, nullable=False) - response: str = Column(Text, nullable=False) - exact: bool = Column(Boolean, nullable=False, server_default="1") - startswith: bool = Column(Boolean, nullable=False, server_default="1") + easter_egg_id: Mapped[int] = mapped_column(primary_key=True) + match: Mapped[str] = mapped_column(nullable=False) + response: Mapped[str] = mapped_column(nullable=False) + exact: Mapped[bool] = mapped_column(nullable=False, server_default="1") + startswith: Mapped[bool] = mapped_column(nullable=False, server_default="1") class Event(Base): @@ -178,11 +172,11 @@ class Event(Base): __tablename__ = "events" - event_id: int = Column(Integer, primary_key=True) - name: str = Column(Text, nullable=False) - description: Optional[str] = Column(Text, nullable=True) - notification_channel: int = Column(BigInteger, nullable=False) - timestamp: datetime = Column(DateTime(timezone=True), nullable=False) + event_id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(nullable=False) + description: Mapped[Optional[str]] = mapped_column(nullable=True) + notification_channel: Mapped[int] = mapped_column(BigInteger, nullable=False) + timestamp: Mapped[datetime] = mapped_column(nullable=False) class FreeGame(Base): @@ -190,7 +184,7 @@ class FreeGame(Base): __tablename__ = "free_games" - free_game_id: int = Column(Integer, primary_key=True) + free_game_id: Mapped[int] = mapped_column(primary_key=True) class GitHubLink(Base): @@ -198,11 +192,11 @@ class GitHubLink(Base): __tablename__ = "github_links" - github_link_id: int = Column(Integer, primary_key=True) - url: str = Column(Text, nullable=False, unique=True) - user_id: int = Column(BigInteger, ForeignKey("users.user_id")) + github_link_id: Mapped[int] = mapped_column(primary_key=True) + url: Mapped[str] = mapped_column(nullable=False, unique=True) + user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id")) - user: User = relationship("User", back_populates="github_links", uselist=False, lazy="selectin") + user: Mapped[User] = relationship(back_populates="github_links", uselist=False, lazy="selectin") class Link(Base): @@ -210,9 +204,9 @@ class Link(Base): __tablename__ = "links" - link_id: int = Column(Integer, primary_key=True) - name: str = Column(Text, nullable=False, unique=True) - url: str = Column(Text, nullable=False) + link_id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(nullable=False, unique=True) + url: Mapped[str] = mapped_column(nullable=False) class MemeTemplate(Base): @@ -220,10 +214,10 @@ class MemeTemplate(Base): __tablename__ = "meme" - meme_id: int = Column(Integer, primary_key=True) - name: str = Column(Text, nullable=False, unique=True) - template_id: int = Column(Integer, nullable=False, unique=True) - field_count: int = Column(Integer, nullable=False) + meme_id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(nullable=False, unique=True) + template_id: Mapped[int] = mapped_column(nullable=False, unique=True) + field_count: Mapped[int] = mapped_column(nullable=False) class NightlyData(Base): @@ -231,12 +225,12 @@ class NightlyData(Base): __tablename__ = "nightly_data" - nightly_id: int = Column(Integer, primary_key=True) - user_id: int = Column(BigInteger, ForeignKey("users.user_id")) - last_nightly: Optional[date] = Column(Date, nullable=True) - count: int = Column(Integer, server_default="0", nullable=False) + nightly_id: Mapped[int] = mapped_column(primary_key=True) + user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id")) + last_nightly: Mapped[Optional[date]] = mapped_column(nullable=True) + count: Mapped[int] = mapped_column(server_default="0", nullable=False) - user: User = relationship("User", back_populates="nightly_data", uselist=False, lazy="selectin") + user: Mapped[User] = relationship(back_populates="nightly_data", uselist=False, lazy="selectin") class Reminder(Base): @@ -244,11 +238,11 @@ class Reminder(Base): __tablename__ = "reminders" - reminder_id: int = Column(Integer, primary_key=True) - user_id: int = Column(BigInteger, ForeignKey("users.user_id")) - category: enums.ReminderCategory = Column(Enum(enums.ReminderCategory), nullable=False) + reminder_id: Mapped[int] = mapped_column(primary_key=True) + user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id")) + category: Mapped[enums.ReminderCategory] = mapped_column(nullable=False) - user: User = relationship("User", back_populates="reminders", uselist=False, lazy="selectin") + user: Mapped[User] = relationship(back_populates="reminders", uselist=False, lazy="selectin") class Task(Base): @@ -256,9 +250,9 @@ class Task(Base): __tablename__ = "tasks" - task_id: int = Column(Integer, primary_key=True) - task: enums.TaskType = Column(Enum(enums.TaskType), nullable=False, unique=True) - previous_run: datetime = Column(DateTime(timezone=True), nullable=True) + task_id: Mapped[int] = mapped_column(primary_key=True) + task: Mapped[enums.TaskType] = mapped_column(nullable=False, unique=True) + previous_run: Mapped[datetime] = mapped_column(nullable=True) class UforaCourse(Base): @@ -266,25 +260,25 @@ class UforaCourse(Base): __tablename__ = "ufora_courses" - course_id: int = Column(Integer, primary_key=True) - name: str = Column(Text, nullable=False, unique=True) - code: str = Column(Text, nullable=False, unique=True) - year: int = Column(Integer, nullable=False) - compulsory: bool = Column(Boolean, server_default="1", nullable=False) - role_id: Optional[int] = Column(BigInteger, nullable=True, unique=False) - overarching_role_id: Optional[int] = Column(BigInteger, nullable=True, unique=False) + course_id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(nullable=False, unique=True) + code: Mapped[str] = mapped_column(nullable=False, unique=True) + year: Mapped[int] = mapped_column(nullable=False) + compulsory: Mapped[bool] = mapped_column(server_default="1", nullable=False) + role_id: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, unique=False) + overarching_role_id: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, unique=False) # This is not the greatest fix, but there can only ever be two, so it will do the job - alternative_overarching_role_id: Optional[int] = Column(BigInteger, nullable=True, unique=False) - log_announcements: bool = Column(Boolean, server_default="0", nullable=False) + alternative_overarching_role_id: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, unique=False) + log_announcements: Mapped[bool] = mapped_column(server_default="0", nullable=False) - announcements: list[UforaAnnouncement] = relationship( - "UforaAnnouncement", back_populates="course", cascade="all, delete-orphan", lazy="selectin" + announcements: Mapped[List[UforaAnnouncement]] = relationship( + back_populates="course", cascade="all, delete-orphan", lazy="selectin" ) - aliases: list[UforaCourseAlias] = relationship( - "UforaCourseAlias", back_populates="course", cascade="all, delete-orphan", lazy="selectin" + aliases: Mapped[List[UforaCourseAlias]] = relationship( + back_populates="course", cascade="all, delete-orphan", lazy="selectin" ) - deadlines: list[Deadline] = relationship( - "Deadline", back_populates="course", cascade="all, delete-orphan", lazy="selectin" + deadlines: Mapped[List[Deadline]] = relationship( + back_populates="course", cascade="all, delete-orphan", lazy="selectin" ) @@ -293,11 +287,11 @@ class UforaCourseAlias(Base): __tablename__ = "ufora_course_aliases" - alias_id: int = Column(Integer, primary_key=True) - alias: str = Column(Text, nullable=False, unique=True) - course_id: int = Column(Integer, ForeignKey("ufora_courses.course_id")) + alias_id: Mapped[int] = mapped_column(primary_key=True) + alias: Mapped[str] = mapped_column(nullable=False, unique=True) + course_id: Mapped[int] = mapped_column(ForeignKey("ufora_courses.course_id")) - course: UforaCourse = relationship("UforaCourse", back_populates="aliases", uselist=False, lazy="selectin") + course: Mapped[UforaCourse] = relationship(back_populates="aliases", uselist=False, lazy="selectin") class UforaAnnouncement(Base): @@ -305,11 +299,11 @@ class UforaAnnouncement(Base): __tablename__ = "ufora_announcements" - announcement_id: int = Column(Integer, primary_key=True) - course_id: int = Column(Integer, ForeignKey("ufora_courses.course_id")) - publication_date: date = Column(Date) + announcement_id: Mapped[int] = mapped_column(primary_key=True) + course_id: Mapped[int] = mapped_column(ForeignKey("ufora_courses.course_id")) + publication_date: Mapped[date] = mapped_column() - course: UforaCourse = relationship("UforaCourse", back_populates="announcements", uselist=False, lazy="selectin") + course: Mapped[UforaCourse] = relationship(back_populates="announcements", uselist=False, lazy="selectin") class User(Base): @@ -317,26 +311,26 @@ class User(Base): __tablename__ = "users" - user_id: int = Column(BigInteger, primary_key=True) + user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True) - bank: Bank = relationship( - "Bank", back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" + bank: Mapped[Bank] = relationship( + back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" ) - birthday: Optional[Birthday] = relationship( - "Birthday", back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" + birthday: Mapped[Optional[Birthday]] = relationship( + back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" ) - bookmarks: list[Bookmark] = relationship( - "Bookmark", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" + bookmarks: Mapped[List[Bookmark]] = relationship( + back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" ) - command_stats: list[CommandStats] = relationship( - "CommandStats", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" + command_stats: Mapped[List[CommandStats]] = relationship( + back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" ) - github_links: list[GitHubLink] = relationship( - "GitHubLink", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" + github_links: Mapped[List[GitHubLink]] = relationship( + back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" ) - nightly_data: NightlyData = relationship( - "NightlyData", back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" + nightly_data: Mapped[NightlyData] = relationship( + back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" ) - reminders: list[Reminder] = relationship( - "Reminder", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" + reminders: Mapped[List[Reminder]] = relationship( + back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" ) diff --git a/didier/data/apis/disease_sh.py b/didier/data/apis/disease_sh.py index 809cdcb..a32daea 100644 --- a/didier/data/apis/disease_sh.py +++ b/didier/data/apis/disease_sh.py @@ -19,7 +19,7 @@ async def get_country_info(http_session: ClientSession, country: str) -> CovidDa yesterday = response data = {"today": today, "yesterday": yesterday} - return CovidData.parse_obj(data) + return CovidData.model_validate(data) async def get_global_info(http_session: ClientSession) -> CovidData: @@ -35,4 +35,4 @@ async def get_global_info(http_session: ClientSession) -> CovidData: yesterday = response data = {"today": today, "yesterday": yesterday} - return CovidData.parse_obj(data) + return CovidData.model_validate(data) diff --git a/didier/data/apis/hydra.py b/didier/data/apis/hydra.py index 620e0df..8d7889b 100644 --- a/didier/data/apis/hydra.py +++ b/didier/data/apis/hydra.py @@ -12,4 +12,4 @@ async def fetch_menu(http_session: ClientSession, day_dt: date) -> Menu: """Fetch the menu for a given day""" endpoint = f"https://hydra.ugent.be/api/2.0/resto/menu/nl/{day_dt.year}/{day_dt.month}/{day_dt.day}.json" async with ensure_get(http_session, endpoint, log_exceptions=False) as response: - return Menu.parse_obj(response) + return Menu.model_validate(response) diff --git a/didier/data/apis/urban_dictionary.py b/didier/data/apis/urban_dictionary.py index 6d81934..a6b5cd6 100644 --- a/didier/data/apis/urban_dictionary.py +++ b/didier/data/apis/urban_dictionary.py @@ -14,4 +14,4 @@ async def lookup(http_session: ClientSession, query: str) -> list[Definition]: url = "https://api.urbandictionary.com/v0/define" async with ensure_get(http_session, url, params={"term": query}) as response: - return list(map(Definition.parse_obj, response["list"])) + return list(map(Definition.model_validate, response["list"])) diff --git a/didier/data/apis/xkcd.py b/didier/data/apis/xkcd.py index c0ad766..bf8ff4d 100644 --- a/didier/data/apis/xkcd.py +++ b/didier/data/apis/xkcd.py @@ -13,4 +13,4 @@ async def fetch_xkcd_post(http_session: ClientSession, *, num: Optional[int] = N url = "https://xkcd.com" + (f"/{num}" if num is not None else "") + "/info.0.json" async with ensure_get(http_session, url) as response: - return XKCDPost.parse_obj(response) + return XKCDPost.model_validate(response) diff --git a/didier/data/embeds/disease_sh.py b/didier/data/embeds/disease_sh.py index 45e8895..a344828 100644 --- a/didier/data/embeds/disease_sh.py +++ b/didier/data/embeds/disease_sh.py @@ -1,6 +1,6 @@ import discord from overrides import overrides -from pydantic import BaseModel, Field, validator +from pydantic import BaseModel, Field, field_validator from didier.data.embeds.base import EmbedPydantic @@ -24,7 +24,7 @@ class _CovidNumbers(BaseModel): active: int tests: int - @validator("updated") + @field_validator("updated") def updated_to_seconds(cls, value: int) -> int: """Turn the updated field into seconds instead of milliseconds""" return int(value) // 1000 diff --git a/didier/data/embeds/free_games.py b/didier/data/embeds/free_games.py index d37e0b7..f159157 100644 --- a/didier/data/embeds/free_games.py +++ b/didier/data/embeds/free_games.py @@ -4,18 +4,17 @@ from typing import Optional import discord from aiohttp import ClientSession from overrides import overrides -from pydantic import validator +from pydantic import field_validator from didier.data.embeds.base import EmbedPydantic from didier.data.scrapers.common import GameStorePage from didier.data.scrapers.steam import get_steam_webpage_info from didier.utils.discord import colours - -__all__ = ["SEPARATOR", "FreeGameEmbed"] - from didier.utils.discord.constants import Limits from didier.utils.types.string import abbreviate +__all__ = ["SEPARATOR", "FreeGameEmbed"] + SEPARATOR = " • Free • " @@ -58,7 +57,7 @@ class FreeGameEmbed(EmbedPydantic): store_page: Optional[GameStorePage] = None - @validator("title") + @field_validator("title") def _clean_title(cls, value: str) -> str: return html.unescape(value) @@ -107,7 +106,6 @@ class FreeGameEmbed(EmbedPydantic): embed.add_field(name="Open in browser", value=f"[{self.link}]({self.link})") if self.store_page.xdg_open_url is not None: - embed.add_field( name="Open in app", value=f"[{self.store_page.xdg_open_url}]({self.store_page.xdg_open_url})" ) diff --git a/didier/data/embeds/urban_dictionary.py b/didier/data/embeds/urban_dictionary.py index 6dfeaac..ad3f90f 100644 --- a/didier/data/embeds/urban_dictionary.py +++ b/didier/data/embeds/urban_dictionary.py @@ -2,7 +2,7 @@ from datetime import datetime import discord from overrides import overrides -from pydantic import validator +from pydantic import field_validator from didier.data.embeds.base import EmbedPydantic from didier.utils.discord import colours @@ -39,8 +39,8 @@ class Definition(EmbedPydantic): total_votes = self.thumbs_up + self.thumbs_down return round(100 * self.thumbs_up / total_votes, 2) - @validator("definition", "example") - def modify_long_text(cls, field): + @field_validator("definition", "example") + def modify_long_text(cls, field: str): """Remove brackets from fields & cut them off if they are too long""" field = field.replace("[", "").replace("]", "") return string_utils.abbreviate(field, max_length=Limits.EMBED_FIELD_VALUE_LENGTH) diff --git a/didier/data/rss_feeds/free_games.py b/didier/data/rss_feeds/free_games.py index fcc02c9..24a1ecf 100644 --- a/didier/data/rss_feeds/free_games.py +++ b/didier/data/rss_feeds/free_games.py @@ -32,7 +32,7 @@ async def fetch_free_games(http_session: ClientSession, database_session: AsyncS if SEPARATOR not in entry["title"]: continue - game = FreeGameEmbed.parse_obj(entry) + game = FreeGameEmbed.model_validate(entry) games.append(game) game_ids.append(game.dc_identifier) diff --git a/requirements-dev.txt b/requirements-dev.txt index a9f7109..8d2d1b3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,22 +1,21 @@ -black==22.3.0 -coverage[toml]==6.4.1 -freezegun==1.2.1 +black==23.3.0 +coverage[toml]==7.2.7 +freezegun==1.2.2 isort==5.12.0 -mypy==0.961 -pre-commit==2.20.0 -pytest==7.1.2 -pytest-asyncio==0.18.3 -pytest-env==0.6.2 -sqlalchemy2-stubs==0.0.2a23 -types-beautifulsoup4==4.11.3 -types-python-dateutil==2.8.19 +mypy==1.4.1 +pre-commit==3.3.3 +pytest==7.4.0 +pytest-asyncio==0.21.0 +pytest-env==0.8.2 +types-beautifulsoup4==4.12.0.5 +types-python-dateutil==2.8.19.13 # Flake8 + plugins -flake8==4.0.1 -flake8-bandit==3.0.0 -flake8-bugbear==22.7.1 -flake8-docstrings==1.6.0 -flake8-dunder-all==0.2.1 -flake8-eradicate==1.2.1 -flake8-isort==4.1.1 -flake8-simplify==0.19.2 +flake8==6.0.0 +flake8-bandit==4.1.1 +flake8-bugbear==23.6.5 +flake8-docstrings==1.7.0 +flake8-dunder-all==0.3.0 +flake8-eradicate==1.5.0 +flake8-isort==6.0.0 +flake8-simplify==0.20.0 diff --git a/requirements.txt b/requirements.txt index a29f1cc..a7b6db2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,13 @@ -aiohttp==3.8.1 -alembic==1.8.0 -asyncpg==0.25.0 -beautifulsoup4==4.11.1 -discord.py==2.0.1 +aiohttp==3.8.4 +alembic==1.11.1 +asyncpg==0.28.0 +beautifulsoup4==4.12.2 +discord.py==2.3.1 environs==9.5.0 feedparser==6.0.10 ics==0.7.2 -markdownify==0.11.2 -overrides==6.1.0 -pydantic==1.9.1 +markdownify==0.11.6 +overrides==7.3.1 +pydantic==2.0.2 python-dateutil==2.8.2 -sqlalchemy[asyncio]==1.4.37 +sqlalchemy[asyncio]==2.0.18