104 lines
2.9 KiB
Python
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] |