diff --git a/.githooks/pre-commit b/.githooks/pre-commit index a4d593c..90f2230 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -3,8 +3,8 @@ # This hooks runs tests and checks if the linter doesn't hate you # Linting -printf "flake8....." -make lint > /dev/null 2>&1 && printf "OK!\n" || { printf "Fail." && exit 1; } +printf "black......" +make format > /dev/null 2>&1 && printf "OK!\n" || { printf "Fail." && exit 1; } # Running tests printf "pytest....." diff --git a/Makefile b/Makefile index e4b0b93..0431562 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,11 @@ test: pytest.ini build-venv lint: build-venv @ "$(VENV)/bin/flake8" "$(SRC)"/**/*.py +# =====FORMATTING===== +# Run black +format: build-venv + @ "$(VENV)/bin/black" '$(SRC)' + # =====PACKAGING===== package: README.md LICENSE setup.py test clean-setup diff --git a/frank/__init__.py b/frank/__init__.py index 0468a36..e5cf103 100644 --- a/frank/__init__.py +++ b/frank/__init__.py @@ -1,18 +1,25 @@ from .frank import Frank from .module import ( - Module, command, Command, default, Default, daemon, Daemon, - regex_command, RegexCommand, + Module, + command, + Command, + default, + Default, + daemon, + Daemon, + regex_command, + RegexCommand, ) __all__ = [ - 'Frank', - 'Module', - 'command', - 'Command', - 'default', - 'Default', - 'daemon', - 'Daemon', - 'regex_command', - 'RegexCommand', + "Frank", + "Module", + "command", + "Command", + "default", + "Default", + "daemon", + "Daemon", + "regex_command", + "RegexCommand", ] diff --git a/frank/frank.py b/frank/frank.py index 2a8a01e..eb84d64 100644 --- a/frank/frank.py +++ b/frank/frank.py @@ -11,6 +11,7 @@ import discord # Typing imports from typing import TYPE_CHECKING, List + if TYPE_CHECKING: # Own imports from .module import Module @@ -23,8 +24,12 @@ class Frank(discord.Client): their own behavior. """ - def __init__(self, modules: List[Module], config_file: str = 'frank.yaml', - prefix: str = 'fr'): + def __init__( + self, + modules: List[Module], + config_file: str = "frank.yaml", + prefix: str = "fr", + ): """ Args: modules: modules to load @@ -39,7 +44,7 @@ class Frank(discord.Client): self.PREFIX = prefix try: - with open(config_file, 'r') as f: + with open(config_file, "r") as f: self._config = yaml.load(f, Loader=yaml.FullLoader) except FileNotFoundError: @@ -50,7 +55,7 @@ class Frank(discord.Client): Runs when the bot has succesfully connected to Discord """ - print('Connected') + print("Connected") # Startup all modules for module in self._modules: @@ -63,7 +68,7 @@ class Frank(discord.Client): await loaded._start() self._loaded_modules.append(loaded) - print('All modules loaded') + print("All modules loaded") async def stop(self): """ @@ -92,9 +97,14 @@ class Frank(discord.Client): if not (cmd and cmd[0] == self.PREFIX): return - module = next((mod for mod in self._loaded_modules - if mod.match(cmd[1])), None) + module = next( + (mod for mod in self._loaded_modules if mod.match(cmd[1])), None + ) if module: - await module(cmd=cmd[2:], author=message.author, - channel=message.channel, mid=message.id) + await module( + cmd=cmd[2:], + author=message.author, + channel=message.channel, + mid=message.id, + ) diff --git a/frank/module/__init__.py b/frank/module/__init__.py index 322a87d..459ef30 100644 --- a/frank/module/__init__.py +++ b/frank/module/__init__.py @@ -1,18 +1,24 @@ from .module import Module from .decorators import ( - command, Command, default, Default, daemon, Daemon, regex_command, + command, + Command, + default, + Default, + daemon, + Daemon, + regex_command, RegexCommand, ) __all__ = [ - 'Module', - 'command', - 'Command', - 'default', - 'Default', - 'daemon', - 'Daemon', - 'regex_command', - 'RegexCommand', + "Module", + "command", + "Command", + "default", + "Default", + "daemon", + "Daemon", + "regex_command", + "RegexCommand", ] diff --git a/frank/module/decorators/__init__.py b/frank/module/decorators/__init__.py index 1c8ce8e..cc5e89d 100644 --- a/frank/module/decorators/__init__.py +++ b/frank/module/decorators/__init__.py @@ -2,12 +2,12 @@ from .classes import Command, RegexCommand, Daemon, Default from .functions import command, regex_command, daemon, default __all__ = [ - 'command', - 'Command', - 'regex_command', - 'RegexCommand', - 'default', - 'Default', - 'daemon', - 'Daemon', + "command", + "Command", + "regex_command", + "RegexCommand", + "default", + "Default", + "daemon", + "Daemon", ] diff --git a/frank/module/decorators/classes.py b/frank/module/decorators/classes.py index 97f31bd..f0fa326 100644 --- a/frank/module/decorators/classes.py +++ b/frank/module/decorators/classes.py @@ -8,6 +8,7 @@ import asyncio # Typing imports from typing import TYPE_CHECKING + if TYPE_CHECKING: # Built-in imports from typing import Union @@ -120,6 +121,7 @@ class Daemon(Simple): # If an interval > 0 is given, it wraps the function inside an infinite # loop with the desired delay if interval > 0: + async def loop(self, *args, **kwargs): while True: # TODO: does this make func and sleep run at the same time? diff --git a/frank/module/decorators/functions.py b/frank/module/decorators/functions.py index 130bcd0..d60fcec 100644 --- a/frank/module/decorators/functions.py +++ b/frank/module/decorators/functions.py @@ -7,6 +7,7 @@ from .classes import Command, RegexCommand, Daemon, Default # Typing imports from typing import TYPE_CHECKING + if TYPE_CHECKING: # Built-in imports from typing import Union diff --git a/frank/module/exceptions.py b/frank/module/exceptions.py index 4502971..d7c541b 100644 --- a/frank/module/exceptions.py +++ b/frank/module/exceptions.py @@ -7,4 +7,4 @@ class DuplicateCommand(Exception): class MultipleDefaults(Exception): - message = 'Multiple default commands detected' + message = "Multiple default commands detected" diff --git a/frank/module/meta.py b/frank/module/meta.py index c488b7e..29f0977 100644 --- a/frank/module/meta.py +++ b/frank/module/meta.py @@ -10,6 +10,7 @@ from .decorators import Command, Daemon, Default, RegexCommand # Typing imports from typing import TYPE_CHECKING + if TYPE_CHECKING: # Built-in imports from typing import List, Any @@ -18,7 +19,7 @@ if TYPE_CHECKING: class ModuleMeta: def _filter_attrs(self, condition: callable[[Any], bool]) -> List[Any]: # This prevents an infinite loop of getting the attribute - illegal_names = ['commands', 'daemons', 'default'] + illegal_names = ["commands", "daemons", "default"] output = [] @@ -36,8 +37,10 @@ class ModuleMeta: # The sort puts all the RegexCommand objects at the back, making them # be matched last - return sorted(self._filter_attrs(lambda val: isinstance(val, Command)), - key=lambda x: isinstance(x, RegexCommand)) + return sorted( + self._filter_attrs(lambda val: isinstance(val, Command)), + key=lambda x: isinstance(x, RegexCommand), + ) @cached_property def daemons(self) -> List[Daemon]: @@ -45,5 +48,6 @@ class ModuleMeta: @cached_property def default(self) -> Default: - return next(iter(self._filter_attrs( - lambda val: isinstance(val, Default))), None) + return next( + iter(self._filter_attrs(lambda val: isinstance(val, Default))), None + ) diff --git a/frank/module/module.py b/frank/module/module.py index 3c9dbf4..03eb053 100644 --- a/frank/module/module.py +++ b/frank/module/module.py @@ -12,6 +12,7 @@ from .decorators import RegexCommand # Typing imports from typing import TYPE_CHECKING + if TYPE_CHECKING: # Built-in imports from typing import List, Dict @@ -33,13 +34,13 @@ class Module(ModuleMeta): Prefix to activate this module. """ - NAME = '' + NAME = "" """ The name is used in various places, such as the config file and the help function. """ - HELP = '' + HELP = "" """ Short description of the module to use in the help function. """ @@ -84,8 +85,9 @@ class Module(ModuleMeta): for task in self._tasks: task.cancel() - async def __call__(self, cmd: List[str], author: User, - channel: Messageable, mid: int): + async def __call__( + self, cmd: List[str], author: User, channel: Messageable, mid: int + ): """ Execute the command, if found. @@ -97,21 +99,26 @@ class Module(ModuleMeta): """ if cmd: - func = next((func for func in self.commands - if func.match(cmd[0])), None) + func = next( + (func for func in self.commands if func.match(cmd[0])), None + ) # Throw error if no function is found if not func: - raise InvalidCommand(f'Unknown command: {cmd}') + raise InvalidCommand(f"Unknown command: {cmd}") # A RegexCommand can use the prefix, as it's not a fixed string if isinstance(func, RegexCommand): - await func(prefix=cmd[0], cmd=cmd[1:], author=author, - channel=channel, mid=mid) + await func( + prefix=cmd[0], + cmd=cmd[1:], + author=author, + channel=channel, + mid=mid, + ) else: - await func(cmd=cmd[1:], author=author, channel=channel, - mid=mid) + await func(cmd=cmd[1:], author=author, channel=channel, mid=mid) elif self.default: await self.default(author=author, channel=channel, mid=mid) diff --git a/frank/modules/__init__.py b/frank/modules/__init__.py index 801d111..f6055c9 100644 --- a/frank/modules/__init__.py +++ b/frank/modules/__init__.py @@ -2,5 +2,5 @@ from .help import HelpMod __all__ = [ - 'HelpMod', + "HelpMod", ] diff --git a/frank/modules/help.py b/frank/modules/help.py index fa08f33..76b6b83 100644 --- a/frank/modules/help.py +++ b/frank/modules/help.py @@ -10,6 +10,7 @@ from .. import Module, default, regex_command # Typing imports from typing import TYPE_CHECKING + if TYPE_CHECKING: # Built-in imports from typing import List @@ -24,11 +25,11 @@ class HelpMod(Module): other modules. """ - PREFIX = 'help' - NAME = 'help' - HELP = 'Shows help info about all modules' + PREFIX = "help" + NAME = "help" + HELP = "Shows help info about all modules" - @default(help_str='Show help about all modules.') + @default(help_str="Show help about all modules.") async def send_all(self, author: User, channel: Messageable, mid: int): embed = Embed() @@ -37,20 +38,33 @@ class HelpMod(Module): await channel.send(embed=embed) - @regex_command(pattern='.+', help_str='Show help about a certain module.') - async def show_module_help(self, prefix: str, cmd: List[str], author: User, - channel: Messageable, mid: int): + @regex_command(pattern=".+", help_str="Show help about a certain module.") + async def show_module_help( + self, + prefix: str, + cmd: List[str], + author: User, + channel: Messageable, + mid: int, + ): # Yes, this command just ignores cmd at the moment mod_name = prefix.lower() - mod = next((mod for mod in self._client._modules - if mod.NAME.lower() == mod_name), None) + mod = next( + ( + mod + for mod in self._client._modules + if mod.NAME.lower() == mod_name + ), + None, + ) if mod: embed = Embed() if mod.default: - embed.add_field(name='default', value=mod.default.help_str, - inline=False) + embed.add_field( + name="default", value=mod.default.help_str, inline=False + ) for cmd in mod._COMMANDS: embed.add_field(name=cmd.cmd, value=mod.help_str, inline=False) diff --git a/requirements-dev.txt b/requirements-dev.txt index 5059612..30c0a62 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -13,3 +13,4 @@ pytest-asyncio>=0.14.0,<1.0.0 twine>=3.2.0,<4.0.0 Sphinx==3.2.1 sphinx-rtd-theme==0.5.0 +black