Added Team table with caching and tests
This commit is contained in:
parent
aa66008577
commit
0deb547257
@ -7,7 +7,8 @@ from discord.ext import commands
|
||||
|
||||
from helpers import PD_PLAYERS_ROLE_NAME
|
||||
from in_game.game_helpers import PUBLIC_FIELDS_CATEGORY_NAME
|
||||
from in_game.gameplay_db import Session, engine, select, Game
|
||||
from in_game.data_cache import get_pd_team
|
||||
from in_game.gameplay_db import Session, engine, create_db_and_tables, select, Game
|
||||
|
||||
|
||||
def get_games_by_channel(session: Session, channel_id: int):
|
||||
@ -17,6 +18,7 @@ def get_games_by_channel(session: Session, channel_id: int):
|
||||
class Gameplay(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
create_db_and_tables()
|
||||
|
||||
async def cog_command_error(self, ctx, error):
|
||||
await ctx.send(f'{error}\n\nRun !help <command_name> to see the command requirements')
|
||||
@ -27,13 +29,16 @@ class Gameplay(commands.Cog):
|
||||
group_new_game = app_commands.Group(name='new-game', description='Start a new baseball game')
|
||||
|
||||
@group_new_game.command(name='mlb-campaign', description='Start a new MLB campaign game against an AI')
|
||||
@app_commands.rename(
|
||||
league='Campaign',
|
||||
away_team_abbrev='Away Team Abbrev',
|
||||
home_team_abbrev='Home Team Abbrev',
|
||||
sp_card_id='SP Card ID',
|
||||
num_innings='Number of Innings'
|
||||
@app_commands.describe(
|
||||
sp_card_id='Light gray number to the left of the pitcher\'s name on your depth chart'
|
||||
)
|
||||
# @app_commands.rename(
|
||||
# league='campaign',
|
||||
# away_team_abbrev='away team abbrev',
|
||||
# home_team_abbrev='home team abbrev',
|
||||
# sp_card_id='sp card id',
|
||||
# num_innings='number of innings'
|
||||
# )
|
||||
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
||||
async def new_game_mlb_campaign_command(
|
||||
self, interaction: discord.Interaction,
|
||||
@ -49,14 +54,23 @@ class Gameplay(commands.Cog):
|
||||
content=f'Ope. There is already a game going on in this channel. Please wait for it to complete '
|
||||
f'before starting a new one.'
|
||||
)
|
||||
return
|
||||
|
||||
if interaction.channel.category is None or interaction.channel.category.name != PUBLIC_FIELDS_CATEGORY_NAME:
|
||||
await interaction.response.send_message(
|
||||
f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything '
|
||||
await interaction.edit_original_response(
|
||||
content=f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything '
|
||||
f'pops up?'
|
||||
)
|
||||
return
|
||||
|
||||
away_team = await get_pd_team(away_team_abbrev)
|
||||
|
||||
await interaction.edit_original_response(
|
||||
content=f'This channel is ripe for the picking!'
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Gameplay(bot))
|
||||
@ -101,6 +101,7 @@ class Owner(commands.Cog):
|
||||
!sync * -> copies all global app commands to current guild and syncs
|
||||
!sync id_1 id_2 -> syncs guilds with id 1 and 2
|
||||
"""
|
||||
logging.info(f'{ctx.author.name} has initiated a sync from guild ID {ctx.guild.id}')
|
||||
if not guilds:
|
||||
if spec == "~":
|
||||
fmt = await ctx.bot.tree.sync(guild=ctx.guild)
|
||||
|
||||
@ -9,7 +9,7 @@ import os
|
||||
AUTH_TOKEN = {'Authorization': f'Bearer {os.environ.get("API_TOKEN")}'}
|
||||
DB_URL = 'https://pd.manticorum.com/api'
|
||||
master_debug = True
|
||||
alt_database = False
|
||||
alt_database = 'dev'
|
||||
PLAYER_CACHE = {}
|
||||
|
||||
if alt_database == 'dev':
|
||||
|
||||
@ -16,7 +16,7 @@ from db_calls import db_get
|
||||
from in_game.data_cache import get_pd_player, CardPosition, BattingCard, get_pd_team
|
||||
|
||||
db = SqliteDatabase(
|
||||
'storage/gameplay.db',
|
||||
'storage/gameplay-legacy.db',
|
||||
pragmas={
|
||||
'journal_mode': 'wal',
|
||||
'cache_size': -1 * 64000,
|
||||
|
||||
@ -4,10 +4,10 @@ import random
|
||||
|
||||
import discord
|
||||
|
||||
# from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, patch_play, advance_runners, \
|
||||
# complete_play, get_team_lineups, get_or_create_bullpen, get_player, get_sheets, make_sub, get_one_lineup, \
|
||||
# advance_one_runner, get_one_lineup, ai_batting, get_manager
|
||||
# from db_calls import db_get, db_post
|
||||
from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, patch_play, advance_runners, \
|
||||
complete_play, get_team_lineups, get_or_create_bullpen, get_player, get_sheets, make_sub, get_one_lineup, \
|
||||
advance_one_runner, get_one_lineup, ai_batting, get_manager
|
||||
from db_calls import db_get, db_post
|
||||
from helpers import Pagination, get_team_embed, image_embed, Confirm
|
||||
from typing import Literal, Optional
|
||||
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
import datetime
|
||||
import logging
|
||||
from sqlmodel import Session, SQLModel, create_engine, select, Field, Relationship
|
||||
|
||||
from db_calls import db_get
|
||||
from helpers import PD_SEASON
|
||||
|
||||
sqlite_url = 'sqlite:///./storage/gameplay.db'
|
||||
|
||||
sqlite_url = 'sqlite:///storage/gameplay.db'
|
||||
connect_args = {"check_same_thread": False}
|
||||
engine = create_engine(sqlite_url, echo=False, connect_args=connect_args)
|
||||
|
||||
@ -64,6 +68,81 @@ class Lineup(SQLModel, table=True):
|
||||
|
||||
game_id: int = Field(foreign_key='game.id', index=True)
|
||||
game: Game = Relationship(back_populates='lineups')
|
||||
|
||||
|
||||
class Team(SQLModel, table=True):
|
||||
id: int = Field(primary_key=True)
|
||||
abbrev: str = Field(index=True)
|
||||
sname: str
|
||||
lname: str
|
||||
gmid: int = Field(index=True)
|
||||
gmname: str
|
||||
gsheet: str
|
||||
wallet: int
|
||||
team_value: int
|
||||
collection_value: int
|
||||
logo: str | None = Field(default=None)
|
||||
color: str
|
||||
season: int
|
||||
career: int
|
||||
ranking: int
|
||||
has_guide: bool
|
||||
is_ai: bool
|
||||
created: datetime.datetime | None = Field(default=datetime.datetime.now())
|
||||
|
||||
|
||||
async def get_team(
|
||||
session: Session, team_id: int | None = None, gm_id: int | None = None, team_abbrev: str | None = None, skip_cache: bool = False) -> Team:
|
||||
if team_id is None and gm_id is None and team_abbrev is None:
|
||||
err = 'One of "team_id", "gm_id", or "team_abbrev" must be included in search'
|
||||
logging.error(f'gameplay_db - get_team - {err}')
|
||||
raise TypeError(err)
|
||||
|
||||
if not skip_cache:
|
||||
if team_id is not None:
|
||||
this_team = session.get(Team, team_id)
|
||||
else:
|
||||
if gm_id is not None:
|
||||
statement = select(Team).where(Team.gmid == gm_id)
|
||||
else:
|
||||
statement = select(Team).where(Team.abbrev.lower() == team_abbrev.lower())
|
||||
this_team = session.exec(statement).one_or_none
|
||||
|
||||
if this_team is not None:
|
||||
tdelta = datetime.datetime.now() - this_team.created
|
||||
if tdelta.total_seconds() < 1209600:
|
||||
return this_team
|
||||
else:
|
||||
session.delete(this_team)
|
||||
session.commit()
|
||||
|
||||
def cache_team(json_data: dict) -> Team:
|
||||
db_team = Team.model_validate(t_query)
|
||||
session.add(db_team)
|
||||
session.commit()
|
||||
session.refresh(db_team)
|
||||
return db_team
|
||||
|
||||
if team_id is not None:
|
||||
t_query = await db_get('teams', object_id=team_id, params=[('inc_packs', False)])
|
||||
if t_query is not None:
|
||||
return cache_team(t_query)
|
||||
|
||||
elif gm_id is not None:
|
||||
t_query = await db_get('teams', params=[('season', PD_SEASON), ('gm_id', gm_id)])
|
||||
if t_query['count'] != 0:
|
||||
for team in [x for x in t_query['teams'] if 'gauntlet' not in x.abbrev.lower()]:
|
||||
return cache_team(team)
|
||||
|
||||
elif team_abbrev is not None:
|
||||
t_query = await db_get('teams', params=[('season', PD_SEASON), ('abbrev', team_abbrev)])
|
||||
if t_query['count'] != 0:
|
||||
for team in [x for x in t_query['teams'] if 'gauntlet' not in x.abbrev.lower()]:
|
||||
return cache_team(team)
|
||||
|
||||
err = 'Team not found'
|
||||
logging.error(f'gameplay_db - get_team - {err}')
|
||||
raise LookupError(err)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import discord
|
||||
import datetime
|
||||
import logging
|
||||
# import logging.handlers
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
@ -18,10 +19,25 @@ else:
|
||||
|
||||
date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
|
||||
logging.basicConfig(
|
||||
filename=f'logs/discord/{date}.log',
|
||||
filename=f'logs/{date}.log',
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
level=log_level
|
||||
)
|
||||
# logging.getLogger('discord.http').setLevel(logging.INFO)
|
||||
# logger = logging.getLogger('discord')
|
||||
# logger.setLevel(log_level)
|
||||
|
||||
# handler = logging.handlers.RotatingFileHandler(
|
||||
# filename='discord.log',
|
||||
# encoding='utf-8',
|
||||
# maxBytes=32 * 1024 * 1024, # 32 MiB
|
||||
# backupCount=5, # Rotate through 5 files
|
||||
# )
|
||||
|
||||
# dt_fmt = '%Y-%m-%d %H:%M:%S'
|
||||
# formatter = logging.Formatter('[{asctime}] [{levelname:<8}] {name}: {message}', dt_fmt, style='{')
|
||||
# handler.setFormatter(formatter)
|
||||
# logger.addHandler(handler)
|
||||
|
||||
COGS = [
|
||||
'cogs.owner',
|
||||
|
||||
2
pytest.ini
Normal file
2
pytest.ini
Normal file
@ -0,0 +1,2 @@
|
||||
[pytest]
|
||||
asyncio_mode = auto
|
||||
@ -1,9 +1,10 @@
|
||||
import datetime
|
||||
import pytest
|
||||
from sqlmodel import Session, SQLModel, create_engine
|
||||
from sqlmodel.pool import StaticPool
|
||||
|
||||
from typing import Literal
|
||||
from in_game.gameplay_db import Game, Lineup
|
||||
from in_game.gameplay_db import Game, Lineup, Team
|
||||
|
||||
|
||||
@pytest.fixture(name='session')
|
||||
@ -41,4 +42,21 @@ def new_games_with_lineups_fixture():
|
||||
for (order, pos) in [(1, 'C'), (2, '1B'), (3, '2B'), (4, '3B'), (5, 'SS'), (6, 'LF'), (7, 'CF'), (8, 'RF'), (9, 'DH'), (10, 'P')]:
|
||||
all_lineups.append(Lineup(team_id=team_id, card_id=order, player_id=100+order, position=pos, batting_order=order, game=game_2))
|
||||
|
||||
return [game_1, game_2]
|
||||
return [game_1, game_2]
|
||||
|
||||
|
||||
@pytest.fixture(name='new_teams')
|
||||
def new_teams_fixture():
|
||||
team_1 = Team(
|
||||
id=31, abbrev='NCB', sname='CornBelters', lname='Normal CornBelters', gmid=1234, gmname='Cal', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='006900', season=7, event=False, career=1234, ranking=1337, has_guide=True, is_ai=False
|
||||
)
|
||||
team_2 = Team(
|
||||
id=400, abbrev='WV', sname='Black Bears', lname='West Virginia Black Bears', gmid=5678, gmname='Evil Cal', gsheet='https://i.postimg.cc/HjDc8bBF/blackbears-transparent.png', wallet=350, team_value=420, collection_value=169, color='6699FF', season=7, event=False, career=2, ranking=969, has_guide=False, is_ai=False
|
||||
)
|
||||
incomplete_team = Team(
|
||||
id=446, abbrev='CLS', sname='Macho Men', lname='Columbus Macho Men', gmid=181818, gmname='Mason Socc', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='https://i.postimg.cc/8kLZCYXh/S10CLS.png', season=7, event=False, career=0
|
||||
)
|
||||
old_cache_team = Team(
|
||||
id=3, abbrev='BAL', sname='Orioles', lname='Baltimore Orioles', gmid=181818, gmname='Brandon Hyde', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='https://i.postimg.cc/8kLZCYXh/S10CLS.png', season=7, event=False, career=0, ranking=500, has_guide=False, is_ai=False, created=datetime.datetime.today() - datetime.timedelta(days=60))
|
||||
|
||||
return [team_1, team_2, incomplete_team, old_cache_team]
|
||||
@ -1,10 +1,13 @@
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from in_game.gameplay_db import Game, Lineup
|
||||
from factory import session_fixture, new_games_with_lineups_fixture
|
||||
from factory import session_fixture, new_games_with_lineups_fixture, new_games_fixture
|
||||
|
||||
|
||||
def test_create_lineup(session: Session, new_games_with_lineups: list[Game]):
|
||||
"""
|
||||
This test fails when run with the entire suite
|
||||
"""
|
||||
game_1 = new_games_with_lineups[0]
|
||||
game_2 = new_games_with_lineups[1]
|
||||
|
||||
|
||||
55
tests/test_gameplay_db_team.py
Normal file
55
tests/test_gameplay_db_team.py
Normal file
@ -0,0 +1,55 @@
|
||||
import datetime
|
||||
from sqlmodel import Session, select
|
||||
from sqlite3 import IntegrityError
|
||||
|
||||
from in_game.gameplay_db import Team, get_team
|
||||
from factory import session_fixture, new_teams_fixture, pytest
|
||||
|
||||
def test_create_team(session: Session, new_teams: list[Team]):
|
||||
team_1 = new_teams[0]
|
||||
team_2 = new_teams[1]
|
||||
|
||||
session.add(team_1)
|
||||
session.add(team_2)
|
||||
session.commit()
|
||||
|
||||
assert team_1.abbrev == 'NCB'
|
||||
assert team_1.id == 31
|
||||
assert team_2.abbrev == 'WV'
|
||||
assert team_2.id == 400
|
||||
|
||||
|
||||
def test_create_incomplete_team(session: Session, new_teams: list[Team]):
|
||||
team_1 = new_teams[2]
|
||||
|
||||
session.add(team_1)
|
||||
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
session.commit()
|
||||
|
||||
assert str(exc_info) == "<ExceptionInfo IntegrityError('(sqlite3.IntegrityError) NOT NULL constraint failed: team.ranking') tblen=24>"
|
||||
|
||||
|
||||
async def test_team_cache(session: Session, new_teams: list[Team]):
|
||||
team_1 = new_teams[0]
|
||||
team_2 = new_teams[1]
|
||||
team_3 = new_teams[3]
|
||||
|
||||
session.add(team_1)
|
||||
session.add(team_2)
|
||||
session.add(team_3)
|
||||
session.commit()
|
||||
|
||||
new_team_1 = await get_team(session, team_id=team_1.id)
|
||||
new_team_2 = await get_team(session, team_id=team_2.id)
|
||||
new_team_3 = await get_team(session, team_id=team_3.id)
|
||||
|
||||
assert team_1.created == new_team_1.created
|
||||
assert team_2.created == new_team_2.created
|
||||
assert (datetime.datetime.now() - team_3.created).total_seconds() > 1209600
|
||||
assert (datetime.datetime.now() - new_team_3.created).total_seconds() < 1209600
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user