Added black formatter to pre-commit hook
parent
6f2d9d1dde
commit
7a7bd6fed4
|
@ -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....."
|
||||
|
|
5
Makefile
5
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
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,4 +7,4 @@ class DuplicateCommand(Exception):
|
|||
|
||||
|
||||
class MultipleDefaults(Exception):
|
||||
message = 'Multiple default commands detected'
|
||||
message = "Multiple default commands detected"
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,5 +2,5 @@ from .help import HelpMod
|
|||
|
||||
|
||||
__all__ = [
|
||||
'HelpMod',
|
||||
"HelpMod",
|
||||
]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Reference in New Issue