mirror of https://github.com/stijndcl/didier
fix typing issues
parent
654fbcd46b
commit
0186a0793a
|
@ -27,10 +27,13 @@ class Currency(commands.Cog):
|
|||
|
||||
@commands.command(name="Award")
|
||||
@commands.check(is_owner)
|
||||
async def award(self, ctx: commands.Context, user: discord.User, amount: abbreviated_number): # type: ignore
|
||||
async def award(
|
||||
self,
|
||||
ctx: commands.Context,
|
||||
user: discord.User,
|
||||
amount: typing.Annotated[int, abbreviated_number],
|
||||
):
|
||||
"""Award a user a given amount of Didier Dinks"""
|
||||
amount = typing.cast(int, amount)
|
||||
|
||||
async with self.client.postgres_session as session:
|
||||
await crud.add_dinks(session, user.id, amount)
|
||||
plural = pluralize("Didier Dink", amount)
|
||||
|
@ -116,10 +119,8 @@ class Currency(commands.Cog):
|
|||
await ctx.reply(f"**{ctx.author.display_name}** has **{bank.dinks}** {plural}.", mention_author=False)
|
||||
|
||||
@commands.command(name="Invest", aliases=["Deposit", "Dep"])
|
||||
async def invest(self, ctx: commands.Context, amount: abbreviated_number): # type: ignore
|
||||
async def invest(self, ctx: commands.Context, amount: typing.Annotated[typing.Union[str, int], abbreviated_number]):
|
||||
"""Invest a given amount of Didier Dinks"""
|
||||
amount = typing.cast(typing.Union[str, int], amount)
|
||||
|
||||
async with self.client.postgres_session as session:
|
||||
invested = await crud.invest(session, ctx.author.id, amount)
|
||||
plural = pluralize("Didier Dink", invested)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
|
@ -5,7 +8,10 @@ from discord.ext import commands
|
|||
from database.crud import ufora_courses
|
||||
from database.crud.deadlines import get_deadlines
|
||||
from didier import Didier
|
||||
from didier.data.apis.hydra import fetch_menu
|
||||
from didier.data.embeds.deadlines import Deadlines
|
||||
from didier.data.embeds.hydra import no_menu_found
|
||||
from didier.exceptions import HTTPException
|
||||
from didier.utils.discord.flags.school import StudyGuideFlags
|
||||
|
||||
|
||||
|
@ -26,6 +32,23 @@ class School(commands.Cog):
|
|||
embed = Deadlines(deadlines).to_embed()
|
||||
await ctx.reply(embed=embed, mention_author=False, ephemeral=False)
|
||||
|
||||
@commands.hybrid_command(
|
||||
name="menu", description="Show the menu in the Ghent University restaurants", aliases=["Eten", "Food"]
|
||||
)
|
||||
async def menu(self, ctx: commands.Context, day: Optional[str] = None):
|
||||
"""Get the menu for a given day in the restaurants"""
|
||||
# TODO time converter (transformer) for [DAY]
|
||||
# TODO autocompletion for [DAY]
|
||||
async with ctx.typing():
|
||||
day_dt = datetime.now()
|
||||
|
||||
try:
|
||||
menu = await fetch_menu(self.client.http_session, day_dt)
|
||||
embed = menu.to_embed(day_dt=day_dt)
|
||||
except HTTPException:
|
||||
embed = no_menu_found(day_dt)
|
||||
await ctx.reply(embed=embed, mention_author=False)
|
||||
|
||||
@commands.hybrid_command(
|
||||
name="fiche", description="Sends the link to the study guide for [Course]", aliases=["guide", "studiefiche"]
|
||||
)
|
||||
|
|
|
@ -11,5 +11,5 @@ __all__ = ["fetch_menu"]
|
|||
async def fetch_menu(http_session: ClientSession, day_dt: datetime) -> 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) as response:
|
||||
async with ensure_get(http_session, endpoint, log_exceptions=False) as response:
|
||||
return Menu.parse_obj(response)
|
||||
|
|
|
@ -13,7 +13,7 @@ class EmbedBaseModel(ABC):
|
|||
"""Abstract base class for a model that can be turned into a Discord embed"""
|
||||
|
||||
@abstractmethod
|
||||
def to_embed(self, **kwargs: dict) -> discord.Embed:
|
||||
def to_embed(self, **kwargs) -> discord.Embed:
|
||||
"""Turn this model into a Discord embed"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class Deadlines(EmbedBaseModel):
|
|||
self.deadlines.sort(key=lambda deadline: deadline.deadline)
|
||||
|
||||
@overrides
|
||||
def to_embed(self, **kwargs: dict) -> discord.Embed:
|
||||
def to_embed(self, **kwargs) -> discord.Embed:
|
||||
embed = discord.Embed(title="Upcoming Deadlines", colour=discord.Colour.dark_gold())
|
||||
now = tz_aware_now()
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ class GoogleSearch(EmbedBaseModel):
|
|||
return embed
|
||||
|
||||
@overrides
|
||||
def to_embed(self, **kwargs: dict) -> discord.Embed:
|
||||
def to_embed(self, **kwargs) -> discord.Embed:
|
||||
if not self.data.results or self.data.status_code != HTTPStatus.OK:
|
||||
return self._error_embed()
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
from .menu import Menu
|
||||
from .menu import Menu, no_menu_found
|
||||
|
||||
__all__ = ["Menu"]
|
||||
__all__ = ["Menu", "no_menu_found"]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from typing import Literal, Optional
|
||||
from datetime import datetime
|
||||
from typing import Literal, Optional, cast
|
||||
|
||||
import discord
|
||||
from overrides import overrides
|
||||
|
@ -6,8 +7,10 @@ from pydantic import BaseModel
|
|||
|
||||
from didier.data.embeds.base import EmbedPydantic
|
||||
from didier.utils.discord.colours import ghent_university_blue
|
||||
from didier.utils.types.datetime import int_to_weekday
|
||||
from didier.utils.types.string import leading
|
||||
|
||||
__all__ = ["Menu"]
|
||||
__all__ = ["Menu", "no_menu_found"]
|
||||
|
||||
|
||||
class _Meal(BaseModel):
|
||||
|
@ -16,7 +19,7 @@ class _Meal(BaseModel):
|
|||
kind: Literal["meat", "fish", "soup", "vegetarian", "vegan"]
|
||||
name: str
|
||||
price: str
|
||||
type: Literal["main", "side"]
|
||||
type: Literal["cold", "main", "side"]
|
||||
|
||||
|
||||
class Menu(EmbedPydantic):
|
||||
|
@ -28,7 +31,18 @@ class Menu(EmbedPydantic):
|
|||
message: Optional[str] = None
|
||||
|
||||
@overrides
|
||||
def to_embed(self, **kwargs: dict) -> discord.Embed:
|
||||
embed = discord.Embed(title="Menu", colour=ghent_university_blue())
|
||||
def to_embed(self, **kwargs) -> discord.Embed:
|
||||
day_dt: datetime = cast(datetime, kwargs.get("day_dt"))
|
||||
weekday = int_to_weekday(day_dt.weekday())
|
||||
formatted_date = f"{leading('0', str(day_dt.day))}/{leading('0', str(day_dt.month))}/{day_dt.year}"
|
||||
|
||||
embed = discord.Embed(title=f"Menu - {weekday} {formatted_date}", colour=ghent_university_blue())
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def no_menu_found(day_dt: datetime) -> discord.Embed:
|
||||
"""Return a different embed if no menu could be found"""
|
||||
embed = discord.Embed(title="Menu", colour=discord.Colour.red())
|
||||
embed.description = f"Unable to retrieve menu for {day_dt.strftime('%d/%m/%Y')}."
|
||||
return embed
|
||||
|
|
|
@ -48,7 +48,7 @@ class UforaNotification(EmbedBaseModel):
|
|||
self.published_dt = self._published_datetime()
|
||||
self._published = self._get_published()
|
||||
|
||||
def to_embed(self, **kwargs: dict) -> discord.Embed:
|
||||
def to_embed(self, **kwargs) -> discord.Embed:
|
||||
"""Turn the notification into an embed"""
|
||||
embed = discord.Embed(title=self._title, colour=ghent_university_blue())
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class Definition(EmbedPydantic):
|
|||
return string_utils.abbreviate(field, max_length=Limits.EMBED_FIELD_VALUE_LENGTH)
|
||||
|
||||
@overrides
|
||||
def to_embed(self, **kwargs: dict) -> discord.Embed:
|
||||
def to_embed(self, **kwargs) -> discord.Embed:
|
||||
embed = discord.Embed(title="Urban Dictionary", colour=colours.urban_dictionary_green())
|
||||
|
||||
embed.add_field(name="Term", value=self.word, inline=True)
|
||||
|
|
|
@ -126,7 +126,7 @@ class WordleErrorEmbed(EmbedBaseModel):
|
|||
message: str
|
||||
|
||||
@overrides
|
||||
def to_embed(self, **kwargs: dict) -> discord.Embed:
|
||||
def to_embed(self, **kwargs) -> discord.Embed:
|
||||
embed = discord.Embed(colour=discord.Colour.red(), title="Wordle")
|
||||
embed.description = self.message
|
||||
embed.set_footer(text=footer())
|
||||
|
|
|
@ -2,7 +2,7 @@ import logging
|
|||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncGenerator
|
||||
|
||||
from aiohttp import ClientResponse, ClientSession
|
||||
from aiohttp import ClientResponse, ClientSession, ContentTypeError
|
||||
|
||||
from didier.exceptions.http_exception import HTTPException
|
||||
|
||||
|
@ -18,13 +18,19 @@ def request_successful(response: ClientResponse) -> bool:
|
|||
|
||||
|
||||
@asynccontextmanager
|
||||
async def ensure_get(http_session: ClientSession, endpoint: str) -> AsyncGenerator[dict, None]:
|
||||
async def ensure_get(
|
||||
http_session: ClientSession, endpoint: str, *, log_exceptions: bool = True
|
||||
) -> AsyncGenerator[dict, None]:
|
||||
"""Context manager that automatically raises an exception if a GET-request fails"""
|
||||
async with http_session.get(endpoint) as response:
|
||||
try:
|
||||
content = await response.json()
|
||||
except ContentTypeError:
|
||||
content = await response.text()
|
||||
|
||||
if not request_successful(response):
|
||||
logger.error(
|
||||
"Failed HTTP request to %s (status %s)\nResponse: %s", endpoint, response.status, await response.json()
|
||||
)
|
||||
if log_exceptions:
|
||||
logger.error("Failed HTTP request to %s (status %s)\nResponse: %s", endpoint, response.status, content)
|
||||
|
||||
raise HTTPException(response.status)
|
||||
|
||||
|
@ -33,18 +39,29 @@ async def ensure_get(http_session: ClientSession, endpoint: str) -> AsyncGenerat
|
|||
|
||||
@asynccontextmanager
|
||||
async def ensure_post(
|
||||
http_session: ClientSession, endpoint: str, payload: dict, *, expect_return: bool = True
|
||||
http_session: ClientSession,
|
||||
endpoint: str,
|
||||
payload: dict,
|
||||
*,
|
||||
log_exceptions: bool = True,
|
||||
expect_return: bool = True
|
||||
) -> AsyncGenerator[dict, None]:
|
||||
"""Context manager that automatically raises an exception if a POST-request fails"""
|
||||
async with http_session.post(endpoint, data=payload) as response:
|
||||
if not request_successful(response):
|
||||
logger.error(
|
||||
"Failed HTTP request to %s (status %s)\nPayload: %s\nResponse: %s",
|
||||
endpoint,
|
||||
response.status,
|
||||
payload,
|
||||
await response.json(),
|
||||
)
|
||||
try:
|
||||
content = await response.json()
|
||||
except ContentTypeError:
|
||||
content = await response.text()
|
||||
|
||||
if log_exceptions:
|
||||
logger.error(
|
||||
"Failed HTTP request to %s (status %s)\nPayload: %s\nResponse: %s",
|
||||
endpoint,
|
||||
response.status,
|
||||
payload,
|
||||
content,
|
||||
)
|
||||
|
||||
raise HTTPException(response.status)
|
||||
|
||||
|
|
Loading…
Reference in New Issue