paper-dynasty-discord/search_utils.py
Cal Corum 3debfd6e82 Catchup commit
Includes discord_ui refactor, testing overhaul, addition of
2025-07-22 09:22:19 -05:00

104 lines
2.9 KiB
Python

"""
Search Utilities
This module contains search and fuzzy matching functionality.
"""
import discord
from difflib import get_close_matches
from typing import Optional
def fuzzy_search(name, master_list):
"""
Perform fuzzy string matching against a list of options.
Args:
name: String to search for
master_list: List of strings to search against
Returns:
Best match string or raises ValueError if no good matches
"""
if name.lower() in master_list:
return name.lower()
great_matches = get_close_matches(name, master_list, cutoff=0.8)
if len(great_matches) == 1:
return great_matches[0]
elif len(great_matches) > 0:
matches = great_matches
else:
matches = get_close_matches(name, master_list, n=6)
if len(matches) == 1:
return matches[0]
if not matches:
raise ValueError(f'{name.title()} was not found')
return matches[0]
async def fuzzy_player_search(ctx, channel, bot, name, master_list):
"""
Interactive fuzzy player search with Discord UI.
Takes a name to search and returns the name of the best match.
Args:
ctx: discord context
channel: discord channel
bot: discord.py bot object
name: string to search for
master_list: list of names to search against
Returns:
Selected match or None if cancelled
"""
# Import here to avoid circular imports
from discord_ui.confirmations import Question
matches = fuzzy_search(name, master_list)
embed = discord.Embed(
title="Did You Mean...",
description='Enter the number of the card you would like to see.',
color=0x7FC600
)
count = 1
for x in matches:
embed.add_field(name=f'{count}', value=x, inline=False)
count += 1
embed.set_footer(text='These are the closest matches. Spell better if they\'re not who you want.')
this_q = Question(bot, channel, None, 'int', 45, embed=embed)
resp = await this_q.ask([ctx.author])
if not resp:
return None
if resp < count:
return matches[resp - 1]
else:
raise ValueError(f'{resp} is not a valid response.')
async def cardset_search(cardset: str, cardset_list: list) -> Optional[dict]:
"""
Search for a cardset by name and return the cardset data.
Args:
cardset: Cardset name to search for
cardset_list: List of available cardset names
Returns:
Cardset dictionary or None if not found
"""
# Import here to avoid circular imports
from api_calls import db_get
cardset_name = fuzzy_search(cardset, cardset_list)
if not cardset_name:
return None
c_query = await db_get('cardsets', params=[('name', cardset_name)])
if c_query['count'] == 0:
return None
return c_query['cardsets'][0]