Skip to content

Commit

Permalink
resolve some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
AbstractUmbra committed Jan 30, 2024
1 parent 9fc8566 commit 6d70b21
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 8 deletions.
51 changes: 44 additions & 7 deletions anilist-cmp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from fastapi.responses import Response

if TYPE_CHECKING:
from .types_.responses import AnilistResponse, InnerMediaEntry, MediaEntry
from .types_.responses import AnilistError, AnilistErrorResponse, AnilistResponse, InnerMediaEntry, MediaEntry

app = FastAPI(debug=False, title="Welcome!", version="0.0.1", openapi_url=None, redoc_url=None, docs_url=None)

Expand Down Expand Up @@ -88,12 +88,18 @@
"""


class NoPlanningData(ValueError):
def __init__(self, user: int, *args: object) -> None:
self.user = user
super().__init__(*args)


def format_entries_as_table(entries: dict[int, InnerMediaEntry]) -> str:
rows = [ROW.format_map(entry) for entry in entries.values()]
return TABLE.format(body="\n".join(rows))


async def _fetch_user_entries(*usernames: str) -> AnilistResponse:
async def _fetch_user_entries(*usernames: str) -> AnilistResponse | AnilistErrorResponse:
username1, username2 = usernames

async with aiohttp.ClientSession() as session, session.post(
Expand All @@ -108,28 +114,59 @@ def _restructure_entries(entries: list[MediaEntry]) -> dict[int, InnerMediaEntry


def _get_common_planning(data: AnilistResponse) -> dict[int, InnerMediaEntry]:
user1_data = data["data"]["user1"]
user2_data = data["data"]["user2"]
user1_data = data["data"]["user1"]["lists"]
user2_data = data["data"]["user2"]["lists"]

if not user1_data:
raise NoPlanningData(1)
elif not user2_data:
raise NoPlanningData(2)

user1_entries = _restructure_entries(user1_data["lists"][0]["entries"])
user2_entries = _restructure_entries(user2_data["lists"][0]["entries"])
user1_entries = _restructure_entries(user1_data[0]["entries"])
user2_entries = _restructure_entries(user2_data[0]["entries"])

all_anime = user1_entries | user2_entries
common_anime = user1_entries.keys() & user2_entries.keys()

return {id_: all_anime[id_] for id_ in common_anime}


def _handle_errors(errors: list[AnilistError], user1: str, user2: str) -> list[str]:
missing_users: list[str] = []
for error in errors:
if error["message"] == "User not found":
for location in error["locations"]:
if location["column"] == 2:
missing_users.append(user1)
elif location["column"] == 17:
missing_users.append(user2)

return missing_users


@app.get("/")
async def index() -> Response:
return Response("Did you forget to add path parameters? Like <url>/User1/User2?", media_type="text/plain")


@app.get("/{user1}/{user2}")
async def get_matches(request: Request, user1: str, user2: str) -> Response:
if user1.casefold() == user2.casefold():
return Response("Haha, you're really funny.", media_type="text/plain")

data = await _fetch_user_entries(user1.casefold(), user2.casefold())

matching_items = _get_common_planning(data)
if errors := data.get("errors"):
errored_users = _handle_errors(errors, user1, user2)

fmt = ", ".join(errored_users)
return Response(f"Sorry, it seems that user(s) {fmt} are not found.")

try:
matching_items = _get_common_planning(data) # type: ignore # the type is resolved above.
except NoPlanningData as err:
errored_user = user1 if err.user == 1 else user2
return Response(f"Sorry, but {errored_user} has no Planning entries!", media_type="text/plain")

if not matching_items:
return Response("No planning anime in common :(", status_code=405, media_type="text/plain")
Expand Down
23 changes: 22 additions & 1 deletion anilist-cmp/types_/responses.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import TypedDict
from typing import Literal, TypedDict


class LocalizedTitle(TypedDict):
Expand Down Expand Up @@ -34,3 +34,24 @@ class MediaListCollectionResponse(TypedDict):

class AnilistResponse(TypedDict):
data: MediaListCollectionResponse


class AnilistErrorLocation(TypedDict):
line: int
column: int


class AnilistError(TypedDict):
message: str
status: int
locations: list[AnilistErrorLocation]


class UserEntryError(TypedDict):
user1: Literal[None]
user2: Literal[None]


class AnilistErrorResponse(TypedDict):
errors: list[AnilistError]
data: UserEntryError

0 comments on commit 6d70b21

Please sign in to comment.