From 4be6afb541f3e1761cd70957b02f57b181b50414 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Sat, 31 Jan 2026 15:52:14 -0600 Subject: [PATCH] Add API timeout/retry logic and fix get_team_by_owner for PostgreSQL - Add APITimeoutError exception and retry logic to db_get - Add timeout handling to db_post, db_put, db_patch, db_delete - Fix get_team_by_owner to prefer non-gauntlet team (PostgreSQL migration fix) - Code formatting cleanup (black) --- api_calls.py | 328 +++-- exceptions.py | 28 +- gauntlets.py | 2553 ++++++++++++++++++++++++--------------- helpers.py | 1943 ++++++++++++++++------------- helpers/main.py | 1944 ++++++++++++++++------------- tests/test_api_calls.py | 237 ++-- 6 files changed, 4102 insertions(+), 2931 deletions(-) diff --git a/api_calls.py b/api_calls.py index f12e044..222847a 100644 --- a/api_calls.py +++ b/api_calls.py @@ -1,35 +1,46 @@ +import asyncio import datetime from dataclasses import dataclass from typing import Optional import logging import aiohttp +from aiohttp import ClientTimeout import os -from exceptions import DatabaseError +from exceptions import DatabaseError, APITimeoutError -AUTH_TOKEN = {'Authorization': f'Bearer {os.environ.get("API_TOKEN")}'} +AUTH_TOKEN = {"Authorization": f"Bearer {os.environ.get('API_TOKEN')}"} ENV_DATABASE = os.getenv("DATABASE", "dev").lower() -DB_URL = 'https://pd.manticorum.com/api' if 'prod' in ENV_DATABASE else 'https://pddev.manticorum.com/api' +DB_URL = ( + "https://pd.manticorum.com/api" + if "prod" in ENV_DATABASE + else "https://pddev.manticorum.com/api" +) master_debug = True PLAYER_CACHE = {} -logger = logging.getLogger('discord_app') +logger = logging.getLogger("discord_app") def param_char(other_params): if other_params: - return '&' + return "&" else: - return '?' + return "?" -def get_req_url(endpoint: str, api_ver: int = 2, object_id: Optional[int] = None, params: Optional[list] = None): - req_url = f'{DB_URL}/v{api_ver}/{endpoint}{"/" if object_id is not None else ""}{object_id if object_id is not None else ""}' +def get_req_url( + endpoint: str, + api_ver: int = 2, + object_id: Optional[int] = None, + params: Optional[list] = None, +): + req_url = f"{DB_URL}/v{api_ver}/{endpoint}{'/' if object_id is not None else ''}{object_id if object_id is not None else ''}" if params: other_params = False for x in params: - req_url += f'{param_char(other_params)}{x[0]}={x[1]}' + req_url += f"{param_char(other_params)}{x[0]}={x[1]}" other_params = True return req_url @@ -42,144 +53,251 @@ def log_return_value(log_string: str): line = log_string[start:end] if len(line) == 0: return - logger.info(f'{"\n\nreturn: " if start == 0 else ""}{log_string[start:end]}') + logger.info(f"{'\n\nreturn: ' if start == 0 else ''}{log_string[start:end]}") start += 3000 end += 3000 - logger.warning('[ S N I P P E D ]') + logger.warning("[ S N I P P E D ]") # if master_debug: # logger.info(f'return: {log_string[:1200]}{" [ S N I P P E D ]" if len(log_string) > 1200 else ""}\n') # else: # logger.debug(f'return: {log_string[:1200]}{" [ S N I P P E D ]" if len(log_string) > 1200 else ""}\n') -async def db_get(endpoint: str, api_ver: int = 2, object_id: Optional[int] = None, params: Optional[list] = None, none_okay: bool = True, timeout: int = 3): +async def db_get( + endpoint: str, + api_ver: int = 2, + object_id: Optional[int] = None, + params: Optional[list] = None, + none_okay: bool = True, + timeout: int = 5, + retries: int = 3, +): + """ + GET request to the API with timeout and retry logic. + + Args: + endpoint: API endpoint path + api_ver: API version (default 2) + object_id: Optional object ID to append to URL + params: Optional list of (key, value) tuples for query params + none_okay: If True, return None on non-200 response; if False, raise DatabaseError + timeout: Request timeout in seconds (default 5) + retries: Number of retry attempts on timeout (default 3) + + Returns: + JSON response or None if none_okay and request failed + + Raises: + APITimeoutError: If all retry attempts fail due to timeout + DatabaseError: If response is non-200 and none_okay is False + """ req_url = get_req_url(endpoint, api_ver=api_ver, object_id=object_id, params=params) - log_string = f'db_get - get: {endpoint} id: {object_id} params: {params}' + log_string = f"db_get - get: {endpoint} id: {object_id} params: {params}" logger.info(log_string) if master_debug else logger.debug(log_string) - async with aiohttp.ClientSession(headers=AUTH_TOKEN) as session: - async with session.get(req_url) as r: - if r.status == 200: - js = await r.json() - log_return_value(f'{js}') - return js - elif none_okay: - e = await r.text() - logger.error(e) - return None + for attempt in range(retries): + try: + client_timeout = ClientTimeout(total=timeout) + async with aiohttp.ClientSession( + headers=AUTH_TOKEN, timeout=client_timeout + ) as session: + async with session.get(req_url) as r: + if r.status == 200: + js = await r.json() + log_return_value(f"{js}") + return js + elif none_okay: + e = await r.text() + logger.error(e) + return None + else: + e = await r.text() + logger.error(e) + raise DatabaseError(e) + except asyncio.TimeoutError: + if attempt < retries - 1: + wait_time = 2**attempt # 1s, 2s, 4s + logger.warning( + f"Timeout on GET {endpoint}, retry {attempt + 1}/{retries} in {wait_time}s" + ) + await asyncio.sleep(wait_time) else: - e = await r.text() - logger.error(e) - raise DatabaseError(e) + logger.error( + f"Connection timeout to host {req_url} after {retries} attempts" + ) + raise APITimeoutError(f"Connection timeout to host {req_url}") -async def db_patch(endpoint: str, object_id: int, params: list, api_ver: int = 2, timeout: int = 3): +async def db_patch( + endpoint: str, object_id: int, params: list, api_ver: int = 2, timeout: int = 5 +): + """ + PATCH request to the API with timeout (no retry - not safe for mutations). + + Args: + endpoint: API endpoint path + object_id: Object ID to patch + params: List of (key, value) tuples for query params + api_ver: API version (default 2) + timeout: Request timeout in seconds (default 5) + + Raises: + APITimeoutError: If request times out + DatabaseError: If response is non-200 + """ req_url = get_req_url(endpoint, api_ver=api_ver, object_id=object_id, params=params) - log_string = f'db_patch - patch: {endpoint} {params}' + log_string = f"db_patch - patch: {endpoint} {params}" logger.info(log_string) if master_debug else logger.debug(log_string) - async with aiohttp.ClientSession(headers=AUTH_TOKEN) as session: - async with session.patch(req_url) as r: - if r.status == 200: - js = await r.json() - log_return_value(f'{js}') - return js - else: - e = await r.text() - logger.error(e) - raise DatabaseError(e) + try: + client_timeout = ClientTimeout(total=timeout) + async with aiohttp.ClientSession( + headers=AUTH_TOKEN, timeout=client_timeout + ) as session: + async with session.patch(req_url) as r: + if r.status == 200: + js = await r.json() + log_return_value(f"{js}") + return js + else: + e = await r.text() + logger.error(e) + raise DatabaseError(e) + except asyncio.TimeoutError: + logger.error(f"Connection timeout to host {req_url}") + raise APITimeoutError(f"Connection timeout to host {req_url}") -async def db_post(endpoint: str, api_ver: int = 2, payload: Optional[dict] = None, timeout: int = 3): +async def db_post( + endpoint: str, api_ver: int = 2, payload: Optional[dict] = None, timeout: int = 5 +): + """ + POST request to the API with timeout (no retry - not safe for mutations). + + Args: + endpoint: API endpoint path + api_ver: API version (default 2) + payload: Optional JSON payload + timeout: Request timeout in seconds (default 5) + + Raises: + APITimeoutError: If request times out + DatabaseError: If response is non-200 + """ req_url = get_req_url(endpoint, api_ver=api_ver) - log_string = f'db_post - post: {endpoint} payload: {payload}\ntype: {type(payload)}' + log_string = f"db_post - post: {endpoint} payload: {payload}\ntype: {type(payload)}" logger.info(log_string) if master_debug else logger.debug(log_string) - async with aiohttp.ClientSession(headers=AUTH_TOKEN) as session: - async with session.post(req_url, json=payload) as r: - if r.status == 200: - js = await r.json() - log_return_value(f'{js}') - return js - else: - e = await r.text() - logger.error(e) - raise DatabaseError(e) + try: + client_timeout = ClientTimeout(total=timeout) + async with aiohttp.ClientSession( + headers=AUTH_TOKEN, timeout=client_timeout + ) as session: + async with session.post(req_url, json=payload) as r: + if r.status == 200: + js = await r.json() + log_return_value(f"{js}") + return js + else: + e = await r.text() + logger.error(e) + raise DatabaseError(e) + except asyncio.TimeoutError: + logger.error(f"Connection timeout to host {req_url}") + raise APITimeoutError(f"Connection timeout to host {req_url}") -async def db_put(endpoint: str, api_ver: int = 2, payload: Optional[dict] = None, timeout: int = 3): +async def db_put( + endpoint: str, api_ver: int = 2, payload: Optional[dict] = None, timeout: int = 5 +): + """ + PUT request to the API with timeout (no retry - not safe for mutations). + + Args: + endpoint: API endpoint path + api_ver: API version (default 2) + payload: Optional JSON payload + timeout: Request timeout in seconds (default 5) + + Raises: + APITimeoutError: If request times out + DatabaseError: If response is non-200 + """ req_url = get_req_url(endpoint, api_ver=api_ver) - log_string = f'post:\n{endpoint} payload: {payload}\ntype: {type(payload)}' + log_string = f"db_put - put: {endpoint} payload: {payload}\ntype: {type(payload)}" logger.info(log_string) if master_debug else logger.debug(log_string) - async with aiohttp.ClientSession(headers=AUTH_TOKEN) as session: - async with session.put(req_url, json=payload) as r: - if r.status == 200: - js = await r.json() - log_return_value(f'{js}') - return js - else: - e = await r.text() - logger.error(e) - raise DatabaseError(e) - - # retries = 0 - # while True: - # try: - # resp = requests.put(req_url, json=payload, headers=AUTH_TOKEN, timeout=timeout) - # break - # except requests.Timeout as e: - # logger.error(f'Post Timeout: {req_url} / retries: {retries} / timeout: {timeout}') - # if retries > 1: - # raise ConnectionError(f'DB: The internet was a bit too slow for me to grab the data I needed. Please ' - # f'hang on a few extra seconds and try again.') - # timeout += [min(3, timeout), min(5, timeout)][retries] - # retries += 1 - # - # if resp.status_code == 200: - # data = resp.json() - # log_string = f'{data}' - # if master_debug: - # logger.info(f'return: {log_string[:1200]}{" [ S N I P P E D ]" if len(log_string) > 1200 else ""}') - # else: - # logger.debug(f'return: {log_string[:1200]}{" [ S N I P P E D ]" if len(log_string) > 1200 else ""}') - # return data - # else: - # logger.warning(resp.text) - # raise ValueError(f'DB: {resp.text}') + try: + client_timeout = ClientTimeout(total=timeout) + async with aiohttp.ClientSession( + headers=AUTH_TOKEN, timeout=client_timeout + ) as session: + async with session.put(req_url, json=payload) as r: + if r.status == 200: + js = await r.json() + log_return_value(f"{js}") + return js + else: + e = await r.text() + logger.error(e) + raise DatabaseError(e) + except asyncio.TimeoutError: + logger.error(f"Connection timeout to host {req_url}") + raise APITimeoutError(f"Connection timeout to host {req_url}") -async def db_delete(endpoint: str, object_id: int, api_ver: int = 2, timeout=3): +async def db_delete(endpoint: str, object_id: int, api_ver: int = 2, timeout: int = 5): + """ + DELETE request to the API with timeout (no retry - not safe for mutations). + + Args: + endpoint: API endpoint path + object_id: Object ID to delete + api_ver: API version (default 2) + timeout: Request timeout in seconds (default 5) + + Raises: + APITimeoutError: If request times out + DatabaseError: If response is non-200 + """ req_url = get_req_url(endpoint, api_ver=api_ver, object_id=object_id) - log_string = f'db_delete - delete: {endpoint} {object_id}' + log_string = f"db_delete - delete: {endpoint} {object_id}" logger.info(log_string) if master_debug else logger.debug(log_string) - async with aiohttp.ClientSession(headers=AUTH_TOKEN) as session: - async with session.delete(req_url) as r: - if r.status == 200: - js = await r.json() - log_return_value(f'{js}') - return js - else: - e = await r.text() - logger.error(e) - raise DatabaseError(e) + try: + client_timeout = ClientTimeout(total=timeout) + async with aiohttp.ClientSession( + headers=AUTH_TOKEN, timeout=client_timeout + ) as session: + async with session.delete(req_url) as r: + if r.status == 200: + js = await r.json() + log_return_value(f"{js}") + return js + else: + e = await r.text() + logger.error(e) + raise DatabaseError(e) + except asyncio.TimeoutError: + logger.error(f"Connection timeout to host {req_url}") + raise APITimeoutError(f"Connection timeout to host {req_url}") async def get_team_by_abbrev(abbrev: str): - all_teams = await db_get('teams', params=[('abbrev', abbrev)]) + all_teams = await db_get("teams", params=[("abbrev", abbrev)]) - if not all_teams or not all_teams['count']: + if not all_teams or not all_teams["count"]: return None - return all_teams['teams'][0] + return all_teams["teams"][0] async def post_to_dex(player, team): - return await db_post('paperdex', payload={'team_id': team['id'], 'player_id': player['id']}) + return await db_post( + "paperdex", payload={"team_id": team["id"], "player_id": player["id"]} + ) def team_hash(team): - hash_string = f'{team["sname"][-1]}{team["gmid"] / 6950123:.0f}{team["sname"][-2]}{team["gmid"] / 42069123:.0f}' + hash_string = f"{team['sname'][-1]}{team['gmid'] / 6950123:.0f}{team['sname'][-2]}{team['gmid'] / 42069123:.0f}" return hash_string - diff --git a/exceptions.py b/exceptions.py index 8838981..8bc7b7a 100644 --- a/exceptions.py +++ b/exceptions.py @@ -1,7 +1,7 @@ import logging from typing import Literal -logger = logging.getLogger('discord_app') +logger = logging.getLogger("discord_app") def log_errors(func): @@ -15,26 +15,32 @@ def log_errors(func): except Exception as e: logger.error(func.__name__) log_exception(e) - return result # type: ignore - + return result # type: ignore + return wrap -def log_exception(e: Exception, msg: str = '', level: Literal['debug', 'error', 'info', 'warn'] = 'error'): - if level == 'debug': + +def log_exception( + e: Exception, + msg: str = "", + level: Literal["debug", "error", "info", "warn"] = "error", +): + if level == "debug": logger.debug(msg, exc_info=True, stack_info=True) - elif level == 'error': + elif level == "error": logger.error(msg, exc_info=True, stack_info=True) - elif level == 'info': + elif level == "info": logger.info(msg, exc_info=True, stack_info=True) else: logger.warning(msg, exc_info=True, stack_info=True) - + # Check if 'e' is an exception class or instance if isinstance(e, Exception): raise e # If 'e' is already an instance of an exception else: raise e(msg) # If 'e' is an exception class + class GameException(Exception): pass @@ -75,6 +81,12 @@ class DatabaseError(GameException): pass +class APITimeoutError(DatabaseError): + """Raised when an API call times out after all retries.""" + + pass + + class PositionNotFoundException(GameException): pass diff --git a/gauntlets.py b/gauntlets.py index b1283fe..d617bd6 100644 --- a/gauntlets.py +++ b/gauntlets.py @@ -14,59 +14,81 @@ import helpers from helpers import RARITY, get_or_create_role, send_to_channel, get_channel from api_calls import db_get, db_post, db_delete, db_patch from in_game.gameplay_models import Lineup, Team -from in_game.gameplay_queries import get_player_or_none, get_team_or_none, get_or_create_ai_card, get_player_id_from_dict +from in_game.gameplay_queries import ( + get_player_or_none, + get_team_or_none, + get_or_create_ai_card, + get_player_id_from_dict, +) from utilities.dropdown import DropdownView, SelectPokemonEvolution -logger = logging.getLogger('discord_app') +logger = logging.getLogger("discord_app") -async def wipe_team(this_team: Team, interaction: discord.Interaction, delete_team: bool = False, delete_runs: bool = False): - await interaction.edit_original_response(content=f'Looking for cards...') +async def wipe_team( + this_team: Team, + interaction: discord.Interaction, + delete_team: bool = False, + delete_runs: bool = False, +): + await interaction.edit_original_response(content=f"Looking for cards...") # Delete cards # c_query = await db_get('cards', params=[('team_id', this_team['id'])]) # await interaction.edit_original_response(content=f'Found {c_query["count"]} cards; deleting cards...') # for x in c_query['cards']: # await db_delete('cards', object_id=x['id']) - c_query = await db_post(f'cards/wipe-team/{this_team.id}') + c_query = await db_post(f"cards/wipe-team/{this_team.id}") # Delete packs - await interaction.edit_original_response(content=f'Done deleting cards; searching for packs...') - p_query = await db_get('packs', params=[('team_id', this_team.id)]) - await interaction.edit_original_response(content=f'Found {p_query["count"]} packs; deleting packs...') - for x in p_query['packs']: - await db_delete('packs', object_id=x['id']) + await interaction.edit_original_response( + content=f"Done deleting cards; searching for packs..." + ) + p_query = await db_get("packs", params=[("team_id", this_team.id)]) + await interaction.edit_original_response( + content=f"Found {p_query['count']} packs; deleting packs..." + ) + for x in p_query["packs"]: + await db_delete("packs", object_id=x["id"]) # Delete team if delete_team: - await interaction.edit_original_response(content=f'Done deleting packs; now deleting team...') - await db_delete('teams', object_id=this_team.id) - await interaction.edit_original_response(content=f'Team is deleted; now finding the run...') + await interaction.edit_original_response( + content=f"Done deleting packs; now deleting team..." + ) + await db_delete("teams", object_id=this_team.id) + await interaction.edit_original_response( + content=f"Team is deleted; now finding the run..." + ) if delete_runs: - r_query = await db_get('gauntletruns', params=[('team_id', this_team.id), ('is_active', True)]) - await interaction.edit_original_response(content=f'Found {r_query["count"]} runs; deleting now...') - for x in r_query['runs']: - await db_delete('gauntletruns', object_id=x['id']) + r_query = await db_get( + "gauntletruns", params=[("team_id", this_team.id), ("is_active", True)] + ) + await interaction.edit_original_response( + content=f"Found {r_query['count']} runs; deleting now..." + ) + for x in r_query["runs"]: + await db_delete("gauntletruns", object_id=x["id"]) def get_game_code(this_team, this_event, this_run): - return f'gauntlet-{this_event["id"]}-run-{this_run["id"]}' + return f"gauntlet-{this_event['id']}-run-{this_run['id']}" def games_played(this_run): - return this_run['wins'] + this_run['losses'] + return this_run["wins"] + this_run["losses"] def is_home_team(this_team, this_event, this_run): - if this_event['id'] in [1, 2]: + if this_event["id"] in [1, 2]: return True return False async def get_opponent(session: Session, this_team, this_event, this_run) -> Team: gp = games_played(this_run) - if this_event['id'] == 1: + if this_event["id"] == 1: if gp == 0: t_id = 30 elif gp == 1: @@ -90,8 +112,8 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: t_id = 58 else: - raise KeyError(f'Huh...I have no idea who you should be playing right now.') - elif this_event['id'] == 2: + raise KeyError(f"Huh...I have no idea who you should be playing right now.") + elif this_event["id"] == 2: if gp == 0: t_id = 23 elif gp == 1: @@ -115,8 +137,8 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: t_id = 28 else: - raise KeyError(f'Huh...I have no idea who you should be playing right now.') - elif this_event['id'] == 3: + raise KeyError(f"Huh...I have no idea who you should be playing right now.") + elif this_event["id"] == 3: if gp == 0: t_id = 28 elif gp == 1: @@ -140,8 +162,8 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: t_id = 19 else: - raise KeyError(f'Huh...I have no idea who you should be playing right now.') - elif this_event['id'] == 4: + raise KeyError(f"Huh...I have no idea who you should be playing right now.") + elif this_event["id"] == 4: if gp == 0: t_id = 3 elif gp == 1: @@ -165,8 +187,8 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: t_id = 79 else: - raise KeyError(f'Hmm...I do not know who you should be playing right now.') - elif this_event['id'] == 5: + raise KeyError(f"Hmm...I do not know who you should be playing right now.") + elif this_event["id"] == 5: if gp == 0: t_id = 15 elif gp == 1: @@ -190,8 +212,8 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: t_id = 19 else: - raise KeyError(f'Hmm...I do not know who you should be playing right now.') - elif this_event['id'] == 6: + raise KeyError(f"Hmm...I do not know who you should be playing right now.") + elif this_event["id"] == 6: if gp == 0: t_id = 18 elif gp == 1: @@ -215,8 +237,8 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: t_id = 25 else: - raise KeyError(f'Hmm...I do not know who you should be playing right now.') - elif this_event['id'] == 7: + raise KeyError(f"Hmm...I do not know who you should be playing right now.") + elif this_event["id"] == 7: if gp == 0: t_id = 10 elif gp == 1: @@ -240,8 +262,8 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: t_id = 17 else: - raise KeyError(f'Hmm...I do not know who you should be playing right now.') - elif this_event['id'] == 8: + raise KeyError(f"Hmm...I do not know who you should be playing right now.") + elif this_event["id"] == 8: if gp == 0: teams = [6, 9] # White Sox and Rockies elif gp == 1: @@ -255,7 +277,7 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 5: teams = [26, 27] # Cardinals, Rays elif gp == 6: - teams = [7, 25, 4] # Reds, Giants, Red Sox + teams = [7, 25, 4] # Reds, Giants, Red Sox elif gp == 7: teams = [24, 23, 19] # Mariners, Padres, Yankees elif gp == 8: @@ -265,9 +287,9 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea elif gp == 10: teams = [5, 10] # Cubs, Tigers else: - raise KeyError(f'Hmm...I do not know who you should be playing right now.') - t_id = teams[random.randint(0, len(teams)-1)] - elif this_event['id'] == 9: + raise KeyError(f"Hmm...I do not know who you should be playing right now.") + t_id = teams[random.randint(0, len(teams) - 1)] + elif this_event["id"] == 9: gp_to_tid = { 0: 7, 1: 4, @@ -279,394 +301,470 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea 7: 1, 8: 26, 9: 20, - 10: 6 + 10: 6, } try: t_id = gp_to_tid[gp] except KeyError: - raise KeyError(f'Hmm...I do not know who you should be playing with {gp} games played.') + raise KeyError( + f"Hmm...I do not know who you should be playing with {gp} games played." + ) else: return None - + this_team = await get_team_or_none(session, team_id=t_id) - logger.info(f'Gauntlet opponent: {this_team}') + logger.info(f"Gauntlet opponent: {this_team}") return await get_team_or_none(session, t_id) async def build_lineup(this_team, this_game, this_event, sp_name): - return await ai_manager.build_lineup(this_team, this_game.id, f'gauntlet-{this_event["id"]}', sp_name) + return await ai_manager.build_lineup( + this_team, this_game.id, f"gauntlet-{this_event['id']}", sp_name + ) async def get_starting_pitcher(session, this_team, this_game, this_event, this_run): sp_rank = (games_played(this_run) % 5) + 1 - starter = await db_get(f'teams/{this_team.id}/sp/gauntlet-{this_event["id"]}?sp_rank={sp_rank}') - logger.info(f'starter: {starter}') + starter = await db_get( + f"teams/{this_team.id}/sp/gauntlet-{this_event['id']}?sp_rank={sp_rank}" + ) + logger.info(f"starter: {starter}") this_player = await get_player_or_none(session, get_player_id_from_dict(starter)) if this_player is None: - log_exception(PlayerNotFoundException, 'Could not pull the AI\'s starting pitcher') + log_exception( + PlayerNotFoundException, "Could not pull the AI's starting pitcher" + ) # get player card; create one if none found - logger.info(f'SP this_player: {this_player}') - this_card = await get_or_create_ai_card( - session, - this_player, - this_team - ) + logger.info(f"SP this_player: {this_player}") + this_card = await get_or_create_ai_card(session, this_player, this_team) return Lineup( team=this_team, player=this_player, card=this_card, - position='P', + position="P", batting_order=10, is_fatigued=False, - game=this_game + game=this_game, ) -async def run_draft(interaction: discord.Interaction, main_team: Team, this_event, draft_team: Team = None): - logger.info(f'Starting draft for {main_team.abbrev if draft_team is None else draft_team.abbrev}') - if this_event['id'] == 1: - embed_title = f'{main_team.lname} - {this_event["name"]} Draft' - embed_description = f'{this_event["name"]}' +async def run_draft( + interaction: discord.Interaction, + main_team: Team, + this_event, + draft_team: Team = None, +): + logger.info( + f"Starting draft for {main_team.abbrev if draft_team is None else draft_team.abbrev}" + ) + if this_event["id"] == 1: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" base_params = copy.deepcopy(ai_manager.GAUNTLET1_PARAMS) - base_params.extend([('limit', 8), ('cardset_id', 8)]) - elif this_event['id'] == 2: - embed_title = f'{main_team.lname} - {this_event["name"]} Draft' - embed_description = f'{this_event["name"]}' + base_params.extend([("limit", 8), ("cardset_id", 8)]) + elif this_event["id"] == 2: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" base_params = copy.deepcopy(ai_manager.GAUNTLET2_PARAMS) - base_params.extend([('limit', 8)]) - elif this_event['id'] == 3: - embed_title = f'{main_team.lname} - {this_event["name"]} Draft' - embed_description = f'{this_event["name"]}' - base_params = [('cardset_id', 8), ('cardset_id', 13), ('cardset_id', 14), ('cardset_id', 15), ('limit', 8)] - elif this_event['id'] == 4: - embed_title = f'{main_team.lname} - {this_event["name"]} Draft' - embed_description = f'{this_event["name"]}' - base_params = [('cardset_id', 3), ('cardset_id', 4), ('cardset_id', 6), ('cardset_id', 16), - ('cardset_id', 15), ('limit', 8)] - elif this_event['id'] == 5: - embed_title = f'{main_team.lname} - {this_event["name"]} Draft' - embed_description = f'{this_event["name"]}' - base_params = [('cardset_id', 17), ('cardset_id', 18), ('cardset_id', 19), ('cardset_id', 16), - ('cardset_id', 8), ('limit', 8)] - elif this_event['id'] == 6: - embed_title = f'{main_team.lname} - {this_event['name']} Draft' - embed_description = f'{this_event["name"]}' - base_params = [('cardset_id', 20), ('cardset_id', 21), ('cardset_id', 22), ('cardset_id', 16), - ('cardset_id', 8), ('limit', 8)] - elif this_event['id'] == 7: - embed_title = f'{main_team.lname} - {this_event['name']} Draft' - embed_description = f'{this_event["name"]}' - base_params = [('cardset_id', 5), ('cardset_id', 1), ('cardset_id', 3), ('cardset_id', 4), ('cardset_id', 23), ('cardset_id', 22), ('limit', 4)] - elif this_event['id'] == 8: - embed_title = f'{main_team.lname} - {this_event['name']} Draft' - embed_description = f'{this_event["name"]}' - base_params = [('cardset_id', 24), ('cardset_id', 25), ('cardset_id', 22), ('cardset_id', 23), - ('limit', 8)] - elif this_event['id'] == 9: - embed_title = f'{main_team.lname} - {this_event['name']} Draft' - embed_description = f'{this_event["name"]}' - base_params = [('cardset_id', 27), ('cardset_id', 28), ('cardset_id', 29), ('limit', 8)] + base_params.extend([("limit", 8)]) + elif this_event["id"] == 3: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" + base_params = [ + ("cardset_id", 8), + ("cardset_id", 13), + ("cardset_id", 14), + ("cardset_id", 15), + ("limit", 8), + ] + elif this_event["id"] == 4: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" + base_params = [ + ("cardset_id", 3), + ("cardset_id", 4), + ("cardset_id", 6), + ("cardset_id", 16), + ("cardset_id", 15), + ("limit", 8), + ] + elif this_event["id"] == 5: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" + base_params = [ + ("cardset_id", 17), + ("cardset_id", 18), + ("cardset_id", 19), + ("cardset_id", 16), + ("cardset_id", 8), + ("limit", 8), + ] + elif this_event["id"] == 6: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" + base_params = [ + ("cardset_id", 20), + ("cardset_id", 21), + ("cardset_id", 22), + ("cardset_id", 16), + ("cardset_id", 8), + ("limit", 8), + ] + elif this_event["id"] == 7: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" + base_params = [ + ("cardset_id", 5), + ("cardset_id", 1), + ("cardset_id", 3), + ("cardset_id", 4), + ("cardset_id", 23), + ("cardset_id", 22), + ("limit", 4), + ] + elif this_event["id"] == 8: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" + base_params = [ + ("cardset_id", 24), + ("cardset_id", 25), + ("cardset_id", 22), + ("cardset_id", 23), + ("limit", 8), + ] + elif this_event["id"] == 9: + embed_title = f"{main_team.lname} - {this_event['name']} Draft" + embed_description = f"{this_event['name']}" + base_params = [ + ("cardset_id", 27), + ("cardset_id", 28), + ("cardset_id", 29), + ("limit", 8), + ] else: - logger.error(f'run_draft - Event ID {this_event["id"]} not recognized') - raise KeyError(f'Draft data not found for Gauntlet {this_event["id"]}') + logger.error(f"run_draft - Event ID {this_event['id']} not recognized") + raise KeyError(f"Draft data not found for Gauntlet {this_event['id']}") if draft_team is None: # Post draft team linked to main team draft_team = await db_post( - 'teams', + "teams", payload={ - 'abbrev': f'Gauntlet-{main_team.abbrev}', - 'sname': main_team.sname, - 'lname': main_team.lname, - 'gmid': main_team.gmid, - 'gmname': main_team.gmname, - 'gsheet': 'NONE', - 'logo': main_team.logo if main_team.logo else None, - 'color': main_team.color if main_team.color else None, - 'season': main_team.season, - 'has_guide': main_team.has_guide - } + "abbrev": f"Gauntlet-{main_team.abbrev}", + "sname": main_team.sname, + "lname": main_team.lname, + "gmid": main_team.gmid, + "gmname": main_team.gmname, + "gsheet": "NONE", + "logo": main_team.logo if main_team.logo else None, + "color": main_team.color if main_team.color else None, + "season": main_team.season, + "has_guide": main_team.has_guide, + }, ) all_players = [] p_names = [] counts = { - 'SP': 0, - 'RP': 0, - 'CP': 0, - 'C': 0, - '1B': 0, - '2B': 0, - '3B': 0, - 'SS': 0, - 'LF': 0, - 'CF': 0, - 'RF': 0, - 'DH': 0, - 'Hall of Fame': 0, - 'MVP': 0, - 'All-Star': 0, - 'Starter': 0, - 'Reserve': 0, - 'Replacement': 0, + "SP": 0, + "RP": 0, + "CP": 0, + "C": 0, + "1B": 0, + "2B": 0, + "3B": 0, + "SS": 0, + "LF": 0, + "CF": 0, + "RF": 0, + "DH": 0, + "Hall of Fame": 0, + "MVP": 0, + "All-Star": 0, + "Starter": 0, + "Reserve": 0, + "Replacement": 0, } max_counts = { - 'Hall of Fame': 1, - 'MVP': 1, - 'All-Star': 3, - 'Starter': 9, - 'Reserve': 7, - 'Replacement': 5 + "Hall of Fame": 1, + "MVP": 1, + "All-Star": 3, + "Starter": 9, + "Reserve": 7, + "Replacement": 5, } - if this_event['id'] in [1, 2]: - max_counts['MVP'] = 2 - elif this_event['id'] in [5, 6, 8, 9]: + if this_event["id"] in [1, 2]: + max_counts["MVP"] = 2 + elif this_event["id"] in [5, 6, 8, 9]: # Handle draft_team as either Team object or dict - dt_season = draft_team.season if isinstance(draft_team, Team) else draft_team['season'] - dt_id = draft_team.id if isinstance(draft_team, Team) else draft_team['id'] - g_query = await db_get( - 'games', - params=[('season', dt_season), ('team1_id', dt_id), ('gauntlet_id', this_event['id'])] + dt_season = ( + draft_team.season if isinstance(draft_team, Team) else draft_team["season"] ) - if g_query['count'] > 4: - game_count = g_query['count'] + dt_id = draft_team.id if isinstance(draft_team, Team) else draft_team["id"] + g_query = await db_get( + "games", + params=[ + ("season", dt_season), + ("team1_id", dt_id), + ("gauntlet_id", this_event["id"]), + ], + ) + if g_query["count"] > 4: + game_count = g_query["count"] if game_count <= 14: max_counts = { - 'Hall of Fame': 1, - 'MVP': 1, - 'All-Star': 3, - 'Starter': 10, - 'Reserve': 7, - 'Replacement': 4 + "Hall of Fame": 1, + "MVP": 1, + "All-Star": 3, + "Starter": 10, + "Reserve": 7, + "Replacement": 4, } elif game_count <= 24: max_counts = { - 'Hall of Fame': 1, - 'MVP': 1, - 'All-Star': 4, - 'Starter': 10, - 'Reserve': 7, - 'Replacement': 3 + "Hall of Fame": 1, + "MVP": 1, + "All-Star": 4, + "Starter": 10, + "Reserve": 7, + "Replacement": 3, } elif game_count <= 34: max_counts = { - 'Hall of Fame': 1, - 'MVP': 2, - 'All-Star': 4, - 'Starter': 10, - 'Reserve': 7, - 'Replacement': 2 + "Hall of Fame": 1, + "MVP": 2, + "All-Star": 4, + "Starter": 10, + "Reserve": 7, + "Replacement": 2, } elif game_count <= 49: max_counts = { - 'Hall of Fame': 2, - 'MVP': 2, - 'All-Star': 4, - 'Starter': 10, - 'Reserve': 7, - 'Replacement': 1 + "Hall of Fame": 2, + "MVP": 2, + "All-Star": 4, + "Starter": 10, + "Reserve": 7, + "Replacement": 1, } elif game_count <= 64: max_counts = { - 'Hall of Fame': 2, - 'MVP': 2, - 'All-Star': 4, - 'Starter': 11, - 'Reserve': 7, - 'Replacement': 0 + "Hall of Fame": 2, + "MVP": 2, + "All-Star": 4, + "Starter": 11, + "Reserve": 7, + "Replacement": 0, } elif game_count <= 79: max_counts = { - 'Hall of Fame': 2, - 'MVP': 2, - 'All-Star': 5, - 'Starter': 11, - 'Reserve': 6, - 'Replacement': 0 + "Hall of Fame": 2, + "MVP": 2, + "All-Star": 5, + "Starter": 11, + "Reserve": 6, + "Replacement": 0, } elif game_count <= 99: max_counts = { - 'Hall of Fame': 2, - 'MVP': 3, - 'All-Star': 5, - 'Starter': 11, - 'Reserve': 5, - 'Replacement': 0 + "Hall of Fame": 2, + "MVP": 3, + "All-Star": 5, + "Starter": 11, + "Reserve": 5, + "Replacement": 0, } elif game_count <= 119: max_counts = { - 'Hall of Fame': 2, - 'MVP': 3, - 'All-Star': 5, - 'Starter': 12, - 'Reserve': 4, - 'Replacement': 0 + "Hall of Fame": 2, + "MVP": 3, + "All-Star": 5, + "Starter": 12, + "Reserve": 4, + "Replacement": 0, } elif game_count <= 139: max_counts = { - 'Hall of Fame': 2, - 'MVP': 3, - 'All-Star': 6, - 'Starter': 12, - 'Reserve': 3, - 'Replacement': 0 + "Hall of Fame": 2, + "MVP": 3, + "All-Star": 6, + "Starter": 12, + "Reserve": 3, + "Replacement": 0, } elif game_count <= 164: max_counts = { - 'Hall of Fame': 2, - 'MVP': 4, - 'All-Star': 6, - 'Starter': 12, - 'Reserve': 2, - 'Replacement': 0 + "Hall of Fame": 2, + "MVP": 4, + "All-Star": 6, + "Starter": 12, + "Reserve": 2, + "Replacement": 0, } elif game_count <= 189: max_counts = { - 'Hall of Fame': 3, - 'MVP': 4, - 'All-Star': 6, - 'Starter': 12, - 'Reserve': 1, - 'Replacement': 0 + "Hall of Fame": 3, + "MVP": 4, + "All-Star": 6, + "Starter": 12, + "Reserve": 1, + "Replacement": 0, } elif game_count <= 219: max_counts = { - 'Hall of Fame': 3, - 'MVP': 4, - 'All-Star': 6, - 'Starter': 13, - 'Reserve': 0, - 'Replacement': 0 + "Hall of Fame": 3, + "MVP": 4, + "All-Star": 6, + "Starter": 13, + "Reserve": 0, + "Replacement": 0, } elif game_count <= 249: max_counts = { - 'Hall of Fame': 3, - 'MVP': 4, - 'All-Star': 7, - 'Starter': 12, - 'Reserve': 0, - 'Replacement': 0 + "Hall of Fame": 3, + "MVP": 4, + "All-Star": 7, + "Starter": 12, + "Reserve": 0, + "Replacement": 0, } else: max_counts = { - 'Hall of Fame': 3, - 'MVP': 5, - 'All-Star': 7, - 'Starter': 11, - 'Reserve': 0, - 'Replacement': 0 + "Hall of Fame": 3, + "MVP": 5, + "All-Star": 7, + "Starter": 11, + "Reserve": 0, + "Replacement": 0, } - logger.info(f'gauntlets.py - run_draft / max_counts: {max_counts}') + logger.info(f"gauntlets.py - run_draft / max_counts: {max_counts}") round_num = 1 counter = 0 view = helpers.Confirm([interaction.user]) - if this_event['id'] == 1: - view.confirm.label = 'Let\'s a-Go!' + if this_event["id"] == 1: + view.confirm.label = "Let's a-Go!" else: - view.confirm.label = 'Let\'s Go!' + view.confirm.label = "Let's Go!" intro_embed = await get_embed(this_event=this_event) - intro_embed.title += ' - Are you ready?' + intro_embed.title += " - Are you ready?" - await interaction.edit_original_response( - content=None, - embed=intro_embed, - view=view - ) + await interaction.edit_original_response(content=None, embed=intro_embed, view=view) await view.wait() if not view.value: - await interaction.edit_original_response(content=None, embed=intro_embed, view=None) - await interaction.channel.send('You\'ll be back') + await interaction.edit_original_response( + content=None, embed=intro_embed, view=None + ) + await interaction.channel.send("You'll be back") raise ZeroDivisionError() else: await interaction.edit_original_response( - content=None, - embed=intro_embed, - view=None + content=None, embed=intro_embed, view=None ) def get_embeds(include_links=True, round_num=1): - top_embed = helpers.get_team_embed(f'{embed_title} - Round {round_num}') - top_embed.description = f'Rarity Counts' - bot_embed = helpers.get_team_embed(f'{embed_title} - Round {round_num}') - bot_embed.description = f'Current Roster' + top_embed = helpers.get_team_embed(f"{embed_title} - Round {round_num}") + top_embed.description = f"Rarity Counts" + bot_embed = helpers.get_team_embed(f"{embed_title} - Round {round_num}") + bot_embed.description = f"Current Roster" all_str = { - 'Hall of Fame': '', - 'MVP': '', - 'All-Star': '', - 'Starter': '', - 'Reserve': '', - 'Replacement': '', - 'C': '', - '1B': '', - '2B': '', - '3B': '', - 'SS': '', - 'LF': '', - 'CF': '', - 'RF': '', - 'DH': '', - 'SP': '', - 'RP': '', - 'CP': '' + "Hall of Fame": "", + "MVP": "", + "All-Star": "", + "Starter": "", + "Reserve": "", + "Replacement": "", + "C": "", + "1B": "", + "2B": "", + "3B": "", + "SS": "", + "LF": "", + "CF": "", + "RF": "", + "DH": "", + "SP": "", + "RP": "", + "CP": "", } for y in all_players: if include_links: - name_string = f'[{helpers.player_desc(y)}]({y["image"]})' + name_string = f"[{helpers.player_desc(y)}]({y['image']})" else: - name_string = f'{helpers.player_desc(y)}' - all_str[y['rarity']['name']] += f'{name_string}\n' + name_string = f"{helpers.player_desc(y)}" + all_str[y["rarity"]["name"]] += f"{name_string}\n" for z in helpers.get_all_pos(y): - all_str[z] += f'{name_string}\n' + all_str[z] += f"{name_string}\n" - if max_counts['Hall of Fame'] > 0: - top_embed.add_field(name=f'HoFs ({counts["Hall of Fame"]}/{max_counts["Hall of Fame"]})', value=all_str['Hall of Fame'], inline=False) - - if max_counts['MVP'] > 0: - top_embed.add_field(name=f'MVPs ({counts["MVP"]}/{max_counts["MVP"]})', value=all_str['MVP'], inline=False) - - if max_counts['All-Star'] > 0: + if max_counts["Hall of Fame"] > 0: top_embed.add_field( - name=f'All-Stars ({counts["All-Star"]}/{max_counts["All-Star"]})', value=all_str['All-Star'], inline=False) - - if max_counts['Starter'] > 0: - top_embed.add_field( - name=f'Starters ({counts["Starter"]}/{max_counts["Starter"]})', value=all_str['Starter'], inline=False) - - if max_counts['Reserve'] > 0: - top_embed.add_field( - name=f'Reserves ({counts["Reserve"]}/{max_counts["Reserve"]})', value=all_str['Reserve'], inline=False) - - if max_counts['Replacement'] > 0: - top_embed.add_field( - name=f'Replacements ({counts["Replacement"]}/{max_counts["Replacement"]})', - value=all_str['Replacement'], - inline=False + name=f"HoFs ({counts['Hall of Fame']}/{max_counts['Hall of Fame']})", + value=all_str["Hall of Fame"], + inline=False, ) - bot_embed.add_field(name=f'Catcher', value=all_str['C'], inline=False) - bot_embed.add_field(name=f'First Base', value=all_str['1B'], inline=False) - bot_embed.add_field(name=f'Second Base', value=all_str['2B'], inline=False) - bot_embed.add_field(name=f'Third Base', value=all_str['3B'], inline=False) - bot_embed.add_field(name=f'Shortstop', value=all_str['SS'], inline=False) - bot_embed.add_field(name=f'Left Field', value=all_str['LF'], inline=False) - bot_embed.add_field(name=f'Center Field', value=all_str['CF'], inline=False) - bot_embed.add_field(name=f'Right Field', value=all_str['RF'], inline=False) - bot_embed.add_field(name=f'Designated Hitter', value=all_str['DH'], inline=False) - bot_embed.add_field(name=f'Starting Pitcher', value=all_str['SP'], inline=False) - bot_embed.add_field(name=f'Relief Pitcher', value=all_str['RP'], inline=False) - bot_embed.add_field(name=f'Closing Pitcher', value=all_str['CP'], inline=False) + if max_counts["MVP"] > 0: + top_embed.add_field( + name=f"MVPs ({counts['MVP']}/{max_counts['MVP']})", + value=all_str["MVP"], + inline=False, + ) + + if max_counts["All-Star"] > 0: + top_embed.add_field( + name=f"All-Stars ({counts['All-Star']}/{max_counts['All-Star']})", + value=all_str["All-Star"], + inline=False, + ) + + if max_counts["Starter"] > 0: + top_embed.add_field( + name=f"Starters ({counts['Starter']}/{max_counts['Starter']})", + value=all_str["Starter"], + inline=False, + ) + + if max_counts["Reserve"] > 0: + top_embed.add_field( + name=f"Reserves ({counts['Reserve']}/{max_counts['Reserve']})", + value=all_str["Reserve"], + inline=False, + ) + + if max_counts["Replacement"] > 0: + top_embed.add_field( + name=f"Replacements ({counts['Replacement']}/{max_counts['Replacement']})", + value=all_str["Replacement"], + inline=False, + ) + + bot_embed.add_field(name=f"Catcher", value=all_str["C"], inline=False) + bot_embed.add_field(name=f"First Base", value=all_str["1B"], inline=False) + bot_embed.add_field(name=f"Second Base", value=all_str["2B"], inline=False) + bot_embed.add_field(name=f"Third Base", value=all_str["3B"], inline=False) + bot_embed.add_field(name=f"Shortstop", value=all_str["SS"], inline=False) + bot_embed.add_field(name=f"Left Field", value=all_str["LF"], inline=False) + bot_embed.add_field(name=f"Center Field", value=all_str["CF"], inline=False) + bot_embed.add_field(name=f"Right Field", value=all_str["RF"], inline=False) + bot_embed.add_field( + name=f"Designated Hitter", value=all_str["DH"], inline=False + ) + bot_embed.add_field(name=f"Starting Pitcher", value=all_str["SP"], inline=False) + bot_embed.add_field(name=f"Relief Pitcher", value=all_str["RP"], inline=False) + bot_embed.add_field(name=f"Closing Pitcher", value=all_str["CP"], inline=False) return [top_embed, bot_embed] - logger.info(f'getting last message') - last_message = await interaction.channel.send(content=None, embeds=get_embeds(include_links=False)) + logger.info(f"getting last message") + last_message = await interaction.channel.send( + content=None, embeds=get_embeds(include_links=False) + ) async def draft_loop(): round_num = 1 @@ -674,44 +772,58 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even while round_num <= 26 and counter < 50: counter += 1 params = copy.deepcopy(base_params) - logger.info(f'gauntlets.py - run_draft - event_id {this_event["id"]} / round_num: {round_num} / counter: {counter} / counts: {counts} / max_counts: {max_counts}') + logger.info( + f"gauntlets.py - run_draft - event_id {this_event['id']} / round_num: {round_num} / counter: {counter} / counts: {counts} / max_counts: {max_counts}" + ) # Set rarity based on remaining counts - if counts['Hall of Fame'] < max_counts['Hall of Fame']: - params.extend([ - ('min_rarity', RARITY['HoF']), ('max_rarity', RARITY['HoF']) - ]) - elif counts['MVP'] < max_counts['MVP']: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']) - ]) - elif counts['All-Star'] < max_counts['All-Star']: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) - elif counts['Starter'] < max_counts['Starter']: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) - elif counts['Reserve'] < max_counts['Reserve']: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + if counts["Hall of Fame"] < max_counts["Hall of Fame"]: + params.extend( + [("min_rarity", RARITY["HoF"]), ("max_rarity", RARITY["HoF"])] + ) + elif counts["MVP"] < max_counts["MVP"]: + params.extend( + [("min_rarity", RARITY["MVP"]), ("max_rarity", RARITY["MVP"])] + ) + elif counts["All-Star"] < max_counts["All-Star"]: + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) + elif counts["Starter"] < max_counts["Starter"]: + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) + elif counts["Reserve"] < max_counts["Reserve"]: + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) else: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) this_batch = [] - for x in ['SP', 'RP', 'IF', 'OF']: + for x in ["SP", "RP", "IF", "OF"]: # Slot 1 - SP - if x == 'SP': - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] + if x == "SP": + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] # if counts['SP'] > 5: # slot_params = [('pos_exc', 'SP')] # elif counts['RP'] < 6: @@ -720,25 +832,31 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')] # Slot 2 - RP - elif x == 'RP': - logger.info(f'counts[RP]: {counts["RP"]}') - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] + elif x == "RP": + logger.info(f"counts[RP]: {counts['RP']}") + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] else: - slot_params = [('pos_inc', 'RP')] + slot_params = [("pos_inc", "RP")] # Slot 3 - IF - elif x == 'IF': + elif x == "IF": slot_params = [] - for y in ['1B', '2B', '3B', 'SS', 'C']: + for y in ["1B", "2B", "3B", "SS", "C"]: if (counts[y] > 1) and 0 in [ - counts['C'], counts['1B'], counts['2B'], counts['3B'], counts['SS'] + counts["C"], + counts["1B"], + counts["2B"], + counts["3B"], + counts["SS"], ]: - slot_params.append(('pos_exc', y)) - elif (y == 'C' and counts['C'] < 3) or (y != 'C' and counts[y] < 4): - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_exc", y)) + elif (y == "C" and counts["C"] < 3) or ( + y != "C" and counts[y] < 4 + ): + slot_params.append(("pos_inc", y)) # if counts['C'] < 2: # slot_params.append(('pos_inc', 'C')) # if len(slot_params) == 0: @@ -748,82 +866,110 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Slot 4 - OF else: slot_params = [] - for y in ['LF', 'CF', 'RF']: + for y in ["LF", "CF", "RF"]: if counts[y] > 4: - slot_params.append(('pos_exc', y)) - elif counts[y] > 1 and 0 in [counts['LF'], counts['CF'], counts['RF']]: - slot_params.append(('pos_exc', y)) + slot_params.append(("pos_exc", y)) + elif counts[y] > 1 and 0 in [ + counts["LF"], + counts["CF"], + counts["RF"], + ]: + slot_params.append(("pos_exc", y)) elif counts[y] < 5: - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_inc", y)) # if len(slot_params) == 0: # slot_params = [('pos_exc', 'LF'), ('pos_exc', 'CF'), ('pos_exc', 'RF')] - logger.info(f'this_batch: {this_batch}') - logger.info(f'slot_params: {slot_params}') - logger.info(f'params: {params}') + logger.info(f"this_batch: {this_batch}") + logger.info(f"slot_params: {slot_params}") + logger.info(f"params: {params}") # No position explicitly requested or denied if len(slot_params) == 0: - if (counts['SP'] + counts['RP']) > ( - counts['C'] + counts['1B'] + counts['2B'] + counts['SS'] + counts['LF'] + counts['CF'] + - counts['RF']): + if (counts["SP"] + counts["RP"]) > ( + counts["C"] + + counts["1B"] + + counts["2B"] + + counts["SS"] + + counts["LF"] + + counts["CF"] + + counts["RF"] + ): pos_counts = [ - ('C', counts['C']), ('1B', counts['1B']), ('2B', counts['2B']), ('3B', counts['3B']), - ('SS', counts['SS']), ('LF', counts['LF']), ('CF', counts['CF']), ('RF', counts['RF']) + ("C", counts["C"]), + ("1B", counts["1B"]), + ("2B", counts["2B"]), + ("3B", counts["3B"]), + ("SS", counts["SS"]), + ("LF", counts["LF"]), + ("CF", counts["CF"]), + ("RF", counts["RF"]), ] pos_counts.sort(key=lambda z: z[1]) - slot_params = [('pos_inc', pos_counts[0][0])] + slot_params = [("pos_inc", pos_counts[0][0])] else: - if counts['SP'] >= counts['RP']: - slot_params = [('pos_inc', 'RP')] + if counts["SP"] >= counts["RP"]: + slot_params = [("pos_inc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] slot_params.extend(params) - p_query = await db_get('players/random', params=slot_params) + p_query = await db_get("players/random", params=slot_params, timeout=10) # Fallback for Event 9 RP shortage - if this_event['id'] == 9 and x == 'RP' and p_query['count'] < 3: - logger.warning(f'Low RP count ({p_query["count"]}) in Event 9, expanding cardsets to 24, 25, 26') - fallback_params = [p for p in slot_params if p[0] != 'cardset_id'] - fallback_params.extend([('cardset_id', 24), ('cardset_id', 25), ('cardset_id', 26)]) - p_query = await db_get('players/random', params=fallback_params) - logger.info(f'Fallback query returned {p_query["count"]} RP options') + if this_event["id"] == 9 and x == "RP" and p_query["count"] < 3: + logger.warning( + f"Low RP count ({p_query['count']}) in Event 9, expanding cardsets to 24, 25, 26" + ) + fallback_params = [p for p in slot_params if p[0] != "cardset_id"] + fallback_params.extend( + [("cardset_id", 24), ("cardset_id", 25), ("cardset_id", 26)] + ) + p_query = await db_get( + "players/random", params=fallback_params, timeout=10 + ) + logger.info( + f"Fallback query returned {p_query['count']} RP options" + ) - if p_query['count'] > 0: + if p_query["count"] > 0: # test_player_list = '' # for z in p_query['players']: # test_player_list += f'{z["rarity"]["name"]} - {z["description"]} - {helpers.get_all_pos(x)}\n' # Collect 1 cards with no repeat player names - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) break if len(this_batch) < 4: - logger.error(f'Pulled less than 4 players in gauntlet draft') - p_query = await db_get('players/random', params=params) - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + logger.error(f"Pulled less than 4 players in gauntlet draft") + p_query = await db_get("players/random", params=params, timeout=10) + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) if len(this_batch) >= 4: break if len(this_batch) < 4: - raise KeyError(f'This is embarassing, but I couldn\'t find enough players for you to draft from.') + raise KeyError( + f"This is embarassing, but I couldn't find enough players for you to draft from." + ) # Present choices and capture selection - p_choice = await helpers.get_choice_from_cards(interaction, this_batch, delete_message=True) + p_choice = await helpers.get_choice_from_cards( + interaction, this_batch, delete_message=True + ) # Add player to list and update counts - p_names.append(p_choice['p_name']) - counts[p_choice['rarity']['name']] += 1 + p_names.append(p_choice["p_name"]) + counts[p_choice["rarity"]["name"]] += 1 all_players.append(p_choice) - if p_choice['pos_1'] in ['SP', 'RP']: - counts[p_choice['pos_1']] += 1 + if p_choice["pos_1"] in ["SP", "RP"]: + counts[p_choice["pos_1"]] += 1 else: for x in helpers.get_all_pos(p_choice): if x in counts: @@ -831,12 +977,15 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Update roster embed round_num += 1 - await last_message.edit(content=None, embeds=get_embeds(include_links=False, round_num=round_num)) - - logger.info(f'going into draft') + await last_message.edit( + content=None, + embeds=get_embeds(include_links=False, round_num=round_num), + ) + + logger.info(f"going into draft") backyard_round = None custom_player_round = None - if this_event['id'] == 1: + if this_event["id"] == 1: mario_round = None while round_num <= 26 and counter < 50: counter += 1 @@ -844,165 +993,232 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Set rarity param based on round number if round_num == 1: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']) - ]) + params.extend( + [("min_rarity", RARITY["MVP"]), ("max_rarity", RARITY["MVP"])] + ) elif round_num == 2: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 5: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num == 6: if random.randint(1, 2) == 1: params = [ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']), ('cardset_id', 8) + ("min_rarity", RARITY["MVP"]), + ("max_rarity", RARITY["MVP"]), + ("cardset_id", 8), ] mario_round = 6 else: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']), ('pos_exc', 'RP') - ]) + params.extend( + [ + ("min_rarity", RARITY["MVP"]), + ("max_rarity", RARITY["MVP"]), + ("pos_exc", "RP"), + ] + ) elif round_num == 7: if random.randint(1, 2) == 1 and mario_round is None: params = [ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']), ('cardset_id', 8) + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ("cardset_id", 8), ] mario_round = 7 else: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num == 8: if mario_round is None: params = [ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']), ('cardset_id', 8) + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ("cardset_id", 8), ] mario_round = 12 else: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 11: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 15: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 18: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) elif round_num == 19: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 21: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 24: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 26: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) this_batch = [] - for x in ['SP', 'RP', 'IF', 'OF']: + for x in ["SP", "RP", "IF", "OF"]: # Slot 1 - SP - if x == 'SP': - if counts['SP'] < 6: - slot_params = [('pos_inc', 'SP')] - elif counts['RP'] < 6: - slot_params = [('pos_inc', 'RP')] + if x == "SP": + if counts["SP"] < 6: + slot_params = [("pos_inc", "SP")] + elif counts["RP"] < 6: + slot_params = [("pos_inc", "RP")] else: - slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')] + slot_params = [("pos_exc", "SP"), ("pos_exc", "RP")] # Slot 2 - RP - elif x == 'RP': - logger.info(f'counts[RP]: {counts["RP"]}') - if counts['RP'] < 8: - slot_params = [('pos_inc', 'RP')] - elif counts['SP'] < 4: - slot_params = [('pos_inc', 'SP')] + elif x == "RP": + logger.info(f"counts[RP]: {counts['RP']}") + if counts["RP"] < 8: + slot_params = [("pos_inc", "RP")] + elif counts["SP"] < 4: + slot_params = [("pos_inc", "SP")] else: - slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')] + slot_params = [("pos_exc", "SP"), ("pos_exc", "RP")] # Slot 3 - IF - elif x == 'IF': + elif x == "IF": slot_params = [] - for y in ['1B', '2B', '3B', 'SS']: + for y in ["1B", "2B", "3B", "SS"]: if (counts[y] == 2 or counts[y] == 3) and 0 not in [ - counts['C'], counts['1B'], counts['2B'], counts['3B'], counts['SS'], counts['LF'], - counts['CF'], counts['RF']]: - slot_params.append(('pos_inc', y)) + counts["C"], + counts["1B"], + counts["2B"], + counts["3B"], + counts["SS"], + counts["LF"], + counts["CF"], + counts["RF"], + ]: + slot_params.append(("pos_inc", y)) elif counts[y] < 4: - slot_params.append(('pos_inc', y)) - if counts['C'] < 2: - slot_params.append(('pos_inc', 'C')) + slot_params.append(("pos_inc", y)) + if counts["C"] < 2: + slot_params.append(("pos_inc", "C")) if len(slot_params) == 0: - slot_params = [('pos_exc', 'C'), ('pos_exc', '1B'), ('pos_exc', '2B'), ('pos_exc', '3B'), - ('pos_exc', 'SS')] + slot_params = [ + ("pos_exc", "C"), + ("pos_exc", "1B"), + ("pos_exc", "2B"), + ("pos_exc", "3B"), + ("pos_exc", "SS"), + ] # Slot 4 - OF else: slot_params = [] - for y in ['LF', 'CF', 'RF']: + for y in ["LF", "CF", "RF"]: if counts[y] > 4: pass - elif counts[y] > 2 and 0 not in [counts['LF'], counts['CF'], counts['RF']]: - slot_params.append(('pos_inc', y)) + elif counts[y] > 2 and 0 not in [ + counts["LF"], + counts["CF"], + counts["RF"], + ]: + slot_params.append(("pos_inc", y)) elif counts[y] < 3: - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_inc", y)) if len(slot_params) == 0: - slot_params = [('pos_exc', 'LF'), ('pos_exc', 'CF'), ('pos_exc', 'RF')] + slot_params = [ + ("pos_exc", "LF"), + ("pos_exc", "CF"), + ("pos_exc", "RF"), + ] - logger.info(f'this_batch: {this_batch}') - logger.info(f'slot_params: {slot_params}') - logger.info(f'params: {params}') + logger.info(f"this_batch: {this_batch}") + logger.info(f"slot_params: {slot_params}") + logger.info(f"params: {params}") slot_params.extend(params) - p_query = await db_get('players/random', params=slot_params) + p_query = await db_get("players/random", params=slot_params, timeout=10) - if p_query['count'] > 0: + if p_query["count"] > 0: # test_player_list = '' # for z in p_query['players']: # test_player_list += f'{z["rarity"]["name"]} - {z["description"]} - {helpers.get_all_pos(x)}\n' # Collect 1 cards with no repeat player names - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) break if len(this_batch) < 4: - logger.error(f'Pulled less than 4 players in gauntlet draft') - p_query = await db_get('players/random', params=params) - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + logger.error(f"Pulled less than 4 players in gauntlet draft") + p_query = await db_get("players/random", params=params, timeout=10) + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) if len(this_batch) >= 4: break if len(this_batch) < 4: - raise KeyError(f'This is embarassing, but I couldn\'t find enough players for you to draft from.') + raise KeyError( + f"This is embarassing, but I couldn't find enough players for you to draft from." + ) # Present choices and capture selection - p_choice = await helpers.get_choice_from_cards(interaction, this_batch, delete_message=True) + p_choice = await helpers.get_choice_from_cards( + interaction, this_batch, delete_message=True + ) # Add player to list and update counts - p_names.append(p_choice['p_name']) - counts[p_choice['rarity']['name']] += 1 + p_names.append(p_choice["p_name"]) + counts[p_choice["rarity"]["name"]] += 1 all_players.append(p_choice) - if p_choice['pos_1'] in ['SP', 'RP']: - counts[p_choice['pos_1']] += 1 + if p_choice["pos_1"] in ["SP", "RP"]: + counts[p_choice["pos_1"]] += 1 else: for x in helpers.get_all_pos(p_choice): if x in counts: @@ -1010,72 +1226,108 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Update roster embed round_num += 1 - await last_message.edit(content=None, embeds=get_embeds(include_links=False)) - elif this_event['id'] == 2: + await last_message.edit( + content=None, embeds=get_embeds(include_links=False) + ) + elif this_event["id"] == 2: while round_num <= 26 and counter < 50: counter += 1 params = copy.deepcopy(base_params) # Set rarity param based on round number if round_num == 1: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']) - ]) + params.extend( + [("min_rarity", RARITY["MVP"]), ("max_rarity", RARITY["MVP"])] + ) elif round_num == 2: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 5: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num == 6: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']), ('pos_exc', 'RP') - ]) + params.extend( + [ + ("min_rarity", RARITY["MVP"]), + ("max_rarity", RARITY["MVP"]), + ("pos_exc", "RP"), + ] + ) elif round_num == 7: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 11: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 15: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 18: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) elif round_num == 19: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 21: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 24: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 26: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) this_batch = [] - for x in ['SP', 'RP', 'IF', 'OF']: + for x in ["SP", "RP", "IF", "OF"]: # Slot 1 - SP - if x == 'SP': - if counts['SP'] > 5: - slot_params = [('pos_exc', 'RP')] - if counts['RP'] > 7: - slot_params = [('pos_exc', 'SP')] + if x == "SP": + if counts["SP"] > 5: + slot_params = [("pos_exc", "RP")] + if counts["RP"] > 7: + slot_params = [("pos_exc", "SP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] # if counts['SP'] > 5: # slot_params = [('pos_exc', 'SP')] # elif counts['RP'] < 6: @@ -1084,25 +1336,31 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')] # Slot 2 - RP - elif x == 'RP': - logger.info(f'counts[RP]: {counts["RP"]}') - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] + elif x == "RP": + logger.info(f"counts[RP]: {counts['RP']}") + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] else: - slot_params = [('pos_inc', 'RP')] + slot_params = [("pos_inc", "RP")] # Slot 3 - IF - elif x == 'IF': + elif x == "IF": slot_params = [] - for y in ['1B', '2B', '3B', 'SS', 'C']: + for y in ["1B", "2B", "3B", "SS", "C"]: if (counts[y] > 1) and 0 in [ - counts['C'], counts['1B'], counts['2B'], counts['3B'], counts['SS'] + counts["C"], + counts["1B"], + counts["2B"], + counts["3B"], + counts["SS"], ]: - slot_params.append(('pos_exc', y)) - elif (y == 'C' and counts['C'] < 3) or (y != 'C' and counts[y] < 4): - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_exc", y)) + elif (y == "C" and counts["C"] < 3) or ( + y != "C" and counts[y] < 4 + ): + slot_params.append(("pos_inc", y)) # if counts['C'] < 2: # slot_params.append(('pos_inc', 'C')) # if len(slot_params) == 0: @@ -1112,73 +1370,93 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Slot 4 - OF else: slot_params = [] - for y in ['LF', 'CF', 'RF']: + for y in ["LF", "CF", "RF"]: if counts[y] > 4: - slot_params.append(('pos_exc', y)) - elif counts[y] > 1 and 0 in [counts['LF'], counts['CF'], counts['RF']]: - slot_params.append(('pos_exc', y)) + slot_params.append(("pos_exc", y)) + elif counts[y] > 1 and 0 in [ + counts["LF"], + counts["CF"], + counts["RF"], + ]: + slot_params.append(("pos_exc", y)) elif counts[y] < 5: - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_inc", y)) # if len(slot_params) == 0: # slot_params = [('pos_exc', 'LF'), ('pos_exc', 'CF'), ('pos_exc', 'RF')] - logger.info(f'this_batch: {this_batch}') - logger.info(f'slot_params: {slot_params}') - logger.info(f'params: {params}') + logger.info(f"this_batch: {this_batch}") + logger.info(f"slot_params: {slot_params}") + logger.info(f"params: {params}") # No position explicitly requested or denied if len(slot_params) == 0: - if (counts['SP'] + counts['RP']) > ( - counts['C'] + counts['1B'] + counts['2B'] + counts['SS'] + counts['LF'] + counts['CF'] + - counts['RF']): + if (counts["SP"] + counts["RP"]) > ( + counts["C"] + + counts["1B"] + + counts["2B"] + + counts["SS"] + + counts["LF"] + + counts["CF"] + + counts["RF"] + ): pos_counts = [ - ('C', counts['C']), ('1B', counts['1B']), ('2B', counts['2B']), ('3B', counts['3B']), - ('SS', counts['SS']), ('LF', counts['LF']), ('CF', counts['CF']), ('RF', counts['RF']) + ("C", counts["C"]), + ("1B", counts["1B"]), + ("2B", counts["2B"]), + ("3B", counts["3B"]), + ("SS", counts["SS"]), + ("LF", counts["LF"]), + ("CF", counts["CF"]), + ("RF", counts["RF"]), ] pos_counts.sort(key=lambda z: z[1]) - slot_params = [('pos_inc', pos_counts[0][0])] + slot_params = [("pos_inc", pos_counts[0][0])] else: - if counts['SP'] >= counts['RP']: - slot_params = [('pos_inc', 'RP')] + if counts["SP"] >= counts["RP"]: + slot_params = [("pos_inc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] slot_params.extend(params) - p_query = await db_get('players/random', params=slot_params) + p_query = await db_get("players/random", params=slot_params, timeout=10) - if p_query['count'] > 0: + if p_query["count"] > 0: # test_player_list = '' # for z in p_query['players']: # test_player_list += f'{z["rarity"]["name"]} - {z["description"]} - {helpers.get_all_pos(x)}\n' # Collect 1 cards with no repeat player names - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) break if len(this_batch) < 4: - logger.error(f'Pulled less than 4 players in gauntlet draft') - p_query = await db_get('players/random', params=params) - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + logger.error(f"Pulled less than 4 players in gauntlet draft") + p_query = await db_get("players/random", params=params, timeout=10) + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) if len(this_batch) >= 4: break if len(this_batch) < 4: - raise KeyError(f'This is embarassing, but I couldn\'t find enough players for you to draft from.') + raise KeyError( + f"This is embarassing, but I couldn't find enough players for you to draft from." + ) # Present choices and capture selection - p_choice = await helpers.get_choice_from_cards(interaction, this_batch, delete_message=True) + p_choice = await helpers.get_choice_from_cards( + interaction, this_batch, delete_message=True + ) # Add player to list and update counts - p_names.append(p_choice['p_name']) - counts[p_choice['rarity']['name']] += 1 + p_names.append(p_choice["p_name"]) + counts[p_choice["rarity"]["name"]] += 1 all_players.append(p_choice) - if p_choice['pos_1'] in ['SP', 'RP']: - counts[p_choice['pos_1']] += 1 + if p_choice["pos_1"] in ["SP", "RP"]: + counts[p_choice["pos_1"]] += 1 else: for x in helpers.get_all_pos(p_choice): if x in counts: @@ -1186,74 +1464,110 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Update roster embed round_num += 1 - await last_message.edit(content=None, embeds=get_embeds(include_links=False)) - elif this_event['id'] == 3: + await last_message.edit( + content=None, embeds=get_embeds(include_links=False) + ) + elif this_event["id"] == 3: while round_num <= 26 and counter < 50: - logger.info(f'round {round_num}') + logger.info(f"round {round_num}") counter += 1 params = copy.deepcopy(base_params) # Set rarity param based on round number if round_num == 1: - params.extend([ - ('min_rarity', RARITY['HoF']), ('max_rarity', RARITY['HoF']) - ]) + params.extend( + [("min_rarity", RARITY["HoF"]), ("max_rarity", RARITY["HoF"])] + ) elif round_num == 2: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 5: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num == 6: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']), ('pos_exc', 'RP') - ]) + params.extend( + [ + ("min_rarity", RARITY["MVP"]), + ("max_rarity", RARITY["MVP"]), + ("pos_exc", "RP"), + ] + ) elif round_num == 7: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 11: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 15: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 18: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) elif round_num == 19: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 21: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 24: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 26: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) - logger.info(f'starting position loop') + logger.info(f"starting position loop") this_batch = [] - for x in ['SP', 'RP', 'IF', 'OF']: + for x in ["SP", "RP", "IF", "OF"]: # Slot 1 - SP - if x == 'SP': - if counts['SP'] > 5: - slot_params = [('pos_exc', 'RP')] - if counts['RP'] > 7: - slot_params = [('pos_exc', 'SP')] + if x == "SP": + if counts["SP"] > 5: + slot_params = [("pos_exc", "RP")] + if counts["RP"] > 7: + slot_params = [("pos_exc", "SP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] # if counts['SP'] > 5: # slot_params = [('pos_exc', 'SP')] # elif counts['RP'] < 6: @@ -1262,25 +1576,31 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')] # Slot 2 - RP - elif x == 'RP': - logger.info(f'counts[RP]: {counts["RP"]}') - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] + elif x == "RP": + logger.info(f"counts[RP]: {counts['RP']}") + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] else: - slot_params = [('pos_inc', 'RP')] + slot_params = [("pos_inc", "RP")] # Slot 3 - IF - elif x == 'IF': + elif x == "IF": slot_params = [] - for y in ['1B', '2B', '3B', 'SS', 'C']: + for y in ["1B", "2B", "3B", "SS", "C"]: if (counts[y] > 1) and 0 in [ - counts['C'], counts['1B'], counts['2B'], counts['3B'], counts['SS'] + counts["C"], + counts["1B"], + counts["2B"], + counts["3B"], + counts["SS"], ]: - slot_params.append(('pos_exc', y)) - elif (y == 'C' and counts['C'] < 3) or (y != 'C' and counts[y] < 4): - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_exc", y)) + elif (y == "C" and counts["C"] < 3) or ( + y != "C" and counts[y] < 4 + ): + slot_params.append(("pos_inc", y)) # if counts['C'] < 2: # slot_params.append(('pos_inc', 'C')) # if len(slot_params) == 0: @@ -1290,73 +1610,93 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Slot 4 - OF else: slot_params = [] - for y in ['LF', 'CF', 'RF']: + for y in ["LF", "CF", "RF"]: if counts[y] > 4: - slot_params.append(('pos_exc', y)) - elif counts[y] > 1 and 0 in [counts['LF'], counts['CF'], counts['RF']]: - slot_params.append(('pos_exc', y)) + slot_params.append(("pos_exc", y)) + elif counts[y] > 1 and 0 in [ + counts["LF"], + counts["CF"], + counts["RF"], + ]: + slot_params.append(("pos_exc", y)) elif counts[y] < 5: - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_inc", y)) # if len(slot_params) == 0: # slot_params = [('pos_exc', 'LF'), ('pos_exc', 'CF'), ('pos_exc', 'RF')] - logger.info(f'this_batch: {this_batch}') - logger.info(f'slot_params: {slot_params}') - logger.info(f'params: {params}') + logger.info(f"this_batch: {this_batch}") + logger.info(f"slot_params: {slot_params}") + logger.info(f"params: {params}") # No position explicitly requested or denied if len(slot_params) == 0: - if (counts['SP'] + counts['RP']) > ( - counts['C'] + counts['1B'] + counts['2B'] + counts['SS'] + counts['LF'] + counts['CF'] + - counts['RF']): + if (counts["SP"] + counts["RP"]) > ( + counts["C"] + + counts["1B"] + + counts["2B"] + + counts["SS"] + + counts["LF"] + + counts["CF"] + + counts["RF"] + ): pos_counts = [ - ('C', counts['C']), ('1B', counts['1B']), ('2B', counts['2B']), ('3B', counts['3B']), - ('SS', counts['SS']), ('LF', counts['LF']), ('CF', counts['CF']), ('RF', counts['RF']) + ("C", counts["C"]), + ("1B", counts["1B"]), + ("2B", counts["2B"]), + ("3B", counts["3B"]), + ("SS", counts["SS"]), + ("LF", counts["LF"]), + ("CF", counts["CF"]), + ("RF", counts["RF"]), ] pos_counts.sort(key=lambda z: z[1]) - slot_params = [('pos_inc', pos_counts[0][0])] + slot_params = [("pos_inc", pos_counts[0][0])] else: - if counts['SP'] >= counts['RP']: - slot_params = [('pos_inc', 'RP')] + if counts["SP"] >= counts["RP"]: + slot_params = [("pos_inc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] slot_params.extend(params) - p_query = await db_get('players/random', params=slot_params) + p_query = await db_get("players/random", params=slot_params, timeout=10) - if p_query['count'] > 0: + if p_query["count"] > 0: # test_player_list = '' # for z in p_query['players']: # test_player_list += f'{z["rarity"]["name"]} - {z["description"]} - {helpers.get_all_pos(x)}\n' # Collect 1 cards with no repeat player names - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) break if len(this_batch) < 4: - logger.error(f'Pulled less than 4 players in gauntlet draft') - p_query = await db_get('players/random', params=params) - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + logger.error(f"Pulled less than 4 players in gauntlet draft") + p_query = await db_get("players/random", params=params, timeout=10) + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) if len(this_batch) >= 4: break if len(this_batch) < 4: - raise KeyError(f'This is embarassing, but I couldn\'t find enough players for you to draft from.') + raise KeyError( + f"This is embarassing, but I couldn't find enough players for you to draft from." + ) # Present choices and capture selection - p_choice = await helpers.get_choice_from_cards(interaction, this_batch, delete_message=True) + p_choice = await helpers.get_choice_from_cards( + interaction, this_batch, delete_message=True + ) # Add player to list and update counts - p_names.append(p_choice['p_name']) - counts[p_choice['rarity']['name']] += 1 + p_names.append(p_choice["p_name"]) + counts[p_choice["rarity"]["name"]] += 1 all_players.append(p_choice) - if p_choice['pos_1'] in ['SP', 'RP']: - counts[p_choice['pos_1']] += 1 + if p_choice["pos_1"] in ["SP", "RP"]: + counts[p_choice["pos_1"]] += 1 else: for x in helpers.get_all_pos(p_choice): if x in counts: @@ -1364,94 +1704,139 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Update roster embed round_num += 1 - await last_message.edit(content=None, embeds=get_embeds(include_links=False)) - elif this_event['id'] == 4: + await last_message.edit( + content=None, embeds=get_embeds(include_links=False) + ) + elif this_event["id"] == 4: while round_num <= 26 and counter < 50: counter += 1 params = copy.deepcopy(base_params) # Set rarity param based on round number if round_num == 1: - params.extend([ - ('min_rarity', RARITY['HoF']), ('max_rarity', RARITY['HoF']) - ]) + params.extend( + [("min_rarity", RARITY["HoF"]), ("max_rarity", RARITY["HoF"])] + ) elif round_num == 2: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 5: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num == 6: if random.randint(1, 2) == 1: params = [ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']), ('cardset_id', 16) + ("min_rarity", RARITY["MVP"]), + ("max_rarity", RARITY["MVP"]), + ("cardset_id", 16), ] backyard_round = 6 else: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']), ('pos_exc', 'RP') - ]) + params.extend( + [ + ("min_rarity", RARITY["MVP"]), + ("max_rarity", RARITY["MVP"]), + ("pos_exc", "RP"), + ] + ) elif round_num == 7: if random.randint(1, 2) == 1 and backyard_round is None: params = [ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']), ('cardset_id', 16) + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ("cardset_id", 16), ] backyard_round = 7 else: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num == 8: if backyard_round is None: params = [ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']), ('cardset_id', 16) + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ("cardset_id", 16), ] backyard_round = 8 else: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 11: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 15: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 18: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) elif round_num == 19: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) elif round_num <= 21: - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) elif round_num <= 24: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) elif round_num <= 26: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) this_batch = [] - for x in ['SP', 'RP', 'IF', 'OF']: + for x in ["SP", "RP", "IF", "OF"]: # Slot 1 - SP - if x == 'SP': - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] + if x == "SP": + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] # if counts['SP'] > 5: # slot_params = [('pos_exc', 'SP')] # elif counts['RP'] < 6: @@ -1460,25 +1845,31 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')] # Slot 2 - RP - elif x == 'RP': - logger.info(f'counts[RP]: {counts["RP"]}') - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] + elif x == "RP": + logger.info(f"counts[RP]: {counts['RP']}") + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] else: - slot_params = [('pos_inc', 'RP')] + slot_params = [("pos_inc", "RP")] # Slot 3 - IF - elif x == 'IF': + elif x == "IF": slot_params = [] - for y in ['1B', '2B', '3B', 'SS', 'C']: + for y in ["1B", "2B", "3B", "SS", "C"]: if (counts[y] > 1) and 0 in [ - counts['C'], counts['1B'], counts['2B'], counts['3B'], counts['SS'] + counts["C"], + counts["1B"], + counts["2B"], + counts["3B"], + counts["SS"], ]: - slot_params.append(('pos_exc', y)) - elif (y == 'C' and counts['C'] < 3) or (y != 'C' and counts[y] < 4): - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_exc", y)) + elif (y == "C" and counts["C"] < 3) or ( + y != "C" and counts[y] < 4 + ): + slot_params.append(("pos_inc", y)) # if counts['C'] < 2: # slot_params.append(('pos_inc', 'C')) # if len(slot_params) == 0: @@ -1488,73 +1879,93 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Slot 4 - OF else: slot_params = [] - for y in ['LF', 'CF', 'RF']: + for y in ["LF", "CF", "RF"]: if counts[y] > 4: - slot_params.append(('pos_exc', y)) - elif counts[y] > 1 and 0 in [counts['LF'], counts['CF'], counts['RF']]: - slot_params.append(('pos_exc', y)) + slot_params.append(("pos_exc", y)) + elif counts[y] > 1 and 0 in [ + counts["LF"], + counts["CF"], + counts["RF"], + ]: + slot_params.append(("pos_exc", y)) elif counts[y] < 5: - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_inc", y)) # if len(slot_params) == 0: # slot_params = [('pos_exc', 'LF'), ('pos_exc', 'CF'), ('pos_exc', 'RF')] - logger.info(f'this_batch: {this_batch}') - logger.info(f'slot_params: {slot_params}') - logger.info(f'params: {params}') + logger.info(f"this_batch: {this_batch}") + logger.info(f"slot_params: {slot_params}") + logger.info(f"params: {params}") # No position explicitly requested or denied if len(slot_params) == 0: - if (counts['SP'] + counts['RP']) > ( - counts['C'] + counts['1B'] + counts['2B'] + counts['SS'] + counts['LF'] + counts['CF'] + - counts['RF']): + if (counts["SP"] + counts["RP"]) > ( + counts["C"] + + counts["1B"] + + counts["2B"] + + counts["SS"] + + counts["LF"] + + counts["CF"] + + counts["RF"] + ): pos_counts = [ - ('C', counts['C']), ('1B', counts['1B']), ('2B', counts['2B']), ('3B', counts['3B']), - ('SS', counts['SS']), ('LF', counts['LF']), ('CF', counts['CF']), ('RF', counts['RF']) + ("C", counts["C"]), + ("1B", counts["1B"]), + ("2B", counts["2B"]), + ("3B", counts["3B"]), + ("SS", counts["SS"]), + ("LF", counts["LF"]), + ("CF", counts["CF"]), + ("RF", counts["RF"]), ] pos_counts.sort(key=lambda z: z[1]) - slot_params = [('pos_inc', pos_counts[0][0])] + slot_params = [("pos_inc", pos_counts[0][0])] else: - if counts['SP'] >= counts['RP']: - slot_params = [('pos_inc', 'RP')] + if counts["SP"] >= counts["RP"]: + slot_params = [("pos_inc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] slot_params.extend(params) - p_query = await db_get('players/random', params=slot_params) + p_query = await db_get("players/random", params=slot_params, timeout=10) - if p_query['count'] > 0: + if p_query["count"] > 0: # test_player_list = '' # for z in p_query['players']: # test_player_list += f'{z["rarity"]["name"]} - {z["description"]} - {helpers.get_all_pos(x)}\n' # Collect 1 cards with no repeat player names - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) break if len(this_batch) < 4: - logger.error(f'Pulled less than 4 players in gauntlet draft') - p_query = await db_get('players/random', params=params) - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + logger.error(f"Pulled less than 4 players in gauntlet draft") + p_query = await db_get("players/random", params=params, timeout=10) + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) if len(this_batch) >= 4: break if len(this_batch) < 4: - raise KeyError(f'This is embarassing, but I couldn\'t find enough players for you to draft from.') + raise KeyError( + f"This is embarassing, but I couldn't find enough players for you to draft from." + ) # Present choices and capture selection - p_choice = await helpers.get_choice_from_cards(interaction, this_batch, delete_message=True) + p_choice = await helpers.get_choice_from_cards( + interaction, this_batch, delete_message=True + ) # Add player to list and update counts - p_names.append(p_choice['p_name']) - counts[p_choice['rarity']['name']] += 1 + p_names.append(p_choice["p_name"]) + counts[p_choice["rarity"]["name"]] += 1 all_players.append(p_choice) - if p_choice['pos_1'] in ['SP', 'RP']: - counts[p_choice['pos_1']] += 1 + if p_choice["pos_1"] in ["SP", "RP"]: + counts[p_choice["pos_1"]] += 1 else: for x in helpers.get_all_pos(p_choice): if x in counts: @@ -1562,56 +1973,72 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Update roster embed round_num += 1 - await last_message.edit(content=None, embeds=get_embeds(include_links=False)) - elif this_event['id'] in [5, 6, 8, 9]: + await last_message.edit( + content=None, embeds=get_embeds(include_links=False) + ) + elif this_event["id"] in [5, 6, 8, 9]: await draft_loop() - elif this_event['id'] == 7: + elif this_event["id"] == 7: round_num = 1 counter = 0 while round_num <= 26 and counter < 50: counter += 1 params = copy.deepcopy(base_params) - logger.info(f'gauntlets.py - run_draft - event_id {this_event["id"]} / round_num: {round_num} / counter: {counter} / counts: {counts} / max_counts: {max_counts}') + logger.info( + f"gauntlets.py - run_draft - event_id {this_event['id']} / round_num: {round_num} / counter: {counter} / counts: {counts} / max_counts: {max_counts}" + ) # Set rarity based on remaining counts - if counts['Hall of Fame'] < max_counts['Hall of Fame']: - params.extend([ - ('min_rarity', RARITY['HoF']), ('max_rarity', RARITY['HoF']) - ]) - elif counts['MVP'] < max_counts['MVP']: - params.extend([ - ('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP']) - ]) - elif counts['All-Star'] < max_counts['All-Star']: - params.extend([ - ('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star']) - ]) - elif counts['Starter'] < max_counts['Starter']: - if counts['Starter'] < 5: - params = [('cardset_id', 23), ('limit', 16)] - - params.extend([ - ('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter']) - ]) - elif counts['Reserve'] < max_counts['Reserve']: - params.extend([ - ('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve']) - ]) + if counts["Hall of Fame"] < max_counts["Hall of Fame"]: + params.extend( + [("min_rarity", RARITY["HoF"]), ("max_rarity", RARITY["HoF"])] + ) + elif counts["MVP"] < max_counts["MVP"]: + params.extend( + [("min_rarity", RARITY["MVP"]), ("max_rarity", RARITY["MVP"])] + ) + elif counts["All-Star"] < max_counts["All-Star"]: + params.extend( + [ + ("min_rarity", RARITY["All-Star"]), + ("max_rarity", RARITY["All-Star"]), + ] + ) + elif counts["Starter"] < max_counts["Starter"]: + if counts["Starter"] < 5: + params = [("cardset_id", 23), ("limit", 16)] + + params.extend( + [ + ("min_rarity", RARITY["Starter"]), + ("max_rarity", RARITY["Starter"]), + ] + ) + elif counts["Reserve"] < max_counts["Reserve"]: + params.extend( + [ + ("min_rarity", RARITY["Reserve"]), + ("max_rarity", RARITY["Reserve"]), + ] + ) else: - params.extend([ - ('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement']) - ]) + params.extend( + [ + ("min_rarity", RARITY["Replacement"]), + ("max_rarity", RARITY["Replacement"]), + ] + ) this_batch = [] - for x in ['SP', 'RP', 'IF', 'OF']: + for x in ["SP", "RP", "IF", "OF"]: # Slot 1 - SP - if x == 'SP': - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] + if x == "SP": + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] # if counts['SP'] > 5: # slot_params = [('pos_exc', 'SP')] # elif counts['RP'] < 6: @@ -1620,25 +2047,31 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')] # Slot 2 - RP - elif x == 'RP': - logger.info(f'counts[RP]: {counts["RP"]}') - if counts['RP'] > 7: - slot_params = [('pos_exc', 'RP')] - if counts['SP'] > 5: - slot_params = [('pos_exc', 'SP')] + elif x == "RP": + logger.info(f"counts[RP]: {counts['RP']}") + if counts["RP"] > 7: + slot_params = [("pos_exc", "RP")] + if counts["SP"] > 5: + slot_params = [("pos_exc", "SP")] else: - slot_params = [('pos_inc', 'RP')] + slot_params = [("pos_inc", "RP")] # Slot 3 - IF - elif x == 'IF': + elif x == "IF": slot_params = [] - for y in ['1B', '2B', '3B', 'SS', 'C']: + for y in ["1B", "2B", "3B", "SS", "C"]: if (counts[y] > 1) and 0 in [ - counts['C'], counts['1B'], counts['2B'], counts['3B'], counts['SS'] + counts["C"], + counts["1B"], + counts["2B"], + counts["3B"], + counts["SS"], ]: - slot_params.append(('pos_exc', y)) - elif (y == 'C' and counts['C'] < 3) or (y != 'C' and counts[y] < 4): - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_exc", y)) + elif (y == "C" and counts["C"] < 3) or ( + y != "C" and counts[y] < 4 + ): + slot_params.append(("pos_inc", y)) # if counts['C'] < 2: # slot_params.append(('pos_inc', 'C')) # if len(slot_params) == 0: @@ -1648,72 +2081,95 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Slot 4 - OF else: slot_params = [] - for y in ['LF', 'CF', 'RF']: + for y in ["LF", "CF", "RF"]: if counts[y] > 4: - slot_params.append(('pos_exc', y)) - elif counts[y] > 1 and 0 in [counts['LF'], counts['CF'], counts['RF']]: - slot_params.append(('pos_exc', y)) + slot_params.append(("pos_exc", y)) + elif counts[y] > 1 and 0 in [ + counts["LF"], + counts["CF"], + counts["RF"], + ]: + slot_params.append(("pos_exc", y)) elif counts[y] < 5: - slot_params.append(('pos_inc', y)) + slot_params.append(("pos_inc", y)) # if len(slot_params) == 0: # slot_params = [('pos_exc', 'LF'), ('pos_exc', 'CF'), ('pos_exc', 'RF')] - logger.info(f'this_batch: {this_batch}') - logger.info(f'slot_params: {slot_params}') - logger.info(f'params: {params}') + logger.info(f"this_batch: {this_batch}") + logger.info(f"slot_params: {slot_params}") + logger.info(f"params: {params}") # No position explicitly requested or denied if len(slot_params) == 0: - if (counts['SP'] + counts['RP']) > ( - counts['C'] + counts['1B'] + counts['2B'] + counts['SS'] + counts['LF'] + counts['CF'] + - counts['RF']): + if (counts["SP"] + counts["RP"]) > ( + counts["C"] + + counts["1B"] + + counts["2B"] + + counts["SS"] + + counts["LF"] + + counts["CF"] + + counts["RF"] + ): pos_counts = [ - ('C', counts['C']), ('1B', counts['1B']), ('2B', counts['2B']), ('3B', counts['3B']), - ('SS', counts['SS']), ('LF', counts['LF']), ('CF', counts['CF']), ('RF', counts['RF']) + ("C", counts["C"]), + ("1B", counts["1B"]), + ("2B", counts["2B"]), + ("3B", counts["3B"]), + ("SS", counts["SS"]), + ("LF", counts["LF"]), + ("CF", counts["CF"]), + ("RF", counts["RF"]), ] pos_counts.sort(key=lambda z: z[1]) - slot_params = [('pos_inc', pos_counts[0][0])] + slot_params = [("pos_inc", pos_counts[0][0])] else: - if counts['SP'] >= counts['RP']: - slot_params = [('pos_inc', 'RP')] + if counts["SP"] >= counts["RP"]: + slot_params = [("pos_inc", "RP")] else: - slot_params = [('pos_inc', 'SP')] + slot_params = [("pos_inc", "SP")] slot_params.extend(params) - p_query = await db_get('players/random', params=slot_params) + p_query = await db_get("players/random", params=slot_params, timeout=10) - if p_query['count'] > 0: - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: - if i['cardset']['id'] == 23 and '420420' not in i['strat_code']: + if p_query["count"] > 0: + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: + if ( + i["cardset"]["id"] == 23 + and "420420" not in i["strat_code"] + ): pass else: this_batch.append(i) break if len(this_batch) < 4: - logger.error(f'Pulled less than 4 players in gauntlet draft') - p_query = await db_get('players/random', params=params) - for i in p_query['players']: - if i['p_name'] not in p_names and i not in this_batch: + logger.error(f"Pulled less than 4 players in gauntlet draft") + p_query = await db_get("players/random", params=params, timeout=10) + for i in p_query["players"]: + if i["p_name"] not in p_names and i not in this_batch: this_batch.append(i) if len(this_batch) >= 4: break if len(this_batch) < 4: - raise KeyError(f'This is embarassing, but I couldn\'t find enough players for you to draft from.') + raise KeyError( + f"This is embarassing, but I couldn't find enough players for you to draft from." + ) # Present choices and capture selection - p_choice = await helpers.get_choice_from_cards(interaction, this_batch, delete_message=True) + p_choice = await helpers.get_choice_from_cards( + interaction, this_batch, delete_message=True + ) # Add player to list and update counts - p_names.append(p_choice['p_name']) - counts[p_choice['rarity']['name']] += 1 + p_names.append(p_choice["p_name"]) + counts[p_choice["rarity"]["name"]] += 1 all_players.append(p_choice) - if p_choice['pos_1'] in ['SP', 'RP']: - counts[p_choice['pos_1']] += 1 + if p_choice["pos_1"] in ["SP", "RP"]: + counts[p_choice["pos_1"]] += 1 else: for x in helpers.get_all_pos(p_choice): if x in counts: @@ -1721,143 +2177,177 @@ async def run_draft(interaction: discord.Interaction, main_team: Team, this_even # Update roster embed round_num += 1 - await last_message.edit(content=None, embeds=get_embeds(include_links=False, round_num=round_num)) - + await last_message.edit( + content=None, + embeds=get_embeds(include_links=False, round_num=round_num), + ) + else: - logger.error(f'run_draft - No draft logic for Event ID {this_event["id"]}') - raise KeyError(f'Draft data not found for Gauntlet {this_event["id"]}') + logger.error(f"run_draft - No draft logic for Event ID {this_event['id']}") + raise KeyError(f"Draft data not found for Gauntlet {this_event['id']}") if len(all_players) < 26: - raise KeyError(f'I gotta be honest - I shit the bed here and wasn\'t able to get you enough players to fill ' - f'a team. I have to wipe this team, but please draft again after you tell Cal his bot sucks.') + raise KeyError( + f"I gotta be honest - I shit the bed here and wasn't able to get you enough players to fill " + f"a team. I have to wipe this team, but please draft again after you tell Cal his bot sucks." + ) # Handle draft_team as either Team object or dict - draft_team_id = draft_team.id if isinstance(draft_team, Team) else draft_team['id'] + draft_team_id = draft_team.id if isinstance(draft_team, Team) else draft_team["id"] this_pack = await db_post( - 'packs/one', + "packs/one", payload={ - 'team_id': draft_team_id, - 'pack_type_id': 2, - 'open_time': datetime.datetime.timestamp(datetime.datetime.now()) * 1000 - } + "team_id": draft_team_id, + "pack_type_id": 2, + "open_time": datetime.datetime.timestamp(datetime.datetime.now()) * 1000, + }, ) await db_post( - 'cards', - payload={'cards': [ - {'player_id': x['player_id'], 'team_id': draft_team_id, 'pack_id': this_pack['id']} for x in all_players - ]} + "cards", + payload={ + "cards": [ + { + "player_id": x["player_id"], + "team_id": draft_team_id, + "pack_id": this_pack["id"], + } + for x in all_players + ] + }, ) await db_post( - 'gauntletruns', - payload={ - 'team_id': draft_team_id, - 'gauntlet_id': this_event['id'] - } + "gauntletruns", + payload={"team_id": draft_team_id, "gauntlet_id": this_event["id"]}, ) final_embed = get_embeds(False)[0] - final_embed.title = f'{main_team.lname} - {this_event["name"]} Draft' + final_embed.title = f"{main_team.lname} - {this_event['name']} Draft" if main_team.logo: final_embed.set_thumbnail(url=main_team.logo) return final_embed async def get_embed(this_run=None, this_event=None, this_team=None): - logger.info(f'get_embed - this_run:\n{this_run}\n\nthis_event:\n{this_event}') + logger.info(f"get_embed - this_run:\n{this_run}\n\nthis_event:\n{this_event}") if this_run is None and this_event is None: - raise KeyError('Must provide either a run or an event to get_embed') + raise KeyError("Must provide either a run or an event to get_embed") if this_run is not None: - this_event = this_run['gauntlet'] + this_event = this_run["gauntlet"] embed = helpers.image_embed( - image_url=this_event['url'], - title=f'{this_event["name"]}', + image_url=this_event["url"], + title=f"{this_event['name']}", ) - if this_run is not None and this_run['team']['logo']: - embed.set_thumbnail(url=this_run['team']['logo']) - embed.description = this_run['team']['lname'] + if this_run is not None and this_run["team"]["logo"]: + embed.set_thumbnail(url=this_run["team"]["logo"]) + embed.description = this_run["team"]["lname"] - embed.add_field(name='Event Info', value=this_event['short_desc'], inline=False) + embed.add_field(name="Event Info", value=this_event["short_desc"], inline=False) if this_run is not None: - embed.add_field(name='Current Record', value=f'{this_run["wins"]}-{this_run["losses"]}', inline=False) + embed.add_field( + name="Current Record", + value=f"{this_run['wins']}-{this_run['losses']}", + inline=False, + ) - r_query = await db_get('gauntletrewards', params=[('gauntlet_id', this_event['id'])]) - reward_string = '' - for x in r_query['rewards']: + r_query = await db_get( + "gauntletrewards", params=[("gauntlet_id", this_event["id"])] + ) + reward_string = "" + for x in r_query["rewards"]: if this_run is not None: - if this_run['wins'] >= x['win_num'] and this_run['losses'] <= x['loss_max']: - reward_string += '✅️ ' - elif this_run['losses'] > x['loss_max']: - reward_string += '❌ ' + if this_run["wins"] >= x["win_num"] and this_run["losses"] <= x["loss_max"]: + reward_string += "✅️ " + elif this_run["losses"] > x["loss_max"]: + reward_string += "❌ " else: - reward_string += '⬜ ' - reward_string += f'{x["win_num"]}{"-0" if x["loss_max"] == 0 else " Wins"}: ' + reward_string += "⬜ " + reward_string += f"{x['win_num']}{'-0' if x['loss_max'] == 0 else ' Wins'}: " - if x['reward']['money']: - reward_string += f' {x["reward"]["money"]}₼\n' - elif x['reward']['player']: - reward_string += f' {x["reward"]["player"]["description"]}\n' - elif x['reward']['pack_type']: - reward_string += f' {x["reward"]["pack_type"]["name"]} Pack\n' + if x["reward"]["money"]: + reward_string += f" {x['reward']['money']}₼\n" + elif x["reward"]["player"]: + reward_string += f" {x['reward']['player']['description']}\n" + elif x["reward"]["pack_type"]: + reward_string += f" {x['reward']['pack_type']['name']} Pack\n" if len(reward_string) > 0: - embed.add_field(name='Rewards', value=reward_string) + embed.add_field(name="Rewards", value=reward_string) if this_team is not None: - run_query = await db_get('gauntletruns', params=[('team_id', this_team['id']), ('gauntlet_id', this_event['id'])]) - record_name = f'{this_team["abbrev"].split("-")[1]} Record' + run_query = await db_get( + "gauntletruns", + params=[("team_id", this_team["id"]), ("gauntlet_id", this_event["id"])], + ) + record_name = f"{this_team['abbrev'].split('-')[1]} Record" else: - run_query = await db_get('gauntletruns', params=[('gauntlet_id', this_event['id'])]) - record_name = f'League Record' + run_query = await db_get( + "gauntletruns", params=[("gauntlet_id", this_event["id"])] + ) + record_name = f"League Record" - record_value = '' - if run_query['count'] > 0: + record_value = "" + if run_query["count"] > 0: max_wins, victories, perfects = 0, 0, 0 - record_value += f'Attempts: {run_query["count"]}\n' + record_value += f"Attempts: {run_query['count']}\n" - for x in run_query['runs']: - if x['wins'] > max_wins: - max_wins = x['wins'] - if x['wins'] == 10: + for x in run_query["runs"]: + if x["wins"] > max_wins: + max_wins = x["wins"] + if x["wins"] == 10: victories += 1 - if x['losses'] == 0: + if x["losses"] == 0: perfects += 1 if victories > 0: - record_value += f'Victories: {victories}\n' \ - f'10-0 Runs: {perfects}' + record_value += f"Victories: {victories}\n10-0 Runs: {perfects}" else: - record_value += f'Most Wins: {max_wins}' + record_value += f"Most Wins: {max_wins}" embed.add_field(name=record_name, value=record_value) if this_run is not None: - embed.add_field(name='Team Sheet', value=helpers.get_roster_sheet(this_run['team']), inline=False) + embed.add_field( + name="Team Sheet", + value=helpers.get_roster_sheet(this_run["team"]), + inline=False, + ) return embed -async def end_run(this_run, this_event, this_team: Team, bot=None, main_team=None, force_end: bool = False): - l_message = f'Tough loss. That brings your {this_event["name"]} record to ' \ - f'**{this_run["wins"]}-{this_run["losses"]}**. ' - if this_run['losses'] == 2 or force_end: - l_message += 'That\'s the end of this run - better luck next time!' +async def end_run( + this_run, + this_event, + this_team: Team, + bot=None, + main_team=None, + force_end: bool = False, +): + l_message = ( + f"Tough loss. That brings your {this_event['name']} record to " + f"**{this_run['wins']}-{this_run['losses']}**. " + ) + if this_run["losses"] == 2 or force_end: + l_message += "That's the end of this run - better luck next time!" this_run = await db_patch( - 'gauntletruns', - object_id=this_run['id'], - params=[('ended', True)] + "gauntletruns", object_id=this_run["id"], params=[("ended", True)] ) - c_query = await db_post(f'cards/wipe-team/{this_team.id}') + c_query = await db_post(f"cards/wipe-team/{this_team.id}") # Send news-ticker message for natural run completion (2 losses), not for manual resets - if bot and main_team and this_run['losses'] == 2 and not force_end: - team_name = main_team.lname if isinstance(main_team, Team) else main_team.get('lname', 'Unknown Team') + if bot and main_team and this_run["losses"] == 2 and not force_end: + team_name = ( + main_team.lname + if isinstance(main_team, Team) + else main_team.get("lname", "Unknown Team") + ) await send_to_channel( bot, - 'pd-news-ticker', - content=f'The **{team_name}**\'s **{this_event["name"]} Gauntlet** run has ended ' - f'with a final record of {this_run["wins"]}-{this_run["losses"]}.' + "pd-news-ticker", + content=f"The **{team_name}**'s **{this_event['name']} Gauntlet** run has ended " + f"with a final record of {this_run['wins']}-{this_run['losses']}.", ) return l_message @@ -1865,138 +2355,195 @@ async def end_run(this_run, this_event, this_team: Team, bot=None, main_team=Non async def evolve_pokemon(this_team: Team, channel, responders): c_query = await db_get( - 'cards', - params=[('team_id', this_team.id), ('order_by', 'new'), ('limit', 26)] + "cards", params=[("team_id", this_team.id), ("order_by", "new"), ("limit", 26)] ) - logger.info(f'received {c_query['count']} cards, searching now') + logger.info(f"received {c_query['count']} cards, searching now") - evolvable_mons = [x for x in c_query['cards'] if x['player']['cardset']['id'] in [23] and x['player']['fangr_id'] is not None and len(x['player']['fangr_id']) > 3] - logger.info(f'evolvable_mons: {evolvable_mons}') + evolvable_mons = [ + x + for x in c_query["cards"] + if x["player"]["cardset"]["id"] in [23] + and x["player"]["fangr_id"] is not None + and len(x["player"]["fangr_id"]) > 3 + ] + logger.info(f"evolvable_mons: {evolvable_mons}") if len(evolvable_mons) > 0: evo_target_options = [ - SelectOption(label=f'{x["player"]["rarity"]["name"]} | {x["player"]["p_name"]}', value=x['id']) for x in evolvable_mons + SelectOption( + label=f"{x['player']['rarity']['name']} | {x['player']['p_name']}", + value=x["id"], + ) + for x in evolvable_mons ] view = DropdownView( - dropdown_objects=[SelectPokemonEvolution(options=evo_target_options, this_team=this_team, responders=responders)] + dropdown_objects=[ + SelectPokemonEvolution( + options=evo_target_options, + this_team=this_team, + responders=responders, + ) + ] ) await channel.send( - content='What? One of your pokemon is ready to evolve!\n\n-# The selected pokemon will be removed from your team and replaced with its evolution', - view=view + content="What? One of your pokemon is ready to evolve!\n\n-# The selected pokemon will be removed from your team and replaced with its evolution", + view=view, ) else: - await channel.send('All of your Pokemon are fully evolved!') + await channel.send("All of your Pokemon are fully evolved!") -async def post_result(run_id: int, is_win: bool, this_team: Team, bot, channel, responders: list[discord.User] = None): - this_run = await db_get('gauntletruns', object_id=run_id) - this_event = await db_get('events', object_id=this_run['gauntlet']['id']) - t_query = await db_get('teams', params=[('abbrev', f'{this_team.abbrev.replace("Gauntlet-","")}')]) - main_team = t_query['teams'][0] +async def post_result( + run_id: int, + is_win: bool, + this_team: Team, + bot, + channel, + responders: list[discord.User] = None, +): + this_run = await db_get("gauntletruns", object_id=run_id) + this_event = await db_get("events", object_id=this_run["gauntlet"]["id"]) + t_query = await db_get( + "teams", params=[("abbrev", f"{this_team.abbrev.replace('Gauntlet-', '')}")] + ) + main_team = t_query["teams"][0] if is_win: this_run = await db_patch( - 'gauntletruns', - object_id=this_run['id'], - params=[('wins', this_run['wins'] + 1), ('ended', this_run['wins'] + 1 == 10)] + "gauntletruns", + object_id=this_run["id"], + params=[ + ("wins", this_run["wins"] + 1), + ("ended", this_run["wins"] + 1 == 10), + ], ) r_query = await db_get( - 'gauntletrewards', - params=[('gauntlet_id', this_event['id']), ('win_num', this_run['wins']), ('loss_max', this_run['losses'])] + "gauntletrewards", + params=[ + ("gauntlet_id", this_event["id"]), + ("win_num", this_run["wins"]), + ("loss_max", this_run["losses"]), + ], ) - reward_string = '' - for x in r_query['rewards']: - if x['reward']['money']: - await db_post(f'teams/{main_team["id"]}/money/{x["reward"]["money"]}') - reward_string += f'- {x["reward"]["money"]}₼\n' - elif x['reward']['player']: + reward_string = "" + for x in r_query["rewards"]: + if x["reward"]["money"]: + await db_post(f"teams/{main_team['id']}/money/{x['reward']['money']}") + reward_string += f"- {x['reward']['money']}₼\n" + elif x["reward"]["player"]: this_pack = await db_post( - 'packs/one', + "packs/one", payload={ - 'team_id': main_team['id'], - 'pack_type_id': 4, - 'open_time': datetime.datetime.timestamp(datetime.datetime.now()) * 1000} + "team_id": main_team["id"], + "pack_type_id": 4, + "open_time": datetime.datetime.timestamp( + datetime.datetime.now() + ) + * 1000, + }, ) await helpers.give_cards_to_team( - main_team, player_ids=[x['reward']['player']['player_id']], pack_id=this_pack['id']) - reward_string += f'- {helpers.player_desc(x["reward"]["player"])}\n' - elif x['reward']['pack_type'] and this_event['id'] in [3, 4, 5, 6, 8, 9]: - if this_event['id'] == 3: + main_team, + player_ids=[x["reward"]["player"]["player_id"]], + pack_id=this_pack["id"], + ) + reward_string += f"- {helpers.player_desc(x['reward']['player'])}\n" + elif x["reward"]["pack_type"] and this_event["id"] in [3, 4, 5, 6, 8, 9]: + if this_event["id"] == 3: cardset_id = 13 team_id = 58 - elif this_event['id'] == 4: + elif this_event["id"] == 4: cardset_id = 16 team_id = 79 - elif this_event['id'] == 5: + elif this_event["id"] == 5: cardset_id = 17 team_id = None - if x['reward']['pack_type']['id'] == 9: + if x["reward"]["pack_type"]["id"] == 9: cardset_id = 18 - elif this_event['id'] == 6: + elif this_event["id"] == 6: cardset_id = 20 team_id = None - if x['reward']['pack_type']['id'] == 9: + if x["reward"]["pack_type"]["id"] == 9: cardset_id = 21 - elif this_event['id'] == 8: + elif this_event["id"] == 8: cardset_id = 24 team_id = None - if x['reward']['pack_type']['id'] == 9: + if x["reward"]["pack_type"]["id"] == 9: cardset_id = 25 - elif this_event['id'] == 9: + elif this_event["id"] == 9: cardset_id = 27 team_id = None - if x['reward']['pack_type']['id'] == 9: + if x["reward"]["pack_type"]["id"] == 9: cardset_id = 26 await db_post( - 'packs', payload={'packs': [{ - 'team_id': main_team['id'], - 'pack_type_id': x['reward']['pack_type']['id'], - 'pack_cardset_id': cardset_id, - 'pack_team_id': team_id if x['reward']['pack_type']['id'] == 8 else None - }]} + "packs", + payload={ + "packs": [ + { + "team_id": main_team["id"], + "pack_type_id": x["reward"]["pack_type"]["id"], + "pack_cardset_id": cardset_id, + "pack_team_id": team_id + if x["reward"]["pack_type"]["id"] == 8 + else None, + } + ] + }, ) - reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack' - elif x['reward']['pack_type'] and this_event['id'] in [7]: - if this_event['id'] == 7: + reward_string += f"- 1x {x['reward']['pack_type']['name']} Pack" + elif x["reward"]["pack_type"] and this_event["id"] in [7]: + if this_event["id"] == 7: cardset_id = 23 team_id = 91 await db_post( - 'packs', payload={'packs': [{ - 'team_id': main_team['id'], - 'pack_type_id': x['reward']['pack_type']['id'], - 'pack_cardset_id': cardset_id if x['reward']['pack_type']['id'] != 8 else None, - 'pack_team_id': team_id if x['reward']['pack_type']['id'] == 8 else None - }]} + "packs", + payload={ + "packs": [ + { + "team_id": main_team["id"], + "pack_type_id": x["reward"]["pack_type"]["id"], + "pack_cardset_id": cardset_id + if x["reward"]["pack_type"]["id"] != 8 + else None, + "pack_team_id": team_id + if x["reward"]["pack_type"]["id"] == 8 + else None, + } + ] + }, ) - reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack' - elif x['reward']['pack_type']: - await helpers.give_packs(main_team, 1, x['reward']['pack_type']) - reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack' + reward_string += f"- 1x {x['reward']['pack_type']['name']} Pack" + elif x["reward"]["pack_type"]: + await helpers.give_packs(main_team, 1, x["reward"]["pack_type"]) + reward_string += f"- 1x {x['reward']['pack_type']['name']} Pack" - if this_run['wins'] == 10: - choas_role = await get_or_create_role(channel, "CHOAS ALERT", mentionable=True) + if this_run["wins"] == 10: + choas_role = await get_or_create_role( + channel, "CHOAS ALERT", mentionable=True + ) await send_to_channel( bot, - 'pd-network-news', - content=f'{choas_role.mention}\n\nThe **{this_team.lname}** have completed the ' - f'**{this_event["name"]} Gauntlet** with a record of {this_run["wins"]}-' - f'{this_run["losses"]}!' + "pd-network-news", + content=f"{choas_role.mention}\n\nThe **{this_team.lname}** have completed the " + f"**{this_event['name']} Gauntlet** with a record of {this_run['wins']}-" + f"{this_run['losses']}!", ) - final_message = f'That\'s number 10! Way to go - you have completed the **{this_event["name"]} Gauntlet** ' \ - f'with a record of {this_run["wins"]}-{this_run["losses"]}! ' - c_query = await db_post(f'cards/wipe-team/{this_team.id}') + final_message = ( + f"That's number 10! Way to go - you have completed the **{this_event['name']} Gauntlet** " + f"with a record of {this_run['wins']}-{this_run['losses']}! " + ) + c_query = await db_post(f"cards/wipe-team/{this_team.id}") else: - final_message = f'Big win there! Your {this_event["name"]} record is now **{this_run["wins"]}-' \ - f'{this_run["losses"]}**. ' + final_message = ( + f"Big win there! Your {this_event['name']} record is now **{this_run['wins']}-" + f"{this_run['losses']}**. " + ) if len(reward_string) > 0: final_message += f"You earned the following rewards:\n{reward_string}" - final_message += f'\n\nGo share the highlights in {get_channel(channel, "pd-news-ticker").mention}!' + final_message += f"\n\nGo share the highlights in {get_channel(channel, 'pd-news-ticker').mention}!" - await channel.send( - content=final_message, - embed=await get_embed(this_run) - ) + await channel.send(content=final_message, embed=await get_embed(this_run)) else: # this_run = await db_patch( # 'gauntletruns', @@ -2010,22 +2557,18 @@ async def post_result(run_id: int, is_win: bool, this_team: Team, bot, channel, # c_query = await db_post(f'cards/wipe-team/{this_team["id"]}') # this_run = await db_patch( - 'gauntletruns', - object_id=this_run['id'], - params=[('losses', this_run['losses'] + 1)] + "gauntletruns", + object_id=this_run["id"], + params=[("losses", this_run["losses"] + 1)], ) l_message = await end_run(this_run, this_event, this_team, bot, main_team) - await channel.send( - content=l_message, - embed=await get_embed(this_run) - ) + await channel.send(content=l_message, embed=await get_embed(this_run)) # Evolve a card! - logger.info(f'Post-game evolution check: Gauntlet ID {this_run["id"]} / Wins: {this_run["wins"]} / Losses: {this_run["losses"]}') - if this_event['id'] == 7 and this_run['wins'] < 10 and this_run['losses'] < 2: - logger.info(f'trying to evolve now') + logger.info( + f"Post-game evolution check: Gauntlet ID {this_run['id']} / Wins: {this_run['wins']} / Losses: {this_run['losses']}" + ) + if this_event["id"] == 7 and this_run["wins"] < 10 and this_run["losses"] < 2: + logger.info(f"trying to evolve now") await evolve_pokemon(this_team, channel, responders) - - - diff --git a/helpers.py b/helpers.py index cc150d1..9485437 100644 --- a/helpers.py +++ b/helpers.py @@ -22,135 +22,160 @@ from in_game.gameplay_models import Team from constants import * from discord_ui import * from random_content import * -from utils import position_name_to_abbrev, user_has_role, get_roster_sheet_legacy, get_roster_sheet, get_player_url, owner_only, get_cal_user, get_context_user +from utils import ( + position_name_to_abbrev, + user_has_role, + get_roster_sheet_legacy, + get_roster_sheet, + get_player_url, + owner_only, + get_cal_user, + get_context_user, +) from search_utils import * from discord_utils import * - async def get_player_photo(player): - search_term = player['bbref_id'] if player['bbref_id'] else player['p_name'] - req_url = f'https://www.thesportsdb.com/api/v1/json/1/searchplayers.php?p={search_term}' + search_term = player["bbref_id"] if player["bbref_id"] else player["p_name"] + req_url = ( + f"https://www.thesportsdb.com/api/v1/json/1/searchplayers.php?p={search_term}" + ) try: - resp = requests.get(req_url, timeout=.5) + resp = requests.get(req_url, timeout=0.5) except Exception as e: return None - if resp.status_code == 200 and resp.json()['player']: - if resp.json()['player'][0]['strSport'] == 'Baseball': - await db_patch('players', object_id=player['player_id'], - params=[('headshot', resp.json()['player'][0]['strThumb'])]) - return resp.json()['player'][0]['strThumb'] + if resp.status_code == 200 and resp.json()["player"]: + if resp.json()["player"][0]["strSport"] == "Baseball": + await db_patch( + "players", + object_id=player["player_id"], + params=[("headshot", resp.json()["player"][0]["strThumb"])], + ) + return resp.json()["player"][0]["strThumb"] return None async def get_player_headshot(player): - search_term = player['bbref_id'] if player['bbref_id'] else player['p_name'] - req_url = f'https://www.baseball-reference.com/search/search.fcgi?search={search_term}' + search_term = player["bbref_id"] if player["bbref_id"] else player["p_name"] + req_url = ( + f"https://www.baseball-reference.com/search/search.fcgi?search={search_term}" + ) try: resp = requests.get(req_url, timeout=2).text - soup = BeautifulSoup(resp, 'html.parser') - for item in soup.find_all('img'): - if 'headshot' in item['src']: - await db_patch('players', object_id=player['player_id'], params=[('headshot', item['src'])]) - return item['src'] + soup = BeautifulSoup(resp, "html.parser") + for item in soup.find_all("img"): + if "headshot" in item["src"]: + await db_patch( + "players", + object_id=player["player_id"], + params=[("headshot", item["src"])], + ) + return item["src"] except: pass return await get_player_photo(player) - - - - - - - - - - - - """ NEW FOR SEASON 4 """ - - async def get_team_by_owner(owner_id: int): - team = await db_get('teams', params=[('gm_id', owner_id)]) + team = await db_get("teams", params=[("gm_id", owner_id)]) - if not team['count']: + if not team["count"]: return None - return team['teams'][0] + # Prefer the non-gauntlet team (main team) if multiple teams exist + for t in team["teams"]: + if "gauntlet" not in t["abbrev"].lower(): + return t + + # Fallback to first team if all are gauntlet teams + return team["teams"][0] async def team_role(ctx, team: Team): - return await get_or_create_role(ctx, f'{team.abbrev} - {team.lname}') - - - - + return await get_or_create_role(ctx, f"{team.abbrev} - {team.lname}") def get_all_pos(player): all_pos = [] for x in range(1, 8): - if player[f'pos_{x}']: - all_pos.append(player[f'pos_{x}']) + if player[f"pos_{x}"]: + all_pos.append(player[f"pos_{x}"]) return all_pos - - async def share_channel(channel, user, read_only=False): await channel.set_permissions(user, read_messages=True, send_messages=not read_only) async def get_card_embeds(card, include_stats=False) -> list: embed = discord.Embed( - title=f'{card["player"]["p_name"]}', - color=int(card['player']['rarity']['color'], 16) + title=f"{card['player']['p_name']}", + color=int(card["player"]["rarity"]["color"], 16), ) # embed.description = card['team']['lname'] - embed.description = f'{card["player"]["cardset"]["name"]} / {card["player"]["mlbclub"]}' - embed.set_author(name=card['team']['lname'], url=IMAGES['logo'], icon_url=card['team']['logo']) - embed.set_footer(text=f'Paper Dynasty Season {card["team"]["season"]}', icon_url=IMAGES['logo']) + embed.description = ( + f"{card['player']['cardset']['name']} / {card['player']['mlbclub']}" + ) + embed.set_author( + name=card["team"]["lname"], url=IMAGES["logo"], icon_url=card["team"]["logo"] + ) + embed.set_footer( + text=f"Paper Dynasty Season {card['team']['season']}", icon_url=IMAGES["logo"] + ) if include_stats: b_query = await db_get( - 'plays/batting', params=[('player_id', card['player']['player_id']), ('season', PD_SEASON)]) + "plays/batting", + params=[("player_id", card["player"]["player_id"]), ("season", PD_SEASON)], + ) p_query = await db_get( - 'plays/pitching', params=[('player_id', card['player']['player_id']), ('season', PD_SEASON)]) + "plays/pitching", + params=[("player_id", card["player"]["player_id"]), ("season", PD_SEASON)], + ) - embed.add_field(name='Player ID', value=f'{card["player"]["player_id"]}') - embed.add_field(name='Rarity', value=f'{card["player"]["rarity"]["name"]}') - embed.add_field(name='Cost', value=f'{card["player"]["cost"]}₼') + embed.add_field(name="Player ID", value=f"{card['player']['player_id']}") + embed.add_field(name="Rarity", value=f"{card['player']['rarity']['name']}") + embed.add_field(name="Cost", value=f"{card['player']['cost']}₼") - pos_string = ", ".join(get_all_pos(card['player'])) - embed.add_field(name='Positions', value=pos_string) + pos_string = ", ".join(get_all_pos(card["player"])) + embed.add_field(name="Positions", value=pos_string) # all_dex = card['player']['paperdex'] - all_dex = await db_get('paperdex', params=[("player_id", card["player"]["player_id"]), ('flat', True)]) - count = all_dex['count'] - if card['team']['lname'] != 'Paper Dynasty': - bool_list = [True for elem in all_dex['paperdex'] if elem['team'] == card['team'].get('id', None)] + all_dex = await db_get( + "paperdex", params=[("player_id", card["player"]["player_id"]), ("flat", True)] + ) + count = all_dex["count"] + if card["team"]["lname"] != "Paper Dynasty": + bool_list = [ + True + for elem in all_dex["paperdex"] + if elem["team"] == card["team"].get("id", None) + ] if any(bool_list): if count == 1: - coll_string = f'Only you' + coll_string = f"Only you" else: - coll_string = f'You and {count - 1} other{"s" if count - 1 != 1 else ""}' + coll_string = ( + f"You and {count - 1} other{'s' if count - 1 != 1 else ''}" + ) elif count: - coll_string = f'{count} other team{"s" if count != 1 else ""}' + coll_string = f"{count} other team{'s' if count != 1 else ''}" else: - coll_string = f'0 teams' - embed.add_field(name='Collected By', value=coll_string) + coll_string = f"0 teams" + embed.add_field(name="Collected By", value=coll_string) else: - embed.add_field(name='Collected By', value=f'{count} team{"s" if count != 1 else ""}') + embed.add_field( + name="Collected By", value=f"{count} team{'s' if count != 1 else ''}" + ) # TODO: check for dupes with the included paperdex data # if card['team']['lname'] != 'Paper Dynasty': @@ -159,86 +184,104 @@ async def get_card_embeds(card, include_stats=False) -> list: # embed.add_field(name='# Dupes', value=f'{count - 1} dupe{"s" if count - 1 != 1 else ""}') # embed.add_field(name='Team', value=f'{card["player"]["mlbclub"]}') - if card['player']['franchise'] != 'Pokemon': - player_pages = f'[BBRef](https://www.baseball-reference.com/players/{card["player"]["bbref_id"][0]}/{card["player"]["bbref_id"]}.shtml)' + if card["player"]["franchise"] != "Pokemon": + player_pages = f"[BBRef](https://www.baseball-reference.com/players/{card['player']['bbref_id'][0]}/{card['player']['bbref_id']}.shtml)" else: - player_pages = f'[Pkmn]({PKMN_REF_URL}{card["player"]["bbref_id"]})' - embed.add_field(name='Player Page', value=f'{player_pages}') + player_pages = f"[Pkmn]({PKMN_REF_URL}{card['player']['bbref_id']})" + embed.add_field(name="Player Page", value=f"{player_pages}") embed.set_image(url=card["player"]["image"]) - headshot = card['player']['headshot'] if card['player']['headshot'] else await get_player_headshot(card['player']) + headshot = ( + card["player"]["headshot"] + if card["player"]["headshot"] + else await get_player_headshot(card["player"]) + ) if headshot: embed.set_thumbnail(url=headshot) else: - embed.set_thumbnail(url=IMAGES['logo']) - - if card['player']['franchise'] == 'Pokemon': - if card['player']['fangr_id'] is not None: + embed.set_thumbnail(url=IMAGES["logo"]) + + if card["player"]["franchise"] == "Pokemon": + if card["player"]["fangr_id"] is not None: try: - evo_mon = await db_get('players', object_id=card['player']['fangr_id'], none_okay=True) + evo_mon = await db_get( + "players", object_id=card["player"]["fangr_id"], none_okay=True + ) if evo_mon is not None: - embed.add_field( - name='Evolves Into', - value=f'{evo_mon["p_name"]}' - ) + embed.add_field(name="Evolves Into", value=f"{evo_mon['p_name']}") except Exception as e: - logging.error('could not pull evolution: {e}', exc_info=True, stack_info=True) - if '420420' not in card['player']['strat_code']: + logging.error( + "could not pull evolution: {e}", exc_info=True, stack_info=True + ) + if "420420" not in card["player"]["strat_code"]: try: - evo_mon = await db_get('players', object_id=card['player']['strat_code'], none_okay=True) + evo_mon = await db_get( + "players", object_id=card["player"]["strat_code"], none_okay=True + ) if evo_mon is not None: - embed.add_field( - name='Evolves From', - value=f'{evo_mon["p_name"]}' - ) + embed.add_field(name="Evolves From", value=f"{evo_mon['p_name']}") except Exception as e: - logging.error('could not pull evolution: {e}', exc_info=True, stack_info=True) + logging.error( + "could not pull evolution: {e}", exc_info=True, stack_info=True + ) if include_stats: - if b_query['count'] > 0: - b = b_query['stats'][0] + if b_query["count"] > 0: + b = b_query["stats"][0] - re24 = f'{b["re24"]:.2f}' - batting_string = f'```\n' \ - f' AVG OBP SLG\n' \ - f' {b["avg"]:.3f} {b["obp"]:.3f} {b["slg"]:.3f}\n``````\n' \ - f' OPS wOBA RE24\n' \ - f' {b["ops"]:.3f} {b["woba"]:.3f} {re24: ^5}\n``````\n' \ - f' PA H RBI 2B 3B HR SB\n' \ - f'{b["pa"]: >3} {b["hit"]: ^3} {b["rbi"]: ^3} {b["double"]: >2} {b["triple"]: >2} ' \ - f'{b["hr"]: >2} {b["sb"]: >2}```\n' - embed.add_field(name='Batting Stats', value=batting_string, inline=False) - if p_query['count'] > 0: - p = p_query['stats'][0] + re24 = f"{b['re24']:.2f}" + batting_string = ( + f"```\n" + f" AVG OBP SLG\n" + f" {b['avg']:.3f} {b['obp']:.3f} {b['slg']:.3f}\n``````\n" + f" OPS wOBA RE24\n" + f" {b['ops']:.3f} {b['woba']:.3f} {re24: ^5}\n``````\n" + f" PA H RBI 2B 3B HR SB\n" + f"{b['pa']: >3} {b['hit']: ^3} {b['rbi']: ^3} {b['double']: >2} {b['triple']: >2} " + f"{b['hr']: >2} {b['sb']: >2}```\n" + ) + embed.add_field(name="Batting Stats", value=batting_string, inline=False) + if p_query["count"] > 0: + p = p_query["stats"][0] - ip_whole = math.floor(p['outs'] / 3) - ip_denom = p['outs'] % 3 + ip_whole = math.floor(p["outs"] / 3) + ip_denom = p["outs"] % 3 ips = ip_whole + (ip_denom * 0.1) - kpbb = f'{p["k/bb"]:.1f}' - era = f'{p["era"]:.2f}' - whip = f'{p["whip"]:.2f}' - re24 = f'{p["re24"]:.2f}' + kpbb = f"{p['k/bb']:.1f}" + era = f"{p['era']:.2f}" + whip = f"{p['whip']:.2f}" + re24 = f"{p['re24']:.2f}" - pitching_string = f'```\n' \ - f' W-L SV ERA WHIP\n' \ - f'{p["win"]: >2}-{p["loss"]: <2} {p["save"]: >2} {era: >5} {whip: >4}\n``````\n' \ - f' IP SO K/BB RE24\n' \ - f'{ips: >5} {p["so"]: ^3} {kpbb: ^4} {re24: ^5}\n```' - embed.add_field(name='Pitching Stats', value=pitching_string, inline=False) + pitching_string = ( + f"```\n" + f" W-L SV ERA WHIP\n" + f"{p['win']: >2}-{p['loss']: <2} {p['save']: >2} {era: >5} {whip: >4}\n``````\n" + f" IP SO K/BB RE24\n" + f"{ips: >5} {p['so']: ^3} {kpbb: ^4} {re24: ^5}\n```" + ) + embed.add_field(name="Pitching Stats", value=pitching_string, inline=False) - if not card['player']['image2']: + if not card["player"]["image2"]: return [embed] - card_two = discord.Embed(color=int(card['player']['rarity']['color'], 16)) - card_two.set_footer(text=f'Paper Dynasty Season {card["team"]["season"]}', icon_url=IMAGES['logo']) - card_two.set_image(url=card['player']['image2']) + card_two = discord.Embed(color=int(card["player"]["rarity"]["color"], 16)) + card_two.set_footer( + text=f"Paper Dynasty Season {card['team']['season']}", icon_url=IMAGES["logo"] + ) + card_two.set_image(url=card["player"]["image2"]) return [embed, card_two] -def image_embed(image_url: str, title: str = None, color: str = None, desc: str = None, author_name: str = None, - author_icon: str = None): +def image_embed( + image_url: str, + title: str = None, + color: str = None, + desc: str = None, + author_name: str = None, + author_icon: str = None, +): embed_color = int(SBA_COLOR, 16) if color is not None: embed_color = int(color, 16) @@ -250,106 +293,128 @@ def image_embed(image_url: str, title: str = None, color: str = None, desc: str if desc is not None: embed.description = desc if author_name is not None: - icon = author_icon if author_icon is not None else IMAGES['logo'] + icon = author_icon if author_icon is not None else IMAGES["logo"] embed.set_author(name=author_name, icon_url=icon) - embed.set_footer(text=f'Paper Dynasty Season {PD_SEASON}', icon_url=IMAGES['logo']) + embed.set_footer(text=f"Paper Dynasty Season {PD_SEASON}", icon_url=IMAGES["logo"]) embed.set_image(url=image_url) return embed def is_shiny(card): - if card['player']['rarity']['value'] >= 5: + if card["player"]["rarity"]["value"] >= 5: return True return False async def display_cards( - cards: list, team: dict, channel, user, bot=None, pack_cover: str = None, cust_message: str = None, - add_roster: bool = True, pack_name: str = None) -> bool: - logger.info(f'display_cards called with {len(cards)} cards for team {team.get("abbrev", "Unknown")}') + cards: list, + team: dict, + channel, + user, + bot=None, + pack_cover: str = None, + cust_message: str = None, + add_roster: bool = True, + pack_name: str = None, +) -> bool: + logger.info( + f"display_cards called with {len(cards)} cards for team {team.get('abbrev', 'Unknown')}" + ) try: - cards.sort(key=lambda x: x['player']['rarity']['value']) - logger.debug(f'Cards sorted successfully') - + cards.sort(key=lambda x: x["player"]["rarity"]["value"]) + logger.debug(f"Cards sorted successfully") + card_embeds = [await get_card_embeds(x) for x in cards] - logger.debug(f'Created {len(card_embeds)} card embeds') - + logger.debug(f"Created {len(card_embeds)} card embeds") + page_num = 0 if pack_cover is None else -1 seen_shiny = False - logger.debug(f'Initial page_num: {page_num}, pack_cover: {pack_cover is not None}') + logger.debug( + f"Initial page_num: {page_num}, pack_cover: {pack_cover is not None}" + ) except Exception as e: - logger.error(f'Error in display_cards initialization: {e}', exc_info=True) + logger.error(f"Error in display_cards initialization: {e}", exc_info=True) return False try: view = Pagination([user], timeout=10) # Use simple text arrows instead of emojis to avoid context issues - l_emoji = '←' - r_emoji = '→' + l_emoji = "←" + r_emoji = "→" view.left_button.disabled = True - view.left_button.label = f'{l_emoji}Prev: -/{len(card_embeds)}' - view.cancel_button.label = f'Close Pack' - view.right_button.label = f'Next: {page_num + 2}/{len(card_embeds)}{r_emoji}' + view.left_button.label = f"{l_emoji}Prev: -/{len(card_embeds)}" + view.cancel_button.label = f"Close Pack" + view.right_button.label = f"Next: {page_num + 2}/{len(card_embeds)}{r_emoji}" if len(cards) == 1: view.right_button.disabled = True - - logger.debug(f'Pagination view created successfully') + + logger.debug(f"Pagination view created successfully") if pack_cover: - logger.debug(f'Sending pack cover message') + logger.debug(f"Sending pack cover message") msg = await channel.send( content=None, - embed=image_embed(pack_cover, title=f'{team["lname"]}', desc=pack_name), - view=view + embed=image_embed(pack_cover, title=f"{team['lname']}", desc=pack_name), + view=view, ) else: - logger.debug(f'Sending card embed message for page {page_num}') - msg = await channel.send(content=None, embeds=card_embeds[page_num], view=view) - - logger.debug(f'Initial message sent successfully') + logger.debug(f"Sending card embed message for page {page_num}") + msg = await channel.send( + content=None, embeds=card_embeds[page_num], view=view + ) + + logger.debug(f"Initial message sent successfully") except Exception as e: - logger.error(f'Error creating view or sending initial message: {e}', exc_info=True) + logger.error( + f"Error creating view or sending initial message: {e}", exc_info=True + ) return False try: if cust_message: - logger.debug(f'Sending custom message: {cust_message[:50]}...') + logger.debug(f"Sending custom message: {cust_message[:50]}...") follow_up = await channel.send(cust_message) else: - logger.debug(f'Sending default message for {len(cards)} cards') - follow_up = await channel.send(f'{user.mention} you\'ve got {len(cards)} cards here') - - logger.debug(f'Follow-up message sent successfully') + logger.debug(f"Sending default message for {len(cards)} cards") + follow_up = await channel.send( + f"{user.mention} you've got {len(cards)} cards here" + ) + + logger.debug(f"Follow-up message sent successfully") except Exception as e: - logger.error(f'Error sending follow-up message: {e}', exc_info=True) + logger.error(f"Error sending follow-up message: {e}", exc_info=True) return False - logger.debug(f'Starting main interaction loop') + logger.debug(f"Starting main interaction loop") while True: try: - logger.debug(f'Waiting for user interaction on page {page_num}') + logger.debug(f"Waiting for user interaction on page {page_num}") await view.wait() - logger.debug(f'User interaction received: {view.value}') + logger.debug(f"User interaction received: {view.value}") except Exception as e: - logger.error(f'Error in view.wait(): {e}', exc_info=True) + logger.error(f"Error in view.wait(): {e}", exc_info=True) await msg.edit(view=None) return False if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) if add_roster: - await follow_up.edit(content=f'Refresh your cards here: {get_roster_sheet(team)}') + await follow_up.edit( + content=f"Refresh your cards here: {get_roster_sheet(team)}" + ) return True - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 0 else 0 - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num < len(card_embeds) - 1 else 0 else: if page_num == len(card_embeds) - 1: await msg.edit(view=None) if add_roster: - await follow_up.edit(content=f'Refresh your cards here: {get_roster_sheet(team)}') + await follow_up.edit( + content=f"Refresh your cards here: {get_roster_sheet(team)}" + ) return True else: page_num += 1 @@ -358,68 +423,85 @@ async def display_cards( try: if is_shiny(cards[page_num]) and not seen_shiny: - logger.info(f'Shiny card detected on page {page_num}: {cards[page_num]["player"]["p_name"]}') + logger.info( + f"Shiny card detected on page {page_num}: {cards[page_num]['player']['p_name']}" + ) seen_shiny = True view = Pagination([user], timeout=300) view.cancel_button.style = discord.ButtonStyle.success - view.cancel_button.label = 'Flip!' - view.left_button.label = '-' - view.right_button.label = '-' + view.cancel_button.label = "Flip!" + view.left_button.label = "-" + view.right_button.label = "-" view.left_button.disabled = True view.right_button.disabled = True # Get MVP image safely with fallback franchise = cards[page_num]["player"]["franchise"] - logger.debug(f'Getting MVP image for franchise: {franchise}') - mvp_image = IMAGES['mvp'].get(franchise, IMAGES.get('mvp-hype', IMAGES['logo'])) - + logger.debug(f"Getting MVP image for franchise: {franchise}") + mvp_image = IMAGES["mvp"].get( + franchise, IMAGES.get("mvp-hype", IMAGES["logo"]) + ) + await msg.edit( embed=image_embed( mvp_image, - color='56f1fa', - author_name=team['lname'], - author_icon=team['logo'] + color="56f1fa", + author_name=team["lname"], + author_icon=team["logo"], ), - view=view) - logger.debug(f'MVP display updated successfully') + view=view, + ) + logger.debug(f"MVP display updated successfully") except Exception as e: - logger.error(f'Error processing shiny card on page {page_num}: {e}', exc_info=True) + logger.error( + f"Error processing shiny card on page {page_num}: {e}", exc_info=True + ) # Continue with regular flow instead of crashing try: - tmp_msg = await channel.send(content=f'<@&1163537676885033010> we\'ve got an MVP!') - await follow_up.edit(content=f'<@&1163537676885033010> we\'ve got an MVP!') + tmp_msg = await channel.send( + content=f"<@&1163537676885033010> we've got an MVP!" + ) + await follow_up.edit( + content=f"<@&1163537676885033010> we've got an MVP!" + ) await tmp_msg.delete() except discord.errors.NotFound: # Role might not exist or message was already deleted - await follow_up.edit(content=f'We\'ve got an MVP!') + await follow_up.edit(content=f"We've got an MVP!") except Exception as e: # Log error but don't crash the function - logger.error(f'Error handling MVP notification: {e}') - await follow_up.edit(content=f'We\'ve got an MVP!') + logger.error(f"Error handling MVP notification: {e}") + await follow_up.edit(content=f"We've got an MVP!") await view.wait() view = Pagination([user], timeout=10) try: - view.right_button.label = f'Next: {page_num + 2}/{len(card_embeds)}{r_emoji}' - view.cancel_button.label = f'Close Pack' - view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(card_embeds)}' + view.right_button.label = ( + f"Next: {page_num + 2}/{len(card_embeds)}{r_emoji}" + ) + view.cancel_button.label = f"Close Pack" + view.left_button.label = f"{l_emoji}Prev: {page_num}/{len(card_embeds)}" if page_num == 0: - view.left_button.label = f'{l_emoji}Prev: -/{len(card_embeds)}' + view.left_button.label = f"{l_emoji}Prev: -/{len(card_embeds)}" view.left_button.disabled = True elif page_num == len(card_embeds) - 1: view.timeout = 600.0 - view.right_button.label = f'Next: -/{len(card_embeds)}{r_emoji}' + view.right_button.label = f"Next: -/{len(card_embeds)}{r_emoji}" view.right_button.disabled = True - logger.debug(f'Updating message to show page {page_num}/{len(card_embeds)}') + logger.debug(f"Updating message to show page {page_num}/{len(card_embeds)}") if page_num >= len(card_embeds): - logger.error(f'Page number {page_num} exceeds card_embeds length {len(card_embeds)}') + logger.error( + f"Page number {page_num} exceeds card_embeds length {len(card_embeds)}" + ) page_num = len(card_embeds) - 1 - + await msg.edit(content=None, embeds=card_embeds[page_num], view=view) - logger.debug(f'Message updated successfully to page {page_num}') + logger.debug(f"Message updated successfully to page {page_num}") except Exception as e: - logger.error(f'Error updating message on page {page_num}: {e}', exc_info=True) + logger.error( + f"Error updating message on page {page_num}: {e}", exc_info=True + ) # Try to clean up and return try: await msg.edit(view=None) @@ -429,38 +511,45 @@ async def display_cards( async def embed_pagination( - all_embeds: list, channel, user: discord.Member, custom_message: str = None, - timeout: int = 10, start_page: int = 0): + all_embeds: list, + channel, + user: discord.Member, + custom_message: str = None, + timeout: int = 10, + start_page: int = 0, +): if start_page > len(all_embeds) - 1 or start_page < 0: page_num = 0 else: page_num = start_page view = Pagination([user], timeout=timeout) - l_emoji = '' - r_emoji = '' - view.right_button.label = f'Next: {page_num + 2}/{len(all_embeds)}{r_emoji}' - view.cancel_button.label = f'Cancel' - view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(all_embeds)}' + l_emoji = "" + r_emoji = "" + view.right_button.label = f"Next: {page_num + 2}/{len(all_embeds)}{r_emoji}" + view.cancel_button.label = f"Cancel" + view.left_button.label = f"{l_emoji}Prev: {page_num}/{len(all_embeds)}" if page_num == 0: - view.left_button.label = f'{l_emoji}Prev: -/{len(all_embeds)}' + view.left_button.label = f"{l_emoji}Prev: -/{len(all_embeds)}" view.left_button.disabled = True elif page_num == len(all_embeds) - 1: - view.right_button.label = f'Next: -/{len(all_embeds)}{r_emoji}' + view.right_button.label = f"Next: -/{len(all_embeds)}{r_emoji}" view.right_button.disabled = True - msg = await channel.send(content=custom_message, embed=all_embeds[page_num], view=view) + msg = await channel.send( + content=custom_message, embed=all_embeds[page_num], view=view + ) while True: await view.wait() if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) return True - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 0 else 0 - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num <= len(all_embeds) else len(all_embeds) else: if page_num == len(all_embeds) - 1: @@ -472,63 +561,83 @@ async def embed_pagination( view.value = None view = Pagination([user], timeout=timeout) - view.right_button.label = f'Next: {page_num + 2}/{len(all_embeds)}{r_emoji}' - view.cancel_button.label = f'Cancel' - view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(all_embeds)}' + view.right_button.label = f"Next: {page_num + 2}/{len(all_embeds)}{r_emoji}" + view.cancel_button.label = f"Cancel" + view.left_button.label = f"{l_emoji}Prev: {page_num}/{len(all_embeds)}" if page_num == 0: - view.left_button.label = f'{l_emoji}Prev: -/{len(all_embeds)}' + view.left_button.label = f"{l_emoji}Prev: -/{len(all_embeds)}" view.left_button.disabled = True elif page_num == len(all_embeds) - 1: view.timeout = 600.0 - view.right_button.label = f'Next: -/{len(all_embeds)}{r_emoji}' + view.right_button.label = f"Next: -/{len(all_embeds)}{r_emoji}" view.right_button.disabled = True await msg.edit(content=None, embed=all_embeds[page_num], view=view) - - - - - - - - async def get_test_pack(ctx, team): pull_notifs = [] - this_pack = await db_post('packs/one', payload={ - 'team_id': team['id'], 'pack_type_id': 1, - 'open_time': int(datetime.datetime.timestamp(datetime.datetime.now())*1000) - }) - ft_query = await db_get('players/random', params=[('max_rarity', 1), ('limit', 3)]) - four_query = await db_get('players/random', params=[('min_rarity', 1), ('max_rarity', 3), ('limit', 1)]) - five_query = await db_get('players/random', params=[('min_rarity', 5), ('max_rarity', 5), ('limit', 1)]) - first_three = ft_query['players'] - fourth = four_query['players'] - fifth = five_query['players'] + this_pack = await db_post( + "packs/one", + payload={ + "team_id": team["id"], + "pack_type_id": 1, + "open_time": int( + datetime.datetime.timestamp(datetime.datetime.now()) * 1000 + ), + }, + ) + ft_query = await db_get("players/random", params=[("max_rarity", 1), ("limit", 3)]) + four_query = await db_get( + "players/random", params=[("min_rarity", 1), ("max_rarity", 3), ("limit", 1)] + ) + five_query = await db_get( + "players/random", params=[("min_rarity", 5), ("max_rarity", 5), ("limit", 1)] + ) + first_three = ft_query["players"] + fourth = four_query["players"] + fifth = five_query["players"] all_cards = [*first_three, *fourth, *fifth] - success = await db_post('cards', timeout=10, payload={'cards': [{ - 'player_id': x['player_id'], 'team_id': team['id'], 'pack_id': this_pack['id']} for x in all_cards] - }) + success = await db_post( + "cards", + timeout=10, + payload={ + "cards": [ + { + "player_id": x["player_id"], + "team_id": team["id"], + "pack_id": this_pack["id"], + } + for x in all_cards + ] + }, + ) if not success: - await ctx.send(f'I was not able to create these cards {get_emoji(ctx, "slight_frown")}') + await ctx.send( + f"I was not able to create these cards {get_emoji(ctx, 'slight_frown')}" + ) return for x in all_cards: - if x['rarity']['value'] >= 3: + if x["rarity"]["value"] >= 3: pull_notifs.append(x) for pull in pull_notifs: - await db_post('notifs', payload={ - 'created': int(datetime.datetime.timestamp(datetime.datetime.now())*1000), - 'title': 'Rare Pull', - 'field_name': f'{player_desc(pull)} ({pull["rarity"]["name"]})', - 'message': f'Pulled by {team["abbrev"]}', - 'about': f'Player-{pull["player_id"]}' - }) + await db_post( + "notifs", + payload={ + "created": int( + datetime.datetime.timestamp(datetime.datetime.now()) * 1000 + ), + "title": "Rare Pull", + "field_name": f"{player_desc(pull)} ({pull['rarity']['name']})", + "message": f"Pulled by {team['abbrev']}", + "about": f"Player-{pull['player_id']}", + }, + ) - return [{'player': x, 'team': team} for x in all_cards] + return [{"player": x, "team": team} for x in all_cards] async def roll_for_cards(all_packs: list, extra_val=None) -> list: @@ -545,156 +654,140 @@ async def roll_for_cards(all_packs: list, extra_val=None) -> list: """ all_players = [] - team = all_packs[0]['team'] + team = all_packs[0]["team"] pack_ids = [] for pack in all_packs: counts = { - 'Rep': { - 'count': 0, - 'rarity': 0 - }, - 'Res': { - 'count': 0, - 'rarity': 1 - }, - 'Sta': { - 'count': 0, - 'rarity': 2 - }, - 'All': { - 'count': 0, - 'rarity': 3 - }, - 'MVP': { - 'count': 0, - 'rarity': 5 - }, - 'HoF': { - 'count': 0, - 'rarity': 8 - }, + "Rep": {"count": 0, "rarity": 0}, + "Res": {"count": 0, "rarity": 1}, + "Sta": {"count": 0, "rarity": 2}, + "All": {"count": 0, "rarity": 3}, + "MVP": {"count": 0, "rarity": 5}, + "HoF": {"count": 0, "rarity": 8}, } this_pack_players = [] - if pack['pack_type']['name'] == 'Standard': + if pack["pack_type"]["name"] == "Standard": # Cards 1 - 2 for x in range(2): d_1000 = random.randint(1, 1000) if d_1000 <= 450: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 900: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 else: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 # Card 3 d_1000 = random.randint(1, 1000) if d_1000 <= 350: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 700: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 950: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 else: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 # Card 4 d_1000 = random.randint(1, 1000) if d_1000 <= 310: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 620: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 940: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 5 d_1000 = random.randint(1, 1000) if d_1000 <= 215: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 430: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 930: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 980: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 <= 990: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 else: - counts['HoF']['count'] += 1 + counts["HoF"]["count"] += 1 - elif pack['pack_type']['name'] == 'Premium': + elif pack["pack_type"]["name"] == "Premium": # Card 1 d_1000 = random.randint(1, 1000) if d_1000 <= 400: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 870: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 970: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 2 d_1000 = random.randint(1, 1000) if d_1000 <= 300: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 770: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 970: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 3 d_1000 = random.randint(1, 1000) if d_1000 <= 200: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 640: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 940: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 4 d_1000 = random.randint(1, 1000) if d_1000 <= 100: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 if d_1000 <= 530: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 930: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 980: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 <= 990: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 else: - counts['HoF']['count'] += 1 + counts["HoF"]["count"] += 1 # Card 5 d_1000 = random.randint(1, 1000) if d_1000 <= 380: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 880: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 980: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 <= 990: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 else: - counts['HoF']['count'] += 1 + counts["HoF"]["count"] += 1 - elif pack['pack_type']['name'] == 'Check-In Player': - logger.info(f'Building Check-In Pack // extra_val (type): {extra_val} {type(extra_val)}') + elif pack["pack_type"]["name"] == "Check-In Player": + logger.info( + f"Building Check-In Pack // extra_val (type): {extra_val} {type(extra_val)}" + ) # Single Card mod = 0 if isinstance(extra_val, int): @@ -702,86 +795,115 @@ async def roll_for_cards(all_packs: list, extra_val=None) -> list: d_1000 = random.randint(1, 1000 + mod) if d_1000 >= 1100: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 >= 1000: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 >= 500: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 else: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 else: - raise TypeError(f'Pack type not recognized: {pack["pack_type"]["name"]}') + raise TypeError(f"Pack type not recognized: {pack['pack_type']['name']}") pull_notifs = [] for key in counts: mvp_flag = None - if counts[key]['count'] > 0: + if counts[key]["count"] > 0: params = [ - ('min_rarity', counts[key]['rarity']), ('max_rarity', counts[key]['rarity']), - ('limit', counts[key]['count']) + ("min_rarity", counts[key]["rarity"]), + ("max_rarity", counts[key]["rarity"]), + ("limit", counts[key]["count"]), ] - if all_packs[0]['pack_team'] is not None: - params.extend([('franchise', all_packs[0]['pack_team']['lname']), ('in_packs', True)]) - elif all_packs[0]['pack_cardset'] is not None: - params.append(('cardset_id', all_packs[0]['pack_cardset']['id'])) + if all_packs[0]["pack_team"] is not None: + params.extend( + [ + ("franchise", all_packs[0]["pack_team"]["lname"]), + ("in_packs", True), + ] + ) + elif all_packs[0]["pack_cardset"] is not None: + params.append(("cardset_id", all_packs[0]["pack_cardset"]["id"])) else: - params.append(('in_packs', True)) + params.append(("in_packs", True)) - pl = await db_get('players/random', params=params) + pl = await db_get("players/random", params=params) - if pl['count'] != counts[key]['count']: - mvp_flag = counts[key]['count'] - pl['count'] - logging.info(f'Set mvp flag to {mvp_flag} / cardset_id: {all_packs[0]["pack_cardset"]["id"]}') + if pl["count"] != counts[key]["count"]: + mvp_flag = counts[key]["count"] - pl["count"] + logging.info( + f"Set mvp flag to {mvp_flag} / cardset_id: {all_packs[0]['pack_cardset']['id']}" + ) - for x in pl['players']: + for x in pl["players"]: this_pack_players.append(x) all_players.append(x) - if x['rarity']['value'] >= 3: + if x["rarity"]["value"] >= 3: pull_notifs.append(x) - if mvp_flag and all_packs[0]['pack_cardset']['id'] not in [23]: - logging.info(f'Adding {mvp_flag} MVPs for missing cards') - pl = await db_get('players/random', params=[('min_rarity', 5), ('limit', mvp_flag)]) + if mvp_flag and all_packs[0]["pack_cardset"]["id"] not in [23]: + logging.info(f"Adding {mvp_flag} MVPs for missing cards") + pl = await db_get( + "players/random", params=[("min_rarity", 5), ("limit", mvp_flag)] + ) - for x in pl['players']: + for x in pl["players"]: this_pack_players.append(x) all_players.append(x) - + # Add dupes of Replacement/Reserve cards elif mvp_flag: - logging.info(f'Adding {mvp_flag} duplicate pokemon cards') + logging.info(f"Adding {mvp_flag} duplicate pokemon cards") for count in range(mvp_flag): - logging.info(f'Adding {pl["players"][0]["p_name"]} to the pack') + logging.info(f"Adding {pl['players'][0]['p_name']} to the pack") this_pack_players.append(x) - all_players.append(pl['players'][0]) + all_players.append(pl["players"][0]) success = await db_post( - 'cards', - payload={'cards': [{ - 'player_id': x['player_id'], 'team_id': pack['team']['id'], 'pack_id': pack['id']} for x in this_pack_players] + "cards", + payload={ + "cards": [ + { + "player_id": x["player_id"], + "team_id": pack["team"]["id"], + "pack_id": pack["id"], + } + for x in this_pack_players + ] }, - timeout=10 + timeout=10, ) if not success: - raise ConnectionError(f'Failed to create this pack of cards.') + raise ConnectionError(f"Failed to create this pack of cards.") - await db_patch('packs', object_id=pack['id'], params=[ - ('open_time', int(datetime.datetime.timestamp(datetime.datetime.now())*1000)) - ]) - pack_ids.append(pack['id']) + await db_patch( + "packs", + object_id=pack["id"], + params=[ + ( + "open_time", + int(datetime.datetime.timestamp(datetime.datetime.now()) * 1000), + ) + ], + ) + pack_ids.append(pack["id"]) for pull in pull_notifs: - logger.info(f'good pull: {pull}') - await db_post('notifs', payload={ - 'created': int(datetime.datetime.timestamp(datetime.datetime.now())*1000), - 'title': 'Rare Pull', - 'field_name': f'{player_desc(pull)} ({pull["rarity"]["name"]})', - 'message': f'Pulled by {team["abbrev"]}', - 'about': f'Player-{pull["player_id"]}' - }) + logger.info(f"good pull: {pull}") + await db_post( + "notifs", + payload={ + "created": int( + datetime.datetime.timestamp(datetime.datetime.now()) * 1000 + ), + "title": "Rare Pull", + "field_name": f"{player_desc(pull)} ({pull['rarity']['name']})", + "message": f"Pulled by {team['abbrev']}", + "about": f"Player-{pull['player_id']}", + }, + ) return pack_ids @@ -798,43 +920,48 @@ async def give_packs(team: dict, num_packs: int, pack_type: dict = None) -> dict ------- { 'count': int, 'packs': [ all team packs ] } """ - pt_id = pack_type['id'] if pack_type is not None else 1 + pt_id = pack_type["id"] if pack_type is not None else 1 await db_post( - 'packs', - payload={'packs': [{'team_id': team['id'], 'pack_type_id': pt_id} for x in range(num_packs)]} + "packs", + payload={ + "packs": [ + {"team_id": team["id"], "pack_type_id": pt_id} for x in range(num_packs) + ] + }, + ) + total_packs = await db_get( + "packs", params=[("team_id", team["id"]), ("opened", False)] ) - total_packs = await db_get('packs', params=[ - ('team_id', team['id']), ('opened', False) - ]) return total_packs def get_sheets(bot): try: - return bot.get_cog('Gameplay').sheets + return bot.get_cog("Gameplay").sheets except Exception as e: - logger.error(f'Could not grab sheets auth: {e}') - raise ConnectionError(f'Bot has not authenticated with discord; please try again in 1 minute.') + logger.error(f"Could not grab sheets auth: {e}") + raise ConnectionError( + f"Bot has not authenticated with discord; please try again in 1 minute." + ) def create_team_sheet(team, email: str, current, bot): sheets = get_sheets(bot) new_sheet = sheets.drive.copy_file( - f'{current["gsheet_template"]}', - f'{team["lname"]} Roster Sheet v{current["gsheet_version"]}', - '1539D0imTMjlUx2VF3NPMt7Sv85sb2XAJ' + f"{current['gsheet_template']}", + f"{team['lname']} Roster Sheet v{current['gsheet_version']}", + "1539D0imTMjlUx2VF3NPMt7Sv85sb2XAJ", ) - logger.info(f'new_sheet: {new_sheet}') + logger.info(f"new_sheet: {new_sheet}") - this_sheet = sheets.open_by_key(new_sheet['id']) - this_sheet.share(email, role='writer') - team_data = this_sheet.worksheet_by_title('Team Data') + this_sheet = sheets.open_by_key(new_sheet["id"]) + this_sheet.share(email, role="writer") + team_data = this_sheet.worksheet_by_title("Team Data") team_data.update_values( - crange='B1:B2', - values=[[f'{team["id"]}'], [f'\'{team_hash(team)}']] + crange="B1:B2", values=[[f"{team['id']}"], [f"'{team_hash(team)}"]] ) - logger.debug(f'this_sheet: {this_sheet}') + logger.debug(f"this_sheet: {this_sheet}") return this_sheet @@ -843,29 +970,29 @@ async def refresh_sheet(team, bot, sheets=None) -> None: if not sheets: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - my_cards = this_sheet.worksheet_by_title('My Cards') - all_cards = this_sheet.worksheet_by_title('All Cards') + this_sheet = sheets.open_by_key(team["gsheet"]) + my_cards = this_sheet.worksheet_by_title("My Cards") + all_cards = this_sheet.worksheet_by_title("All Cards") - my_cards.update_value('A2', 'FALSE') - all_cards.update_value('A2', 'FALSE') + my_cards.update_value("A2", "FALSE") + all_cards.update_value("A2", "FALSE") await asyncio.sleep(1) - my_cards.update_value('A2', 'TRUE') + my_cards.update_value("A2", "TRUE") await asyncio.sleep(0.5) - all_cards.update_value('A2', 'TRUE') + all_cards.update_value("A2", "TRUE") def delete_sheet(team, bot): sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) + this_sheet = sheets.open_by_key(team["gsheet"]) this_sheet.delete() def share_sheet(team, email, bot) -> None: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - this_sheet.share(email, role='writer') + this_sheet = sheets.open_by_key(team["gsheet"]) + this_sheet.share(email, role="writer") def int_timestamp(datetime_obj: datetime.datetime) -> int: @@ -873,30 +1000,30 @@ def int_timestamp(datetime_obj: datetime.datetime) -> int: def get_pos_abbrev(pos_name): - if pos_name == 'Catcher': - return 'C' - elif pos_name == 'First Base': - return '1B' - elif pos_name == 'Second Base': - return '2B' - elif pos_name == 'Third Base': - return '3B' - elif pos_name == 'Shortstop': - return 'SS' - elif pos_name == 'Left Field': - return 'LF' - elif pos_name == 'Center Field': - return 'CF' - elif pos_name == 'Right Field': - return 'RF' - elif pos_name == 'Pitcher': - return 'P' - elif pos_name == 'Designated Hitter': - return 'DH' - elif pos_name == 'Pinch Hitter': - return 'PH' + if pos_name == "Catcher": + return "C" + elif pos_name == "First Base": + return "1B" + elif pos_name == "Second Base": + return "2B" + elif pos_name == "Third Base": + return "3B" + elif pos_name == "Shortstop": + return "SS" + elif pos_name == "Left Field": + return "LF" + elif pos_name == "Center Field": + return "CF" + elif pos_name == "Right Field": + return "RF" + elif pos_name == "Pitcher": + return "P" + elif pos_name == "Designated Hitter": + return "DH" + elif pos_name == "Pinch Hitter": + return "PH" else: - raise KeyError(f'{pos_name} is not a recognized position name') + raise KeyError(f"{pos_name} is not a recognized position name") async def cardset_search(cardset: str, cardset_list: list) -> Optional[dict]: @@ -904,64 +1031,87 @@ async def cardset_search(cardset: str, cardset_list: list) -> Optional[dict]: if not cardset_name: return None - c_query = await db_get('cardsets', params=[('name', cardset_name)]) - if c_query['count'] == 0: + c_query = await db_get("cardsets", params=[("name", cardset_name)]) + if c_query["count"] == 0: return None - return c_query['cardsets'][0] + return c_query["cardsets"][0] def get_blank_team_card(player): - return {'player': player, 'team': {'lname': 'Paper Dynasty', 'logo': IMAGES['logo'], 'season': PD_SEASON, 'id': None}} + return { + "player": player, + "team": { + "lname": "Paper Dynasty", + "logo": IMAGES["logo"], + "season": PD_SEASON, + "id": None, + }, + } def get_rosters(team, bot, roster_num: Optional[int] = None) -> list: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - r_sheet = this_sheet.worksheet_by_title(f'My Rosters') - logger.debug(f'this_sheet: {this_sheet} / r_sheet = {r_sheet}') + this_sheet = sheets.open_by_key(team["gsheet"]) + r_sheet = this_sheet.worksheet_by_title(f"My Rosters") + logger.debug(f"this_sheet: {this_sheet} / r_sheet = {r_sheet}") all_rosters = [None, None, None] # Pull roster 1 if not roster_num or roster_num == 1: - roster_1 = r_sheet.range('B3:B28') - roster_name = r_sheet.cell('F30').value - logger.info(f'roster_1: {roster_1}') + roster_1 = r_sheet.range("B3:B28") + roster_name = r_sheet.cell("F30").value + logger.info(f"roster_1: {roster_1}") - if not roster_1[0][0].value == '': - all_rosters[0] = {'name': roster_name, 'roster_num': 1, 'team_id': team['id'], 'cards': None} - all_rosters[0]['cards'] = [int(x[0].value) for x in roster_1] + if not roster_1[0][0].value == "": + all_rosters[0] = { + "name": roster_name, + "roster_num": 1, + "team_id": team["id"], + "cards": None, + } + all_rosters[0]["cards"] = [int(x[0].value) for x in roster_1] # Pull roster 2 if not roster_num or roster_num == 2: - roster_2 = r_sheet.range('B29:B54') - roster_name = r_sheet.cell('F31').value - logger.info(f'roster_2: {roster_2}') + roster_2 = r_sheet.range("B29:B54") + roster_name = r_sheet.cell("F31").value + logger.info(f"roster_2: {roster_2}") - if not roster_2[0][0].value == '': - all_rosters[1] = {'name': roster_name, 'roster_num': 2, 'team_id': team['id'], 'cards': None} - all_rosters[1]['cards'] = [int(x[0].value) for x in roster_2] + if not roster_2[0][0].value == "": + all_rosters[1] = { + "name": roster_name, + "roster_num": 2, + "team_id": team["id"], + "cards": None, + } + all_rosters[1]["cards"] = [int(x[0].value) for x in roster_2] # Pull roster 3 if not roster_num or roster_num == 3: - roster_3 = r_sheet.range('B55:B80') - roster_name = r_sheet.cell('F32').value - logger.info(f'roster_3: {roster_3}') + roster_3 = r_sheet.range("B55:B80") + roster_name = r_sheet.cell("F32").value + logger.info(f"roster_3: {roster_3}") - if not roster_3[0][0].value == '': - all_rosters[2] = {'name': roster_name, 'roster_num': 3, 'team_id': team['id'], 'cards': None} - all_rosters[2]['cards'] = [int(x[0].value) for x in roster_3] + if not roster_3[0][0].value == "": + all_rosters[2] = { + "name": roster_name, + "roster_num": 3, + "team_id": team["id"], + "cards": None, + } + all_rosters[2]["cards"] = [int(x[0].value) for x in roster_3] return all_rosters def get_roster_lineups(team, bot, roster_num, lineup_num) -> list: sheets = get_sheets(bot) - logger.debug(f'sheets: {sheets}') - this_sheet = sheets.open_by_key(team['gsheet']) - logger.debug(f'this_sheet: {this_sheet}') - r_sheet = this_sheet.worksheet_by_title('My Rosters') - logger.debug(f'r_sheet: {r_sheet}') + logger.debug(f"sheets: {sheets}") + this_sheet = sheets.open_by_key(team["gsheet"]) + logger.debug(f"this_sheet: {this_sheet}") + r_sheet = this_sheet.worksheet_by_title("My Rosters") + logger.debug(f"r_sheet: {r_sheet}") if lineup_num == 1: row_start = 9 @@ -971,23 +1121,25 @@ def get_roster_lineups(team, bot, roster_num, lineup_num) -> list: row_end = 26 if roster_num == 1: - l_range = f'H{row_start}:I{row_end}' + l_range = f"H{row_start}:I{row_end}" elif roster_num == 2: - l_range = f'J{row_start}:K{row_end}' + l_range = f"J{row_start}:K{row_end}" else: - l_range = f'L{row_start}:M{row_end}' + l_range = f"L{row_start}:M{row_end}" - logger.debug(f'l_range: {l_range}') + logger.debug(f"l_range: {l_range}") raw_cells = r_sheet.range(l_range) - logger.debug(f'raw_cells: {raw_cells}') + logger.debug(f"raw_cells: {raw_cells}") try: lineup_cells = [(row[0].value, int(row[1].value)) for row in raw_cells] except ValueError as e: - logger.error(f'Could not pull roster for {team["abbrev"]} due to a ValueError') - raise ValueError(f'Uh oh. Looks like your roster might not be saved. I am reading blanks when I try to ' - f'get the card IDs') - logger.debug(f'lineup_cells: {lineup_cells}') + logger.error(f"Could not pull roster for {team['abbrev']} due to a ValueError") + raise ValueError( + f"Uh oh. Looks like your roster might not be saved. I am reading blanks when I try to " + f"get the card IDs" + ) + logger.debug(f"lineup_cells: {lineup_cells}") return lineup_cells @@ -995,21 +1147,23 @@ def get_roster_lineups(team, bot, roster_num, lineup_num) -> list: def post_ratings_guide(team, bot, this_sheet=None): if not this_sheet: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - p_guide = this_sheet.worksheet_by_title('Full Guide - Pitchers') - b_guide = this_sheet.worksheet_by_title('Full Guide - Batters') + this_sheet = sheets.open_by_key(team["gsheet"]) + p_guide = this_sheet.worksheet_by_title("Full Guide - Pitchers") + b_guide = this_sheet.worksheet_by_title("Full Guide - Batters") - p_guide.update_value('A1', RATINGS_PITCHER_FORMULA) - b_guide.update_value('A1', RATINGS_BATTER_FORMULA) + p_guide.update_value("A1", RATINGS_PITCHER_FORMULA) + b_guide.update_value("A1", RATINGS_BATTER_FORMULA) async def legal_channel(ctx): """Check for prefix commands (commands.Context).""" - bad_channels = ['paper-dynasty-chat', 'pd-news-ticker', 'pd-network-news'] + bad_channels = ["paper-dynasty-chat", "pd-news-ticker", "pd-network-news"] if isinstance(ctx, commands.Context): if ctx.channel.name in bad_channels: - raise commands.CheckFailure(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)') + raise commands.CheckFailure( + f"Slide on down to the {get_channel(ctx, 'pd-bot-hole').mention} ;)" + ) else: return True @@ -1018,40 +1172,44 @@ async def legal_channel(ctx): # await ctx.send(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)') # logger.warning(f'{ctx.author.name} posted in illegal channel.') # return False - raise discord.app_commands.AppCommandError(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)') + raise discord.app_commands.AppCommandError( + f"Slide on down to the {get_channel(ctx, 'pd-bot-hole').mention} ;)" + ) else: return True def app_legal_channel(): """Check for slash commands (app_commands). Use as @app_legal_channel()""" + async def predicate(interaction: discord.Interaction) -> bool: - bad_channels = ['paper-dynasty-chat', 'pd-news-ticker', 'pd-network-news'] + bad_channels = ["paper-dynasty-chat", "pd-news-ticker", "pd-network-news"] if interaction.channel.name in bad_channels: raise discord.app_commands.CheckFailure( - f'Slide on down to the {get_channel(interaction, "pd-bot-hole").mention} ;)' + f"Slide on down to the {get_channel(interaction, 'pd-bot-hole').mention} ;)" ) return True + return discord.app_commands.check(predicate) def is_ephemeral_channel(channel) -> bool: """Check if channel requires ephemeral responses (chat channels).""" - if not channel or not hasattr(channel, 'name'): + if not channel or not hasattr(channel, "name"): return False - return channel.name in ['paper-dynasty-chat', 'pd-news-ticker'] + return channel.name in ["paper-dynasty-chat", "pd-news-ticker"] def is_restricted_channel(channel) -> bool: """Check if channel is restricted for certain commands (chat/ticker channels).""" - if not channel or not hasattr(channel, 'name'): + if not channel or not hasattr(channel, "name"): return False - return channel.name in ['paper-dynasty-chat', 'pd-news-ticker'] + return channel.name in ["paper-dynasty-chat", "pd-news-ticker"] def can_send_message(channel) -> bool: """Check if channel supports sending messages.""" - return channel and hasattr(channel, 'send') + return channel and hasattr(channel, "send") async def send_safe_message( @@ -1061,20 +1219,20 @@ async def send_safe_message( embeds: List[discord.Embed] = None, view: discord.ui.View = None, ephemeral: bool = False, - delete_after: float = None + delete_after: float = None, ) -> discord.Message: """ Safely send a message using the most appropriate method based on context. - + For Interactions: 1. Try edit_original_response() if deferred 2. Try followup.send() if response is done 3. Try channel.send() if channel supports it - + For Context: - 1. Try ctx.send() + 1. Try ctx.send() 2. Try DM to user with context info if channel send fails - + Args: source: Discord Interaction or Context object content: Message content @@ -1082,110 +1240,126 @@ async def send_safe_message( view: UI view to attach ephemeral: Whether message should be ephemeral (Interaction only) delete_after: Seconds after which to delete message - + Returns: The sent message object - + Raises: Exception: If all send methods fail """ - logger = logging.getLogger('discord_app') - + logger = logging.getLogger("discord_app") + # Prepare message kwargs kwargs = {} if content is not None: - kwargs['content'] = content + kwargs["content"] = content if embeds is not None: - kwargs['embeds'] = embeds + kwargs["embeds"] = embeds if view is not None: - kwargs['view'] = view + kwargs["view"] = view if delete_after is not None: - kwargs['delete_after'] = delete_after - + kwargs["delete_after"] = delete_after + # Handle Interaction objects if isinstance(source, discord.Interaction): # Add ephemeral parameter for interactions if ephemeral: - kwargs['ephemeral'] = ephemeral - + kwargs["ephemeral"] = ephemeral + # Strategy 1: Try edit_original_response if already deferred if source.response.is_done(): try: # For edit_original_response, we need to handle embeds differently edit_kwargs = kwargs.copy() - if 'embeds' in edit_kwargs: + if "embeds" in edit_kwargs: # edit_original_response expects 'embeds' parameter pass # Already correct - if 'ephemeral' in edit_kwargs: + if "ephemeral" in edit_kwargs: # Can't change ephemeral status on edit - del edit_kwargs['ephemeral'] - + del edit_kwargs["ephemeral"] + await source.edit_original_response(**edit_kwargs) # edit_original_response doesn't return a message object in the same way # We'll use followup as backup to get a returnable message - if 'delete_after' not in kwargs: # Don't create extra messages if auto-deleting - return await source.followup.send("Message sent", ephemeral=True, delete_after=0.1) + if ( + "delete_after" not in kwargs + ): # Don't create extra messages if auto-deleting + return await source.followup.send( + "Message sent", ephemeral=True, delete_after=0.1 + ) return None # Can't return meaningful message object from edit except Exception as e: logger.debug(f"Failed to edit original response: {e}") - + # Strategy 2: Try followup.send() try: return await source.followup.send(**kwargs) except Exception as e: logger.debug(f"Failed to send followup message: {e}") - + # Strategy 3: Try channel.send() if possible if can_send_message(source.channel): try: # Remove ephemeral for channel send (not supported) channel_kwargs = kwargs.copy() - if 'ephemeral' in channel_kwargs: - del channel_kwargs['ephemeral'] + if "ephemeral" in channel_kwargs: + del channel_kwargs["ephemeral"] return await source.channel.send(**channel_kwargs) except Exception as e: logger.debug(f"Failed to send channel message: {e}") - + # All interaction methods failed - logger.error(f"All interaction message send methods failed for user {source.user.id}") - raise RuntimeError("Unable to send interaction message through any available method") - - # Handle Context objects + logger.error( + f"All interaction message send methods failed for user {source.user.id}" + ) + raise RuntimeError( + "Unable to send interaction message through any available method" + ) + + # Handle Context objects elif isinstance(source, commands.Context): # Strategy 1: Try ctx.send() directly try: # Remove ephemeral (not supported in Context) ctx_kwargs = kwargs.copy() - if 'ephemeral' in ctx_kwargs: - del ctx_kwargs['ephemeral'] + if "ephemeral" in ctx_kwargs: + del ctx_kwargs["ephemeral"] return await source.send(**ctx_kwargs) except Exception as e: logger.debug(f"Failed to send context message to channel: {e}") - + # Strategy 2: Try DM to user with context info try: # Prepare DM with context information - channel_name = getattr(source.channel, 'name', 'Unknown Channel') - guild_name = getattr(source.guild, 'name', 'Unknown Server') if source.guild else 'DM' - + channel_name = getattr(source.channel, "name", "Unknown Channel") + guild_name = ( + getattr(source.guild, "name", "Unknown Server") + if source.guild + else "DM" + ) + dm_content = f"[Bot Response from #{channel_name} in {guild_name}]\n\n" if content: dm_content += content - + # Send DM with modified content dm_kwargs = kwargs.copy() - dm_kwargs['content'] = dm_content - if 'ephemeral' in dm_kwargs: - del dm_kwargs['ephemeral'] - + dm_kwargs["content"] = dm_content + if "ephemeral" in dm_kwargs: + del dm_kwargs["ephemeral"] + return await source.author.send(**dm_kwargs) except Exception as dm_error: - logger.error(f"Failed to send DM fallback to user {source.author.id}: {dm_error}") + logger.error( + f"Failed to send DM fallback to user {source.author.id}: {dm_error}" + ) # Both ctx.send() and DM failed - let the exception bubble up raise dm_error - + else: - raise TypeError(f"Source must be discord.Interaction or commands.Context, got {type(source)}") + raise TypeError( + f"Source must be discord.Interaction or commands.Context, got {type(source)}" + ) def get_role(ctx, role_name): @@ -1193,35 +1367,35 @@ def get_role(ctx, role_name): async def team_summary_embed(team, ctx, include_roster: bool = True): - embed = get_team_embed(f'{team["lname"]} Overview', team) + embed = get_team_embed(f"{team['lname']} Overview", team) - embed.add_field(name='General Manager', value=team['gmname'], inline=False) - embed.add_field(name='Wallet', value=f'{team["wallet"]}₼') + embed.add_field(name="General Manager", value=team["gmname"], inline=False) + embed.add_field(name="Wallet", value=f"{team['wallet']}₼") # embed.add_field(name='Collection Value', value=team['collection_value']) - p_query = await db_get('packs', params=[('team_id', team['id']), ('opened', False)]) - if p_query['count'] > 0: + p_query = await db_get("packs", params=[("team_id", team["id"]), ("opened", False)]) + if p_query["count"] > 0: all_packs = {} - for x in p_query['packs']: - if x['pack_type']['name'] not in all_packs: - all_packs[x['pack_type']['name']] = 1 + for x in p_query["packs"]: + if x["pack_type"]["name"] not in all_packs: + all_packs[x["pack_type"]["name"]] = 1 else: - all_packs[x['pack_type']['name']] += 1 + all_packs[x["pack_type"]["name"]] += 1 - pack_string = '' + pack_string = "" for pack_type in all_packs: - pack_string += f'{pack_type.title()}: {all_packs[pack_type]}\n' + pack_string += f"{pack_type.title()}: {all_packs[pack_type]}\n" else: - pack_string = 'None' - embed.add_field(name='Unopened Packs', value=pack_string) - embed.add_field(name='Team Rating', value=f'{team["ranking"]}') + pack_string = "None" + embed.add_field(name="Unopened Packs", value=pack_string) + embed.add_field(name="Team Rating", value=f"{team['ranking']}") - r_query = await db_get(f'results/team/{team["id"]}?season={PD_SEASON}') + r_query = await db_get(f"results/team/{team['id']}?season={PD_SEASON}") if r_query: embed.add_field( - name='Record', - value=f'Ranked: {r_query["ranked_wins"]}-{r_query["ranked_losses"]}\n' - f'Unlimited: {r_query["casual_wins"]}-{r_query["casual_losses"]}' + name="Record", + value=f"Ranked: {r_query['ranked_wins']}-{r_query['ranked_losses']}\n" + f"Unlimited: {r_query['casual_wins']}-{r_query['casual_losses']}", ) # try: @@ -1252,325 +1426,335 @@ async def team_summary_embed(team, ctx, include_roster: bool = True): # ) if include_roster: - embed.add_field(name='Team Sheet', value=get_roster_sheet(team), inline=False) + embed.add_field(name="Team Sheet", value=get_roster_sheet(team), inline=False) embed.add_field( - name='For Help', - value=f'`/help-pd` has FAQs; feel free to post questions in ' - f'{get_channel(ctx, "paper-dynasty-chat").mention}.', - inline=False + name="For Help", + value=f"`/help-pd` has FAQs; feel free to post questions in " + f"{get_channel(ctx, 'paper-dynasty-chat').mention}.", + inline=False, ) return embed -async def give_cards_to_team(team, players: list = None, player_ids: list = None, pack_id=None): +async def give_cards_to_team( + team, players: list = None, player_ids: list = None, pack_id=None +): if not pack_id: p_query = await db_post( - 'packs/one', + "packs/one", payload={ - 'team_id': team['id'], - 'pack_type_id': 4, - 'open_time': datetime.datetime.timestamp(datetime.datetime.now()) * 1000} + "team_id": team["id"], + "pack_type_id": 4, + "open_time": datetime.datetime.timestamp(datetime.datetime.now()) + * 1000, + }, ) - pack_id = p_query['id'] + pack_id = p_query["id"] if not players and not player_ids: - raise ValueError('One of players or player_ids must be provided to distribute cards') + raise ValueError( + "One of players or player_ids must be provided to distribute cards" + ) if players: - await db_post('cards', payload={'cards': [ - {'player_id': x['player_id'], 'team_id': team['id'], 'pack_id': pack_id} for x in players - ]}, timeout=10) + await db_post( + "cards", + payload={ + "cards": [ + { + "player_id": x["player_id"], + "team_id": team["id"], + "pack_id": pack_id, + } + for x in players + ] + }, + timeout=10, + ) elif player_ids: - await db_post('cards', payload={'cards': [ - {'player_id': x, 'team_id': team['id'], 'pack_id': pack_id} for x in player_ids - ]}, timeout=10) + await db_post( + "cards", + payload={ + "cards": [ + {"player_id": x, "team_id": team["id"], "pack_id": pack_id} + for x in player_ids + ] + }, + timeout=10, + ) def get_ratings_guide(sheets): this_sheet = sheets.open_by_key(RATINGS_SHEET_KEY) - b_sheet = this_sheet.worksheet_by_title('ratings_Batters') - p_sheet = this_sheet.worksheet_by_title('ratings_Pitchers') + b_sheet = this_sheet.worksheet_by_title("ratings_Batters") + p_sheet = this_sheet.worksheet_by_title("ratings_Pitchers") - b_data = b_sheet.range('A2:N') - p_data = p_sheet.range('A2:N') + b_data = b_sheet.range("A2:N") + p_data = p_sheet.range("A2:N") try: batters = [ { - 'player_id': int(x[0].value), - 'p_name': x[1].value, - 'rating': int(x[2].value), - 'contact-r': int(x[3].value), - 'contact-l': int(x[4].value), - 'power-r': int(x[5].value), - 'power-l': int(x[6].value), - 'vision': int(x[7].value), - 'speed': int(x[8].value), - 'stealing': int(x[9].value), - 'reaction': int(x[10].value), - 'arm': int(x[11].value), - 'fielding': int(x[12].value), - 'hand': int(x[13].value), - } for x in b_data + "player_id": int(x[0].value), + "p_name": x[1].value, + "rating": int(x[2].value), + "contact-r": int(x[3].value), + "contact-l": int(x[4].value), + "power-r": int(x[5].value), + "power-l": int(x[6].value), + "vision": int(x[7].value), + "speed": int(x[8].value), + "stealing": int(x[9].value), + "reaction": int(x[10].value), + "arm": int(x[11].value), + "fielding": int(x[12].value), + "hand": int(x[13].value), + } + for x in b_data ] pitchers = [ { - 'player_id': int(x[0].value), - 'p_name': x[1].value, - 'rating': int(x[2].value), - 'control-r': int(x[3].value), - 'control-l': int(x[4].value), - 'stuff-r': int(x[5].value), - 'stuff-l': int(x[6].value), - 'stamina': int(x[7].value), - 'fielding': int(x[8].value), - 'hit-9': int(x[9].value), - 'k-9': int(x[10].value), - 'bb-9': int(x[11].value), - 'hr-9': int(x[12].value), - 'hand': int(x[13].value), - } for x in p_data + "player_id": int(x[0].value), + "p_name": x[1].value, + "rating": int(x[2].value), + "control-r": int(x[3].value), + "control-l": int(x[4].value), + "stuff-r": int(x[5].value), + "stuff-l": int(x[6].value), + "stamina": int(x[7].value), + "fielding": int(x[8].value), + "hit-9": int(x[9].value), + "k-9": int(x[10].value), + "bb-9": int(x[11].value), + "hr-9": int(x[12].value), + "hand": int(x[13].value), + } + for x in p_data ] except Exception as e: - return {'valid': False} + return {"valid": False} - return { - 'valid': True, - 'batter_ratings': batters, - 'pitcher_ratings': pitchers - } + return {"valid": True, "batter_ratings": batters, "pitcher_ratings": pitchers} async def paperdex_cardset_embed(team: dict, this_cardset: dict) -> list[discord.Embed]: all_dex = await db_get( - 'paperdex', - params=[('team_id', team['id']), ('cardset_id', this_cardset['id']), ('flat', True)] + "paperdex", + params=[ + ("team_id", team["id"]), + ("cardset_id", this_cardset["id"]), + ("flat", True), + ], ) - dex_player_list = [x['player'] for x in all_dex['paperdex']] + dex_player_list = [x["player"] for x in all_dex["paperdex"]] - hof_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - mvp_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - as_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - sta_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - res_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - rep_embed = get_team_embed(f'{team["lname"]} Collection', team=team) + hof_embed = get_team_embed(f"{team['lname']} Collection", team=team) + mvp_embed = get_team_embed(f"{team['lname']} Collection", team=team) + as_embed = get_team_embed(f"{team['lname']} Collection", team=team) + sta_embed = get_team_embed(f"{team['lname']} Collection", team=team) + res_embed = get_team_embed(f"{team['lname']} Collection", team=team) + rep_embed = get_team_embed(f"{team['lname']} Collection", team=team) coll_data = { - 99: { - 'name': 'Hall of Fame', - 'owned': 0, - 'players': [], - 'embeds': [hof_embed] - }, - 1: { - 'name': 'MVP', - 'owned': 0, - 'players': [], - 'embeds': [mvp_embed] - }, - 2: { - 'name': 'All-Star', - 'owned': 0, - 'players': [], - 'embeds': [as_embed] - }, - 3: { - 'name': 'Starter', - 'owned': 0, - 'players': [], - 'embeds': [sta_embed] - }, - 4: { - 'name': 'Reserve', - 'owned': 0, - 'players': [], - 'embeds': [res_embed] - }, - 5: { - 'name': 'Replacement', - 'owned': 0, - 'players': [], - 'embeds': [rep_embed] - }, - 'total_owned': 0 + 99: {"name": "Hall of Fame", "owned": 0, "players": [], "embeds": [hof_embed]}, + 1: {"name": "MVP", "owned": 0, "players": [], "embeds": [mvp_embed]}, + 2: {"name": "All-Star", "owned": 0, "players": [], "embeds": [as_embed]}, + 3: {"name": "Starter", "owned": 0, "players": [], "embeds": [sta_embed]}, + 4: {"name": "Reserve", "owned": 0, "players": [], "embeds": [res_embed]}, + 5: {"name": "Replacement", "owned": 0, "players": [], "embeds": [rep_embed]}, + "total_owned": 0, } set_players = await db_get( - 'players', - params=[('cardset_id', this_cardset['id']), ('flat', True), ('inc_dex', False)], - timeout=5 + "players", + params=[("cardset_id", this_cardset["id"]), ("flat", True), ("inc_dex", False)], + timeout=5, ) - for player in set_players['players']: - if player['player_id'] in dex_player_list: - coll_data[player['rarity']]['owned'] += 1 - coll_data['total_owned'] += 1 - player['owned'] = True + for player in set_players["players"]: + if player["player_id"] in dex_player_list: + coll_data[player["rarity"]]["owned"] += 1 + coll_data["total_owned"] += 1 + player["owned"] = True else: - player['owned'] = False + player["owned"] = False - logger.debug(f'player: {player} / type: {type(player)}') - coll_data[player['rarity']]['players'].append(player) + logger.debug(f"player: {player} / type: {type(player)}") + coll_data[player["rarity"]]["players"].append(player) - cover_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - cover_embed.description = this_cardset['name'] - cover_embed.add_field(name='# Total Cards', value=f'{set_players["count"]}') - cover_embed.add_field(name='# Collected', value=f'{coll_data["total_owned"]}') + cover_embed = get_team_embed(f"{team['lname']} Collection", team=team) + cover_embed.description = this_cardset["name"] + cover_embed.add_field(name="# Total Cards", value=f"{set_players['count']}") + cover_embed.add_field(name="# Collected", value=f"{coll_data['total_owned']}") display_embeds = [cover_embed] for rarity_id in coll_data: - if rarity_id != 'total_owned': - if coll_data[rarity_id]['players']: - coll_data[rarity_id]['embeds'][0].description = f'Rarity: {coll_data[rarity_id]["name"]}' - coll_data[rarity_id]['embeds'][0].add_field( - name='# Collected / # Total Cards', - value=f'{coll_data[rarity_id]["owned"]} / {len(coll_data[rarity_id]["players"])}', - inline=False + if rarity_id != "total_owned": + if coll_data[rarity_id]["players"]: + coll_data[rarity_id]["embeds"][ + 0 + ].description = f"Rarity: {coll_data[rarity_id]['name']}" + coll_data[rarity_id]["embeds"][0].add_field( + name="# Collected / # Total Cards", + value=f"{coll_data[rarity_id]['owned']} / {len(coll_data[rarity_id]['players'])}", + inline=False, ) - chunk_string = '' - for index, this_player in enumerate(coll_data[rarity_id]['players']): - logger.debug(f'this_player: {this_player}') - chunk_string += '☑ ' if this_player['owned'] else '⬜ ' - chunk_string += f'{this_player["p_name"]}\n' + chunk_string = "" + for index, this_player in enumerate(coll_data[rarity_id]["players"]): + logger.debug(f"this_player: {this_player}") + chunk_string += "☑ " if this_player["owned"] else "⬜ " + chunk_string += f"{this_player['p_name']}\n" if (index + 1) == len(coll_data[rarity_id]["players"]): - coll_data[rarity_id]['embeds'][0].add_field( - name=f'Group {math.ceil((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[rarity_id]["players"]) / 20)}', - value=chunk_string + coll_data[rarity_id]["embeds"][0].add_field( + name=f"Group {math.ceil((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[rarity_id]['players']) / 20)}", + value=chunk_string, ) elif (index + 1) % 20 == 0: - coll_data[rarity_id]['embeds'][0].add_field( - name=f'Group {math.floor((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[rarity_id]["players"]) / 20)}', - value=chunk_string + coll_data[rarity_id]["embeds"][0].add_field( + name=f"Group {math.floor((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[rarity_id]['players']) / 20)}", + value=chunk_string, ) - chunk_string = '' + chunk_string = "" - display_embeds.append(coll_data[rarity_id]['embeds'][0]) + display_embeds.append(coll_data[rarity_id]["embeds"][0]) return display_embeds async def paperdex_team_embed(team: dict, mlb_team: dict) -> list[discord.Embed]: all_dex = await db_get( - 'paperdex', - params=[('team_id', team['id']), ('franchise', mlb_team['lname']), ('flat', True)] + "paperdex", + params=[ + ("team_id", team["id"]), + ("franchise", mlb_team["lname"]), + ("flat", True), + ], ) - dex_player_list = [x['player'] for x in all_dex['paperdex']] + dex_player_list = [x["player"] for x in all_dex["paperdex"]] - c_query = await db_get('cardsets') - coll_data = {'total_owned': 0} + c_query = await db_get("cardsets") + coll_data = {"total_owned": 0} total_players = 0 - for x in c_query['cardsets']: + for x in c_query["cardsets"]: set_players = await db_get( - 'players', - params=[('cardset_id', x['id']), ('franchise', mlb_team['lname']), ('flat', True), ('inc_dex', False)] + "players", + params=[ + ("cardset_id", x["id"]), + ("franchise", mlb_team["lname"]), + ("flat", True), + ("inc_dex", False), + ], ) if set_players is not None: - coll_data[x['id']] = { - 'name': x['name'], - 'owned': 0, - 'players': [], - 'embeds': [get_team_embed(f'{team["lname"]} Collection', team=team)] + coll_data[x["id"]] = { + "name": x["name"], + "owned": 0, + "players": [], + "embeds": [get_team_embed(f"{team['lname']} Collection", team=team)], } - total_players += set_players['count'] + total_players += set_players["count"] - for player in set_players['players']: - if player['player_id'] in dex_player_list: - coll_data[x['id']]['owned'] += 1 - coll_data['total_owned'] += 1 - player['owned'] = True + for player in set_players["players"]: + if player["player_id"] in dex_player_list: + coll_data[x["id"]]["owned"] += 1 + coll_data["total_owned"] += 1 + player["owned"] = True else: - player['owned'] = False + player["owned"] = False - logger.debug(f'player: {player} / type: {type(player)}') - coll_data[x['id']]['players'].append(player) + logger.debug(f"player: {player} / type: {type(player)}") + coll_data[x["id"]]["players"].append(player) - cover_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - cover_embed.description = mlb_team['lname'] - cover_embed.add_field(name='# Total Cards', value=f'{total_players}') - cover_embed.add_field(name='# Collected', value=f'{coll_data["total_owned"]}') + cover_embed = get_team_embed(f"{team['lname']} Collection", team=team) + cover_embed.description = mlb_team["lname"] + cover_embed.add_field(name="# Total Cards", value=f"{total_players}") + cover_embed.add_field(name="# Collected", value=f"{coll_data['total_owned']}") display_embeds = [cover_embed] for cardset_id in coll_data: - if cardset_id != 'total_owned': - if coll_data[cardset_id]['players']: - coll_data[cardset_id]['embeds'][0].description = f'{mlb_team["lname"]} / ' \ - f'{coll_data[cardset_id]["name"]}' - coll_data[cardset_id]['embeds'][0].add_field( - name='# Collected / # Total Cards', - value=f'{coll_data[cardset_id]["owned"]} / {len(coll_data[cardset_id]["players"])}', - inline=False + if cardset_id != "total_owned": + if coll_data[cardset_id]["players"]: + coll_data[cardset_id]["embeds"][0].description = ( + f"{mlb_team['lname']} / {coll_data[cardset_id]['name']}" + ) + coll_data[cardset_id]["embeds"][0].add_field( + name="# Collected / # Total Cards", + value=f"{coll_data[cardset_id]['owned']} / {len(coll_data[cardset_id]['players'])}", + inline=False, ) - chunk_string = '' - for index, this_player in enumerate(coll_data[cardset_id]['players']): - logger.debug(f'this_player: {this_player}') - chunk_string += '☑ ' if this_player['owned'] else '⬜ ' - chunk_string += f'{this_player["p_name"]}\n' + chunk_string = "" + for index, this_player in enumerate(coll_data[cardset_id]["players"]): + logger.debug(f"this_player: {this_player}") + chunk_string += "☑ " if this_player["owned"] else "⬜ " + chunk_string += f"{this_player['p_name']}\n" if (index + 1) == len(coll_data[cardset_id]["players"]): - coll_data[cardset_id]['embeds'][0].add_field( - name=f'Group {math.ceil((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[cardset_id]["players"]) / 20)}', - value=chunk_string + coll_data[cardset_id]["embeds"][0].add_field( + name=f"Group {math.ceil((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[cardset_id]['players']) / 20)}", + value=chunk_string, ) elif (index + 1) % 20 == 0: - coll_data[cardset_id]['embeds'][0].add_field( - name=f'Group {math.floor((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[cardset_id]["players"]) / 20)}', - value=chunk_string + coll_data[cardset_id]["embeds"][0].add_field( + name=f"Group {math.floor((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[cardset_id]['players']) / 20)}", + value=chunk_string, ) - chunk_string = '' + chunk_string = "" - display_embeds.append(coll_data[cardset_id]['embeds'][0]) + display_embeds.append(coll_data[cardset_id]["embeds"][0]) return display_embeds def get_pack_cover(pack): - if pack['pack_cardset'] is not None and pack['pack_cardset'] == 23: - return IMAGES['pack-pkmnbs'] - elif pack['pack_type']['name'] in ['Premium', 'MVP']: - return IMAGES['pack-pre'] - elif pack['pack_type']['name'] == 'Standard': - return IMAGES['pack-sta'] - elif pack['pack_type']['name'] == 'Mario': - return IMAGES['pack-mar'] + if pack["pack_cardset"] is not None and pack["pack_cardset"] == 23: + return IMAGES["pack-pkmnbs"] + elif pack["pack_type"]["name"] in ["Premium", "MVP"]: + return IMAGES["pack-pre"] + elif pack["pack_type"]["name"] == "Standard": + return IMAGES["pack-sta"] + elif pack["pack_type"]["name"] == "Mario": + return IMAGES["pack-mar"] else: return None async def open_st_pr_packs(all_packs: list, team: dict, context): - pack_channel = get_channel(context, 'pack-openings') + pack_channel = get_channel(context, "pack-openings") pack_cover = get_pack_cover(all_packs[0]) if pack_cover is None: pack_channel = context.channel if not pack_channel: - raise ValueError(f'I cannot find the pack-openings channel. {get_cal_user(context).mention} - halp?') + raise ValueError( + f"I cannot find the pack-openings channel. {get_cal_user(context).mention} - halp?" + ) pack_ids = await roll_for_cards(all_packs) if not pack_ids: - logger.error(f'open_packs - unable to roll_for_cards for packs: {all_packs}') - raise ValueError(f'I was not able to unpack these cards') + logger.error(f"open_packs - unable to roll_for_cards for packs: {all_packs}") + raise ValueError(f"I was not able to unpack these cards") all_cards = [] for p_id in pack_ids: - new_cards = await db_get('cards', params=[('pack_id', p_id)]) - all_cards.extend(new_cards['cards']) + new_cards = await db_get("cards", params=[("pack_id", p_id)]) + all_cards.extend(new_cards["cards"]) if not all_cards: - logger.error(f'open_packs - unable to get cards for packs: {pack_ids}') - raise ValueError(f'I was not able to display these cards') + logger.error(f"open_packs - unable to get cards for packs: {pack_ids}") + raise ValueError(f"I was not able to display these cards") # Present cards to opening channel if type(context) == commands.Context: @@ -1578,53 +1762,68 @@ async def open_st_pr_packs(all_packs: list, team: dict, context): else: author = context.user - await context.channel.send(content=f'Let\'s head down to {pack_channel.mention}!') + await context.channel.send(content=f"Let's head down to {pack_channel.mention}!") await display_cards(all_cards, team, pack_channel, author, pack_cover=pack_cover) async def get_choice_from_cards( - interaction: discord.Interaction, all_players: list = None, cover_title: str = None, - cover_desc: str = None, cover_image_url: str = None, callback=None, temp_message: str = None, - conf_message: str = None, delete_message: bool = False): + interaction: discord.Interaction, + all_players: list = None, + cover_title: str = None, + cover_desc: str = None, + cover_image_url: str = None, + callback=None, + temp_message: str = None, + conf_message: str = None, + delete_message: bool = False, +): # Display them with pagination, prev/next/select card_embeds = [ await get_card_embeds( - {'player': x, 'team': {'lname': 'Paper Dynasty', 'season': PD_SEASON, 'logo': IMAGES['logo']}} - ) for x in all_players + { + "player": x, + "team": { + "lname": "Paper Dynasty", + "season": PD_SEASON, + "logo": IMAGES["logo"], + }, + } + ) + for x in all_players ] - logger.debug(f'card embeds: {card_embeds}') + logger.debug(f"card embeds: {card_embeds}") if cover_title is not None and cover_image_url is not None: page_num = 0 view = Pagination([interaction.user], timeout=30) view.left_button.disabled = True - view.left_button.label = f'Prev: -/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: -/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success view.cancel_button.disabled = True - view.right_button.label = f'Next: 1/{len(card_embeds)}' + view.right_button.label = f"Next: 1/{len(card_embeds)}" msg = await interaction.channel.send( content=None, embed=image_embed( - image_url=cover_image_url, - title=cover_title, - desc=cover_desc + image_url=cover_image_url, title=cover_title, desc=cover_desc ), - view=view + view=view, ) else: page_num = 1 view = Pagination([interaction.user], timeout=30) - view.left_button.label = f'Prev: -/{len(card_embeds)}' + view.left_button.label = f"Prev: -/{len(card_embeds)}" view.left_button.disabled = True - view.cancel_button.label = f'Take This Card' + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success - view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}' + view.right_button.label = f"Next: {page_num + 1}/{len(card_embeds)}" - msg = await interaction.channel.send(content=None, embeds=card_embeds[page_num - 1], view=view) + msg = await interaction.channel.send( + content=None, embeds=card_embeds[page_num - 1], view=view + ) if temp_message is not None: temp_msg = await interaction.channel.send(content=temp_message) @@ -1635,7 +1834,7 @@ async def get_choice_from_cards( await view.wait() if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) if callback is not None: @@ -1647,9 +1846,9 @@ async def get_choice_from_cards( else: await interaction.channel.send(content=conf_message) break - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 1 else len(card_embeds) - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num < len(card_embeds) else 1 else: if page_num == len(card_embeds): @@ -1660,15 +1859,15 @@ async def get_choice_from_cards( view.value = None view = Pagination([interaction.user], timeout=30) - view.left_button.label = f'Prev: {page_num - 1}/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: {page_num - 1}/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success - view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}' + view.right_button.label = f"Next: {page_num + 1}/{len(card_embeds)}" if page_num == 1: - view.left_button.label = f'Prev: -/{len(card_embeds)}' + view.left_button.label = f"Prev: -/{len(card_embeds)}" view.left_button.disabled = True elif page_num == len(card_embeds): - view.right_button.label = f'Next: -/{len(card_embeds)}' + view.right_button.label = f"Next: -/{len(card_embeds)}" view.right_button.disabled = True await msg.edit(content=None, embeds=card_embeds[page_num - 1], view=view) @@ -1678,14 +1877,16 @@ async def get_choice_from_cards( return all_players[page_num - 1] -async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[int] = None): - pack_channel = get_channel(context, 'pack-openings') +async def open_choice_pack( + this_pack, team: dict, context, cardset_id: Optional[int] = None +): + pack_channel = get_channel(context, "pack-openings") pack_cover = get_pack_cover(this_pack) - pack_type = this_pack['pack_type']['name'] + pack_type = this_pack["pack_type"]["name"] players = [] - if pack_type == 'Mario': + if pack_type == "Mario": d1000 = random.randint(1, 1000) if d1000 > 800: rarity_id = 5 @@ -1694,21 +1895,24 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ else: rarity_id = 2 pl = await db_get( - 'players/random', + "players/random", params=[ - ('cardset_id', 8), ('min_rarity', rarity_id), ('max_rarity', rarity_id), ('limit', 4) - ] + ("cardset_id", 8), + ("min_rarity", rarity_id), + ("max_rarity", rarity_id), + ("limit", 4), + ], ) - players = pl['players'] - elif pack_type == 'Team Choice': - if this_pack['pack_team'] is None: - raise KeyError(f'Team not listed for Team Choice pack') + players = pl["players"] + elif pack_type == "Team Choice": + if this_pack["pack_team"] is None: + raise KeyError(f"Team not listed for Team Choice pack") d1000 = random.randint(1, 1000) - pack_cover = this_pack['pack_team']['logo'] + pack_cover = this_pack["pack_team"]["logo"] if d1000 > 800: rarity_id = 5 - pack_cover = IMAGES['mvp'][this_pack['pack_team']['lname']] + pack_cover = IMAGES["mvp"][this_pack["pack_team"]["lname"]] elif d1000 > 550: rarity_id = 3 else: @@ -1721,43 +1925,46 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ min_rarity = rarity_id while len(players) < 4 and rarity_id < 10: params = [ - ('min_rarity', min_rarity), ('max_rarity', rarity_id), ('limit', 4 - len(players)), - ('franchise', this_pack['pack_team']['lname']) + ("min_rarity", min_rarity), + ("max_rarity", rarity_id), + ("limit", 4 - len(players)), + ("franchise", this_pack["pack_team"]["lname"]), ] - if this_pack['pack_team']['abbrev'] not in ['MSS']: - params.append(('in_packs', True)) + if this_pack["pack_team"]["abbrev"] not in ["MSS"]: + params.append(("in_packs", True)) if cardset_id is not None: - params.append(('cardset_id', cardset_id)) - pl = await db_get( - 'players/random', - params=params - ) - if pl['count'] >= 0: - for x in pl['players']: + params.append(("cardset_id", cardset_id)) + pl = await db_get("players/random", params=params) + if pl["count"] >= 0: + for x in pl["players"]: if x not in players: players.append(x) if len(players) < 4: min_rarity += 1 rarity_id += 1 - elif pack_type == 'Promo Choice': - if this_pack['pack_cardset'] is None: - raise KeyError(f'Cardset not listed for Promo Choice pack') + elif pack_type == "Promo Choice": + if this_pack["pack_cardset"] is None: + raise KeyError(f"Cardset not listed for Promo Choice pack") d1000 = random.randint(1, 1000) - pack_cover = IMAGES['mvp-hype'] - cardset_id = this_pack['pack_cardset']['id'] + pack_cover = IMAGES["mvp-hype"] + cardset_id = this_pack["pack_cardset"]["id"] rarity_id = 5 if d1000 > 800: rarity_id = 8 while len(players) < 4 and rarity_id < 10: pl = await db_get( - 'players/random', - params=[('cardset_id', cardset_id), ('min_rarity', rarity_id), ('max_rarity', rarity_id), - ('limit', 8)] + "players/random", + params=[ + ("cardset_id", cardset_id), + ("min_rarity", rarity_id), + ("max_rarity", rarity_id), + ("limit", 8), + ], ) - if pl['count'] >= 0: - for x in pl['players']: + if pl["count"] >= 0: + for x in pl["players"]: if len(players) >= 4: break if x not in players: @@ -1767,92 +1974,114 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ else: # Get 4 MVP cards rarity_id = 5 - if pack_type == 'HoF': + if pack_type == "HoF": rarity_id = 8 - elif pack_type == 'All Star': + elif pack_type == "All Star": rarity_id = 3 min_rarity = rarity_id while len(players) < 4 and rarity_id < 10: params = [ - ('min_rarity', min_rarity), ('max_rarity', rarity_id), ('limit', 4), ('in_packs', True) + ("min_rarity", min_rarity), + ("max_rarity", rarity_id), + ("limit", 4), + ("in_packs", True), ] - if this_pack['pack_team'] is not None: - params.append(('franchise', this_pack['pack_team']['lname'])) + if this_pack["pack_team"] is not None: + params.append(("franchise", this_pack["pack_team"]["lname"])) if cardset_id is not None: - params.append(('cardset_id', cardset_id)) - pl = await db_get('players/random', params=params) + params.append(("cardset_id", cardset_id)) + pl = await db_get("players/random", params=params) - if pl['count'] > 0: - players.extend(pl['players']) + if pl["count"] > 0: + players.extend(pl["players"]) if len(players) < 4: rarity_id += 3 if len(players) == 0: - logger.error(f'Could not create choice pack') - raise ConnectionError(f'Could not create choice pack') + logger.error(f"Could not create choice pack") + raise ConnectionError(f"Could not create choice pack") if type(context) == commands.Context: author = context.author else: author = context.user - logger.info(f'helpers - open_choice_pack - players: {players}') + logger.info(f"helpers - open_choice_pack - players: {players}") # Display them with pagination, prev/next/select card_embeds = [ await get_card_embeds( # {'player': x, 'team': {'lname': 'Paper Dynasty', 'season': PD_SEASON, 'logo': IMAGES['logo']}} - {'player': x, 'team': team} # Show team and dupe info - ) for x in players + {"player": x, "team": team} # Show team and dupe info + ) + for x in players ] - logger.debug(f'card embeds: {card_embeds}') + logger.debug(f"card embeds: {card_embeds}") page_num = 0 view = Pagination([author], timeout=30) view.left_button.disabled = True - view.left_button.label = f'Prev: -/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: -/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success view.cancel_button.disabled = True - view.right_button.label = f'Next: 1/{len(card_embeds)}' + view.right_button.label = f"Next: 1/{len(card_embeds)}" # React to selection - await context.channel.send(f'Let\'s head down to {pack_channel.mention}!') + await context.channel.send(f"Let's head down to {pack_channel.mention}!") msg = await pack_channel.send( content=None, - embed=image_embed(pack_cover, title=f'{team["lname"]}', desc=f'{pack_type} Pack - Choose 1 of 4 {pack_type}s!'), - view=view + embed=image_embed( + pack_cover, + title=f"{team['lname']}", + desc=f"{pack_type} Pack - Choose 1 of 4 {pack_type}s!", + ), + view=view, ) if rarity_id >= 5: - tmp_msg = await pack_channel.send(content=f'<@&1163537676885033010> we\'ve got an MVP!') + tmp_msg = await pack_channel.send( + content=f"<@&1163537676885033010> we've got an MVP!" + ) else: - tmp_msg = await pack_channel.send(content=f'We\'ve got a choice pack here!') + tmp_msg = await pack_channel.send(content=f"We've got a choice pack here!") while True: await view.wait() if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) try: - await give_cards_to_team(team, players=[players[page_num - 1]], pack_id=this_pack['id']) + await give_cards_to_team( + team, players=[players[page_num - 1]], pack_id=this_pack["id"] + ) except Exception as e: - logger.error(f'failed to create cards: {e}') - raise ConnectionError(f'Failed to distribute these cards.') + logger.error(f"failed to create cards: {e}") + raise ConnectionError(f"Failed to distribute these cards.") - await db_patch('packs', object_id=this_pack['id'], params=[ - ('open_time', int(datetime.datetime.timestamp(datetime.datetime.now()) * 1000)) - ]) + await db_patch( + "packs", + object_id=this_pack["id"], + params=[ + ( + "open_time", + int( + datetime.datetime.timestamp(datetime.datetime.now()) + * 1000 + ), + ) + ], + ) await tmp_msg.edit( - content=f'{players[page_num - 1]["p_name"]} has been added to the ' - f'**{team["sname"]}** binder!' + content=f"{players[page_num - 1]['p_name']} has been added to the " + f"**{team['sname']}** binder!" ) break - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 1 else len(card_embeds) - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num < len(card_embeds) else 1 else: if page_num == len(card_embeds): @@ -1863,70 +2092,62 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ view.value = None view = Pagination([author], timeout=30) - view.left_button.label = f'Prev: {page_num - 1}/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: {page_num - 1}/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success - view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}' + view.right_button.label = f"Next: {page_num + 1}/{len(card_embeds)}" if page_num == 1: - view.left_button.label = f'Prev: -/{len(card_embeds)}' + view.left_button.label = f"Prev: -/{len(card_embeds)}" view.left_button.disabled = True elif page_num == len(card_embeds): - view.right_button.label = f'Next: -/{len(card_embeds)}' + view.right_button.label = f"Next: -/{len(card_embeds)}" view.right_button.disabled = True await msg.edit(content=None, embeds=card_embeds[page_num - 1], view=view) -async def confirm_pack_purchase(interaction, owner_team, num_packs, total_cost, pack_embed): +async def confirm_pack_purchase( + interaction, owner_team, num_packs, total_cost, pack_embed +): view = Confirm(responders=[interaction.user], timeout=30) - await interaction.channel.send( - content=None, - embed=pack_embed - ) + await interaction.channel.send(content=None, embed=pack_embed) question = await interaction.channel.send( - content=f'Your Wallet: {owner_team["wallet"]}₼\n' - f'Pack{"s" if num_packs > 1 else ""} Price: {total_cost}₼\n' - f'After Purchase: {owner_team["wallet"] - total_cost}₼\n\n' - f'Would you like to make this purchase?', - view=view + content=f"Your Wallet: {owner_team['wallet']}₼\n" + f"Pack{'s' if num_packs > 1 else ''} Price: {total_cost}₼\n" + f"After Purchase: {owner_team['wallet'] - total_cost}₼\n\n" + f"Would you like to make this purchase?", + view=view, ) await view.wait() if not view.value: - await question.edit( - content='Saving that money. Smart.', - view=None - ) + await question.edit(content="Saving that money. Smart.", view=None) return None else: return question def player_desc(this_player) -> str: - if this_player['p_name'] in this_player['description']: - return this_player['description'] - return f'{this_player["description"]} {this_player["p_name"]}' + if this_player["p_name"] in this_player["description"]: + return this_player["description"] + return f"{this_player['description']} {this_player['p_name']}" def player_pcard(this_player): - if this_player['image'] is not None and 'pitching' in this_player['image']: - return this_player['image'] - elif this_player['image2'] is not None and 'pitching' in this_player['image2']: - return this_player['image2'] + if this_player["image"] is not None and "pitching" in this_player["image"]: + return this_player["image"] + elif this_player["image2"] is not None and "pitching" in this_player["image2"]: + return this_player["image2"] else: - return this_player['image'] + return this_player["image"] def player_bcard(this_player): - if this_player['image'] is not None and 'batting' in this_player['image']: - return this_player['image'] - elif this_player['image2'] is not None and 'batting' in this_player['image2']: - return this_player['image2'] + if this_player["image"] is not None and "batting" in this_player["image"]: + return this_player["image"] + elif this_player["image2"] is not None and "batting" in this_player["image2"]: + return this_player["image2"] # elif this_player['image'] is not None and 'pitching' in this_player['image']: # return PITCHER_BATTING_CARD else: - return this_player['image'] - - - - + return this_player["image"] diff --git a/helpers/main.py b/helpers/main.py index ff744c8..ed16a3b 100644 --- a/helpers/main.py +++ b/helpers/main.py @@ -22,135 +22,160 @@ from in_game.gameplay_models import Team from constants import * from discord_ui import * from random_content import * -from utils import position_name_to_abbrev, user_has_role, get_roster_sheet_legacy, get_roster_sheet, get_player_url, owner_only, get_cal_user, get_context_user +from utils import ( + position_name_to_abbrev, + user_has_role, + get_roster_sheet_legacy, + get_roster_sheet, + get_player_url, + owner_only, + get_cal_user, + get_context_user, +) from search_utils import * from discord_utils import * - async def get_player_photo(player): - search_term = player['bbref_id'] if player['bbref_id'] else player['p_name'] - req_url = f'https://www.thesportsdb.com/api/v1/json/1/searchplayers.php?p={search_term}' + search_term = player["bbref_id"] if player["bbref_id"] else player["p_name"] + req_url = ( + f"https://www.thesportsdb.com/api/v1/json/1/searchplayers.php?p={search_term}" + ) try: - resp = requests.get(req_url, timeout=.5) + resp = requests.get(req_url, timeout=0.5) except Exception as e: return None - if resp.status_code == 200 and resp.json()['player']: - if resp.json()['player'][0]['strSport'] == 'Baseball': - await db_patch('players', object_id=player['player_id'], - params=[('headshot', resp.json()['player'][0]['strThumb'])]) - return resp.json()['player'][0]['strThumb'] + if resp.status_code == 200 and resp.json()["player"]: + if resp.json()["player"][0]["strSport"] == "Baseball": + await db_patch( + "players", + object_id=player["player_id"], + params=[("headshot", resp.json()["player"][0]["strThumb"])], + ) + return resp.json()["player"][0]["strThumb"] return None async def get_player_headshot(player): - search_term = player['bbref_id'] if player['bbref_id'] else player['p_name'] - req_url = f'https://www.baseball-reference.com/search/search.fcgi?search={search_term}' + search_term = player["bbref_id"] if player["bbref_id"] else player["p_name"] + req_url = ( + f"https://www.baseball-reference.com/search/search.fcgi?search={search_term}" + ) try: resp = requests.get(req_url, timeout=2).text - soup = BeautifulSoup(resp, 'html.parser') - for item in soup.find_all('img'): - if 'headshot' in item['src']: - await db_patch('players', object_id=player['player_id'], params=[('headshot', item['src'])]) - return item['src'] + soup = BeautifulSoup(resp, "html.parser") + for item in soup.find_all("img"): + if "headshot" in item["src"]: + await db_patch( + "players", + object_id=player["player_id"], + params=[("headshot", item["src"])], + ) + return item["src"] except: pass return await get_player_photo(player) - - - - - - - - - - - - """ NEW FOR SEASON 4 """ - - async def get_team_by_owner(owner_id: int): - team = await db_get('teams', params=[('gm_id', owner_id)]) + team = await db_get("teams", params=[("gm_id", owner_id)]) - if not team['count']: + if not team["count"]: return None - return team['teams'][0] + # Prefer the non-gauntlet team (main team) if multiple teams exist + for t in team["teams"]: + if "gauntlet" not in t["abbrev"].lower(): + return t + + # Fallback to first team if all are gauntlet teams + return team["teams"][0] async def team_role(ctx, team: Team): - return await get_or_create_role(ctx, f'{team.abbrev} - {team.lname}') - - - - + return await get_or_create_role(ctx, f"{team.abbrev} - {team.lname}") def get_all_pos(player): all_pos = [] for x in range(1, 8): - if player[f'pos_{x}']: - all_pos.append(player[f'pos_{x}']) + if player[f"pos_{x}"]: + all_pos.append(player[f"pos_{x}"]) return all_pos - - async def share_channel(channel, user, read_only=False): await channel.set_permissions(user, read_messages=True, send_messages=not read_only) async def get_card_embeds(card, include_stats=False) -> list: embed = discord.Embed( - title=f'{card["player"]["p_name"]}', - color=int(card['player']['rarity']['color'], 16) + title=f"{card['player']['p_name']}", + color=int(card["player"]["rarity"]["color"], 16), ) # embed.description = card['team']['lname'] - embed.description = f'{card["player"]["cardset"]["name"]} / {card["player"]["mlbclub"]}' - embed.set_author(name=card['team']['lname'], url=IMAGES['logo'], icon_url=card['team']['logo']) - embed.set_footer(text=f'Paper Dynasty Season {card["team"]["season"]}', icon_url=IMAGES['logo']) + embed.description = ( + f"{card['player']['cardset']['name']} / {card['player']['mlbclub']}" + ) + embed.set_author( + name=card["team"]["lname"], url=IMAGES["logo"], icon_url=card["team"]["logo"] + ) + embed.set_footer( + text=f"Paper Dynasty Season {card['team']['season']}", icon_url=IMAGES["logo"] + ) if include_stats: b_query = await db_get( - 'plays/batting', params=[('player_id', card['player']['player_id']), ('season', PD_SEASON)]) + "plays/batting", + params=[("player_id", card["player"]["player_id"]), ("season", PD_SEASON)], + ) p_query = await db_get( - 'plays/pitching', params=[('player_id', card['player']['player_id']), ('season', PD_SEASON)]) + "plays/pitching", + params=[("player_id", card["player"]["player_id"]), ("season", PD_SEASON)], + ) - embed.add_field(name='Player ID', value=f'{card["player"]["player_id"]}') - embed.add_field(name='Rarity', value=f'{card["player"]["rarity"]["name"]}') - embed.add_field(name='Cost', value=f'{card["player"]["cost"]}₼') + embed.add_field(name="Player ID", value=f"{card['player']['player_id']}") + embed.add_field(name="Rarity", value=f"{card['player']['rarity']['name']}") + embed.add_field(name="Cost", value=f"{card['player']['cost']}₼") - pos_string = ", ".join(get_all_pos(card['player'])) - embed.add_field(name='Positions', value=pos_string) + pos_string = ", ".join(get_all_pos(card["player"])) + embed.add_field(name="Positions", value=pos_string) # all_dex = card['player']['paperdex'] - all_dex = await db_get('paperdex', params=[("player_id", card["player"]["player_id"]), ('flat', True)]) - count = all_dex['count'] - if card['team']['lname'] != 'Paper Dynasty': - bool_list = [True for elem in all_dex['paperdex'] if elem['team'] == card['team'].get('id', None)] + all_dex = await db_get( + "paperdex", params=[("player_id", card["player"]["player_id"]), ("flat", True)] + ) + count = all_dex["count"] + if card["team"]["lname"] != "Paper Dynasty": + bool_list = [ + True + for elem in all_dex["paperdex"] + if elem["team"] == card["team"].get("id", None) + ] if any(bool_list): if count == 1: - coll_string = f'Only you' + coll_string = f"Only you" else: - coll_string = f'You and {count - 1} other{"s" if count - 1 != 1 else ""}' + coll_string = ( + f"You and {count - 1} other{'s' if count - 1 != 1 else ''}" + ) elif count: - coll_string = f'{count} other team{"s" if count != 1 else ""}' + coll_string = f"{count} other team{'s' if count != 1 else ''}" else: - coll_string = f'0 teams' - embed.add_field(name='Collected By', value=coll_string) + coll_string = f"0 teams" + embed.add_field(name="Collected By", value=coll_string) else: - embed.add_field(name='Collected By', value=f'{count} team{"s" if count != 1 else ""}') + embed.add_field( + name="Collected By", value=f"{count} team{'s' if count != 1 else ''}" + ) # TODO: check for dupes with the included paperdex data # if card['team']['lname'] != 'Paper Dynasty': @@ -159,86 +184,104 @@ async def get_card_embeds(card, include_stats=False) -> list: # embed.add_field(name='# Dupes', value=f'{count - 1} dupe{"s" if count - 1 != 1 else ""}') # embed.add_field(name='Team', value=f'{card["player"]["mlbclub"]}') - if card['player']['franchise'] != 'Pokemon': - player_pages = f'[BBRef](https://www.baseball-reference.com/players/{card["player"]["bbref_id"][0]}/{card["player"]["bbref_id"]}.shtml)' + if card["player"]["franchise"] != "Pokemon": + player_pages = f"[BBRef](https://www.baseball-reference.com/players/{card['player']['bbref_id'][0]}/{card['player']['bbref_id']}.shtml)" else: - player_pages = f'[Pkmn]({PKMN_REF_URL}{card["player"]["bbref_id"]})' - embed.add_field(name='Player Page', value=f'{player_pages}') + player_pages = f"[Pkmn]({PKMN_REF_URL}{card['player']['bbref_id']})" + embed.add_field(name="Player Page", value=f"{player_pages}") embed.set_image(url=card["player"]["image"]) - headshot = card['player']['headshot'] if card['player']['headshot'] else await get_player_headshot(card['player']) + headshot = ( + card["player"]["headshot"] + if card["player"]["headshot"] + else await get_player_headshot(card["player"]) + ) if headshot: embed.set_thumbnail(url=headshot) else: - embed.set_thumbnail(url=IMAGES['logo']) - - if card['player']['franchise'] == 'Pokemon': - if card['player']['fangr_id'] is not None: + embed.set_thumbnail(url=IMAGES["logo"]) + + if card["player"]["franchise"] == "Pokemon": + if card["player"]["fangr_id"] is not None: try: - evo_mon = await db_get('players', object_id=card['player']['fangr_id'], none_okay=True) + evo_mon = await db_get( + "players", object_id=card["player"]["fangr_id"], none_okay=True + ) if evo_mon is not None: - embed.add_field( - name='Evolves Into', - value=f'{evo_mon["p_name"]}' - ) + embed.add_field(name="Evolves Into", value=f"{evo_mon['p_name']}") except Exception as e: - logging.error('could not pull evolution: {e}', exc_info=True, stack_info=True) - if '420420' not in card['player']['strat_code']: + logging.error( + "could not pull evolution: {e}", exc_info=True, stack_info=True + ) + if "420420" not in card["player"]["strat_code"]: try: - evo_mon = await db_get('players', object_id=card['player']['strat_code'], none_okay=True) + evo_mon = await db_get( + "players", object_id=card["player"]["strat_code"], none_okay=True + ) if evo_mon is not None: - embed.add_field( - name='Evolves From', - value=f'{evo_mon["p_name"]}' - ) + embed.add_field(name="Evolves From", value=f"{evo_mon['p_name']}") except Exception as e: - logging.error('could not pull evolution: {e}', exc_info=True, stack_info=True) + logging.error( + "could not pull evolution: {e}", exc_info=True, stack_info=True + ) if include_stats: - if b_query['count'] > 0: - b = b_query['stats'][0] + if b_query["count"] > 0: + b = b_query["stats"][0] - re24 = f'{b["re24"]:.2f}' - batting_string = f'```\n' \ - f' AVG OBP SLG\n' \ - f' {b["avg"]:.3f} {b["obp"]:.3f} {b["slg"]:.3f}\n``````\n' \ - f' OPS wOBA RE24\n' \ - f' {b["ops"]:.3f} {b["woba"]:.3f} {re24: ^5}\n``````\n' \ - f' PA H RBI 2B 3B HR SB\n' \ - f'{b["pa"]: >3} {b["hit"]: ^3} {b["rbi"]: ^3} {b["double"]: >2} {b["triple"]: >2} ' \ - f'{b["hr"]: >2} {b["sb"]: >2}```\n' - embed.add_field(name='Batting Stats', value=batting_string, inline=False) - if p_query['count'] > 0: - p = p_query['stats'][0] + re24 = f"{b['re24']:.2f}" + batting_string = ( + f"```\n" + f" AVG OBP SLG\n" + f" {b['avg']:.3f} {b['obp']:.3f} {b['slg']:.3f}\n``````\n" + f" OPS wOBA RE24\n" + f" {b['ops']:.3f} {b['woba']:.3f} {re24: ^5}\n``````\n" + f" PA H RBI 2B 3B HR SB\n" + f"{b['pa']: >3} {b['hit']: ^3} {b['rbi']: ^3} {b['double']: >2} {b['triple']: >2} " + f"{b['hr']: >2} {b['sb']: >2}```\n" + ) + embed.add_field(name="Batting Stats", value=batting_string, inline=False) + if p_query["count"] > 0: + p = p_query["stats"][0] - ip_whole = math.floor(p['outs'] / 3) - ip_denom = p['outs'] % 3 + ip_whole = math.floor(p["outs"] / 3) + ip_denom = p["outs"] % 3 ips = ip_whole + (ip_denom * 0.1) - kpbb = f'{p["k/bb"]:.1f}' - era = f'{p["era"]:.2f}' - whip = f'{p["whip"]:.2f}' - re24 = f'{p["re24"]:.2f}' + kpbb = f"{p['k/bb']:.1f}" + era = f"{p['era']:.2f}" + whip = f"{p['whip']:.2f}" + re24 = f"{p['re24']:.2f}" - pitching_string = f'```\n' \ - f' W-L SV ERA WHIP\n' \ - f'{p["win"]: >2}-{p["loss"]: <2} {p["save"]: >2} {era: >5} {whip: >4}\n``````\n' \ - f' IP SO K/BB RE24\n' \ - f'{ips: >5} {p["so"]: ^3} {kpbb: ^4} {re24: ^5}\n```' - embed.add_field(name='Pitching Stats', value=pitching_string, inline=False) + pitching_string = ( + f"```\n" + f" W-L SV ERA WHIP\n" + f"{p['win']: >2}-{p['loss']: <2} {p['save']: >2} {era: >5} {whip: >4}\n``````\n" + f" IP SO K/BB RE24\n" + f"{ips: >5} {p['so']: ^3} {kpbb: ^4} {re24: ^5}\n```" + ) + embed.add_field(name="Pitching Stats", value=pitching_string, inline=False) - if not card['player']['image2']: + if not card["player"]["image2"]: return [embed] - card_two = discord.Embed(color=int(card['player']['rarity']['color'], 16)) - card_two.set_footer(text=f'Paper Dynasty Season {card["team"]["season"]}', icon_url=IMAGES['logo']) - card_two.set_image(url=card['player']['image2']) + card_two = discord.Embed(color=int(card["player"]["rarity"]["color"], 16)) + card_two.set_footer( + text=f"Paper Dynasty Season {card['team']['season']}", icon_url=IMAGES["logo"] + ) + card_two.set_image(url=card["player"]["image2"]) return [embed, card_two] -def image_embed(image_url: str, title: str = None, color: str = None, desc: str = None, author_name: str = None, - author_icon: str = None): +def image_embed( + image_url: str, + title: str = None, + color: str = None, + desc: str = None, + author_name: str = None, + author_icon: str = None, +): embed_color = int(SBA_COLOR, 16) if color is not None: embed_color = int(color, 16) @@ -250,106 +293,128 @@ def image_embed(image_url: str, title: str = None, color: str = None, desc: str if desc is not None: embed.description = desc if author_name is not None: - icon = author_icon if author_icon is not None else IMAGES['logo'] + icon = author_icon if author_icon is not None else IMAGES["logo"] embed.set_author(name=author_name, icon_url=icon) - embed.set_footer(text=f'Paper Dynasty Season {PD_SEASON}', icon_url=IMAGES['logo']) + embed.set_footer(text=f"Paper Dynasty Season {PD_SEASON}", icon_url=IMAGES["logo"]) embed.set_image(url=image_url) return embed def is_shiny(card): - if card['player']['rarity']['value'] >= 5: + if card["player"]["rarity"]["value"] >= 5: return True return False async def display_cards( - cards: list, team: dict, channel, user, bot=None, pack_cover: str = None, cust_message: str = None, - add_roster: bool = True, pack_name: str = None) -> bool: - logger.info(f'display_cards called with {len(cards)} cards for team {team.get("abbrev", "Unknown")}') + cards: list, + team: dict, + channel, + user, + bot=None, + pack_cover: str = None, + cust_message: str = None, + add_roster: bool = True, + pack_name: str = None, +) -> bool: + logger.info( + f"display_cards called with {len(cards)} cards for team {team.get('abbrev', 'Unknown')}" + ) try: - cards.sort(key=lambda x: x['player']['rarity']['value']) - logger.debug(f'Cards sorted successfully') - + cards.sort(key=lambda x: x["player"]["rarity"]["value"]) + logger.debug(f"Cards sorted successfully") + card_embeds = [await get_card_embeds(x) for x in cards] - logger.debug(f'Created {len(card_embeds)} card embeds') - + logger.debug(f"Created {len(card_embeds)} card embeds") + page_num = 0 if pack_cover is None else -1 seen_shiny = False - logger.debug(f'Initial page_num: {page_num}, pack_cover: {pack_cover is not None}') + logger.debug( + f"Initial page_num: {page_num}, pack_cover: {pack_cover is not None}" + ) except Exception as e: - logger.error(f'Error in display_cards initialization: {e}', exc_info=True) + logger.error(f"Error in display_cards initialization: {e}", exc_info=True) return False try: view = Pagination([user], timeout=10) # Use simple text arrows instead of emojis to avoid context issues - l_emoji = '←' - r_emoji = '→' + l_emoji = "←" + r_emoji = "→" view.left_button.disabled = True - view.left_button.label = f'{l_emoji}Prev: -/{len(card_embeds)}' - view.cancel_button.label = f'Close Pack' - view.right_button.label = f'Next: {page_num + 2}/{len(card_embeds)}{r_emoji}' + view.left_button.label = f"{l_emoji}Prev: -/{len(card_embeds)}" + view.cancel_button.label = f"Close Pack" + view.right_button.label = f"Next: {page_num + 2}/{len(card_embeds)}{r_emoji}" if len(cards) == 1: view.right_button.disabled = True - - logger.debug(f'Pagination view created successfully') + + logger.debug(f"Pagination view created successfully") if pack_cover: - logger.debug(f'Sending pack cover message') + logger.debug(f"Sending pack cover message") msg = await channel.send( content=None, - embed=image_embed(pack_cover, title=f'{team["lname"]}', desc=pack_name), - view=view + embed=image_embed(pack_cover, title=f"{team['lname']}", desc=pack_name), + view=view, ) else: - logger.debug(f'Sending card embed message for page {page_num}') - msg = await channel.send(content=None, embeds=card_embeds[page_num], view=view) - - logger.debug(f'Initial message sent successfully') + logger.debug(f"Sending card embed message for page {page_num}") + msg = await channel.send( + content=None, embeds=card_embeds[page_num], view=view + ) + + logger.debug(f"Initial message sent successfully") except Exception as e: - logger.error(f'Error creating view or sending initial message: {e}', exc_info=True) + logger.error( + f"Error creating view or sending initial message: {e}", exc_info=True + ) return False try: if cust_message: - logger.debug(f'Sending custom message: {cust_message[:50]}...') + logger.debug(f"Sending custom message: {cust_message[:50]}...") follow_up = await channel.send(cust_message) else: - logger.debug(f'Sending default message for {len(cards)} cards') - follow_up = await channel.send(f'{user.mention} you\'ve got {len(cards)} cards here') - - logger.debug(f'Follow-up message sent successfully') + logger.debug(f"Sending default message for {len(cards)} cards") + follow_up = await channel.send( + f"{user.mention} you've got {len(cards)} cards here" + ) + + logger.debug(f"Follow-up message sent successfully") except Exception as e: - logger.error(f'Error sending follow-up message: {e}', exc_info=True) + logger.error(f"Error sending follow-up message: {e}", exc_info=True) return False - logger.debug(f'Starting main interaction loop') + logger.debug(f"Starting main interaction loop") while True: try: - logger.debug(f'Waiting for user interaction on page {page_num}') + logger.debug(f"Waiting for user interaction on page {page_num}") await view.wait() - logger.debug(f'User interaction received: {view.value}') + logger.debug(f"User interaction received: {view.value}") except Exception as e: - logger.error(f'Error in view.wait(): {e}', exc_info=True) + logger.error(f"Error in view.wait(): {e}", exc_info=True) await msg.edit(view=None) return False if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) if add_roster: - await follow_up.edit(content=f'Refresh your cards here: {get_roster_sheet(team)}') + await follow_up.edit( + content=f"Refresh your cards here: {get_roster_sheet(team)}" + ) return True - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 0 else 0 - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num < len(card_embeds) - 1 else 0 else: if page_num == len(card_embeds) - 1: await msg.edit(view=None) if add_roster: - await follow_up.edit(content=f'Refresh your cards here: {get_roster_sheet(team)}') + await follow_up.edit( + content=f"Refresh your cards here: {get_roster_sheet(team)}" + ) return True else: page_num += 1 @@ -358,68 +423,85 @@ async def display_cards( try: if is_shiny(cards[page_num]) and not seen_shiny: - logger.info(f'Shiny card detected on page {page_num}: {cards[page_num]["player"]["p_name"]}') + logger.info( + f"Shiny card detected on page {page_num}: {cards[page_num]['player']['p_name']}" + ) seen_shiny = True view = Pagination([user], timeout=300) view.cancel_button.style = discord.ButtonStyle.success - view.cancel_button.label = 'Flip!' - view.left_button.label = '-' - view.right_button.label = '-' + view.cancel_button.label = "Flip!" + view.left_button.label = "-" + view.right_button.label = "-" view.left_button.disabled = True view.right_button.disabled = True # Get MVP image safely with fallback franchise = cards[page_num]["player"]["franchise"] - logger.debug(f'Getting MVP image for franchise: {franchise}') - mvp_image = IMAGES['mvp'].get(franchise, IMAGES.get('mvp-hype', IMAGES['logo'])) - + logger.debug(f"Getting MVP image for franchise: {franchise}") + mvp_image = IMAGES["mvp"].get( + franchise, IMAGES.get("mvp-hype", IMAGES["logo"]) + ) + await msg.edit( embed=image_embed( mvp_image, - color='56f1fa', - author_name=team['lname'], - author_icon=team['logo'] + color="56f1fa", + author_name=team["lname"], + author_icon=team["logo"], ), - view=view) - logger.debug(f'MVP display updated successfully') + view=view, + ) + logger.debug(f"MVP display updated successfully") except Exception as e: - logger.error(f'Error processing shiny card on page {page_num}: {e}', exc_info=True) + logger.error( + f"Error processing shiny card on page {page_num}: {e}", exc_info=True + ) # Continue with regular flow instead of crashing try: - tmp_msg = await channel.send(content=f'<@&1163537676885033010> we\'ve got an MVP!') - await follow_up.edit(content=f'<@&1163537676885033010> we\'ve got an MVP!') + tmp_msg = await channel.send( + content=f"<@&1163537676885033010> we've got an MVP!" + ) + await follow_up.edit( + content=f"<@&1163537676885033010> we've got an MVP!" + ) await tmp_msg.delete() except discord.errors.NotFound: # Role might not exist or message was already deleted - await follow_up.edit(content=f'We\'ve got an MVP!') + await follow_up.edit(content=f"We've got an MVP!") except Exception as e: # Log error but don't crash the function - logger.error(f'Error handling MVP notification: {e}') - await follow_up.edit(content=f'We\'ve got an MVP!') + logger.error(f"Error handling MVP notification: {e}") + await follow_up.edit(content=f"We've got an MVP!") await view.wait() view = Pagination([user], timeout=10) try: - view.right_button.label = f'Next: {page_num + 2}/{len(card_embeds)}{r_emoji}' - view.cancel_button.label = f'Close Pack' - view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(card_embeds)}' + view.right_button.label = ( + f"Next: {page_num + 2}/{len(card_embeds)}{r_emoji}" + ) + view.cancel_button.label = f"Close Pack" + view.left_button.label = f"{l_emoji}Prev: {page_num}/{len(card_embeds)}" if page_num == 0: - view.left_button.label = f'{l_emoji}Prev: -/{len(card_embeds)}' + view.left_button.label = f"{l_emoji}Prev: -/{len(card_embeds)}" view.left_button.disabled = True elif page_num == len(card_embeds) - 1: view.timeout = 600.0 - view.right_button.label = f'Next: -/{len(card_embeds)}{r_emoji}' + view.right_button.label = f"Next: -/{len(card_embeds)}{r_emoji}" view.right_button.disabled = True - logger.debug(f'Updating message to show page {page_num}/{len(card_embeds)}') + logger.debug(f"Updating message to show page {page_num}/{len(card_embeds)}") if page_num >= len(card_embeds): - logger.error(f'Page number {page_num} exceeds card_embeds length {len(card_embeds)}') + logger.error( + f"Page number {page_num} exceeds card_embeds length {len(card_embeds)}" + ) page_num = len(card_embeds) - 1 - + await msg.edit(content=None, embeds=card_embeds[page_num], view=view) - logger.debug(f'Message updated successfully to page {page_num}') + logger.debug(f"Message updated successfully to page {page_num}") except Exception as e: - logger.error(f'Error updating message on page {page_num}: {e}', exc_info=True) + logger.error( + f"Error updating message on page {page_num}: {e}", exc_info=True + ) # Try to clean up and return try: await msg.edit(view=None) @@ -429,38 +511,45 @@ async def display_cards( async def embed_pagination( - all_embeds: list, channel, user: discord.Member, custom_message: str = None, - timeout: int = 10, start_page: int = 0): + all_embeds: list, + channel, + user: discord.Member, + custom_message: str = None, + timeout: int = 10, + start_page: int = 0, +): if start_page > len(all_embeds) - 1 or start_page < 0: page_num = 0 else: page_num = start_page view = Pagination([user], timeout=timeout) - l_emoji = '' - r_emoji = '' - view.right_button.label = f'Next: {page_num + 2}/{len(all_embeds)}{r_emoji}' - view.cancel_button.label = f'Cancel' - view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(all_embeds)}' + l_emoji = "" + r_emoji = "" + view.right_button.label = f"Next: {page_num + 2}/{len(all_embeds)}{r_emoji}" + view.cancel_button.label = f"Cancel" + view.left_button.label = f"{l_emoji}Prev: {page_num}/{len(all_embeds)}" if page_num == 0: - view.left_button.label = f'{l_emoji}Prev: -/{len(all_embeds)}' + view.left_button.label = f"{l_emoji}Prev: -/{len(all_embeds)}" view.left_button.disabled = True elif page_num == len(all_embeds) - 1: - view.right_button.label = f'Next: -/{len(all_embeds)}{r_emoji}' + view.right_button.label = f"Next: -/{len(all_embeds)}{r_emoji}" view.right_button.disabled = True - msg = await channel.send(content=custom_message, embed=all_embeds[page_num], view=view) + msg = await channel.send( + content=custom_message, embed=all_embeds[page_num], view=view + ) while True: await view.wait() if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) return True - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 0 else 0 - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num <= len(all_embeds) else len(all_embeds) else: if page_num == len(all_embeds) - 1: @@ -472,63 +561,83 @@ async def embed_pagination( view.value = None view = Pagination([user], timeout=timeout) - view.right_button.label = f'Next: {page_num + 2}/{len(all_embeds)}{r_emoji}' - view.cancel_button.label = f'Cancel' - view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(all_embeds)}' + view.right_button.label = f"Next: {page_num + 2}/{len(all_embeds)}{r_emoji}" + view.cancel_button.label = f"Cancel" + view.left_button.label = f"{l_emoji}Prev: {page_num}/{len(all_embeds)}" if page_num == 0: - view.left_button.label = f'{l_emoji}Prev: -/{len(all_embeds)}' + view.left_button.label = f"{l_emoji}Prev: -/{len(all_embeds)}" view.left_button.disabled = True elif page_num == len(all_embeds) - 1: view.timeout = 600.0 - view.right_button.label = f'Next: -/{len(all_embeds)}{r_emoji}' + view.right_button.label = f"Next: -/{len(all_embeds)}{r_emoji}" view.right_button.disabled = True await msg.edit(content=None, embed=all_embeds[page_num], view=view) - - - - - - - - async def get_test_pack(ctx, team): pull_notifs = [] - this_pack = await db_post('packs/one', payload={ - 'team_id': team['id'], 'pack_type_id': 1, - 'open_time': int(datetime.datetime.timestamp(datetime.datetime.now())*1000) - }) - ft_query = await db_get('players/random', params=[('max_rarity', 1), ('limit', 3)]) - four_query = await db_get('players/random', params=[('min_rarity', 1), ('max_rarity', 3), ('limit', 1)]) - five_query = await db_get('players/random', params=[('min_rarity', 5), ('max_rarity', 5), ('limit', 1)]) - first_three = ft_query['players'] - fourth = four_query['players'] - fifth = five_query['players'] + this_pack = await db_post( + "packs/one", + payload={ + "team_id": team["id"], + "pack_type_id": 1, + "open_time": int( + datetime.datetime.timestamp(datetime.datetime.now()) * 1000 + ), + }, + ) + ft_query = await db_get("players/random", params=[("max_rarity", 1), ("limit", 3)]) + four_query = await db_get( + "players/random", params=[("min_rarity", 1), ("max_rarity", 3), ("limit", 1)] + ) + five_query = await db_get( + "players/random", params=[("min_rarity", 5), ("max_rarity", 5), ("limit", 1)] + ) + first_three = ft_query["players"] + fourth = four_query["players"] + fifth = five_query["players"] all_cards = [*first_three, *fourth, *fifth] - success = await db_post('cards', timeout=10, payload={'cards': [{ - 'player_id': x['player_id'], 'team_id': team['id'], 'pack_id': this_pack['id']} for x in all_cards] - }) + success = await db_post( + "cards", + timeout=10, + payload={ + "cards": [ + { + "player_id": x["player_id"], + "team_id": team["id"], + "pack_id": this_pack["id"], + } + for x in all_cards + ] + }, + ) if not success: - await ctx.send(f'I was not able to create these cards {get_emoji(ctx, "slight_frown")}') + await ctx.send( + f"I was not able to create these cards {get_emoji(ctx, 'slight_frown')}" + ) return for x in all_cards: - if x['rarity']['value'] >= 3: + if x["rarity"]["value"] >= 3: pull_notifs.append(x) for pull in pull_notifs: - await db_post('notifs', payload={ - 'created': int(datetime.datetime.timestamp(datetime.datetime.now())*1000), - 'title': 'Rare Pull', - 'field_name': f'{player_desc(pull)} ({pull["rarity"]["name"]})', - 'message': f'Pulled by {team["abbrev"]}', - 'about': f'Player-{pull["player_id"]}' - }) + await db_post( + "notifs", + payload={ + "created": int( + datetime.datetime.timestamp(datetime.datetime.now()) * 1000 + ), + "title": "Rare Pull", + "field_name": f"{player_desc(pull)} ({pull['rarity']['name']})", + "message": f"Pulled by {team['abbrev']}", + "about": f"Player-{pull['player_id']}", + }, + ) - return [{'player': x, 'team': team} for x in all_cards] + return [{"player": x, "team": team} for x in all_cards] async def roll_for_cards(all_packs: list, extra_val=None) -> list: @@ -545,156 +654,140 @@ async def roll_for_cards(all_packs: list, extra_val=None) -> list: """ all_players = [] - team = all_packs[0]['team'] + team = all_packs[0]["team"] pack_ids = [] for pack in all_packs: counts = { - 'Rep': { - 'count': 0, - 'rarity': 0 - }, - 'Res': { - 'count': 0, - 'rarity': 1 - }, - 'Sta': { - 'count': 0, - 'rarity': 2 - }, - 'All': { - 'count': 0, - 'rarity': 3 - }, - 'MVP': { - 'count': 0, - 'rarity': 5 - }, - 'HoF': { - 'count': 0, - 'rarity': 8 - }, + "Rep": {"count": 0, "rarity": 0}, + "Res": {"count": 0, "rarity": 1}, + "Sta": {"count": 0, "rarity": 2}, + "All": {"count": 0, "rarity": 3}, + "MVP": {"count": 0, "rarity": 5}, + "HoF": {"count": 0, "rarity": 8}, } this_pack_players = [] - if pack['pack_type']['name'] == 'Standard': + if pack["pack_type"]["name"] == "Standard": # Cards 1 - 2 for x in range(2): d_1000 = random.randint(1, 1000) if d_1000 <= 450: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 900: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 else: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 # Card 3 d_1000 = random.randint(1, 1000) if d_1000 <= 350: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 700: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 950: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 else: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 # Card 4 d_1000 = random.randint(1, 1000) if d_1000 <= 310: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 620: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 940: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 5 d_1000 = random.randint(1, 1000) if d_1000 <= 215: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 430: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 930: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 980: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 <= 990: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 else: - counts['HoF']['count'] += 1 + counts["HoF"]["count"] += 1 - elif pack['pack_type']['name'] == 'Premium': + elif pack["pack_type"]["name"] == "Premium": # Card 1 d_1000 = random.randint(1, 1000) if d_1000 <= 400: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 870: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 970: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 2 d_1000 = random.randint(1, 1000) if d_1000 <= 300: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 770: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 970: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 3 d_1000 = random.randint(1, 1000) if d_1000 <= 200: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 elif d_1000 <= 640: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 940: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 990: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 else: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 # Card 4 d_1000 = random.randint(1, 1000) if d_1000 <= 100: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 if d_1000 <= 530: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 930: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 980: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 <= 990: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 else: - counts['HoF']['count'] += 1 + counts["HoF"]["count"] += 1 # Card 5 d_1000 = random.randint(1, 1000) if d_1000 <= 380: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 elif d_1000 <= 880: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 <= 980: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 <= 990: - counts['MVP']['count'] += 1 + counts["MVP"]["count"] += 1 else: - counts['HoF']['count'] += 1 + counts["HoF"]["count"] += 1 - elif pack['pack_type']['name'] == 'Check-In Player': - logger.info(f'Building Check-In Pack // extra_val (type): {extra_val} {type(extra_val)}') + elif pack["pack_type"]["name"] == "Check-In Player": + logger.info( + f"Building Check-In Pack // extra_val (type): {extra_val} {type(extra_val)}" + ) # Single Card mod = 0 if isinstance(extra_val, int): @@ -702,86 +795,115 @@ async def roll_for_cards(all_packs: list, extra_val=None) -> list: d_1000 = random.randint(1, 1000 + mod) if d_1000 >= 1100: - counts['All']['count'] += 1 + counts["All"]["count"] += 1 elif d_1000 >= 1000: - counts['Sta']['count'] += 1 + counts["Sta"]["count"] += 1 elif d_1000 >= 500: - counts['Res']['count'] += 1 + counts["Res"]["count"] += 1 else: - counts['Rep']['count'] += 1 + counts["Rep"]["count"] += 1 else: - raise TypeError(f'Pack type not recognized: {pack["pack_type"]["name"]}') + raise TypeError(f"Pack type not recognized: {pack['pack_type']['name']}") pull_notifs = [] for key in counts: mvp_flag = None - if counts[key]['count'] > 0: + if counts[key]["count"] > 0: params = [ - ('min_rarity', counts[key]['rarity']), ('max_rarity', counts[key]['rarity']), - ('limit', counts[key]['count']) + ("min_rarity", counts[key]["rarity"]), + ("max_rarity", counts[key]["rarity"]), + ("limit", counts[key]["count"]), ] - if all_packs[0]['pack_team'] is not None: - params.extend([('franchise', all_packs[0]['pack_team']['sname']), ('in_packs', True)]) - elif all_packs[0]['pack_cardset'] is not None: - params.append(('cardset_id', all_packs[0]['pack_cardset']['id'])) + if all_packs[0]["pack_team"] is not None: + params.extend( + [ + ("franchise", all_packs[0]["pack_team"]["sname"]), + ("in_packs", True), + ] + ) + elif all_packs[0]["pack_cardset"] is not None: + params.append(("cardset_id", all_packs[0]["pack_cardset"]["id"])) else: - params.append(('in_packs', True)) + params.append(("in_packs", True)) - pl = await db_get('players/random', params=params) + pl = await db_get("players/random", params=params) - if pl['count'] != counts[key]['count']: - mvp_flag = counts[key]['count'] - pl['count'] - logging.info(f'Set mvp flag to {mvp_flag} / cardset_id: {all_packs[0]["pack_cardset"]["id"]}') + if pl["count"] != counts[key]["count"]: + mvp_flag = counts[key]["count"] - pl["count"] + logging.info( + f"Set mvp flag to {mvp_flag} / cardset_id: {all_packs[0]['pack_cardset']['id']}" + ) - for x in pl['players']: + for x in pl["players"]: this_pack_players.append(x) all_players.append(x) - if x['rarity']['value'] >= 3: + if x["rarity"]["value"] >= 3: pull_notifs.append(x) - if mvp_flag and all_packs[0]['pack_cardset']['id'] not in [23]: - logging.info(f'Adding {mvp_flag} MVPs for missing cards') - pl = await db_get('players/random', params=[('min_rarity', 5), ('limit', mvp_flag)]) + if mvp_flag and all_packs[0]["pack_cardset"]["id"] not in [23]: + logging.info(f"Adding {mvp_flag} MVPs for missing cards") + pl = await db_get( + "players/random", params=[("min_rarity", 5), ("limit", mvp_flag)] + ) - for x in pl['players']: + for x in pl["players"]: this_pack_players.append(x) all_players.append(x) - + # Add dupes of Replacement/Reserve cards elif mvp_flag: - logging.info(f'Adding {mvp_flag} duplicate pokemon cards') + logging.info(f"Adding {mvp_flag} duplicate pokemon cards") for count in range(mvp_flag): - logging.info(f'Adding {pl["players"][0]["p_name"]} to the pack') + logging.info(f"Adding {pl['players'][0]['p_name']} to the pack") this_pack_players.append(x) - all_players.append(pl['players'][0]) + all_players.append(pl["players"][0]) success = await db_post( - 'cards', - payload={'cards': [{ - 'player_id': x['player_id'], 'team_id': pack['team']['id'], 'pack_id': pack['id']} for x in this_pack_players] + "cards", + payload={ + "cards": [ + { + "player_id": x["player_id"], + "team_id": pack["team"]["id"], + "pack_id": pack["id"], + } + for x in this_pack_players + ] }, - timeout=10 + timeout=10, ) if not success: - raise ConnectionError(f'Failed to create this pack of cards.') + raise ConnectionError(f"Failed to create this pack of cards.") - await db_patch('packs', object_id=pack['id'], params=[ - ('open_time', int(datetime.datetime.timestamp(datetime.datetime.now())*1000)) - ]) - pack_ids.append(pack['id']) + await db_patch( + "packs", + object_id=pack["id"], + params=[ + ( + "open_time", + int(datetime.datetime.timestamp(datetime.datetime.now()) * 1000), + ) + ], + ) + pack_ids.append(pack["id"]) for pull in pull_notifs: - logger.info(f'good pull: {pull}') - await db_post('notifs', payload={ - 'created': int(datetime.datetime.timestamp(datetime.datetime.now())*1000), - 'title': 'Rare Pull', - 'field_name': f'{player_desc(pull)} ({pull["rarity"]["name"]})', - 'message': f'Pulled by {team["abbrev"]}', - 'about': f'Player-{pull["player_id"]}' - }) + logger.info(f"good pull: {pull}") + await db_post( + "notifs", + payload={ + "created": int( + datetime.datetime.timestamp(datetime.datetime.now()) * 1000 + ), + "title": "Rare Pull", + "field_name": f"{player_desc(pull)} ({pull['rarity']['name']})", + "message": f"Pulled by {team['abbrev']}", + "about": f"Player-{pull['player_id']}", + }, + ) return pack_ids @@ -798,43 +920,48 @@ async def give_packs(team: dict, num_packs: int, pack_type: dict = None) -> dict ------- { 'count': int, 'packs': [ all team packs ] } """ - pt_id = pack_type['id'] if pack_type is not None else 1 + pt_id = pack_type["id"] if pack_type is not None else 1 await db_post( - 'packs', - payload={'packs': [{'team_id': team['id'], 'pack_type_id': pt_id} for x in range(num_packs)]} + "packs", + payload={ + "packs": [ + {"team_id": team["id"], "pack_type_id": pt_id} for x in range(num_packs) + ] + }, + ) + total_packs = await db_get( + "packs", params=[("team_id", team["id"]), ("opened", False)] ) - total_packs = await db_get('packs', params=[ - ('team_id', team['id']), ('opened', False) - ]) return total_packs def get_sheets(bot): try: - return bot.get_cog('Gameplay').sheets + return bot.get_cog("Gameplay").sheets except Exception as e: - logger.error(f'Could not grab sheets auth: {e}') - raise ConnectionError(f'Bot has not authenticated with discord; please try again in 1 minute.') + logger.error(f"Could not grab sheets auth: {e}") + raise ConnectionError( + f"Bot has not authenticated with discord; please try again in 1 minute." + ) def create_team_sheet(team, email: str, current, bot): sheets = get_sheets(bot) new_sheet = sheets.drive.copy_file( - f'{current["gsheet_template"]}', - f'{team["lname"]} Roster Sheet v{current["gsheet_version"]}', - '1539D0imTMjlUx2VF3NPMt7Sv85sb2XAJ' + f"{current['gsheet_template']}", + f"{team['lname']} Roster Sheet v{current['gsheet_version']}", + "1539D0imTMjlUx2VF3NPMt7Sv85sb2XAJ", ) - logger.info(f'new_sheet: {new_sheet}') + logger.info(f"new_sheet: {new_sheet}") - this_sheet = sheets.open_by_key(new_sheet['id']) - this_sheet.share(email, role='writer') - team_data = this_sheet.worksheet_by_title('Team Data') + this_sheet = sheets.open_by_key(new_sheet["id"]) + this_sheet.share(email, role="writer") + team_data = this_sheet.worksheet_by_title("Team Data") team_data.update_values( - crange='B1:B2', - values=[[f'{team["id"]}'], [f'\'{team_hash(team)}']] + crange="B1:B2", values=[[f"{team['id']}"], [f"'{team_hash(team)}"]] ) - logger.debug(f'this_sheet: {this_sheet}') + logger.debug(f"this_sheet: {this_sheet}") return this_sheet @@ -843,29 +970,29 @@ async def refresh_sheet(team, bot, sheets=None) -> None: if not sheets: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - my_cards = this_sheet.worksheet_by_title('My Cards') - all_cards = this_sheet.worksheet_by_title('All Cards') + this_sheet = sheets.open_by_key(team["gsheet"]) + my_cards = this_sheet.worksheet_by_title("My Cards") + all_cards = this_sheet.worksheet_by_title("All Cards") - my_cards.update_value('A2', 'FALSE') - all_cards.update_value('A2', 'FALSE') + my_cards.update_value("A2", "FALSE") + all_cards.update_value("A2", "FALSE") await asyncio.sleep(1) - my_cards.update_value('A2', 'TRUE') + my_cards.update_value("A2", "TRUE") await asyncio.sleep(0.5) - all_cards.update_value('A2', 'TRUE') + all_cards.update_value("A2", "TRUE") def delete_sheet(team, bot): sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) + this_sheet = sheets.open_by_key(team["gsheet"]) this_sheet.delete() def share_sheet(team, email, bot) -> None: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - this_sheet.share(email, role='writer') + this_sheet = sheets.open_by_key(team["gsheet"]) + this_sheet.share(email, role="writer") def int_timestamp(datetime_obj: datetime.datetime) -> int: @@ -873,30 +1000,30 @@ def int_timestamp(datetime_obj: datetime.datetime) -> int: def get_pos_abbrev(pos_name): - if pos_name == 'Catcher': - return 'C' - elif pos_name == 'First Base': - return '1B' - elif pos_name == 'Second Base': - return '2B' - elif pos_name == 'Third Base': - return '3B' - elif pos_name == 'Shortstop': - return 'SS' - elif pos_name == 'Left Field': - return 'LF' - elif pos_name == 'Center Field': - return 'CF' - elif pos_name == 'Right Field': - return 'RF' - elif pos_name == 'Pitcher': - return 'P' - elif pos_name == 'Designated Hitter': - return 'DH' - elif pos_name == 'Pinch Hitter': - return 'PH' + if pos_name == "Catcher": + return "C" + elif pos_name == "First Base": + return "1B" + elif pos_name == "Second Base": + return "2B" + elif pos_name == "Third Base": + return "3B" + elif pos_name == "Shortstop": + return "SS" + elif pos_name == "Left Field": + return "LF" + elif pos_name == "Center Field": + return "CF" + elif pos_name == "Right Field": + return "RF" + elif pos_name == "Pitcher": + return "P" + elif pos_name == "Designated Hitter": + return "DH" + elif pos_name == "Pinch Hitter": + return "PH" else: - raise KeyError(f'{pos_name} is not a recognized position name') + raise KeyError(f"{pos_name} is not a recognized position name") async def cardset_search(cardset: str, cardset_list: list) -> Optional[dict]: @@ -904,64 +1031,87 @@ async def cardset_search(cardset: str, cardset_list: list) -> Optional[dict]: if not cardset_name: return None - c_query = await db_get('cardsets', params=[('name', cardset_name)]) - if c_query['count'] == 0: + c_query = await db_get("cardsets", params=[("name", cardset_name)]) + if c_query["count"] == 0: return None - return c_query['cardsets'][0] + return c_query["cardsets"][0] def get_blank_team_card(player): - return {'player': player, 'team': {'lname': 'Paper Dynasty', 'logo': IMAGES['logo'], 'season': PD_SEASON, 'id': None}} + return { + "player": player, + "team": { + "lname": "Paper Dynasty", + "logo": IMAGES["logo"], + "season": PD_SEASON, + "id": None, + }, + } def get_rosters(team, bot, roster_num: Optional[int] = None) -> list: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - r_sheet = this_sheet.worksheet_by_title(f'My Rosters') - logger.debug(f'this_sheet: {this_sheet} / r_sheet = {r_sheet}') + this_sheet = sheets.open_by_key(team["gsheet"]) + r_sheet = this_sheet.worksheet_by_title(f"My Rosters") + logger.debug(f"this_sheet: {this_sheet} / r_sheet = {r_sheet}") all_rosters = [None, None, None] # Pull roster 1 if not roster_num or roster_num == 1: - roster_1 = r_sheet.range('B3:B28') - roster_name = r_sheet.cell('F30').value - logger.info(f'roster_1: {roster_1}') + roster_1 = r_sheet.range("B3:B28") + roster_name = r_sheet.cell("F30").value + logger.info(f"roster_1: {roster_1}") - if not roster_1[0][0].value == '': - all_rosters[0] = {'name': roster_name, 'roster_num': 1, 'team_id': team['id'], 'cards': None} - all_rosters[0]['cards'] = [int(x[0].value) for x in roster_1] + if not roster_1[0][0].value == "": + all_rosters[0] = { + "name": roster_name, + "roster_num": 1, + "team_id": team["id"], + "cards": None, + } + all_rosters[0]["cards"] = [int(x[0].value) for x in roster_1] # Pull roster 2 if not roster_num or roster_num == 2: - roster_2 = r_sheet.range('B29:B54') - roster_name = r_sheet.cell('F31').value - logger.info(f'roster_2: {roster_2}') + roster_2 = r_sheet.range("B29:B54") + roster_name = r_sheet.cell("F31").value + logger.info(f"roster_2: {roster_2}") - if not roster_2[0][0].value == '': - all_rosters[1] = {'name': roster_name, 'roster_num': 2, 'team_id': team['id'], 'cards': None} - all_rosters[1]['cards'] = [int(x[0].value) for x in roster_2] + if not roster_2[0][0].value == "": + all_rosters[1] = { + "name": roster_name, + "roster_num": 2, + "team_id": team["id"], + "cards": None, + } + all_rosters[1]["cards"] = [int(x[0].value) for x in roster_2] # Pull roster 3 if not roster_num or roster_num == 3: - roster_3 = r_sheet.range('B55:B80') - roster_name = r_sheet.cell('F32').value - logger.info(f'roster_3: {roster_3}') + roster_3 = r_sheet.range("B55:B80") + roster_name = r_sheet.cell("F32").value + logger.info(f"roster_3: {roster_3}") - if not roster_3[0][0].value == '': - all_rosters[2] = {'name': roster_name, 'roster_num': 3, 'team_id': team['id'], 'cards': None} - all_rosters[2]['cards'] = [int(x[0].value) for x in roster_3] + if not roster_3[0][0].value == "": + all_rosters[2] = { + "name": roster_name, + "roster_num": 3, + "team_id": team["id"], + "cards": None, + } + all_rosters[2]["cards"] = [int(x[0].value) for x in roster_3] return all_rosters def get_roster_lineups(team, bot, roster_num, lineup_num) -> list: sheets = get_sheets(bot) - logger.debug(f'sheets: {sheets}') - this_sheet = sheets.open_by_key(team['gsheet']) - logger.debug(f'this_sheet: {this_sheet}') - r_sheet = this_sheet.worksheet_by_title('My Rosters') - logger.debug(f'r_sheet: {r_sheet}') + logger.debug(f"sheets: {sheets}") + this_sheet = sheets.open_by_key(team["gsheet"]) + logger.debug(f"this_sheet: {this_sheet}") + r_sheet = this_sheet.worksheet_by_title("My Rosters") + logger.debug(f"r_sheet: {r_sheet}") if lineup_num == 1: row_start = 9 @@ -971,23 +1121,25 @@ def get_roster_lineups(team, bot, roster_num, lineup_num) -> list: row_end = 26 if roster_num == 1: - l_range = f'H{row_start}:I{row_end}' + l_range = f"H{row_start}:I{row_end}" elif roster_num == 2: - l_range = f'J{row_start}:K{row_end}' + l_range = f"J{row_start}:K{row_end}" else: - l_range = f'L{row_start}:M{row_end}' + l_range = f"L{row_start}:M{row_end}" - logger.debug(f'l_range: {l_range}') + logger.debug(f"l_range: {l_range}") raw_cells = r_sheet.range(l_range) - logger.debug(f'raw_cells: {raw_cells}') + logger.debug(f"raw_cells: {raw_cells}") try: lineup_cells = [(row[0].value, int(row[1].value)) for row in raw_cells] except ValueError as e: - logger.error(f'Could not pull roster for {team["abbrev"]} due to a ValueError') - raise ValueError(f'Uh oh. Looks like your roster might not be saved. I am reading blanks when I try to ' - f'get the card IDs') - logger.debug(f'lineup_cells: {lineup_cells}') + logger.error(f"Could not pull roster for {team['abbrev']} due to a ValueError") + raise ValueError( + f"Uh oh. Looks like your roster might not be saved. I am reading blanks when I try to " + f"get the card IDs" + ) + logger.debug(f"lineup_cells: {lineup_cells}") return lineup_cells @@ -995,20 +1147,22 @@ def get_roster_lineups(team, bot, roster_num, lineup_num) -> list: def post_ratings_guide(team, bot, this_sheet=None): if not this_sheet: sheets = get_sheets(bot) - this_sheet = sheets.open_by_key(team['gsheet']) - p_guide = this_sheet.worksheet_by_title('Full Guide - Pitchers') - b_guide = this_sheet.worksheet_by_title('Full Guide - Batters') + this_sheet = sheets.open_by_key(team["gsheet"]) + p_guide = this_sheet.worksheet_by_title("Full Guide - Pitchers") + b_guide = this_sheet.worksheet_by_title("Full Guide - Batters") - p_guide.update_value('A1', RATINGS_PITCHER_FORMULA) - b_guide.update_value('A1', RATINGS_BATTER_FORMULA) + p_guide.update_value("A1", RATINGS_PITCHER_FORMULA) + b_guide.update_value("A1", RATINGS_BATTER_FORMULA) async def legal_channel(ctx): - bad_channels = ['paper-dynasty-chat', 'pd-news-ticker', 'pd-network-news'] + bad_channels = ["paper-dynasty-chat", "pd-news-ticker", "pd-network-news"] if isinstance(ctx, commands.Context): if ctx.channel.name in bad_channels: - raise commands.CheckFailure(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)') + raise commands.CheckFailure( + f"Slide on down to the {get_channel(ctx, 'pd-bot-hole').mention} ;)" + ) else: return True @@ -1017,40 +1171,44 @@ async def legal_channel(ctx): # await ctx.send(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)') # logger.warning(f'{ctx.author.name} posted in illegal channel.') # return False - raise discord.app_commands.AppCommandError(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)') + raise discord.app_commands.AppCommandError( + f"Slide on down to the {get_channel(ctx, 'pd-bot-hole').mention} ;)" + ) else: return True def app_legal_channel(): """Check for slash commands (app_commands). Use as @app_legal_channel()""" + async def predicate(interaction: discord.Interaction) -> bool: - bad_channels = ['paper-dynasty-chat', 'pd-news-ticker', 'pd-network-news'] + bad_channels = ["paper-dynasty-chat", "pd-news-ticker", "pd-network-news"] if interaction.channel.name in bad_channels: raise discord.app_commands.CheckFailure( - f'Slide on down to the {get_channel(interaction, "pd-bot-hole").mention} ;)' + f"Slide on down to the {get_channel(interaction, 'pd-bot-hole').mention} ;)" ) return True + return discord.app_commands.check(predicate) def is_ephemeral_channel(channel) -> bool: """Check if channel requires ephemeral responses (chat channels).""" - if not channel or not hasattr(channel, 'name'): + if not channel or not hasattr(channel, "name"): return False - return channel.name in ['paper-dynasty-chat', 'pd-news-ticker'] + return channel.name in ["paper-dynasty-chat", "pd-news-ticker"] def is_restricted_channel(channel) -> bool: """Check if channel is restricted for certain commands (chat/ticker channels).""" - if not channel or not hasattr(channel, 'name'): + if not channel or not hasattr(channel, "name"): return False - return channel.name in ['paper-dynasty-chat', 'pd-news-ticker'] + return channel.name in ["paper-dynasty-chat", "pd-news-ticker"] def can_send_message(channel) -> bool: """Check if channel supports sending messages.""" - return channel and hasattr(channel, 'send') + return channel and hasattr(channel, "send") async def send_safe_message( @@ -1060,20 +1218,20 @@ async def send_safe_message( embeds: List[discord.Embed] = None, view: discord.ui.View = None, ephemeral: bool = False, - delete_after: float = None + delete_after: float = None, ) -> discord.Message: """ Safely send a message using the most appropriate method based on context. - + For Interactions: 1. Try edit_original_response() if deferred 2. Try followup.send() if response is done 3. Try channel.send() if channel supports it - + For Context: - 1. Try ctx.send() + 1. Try ctx.send() 2. Try DM to user with context info if channel send fails - + Args: source: Discord Interaction or Context object content: Message content @@ -1081,110 +1239,126 @@ async def send_safe_message( view: UI view to attach ephemeral: Whether message should be ephemeral (Interaction only) delete_after: Seconds after which to delete message - + Returns: The sent message object - + Raises: Exception: If all send methods fail """ - logger = logging.getLogger('discord_app') - + logger = logging.getLogger("discord_app") + # Prepare message kwargs kwargs = {} if content is not None: - kwargs['content'] = content + kwargs["content"] = content if embeds is not None: - kwargs['embeds'] = embeds + kwargs["embeds"] = embeds if view is not None: - kwargs['view'] = view + kwargs["view"] = view if delete_after is not None: - kwargs['delete_after'] = delete_after - + kwargs["delete_after"] = delete_after + # Handle Interaction objects if isinstance(source, discord.Interaction): # Add ephemeral parameter for interactions if ephemeral: - kwargs['ephemeral'] = ephemeral - + kwargs["ephemeral"] = ephemeral + # Strategy 1: Try edit_original_response if already deferred if source.response.is_done(): try: # For edit_original_response, we need to handle embeds differently edit_kwargs = kwargs.copy() - if 'embeds' in edit_kwargs: + if "embeds" in edit_kwargs: # edit_original_response expects 'embeds' parameter pass # Already correct - if 'ephemeral' in edit_kwargs: + if "ephemeral" in edit_kwargs: # Can't change ephemeral status on edit - del edit_kwargs['ephemeral'] - + del edit_kwargs["ephemeral"] + await source.edit_original_response(**edit_kwargs) # edit_original_response doesn't return a message object in the same way # We'll use followup as backup to get a returnable message - if 'delete_after' not in kwargs: # Don't create extra messages if auto-deleting - return await source.followup.send("Message sent", ephemeral=True, delete_after=0.1) + if ( + "delete_after" not in kwargs + ): # Don't create extra messages if auto-deleting + return await source.followup.send( + "Message sent", ephemeral=True, delete_after=0.1 + ) return None # Can't return meaningful message object from edit except Exception as e: logger.debug(f"Failed to edit original response: {e}") - + # Strategy 2: Try followup.send() try: return await source.followup.send(**kwargs) except Exception as e: logger.debug(f"Failed to send followup message: {e}") - + # Strategy 3: Try channel.send() if possible if can_send_message(source.channel): try: # Remove ephemeral for channel send (not supported) channel_kwargs = kwargs.copy() - if 'ephemeral' in channel_kwargs: - del channel_kwargs['ephemeral'] + if "ephemeral" in channel_kwargs: + del channel_kwargs["ephemeral"] return await source.channel.send(**channel_kwargs) except Exception as e: logger.debug(f"Failed to send channel message: {e}") - + # All interaction methods failed - logger.error(f"All interaction message send methods failed for user {source.user.id}") - raise RuntimeError("Unable to send interaction message through any available method") - - # Handle Context objects + logger.error( + f"All interaction message send methods failed for user {source.user.id}" + ) + raise RuntimeError( + "Unable to send interaction message through any available method" + ) + + # Handle Context objects elif isinstance(source, commands.Context): # Strategy 1: Try ctx.send() directly try: # Remove ephemeral (not supported in Context) ctx_kwargs = kwargs.copy() - if 'ephemeral' in ctx_kwargs: - del ctx_kwargs['ephemeral'] + if "ephemeral" in ctx_kwargs: + del ctx_kwargs["ephemeral"] return await source.send(**ctx_kwargs) except Exception as e: logger.debug(f"Failed to send context message to channel: {e}") - + # Strategy 2: Try DM to user with context info try: # Prepare DM with context information - channel_name = getattr(source.channel, 'name', 'Unknown Channel') - guild_name = getattr(source.guild, 'name', 'Unknown Server') if source.guild else 'DM' - + channel_name = getattr(source.channel, "name", "Unknown Channel") + guild_name = ( + getattr(source.guild, "name", "Unknown Server") + if source.guild + else "DM" + ) + dm_content = f"[Bot Response from #{channel_name} in {guild_name}]\n\n" if content: dm_content += content - + # Send DM with modified content dm_kwargs = kwargs.copy() - dm_kwargs['content'] = dm_content - if 'ephemeral' in dm_kwargs: - del dm_kwargs['ephemeral'] - + dm_kwargs["content"] = dm_content + if "ephemeral" in dm_kwargs: + del dm_kwargs["ephemeral"] + return await source.author.send(**dm_kwargs) except Exception as dm_error: - logger.error(f"Failed to send DM fallback to user {source.author.id}: {dm_error}") + logger.error( + f"Failed to send DM fallback to user {source.author.id}: {dm_error}" + ) # Both ctx.send() and DM failed - let the exception bubble up raise dm_error - + else: - raise TypeError(f"Source must be discord.Interaction or commands.Context, got {type(source)}") + raise TypeError( + f"Source must be discord.Interaction or commands.Context, got {type(source)}" + ) def get_role(ctx, role_name): @@ -1192,35 +1366,35 @@ def get_role(ctx, role_name): async def team_summary_embed(team, ctx, include_roster: bool = True): - embed = get_team_embed(f'{team["lname"]} Overview', team) + embed = get_team_embed(f"{team['lname']} Overview", team) - embed.add_field(name='General Manager', value=team['gmname'], inline=False) - embed.add_field(name='Wallet', value=f'{team["wallet"]}₼') + embed.add_field(name="General Manager", value=team["gmname"], inline=False) + embed.add_field(name="Wallet", value=f"{team['wallet']}₼") # embed.add_field(name='Collection Value', value=team['collection_value']) - p_query = await db_get('packs', params=[('team_id', team['id']), ('opened', False)]) - if p_query['count'] > 0: + p_query = await db_get("packs", params=[("team_id", team["id"]), ("opened", False)]) + if p_query["count"] > 0: all_packs = {} - for x in p_query['packs']: - if x['pack_type']['name'] not in all_packs: - all_packs[x['pack_type']['name']] = 1 + for x in p_query["packs"]: + if x["pack_type"]["name"] not in all_packs: + all_packs[x["pack_type"]["name"]] = 1 else: - all_packs[x['pack_type']['name']] += 1 + all_packs[x["pack_type"]["name"]] += 1 - pack_string = '' + pack_string = "" for pack_type in all_packs: - pack_string += f'{pack_type.title()}: {all_packs[pack_type]}\n' + pack_string += f"{pack_type.title()}: {all_packs[pack_type]}\n" else: - pack_string = 'None' - embed.add_field(name='Unopened Packs', value=pack_string) - embed.add_field(name='Team Rating', value=f'{team["ranking"]}') + pack_string = "None" + embed.add_field(name="Unopened Packs", value=pack_string) + embed.add_field(name="Team Rating", value=f"{team['ranking']}") - r_query = await db_get(f'results/team/{team["id"]}?season={PD_SEASON}') + r_query = await db_get(f"results/team/{team['id']}?season={PD_SEASON}") if r_query: embed.add_field( - name='Record', - value=f'Ranked: {r_query["ranked_wins"]}-{r_query["ranked_losses"]}\n' - f'Unlimited: {r_query["casual_wins"]}-{r_query["casual_losses"]}' + name="Record", + value=f"Ranked: {r_query['ranked_wins']}-{r_query['ranked_losses']}\n" + f"Unlimited: {r_query['casual_wins']}-{r_query['casual_losses']}", ) # try: @@ -1251,325 +1425,335 @@ async def team_summary_embed(team, ctx, include_roster: bool = True): # ) if include_roster: - embed.add_field(name='Team Sheet', value=get_roster_sheet(team), inline=False) + embed.add_field(name="Team Sheet", value=get_roster_sheet(team), inline=False) embed.add_field( - name='For Help', - value=f'`/help-pd` has FAQs; feel free to post questions in ' - f'{get_channel(ctx, "paper-dynasty-chat").mention}.', - inline=False + name="For Help", + value=f"`/help-pd` has FAQs; feel free to post questions in " + f"{get_channel(ctx, 'paper-dynasty-chat').mention}.", + inline=False, ) return embed -async def give_cards_to_team(team, players: list = None, player_ids: list = None, pack_id=None): +async def give_cards_to_team( + team, players: list = None, player_ids: list = None, pack_id=None +): if not pack_id: p_query = await db_post( - 'packs/one', + "packs/one", payload={ - 'team_id': team['id'], - 'pack_type_id': 4, - 'open_time': datetime.datetime.timestamp(datetime.datetime.now()) * 1000} + "team_id": team["id"], + "pack_type_id": 4, + "open_time": datetime.datetime.timestamp(datetime.datetime.now()) + * 1000, + }, ) - pack_id = p_query['id'] + pack_id = p_query["id"] if not players and not player_ids: - raise ValueError('One of players or player_ids must be provided to distribute cards') + raise ValueError( + "One of players or player_ids must be provided to distribute cards" + ) if players: - await db_post('cards', payload={'cards': [ - {'player_id': x['player_id'], 'team_id': team['id'], 'pack_id': pack_id} for x in players - ]}, timeout=10) + await db_post( + "cards", + payload={ + "cards": [ + { + "player_id": x["player_id"], + "team_id": team["id"], + "pack_id": pack_id, + } + for x in players + ] + }, + timeout=10, + ) elif player_ids: - await db_post('cards', payload={'cards': [ - {'player_id': x, 'team_id': team['id'], 'pack_id': pack_id} for x in player_ids - ]}, timeout=10) + await db_post( + "cards", + payload={ + "cards": [ + {"player_id": x, "team_id": team["id"], "pack_id": pack_id} + for x in player_ids + ] + }, + timeout=10, + ) def get_ratings_guide(sheets): this_sheet = sheets.open_by_key(RATINGS_SHEET_KEY) - b_sheet = this_sheet.worksheet_by_title('ratings_Batters') - p_sheet = this_sheet.worksheet_by_title('ratings_Pitchers') + b_sheet = this_sheet.worksheet_by_title("ratings_Batters") + p_sheet = this_sheet.worksheet_by_title("ratings_Pitchers") - b_data = b_sheet.range('A2:N') - p_data = p_sheet.range('A2:N') + b_data = b_sheet.range("A2:N") + p_data = p_sheet.range("A2:N") try: batters = [ { - 'player_id': int(x[0].value), - 'p_name': x[1].value, - 'rating': int(x[2].value), - 'contact-r': int(x[3].value), - 'contact-l': int(x[4].value), - 'power-r': int(x[5].value), - 'power-l': int(x[6].value), - 'vision': int(x[7].value), - 'speed': int(x[8].value), - 'stealing': int(x[9].value), - 'reaction': int(x[10].value), - 'arm': int(x[11].value), - 'fielding': int(x[12].value), - 'hand': int(x[13].value), - } for x in b_data + "player_id": int(x[0].value), + "p_name": x[1].value, + "rating": int(x[2].value), + "contact-r": int(x[3].value), + "contact-l": int(x[4].value), + "power-r": int(x[5].value), + "power-l": int(x[6].value), + "vision": int(x[7].value), + "speed": int(x[8].value), + "stealing": int(x[9].value), + "reaction": int(x[10].value), + "arm": int(x[11].value), + "fielding": int(x[12].value), + "hand": int(x[13].value), + } + for x in b_data ] pitchers = [ { - 'player_id': int(x[0].value), - 'p_name': x[1].value, - 'rating': int(x[2].value), - 'control-r': int(x[3].value), - 'control-l': int(x[4].value), - 'stuff-r': int(x[5].value), - 'stuff-l': int(x[6].value), - 'stamina': int(x[7].value), - 'fielding': int(x[8].value), - 'hit-9': int(x[9].value), - 'k-9': int(x[10].value), - 'bb-9': int(x[11].value), - 'hr-9': int(x[12].value), - 'hand': int(x[13].value), - } for x in p_data + "player_id": int(x[0].value), + "p_name": x[1].value, + "rating": int(x[2].value), + "control-r": int(x[3].value), + "control-l": int(x[4].value), + "stuff-r": int(x[5].value), + "stuff-l": int(x[6].value), + "stamina": int(x[7].value), + "fielding": int(x[8].value), + "hit-9": int(x[9].value), + "k-9": int(x[10].value), + "bb-9": int(x[11].value), + "hr-9": int(x[12].value), + "hand": int(x[13].value), + } + for x in p_data ] except Exception as e: - return {'valid': False} + return {"valid": False} - return { - 'valid': True, - 'batter_ratings': batters, - 'pitcher_ratings': pitchers - } + return {"valid": True, "batter_ratings": batters, "pitcher_ratings": pitchers} async def paperdex_cardset_embed(team: dict, this_cardset: dict) -> list[discord.Embed]: all_dex = await db_get( - 'paperdex', - params=[('team_id', team['id']), ('cardset_id', this_cardset['id']), ('flat', True)] + "paperdex", + params=[ + ("team_id", team["id"]), + ("cardset_id", this_cardset["id"]), + ("flat", True), + ], ) - dex_player_list = [x['player'] for x in all_dex['paperdex']] + dex_player_list = [x["player"] for x in all_dex["paperdex"]] - hof_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - mvp_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - as_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - sta_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - res_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - rep_embed = get_team_embed(f'{team["lname"]} Collection', team=team) + hof_embed = get_team_embed(f"{team['lname']} Collection", team=team) + mvp_embed = get_team_embed(f"{team['lname']} Collection", team=team) + as_embed = get_team_embed(f"{team['lname']} Collection", team=team) + sta_embed = get_team_embed(f"{team['lname']} Collection", team=team) + res_embed = get_team_embed(f"{team['lname']} Collection", team=team) + rep_embed = get_team_embed(f"{team['lname']} Collection", team=team) coll_data = { - 99: { - 'name': 'Hall of Fame', - 'owned': 0, - 'players': [], - 'embeds': [hof_embed] - }, - 1: { - 'name': 'MVP', - 'owned': 0, - 'players': [], - 'embeds': [mvp_embed] - }, - 2: { - 'name': 'All-Star', - 'owned': 0, - 'players': [], - 'embeds': [as_embed] - }, - 3: { - 'name': 'Starter', - 'owned': 0, - 'players': [], - 'embeds': [sta_embed] - }, - 4: { - 'name': 'Reserve', - 'owned': 0, - 'players': [], - 'embeds': [res_embed] - }, - 5: { - 'name': 'Replacement', - 'owned': 0, - 'players': [], - 'embeds': [rep_embed] - }, - 'total_owned': 0 + 99: {"name": "Hall of Fame", "owned": 0, "players": [], "embeds": [hof_embed]}, + 1: {"name": "MVP", "owned": 0, "players": [], "embeds": [mvp_embed]}, + 2: {"name": "All-Star", "owned": 0, "players": [], "embeds": [as_embed]}, + 3: {"name": "Starter", "owned": 0, "players": [], "embeds": [sta_embed]}, + 4: {"name": "Reserve", "owned": 0, "players": [], "embeds": [res_embed]}, + 5: {"name": "Replacement", "owned": 0, "players": [], "embeds": [rep_embed]}, + "total_owned": 0, } set_players = await db_get( - 'players', - params=[('cardset_id', this_cardset['id']), ('flat', True), ('inc_dex', False)], - timeout=5 + "players", + params=[("cardset_id", this_cardset["id"]), ("flat", True), ("inc_dex", False)], + timeout=5, ) - for player in set_players['players']: - if player['player_id'] in dex_player_list: - coll_data[player['rarity']]['owned'] += 1 - coll_data['total_owned'] += 1 - player['owned'] = True + for player in set_players["players"]: + if player["player_id"] in dex_player_list: + coll_data[player["rarity"]]["owned"] += 1 + coll_data["total_owned"] += 1 + player["owned"] = True else: - player['owned'] = False + player["owned"] = False - logger.debug(f'player: {player} / type: {type(player)}') - coll_data[player['rarity']]['players'].append(player) + logger.debug(f"player: {player} / type: {type(player)}") + coll_data[player["rarity"]]["players"].append(player) - cover_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - cover_embed.description = this_cardset['name'] - cover_embed.add_field(name='# Total Cards', value=f'{set_players["count"]}') - cover_embed.add_field(name='# Collected', value=f'{coll_data["total_owned"]}') + cover_embed = get_team_embed(f"{team['lname']} Collection", team=team) + cover_embed.description = this_cardset["name"] + cover_embed.add_field(name="# Total Cards", value=f"{set_players['count']}") + cover_embed.add_field(name="# Collected", value=f"{coll_data['total_owned']}") display_embeds = [cover_embed] for rarity_id in coll_data: - if rarity_id != 'total_owned': - if coll_data[rarity_id]['players']: - coll_data[rarity_id]['embeds'][0].description = f'Rarity: {coll_data[rarity_id]["name"]}' - coll_data[rarity_id]['embeds'][0].add_field( - name='# Collected / # Total Cards', - value=f'{coll_data[rarity_id]["owned"]} / {len(coll_data[rarity_id]["players"])}', - inline=False + if rarity_id != "total_owned": + if coll_data[rarity_id]["players"]: + coll_data[rarity_id]["embeds"][ + 0 + ].description = f"Rarity: {coll_data[rarity_id]['name']}" + coll_data[rarity_id]["embeds"][0].add_field( + name="# Collected / # Total Cards", + value=f"{coll_data[rarity_id]['owned']} / {len(coll_data[rarity_id]['players'])}", + inline=False, ) - chunk_string = '' - for index, this_player in enumerate(coll_data[rarity_id]['players']): - logger.debug(f'this_player: {this_player}') - chunk_string += '☑ ' if this_player['owned'] else '⬜ ' - chunk_string += f'{this_player["p_name"]}\n' + chunk_string = "" + for index, this_player in enumerate(coll_data[rarity_id]["players"]): + logger.debug(f"this_player: {this_player}") + chunk_string += "☑ " if this_player["owned"] else "⬜ " + chunk_string += f"{this_player['p_name']}\n" if (index + 1) == len(coll_data[rarity_id]["players"]): - coll_data[rarity_id]['embeds'][0].add_field( - name=f'Group {math.ceil((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[rarity_id]["players"]) / 20)}', - value=chunk_string + coll_data[rarity_id]["embeds"][0].add_field( + name=f"Group {math.ceil((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[rarity_id]['players']) / 20)}", + value=chunk_string, ) elif (index + 1) % 20 == 0: - coll_data[rarity_id]['embeds'][0].add_field( - name=f'Group {math.floor((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[rarity_id]["players"]) / 20)}', - value=chunk_string + coll_data[rarity_id]["embeds"][0].add_field( + name=f"Group {math.floor((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[rarity_id]['players']) / 20)}", + value=chunk_string, ) - chunk_string = '' + chunk_string = "" - display_embeds.append(coll_data[rarity_id]['embeds'][0]) + display_embeds.append(coll_data[rarity_id]["embeds"][0]) return display_embeds async def paperdex_team_embed(team: dict, mlb_team: dict) -> list[discord.Embed]: all_dex = await db_get( - 'paperdex', - params=[('team_id', team['id']), ('franchise', mlb_team['sname']), ('flat', True)] + "paperdex", + params=[ + ("team_id", team["id"]), + ("franchise", mlb_team["sname"]), + ("flat", True), + ], ) - dex_player_list = [x['player'] for x in all_dex['paperdex']] + dex_player_list = [x["player"] for x in all_dex["paperdex"]] - c_query = await db_get('cardsets') - coll_data = {'total_owned': 0} + c_query = await db_get("cardsets") + coll_data = {"total_owned": 0} total_players = 0 - for x in c_query['cardsets']: + for x in c_query["cardsets"]: set_players = await db_get( - 'players', - params=[('cardset_id', x['id']), ('franchise', mlb_team['sname']), ('flat', True), ('inc_dex', False)] + "players", + params=[ + ("cardset_id", x["id"]), + ("franchise", mlb_team["sname"]), + ("flat", True), + ("inc_dex", False), + ], ) if set_players is not None: - coll_data[x['id']] = { - 'name': x['name'], - 'owned': 0, - 'players': [], - 'embeds': [get_team_embed(f'{team["lname"]} Collection', team=team)] + coll_data[x["id"]] = { + "name": x["name"], + "owned": 0, + "players": [], + "embeds": [get_team_embed(f"{team['lname']} Collection", team=team)], } - total_players += set_players['count'] + total_players += set_players["count"] - for player in set_players['players']: - if player['player_id'] in dex_player_list: - coll_data[x['id']]['owned'] += 1 - coll_data['total_owned'] += 1 - player['owned'] = True + for player in set_players["players"]: + if player["player_id"] in dex_player_list: + coll_data[x["id"]]["owned"] += 1 + coll_data["total_owned"] += 1 + player["owned"] = True else: - player['owned'] = False + player["owned"] = False - logger.debug(f'player: {player} / type: {type(player)}') - coll_data[x['id']]['players'].append(player) + logger.debug(f"player: {player} / type: {type(player)}") + coll_data[x["id"]]["players"].append(player) - cover_embed = get_team_embed(f'{team["lname"]} Collection', team=team) - cover_embed.description = mlb_team['lname'] - cover_embed.add_field(name='# Total Cards', value=f'{total_players}') - cover_embed.add_field(name='# Collected', value=f'{coll_data["total_owned"]}') + cover_embed = get_team_embed(f"{team['lname']} Collection", team=team) + cover_embed.description = mlb_team["lname"] + cover_embed.add_field(name="# Total Cards", value=f"{total_players}") + cover_embed.add_field(name="# Collected", value=f"{coll_data['total_owned']}") display_embeds = [cover_embed] for cardset_id in coll_data: - if cardset_id != 'total_owned': - if coll_data[cardset_id]['players']: - coll_data[cardset_id]['embeds'][0].description = f'{mlb_team["lname"]} / ' \ - f'{coll_data[cardset_id]["name"]}' - coll_data[cardset_id]['embeds'][0].add_field( - name='# Collected / # Total Cards', - value=f'{coll_data[cardset_id]["owned"]} / {len(coll_data[cardset_id]["players"])}', - inline=False + if cardset_id != "total_owned": + if coll_data[cardset_id]["players"]: + coll_data[cardset_id]["embeds"][0].description = ( + f"{mlb_team['lname']} / {coll_data[cardset_id]['name']}" + ) + coll_data[cardset_id]["embeds"][0].add_field( + name="# Collected / # Total Cards", + value=f"{coll_data[cardset_id]['owned']} / {len(coll_data[cardset_id]['players'])}", + inline=False, ) - chunk_string = '' - for index, this_player in enumerate(coll_data[cardset_id]['players']): - logger.debug(f'this_player: {this_player}') - chunk_string += '☑ ' if this_player['owned'] else '⬜ ' - chunk_string += f'{this_player["p_name"]}\n' + chunk_string = "" + for index, this_player in enumerate(coll_data[cardset_id]["players"]): + logger.debug(f"this_player: {this_player}") + chunk_string += "☑ " if this_player["owned"] else "⬜ " + chunk_string += f"{this_player['p_name']}\n" if (index + 1) == len(coll_data[cardset_id]["players"]): - coll_data[cardset_id]['embeds'][0].add_field( - name=f'Group {math.ceil((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[cardset_id]["players"]) / 20)}', - value=chunk_string + coll_data[cardset_id]["embeds"][0].add_field( + name=f"Group {math.ceil((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[cardset_id]['players']) / 20)}", + value=chunk_string, ) elif (index + 1) % 20 == 0: - coll_data[cardset_id]['embeds'][0].add_field( - name=f'Group {math.floor((index + 1) / 20)} / ' - f'{math.ceil(len(coll_data[cardset_id]["players"]) / 20)}', - value=chunk_string + coll_data[cardset_id]["embeds"][0].add_field( + name=f"Group {math.floor((index + 1) / 20)} / " + f"{math.ceil(len(coll_data[cardset_id]['players']) / 20)}", + value=chunk_string, ) - chunk_string = '' + chunk_string = "" - display_embeds.append(coll_data[cardset_id]['embeds'][0]) + display_embeds.append(coll_data[cardset_id]["embeds"][0]) return display_embeds def get_pack_cover(pack): - if pack['pack_cardset'] is not None and pack['pack_cardset'] == 23: - return IMAGES['pack-pkmnbs'] - elif pack['pack_type']['name'] in ['Premium', 'MVP']: - return IMAGES['pack-pre'] - elif pack['pack_type']['name'] == 'Standard': - return IMAGES['pack-sta'] - elif pack['pack_type']['name'] == 'Mario': - return IMAGES['pack-mar'] + if pack["pack_cardset"] is not None and pack["pack_cardset"] == 23: + return IMAGES["pack-pkmnbs"] + elif pack["pack_type"]["name"] in ["Premium", "MVP"]: + return IMAGES["pack-pre"] + elif pack["pack_type"]["name"] == "Standard": + return IMAGES["pack-sta"] + elif pack["pack_type"]["name"] == "Mario": + return IMAGES["pack-mar"] else: return None async def open_st_pr_packs(all_packs: list, team: dict, context): - pack_channel = get_channel(context, 'pack-openings') + pack_channel = get_channel(context, "pack-openings") pack_cover = get_pack_cover(all_packs[0]) if pack_cover is None: pack_channel = context.channel if not pack_channel: - raise ValueError(f'I cannot find the pack-openings channel. {get_cal_user(context).mention} - halp?') + raise ValueError( + f"I cannot find the pack-openings channel. {get_cal_user(context).mention} - halp?" + ) pack_ids = await roll_for_cards(all_packs) if not pack_ids: - logger.error(f'open_packs - unable to roll_for_cards for packs: {all_packs}') - raise ValueError(f'I was not able to unpack these cards') + logger.error(f"open_packs - unable to roll_for_cards for packs: {all_packs}") + raise ValueError(f"I was not able to unpack these cards") all_cards = [] for p_id in pack_ids: - new_cards = await db_get('cards', params=[('pack_id', p_id)]) - all_cards.extend(new_cards['cards']) + new_cards = await db_get("cards", params=[("pack_id", p_id)]) + all_cards.extend(new_cards["cards"]) if not all_cards: - logger.error(f'open_packs - unable to get cards for packs: {pack_ids}') - raise ValueError(f'I was not able to display these cards') + logger.error(f"open_packs - unable to get cards for packs: {pack_ids}") + raise ValueError(f"I was not able to display these cards") # Present cards to opening channel if type(context) == commands.Context: @@ -1577,53 +1761,68 @@ async def open_st_pr_packs(all_packs: list, team: dict, context): else: author = context.user - await context.channel.send(content=f'Let\'s head down to {pack_channel.mention}!') + await context.channel.send(content=f"Let's head down to {pack_channel.mention}!") await display_cards(all_cards, team, pack_channel, author, pack_cover=pack_cover) async def get_choice_from_cards( - interaction: discord.Interaction, all_players: list = None, cover_title: str = None, - cover_desc: str = None, cover_image_url: str = None, callback=None, temp_message: str = None, - conf_message: str = None, delete_message: bool = False): + interaction: discord.Interaction, + all_players: list = None, + cover_title: str = None, + cover_desc: str = None, + cover_image_url: str = None, + callback=None, + temp_message: str = None, + conf_message: str = None, + delete_message: bool = False, +): # Display them with pagination, prev/next/select card_embeds = [ await get_card_embeds( - {'player': x, 'team': {'lname': 'Paper Dynasty', 'season': PD_SEASON, 'logo': IMAGES['logo']}} - ) for x in all_players + { + "player": x, + "team": { + "lname": "Paper Dynasty", + "season": PD_SEASON, + "logo": IMAGES["logo"], + }, + } + ) + for x in all_players ] - logger.debug(f'card embeds: {card_embeds}') + logger.debug(f"card embeds: {card_embeds}") if cover_title is not None and cover_image_url is not None: page_num = 0 view = Pagination([interaction.user], timeout=30) view.left_button.disabled = True - view.left_button.label = f'Prev: -/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: -/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success view.cancel_button.disabled = True - view.right_button.label = f'Next: 1/{len(card_embeds)}' + view.right_button.label = f"Next: 1/{len(card_embeds)}" msg = await interaction.channel.send( content=None, embed=image_embed( - image_url=cover_image_url, - title=cover_title, - desc=cover_desc + image_url=cover_image_url, title=cover_title, desc=cover_desc ), - view=view + view=view, ) else: page_num = 1 view = Pagination([interaction.user], timeout=30) - view.left_button.label = f'Prev: -/{len(card_embeds)}' + view.left_button.label = f"Prev: -/{len(card_embeds)}" view.left_button.disabled = True - view.cancel_button.label = f'Take This Card' + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success - view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}' + view.right_button.label = f"Next: {page_num + 1}/{len(card_embeds)}" - msg = await interaction.channel.send(content=None, embeds=card_embeds[page_num - 1], view=view) + msg = await interaction.channel.send( + content=None, embeds=card_embeds[page_num - 1], view=view + ) if temp_message is not None: temp_msg = await interaction.channel.send(content=temp_message) @@ -1634,7 +1833,7 @@ async def get_choice_from_cards( await view.wait() if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) if callback is not None: @@ -1646,9 +1845,9 @@ async def get_choice_from_cards( else: await interaction.channel.send(content=conf_message) break - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 1 else len(card_embeds) - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num < len(card_embeds) else 1 else: if page_num == len(card_embeds): @@ -1659,15 +1858,15 @@ async def get_choice_from_cards( view.value = None view = Pagination([interaction.user], timeout=30) - view.left_button.label = f'Prev: {page_num - 1}/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: {page_num - 1}/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success - view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}' + view.right_button.label = f"Next: {page_num + 1}/{len(card_embeds)}" if page_num == 1: - view.left_button.label = f'Prev: -/{len(card_embeds)}' + view.left_button.label = f"Prev: -/{len(card_embeds)}" view.left_button.disabled = True elif page_num == len(card_embeds): - view.right_button.label = f'Next: -/{len(card_embeds)}' + view.right_button.label = f"Next: -/{len(card_embeds)}" view.right_button.disabled = True await msg.edit(content=None, embeds=card_embeds[page_num - 1], view=view) @@ -1677,14 +1876,16 @@ async def get_choice_from_cards( return all_players[page_num - 1] -async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[int] = None): - pack_channel = get_channel(context, 'pack-openings') +async def open_choice_pack( + this_pack, team: dict, context, cardset_id: Optional[int] = None +): + pack_channel = get_channel(context, "pack-openings") pack_cover = get_pack_cover(this_pack) - pack_type = this_pack['pack_type']['name'] + pack_type = this_pack["pack_type"]["name"] players = [] - if pack_type == 'Mario': + if pack_type == "Mario": d1000 = random.randint(1, 1000) if d1000 > 800: rarity_id = 5 @@ -1693,21 +1894,24 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ else: rarity_id = 2 pl = await db_get( - 'players/random', + "players/random", params=[ - ('cardset_id', 8), ('min_rarity', rarity_id), ('max_rarity', rarity_id), ('limit', 4) - ] + ("cardset_id", 8), + ("min_rarity", rarity_id), + ("max_rarity", rarity_id), + ("limit", 4), + ], ) - players = pl['players'] - elif pack_type == 'Team Choice': - if this_pack['pack_team'] is None: - raise KeyError(f'Team not listed for Team Choice pack') + players = pl["players"] + elif pack_type == "Team Choice": + if this_pack["pack_team"] is None: + raise KeyError(f"Team not listed for Team Choice pack") d1000 = random.randint(1, 1000) - pack_cover = this_pack['pack_team']['logo'] + pack_cover = this_pack["pack_team"]["logo"] if d1000 > 800: rarity_id = 5 - pack_cover = IMAGES['mvp'][this_pack['pack_team']['lname']] + pack_cover = IMAGES["mvp"][this_pack["pack_team"]["lname"]] elif d1000 > 550: rarity_id = 3 else: @@ -1720,44 +1924,47 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ min_rarity = rarity_id while len(players) < 4 and rarity_id < 10: params = [ - ('min_rarity', min_rarity), ('max_rarity', rarity_id), ('limit', 4 - len(players)), - ('franchise', this_pack['pack_team']['sname']) + ("min_rarity", min_rarity), + ("max_rarity", rarity_id), + ("limit", 4 - len(players)), + ("franchise", this_pack["pack_team"]["sname"]), ] # Only apply in_packs filter if no specific cardset is provided - if this_pack['pack_team']['abbrev'] not in ['MSS'] and cardset_id is None: - params.append(('in_packs', True)) + if this_pack["pack_team"]["abbrev"] not in ["MSS"] and cardset_id is None: + params.append(("in_packs", True)) if cardset_id is not None: - params.append(('cardset_id', cardset_id)) - pl = await db_get( - 'players/random', - params=params - ) - if pl['count'] >= 0: - for x in pl['players']: + params.append(("cardset_id", cardset_id)) + pl = await db_get("players/random", params=params) + if pl["count"] >= 0: + for x in pl["players"]: if x not in players: players.append(x) if len(players) < 4: min_rarity += 1 rarity_id += 1 - elif pack_type == 'Promo Choice': - if this_pack['pack_cardset'] is None: - raise KeyError(f'Cardset not listed for Promo Choice pack') + elif pack_type == "Promo Choice": + if this_pack["pack_cardset"] is None: + raise KeyError(f"Cardset not listed for Promo Choice pack") d1000 = random.randint(1, 1000) - pack_cover = IMAGES['mvp-hype'] - cardset_id = this_pack['pack_cardset']['id'] + pack_cover = IMAGES["mvp-hype"] + cardset_id = this_pack["pack_cardset"]["id"] rarity_id = 5 if d1000 > 800: rarity_id = 8 while len(players) < 4 and rarity_id < 10: pl = await db_get( - 'players/random', - params=[('cardset_id', cardset_id), ('min_rarity', rarity_id), ('max_rarity', rarity_id), - ('limit', 8)] + "players/random", + params=[ + ("cardset_id", cardset_id), + ("min_rarity", rarity_id), + ("max_rarity", rarity_id), + ("limit", 8), + ], ) - if pl['count'] >= 0: - for x in pl['players']: + if pl["count"] >= 0: + for x in pl["players"]: if len(players) >= 4: break if x not in players: @@ -1767,95 +1974,116 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ else: # Get 4 MVP cards rarity_id = 5 - if pack_type == 'HoF': + if pack_type == "HoF": rarity_id = 8 - elif pack_type == 'All Star': + elif pack_type == "All Star": rarity_id = 3 min_rarity = rarity_id while len(players) < 4 and rarity_id < 10: params = [ - ('min_rarity', min_rarity), ('max_rarity', rarity_id), ('limit', 4) + ("min_rarity", min_rarity), + ("max_rarity", rarity_id), + ("limit", 4), ] # Only apply in_packs filter if no specific cardset is provided if cardset_id is None: - params.append(('in_packs', True)) - if this_pack['pack_team'] is not None: - params.append(('franchise', this_pack['pack_team']['sname'])) + params.append(("in_packs", True)) + if this_pack["pack_team"] is not None: + params.append(("franchise", this_pack["pack_team"]["sname"])) if cardset_id is not None: - params.append(('cardset_id', cardset_id)) - pl = await db_get('players/random', params=params) + params.append(("cardset_id", cardset_id)) + pl = await db_get("players/random", params=params) - if pl['count'] > 0: - players.extend(pl['players']) + if pl["count"] > 0: + players.extend(pl["players"]) if len(players) < 4: rarity_id += 3 if len(players) == 0: - logger.error(f'Could not create choice pack') - raise ConnectionError(f'Could not create choice pack') + logger.error(f"Could not create choice pack") + raise ConnectionError(f"Could not create choice pack") if type(context) == commands.Context: author = context.author else: author = context.user - logger.info(f'helpers - open_choice_pack - players: {players}') + logger.info(f"helpers - open_choice_pack - players: {players}") # Display them with pagination, prev/next/select card_embeds = [ await get_card_embeds( # {'player': x, 'team': {'lname': 'Paper Dynasty', 'season': PD_SEASON, 'logo': IMAGES['logo']}} - {'player': x, 'team': team} # Show team and dupe info - ) for x in players + {"player": x, "team": team} # Show team and dupe info + ) + for x in players ] - logger.debug(f'card embeds: {card_embeds}') + logger.debug(f"card embeds: {card_embeds}") page_num = 0 view = Pagination([author], timeout=30) view.left_button.disabled = True - view.left_button.label = f'Prev: -/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: -/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success view.cancel_button.disabled = True - view.right_button.label = f'Next: 1/{len(card_embeds)}' + view.right_button.label = f"Next: 1/{len(card_embeds)}" # React to selection - await context.channel.send(f'Let\'s head down to {pack_channel.mention}!') + await context.channel.send(f"Let's head down to {pack_channel.mention}!") msg = await pack_channel.send( content=None, - embed=image_embed(pack_cover, title=f'{team["lname"]}', desc=f'{pack_type} Pack - Choose 1 of 4 {pack_type}s!'), - view=view + embed=image_embed( + pack_cover, + title=f"{team['lname']}", + desc=f"{pack_type} Pack - Choose 1 of 4 {pack_type}s!", + ), + view=view, ) if rarity_id >= 5: - tmp_msg = await pack_channel.send(content=f'<@&1163537676885033010> we\'ve got an MVP!') + tmp_msg = await pack_channel.send( + content=f"<@&1163537676885033010> we've got an MVP!" + ) else: - tmp_msg = await pack_channel.send(content=f'We\'ve got a choice pack here!') + tmp_msg = await pack_channel.send(content=f"We've got a choice pack here!") while True: await view.wait() if view.value: - if view.value == 'cancel': + if view.value == "cancel": await msg.edit(view=None) try: - await give_cards_to_team(team, players=[players[page_num - 1]], pack_id=this_pack['id']) + await give_cards_to_team( + team, players=[players[page_num - 1]], pack_id=this_pack["id"] + ) except Exception as e: - logger.error(f'failed to create cards: {e}') - raise ConnectionError(f'Failed to distribute these cards.') + logger.error(f"failed to create cards: {e}") + raise ConnectionError(f"Failed to distribute these cards.") - await db_patch('packs', object_id=this_pack['id'], params=[ - ('open_time', int(datetime.datetime.timestamp(datetime.datetime.now()) * 1000)) - ]) + await db_patch( + "packs", + object_id=this_pack["id"], + params=[ + ( + "open_time", + int( + datetime.datetime.timestamp(datetime.datetime.now()) + * 1000 + ), + ) + ], + ) await tmp_msg.edit( - content=f'{players[page_num - 1]["p_name"]} has been added to the ' - f'**{team["sname"]}** binder!' + content=f"{players[page_num - 1]['p_name']} has been added to the " + f"**{team['sname']}** binder!" ) break - if view.value == 'left': + if view.value == "left": page_num -= 1 if page_num > 1 else len(card_embeds) - if view.value == 'right': + if view.value == "right": page_num += 1 if page_num < len(card_embeds) else 1 else: if page_num == len(card_embeds): @@ -1866,70 +2094,62 @@ async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[ view.value = None view = Pagination([author], timeout=30) - view.left_button.label = f'Prev: {page_num - 1}/{len(card_embeds)}' - view.cancel_button.label = f'Take This Card' + view.left_button.label = f"Prev: {page_num - 1}/{len(card_embeds)}" + view.cancel_button.label = f"Take This Card" view.cancel_button.style = discord.ButtonStyle.success - view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}' + view.right_button.label = f"Next: {page_num + 1}/{len(card_embeds)}" if page_num == 1: - view.left_button.label = f'Prev: -/{len(card_embeds)}' + view.left_button.label = f"Prev: -/{len(card_embeds)}" view.left_button.disabled = True elif page_num == len(card_embeds): - view.right_button.label = f'Next: -/{len(card_embeds)}' + view.right_button.label = f"Next: -/{len(card_embeds)}" view.right_button.disabled = True await msg.edit(content=None, embeds=card_embeds[page_num - 1], view=view) -async def confirm_pack_purchase(interaction, owner_team, num_packs, total_cost, pack_embed): +async def confirm_pack_purchase( + interaction, owner_team, num_packs, total_cost, pack_embed +): view = Confirm(responders=[interaction.user], timeout=30) - await interaction.channel.send( - content=None, - embed=pack_embed - ) + await interaction.channel.send(content=None, embed=pack_embed) question = await interaction.channel.send( - content=f'Your Wallet: {owner_team["wallet"]}₼\n' - f'Pack{"s" if num_packs > 1 else ""} Price: {total_cost}₼\n' - f'After Purchase: {owner_team["wallet"] - total_cost}₼\n\n' - f'Would you like to make this purchase?', - view=view + content=f"Your Wallet: {owner_team['wallet']}₼\n" + f"Pack{'s' if num_packs > 1 else ''} Price: {total_cost}₼\n" + f"After Purchase: {owner_team['wallet'] - total_cost}₼\n\n" + f"Would you like to make this purchase?", + view=view, ) await view.wait() if not view.value: - await question.edit( - content='Saving that money. Smart.', - view=None - ) + await question.edit(content="Saving that money. Smart.", view=None) return None else: return question def player_desc(this_player) -> str: - if this_player['p_name'] in this_player['description']: - return this_player['description'] - return f'{this_player["description"]} {this_player["p_name"]}' + if this_player["p_name"] in this_player["description"]: + return this_player["description"] + return f"{this_player['description']} {this_player['p_name']}" def player_pcard(this_player): - if this_player['image'] is not None and 'pitching' in this_player['image']: - return this_player['image'] - elif this_player['image2'] is not None and 'pitching' in this_player['image2']: - return this_player['image2'] + if this_player["image"] is not None and "pitching" in this_player["image"]: + return this_player["image"] + elif this_player["image2"] is not None and "pitching" in this_player["image2"]: + return this_player["image2"] else: - return this_player['image'] + return this_player["image"] def player_bcard(this_player): - if this_player['image'] is not None and 'batting' in this_player['image']: - return this_player['image'] - elif this_player['image2'] is not None and 'batting' in this_player['image2']: - return this_player['image2'] + if this_player["image"] is not None and "batting" in this_player["image"]: + return this_player["image"] + elif this_player["image2"] is not None and "batting" in this_player["image2"]: + return this_player["image2"] # elif this_player['image'] is not None and 'pitching' in this_player['image']: # return PITCHER_BATTING_CARD else: - return this_player['image'] - - - - + return this_player["image"] diff --git a/tests/test_api_calls.py b/tests/test_api_calls.py index 9a44a68..a9fca56 100644 --- a/tests/test_api_calls.py +++ b/tests/test_api_calls.py @@ -1,102 +1,102 @@ +import asyncio import pytest import aiohttp -from unittest.mock import Mock, patch, AsyncMock -from exceptions import DatabaseError +from unittest.mock import Mock, patch, AsyncMock, MagicMock +from exceptions import DatabaseError, APITimeoutError import api_calls class TestUtilityFunctions: """Test utility functions in api_calls.""" - + def test_param_char_with_params(self): """Test param_char returns & when other_params is truthy.""" - assert api_calls.param_char(True) == '&' - assert api_calls.param_char(['param1']) == '&' - assert api_calls.param_char({'key': 'value'}) == '&' - assert api_calls.param_char('some_param') == '&' - + assert api_calls.param_char(True) == "&" + assert api_calls.param_char(["param1"]) == "&" + assert api_calls.param_char({"key": "value"}) == "&" + assert api_calls.param_char("some_param") == "&" + def test_param_char_without_params(self): """Test param_char returns ? when other_params is falsy.""" - assert api_calls.param_char(False) == '?' - assert api_calls.param_char(None) == '?' - assert api_calls.param_char([]) == '?' - assert api_calls.param_char({}) == '?' - assert api_calls.param_char('') == '?' - assert api_calls.param_char(0) == '?' - - @patch('api_calls.DB_URL', 'https://test.example.com/api') + assert api_calls.param_char(False) == "?" + assert api_calls.param_char(None) == "?" + assert api_calls.param_char([]) == "?" + assert api_calls.param_char({}) == "?" + assert api_calls.param_char("") == "?" + assert api_calls.param_char(0) == "?" + + @patch("api_calls.DB_URL", "https://test.example.com/api") def test_get_req_url_basic(self): """Test basic URL generation without object_id or params.""" - result = api_calls.get_req_url('teams') - expected = 'https://test.example.com/api/v2/teams' + result = api_calls.get_req_url("teams") + expected = "https://test.example.com/api/v2/teams" assert result == expected - - @patch('api_calls.DB_URL', 'https://test.example.com/api') + + @patch("api_calls.DB_URL", "https://test.example.com/api") def test_get_req_url_with_version(self): """Test URL generation with custom API version.""" - result = api_calls.get_req_url('teams', api_ver=1) - expected = 'https://test.example.com/api/v1/teams' + result = api_calls.get_req_url("teams", api_ver=1) + expected = "https://test.example.com/api/v1/teams" assert result == expected - - @patch('api_calls.DB_URL', 'https://test.example.com/api') + + @patch("api_calls.DB_URL", "https://test.example.com/api") def test_get_req_url_with_object_id(self): """Test URL generation with object_id.""" - result = api_calls.get_req_url('teams', object_id=123) - expected = 'https://test.example.com/api/v2/teams/123' + result = api_calls.get_req_url("teams", object_id=123) + expected = "https://test.example.com/api/v2/teams/123" assert result == expected - - @patch('api_calls.DB_URL', 'https://test.example.com/api') + + @patch("api_calls.DB_URL", "https://test.example.com/api") def test_get_req_url_with_params(self): """Test URL generation with parameters.""" - params = [('season', '7'), ('active', 'true')] - result = api_calls.get_req_url('teams', params=params) - expected = 'https://test.example.com/api/v2/teams?season=7&active=true' + params = [("season", "7"), ("active", "true")] + result = api_calls.get_req_url("teams", params=params) + expected = "https://test.example.com/api/v2/teams?season=7&active=true" assert result == expected - - @patch('api_calls.DB_URL', 'https://test.example.com/api') + + @patch("api_calls.DB_URL", "https://test.example.com/api") def test_get_req_url_complete(self): """Test URL generation with all parameters.""" - params = [('season', '7'), ('limit', '10')] - result = api_calls.get_req_url('games', api_ver=1, object_id=456, params=params) - expected = 'https://test.example.com/api/v1/games/456?season=7&limit=10' + params = [("season", "7"), ("limit", "10")] + result = api_calls.get_req_url("games", api_ver=1, object_id=456, params=params) + expected = "https://test.example.com/api/v1/games/456?season=7&limit=10" assert result == expected - - @patch('api_calls.logger') + + @patch("api_calls.logger") def test_log_return_value_short_string(self, mock_logger): """Test logging short return values.""" - api_calls.log_return_value('Short log message') - mock_logger.info.assert_called_once_with('\n\nreturn: Short log message') - - @patch('api_calls.logger') + api_calls.log_return_value("Short log message") + mock_logger.info.assert_called_once_with("\n\nreturn: Short log message") + + @patch("api_calls.logger") def test_log_return_value_long_string(self, mock_logger): """Test logging long return values that get chunked.""" - long_string = 'A' * 5000 # 5000 character string + long_string = "A" * 5000 # 5000 character string api_calls.log_return_value(long_string) - + # Should have been called twice (first chunk + second chunk) assert mock_logger.info.call_count == 2 # First call should include the "return:" prefix - assert '\n\nreturn: ' in mock_logger.info.call_args_list[0][0][0] - - @patch('api_calls.logger') + assert "\n\nreturn: " in mock_logger.info.call_args_list[0][0][0] + + @patch("api_calls.logger") def test_log_return_value_extremely_long_string(self, mock_logger): """Test logging extremely long return values that get snipped.""" - extremely_long_string = 'B' * 400000 # 400k character string (exceeds 300k limit) + extremely_long_string = ( + "B" * 400000 + ) # 400k character string (exceeds 300k limit) api_calls.log_return_value(extremely_long_string) - + # Should warn about snipping - mock_logger.warning.assert_called_with('[ S N I P P E D ]') - + mock_logger.warning.assert_called_with("[ S N I P P E D ]") + def test_team_hash(self): """Test team hash generation.""" - mock_team = { - 'sname': 'TestTeam', - 'gmid': 1234567 - } - + mock_team = {"sname": "TestTeam", "gmid": 1234567} + result = api_calls.team_hash(mock_team) # Expected format: last char + gmid/6950123 + second-to-last char + gmid/42069123 - expected = f'm{1234567 / 6950123:.0f}a{1234567 / 42069123:.0f}' + expected = f"m{1234567 / 6950123:.0f}a{1234567 / 42069123:.0f}" assert result == expected @@ -106,59 +106,116 @@ class TestUtilityFunctions: class TestSpecificFunctions: """Test specific API wrapper functions.""" - + @pytest.mark.asyncio - @patch('api_calls.db_get') + @patch("api_calls.db_get") async def test_get_team_by_abbrev_found(self, mock_db_get): """Test get_team_by_abbrev function when team is found.""" mock_db_get.return_value = { - 'count': 1, - 'teams': [{'id': 123, 'abbrev': 'TEST', 'name': 'Test Team'}] + "count": 1, + "teams": [{"id": 123, "abbrev": "TEST", "name": "Test Team"}], } - - result = await api_calls.get_team_by_abbrev('TEST') - - assert result == {'id': 123, 'abbrev': 'TEST', 'name': 'Test Team'} - mock_db_get.assert_called_once_with('teams', params=[('abbrev', 'TEST')]) - + + result = await api_calls.get_team_by_abbrev("TEST") + + assert result == {"id": 123, "abbrev": "TEST", "name": "Test Team"} + mock_db_get.assert_called_once_with("teams", params=[("abbrev", "TEST")]) + @pytest.mark.asyncio - @patch('api_calls.db_get') + @patch("api_calls.db_get") async def test_get_team_by_abbrev_not_found(self, mock_db_get): """Test get_team_by_abbrev function when team is not found.""" - mock_db_get.return_value = { - 'count': 0, - 'teams': [] - } - - result = await api_calls.get_team_by_abbrev('NONEXISTENT') - + mock_db_get.return_value = {"count": 0, "teams": []} + + result = await api_calls.get_team_by_abbrev("NONEXISTENT") + assert result is None - mock_db_get.assert_called_once_with('teams', params=[('abbrev', 'NONEXISTENT')]) - + mock_db_get.assert_called_once_with("teams", params=[("abbrev", "NONEXISTENT")]) + @pytest.mark.asyncio - @patch('api_calls.db_post') + @patch("api_calls.db_post") async def test_post_to_dex(self, mock_db_post): """Test post_to_dex function.""" - mock_db_post.return_value = {'id': 456, 'posted': True} - - mock_player = {'id': 123} - mock_team = {'id': 456} - + mock_db_post.return_value = {"id": 456, "posted": True} + + mock_player = {"id": 123} + mock_team = {"id": 456} + result = await api_calls.post_to_dex(mock_player, mock_team) - - assert result == {'id': 456, 'posted': True} - mock_db_post.assert_called_once_with('paperdex', payload={'player_id': 123, 'team_id': 456}) + + assert result == {"id": 456, "posted": True} + mock_db_post.assert_called_once_with( + "paperdex", payload={"player_id": 123, "team_id": 456} + ) class TestEnvironmentConfiguration: """Test environment-based configuration.""" - + def test_db_url_exists(self): """Test that DB_URL is configured.""" assert api_calls.DB_URL is not None - assert 'manticorum.com' in api_calls.DB_URL - + assert "manticorum.com" in api_calls.DB_URL + def test_auth_token_exists(self): """Test that AUTH_TOKEN is configured.""" assert api_calls.AUTH_TOKEN is not None - assert 'Authorization' in api_calls.AUTH_TOKEN \ No newline at end of file + assert "Authorization" in api_calls.AUTH_TOKEN + + +class TestTimeoutAndRetry: + """Test timeout and retry logic for API calls. + + These tests verify that: + 1. Default timeout values are correctly set + 2. db_get has retry parameter, mutation methods do not + 3. APITimeoutError exception exists and is a subclass of DatabaseError + """ + + def test_default_timeout_values(self): + """Test that default timeout values are set correctly. + + Default should be 5 seconds for all functions. + db_get should have retries parameter, mutation methods should not. + """ + import inspect + + # Check db_get signature - should have both timeout and retries + sig = inspect.signature(api_calls.db_get) + assert sig.parameters["timeout"].default == 5 + assert sig.parameters["retries"].default == 3 + + # Check mutation functions - should have timeout but no retries param + for func_name in ["db_post", "db_patch", "db_put", "db_delete"]: + func = getattr(api_calls, func_name) + sig = inspect.signature(func) + assert sig.parameters["timeout"].default == 5, ( + f"{func_name} should have default timeout=5" + ) + assert "retries" not in sig.parameters, ( + f"{func_name} should not have retries parameter" + ) + + def test_api_timeout_error_exists(self): + """Test that APITimeoutError exception is properly defined. + + APITimeoutError should be a subclass of DatabaseError so existing + error handlers that catch DatabaseError will also catch timeouts. + """ + assert issubclass(APITimeoutError, DatabaseError) + assert issubclass(APITimeoutError, Exception) + + # Test that it can be instantiated with a message + error = APITimeoutError("Test timeout message") + assert "Test timeout message" in str(error) + + def test_client_timeout_import(self): + """Test that ClientTimeout is properly imported from aiohttp. + + This verifies the timeout functionality can be used. + """ + from aiohttp import ClientTimeout + + # Create a timeout object to verify it works + timeout = ClientTimeout(total=5) + assert timeout.total == 5