diff options
author | 2021-10-21 22:29:54 -0400 | |
---|---|---|
committer | 2021-10-22 02:29:54 +0000 | |
commit | 93f8385fcaa543b7deb69e7c7740cd148be6297c (patch) | |
tree | e86c0d87b4009e4f26fbe45afcba71e985a0db6d | |
parent | Merge pull request #925 from python-discord/bump-pip-licenses (diff) |
Add WTF Python Command (#859)
* Add WTF Python Command
* Fix grammar in docstrings, remove redundant variable, remove the use of a wrapper
* Fix indentation issues and make use of triple quotes
* Update docstrings and remove redundant list()
* Change minimum certainty to 75.
* Make 'make_embed' function a non async function
* Try to unload WTFPython Extension if max fetch requests hit i.e. 3 else try to load the extension.
* Correct log messages.
* Make flake8 happy :D
* Remove redundant class attributes and async functions.
* Apply requested grammar and style changes.
* Fix unload and load extension logic.
* Fix typo in `WTF_PYTHON_RAW_URL`
* Changed fuzzy_wuzzy to rapidfuzz
Since rapidfuzz also has an extractOne method, this should be a
straight replacement with the import statement.
* Move wtf_python.py to bot/exts/utilities, flake8
Moved the file to the correct location after merge with main,
made changes from the last open suggestions from the previous PR,
had to make WTF lowercase to pass flake8 on lines 54 and 118.
* Fix trailing commas and long lines
* # This is a combination of 3 commits.
# This is the 1st commit message:
Squashing small commits
Small changes and fixes
-Added "the" to setup docstring
-Fixed typo for mis-matched WTF and wtf in get_wtf_python_readme
-Fixed ext location
-Added more information to fuzzy_match_header docstring regarding
the MINIMUM_CERTAINTY and what the score / value represents.
Add wildcard to capture unused return
Updated MINIMUM_CERTAINTY to 75
Change MINIMUM_CERTAINTY to 50
Squash commits from Bluenix suggestions
Fix docstring for fuzzy_match_header
Swap if / else for match
Fix functools import
Rename get_wtf_python_readme to fetch_readme
Collapse self.headers into one line
Fix docstring for fuzzy_match_header
Swap if / else for match
# This is the commit message #2:
Fix functools import
# This is the commit message #3:
Rename get_wtf_python_readme to fetch_readme
* Squashing commits
Squashing small commits
Small changes and fixes
-Added "the" to setup docstring
-Fixed typo for mis-matched WTF and wtf in get_wtf_python_readme
-Fixed ext location
-Added more information to fuzzy_match_header docstring regarding
the MINIMUM_CERTAINTY and what the score / value represents.
Add wildcard to capture unused return
Updated MINIMUM_CERTAINTY to 75
Change MINIMUM_CERTAINTY to 50
Squash commits from Bluenix suggestions
Fix docstring for fuzzy_match_header
Swap if / else for match
Fix functools import
Rename get_wtf_python_readme to fetch_readme
Collapse self.headers into one line
Fix docstring for fuzzy_match_header
Swap if / else for match
Fix functools import
Rename get_wtf_python_readme to fetch_readme
Collapse self.headers into one line
Fix type hints with dict
Add match comment for clarity
* Add debug logs, and send embed
* Add markdown file creation
Big change here is to create a .md file based on the matched header.
I save the raw text as a class attribute, then slice it based on the
index returned by the .find() method for the header, and the separator
"/n---/n".
* Move the list(map(str.strip , ...) to for loop
* Remove line
* Use StringIO for file creation
* Update file creation with StringIO
* Remove embed file preview
* chore: update wtf_python docstring
* chore: change regex to search, remove file preview
* feat: update caching as recommended
Minor fixes to import statements as well.
Co-authored-by: Bluenix2 <[email protected]>
* chore: remove logging statements
* feat: scheduled task for fetch_readme
* chore: fix hyperlink, remove dead code
* fix: capitalization clean up
* chore: remove unused code
* chore: remove more unused code
* feat: add light grey logo image in embed
* feat: add light grey image
* chore: remove debug log message
* feat: add found search result header
* feat: limit user query to 50 characters
* cleanup: remove debug logging
* fix: restructure if not match statement
Co-authored-by: Bluenix <[email protected]>
Co-authored-by: Shivansh-007 <[email protected]>
Co-authored-by: Shivansh-007 <[email protected]>
Co-authored-by: Bluenix2 <[email protected]>
Co-authored-by: Xithrius <[email protected]>
-rw-r--r-- | bot/exts/utilities/wtf_python.py | 126 | ||||
-rw-r--r-- | bot/resources/utilities/wtf_python_logo.jpg | bin | 0 -> 19481 bytes |
2 files changed, 126 insertions, 0 deletions
diff --git a/bot/exts/utilities/wtf_python.py b/bot/exts/utilities/wtf_python.py new file mode 100644 index 00000000..66a022d7 --- /dev/null +++ b/bot/exts/utilities/wtf_python.py @@ -0,0 +1,126 @@ +import logging +import random +import re +from typing import Optional + +import rapidfuzz +from discord import Embed, File +from discord.ext import commands, tasks + +from bot import constants +from bot.bot import Bot + +log = logging.getLogger(__name__) + +WTF_PYTHON_RAW_URL = "http://raw.githubusercontent.com/satwikkansal/wtfpython/master/" +BASE_URL = "https://github.com/satwikkansal/wtfpython" +LOGO_PATH = "./bot/resources/utilities/wtf_python_logo.jpg" + +ERROR_MESSAGE = f""" +Unknown WTF Python Query. Please try to reformulate your query. + +**Examples**: +```md +{constants.Client.prefix}wtf wild imports +{constants.Client.prefix}wtf subclass +{constants.Client.prefix}wtf del +``` +If the problem persists send a message in <#{constants.Channels.dev_contrib}> +""" + +MINIMUM_CERTAINTY = 55 + + +class WTFPython(commands.Cog): + """Cog that allows getting WTF Python entries from the WTF Python repository.""" + + def __init__(self, bot: Bot): + self.bot = bot + self.headers: dict[str, str] = {} + self.fetch_readme.start() + + @tasks.loop(minutes=60) + async def fetch_readme(self) -> None: + """Gets the content of README.md from the WTF Python Repository.""" + async with self.bot.http_session.get(f"{WTF_PYTHON_RAW_URL}README.md") as resp: + log.trace("Fetching the latest WTF Python README.md") + if resp.status == 200: + raw = await resp.text() + self.parse_readme(raw) + + def parse_readme(self, data: str) -> None: + """ + Parses the README.md into a dict. + + It parses the readme into the `self.headers` dict, + where the key is the heading and the value is the + link to the heading. + """ + # Match the start of examples, until the end of the table of contents (toc) + table_of_contents = re.search( + r"\[👀 Examples\]\(#-examples\)\n([\w\W]*)<!-- tocstop -->", data + )[0].split("\n") + + for header in list(map(str.strip, table_of_contents)): + match = re.search(r"\[▶ (.*)\]\((.*)\)", header) + if match: + hyper_link = match[0].split("(")[1].replace(")", "") + self.headers[match[0]] = f"{BASE_URL}/{hyper_link}" + + def fuzzy_match_header(self, query: str) -> Optional[str]: + """ + Returns the fuzzy match of a query if its ratio is above "MINIMUM_CERTAINTY" else returns None. + + "MINIMUM_CERTAINTY" is the lowest score at which the fuzzy match will return a result. + The certainty returned by rapidfuzz.process.extractOne is a score between 0 and 100, + with 100 being a perfect match. + """ + match, certainty, _ = rapidfuzz.process.extractOne(query, self.headers.keys()) + return match if certainty > MINIMUM_CERTAINTY else None + + @commands.command(aliases=("wtf", "WTF")) + async def wtf_python(self, ctx: commands.Context, *, query: str) -> None: + """ + Search WTF Python repository. + + Gets the link of the fuzzy matched query from https://github.com/satwikkansal/wtfpython. + Usage: + --> .wtf wild imports + """ + if len(query) > 50: + embed = Embed( + title=random.choice(constants.ERROR_REPLIES), + description=ERROR_MESSAGE, + colour=constants.Colours.soft_red, + ) + match = None + else: + match = self.fuzzy_match_header(query) + + if not match: + embed = Embed( + title=random.choice(constants.ERROR_REPLIES), + description=ERROR_MESSAGE, + colour=constants.Colours.soft_red, + ) + await ctx.send(embed=embed) + return + + embed = Embed( + title="WTF Python?!", + colour=constants.Colours.dark_green, + description=f"""Search result for '{query}': {match.split("]")[0].replace("[", "")} + [Go to Repository Section]({self.headers[match]})""", + ) + logo = File(LOGO_PATH, filename="wtf_logo.jpg") + embed.set_thumbnail(url="attachment://wtf_logo.jpg") + await ctx.send(embed=embed, file=logo) + + def cog_unload(self) -> None: + """Unload the cog and cancel the task.""" + self.fetch_readme.cancel() + + +def setup(bot: Bot) -> None: + """Load the WTFPython Cog.""" + bot.add_cog(WTFPython(bot)) diff --git a/bot/resources/utilities/wtf_python_logo.jpg b/bot/resources/utilities/wtf_python_logo.jpg Binary files differnew file mode 100644 index 00000000..851d7f9a --- /dev/null +++ b/bot/resources/utilities/wtf_python_logo.jpg |