From f56edd9b48a771c5a14b00bd3aa6b1bd731d458d Mon Sep 17 00:00:00 2001 From: thrly Date: Tue, 7 Oct 2025 20:15:36 +0100 Subject: [PATCH 1/8] Change request timeout to 5 seconds --- src/scry/request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scry/request.py b/src/scry/request.py index 72d95ac..3a0a064 100644 --- a/src/scry/request.py +++ b/src/scry/request.py @@ -15,7 +15,7 @@ def get_random_card(query: str) -> list: try: - res = requests.get(url + endpoint + clean_query, headers=headers, timeout=3) + res = requests.get(url + endpoint + clean_query, headers=headers, timeout=5) res.raise_for_status() card = res.json() From 2e2c8a64bb8ba14c3aa0eaddfcd8f8002adbec62 Mon Sep 17 00:00:00 2001 From: thrly Date: Tue, 7 Oct 2025 20:17:19 +0100 Subject: [PATCH 2/8] Redesign command interface to use argparse rather than argv; change entry point to main.py; update README to reflect new UX --- README.md | 18 ++-- pyproject.toml | 2 +- src/scry/cli.py | 221 +++++++++++++++++++++++++++++++++-------------- src/scry/main.py | 37 ++++++++ 4 files changed, 205 insertions(+), 73 deletions(-) create mode 100644 src/scry/main.py diff --git a/README.md b/README.md index 2fbd1cb..ad11b0b 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,18 @@ Clone and install with `pipx install scry` ## use -- Draw a random card and add it to your database with `scry random` -- Get a list of cards based on a scryfall [search query](https://scryfall.com/docs/syntax) and add them to your database: - - `scry list "set:blb"` returns unique cards from the Bloomburrow set and shows stats for that list. -- Request a list of set releases with: `scry setcodes` -- Return stats for your entire database: `scry stats` -- (Optional:) Clear your database: `scry clear` +- Request a reference list of set releases with: `scry setcodes` +- Get stats for a specific set: + - `scry set BLB` returns all cards from the _Bloomburrow_ set. +- Get stats for cards based on a scryfall [search query](https://scryfall.com/docs/syntax): + - `scry search id:orzhov type:land legal:modern` returns all unique Orzhov Land cards that are legal in Modern format, and shows stats for that list. +- Get help for cli commands with `scry --help` + +### local database + +Scry creates a local sqlite database and adds your queried cards to it. This means you can build a larger collection of cards by executing multiple searches, and then view stats for the entire database with `scry stats` + +In order to clear your database (for instance, to start a fresh collection to view stats on), run `scry clear` and confirm at the prompt. ## about diff --git a/pyproject.toml b/pyproject.toml index 45ad738..ceb739c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ readme = "README.md" # defines the command and script that will be used to run [project.scripts] -scry = "scry.cli:main" +scry = "scry.main:main" [project.urls] repository = "https://github.com/thrly/scry" diff --git a/src/scry/cli.py b/src/scry/cli.py index fbbbfb3..c9ee53d 100644 --- a/src/scry/cli.py +++ b/src/scry/cli.py @@ -1,11 +1,6 @@ -# add cards to db using scryfall -# query and return stats - - +import argparse from datetime import datetime -from sys import argv from . import ( - create_table, get_random_card, insert_cards, get_card_list, @@ -17,65 +12,163 @@ ) -def main(): +def build_arg_parser() -> argparse.ArgumentParser: + # setup parser and sub command parsers + parser = argparse.ArgumentParser( + description="🃏 Query cards from Scryfall and draw stats from a set.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=( + """ + Examples: + scry random -n 3 + scry search t:creature c:g + scry set BLB + """ + ), + ) + subparsers = parser.add_subparsers( + # dest="subcommand", + title="subcommands", + description="Basic scrying functions. Some require additional parameters.", + required=True, + ) + + # Define each subcommand: + # RANDOM ------------------------ + random_parser = subparsers.add_parser( + "random", + help="Draw random cards from Scryfall", + ) + random_parser.add_argument( + "-n", + "--number", + type=int, + default=1, + help="Number of random cards to draw", + ) + random_parser.set_defaults(func=handle_random) + + # SEARCH ------------------------ + # TODO: bypass this completely and just run with `scry ` + list_parser = subparsers.add_parser( + "search", help="Returns a list of cards matching search parameters" + ) + list_parser.add_argument( + "search_query", + nargs="+", + help="Argument as Scryfall-syntax search query (e.g. 't:creature+c:green')", + # TODO: is it possible to set a default value if no query arg is given? 't:land' etc. + ) + list_parser.set_defaults(func=handle_search) + + # SET ------------------------ + set_parser = subparsers.add_parser("set") + set_parser.add_argument( + "set_query", + help="Specify setcode (run `scry setcodes` for reference) or 'latest'", + ) + set_parser.set_defaults(func=handle_set) + + # SETCODES ------------------------ + setcodes_parser = subparsers.add_parser( + "setcodes", + help="Return list of sets with code, card total, and year of release", + ) + setcodes_parser.set_defaults(func=handle_setcodes) + + # STATS ----------------------- + stats_parser = subparsers.add_parser( + "stats", help="Return stats for current database" + ) + # TODO: Add additional optional args to filter search query: type, colour, set, etc. + # + # stats_parser.add_argument( + # "-s", "--set", help="search database for cards matching this setcode" + # ) + # stats_parser.add_argument( + # "-ct", "--card-type", help="search database for cards matching this type" + # ) + + stats_parser.set_defaults(func=handle_stats) + + # CLEAR ------------------------ + clear_parser = subparsers.add_parser("clear", help="Clear the database") + clear_parser.set_defaults(func=handle_clear) + + return parser + + +def handle_random(args): + if args.number == 1: + print("Drawing a random card from Scryfall.com...") + else: + print(f"Drawing {args.number} random cards from Scryfall.com...") + + query = "" # TODO: add optional search flag to random argparse + + # get a single random card, based on search parameters + connection = db_connect() + card = get_random_card(query) or [] + insert_cards(card, get_timestamp(), connection) + print(get_total_cards(connection), "cards currently in database.") + + +def handle_search(args): + query = " ".join(args.search_query) + print(f"Searching for cards matching: {query}") + connection = db_connect() - try: - create_table(connection) - - if len(argv) > 1: - # TODO: swap argv for argparse - req_type = argv[1] - # use argument inputs from CLI: random (single card) or list (multiple cards) - if req_type == "random": - # optional query argument for random card, otherwise no constraint - if 1 < len(argv) > 2: - query = argv[1] - else: - query = "" - # get a single random card, based on search parameters - card = get_random_card(query) or [] - insert_cards(card, get_timestamp(), connection) - print(get_total_cards(connection), "cards currently in database.") - - elif req_type == "list": - if len(argv) > 2: - search_param = argv[2] - card_list = get_card_list(search_param) or [] - stamp = get_timestamp() - insert_cards(card_list, stamp, connection) - print(get_total_cards(connection), "cards currently in database.") - print( - f"================================================\nSTATS for '{search_param}':" - ) - print_stats(connection, stamp) - - else: - print("Lists need a query parameter (i.e. 'color:black set:BLB')") - - elif req_type == "setcodes": - for set_code in set_codes(): - if set_code[3] == "expansion" or set_code[3] == "commander": - # extract year from YYYY-MM-DD - date = datetime.fromisoformat(set_code[2]) - print( - f"{set_code[0]} : {set_code[1]}\t{set_code[4]} cards\t{date.year}" - ) - elif req_type == "clear": - clear_database() - - elif req_type == "stats": - print( - "================================================\nSTATS for ALL cards in database:" - ) - print_stats(connection) - else: + card_list = get_card_list(query) or [] + stamp = get_timestamp() + insert_cards(card_list, stamp, connection) + print(get_total_cards(connection), "cards currently in database.") + print( + f"================================================\nSTATS for '{args.search_query}':" + ) + print_stats(connection, stamp) + + +def handle_set(args): + # Search for a set of cards + connection = db_connect() + + if args.set_query.lower() == "latest": + print("Finding the latest set...") + # TODO: find out how to find the latest set... + else: + print(f"Stats for set {args.set_query.upper()}:") + + query = f"set:{args.set_query}" + card_list = get_card_list(query) or [] + stamp = get_timestamp() + # HACK: since we know its a set, we could just query sets directly from scryfall? + insert_cards(card_list, stamp, connection) + print_stats(connection, stamp) + + +def handle_setcodes(args): + print("All main and commander MTG expansions:") + + for set_code in set_codes(): + if set_code[3] == "expansion" or set_code[3] == "commander": + # extract year from YYYY-MM-DD + date = datetime.fromisoformat(set_code[2]) print( - "No valid search parameters. Try `scry random` or `scry list ''" + f"{set_code[0].upper(): <5} {set_code[1]:<40} {set_code[4]:>6} cards {date.year:>10}" ) - except Exception as err: - print("Error in __main__: ", err) - finally: - connection.close() # finally close db connection + + +def handle_stats(args): + print("STATS for ALL cards in database:") + connection = db_connect() + print_stats(connection) + + +def handle_clear(args): + clear_database() + + +# Helper functions: def print_stats(connection, timestamp=None): @@ -86,7 +179,3 @@ def print_stats(connection, timestamp=None): def get_timestamp(): return datetime.now() - - -if __name__ == "__main__": - main() diff --git a/src/scry/main.py b/src/scry/main.py new file mode 100644 index 0000000..d4b98f3 --- /dev/null +++ b/src/scry/main.py @@ -0,0 +1,37 @@ +# Main entry point for SCRY: a command-line scryfall query tool +# by thrly + + +from . import ( + create_table, + db_connect, +) +from .cli import ( + build_arg_parser, +) + + +def main(argv=None): + # setup argument parsing (argv for testing) + parser = build_arg_parser() + args = parser.parse_args(argv) + + connection = db_connect() + # HACK: we're creating the connection twice: once here, and again in + # each of the cli handler functions... this is going to cause a problem... + + try: + # setup / connect to local database + create_table(connection) + + # execute commands from cli arguments (see cli.py for handling) + args.func(args) + + except Exception as err: + print("Error in __main__: ", err) + finally: + connection.close() # finally close db connection + + +if __name__ == "__main__": + main() From 92b47afc3e6a10269ced77bcfde82195d8e8627a Mon Sep 17 00:00:00 2001 From: thrly Date: Wed, 8 Oct 2025 13:52:32 +0100 Subject: [PATCH 3/8] Remove print when adding cards to db --- src/scry/db_insert.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/scry/db_insert.py b/src/scry/db_insert.py index 9fe6705..1815f7a 100644 --- a/src/scry/db_insert.py +++ b/src/scry/db_insert.py @@ -17,11 +17,6 @@ def insert_cards(cards: list, timestamp: datetime, connection) -> int: cursor.executemany(insert_query, rows) connection.commit() - if len(cards) > 1: - print(f"Added {len(cards)} cards into database.") - else: - print(f"Added '{cards[0]['name']}' into database.") - return len(cards) except Exception as err: print(f"Error occured talking to database: {err}") From ef67ed5cc622613273328df21835795bc4a8267d Mon Sep 17 00:00:00 2001 From: thrly Date: Wed, 8 Oct 2025 13:53:40 +0100 Subject: [PATCH 4/8] Find current set release and use dict for populating setcodes rather than list --- src/scry/request.py | 63 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/src/scry/request.py b/src/scry/request.py index 3a0a064..71557f3 100644 --- a/src/scry/request.py +++ b/src/scry/request.py @@ -1,3 +1,4 @@ +from datetime import datetime import requests from time import sleep import urllib.parse @@ -8,6 +9,9 @@ # NOTE: scryfall returns an 'object : card/list` which could be used to detemine how to display/add single/lists of cards +################# +# Return a random card (optional search parameters) + def get_random_card(query: str) -> list: clean_query = urllib.parse.quote(query) @@ -39,6 +43,10 @@ def get_random_card(query: str) -> list: return [] +################# +# Return list of cards based on search query + + def get_card_list(query: str) -> list: clean_query = urllib.parse.quote(query) @@ -106,6 +114,40 @@ def show_warnings(res): print(f"WARNING [LIST REQ]: {warnings}") +###################### +# Retreive List of Set Releases + + +def check_date_past(date_to_check) -> str: + # check the release date against today's date to see if its past or future + date_to_check = datetime.date(datetime.fromisoformat(date_to_check)) + current_date = datetime.date(datetime.today()) + if current_date >= date_to_check: + return "Past" + else: + return "Future" + + +def is_current_release(date_A: datetime, date_B: datetime) -> str: + if check_date_past(date_A) == "Future" and check_date_past(date_B) == "Past": + return "*" + else: + return "-" + + +def find_current_release(setlist: list) -> dict: + for i, item in enumerate(setlist): + if i > 0: + check = is_current_release( + setlist[i - 1]["release_date"], setlist[i]["release_date"] + ) + if check == "*": + return dict(item) + + print("Current release not found") + return {} + + def set_codes() -> list: endpoint = "/sets" @@ -127,15 +169,18 @@ def set_codes() -> list: # TODO: like the card_transform, this would be better to define as a dict, rather than a list for set_info in setlist_data: - setlist.append( - [ - set_info.get("code"), - set_info.get("name"), - set_info.get("released_at"), - set_info.get("set_type"), - set_info.get("card_count"), - ] - ) + released = set_info.get("released_at") + set_type = set_info.get("set_type") + if set_type == "expansion" or set_type == "commander": + setlist.append( + { + "set_code": set_info.get("code").upper(), + "name": set_info.get("name"), + "release_date": released, + # "set_type": set_info.get("set_type"), + "card_count": set_info.get("card_count"), + } + ) return setlist else: print( From cfe497b58f5bfc11e39c0a1c2ab08151856911b8 Mon Sep 17 00:00:00 2001 From: thrly Date: Wed, 8 Oct 2025 13:54:37 +0100 Subject: [PATCH 5/8] Add colour distribution chart; Fix duplicate expensive cards --- src/scry/db_queries.py | 53 +++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/scry/db_queries.py b/src/scry/db_queries.py index 06a497d..279d570 100644 --- a/src/scry/db_queries.py +++ b/src/scry/db_queries.py @@ -23,7 +23,7 @@ def db_stats(connection, stamp=None) -> list: # print("timestamp_query: ", timestamp_query) total_cards = get_total_cards(connection, stamp) - stats.append(f"Total cards: {total_cards}") + # stats.append(f"Stats for {total_cards} cards") cursor = connection.cursor() @@ -32,22 +32,40 @@ def db_stats(connection, stamp=None) -> list: f"SELECT cmc, COUNT(*) as Mana FROM cards {timestamp_query} GROUP BY cmc" ) curve = cursor.fetchall() - stats.append(f"\n## MANA CURVE\n{chart_data(curve, total_cards)}") + stats.append(f"\nMANA CURVE\n{chart_data(curve, total_cards)}") + + # Colour distribution + cursor.execute( + f"""SELECT + value as color_identity, + COUNT(*) AS color_count + FROM cards, + json_each(cards.color_identity) {timestamp_query} + GROUP BY value + ORDER BY color_count DESC + """ + ) + + curve = cursor.fetchall() + coloured_results = [[scryfall_colours(id), count] for id, count in curve] + + stats.append( + f"\nCOLOUR DISTRIBUTION\n{chart_data(coloured_results, total_cards)}" + ) # Tally of card types cursor.execute( report_card_types(timestamp_query)[0], report_card_types(timestamp_query)[1] ) curve = cursor.fetchall() - stats.append(f"## CARD TYPES\n{chart_data(curve, total_cards)}") + stats.append(f"CARD TYPES\n{chart_data(curve, total_cards)}") # Prices: highest and average - stats.append("## PRICES\n") + stats.append("PRICES\n") stats.append( - f" Average Price is {report_prices(cursor,timestamp_query)[1]} EUR" + f" Average Price is {report_prices(cursor,timestamp_query)[1]} EUR\n" ) stats.append("\n".join(report_prices(cursor, timestamp_query)[0])) - stats.append("\n===========================\n") return stats @@ -129,13 +147,25 @@ def report_prices(cursor, timestamp_query: str): # available (not always), they should also be included and aaveraged, though it might # skew the hightest prices? cursor.execute( - f"SELECT name, CAST(json_extract(price,'$.eur') AS REAL) AS price FROM cards {timestamp_query} ORDER BY price DESC LIMIT 3" + f"SELECT name, CAST(json_extract(price,'$.eur') AS REAL) AS price FROM cards {timestamp_query} ORDER BY price DESC LIMIT 9" ) highest_price = cursor.fetchall() top_prices = [] top_prices.append(" Most expensive cards:") - for i, val in enumerate(highest_price): - top_prices.append(f" {i+1}. '{val[0]}' at {round(val[1],2)} EUR") + # check for duplicate cards appearing in expensive list + # this happens when variation prints are equally sought after + # do not append duplicate cards to the top + + top_price_dict = {} + for item in highest_price: + if item[0] not in top_price_dict.keys(): + top_price_dict[item[0]] = item[1] + + for card, price in top_price_dict.items(): + card_price_info = f" - {card:<35} {round(price,2):>10} EUR" + top_prices.append(card_price_info) + if len(top_prices) == 4: # stop after three top prices + 1 for heading + break cursor.execute( f"SELECT AVG(CAST(json_extract(price,'$.eur') AS REAL)) FROM cards {timestamp_query}" @@ -143,3 +173,8 @@ def report_prices(cursor, timestamp_query: str): average_price = cursor.fetchone()[0] return top_prices, round(average_price, 2) + + +def scryfall_colours(reference: str) -> str: + colour_codes = {"R": "Red", "G": "Green", "U": "Blue", "B": "Black", "W": "White"} + return colour_codes.get(reference, "Unknown") From 3db5698e40ea675edbb03f5d7a70b7f34163062b Mon Sep 17 00:00:00 2001 From: thrly Date: Wed, 8 Oct 2025 13:55:31 +0100 Subject: [PATCH 6/8] Update handler functions and pass single db connection from main via args --- src/scry/cli.py | 119 +++++++++++++++++++++++++++++------------------ src/scry/main.py | 8 ++-- 2 files changed, 78 insertions(+), 49 deletions(-) diff --git a/src/scry/cli.py b/src/scry/cli.py index c9ee53d..93adb7d 100644 --- a/src/scry/cli.py +++ b/src/scry/cli.py @@ -1,5 +1,7 @@ import argparse from datetime import datetime + +from scry.request import find_current_release from . import ( get_random_card, insert_cards, @@ -8,21 +10,21 @@ get_total_cards, clear_database, set_codes, - db_connect, ) def build_arg_parser() -> argparse.ArgumentParser: # setup parser and sub command parsers parser = argparse.ArgumentParser( - description="🃏 Query cards from Scryfall and draw stats from a set.", + description="🃏 Stats for card sets from Scryfall.", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=( """ Examples: - scry random -n 3 - scry search t:creature c:g + scry setlist scry set BLB + scry set latest + scry search t:creature c:green legal:modern """ ), ) @@ -56,7 +58,7 @@ def build_arg_parser() -> argparse.ArgumentParser: list_parser.add_argument( "search_query", nargs="+", - help="Argument as Scryfall-syntax search query (e.g. 't:creature+c:green')", + help="Arguments as Scryfall-syntax search query (e.g. 't:creature c:green')", # TODO: is it possible to set a default value if no query arg is given? 't:land' etc. ) list_parser.set_defaults(func=handle_search) @@ -65,16 +67,16 @@ def build_arg_parser() -> argparse.ArgumentParser: set_parser = subparsers.add_parser("set") set_parser.add_argument( "set_query", - help="Specify setcode (run `scry setcodes` for reference) or 'latest'", + help="Specify setcode (run `scry setlist` for reference) or 'latest'", ) set_parser.set_defaults(func=handle_set) - # SETCODES ------------------------ - setcodes_parser = subparsers.add_parser( - "setcodes", + # SETLIST ------------------------ + setlist_parser = subparsers.add_parser( + "setlist", help="Return list of sets with code, card total, and year of release", ) - setcodes_parser.set_defaults(func=handle_setcodes) + setlist_parser.set_defaults(func=handle_setlist) # STATS ----------------------- stats_parser = subparsers.add_parser( @@ -98,7 +100,12 @@ def build_arg_parser() -> argparse.ArgumentParser: return parser -def handle_random(args): +################ +# Command handlers +# + + +def handle_random(args, db_connection): if args.number == 1: print("Drawing a random card from Scryfall.com...") else: @@ -107,64 +114,75 @@ def handle_random(args): query = "" # TODO: add optional search flag to random argparse # get a single random card, based on search parameters - connection = db_connect() card = get_random_card(query) or [] - insert_cards(card, get_timestamp(), connection) - print(get_total_cards(connection), "cards currently in database.") + insert_cards(card, get_timestamp(), db_connection) + print(get_total_cards(db_connection), "cards currently in database.") -def handle_search(args): +def handle_search(args, db_connection): query = " ".join(args.search_query) print(f"Searching for cards matching: {query}") - connection = db_connect() card_list = get_card_list(query) or [] stamp = get_timestamp() - insert_cards(card_list, stamp, connection) - print(get_total_cards(connection), "cards currently in database.") - print( - f"================================================\nSTATS for '{args.search_query}':" - ) - print_stats(connection, stamp) + insert_cards(card_list, stamp, db_connection) + # print(get_total_cards(db_connection), "cards currently in database.") + print(f"{len(card_list)} cards found.") + print_stats(db_connection, stamp) -def handle_set(args): +def handle_set(args, db_connection): # Search for a set of cards - connection = db_connect() - + connection = db_connection + query_setcode = "" if args.set_query.lower() == "latest": - print("Finding the latest set...") - # TODO: find out how to find the latest set... + # Find the moce recent release and query stats for it + current_set = find_current_release(set_codes()) + current_set_code = current_set.get("set_code") + query_setcode = str(current_set_code) + current_set_name = current_set.get("name") + print(f"Stats for {current_set_name} ({current_set_code}):") else: - print(f"Stats for set {args.set_query.upper()}:") + query_setcode = str(args.set_query) + print(f"Stats for {lookup_set_info("name", args.set_query.upper())}") + + query = f"set:{query_setcode} unique:prints" # unique:prints includes variations within set + + print(f" Released: {lookup_set_info("release_date", query_setcode.upper())}") + + print(f" {lookup_set_info("card_count", query_setcode.upper())} cards in set") - query = f"set:{args.set_query}" card_list = get_card_list(query) or [] stamp = get_timestamp() - # HACK: since we know its a set, we could just query sets directly from scryfall? + insert_cards(card_list, stamp, connection) print_stats(connection, stamp) -def handle_setcodes(args): - print("All main and commander MTG expansions:") - - for set_code in set_codes(): - if set_code[3] == "expansion" or set_code[3] == "commander": - # extract year from YYYY-MM-DD - date = datetime.fromisoformat(set_code[2]) - print( - f"{set_code[0].upper(): <5} {set_code[1]:<40} {set_code[4]:>6} cards {date.year:>10}" - ) +def handle_setlist(args, db_connection): + print("All Main and Commander MTG expansion sets:\n") + setlist = set_codes() + current_set = find_current_release(setlist) + for set_info in setlist: + print( + format_set_info(set_info), + end="", + ) + if set_info == current_set: + print(" <- current release") + else: + print() -def handle_stats(args): +def handle_stats(args, db_connection): print("STATS for ALL cards in database:") - connection = db_connect() - print_stats(connection) + print(get_total_cards(db_connection), "cards in database") + print_stats(db_connection) -def handle_clear(args): +def handle_clear(args, db_connection): + # HACK: why does this only work with db_connection and args, even though neither + # are required? Same with handle_setlist... clear_database() @@ -177,5 +195,18 @@ def print_stats(connection, timestamp=None): print(s) +def format_set_info(set_details) -> str: + date = datetime.fromisoformat(set_details["release_date"]) + return f"{set_details["set_code"]: <5} {set_details["name"]:<38} {set_details["card_count"]:>6} cards {date.year:>10}" + + +def lookup_set_info(info: str, set_code: str) -> str: + setlist = set_codes() + for s in setlist: + if set_code == s["set_code"]: + return s[info] + return "Set info not found. Check the setcode is correct. You can request name, card_count, release_date" + + def get_timestamp(): return datetime.now() diff --git a/src/scry/main.py b/src/scry/main.py index d4b98f3..4f350d8 100644 --- a/src/scry/main.py +++ b/src/scry/main.py @@ -12,20 +12,18 @@ def main(argv=None): + connection = db_connect() + # setup argument parsing (argv for testing) parser = build_arg_parser() args = parser.parse_args(argv) - connection = db_connect() - # HACK: we're creating the connection twice: once here, and again in - # each of the cli handler functions... this is going to cause a problem... - try: # setup / connect to local database create_table(connection) # execute commands from cli arguments (see cli.py for handling) - args.func(args) + args.func(args, connection) except Exception as err: print("Error in __main__: ", err) From 5594564a0a9a45e3a0f7b647c45b6ddb4aab63d4 Mon Sep 17 00:00:00 2001 From: thrly Date: Wed, 8 Oct 2025 13:56:03 +0100 Subject: [PATCH 7/8] Update README with cli commands --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ad11b0b..92ade47 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,19 @@ Clone and install with `pipx install scry` ## use -- Request a reference list of set releases with: `scry setcodes` +- Request a reference list of set releases with: `scry setlist` - Get stats for a specific set: - - `scry set BLB` returns all cards from the _Bloomburrow_ set. + - `scry set BLB` returns all cards from the _Bloomburrow_ set + - `scry set latest` finds the most recent release. - Get stats for cards based on a scryfall [search query](https://scryfall.com/docs/syntax): - `scry search id:orzhov type:land legal:modern` returns all unique Orzhov Land cards that are legal in Modern format, and shows stats for that list. -- Get help for cli commands with `scry --help` +- Get help with `scry --help` ### local database Scry creates a local sqlite database and adds your queried cards to it. This means you can build a larger collection of cards by executing multiple searches, and then view stats for the entire database with `scry stats` -In order to clear your database (for instance, to start a fresh collection to view stats on), run `scry clear` and confirm at the prompt. +To clear your database (for instance, to start a fresh collection to view stats on), run `scry clear` and confirm at the prompt. ## about From 5245d8e2e5c5a925061d9e512298f515caccd5f8 Mon Sep 17 00:00:00 2001 From: thrly Date: Wed, 8 Oct 2025 14:10:13 +0100 Subject: [PATCH 8/8] No longer printing when cards added; assertion removed. --- tests/test_db.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test_db.py b/tests/test_db.py index a5d19ff..945d2f9 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -5,7 +5,7 @@ from tests.sample_card import sample_card -def test_card_insert_and_get(capfd): +def test_card_insert_and_get(): connection = sqlite3.connect("./tests/tests.db") try: @@ -14,10 +14,6 @@ def test_card_insert_and_get(capfd): assert insert_cards([sample_card()], datetime.datetime.now(), connection) == 1 # this should return 1 (the single card added) - # check that insert cards writes "Added" message to stdout: - captured = capfd.readouterr() - assert captured.out == "Added 'Llanowar Elves' into database.\n" - # pull first row from test db, then check that it is Llanowar cursor = connection.cursor() cursor.execute("SELECT * FROM cards")