Update all dependencies, move to pydantic 2.x and sqlalchemy 2.x

pull/176/head
Stijn De Clercq 2023-07-07 16:16:33 +02:00
parent ee6013da5d
commit c2a2fee50f
13 changed files with 173 additions and 185 deletions

View File

@ -3,12 +3,12 @@ default_language_version:
repos: repos:
- repo: https://github.com/ambv/black - repo: https://github.com/ambv/black
rev: 22.3.0 rev: 23.3.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0 rev: v4.4.0
hooks: hooks:
- id: check-json - id: check-json
- id: end-of-file-fixer - id: end-of-file-fixer
@ -21,7 +21,7 @@ repos:
- id: isort - id: isort
- repo: https://github.com/PyCQA/autoflake - repo: https://github.com/PyCQA/autoflake
rev: v1.4 rev: v2.2.0
hooks: hooks:
- id: autoflake - id: autoflake
name: autoflake (python) name: autoflake (python)
@ -31,7 +31,7 @@ repos:
- "--ignore-init-module-imports" - "--ignore-init-module-imports"
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 4.0.1 rev: 6.0.0
hooks: hooks:
- id: flake8 - id: flake8
exclude: ^(alembic|.github) exclude: ^(alembic|.github)

View File

@ -1,8 +1,7 @@
from urllib.parse import quote_plus from urllib.parse import quote_plus
from sqlalchemy.engine import URL from sqlalchemy.engine import URL
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
from sqlalchemy.orm import sessionmaker
import settings import settings
@ -22,6 +21,4 @@ postgres_engine = create_async_engine(
future=True, future=True,
) )
DBSession = sessionmaker( DBSession = async_sessionmaker(autocommit=False, autoflush=False, bind=postgres_engine, expire_on_commit=False)
autocommit=False, autoflush=False, bind=postgres_engine, class_=AsyncSession, expire_on_commit=False
)

View File

@ -1,27 +1,14 @@
from __future__ import annotations from __future__ import annotations
from datetime import date, datetime from datetime import date, datetime
from typing import Optional from typing import List, Optional
from sqlalchemy import ( from sqlalchemy import BigInteger, ForeignKey, UniqueConstraint
BigInteger, from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
Boolean, from sqlalchemy.types import DateTime
Column,
Date,
DateTime,
Enum,
ForeignKey,
Integer,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import declarative_base, relationship
from database import enums from database import enums
Base = declarative_base()
__all__ = [ __all__ = [
"Base", "Base",
"Bank", "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): class Bank(Base):
"""A user's currency information""" """A user's currency information"""
__tablename__ = "bank" __tablename__ = "bank"
bank_id: int = Column(Integer, primary_key=True) bank_id: Mapped[int] = mapped_column(primary_key=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
dinks: int = Column(BigInteger, server_default="0", nullable=False) dinks: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False)
invested: int = Column(BigInteger, server_default="0", nullable=False) invested: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False)
# Interest rate # 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 # 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 # 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): class Birthday(Base):
@ -76,11 +70,11 @@ class Birthday(Base):
__tablename__ = "birthdays" __tablename__ = "birthdays"
birthday_id: int = Column(Integer, primary_key=True) birthday_id: Mapped[int] = mapped_column(primary_key=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
birthday: date = Column(Date, nullable=False) 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): class Bookmark(Base):
@ -89,26 +83,26 @@ class Bookmark(Base):
__tablename__ = "bookmarks" __tablename__ = "bookmarks"
__table_args__ = (UniqueConstraint("user_id", "label"),) __table_args__ = (UniqueConstraint("user_id", "label"),)
bookmark_id: int = Column(Integer, primary_key=True) bookmark_id: Mapped[int] = mapped_column(primary_key=True)
label: str = Column(Text, nullable=False) label: Mapped[str] = mapped_column(nullable=False)
jump_url: str = Column(Text, nullable=False) jump_url: Mapped[str] = mapped_column(nullable=False)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) 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): class CommandStats(Base):
"""Metrics on how often commands are used""" """Metrics on how often commands are used"""
__tablename__ = "command_stats" __tablename__ = "command_stats"
command_stats_id: int = Column(Integer, primary_key=True) command_stats_id: Mapped[int] = mapped_column(primary_key=True)
command: str = Column(Text, nullable=False) command: Mapped[str] = mapped_column(nullable=False)
timestamp: datetime = Column(DateTime(timezone=True), nullable=False) timestamp: Mapped[datetime] = mapped_column(nullable=False)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
slash: bool = Column(Boolean, nullable=False) slash: Mapped[bool] = mapped_column(nullable=False)
context_menu: bool = Column(Boolean, 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): class CustomCommand(Base):
@ -116,13 +110,13 @@ class CustomCommand(Base):
__tablename__ = "custom_commands" __tablename__ = "custom_commands"
command_id: int = Column(Integer, primary_key=True) command_id: Mapped[int] = mapped_column(primary_key=True)
name: str = Column(Text, nullable=False, unique=True) name: Mapped[str] = mapped_column(nullable=False, unique=True)
indexed_name: str = Column(Text, nullable=False, index=True) indexed_name: Mapped[str] = mapped_column(nullable=False, index=True)
response: str = Column(Text, nullable=False) response: Mapped[str] = mapped_column(nullable=False)
aliases: list[CustomCommandAlias] = relationship( aliases: Mapped[List[CustomCommandAlias]] = relationship(
"CustomCommandAlias", back_populates="command", uselist=True, cascade="all, delete-orphan", lazy="selectin" back_populates="command", uselist=True, cascade="all, delete-orphan", lazy="selectin"
) )
@ -131,12 +125,12 @@ class CustomCommandAlias(Base):
__tablename__ = "custom_command_aliases" __tablename__ = "custom_command_aliases"
alias_id: int = Column(Integer, primary_key=True) alias_id: Mapped[int] = mapped_column(primary_key=True)
alias: str = Column(Text, nullable=False, unique=True) alias: Mapped[str] = mapped_column(nullable=False, unique=True)
indexed_alias: str = Column(Text, nullable=False, index=True) indexed_alias: Mapped[str] = mapped_column(nullable=False, index=True)
command_id: int = Column(Integer, ForeignKey("custom_commands.command_id")) 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): class DadJoke(Base):
@ -144,8 +138,8 @@ class DadJoke(Base):
__tablename__ = "dad_jokes" __tablename__ = "dad_jokes"
dad_joke_id: int = Column(Integer, primary_key=True) dad_joke_id: Mapped[int] = mapped_column(primary_key=True)
joke: str = Column(Text, nullable=False) joke: Mapped[str] = mapped_column(nullable=False)
class Deadline(Base): class Deadline(Base):
@ -153,12 +147,12 @@ class Deadline(Base):
__tablename__ = "deadlines" __tablename__ = "deadlines"
deadline_id: int = Column(Integer, primary_key=True) deadline_id: Mapped[int] = mapped_column(primary_key=True)
course_id: int = Column(Integer, ForeignKey("ufora_courses.course_id")) course_id: Mapped[int] = mapped_column(ForeignKey("ufora_courses.course_id"))
name: str = Column(Text, nullable=False) name: Mapped[str] = mapped_column(nullable=False)
deadline: datetime = Column(DateTime(timezone=True), 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): class EasterEgg(Base):
@ -166,11 +160,11 @@ class EasterEgg(Base):
__tablename__ = "easter_eggs" __tablename__ = "easter_eggs"
easter_egg_id: int = Column(Integer, primary_key=True) easter_egg_id: Mapped[int] = mapped_column(primary_key=True)
match: str = Column(Text, nullable=False) match: Mapped[str] = mapped_column(nullable=False)
response: str = Column(Text, nullable=False) response: Mapped[str] = mapped_column(nullable=False)
exact: bool = Column(Boolean, nullable=False, server_default="1") exact: Mapped[bool] = mapped_column(nullable=False, server_default="1")
startswith: bool = Column(Boolean, nullable=False, server_default="1") startswith: Mapped[bool] = mapped_column(nullable=False, server_default="1")
class Event(Base): class Event(Base):
@ -178,11 +172,11 @@ class Event(Base):
__tablename__ = "events" __tablename__ = "events"
event_id: int = Column(Integer, primary_key=True) event_id: Mapped[int] = mapped_column(primary_key=True)
name: str = Column(Text, nullable=False) name: Mapped[str] = mapped_column(nullable=False)
description: Optional[str] = Column(Text, nullable=True) description: Mapped[Optional[str]] = mapped_column(nullable=True)
notification_channel: int = Column(BigInteger, nullable=False) notification_channel: Mapped[int] = mapped_column(BigInteger, nullable=False)
timestamp: datetime = Column(DateTime(timezone=True), nullable=False) timestamp: Mapped[datetime] = mapped_column(nullable=False)
class FreeGame(Base): class FreeGame(Base):
@ -190,7 +184,7 @@ class FreeGame(Base):
__tablename__ = "free_games" __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): class GitHubLink(Base):
@ -198,11 +192,11 @@ class GitHubLink(Base):
__tablename__ = "github_links" __tablename__ = "github_links"
github_link_id: int = Column(Integer, primary_key=True) github_link_id: Mapped[int] = mapped_column(primary_key=True)
url: str = Column(Text, nullable=False, unique=True) url: Mapped[str] = mapped_column(nullable=False, unique=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) 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): class Link(Base):
@ -210,9 +204,9 @@ class Link(Base):
__tablename__ = "links" __tablename__ = "links"
link_id: int = Column(Integer, primary_key=True) link_id: Mapped[int] = mapped_column(primary_key=True)
name: str = Column(Text, nullable=False, unique=True) name: Mapped[str] = mapped_column(nullable=False, unique=True)
url: str = Column(Text, nullable=False) url: Mapped[str] = mapped_column(nullable=False)
class MemeTemplate(Base): class MemeTemplate(Base):
@ -220,10 +214,10 @@ class MemeTemplate(Base):
__tablename__ = "meme" __tablename__ = "meme"
meme_id: int = Column(Integer, primary_key=True) meme_id: Mapped[int] = mapped_column(primary_key=True)
name: str = Column(Text, nullable=False, unique=True) name: Mapped[str] = mapped_column(nullable=False, unique=True)
template_id: int = Column(Integer, nullable=False, unique=True) template_id: Mapped[int] = mapped_column(nullable=False, unique=True)
field_count: int = Column(Integer, nullable=False) field_count: Mapped[int] = mapped_column(nullable=False)
class NightlyData(Base): class NightlyData(Base):
@ -231,12 +225,12 @@ class NightlyData(Base):
__tablename__ = "nightly_data" __tablename__ = "nightly_data"
nightly_id: int = Column(Integer, primary_key=True) nightly_id: Mapped[int] = mapped_column(primary_key=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
last_nightly: Optional[date] = Column(Date, nullable=True) last_nightly: Mapped[Optional[date]] = mapped_column(nullable=True)
count: int = Column(Integer, server_default="0", nullable=False) 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): class Reminder(Base):
@ -244,11 +238,11 @@ class Reminder(Base):
__tablename__ = "reminders" __tablename__ = "reminders"
reminder_id: int = Column(Integer, primary_key=True) reminder_id: Mapped[int] = mapped_column(primary_key=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
category: enums.ReminderCategory = Column(Enum(enums.ReminderCategory), nullable=False) 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): class Task(Base):
@ -256,9 +250,9 @@ class Task(Base):
__tablename__ = "tasks" __tablename__ = "tasks"
task_id: int = Column(Integer, primary_key=True) task_id: Mapped[int] = mapped_column(primary_key=True)
task: enums.TaskType = Column(Enum(enums.TaskType), nullable=False, unique=True) task: Mapped[enums.TaskType] = mapped_column(nullable=False, unique=True)
previous_run: datetime = Column(DateTime(timezone=True), nullable=True) previous_run: Mapped[datetime] = mapped_column(nullable=True)
class UforaCourse(Base): class UforaCourse(Base):
@ -266,25 +260,25 @@ class UforaCourse(Base):
__tablename__ = "ufora_courses" __tablename__ = "ufora_courses"
course_id: int = Column(Integer, primary_key=True) course_id: Mapped[int] = mapped_column(primary_key=True)
name: str = Column(Text, nullable=False, unique=True) name: Mapped[str] = mapped_column(nullable=False, unique=True)
code: str = Column(Text, nullable=False, unique=True) code: Mapped[str] = mapped_column(nullable=False, unique=True)
year: int = Column(Integer, nullable=False) year: Mapped[int] = mapped_column(nullable=False)
compulsory: bool = Column(Boolean, server_default="1", nullable=False) compulsory: Mapped[bool] = mapped_column(server_default="1", nullable=False)
role_id: Optional[int] = Column(BigInteger, nullable=True, unique=False) role_id: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, unique=False)
overarching_role_id: Optional[int] = 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 # 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) alternative_overarching_role_id: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, unique=False)
log_announcements: bool = Column(Boolean, server_default="0", nullable=False) log_announcements: Mapped[bool] = mapped_column(server_default="0", nullable=False)
announcements: list[UforaAnnouncement] = relationship( announcements: Mapped[List[UforaAnnouncement]] = relationship(
"UforaAnnouncement", back_populates="course", cascade="all, delete-orphan", lazy="selectin" back_populates="course", cascade="all, delete-orphan", lazy="selectin"
) )
aliases: list[UforaCourseAlias] = relationship( aliases: Mapped[List[UforaCourseAlias]] = relationship(
"UforaCourseAlias", back_populates="course", cascade="all, delete-orphan", lazy="selectin" back_populates="course", cascade="all, delete-orphan", lazy="selectin"
) )
deadlines: list[Deadline] = relationship( deadlines: Mapped[List[Deadline]] = relationship(
"Deadline", back_populates="course", cascade="all, delete-orphan", lazy="selectin" back_populates="course", cascade="all, delete-orphan", lazy="selectin"
) )
@ -293,11 +287,11 @@ class UforaCourseAlias(Base):
__tablename__ = "ufora_course_aliases" __tablename__ = "ufora_course_aliases"
alias_id: int = Column(Integer, primary_key=True) alias_id: Mapped[int] = mapped_column(primary_key=True)
alias: str = Column(Text, nullable=False, unique=True) alias: Mapped[str] = mapped_column(nullable=False, unique=True)
course_id: int = Column(Integer, ForeignKey("ufora_courses.course_id")) 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): class UforaAnnouncement(Base):
@ -305,11 +299,11 @@ class UforaAnnouncement(Base):
__tablename__ = "ufora_announcements" __tablename__ = "ufora_announcements"
announcement_id: int = Column(Integer, primary_key=True) announcement_id: Mapped[int] = mapped_column(primary_key=True)
course_id: int = Column(Integer, ForeignKey("ufora_courses.course_id")) course_id: Mapped[int] = mapped_column(ForeignKey("ufora_courses.course_id"))
publication_date: date = Column(Date) 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): class User(Base):
@ -317,26 +311,26 @@ class User(Base):
__tablename__ = "users" __tablename__ = "users"
user_id: int = Column(BigInteger, primary_key=True) user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
bank: Bank = relationship( bank: Mapped[Bank] = relationship(
"Bank", back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan"
) )
birthday: Optional[Birthday] = relationship( birthday: Mapped[Optional[Birthday]] = relationship(
"Birthday", back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan"
) )
bookmarks: list[Bookmark] = relationship( bookmarks: Mapped[List[Bookmark]] = relationship(
"Bookmark", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan"
) )
command_stats: list[CommandStats] = relationship( command_stats: Mapped[List[CommandStats]] = relationship(
"CommandStats", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan"
) )
github_links: list[GitHubLink] = relationship( github_links: Mapped[List[GitHubLink]] = relationship(
"GitHubLink", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan"
) )
nightly_data: NightlyData = relationship( nightly_data: Mapped[NightlyData] = relationship(
"NightlyData", back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan" back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan"
) )
reminders: list[Reminder] = relationship( reminders: Mapped[List[Reminder]] = relationship(
"Reminder", back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan" back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan"
) )

View File

@ -19,7 +19,7 @@ async def get_country_info(http_session: ClientSession, country: str) -> CovidDa
yesterday = response yesterday = response
data = {"today": today, "yesterday": yesterday} data = {"today": today, "yesterday": yesterday}
return CovidData.parse_obj(data) return CovidData.model_validate(data)
async def get_global_info(http_session: ClientSession) -> CovidData: async def get_global_info(http_session: ClientSession) -> CovidData:
@ -35,4 +35,4 @@ async def get_global_info(http_session: ClientSession) -> CovidData:
yesterday = response yesterday = response
data = {"today": today, "yesterday": yesterday} data = {"today": today, "yesterday": yesterday}
return CovidData.parse_obj(data) return CovidData.model_validate(data)

View File

@ -12,4 +12,4 @@ async def fetch_menu(http_session: ClientSession, day_dt: date) -> Menu:
"""Fetch the menu for a given day""" """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" 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: async with ensure_get(http_session, endpoint, log_exceptions=False) as response:
return Menu.parse_obj(response) return Menu.model_validate(response)

View File

@ -14,4 +14,4 @@ async def lookup(http_session: ClientSession, query: str) -> list[Definition]:
url = "https://api.urbandictionary.com/v0/define" url = "https://api.urbandictionary.com/v0/define"
async with ensure_get(http_session, url, params={"term": query}) as response: 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"]))

View File

@ -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" url = "https://xkcd.com" + (f"/{num}" if num is not None else "") + "/info.0.json"
async with ensure_get(http_session, url) as response: async with ensure_get(http_session, url) as response:
return XKCDPost.parse_obj(response) return XKCDPost.model_validate(response)

View File

@ -1,6 +1,6 @@
import discord import discord
from overrides import overrides from overrides import overrides
from pydantic import BaseModel, Field, validator from pydantic import BaseModel, Field, field_validator
from didier.data.embeds.base import EmbedPydantic from didier.data.embeds.base import EmbedPydantic
@ -24,7 +24,7 @@ class _CovidNumbers(BaseModel):
active: int active: int
tests: int tests: int
@validator("updated") @field_validator("updated")
def updated_to_seconds(cls, value: int) -> int: def updated_to_seconds(cls, value: int) -> int:
"""Turn the updated field into seconds instead of milliseconds""" """Turn the updated field into seconds instead of milliseconds"""
return int(value) // 1000 return int(value) // 1000

View File

@ -4,18 +4,17 @@ from typing import Optional
import discord import discord
from aiohttp import ClientSession from aiohttp import ClientSession
from overrides import overrides from overrides import overrides
from pydantic import validator from pydantic import field_validator
from didier.data.embeds.base import EmbedPydantic from didier.data.embeds.base import EmbedPydantic
from didier.data.scrapers.common import GameStorePage from didier.data.scrapers.common import GameStorePage
from didier.data.scrapers.steam import get_steam_webpage_info from didier.data.scrapers.steam import get_steam_webpage_info
from didier.utils.discord import colours from didier.utils.discord import colours
__all__ = ["SEPARATOR", "FreeGameEmbed"]
from didier.utils.discord.constants import Limits from didier.utils.discord.constants import Limits
from didier.utils.types.string import abbreviate from didier.utils.types.string import abbreviate
__all__ = ["SEPARATOR", "FreeGameEmbed"]
SEPARATOR = " • Free • " SEPARATOR = " • Free • "
@ -58,7 +57,7 @@ class FreeGameEmbed(EmbedPydantic):
store_page: Optional[GameStorePage] = None store_page: Optional[GameStorePage] = None
@validator("title") @field_validator("title")
def _clean_title(cls, value: str) -> str: def _clean_title(cls, value: str) -> str:
return html.unescape(value) return html.unescape(value)
@ -107,7 +106,6 @@ class FreeGameEmbed(EmbedPydantic):
embed.add_field(name="Open in browser", value=f"[{self.link}]({self.link})") embed.add_field(name="Open in browser", value=f"[{self.link}]({self.link})")
if self.store_page.xdg_open_url is not None: if self.store_page.xdg_open_url is not None:
embed.add_field( embed.add_field(
name="Open in app", value=f"[{self.store_page.xdg_open_url}]({self.store_page.xdg_open_url})" name="Open in app", value=f"[{self.store_page.xdg_open_url}]({self.store_page.xdg_open_url})"
) )

View File

@ -2,7 +2,7 @@ from datetime import datetime
import discord import discord
from overrides import overrides from overrides import overrides
from pydantic import validator from pydantic import field_validator
from didier.data.embeds.base import EmbedPydantic from didier.data.embeds.base import EmbedPydantic
from didier.utils.discord import colours from didier.utils.discord import colours
@ -39,8 +39,8 @@ class Definition(EmbedPydantic):
total_votes = self.thumbs_up + self.thumbs_down total_votes = self.thumbs_up + self.thumbs_down
return round(100 * self.thumbs_up / total_votes, 2) return round(100 * self.thumbs_up / total_votes, 2)
@validator("definition", "example") @field_validator("definition", "example")
def modify_long_text(cls, field): def modify_long_text(cls, field: str):
"""Remove brackets from fields & cut them off if they are too long""" """Remove brackets from fields & cut them off if they are too long"""
field = field.replace("[", "").replace("]", "") field = field.replace("[", "").replace("]", "")
return string_utils.abbreviate(field, max_length=Limits.EMBED_FIELD_VALUE_LENGTH) return string_utils.abbreviate(field, max_length=Limits.EMBED_FIELD_VALUE_LENGTH)

View File

@ -32,7 +32,7 @@ async def fetch_free_games(http_session: ClientSession, database_session: AsyncS
if SEPARATOR not in entry["title"]: if SEPARATOR not in entry["title"]:
continue continue
game = FreeGameEmbed.parse_obj(entry) game = FreeGameEmbed.model_validate(entry)
games.append(game) games.append(game)
game_ids.append(game.dc_identifier) game_ids.append(game.dc_identifier)

View File

@ -1,22 +1,21 @@
black==22.3.0 black==23.3.0
coverage[toml]==6.4.1 coverage[toml]==7.2.7
freezegun==1.2.1 freezegun==1.2.2
isort==5.12.0 isort==5.12.0
mypy==0.961 mypy==1.4.1
pre-commit==2.20.0 pre-commit==3.3.3
pytest==7.1.2 pytest==7.4.0
pytest-asyncio==0.18.3 pytest-asyncio==0.21.0
pytest-env==0.6.2 pytest-env==0.8.2
sqlalchemy2-stubs==0.0.2a23 types-beautifulsoup4==4.12.0.5
types-beautifulsoup4==4.11.3 types-python-dateutil==2.8.19.13
types-python-dateutil==2.8.19
# Flake8 + plugins # Flake8 + plugins
flake8==4.0.1 flake8==6.0.0
flake8-bandit==3.0.0 flake8-bandit==4.1.1
flake8-bugbear==22.7.1 flake8-bugbear==23.6.5
flake8-docstrings==1.6.0 flake8-docstrings==1.7.0
flake8-dunder-all==0.2.1 flake8-dunder-all==0.3.0
flake8-eradicate==1.2.1 flake8-eradicate==1.5.0
flake8-isort==4.1.1 flake8-isort==6.0.0
flake8-simplify==0.19.2 flake8-simplify==0.20.0

View File

@ -1,13 +1,13 @@
aiohttp==3.8.1 aiohttp==3.8.4
alembic==1.8.0 alembic==1.11.1
asyncpg==0.25.0 asyncpg==0.28.0
beautifulsoup4==4.11.1 beautifulsoup4==4.12.2
discord.py==2.0.1 discord.py==2.3.1
environs==9.5.0 environs==9.5.0
feedparser==6.0.10 feedparser==6.0.10
ics==0.7.2 ics==0.7.2
markdownify==0.11.2 markdownify==0.11.6
overrides==6.1.0 overrides==7.3.1
pydantic==1.9.1 pydantic==2.0.2
python-dateutil==2.8.2 python-dateutil==2.8.2
sqlalchemy[asyncio]==1.4.37 sqlalchemy[asyncio]==2.0.18