diff --git a/sopel/builtins/dice.py b/sopel/builtins/dice.py index 40f0bfde7..bdfefd550 100644 --- a/sopel/builtins/dice.py +++ b/sopel/builtins/dice.py @@ -244,7 +244,7 @@ def _roll_dice(dice_match: re.Match[str]) -> DicePouch: @plugin.example(".roll 2d10+3", user_help=True) @plugin.example(".roll 1d6", user_help=True) @plugin.output_prefix('[dice] ') -def roll(bot: SopelWrapper, trigger: Trigger): +def roll(bot: SopelWrapper, trigger: Trigger) -> None: """Rolls dice and reports the result. The dice roll follows this format: XdY[vZ][+N][#COMMENT] diff --git a/sopel/builtins/safety.py b/sopel/builtins/safety.py index 0522f54bf..bf47e7d6f 100644 --- a/sopel/builtins/safety.py +++ b/sopel/builtins/safety.py @@ -56,7 +56,7 @@ class SafetySection(types.StaticSection): """Optional hosts-file formatted domain blocklist to use instead of StevenBlack's.""" -def configure(settings: Config): +def configure(settings: Config) -> None: """ | name | example | purpose | | ---- | ------- | ------- | @@ -90,7 +90,7 @@ def configure(settings: Config): ) -def setup(bot: Sopel): +def setup(bot: Sopel) -> None: bot.settings.define_section("safety", SafetySection) if bot.settings.safety.default_mode is None: @@ -166,7 +166,7 @@ def download_domain_list(bot: Sopel, path: str) -> bool: return True -def update_local_cache(bot: Sopel, init: bool = False): +def update_local_cache(bot: Sopel, init: bool = False) -> None: """Download the current malware domain list and load it into memory. :param init: Load the file even if it's unchanged @@ -202,7 +202,7 @@ def update_local_cache(bot: Sopel, init: bool = False): bot.memory[SAFETY_CACHE_LOCAL_KEY] = unsafe_domains -def shutdown(bot: Sopel): +def shutdown(bot: Sopel) -> None: bot.memory.pop(SAFETY_CACHE_KEY, None) bot.memory.pop(SAFETY_CACHE_LOCAL_KEY, None) bot.memory.pop(SAFETY_CACHE_LOCK_KEY, None) @@ -211,7 +211,7 @@ def shutdown(bot: Sopel): @plugin.rule(r'(?u).*(https?://\S+).*') @plugin.priority('high') @plugin.output_prefix(PLUGIN_OUTPUT_PREFIX) -def url_handler(bot: SopelWrapper, trigger: Trigger): +def url_handler(bot: SopelWrapper, trigger: Trigger) -> None: """Checks for malicious URLs.""" mode = bot.db.get_channel_value( trigger.sender, @@ -365,7 +365,7 @@ def virustotal_lookup( @plugin.example(".virustotal https://malware.wicar.org/") @plugin.example(".virustotal hxxps://malware.wicar.org/") @plugin.output_prefix("[safety][VirusTotal] ") -def vt_command(bot: SopelWrapper, trigger: Trigger): +def vt_command(bot: SopelWrapper, trigger: Trigger) -> None: """Look up VT results on demand.""" if not bot.settings.safety.vt_api_key: bot.reply("Sorry, I don't have a VirusTotal API key configured.") @@ -421,7 +421,7 @@ def vt_command(bot: SopelWrapper, trigger: Trigger): @plugin.command('safety') @plugin.example(".safety on") @plugin.output_prefix(PLUGIN_OUTPUT_PREFIX) -def toggle_safety(bot: SopelWrapper, trigger: Trigger): +def toggle_safety(bot: SopelWrapper, trigger: Trigger) -> None: """Set safety setting for channel.""" if not trigger.admin and bot.channels[trigger.sender].privileges[trigger.nick] < plugin.OP: bot.reply('Only channel operators can change safety settings') @@ -455,7 +455,7 @@ def toggle_safety(bot: SopelWrapper, trigger: Trigger): # Clean the cache every day # Code above also calls this if there are too many cache entries @plugin.interval(24 * 60 * 60) -def _clean_cache(bot: Sopel): +def _clean_cache(bot: Sopel) -> None: """Cleans up old entries in URL safety cache.""" update_local_cache(bot) diff --git a/sopel/builtins/units.py b/sopel/builtins/units.py index 02316339a..31b61e634 100644 --- a/sopel/builtins/units.py +++ b/sopel/builtins/units.py @@ -9,10 +9,16 @@ from __future__ import annotations import re +from typing import Pattern, TYPE_CHECKING from sopel import plugin +if TYPE_CHECKING: + from sopel.bot import SopelWrapper + from sopel.trigger import Trigger + + PLUGIN_OUTPUT_PREFIX = '[units] ' find_temp = re.compile(r'(-?[0-9]*\.?[0-9]*)[ °]*(K|C|F)', re.IGNORECASE) @@ -20,23 +26,23 @@ find_mass = re.compile(r'([0-9]*\.?[0-9]*)[ ]*(lb|lbm|pound[s]?|ounce|oz|(?:kilo|)gram(?:me|)[s]?|[k]?g)', re.IGNORECASE) -def f_to_c(temp): +def f_to_c(temp: float) -> float: return (float(temp) - 32) * 5 / 9 -def c_to_k(temp): +def c_to_k(temp: float) -> float: return temp + 273.15 -def c_to_f(temp): +def c_to_f(temp: float) -> float: return (9.0 / 5.0 * temp + 32) -def k_to_c(temp): +def k_to_c(temp: float) -> float: return temp - 273.15 -def _extract_source(pattern, trigger) -> tuple[str, ...]: +def _extract_source(pattern: Pattern, trigger: Trigger) -> tuple[str, ...]: match = pattern.match(trigger.group(2)) if match: return match.groups() @@ -49,7 +55,7 @@ def _extract_source(pattern, trigger) -> tuple[str, ...]: @plugin.example('.temp 100C', '100.00°C = 212.00°F = 373.15K') @plugin.example('.temp 100K', '-173.15°C = -279.67°F = 100.00K') @plugin.output_prefix(PLUGIN_OUTPUT_PREFIX) -def temperature(bot, trigger): +def temperature(bot: SopelWrapper, trigger: Trigger) -> int | None: """Convert temperatures""" try: source = _extract_source(find_temp, trigger) @@ -71,7 +77,7 @@ def temperature(bot, trigger): if kelvin <= 0: bot.reply("Physically impossible temperature.") - return + return None bot.say("{:.2f}°C = {:.2f}°F = {:.2f}K".format( celsius, @@ -79,6 +85,8 @@ def temperature(bot, trigger): kelvin, )) + return None + @plugin.command('length', 'distance') @plugin.example('.distance 3m', '3.00m = 9 feet, 10.11 inches') @@ -92,7 +100,7 @@ def temperature(bot, trigger): @plugin.example('.length 3 au', '448793612.10km = 278867421.71 miles') @plugin.example('.length 3 parsec', '92570329129020.20km = 57520535754731.61 miles') @plugin.output_prefix(PLUGIN_OUTPUT_PREFIX) -def distance(bot, trigger): +def distance(bot: SopelWrapper, trigger: Trigger) -> int | None: """Convert distances""" try: source = _extract_source(find_length, trigger) @@ -160,10 +168,12 @@ def distance(bot, trigger): bot.say('{} = {}'.format(metric_part, stupid_part)) + return None + @plugin.command('weight', 'mass') @plugin.output_prefix(PLUGIN_OUTPUT_PREFIX) -def mass(bot, trigger): +def mass(bot: SopelWrapper, trigger: Trigger) -> int | None: """Convert mass""" try: source = _extract_source(find_mass, trigger) @@ -199,3 +209,5 @@ def mass(bot, trigger): stupid_part = '{:.2f} oz'.format(ounce) bot.say('{} = {}'.format(metric_part, stupid_part)) + + return None diff --git a/sopel/builtins/url.py b/sopel/builtins/url.py index 283349635..941dae7ab 100644 --- a/sopel/builtins/url.py +++ b/sopel/builtins/url.py @@ -76,7 +76,7 @@ class UrlSection(types.StaticSection): """Enable requests to private and local network IP addresses""" -def configure(config: Config): +def configure(config: Config) -> None: """ | name | example | purpose | | ---- | ------- | ------- | @@ -111,7 +111,7 @@ def configure(config: Config): ) -def setup(bot: Sopel): +def setup(bot: Sopel) -> None: bot.config.define_section('url', UrlSection) if bot.config.url.exclude: @@ -140,7 +140,7 @@ def setup(bot: Sopel): bot.memory['shortened_urls'] = tools.SopelMemory() -def shutdown(bot: Sopel): +def shutdown(bot: Sopel) -> None: # Unset `url_exclude` and `last_seen_url`, but not `shortened_urls`; # clearing `shortened_urls` will increase API calls. Leaving it in memory # should not lead to unexpected behavior. @@ -151,7 +151,7 @@ def shutdown(bot: Sopel): pass -def _user_can_change_excludes(bot: SopelWrapper, trigger: Trigger): +def _user_can_change_excludes(bot: SopelWrapper, trigger: Trigger) -> bool: if trigger.admin: return True @@ -169,7 +169,7 @@ def _user_can_change_excludes(bot: SopelWrapper, trigger: Trigger): @plugin.example('.urlpexclude example\\.com/\\w+', user_help=True) @plugin.example('.urlexclude example.com/path', user_help=True) @plugin.output_prefix('[url] ') -def url_ban(bot: SopelWrapper, trigger: Trigger): +def url_ban(bot: SopelWrapper, trigger: Trigger) -> None: """Exclude a URL from auto title. Use ``urlpexclude`` to exclude a pattern instead of a URL. @@ -220,7 +220,7 @@ def url_ban(bot: SopelWrapper, trigger: Trigger): @plugin.example('.urlpallow example\\.com/\\w+', user_help=True) @plugin.example('.urlallow example.com/path', user_help=True) @plugin.output_prefix('[url] ') -def url_unban(bot: SopelWrapper, trigger: Trigger): +def url_unban(bot: SopelWrapper, trigger: Trigger) -> None: """Allow a URL for auto title. Use ``urlpallow`` to allow a pattern instead of a URL. @@ -273,7 +273,7 @@ def url_unban(bot: SopelWrapper, trigger: Trigger): 'Google | www.google.com', online=True, vcr=True) @plugin.output_prefix('[url] ') -def title_command(bot: SopelWrapper, trigger: Trigger): +def title_command(bot: SopelWrapper, trigger: Trigger) -> None: """ Show the title or URL information for the given URL, or the last URL seen in this channel. @@ -313,7 +313,7 @@ def title_command(bot: SopelWrapper, trigger: Trigger): @plugin.rule(r'(?u).*(https?://\S+).*') @plugin.output_prefix('[url] ') -def title_auto(bot: SopelWrapper, trigger: Trigger): +def title_auto(bot: SopelWrapper, trigger: Trigger) -> None: """ Automatically show titles for URLs. For shortened URLs/redirects, find where the URL redirects to and show the title for that. @@ -475,7 +475,11 @@ def process_urls( yield URLInfo(url, title, parsed_url.hostname, tinyurl, False) -def check_callbacks(bot: SopelWrapper, url: str, use_excludes: bool = True) -> bool: +def check_callbacks( + bot: SopelWrapper, + url: str, + use_excludes: bool = True, +) -> bool: """Check if ``url`` is excluded or matches any URL callback patterns. :param bot: Sopel instance