diff --git a/pauperformance_bot/constant/arena/twitch.py b/pauperformance_bot/constant/arena/twitch.py deleted file mode 100644 index 564c5b6..0000000 --- a/pauperformance_bot/constant/arena/twitch.py +++ /dev/null @@ -1 +0,0 @@ -TWITCH_VIDEO_URL = "https://www.twitch.tv/videos/" # followed by video_id diff --git a/pauperformance_bot/entity/arena/indexable_video.py b/pauperformance_bot/entity/arena/indexable_video.py deleted file mode 100644 index dd3cb8d..0000000 --- a/pauperformance_bot/entity/arena/indexable_video.py +++ /dev/null @@ -1,43 +0,0 @@ -from pauperformance_bot.constant.pauperformance.myr import VIDEO_DECK_TAG -from pauperformance_bot.util.decorators import auto_repr, auto_str -from pauperformance_bot.util.log import get_application_logger -from pauperformance_bot.util.naming import is_valid_p12e_deck_name - -logger = get_application_logger() - - -@auto_repr -@auto_str -class IndexableVideo: - def __init__(self, description): - self.description = description - - @property - def deck_name(self): - deck_name = None - for line in self.description.split("\n"): - line = line.strip() - if line.lower().startswith(VIDEO_DECK_TAG.lower()): - logger.debug(f"Extracting deck name from line:\n{line}") - maybe_deck_name = line[len(VIDEO_DECK_TAG) :] - if is_valid_p12e_deck_name(maybe_deck_name): - deck_name = maybe_deck_name - logger.debug(f"Pairing video to deck {deck_name}") - break - return deck_name - - @property - def archetype(self): - archetype = None - for line in self.description.split("\n"): - line = line.strip() - if line.lower().startswith(VIDEO_DECK_TAG.lower()): - logger.debug(f"Extracting archetype from line:\n{line}") - archetype = line[len(VIDEO_DECK_TAG) :] - if "." in archetype: # need to drop deck name - archetype = archetype.split(".", maxsplit=1)[0].rsplit( - " ", maxsplit=1 - )[0] - logger.debug(f"Pairing video to archetype {archetype}") - break - return archetype diff --git a/pauperformance_bot/entity/arena/youtube_video.py b/pauperformance_bot/entity/arena/youtube_video.py index 4268566..b88e4c8 100644 --- a/pauperformance_bot/entity/arena/youtube_video.py +++ b/pauperformance_bot/entity/arena/youtube_video.py @@ -1,10 +1,9 @@ -from pauperformance_bot.entity.arena.indexable_video import IndexableVideo from pauperformance_bot.util.decorators import auto_repr, auto_str @auto_repr @auto_str -class YouTubeVideo(IndexableVideo): +class YouTubeVideo: def __init__( self, video_id, # YouTube internals @@ -23,13 +22,13 @@ def __init__( language, is_short, ): - super().__init__(description) self.video_id = video_id self.etag = etag self.content_video_id = content_video_id self.published_at = published_at self.channel_id = channel_id self.channel_title = channel_title + self.description = description self.playlist_id = playlist_id self.position = position self.created_at = created_at diff --git a/pauperformance_bot/service/academy/data_exporter.py b/pauperformance_bot/service/academy/data_exporter.py index e356497..ff6d0a0 100644 --- a/pauperformance_bot/service/academy/data_exporter.py +++ b/pauperformance_bot/service/academy/data_exporter.py @@ -64,6 +64,7 @@ def __init__( def export_all(self): # TODO: remove each (relevant) folder before re-exporting to avoid stale files + # TODO: figure out what is the right order of export operations # self.export_miscellanea() # self.export_creator_sheets() # self.export_archetypes() diff --git a/pauperformance_bot/service/arena/twitch.py b/pauperformance_bot/service/arena/twitch.py deleted file mode 100644 index 89b9714..0000000 --- a/pauperformance_bot/service/arena/twitch.py +++ /dev/null @@ -1,39 +0,0 @@ -from twitchAPI.twitch import Twitch - -from pauperformance_bot.credentials import ( - TWITCH_APP_CLIENT_ID, - TWITCH_APP_CLIENT_SECRET, -) -from pauperformance_bot.entity.arena.twitch_user import TwitchUser -from pauperformance_bot.util.log import get_application_logger - -logger = get_application_logger() - - -class TwitchService: - def __init__( - self, - myr_client_id=TWITCH_APP_CLIENT_ID, - myr_client_secret=TWITCH_APP_CLIENT_SECRET, - ): - self._service = Twitch(myr_client_id, myr_client_secret) - - def get_user(self, login_name): - user = self._service.get_users(logins=[login_name])["data"][0] - return TwitchUser( - user["id"], - user["login"], - user["display_name"], - user["description"], - ) - - def get_users(self, login_names): - return [ - TwitchUser( - user["id"], - user["login"], - user["display_name"], - user["description"], - ) - for user in self._service.get_users(logins=login_names)["data"] - ] diff --git a/pauperformance_bot/service/pauperformance/archive/mtggoldfish.py b/pauperformance_bot/service/pauperformance/archive/mtggoldfish.py index ec10a54..9b26c44 100644 --- a/pauperformance_bot/service/pauperformance/archive/mtggoldfish.py +++ b/pauperformance_bot/service/pauperformance/archive/mtggoldfish.py @@ -82,6 +82,7 @@ def __init__( # So, let's just fix this shit ourselves with some caching mechanism. self.storage = storage # will be the source of truth to detect missing decks self._decks_cache: list[AbstractArchivedDeck] = [] # will act as a cache + self.list_decks() # forces caching @staticmethod def _parse_login_authenticity_token(response): diff --git a/pauperformance_bot/service/pauperformance/async_pauperformance.py b/pauperformance_bot/service/pauperformance/async_pauperformance.py index a671234..89214d0 100644 --- a/pauperformance_bot/service/pauperformance/async_pauperformance.py +++ b/pauperformance_bot/service/pauperformance/async_pauperformance.py @@ -2,7 +2,6 @@ from pauperformance_bot.constant.arena.youtube import YOUTUBE_CONNECTION_POOL_SIZE_API from pauperformance_bot.entity.config.creator import CreatorConfig -from pauperformance_bot.service.arena.twitch import TwitchService from pauperformance_bot.service.arena.youtube import YouTubeService from pauperformance_bot.service.mtg.scryfall import ScryfallService from pauperformance_bot.service.nexus.async_discord_service import AsyncDiscordService @@ -22,7 +21,6 @@ def __init__( storage, archive, scryfall=ScryfallService(), - twitch=TwitchService(), youtube=YouTubeService(), config_reader=ConfigReader(), ): @@ -30,7 +28,6 @@ def __init__( storage, archive, scryfall, - twitch, youtube, config_reader, ) diff --git a/pauperformance_bot/service/pauperformance/pauperformance.py b/pauperformance_bot/service/pauperformance/pauperformance.py index 4dc74bb..42fc66f 100644 --- a/pauperformance_bot/service/pauperformance/pauperformance.py +++ b/pauperformance_bot/service/pauperformance/pauperformance.py @@ -10,7 +10,6 @@ from requests.exceptions import HTTPError import pauperformance_bot -from pauperformance_bot.constant.arena.twitch import TWITCH_VIDEO_URL from pauperformance_bot.constant.arena.youtube import YOUTUBE_VIDEO_URL from pauperformance_bot.constant.mtg.scryfall import REQUESTS_SLEEP_SECONDS from pauperformance_bot.constant.pauperformance.myr import ( @@ -28,7 +27,6 @@ from pauperformance_bot.entity.deck.archive.abstract import AbstractArchivedDeck from pauperformance_bot.entity.deck.playable import PlayableDeck from pauperformance_bot.exceptions import PauperformanceException -from pauperformance_bot.service.arena.twitch import TwitchService from pauperformance_bot.service.arena.youtube import YouTubeService from pauperformance_bot.service.mtg.deckstats import DeckstatsService from pauperformance_bot.service.mtg.scryfall import ScryfallService @@ -55,14 +53,12 @@ def __init__( storage, archive, scryfall=ScryfallService(), - twitch=TwitchService(), youtube=YouTubeService(), config_reader=ConfigReader(), ): self.storage: AbstractStorageService = storage self.archive: AbstractArchiveService = archive self.scryfall = scryfall - self.twitch = twitch self.youtube = youtube self.config_reader = config_reader self.players = config_reader.list_creators() @@ -313,33 +309,6 @@ def delete_deck(self, deck_name): discord_logger = DiscordMessagesSenderSyncService([message]) discord_logger.run_task() - def _list_twitch_videos(self): - logger.debug("Retrieving stored Twitch videos...") - academy_videos = [] - for video in self.storage.list_imported_twitch_videos(): - video_id, user_name, language, date, key = video.split(">") - video_path = posix_path( - self.storage.youtube_video_path, - video + ".txt", # TODO: get rid of this - ) - indexable_video = self.storage.get_file(video_path) - academy_videos.append( - AcademyVideo( - video_id, - user_name, - indexable_video["title"], - language, - date, - indexable_video["deck_name"], - indexable_video["archetype"], - indexable_video["creator"], - f"{TWITCH_VIDEO_URL}{video_id}", - "twitch", - ) - ) - logger.debug("Retrieved stored Twitch videos.") - return academy_videos - def _list_youtube_videos(self): logger.debug("Retrieving stored YouTube videos...") academy_videos = [] @@ -368,7 +337,7 @@ def _list_youtube_videos(self): return academy_videos def list_videos(self) -> list[AcademyVideo]: - return self._list_twitch_videos() + self._list_youtube_videos() + return self._list_youtube_videos() def print_stats( self, diff --git a/pauperformance_bot/service/pauperformance/silver/decklassifier.py b/pauperformance_bot/service/pauperformance/silver/decklassifier.py index b49e0ad..04e7ac7 100644 --- a/pauperformance_bot/service/pauperformance/silver/decklassifier.py +++ b/pauperformance_bot/service/pauperformance/silver/decklassifier.py @@ -3,8 +3,6 @@ from collections import defaultdict from typing import DefaultDict, Optional, Tuple -from entity.deck.playable import PlayedCard - from pauperformance_bot.constant.mtg.game import BASIC_LANDS from pauperformance_bot.constant.pauperformance.academy import AcademyFileSystem from pauperformance_bot.constant.pauperformance.silver import ( @@ -21,6 +19,7 @@ from pauperformance_bot.entity.config.archetype import ArchetypeConfig from pauperformance_bot.entity.deck.playable import ( PlayableDeck, + PlayedCard, parse_playable_deck_from_lines, ) from pauperformance_bot.service.mtg.mtggoldfish import MTGGoldfish diff --git a/pauperformance_bot/task/async_scraper.py b/pauperformance_bot/task/async_scraper.py index c9ce0a3..1d619bc 100644 --- a/pauperformance_bot/task/async_scraper.py +++ b/pauperformance_bot/task/async_scraper.py @@ -17,7 +17,11 @@ ) from pauperformance_bot.service.pauperformance.storage.dropbox_ import DropboxService from pauperformance_bot.util.log import get_application_logger -from pauperformance_bot.util.time import last_week # noqa: F401 +from pauperformance_bot.util.time import ( # noqa: F401 + last_n_hours, + last_n_weeks, + last_week, +) logger = get_application_logger() @@ -59,8 +63,10 @@ async def scrape(since=None): ) def main(): try: + asyncio.run(scrape(last_n_hours(1))) + # asyncio.run(scrape(last_n_weeks(1))) # asyncio.run(scrape(last_week())) - asyncio.run(scrape()) + # asyncio.run(scrape()) except RuntimeError as exc: logger.exception(exc) diff --git a/pauperformance_bot/task/silver.py b/pauperformance_bot/task/silver.py index a25794e..4e60f90 100644 --- a/pauperformance_bot/task/silver.py +++ b/pauperformance_bot/task/silver.py @@ -4,6 +4,7 @@ import jsonpickle from pauperformance_bot.constant.pauperformance.academy import ACADEMY_FILE_SYSTEM +from pauperformance_bot.constant.pauperformance.myr import TOP_PATH from pauperformance_bot.service.pauperformance.archive.mtggoldfish import ( MTGGoldfishArchiveService, ) @@ -17,6 +18,7 @@ from pauperformance_bot.service.pauperformance.storage.dropbox_ import DropboxService from pauperformance_bot.util.log import get_application_logger from pauperformance_bot.util.path import ( + posix_path, safe_dump_json_to_file, ) @@ -83,6 +85,43 @@ def dpl_classifier(environ, start_response): return [json.dumps({"error": str(e)}).encode("utf-8")] +def apl_classifier(environ, start_response): + try: + method = environ["REQUEST_METHOD"] + if method != "POST": + start_response( + "405 Method Not Allowed", [("Content-Type", "application/json")] + ) + return [json.dumps({"error": "Method not allowed"}).encode("utf-8")] + try: + request_length = int(environ.get("CONTENT_LENGTH", 0)) + except (ValueError, TypeError): + request_length = 0 + request_body = environ["wsgi.input"].read(request_length) + raw_data = json.loads(request_body.decode("utf-8")) + data = [] + for d in raw_data["decks"]: + data.append( + { + "id": d["id"], + "cards": { + "mainboard": d["mainDeck"], + "sideboard": d["sideboard"], + }, + } + ) + response = generate_dpl_meta(data) + response = {d.identifier: d.archetype for d in response.dpl_decks} + response = json.loads(jsonpickle.encode(response, make_refs=False, warn=True)) + start_response("200 OK", [("Content-Type", "application/json")]) + return [json.dumps(response).encode("utf-8")] + except Exception as e: + start_response( + "500 Internal Server Error", [("Content-Type", "application/json")] + ) + return [json.dumps({"error": str(e)}).encode("utf-8")] + + def classify(): storage = DropboxService() archive = MTGGoldfishArchiveService(storage) @@ -97,4 +136,5 @@ def classify(): # posix_path(TOP_PATH, "dev", "decks-all-tournaments.json"), # posix_path(TOP_PATH, "dev", "decks-all-tournaments-classified.json"), # ) - classify() + # classify() + generate_dpl_meta(posix_path(TOP_PATH, "dev", "decks-all-tournaments-mini.json")) diff --git a/pauperformance_bot/task/sync_scraper.py b/pauperformance_bot/task/sync_scraper.py index fc7f27d..1392a59 100644 --- a/pauperformance_bot/task/sync_scraper.py +++ b/pauperformance_bot/task/sync_scraper.py @@ -8,8 +8,11 @@ from pauperformance_bot.constant.pauperformance.academy import AcademyFileSystem from pauperformance_bot.entity.api.tournament import Tournament from pauperformance_bot.service.mtg.mtggoldfish import MTGGoldfish +from pauperformance_bot.service.pauperformance.silver.sideboard_scraper import ( + update_sideboard_guides, +) from pauperformance_bot.util.log import get_application_logger -from pauperformance_bot.util.time import last_week +from pauperformance_bot.util.time import last_n_weeks logger = get_application_logger() logger.setLevel(logging.DEBUG) @@ -48,7 +51,9 @@ def download_mtggoldfish(since): def scrape(since): download_mtggoldfish(since) + update_sideboard_guides() if __name__ == "__main__": - scrape(last_week()) + # scrape(last_week()) + scrape(last_n_weeks(4 * 12)) diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index 343051c..6e6a5f9 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -6,25 +6,25 @@ # requirements upgrade # -r requirements.txt -ast-serialize==0.5.0 +ast-serialize==0.6.0 # via mypy astroid==4.0.4 # via pylint black==26.5.1 # via -r requirements/requirements-test.in -click==8.4.1 +click==8.4.2 # via black -coverage[toml]==7.14.0 +coverage[toml]==7.15.2 # via pytest-cov ddt==1.7.2 # via -r requirements/requirements-test.in dill==0.4.1 # via pylint -distlib==0.4.0 +distlib==0.4.3 # via virtualenv execnet==2.1.2 # via pytest-xdist -filelock==3.29.0 +filelock==3.29.7 # via # python-discovery # tox @@ -37,19 +37,19 @@ isort==8.0.1 # via # -r requirements/requirements-test.in # pylint -librt==0.11.0 +librt==0.13.0 # via mypy mccabe==0.7.0 # via # flake8 # pylint -mypy==2.1.0 +mypy==2.3.0 # via -r requirements/requirements-test.in pathspec==1.1.1 # via # black # mypy -platformdirs==4.9.6 +platformdirs==4.10.0 # via # black # pylint @@ -68,9 +68,9 @@ pyflakes==3.4.0 # via flake8 pygments==2.20.0 # via pytest -pylint==4.0.5 +pylint==4.0.6 # via -r requirements/requirements-test.in -pytest==9.0.3 +pytest==9.1.1 # via # -r requirements/requirements-test.in # pytest-cov @@ -79,7 +79,7 @@ pytest-cov==7.1.0 # via -r requirements/requirements-test.in pytest-xdist==3.8.0 # via -r requirements/requirements-test.in -python-discovery==1.3.1 +python-discovery==1.4.4 # via virtualenv pytokens==0.4.1 # via black @@ -91,15 +91,15 @@ tox==3.25.0 # via -r requirements/requirements-test.in types-backports==0.1.3 # via -r requirements/requirements-test.in -types-cachetools==7.0.0.20260518 +types-cachetools==7.0.0.20260713 # via -r requirements/requirements-test.in types-pytz==2026.2.0.20260518 # via -r requirements/requirements-test.in -types-requests==2.33.0.20260518 +types-requests==2.33.0.20260712 # via -r requirements/requirements-test.in -types-setuptools==82.0.0.20260518 +types-setuptools==83.0.0.20260706 # via -r requirements/requirements-test.in types-ujson==5.10.0.20250822 # via -r requirements/requirements-test.in -virtualenv==21.3.3 +virtualenv==21.6.1 # via tox diff --git a/requirements/requirements.in b/requirements/requirements.in index a7d4f2f..15735e4 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -3,7 +3,6 @@ pyquery requests retrying argcomplete -twitchAPI==2.5.5 # v3.10.0+ requires additional work python-youtube discord.py==1.7.3 # v2+ requires additional work beautifulsoup4 diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 57e7a79..8adb722 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,4 +1,4 @@ -# SHA1:18d617c4ac015e3f51283923142a9f47df9c8a37 +# SHA1:64c0a04a54fb3da08546ec696baca485f9e33231 # # This file was generated by pip-compile-multi. # To update, run: @@ -6,22 +6,20 @@ # requirements upgrade # aiohttp==3.7.4.post0 - # via - # discord-py - # twitchapi -argcomplete==3.6.3 + # via discord-py +argcomplete==3.7.0 # via -r requirements/requirements.in async-timeout==3.0.1 # via aiohttp attrs==26.1.0 # via aiohttp -beautifulsoup4==4.14.3 +beautifulsoup4==4.15.0 # via -r requirements/requirements.in -certifi==2026.5.20 +certifi==2026.6.17 # via requests chardet==4.0.0 # via aiohttp -charset-normalizer==3.4.7 +charset-normalizer==3.4.9 # via requests cloudscraper==1.2.71 # via -r requirements/requirements.in @@ -43,13 +41,13 @@ fonttools==4.63.0 # via matplotlib gunicorn==26.0.0 # via -r requirements/requirements.in -idna==3.16 +idna==3.18 # via # requests # yarl isodate==0.7.2 # via python-youtube -jsonpickle==4.1.1 +jsonpickle==4.1.2 # via -r requirements/requirements.in kiwisolver==1.5.0 # via matplotlib @@ -57,7 +55,7 @@ lxml==6.1.1 # via pyquery marshmallow==3.26.2 # via dataclasses-json -matplotlib==3.10.9 +matplotlib==3.11.0 # via seaborn multidict==6.7.1 # via @@ -80,7 +78,7 @@ packaging==26.2 # matplotlib pandas==3.0.3 # via seaborn -pillow==12.2.0 +pillow==12.3.0 # via matplotlib ply==3.11 # via stone @@ -96,7 +94,6 @@ python-dateutil==2.9.0.post0 # via # matplotlib # pandas - # twitchapi python-youtube==0.9.9 # via -r requirements/requirements.in requests==2.34.2 @@ -107,7 +104,6 @@ requests==2.34.2 # python-youtube # requests-oauthlib # requests-toolbelt - # twitchapi requests-oauthlib==2.0.0 # via python-youtube requests-toolbelt==1.0.0 @@ -127,21 +123,16 @@ stone==3.3.1 # via dropbox tenacity==9.1.4 # via -r requirements/requirements.in -twitchapi==2.5.5 - # via -r requirements/requirements.in -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via # aiohttp # beautifulsoup4 - # twitchapi # typing-inspect typing-inspect==0.9.0 # via dataclasses-json urllib3==2.7.0 # via requests -websockets==16.0 - # via twitchapi -wrapt==2.2.1 +wrapt==2.2.2 # via deprecated yarl==1.24.2 # via aiohttp diff --git a/resources/set_index.json b/resources/set_index.json index 075a358..180e6ce 100644 --- a/resources/set_index.json +++ b/resources/set_index.json @@ -6466,5 +6466,35 @@ "scryfall_code": "trk", "name": "Star Trek", "date": "2026-11-13" + }, + "1079": { + "p12e_code": 1079, + "scryfall_code": "amsh", + "name": "Marvel Super Heroes Art Series", + "date": "2026-06-26" + }, + "1080": { + "p12e_code": 1080, + "scryfall_code": "fmsc", + "name": "Marvel Super Heroes Jumpstart Front Cards", + "date": "2026-06-26" + }, + "1081": { + "p12e_code": 1081, + "scryfall_code": "tmsc", + "name": "Marvel Super Heroes Commander Tokens", + "date": "2026-06-26" + }, + "1082": { + "p12e_code": 1082, + "scryfall_code": "sds", + "name": "Stardates", + "date": "2026-11-20" + }, + "1083": { + "p12e_code": 1083, + "scryfall_code": "ttrk", + "name": "Star Trek Tokens", + "date": "2026-11-20" } } \ No newline at end of file diff --git a/resources/silver/training_data_archetypes/dpl_decks.csv b/resources/silver/training_data_archetypes/dpl_decks.csv index 58e561c..e1547b4 100644 --- a/resources/silver/training_data_archetypes/dpl_decks.csv +++ b/resources/silver/training_data_archetypes/dpl_decks.csv @@ -73,7 +73,6 @@ ko4xe4dfqpnd1plx6xscbgss,Altar Tron rpqew66585slfdl0kroty6mm,One Land Spy xhf85580k543rrbg868szb8p,One Land Spy bpn95hp5krl6lfwzkkoize1z,MonoR Tron -zv4t97pn6v6q0yrwtai3at4c,Brew q149w2bzex65u851eury8hvf,Brew gtqjvzc2tqd43mdjtinfhofr,Elves jrxw3szk4yg103e8ym9xshm3,Burn @@ -131,3 +130,51 @@ dcyzm7wx27wtdvf3880yi3qg,Esper Affinity vmb6bhuqxg3cjnco9cd2jmhr,Burn fmvc2rrp8v92yfud099o0qq0,Cat-Food Combo srj1j9efpizh3gaqqh1y7yie,Golgari Gardens +gaofBFhyILRpoQWOrYJFuLvEatd2,Spy Walls +2ebaPkr3S4M6za5LYjn5OQZvDlw1,Spy Walls +4SxREx8i42aZJhd3Vqngw8NT9bG3,MonoR Rally +HRzczTOaOQWz13Q6nf9S14hYqII3,Ruby Storm +Xopd3GyttdWVeaJPcGZXV0A7qi92,Spy Walls +6hVWhkOz1uXnX9db859Wk8ubeP43,Selesnya Gates +biuoEAg6P5O3ozzXka7cNGKFWYR2,Spy Walls +AT81NVr1HlVmMnXl4luvUorE8Zk1,Jeskai Ephemerate +E0NmWXOL1WV1kSD11m4XhxkjbAv2,Azorius Gates +kBX6yZadhyW9ajR7TyABLzbBDd43,Boros Bully +Cn8mL2l7xPQGPLu9uUOLoqeANF32,Izzet Terror +2Q3QynkzgbNVKAmrYcg2YDqGQyl1,Golgari Food Pestilence +k70Ar8wnHcRcDGN7hKwhV96S5ml2,Elves +mhhqO8qTuEOSmJVQ7eQDULAOzj82,Ruby Storm +vRDl5dUGhQRB9ckDjsZkt5I75gs2,MonoG Tron +CDpQeExwsOc91b2OrQ1MymZT1S42,Naya Gates +zv4t97pn6v6q0yrwtai3at4c,MonoR Dredge +tjk8b389roxaiwrvmoku287a,Goblins +xmmhd8ktbkaknkpzc1uqj8u4,Gruul Ponza +xv46gcmolfyosyczwv4oh92e,Gruul Ponza +qphwigiwvdiptokbs108hvu3,Gruul Ponza +rz7bi0b5i7uc1gdnyzw3pjz2,Altar Tron +nzfndqr5dym4u3xmqso5zj8l,Gruul Ponza +y13v0ddm6tg4gexp9f2uegxo,Gruul Ponza +jsez82a0nvhczv2oz80otzsp,Gruul Ponza +ltla6d7kn43lc4bqa0xggso7,Gruul Ponza +tnvziadhg7iqcss2728qz5x9,Gruul Ponza +ana3kxe4p5llfmcnoplm3jtz,Spy Walls +jqaa1xk6zwaipyh3qw5850u2,Spy Walls +na8zqq1v29wal1m7ywp25u6n,Spy Walls +d3yc9s540yr1ozqnnv33tx6n,Spy Walls +vacek7p71emeemswpfox2sh7,Spy Walls +lesicu1zcga4dhn3ewu0bsh7,Spy Walls +xz19dyp8splrgd57g1xye81w,Spy Walls +jzbenah1c8byq1vd1agwkxiw,Spy Walls +ilyma53pje7zdzr99qmt6td1,Spy Walls +s75fg3dcxhzuv1cx5nr635td,Spy Walls +opkqzjlb892850ingexlyx3r,Spy Walls +rvs5m9n3fu00y47nvs5amyeo,Spy Walls +cymc977gcsz43b3qvx985cly,Spy Walls +s11cbptjkgfljoqzbknb13eq,Spy Walls +gju6kg9aiyxm9rtgglfgb6fe,Spy Walls +comxbmbjkrrk6evsclnb7u53,Spy Walls +lk523p3507r7erodz64xfu2a,Spy Walls +rl3u7qu6epbr1qzuwg6dpuov,Spy Walls +b6yr1pjvx8a4g13774j538jd,Spy Walls +c8gon0xwc0olj8byfnqmmkp7,Spy Walls +zjkeeomxxh6d989eay52hr3c,Spy Walls diff --git a/tests/test_entities.py b/tests/test_entities.py index 2f0671e..612c6b3 100644 --- a/tests/test_entities.py +++ b/tests/test_entities.py @@ -28,7 +28,7 @@ def _make_archetype(**overrides): must_have_cards=[], must_not_have_cards=[], reference_decks=[], - resource_sideboard=None, + resource_sideboards=None, resources_discord=[], resources=[], staples=[], diff --git a/tests/test_playable.py b/tests/test_playable.py index 9a358a1..60a53de 100644 --- a/tests/test_playable.py +++ b/tests/test_playable.py @@ -30,13 +30,13 @@ def test_playable_deck_with_less_than_sixty_main(self): main_deck = data.DECK_MAIN[:-1] with self.assertRaises(ValueError): - PlayableDeck(main_deck, []) + PlayableDeck(main_deck, [], raise_error_if_invalid=True) def test_playable_deck_with_more_than_fifteen_side(self): side_deck = data.DECK_SIDE + [PlayedCard(4, "Fake Card")] with self.assertRaises(ValueError): - PlayableDeck(data.DECK_MAIN, side_deck) + PlayableDeck(data.DECK_MAIN, side_deck, raise_error_if_invalid=True) def test_playable_deck(self): pd = PlayableDeck(data.DECK_MAIN, data.DECK_SIDE)