paper-dynasty-discord/search_utils.py
Cal Corum ee80cd72ae fix: apply Black formatting and resolve ruff lint violations
Run Black formatter across 83 files and fix 1514 ruff violations:
- E722: bare except → typed exceptions (17 fixes)
- E711/E712/E721: comparison style fixes with noqa for SQLAlchemy (44 fixes)
- F841: unused variable assignments (70 fixes)
- F541/F401: f-string and import cleanup (1383 auto-fixes)

Remaining 925 errors are all F403/F405 (star imports) — structural,
requires converting to explicit imports in a separate effort.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:37:46 -05:00

108 lines
2.8 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]