paper-dynasty-discord/in_game/data_cache.py
Cal Corum ee80cd72ae fix: apply Black formatting and resolve ruff lint violations
Run Black formatter across 83 files and fix 1514 ruff violations:
- E722: bare except → typed exceptions (17 fixes)
- E711/E712/E721: comparison style fixes with noqa for SQLAlchemy (44 fixes)
- F841: unused variable assignments (70 fixes)
- F541/F401: f-string and import cleanup (1383 auto-fixes)

Remaining 925 errors are all F403/F405 (star imports) — structural,
requires converting to explicit imports in a separate effort.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:37:46 -05:00

424 lines
12 KiB
Python

import datetime
from dataclasses import dataclass
import logging
from typing import Optional, Literal
from api_calls import db_get
from helpers import PD_SEASON
PLAYER_CACHE = {}
TEAM_CACHE = {}
BATTINGCARD_CACHE = {} # { <player_id: int>: { <variant: int>: BattingWrapper } }
PITCHINGCARD_CACHE = {} # { <player_id: int>: { <variant: int>: PitchingWrapper } }
logger = logging.getLogger("discord_app")
@dataclass
class Player:
player_id: int
p_name: str
cost: int
image: str
mlbclub: str
franchise: str
cardset: dict
set_num: int
rarity: dict
pos_1: str
description: str
quantity: Optional[int] = 999
image2: Optional[str] = None
pos_2: Optional[str] = None
pos_3: Optional[str] = None
pos_4: Optional[str] = None
pos_5: Optional[str] = None
pos_6: Optional[str] = None
pos_7: Optional[str] = None
pos_8: Optional[str] = None
headshot: Optional[str] = None
vanity_card: Optional[str] = None
strat_code: Optional[str] = None
bbref_id: Optional[str] = None
fangr_id: Optional[str] = None
mlbplayer: Optional[dict] = None
created: datetime.datetime = datetime.datetime.now()
def to_dict(self):
return {
"player_id": self.player_id,
"p_name": self.p_name,
"cost": self.cost,
"image": self.image,
"mlbclub": self.mlbclub,
"franchise": self.franchise,
"cardset": self.cardset,
"set_num": self.set_num,
"rarity": self.rarity,
"pos_1": self.pos_1,
"description": self.description,
"quantity": self.quantity,
"image2": self.image2,
"pos_2": self.pos_2,
"pos_3": self.pos_3,
"pos_4": self.pos_4,
"pos_5": self.pos_5,
"pos_6": self.pos_6,
"pos_7": self.pos_7,
"pos_8": self.pos_8,
"headshot": self.headshot,
"vanity_card": self.vanity_card,
"strat_code": self.strat_code,
"bbref_id": self.bbref_id,
"fangr_id": self.fangr_id,
"mlbplayer": self.mlbplayer,
}
@dataclass
class Team:
id: int
abbrev: str
sname: str
lname: str
gmid: int
gmname: str
gsheet: str
wallet: int
team_value: int
collection_value: int
logo: str
color: str
season: int
event: bool
career: int
ranking: int
has_guide: bool
is_ai: bool
created: datetime.datetime = datetime.datetime.now()
def to_dict(self):
return {
"id": self.id,
"abbrev": self.abbrev,
"sname": self.sname,
"lname": self.lname,
"gmid": self.gmid,
"gmname": self.gmname,
"gsheet": self.gsheet,
"wallet": self.wallet,
"team_value": self.team_value,
"collection_value": self.collection_value,
"logo": self.logo,
"color": self.color,
"season": self.season,
"event": self.event,
"career": self.career,
"ranking": self.ranking,
"has_guide": self.has_guide,
"is_ai": self.is_ai,
}
@dataclass
class BattingCard:
player_id: int
variant: int
steal_low: int
steal_high: int
steal_auto: bool
steal_jump: float
bunting: str
hit_and_run: str
running: int
offense_col: int
hand: str
@dataclass
class CardPosition:
player_id: int
variant: int
position: Literal["P", "C", "1B", "2B", "3B", "SS", "LF", "CF", "RF", "DH"]
innings: int
range: int
error: int
arm: Optional[int] = None
pb: Optional[int] = None
overthrow: Optional[int] = None
def to_dict(self):
return_val = {
"player_id": self.player_id,
"variant": self.variant,
"position": self.position,
"innings": self.innings,
"range": self.range,
"error": self.error,
}
if self.arm is not None:
return_val["arm"] = self.arm
if self.pb is not None:
return_val["pb"] = self.pb
if self.overthrow is not None:
return_val["overthrow"] = self.overthrow
return return_val
@dataclass
class BattingRatings:
homerun: float
bp_homerun: float
triple: float
double_three: float
double_two: float
double_pull: float
single_two: float
single_one: float
single_center: float
bp_single: float
hbp: float
walk: float
strikeout: float
lineout: float
popout: float
flyout_a: float
flyout_bq: float
flyout_lf_b: float
flyout_rf_b: float
groundout_a: float
groundout_b: float
groundout_c: float
avg: float
obp: float
slg: float
pull_rate: float
center_rate: float
slap_rate: float
@dataclass
class BattingWrapper:
card: BattingCard
ratings_vl: BattingRatings
ratings_vr: BattingRatings
created: datetime.datetime = datetime.datetime.now()
@dataclass
class PitchingCard:
player_id: int
variant: int
balk: int
wild_pitch: int
hold: int
starter_rating: int
relief_rating: int
batting: str
offense_col: int
hand: str
closer_rating: Optional[int] = None
@dataclass
class PitchingRatings:
homerun: float
bp_homerun: float
triple: float
double_three: float
double_two: float
double_cf: float
single_two: float
single_one: float
single_center: float
bp_single: float
hbp: float
walk: float
strikeout: float
flyout_lf_b: float
flyout_cf_b: float
flyout_rf_b: float
groundout_a: float
groundout_b: float
xcheck_p: float
xcheck_c: float
xcheck_1b: float
xcheck_2b: float
xcheck_3b: float
xcheck_ss: float
xcheck_lf: float
xcheck_cf: float
xcheck_rf: float
avg: float
obp: float
slg: float
@dataclass
class PitchingWrapper:
card: PitchingCard
ratings_vl: PitchingRatings
ratings_vr: PitchingRatings
created: datetime.datetime = datetime.datetime.now()
async def get_pd_player(
player_id, as_dict: Optional[bool] = True, skip_cache: bool = False
):
if player_id in PLAYER_CACHE and not skip_cache:
tdelta = datetime.datetime.now() - PLAYER_CACHE[player_id].created
if tdelta.total_seconds() < 1209600:
logger.debug(f"this_player: {PLAYER_CACHE[player_id]}")
if as_dict:
return PLAYER_CACHE[player_id].to_dict()
else:
return PLAYER_CACHE[player_id]
else:
logger.error(f"Refreshing player {player_id} in cache...")
this_player = await db_get("players", object_id=player_id)
for bad_key in ["mlbplayer", "paperdex"]:
if bad_key in this_player:
del this_player[bad_key]
logger.debug(f"this_player: {this_player}")
PLAYER_CACHE[player_id] = Player(**this_player)
if as_dict:
return this_player
return PLAYER_CACHE[player_id]
async def get_pd_team(team_or_gm_id, as_dict: bool = True, skip_cache: bool = False):
if team_or_gm_id in TEAM_CACHE and not skip_cache:
tdelta = datetime.datetime.now() - TEAM_CACHE[team_or_gm_id].created
if tdelta.total_seconds() < 1209600:
logger.info(f"this_team: {TEAM_CACHE[team_or_gm_id]}")
if as_dict:
return TEAM_CACHE[team_or_gm_id].to_dict()
else:
return TEAM_CACHE[team_or_gm_id]
else:
logger.error(f"Refreshing team {team_or_gm_id} in cache...")
this_team = await db_get(
"teams", object_id=team_or_gm_id, params=[("inc_packs", False)]
)
if this_team is None:
t_query = await db_get(
"teams", params=[("season", PD_SEASON), ("gm_id", team_or_gm_id)]
)
if t_query is None:
raise KeyError(f"No team found for ID {team_or_gm_id}")
this_team = t_query["teams"][0]
logger.info(f"this_team: {this_team}")
TEAM_CACHE[team_or_gm_id] = Team(**this_team)
if as_dict:
return this_team
return TEAM_CACHE[team_or_gm_id]
async def get_pd_battingcard(player_id: int, variant: Optional[int] = 0):
if player_id in BATTINGCARD_CACHE and variant in BATTINGCARD_CACHE[player_id]:
tdelta = datetime.datetime.now() - BATTINGCARD_CACHE[player_id][variant].created
if tdelta.total_seconds() < 609600:
logger.info(f"this_battingcard: {BATTINGCARD_CACHE[player_id][variant]}")
return BATTINGCARD_CACHE[player_id][variant]
vl_data, vr_data = None, None
r_query = await db_get(f"battingcardratings/player/{player_id}")
if r_query["count"] > 0:
for row in r_query["ratings"]:
if row["battingcard"]["variant"] == variant:
if row["vs_hand"].lower() == "r":
vr_data = row
elif row["vs_hand"].lower() == "l":
vl_data = row
if vl_data is not None and vr_data is not None:
break
if None in [vl_data, vr_data]:
raise KeyError(
f"Could not find batting card ratings for player {player_id} variant {variant}"
)
logger.info("prepping the batting card")
bc_data = vl_data["battingcard"]
bc_data["player_id"] = player_id
del bc_data["id"], bc_data["player"]
this_bc = BattingCard(**bc_data)
logger.info("prepping the vl ratings")
vl_ratings = vl_data
del vl_ratings["battingcard"], vl_ratings["id"], vl_ratings["vs_hand"]
this_vl = BattingRatings(**vl_ratings)
logger.info("prepping the vl ratings")
vr_ratings = vr_data
del vr_ratings["battingcard"], vr_ratings["id"], vr_ratings["vs_hand"]
this_vr = BattingRatings(**vr_ratings)
logger.info("prepping the wrapper")
this_wrapper = BattingWrapper(card=this_bc, ratings_vl=this_vl, ratings_vr=this_vr)
if player_id in BATTINGCARD_CACHE:
BATTINGCARD_CACHE[player_id][variant] = this_wrapper
else:
BATTINGCARD_CACHE[player_id] = {variant: this_wrapper}
return this_wrapper
async def get_pd_pitchingcard(player_id: int, variant: Optional[int] = 0):
if player_id in PITCHINGCARD_CACHE and variant in PITCHINGCARD_CACHE[player_id]:
tdelta = (
datetime.datetime.now() - PITCHINGCARD_CACHE[player_id][variant].created
)
if tdelta.total_seconds() < 609600:
logger.debug(f"this_pitchingcard: {PITCHINGCARD_CACHE[player_id][variant]}")
return PITCHINGCARD_CACHE[player_id][variant]
vl_data, vr_data = None, None
r_query = await db_get(f"pitchingcardratings/player/{player_id}")
if r_query["count"] > 0:
for row in r_query["ratings"]:
if row["pitchingcard"]["variant"] == variant:
if row["vs_hand"].lower() == "r":
vr_data = row
elif row["vs_hand"].lower() == "l":
vl_data = row
if vl_data is not None and vr_data is not None:
break
if None in [vl_data, vr_data]:
raise KeyError(
f"Could not find pitching card ratings for player {player_id} variant {variant}"
)
logger.debug("prepping the pitching card")
pc_data = vl_data["pitchingcard"]
pc_data["player_id"] = player_id
del pc_data["id"], pc_data["player"]
this_pc = PitchingCard(**pc_data)
logger.debug("prepping the vl ratings")
vl_ratings = vl_data
del vl_ratings["pitchingcard"], vl_ratings["id"], vl_ratings["vs_hand"]
this_vl = PitchingRatings(**vl_ratings)
logger.debug("prepping the vr ratings")
vr_ratings = vr_data
del vr_ratings["pitchingcard"], vr_ratings["id"], vr_ratings["vs_hand"]
this_vr = PitchingRatings(**vr_ratings)
logger.debug("prepping the wrapper")
this_wrapper = PitchingWrapper(card=this_pc, ratings_vl=this_vl, ratings_vr=this_vr)
if player_id in PITCHINGCARD_CACHE:
PITCHINGCARD_CACHE[player_id][variant] = this_wrapper
else:
PITCHINGCARD_CACHE[player_id] = {variant: this_wrapper}
return this_wrapper