Finished v2 of deck_builder, should be largely functional, but could use refinements. WIll continue to work on it, but largely satisfied with how it works.

This commit is contained in:
matt 2025-01-17 17:04:02 -08:00
parent 3fc3c584a4
commit 1c7436f33d
9 changed files with 83 additions and 60 deletions

BIN
README.md

Binary file not shown.

View file

@ -8,12 +8,12 @@ import time
from functools import lru_cache from functools import lru_cache
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Union
import inquirer.prompt # type: ignore import inquirer.prompt
import keyboard # type: ignore import keyboard
import pandas as pd # type: ignore import pandas as pd
import pprint # type: ignore import pprint
from fuzzywuzzy import process # type: ignore from fuzzywuzzy import process
from tqdm import tqdm # type: ignore from tqdm import tqdm
from settings import ( from settings import (
BASIC_LANDS, CARD_TYPES, CSV_DIRECTORY, multiple_copy_cards, DEFAULT_NON_BASIC_LAND_SLOTS, BASIC_LANDS, CARD_TYPES, CSV_DIRECTORY, multiple_copy_cards, DEFAULT_NON_BASIC_LAND_SLOTS,
@ -79,7 +79,7 @@ from type_definitions import (
# Try to import scrython and price_checker # Try to import scrython and price_checker
try: try:
import scrython # type: ignore import scrython
from price_check import PriceChecker from price_check import PriceChecker
use_scrython = True use_scrython = True
except ImportError: except ImportError:
@ -2485,6 +2485,7 @@ class DeckBuilder:
else: else:
print() print()
logger.info(f"Successfully filled deck to {final_count} cards in {attempts} attempts") logger.info(f"Successfully filled deck to {final_count} cards in {attempts} attempts")
def main(): def main():
"""Main entry point for deck builder application.""" """Main entry point for deck builder application."""
build_deck = DeckBuilder() build_deck = DeckBuilder()

View file

@ -5,7 +5,7 @@ from __future__ import annotations
import logging import logging
from typing import Any, List, Optional, Tuple, Union from typing import Any, List, Optional, Tuple, Union
import inquirer.prompt # type: ignore import inquirer.prompt
from settings import ( from settings import (
COLORS, COLOR_ABRV, DEFAULT_MAX_CARD_PRICE, COLORS, COLOR_ABRV, DEFAULT_MAX_CARD_PRICE,
DEFAULT_MAX_DECK_PRICE, DEFAULT_THEME_TAGS, MONO_COLOR_MAP, DEFAULT_MAX_DECK_PRICE, DEFAULT_THEME_TAGS, MONO_COLOR_MAP,

51
main.py
View file

@ -8,11 +8,11 @@ from pathlib import Path
from typing import NoReturn, Optional from typing import NoReturn, Optional
# Third-party imports # Third-party imports
import inquirer.prompt # type: ignore import inquirer.prompt
# Local imports # Local imports
import deck_builder
import setup import setup
import card_info
import tagger import tagger
"""Command-line interface for the MTG Python Deckbuilder application. """Command-line interface for the MTG Python Deckbuilder application.
@ -38,12 +38,11 @@ logger = logging.getLogger(__name__)
# Menu constants # Menu constants
MENU_SETUP = 'Setup' MENU_SETUP = 'Setup'
MENU_BUILD_DECK = 'Build a Deck'
MENU_CARD_INFO = 'Get Card Info'
MAIN_TAG = 'Tag CSV Files' MAIN_TAG = 'Tag CSV Files'
MENU_BUILD_DECK = 'Build a Deck'
MENU_QUIT = 'Quit' MENU_QUIT = 'Quit'
MENU_CHOICES = [MENU_SETUP, MENU_BUILD_DECK, MENU_CARD_INFO, MAIN_TAG, MENU_QUIT] MENU_CHOICES = [MENU_SETUP, MAIN_TAG, MENU_BUILD_DECK, MENU_QUIT]
def get_menu_choice() -> Optional[str]: def get_menu_choice() -> Optional[str]:
"""Display the main menu and get user choice. """Display the main menu and get user choice.
@ -64,44 +63,12 @@ def get_menu_choice() -> Optional[str]:
carousel=True) carousel=True)
] ]
try: try:
answer = inquirer.prompt(question) # type: ignore answer = inquirer.prompt(question)
return answer['menu'] if answer else None return answer['menu'] if answer else None
except (KeyError, TypeError) as e: except (KeyError, TypeError) as e:
logger.error(f"Error getting menu choice: {e}") logger.error(f"Error getting menu choice: {e}")
return None return None
def handle_card_info() -> None:
"""Handle the card info menu option with proper error handling.
Provides an interface for looking up card information repeatedly until the user
chooses to stop. Handles potential errors from card info lookup and user input.
Returns:
None
Example:
>>> handle_card_info()
Enter card name: Lightning Bolt
[Card info displayed]
Would you like to look up another card? [y/N]: n
"""
try:
while True:
card_info.get_card_info()
question = [
inquirer.Confirm('continue',
message='Would you like to look up another card?')
]
try:
answer = inquirer.prompt(question) # type: ignore
if not answer or not answer['continue']:
break
except (KeyError, TypeError) as e:
logger.error(f"Error in card info continuation prompt: {e}")
break
except Exception as e:
logger.error(f"Error in card info handling: {e}")
def run_menu() -> NoReturn: def run_menu() -> NoReturn:
"""Main menu loop with improved error handling and logger. """Main menu loop with improved error handling and logger.
@ -141,14 +108,10 @@ def run_menu() -> NoReturn:
match choice: match choice:
case 'Setup': case 'Setup':
setup.setup() setup.setup()
tagger.run_tagging()
case 'Build a Deck':
logger.info("Deck building not yet implemented")
print('Deck building not yet implemented')
case 'Get Card Info':
handle_card_info()
case 'Tag CSV Files': case 'Tag CSV Files':
tagger.run_tagging() tagger.run_tagging()
case 'Build a Deck':
deck_builder.main()
case 'Quit': case 'Quit':
logger.info("Exiting application") logger.info("Exiting application")
sys.exit(0) sys.exit(0)

44
main.spec Normal file
View file

@ -0,0 +1,44 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['C:\\Users\\Matt\\mtg_python\\mtg_python_deckbuilder\\main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='main',
)

13
mypy.ini Normal file
View file

@ -0,0 +1,13 @@
[mypy]
python_version = 3.10
strict = True
ignore_missing_imports = True
[mypy-inquirer.*]
ignore_missing_imports = True
[mypy-fuzzywuzzy.*]
ignore_missing_imports = True
[mypy-IPython.*]
ignore_missing_imports = True

View file

@ -1,8 +1,9 @@
pandas>=1.5.0 pandas>=1.5.0
inquirer>=3.1.3 inquirer>=3.1.3
typing-extensions>=4.5.0 typing_extensions>=4.5.0
fuzzywuzzy>=0.18.0
python-Levenshtein>=0.12.0
# Development dependencies # Development dependencies
mypy>=1.3.0 mypy>=1.3.0
pandas-stubs>=2.0.0 pandas-stubs>=2.0.0
types-inquirer>=3.1.3

View file

@ -1,5 +1,3 @@
from __future__ import annotations
"""MTG Python Deckbuilder setup module. """MTG Python Deckbuilder setup module.
This module provides the main setup functionality for the MTG Python Deckbuilder This module provides the main setup functionality for the MTG Python Deckbuilder
@ -17,6 +15,8 @@ The module works in conjunction with setup_utils.py for utility functions and
exceptions.py for error handling. exceptions.py for error handling.
""" """
from __future__ import annotations
# Standard library imports # Standard library imports
import logging import logging
from enum import Enum from enum import Enum
@ -49,6 +49,7 @@ from exceptions import (
DataFrameProcessingError, DataFrameProcessingError,
MTGJSONDownloadError MTGJSONDownloadError
) )
# Create logs directory if it doesn't exist # Create logs directory if it doesn't exist
if not os.path.exists('logs'): if not os.path.exists('logs'):
os.makedirs('logs') os.makedirs('logs')

View file

@ -7,10 +7,10 @@ import re
from typing import Union from typing import Union
# Third-party imports # Third-party imports
import pandas as pd # type: ignore import pandas as pd
import settings # type: ignore import settings
import tag_utils # type: ignore import tag_utils
# Local application imports # Local application imports
from settings import CSV_DIRECTORY, multiple_copy_cards, num_to_search, triggers from settings import CSV_DIRECTORY, multiple_copy_cards, num_to_search, triggers