Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint and typecheck fixes #354

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: CI

on: [push, pull_request]
on:
push:
branches-ignore:
- "dependabot/**"
pull_request:

jobs:
lint:
Expand All @@ -16,10 +20,10 @@ jobs:
with:
python-version: "3.8"

- name: Run black
- name: Run format checks
run: |
pip install nox
nox -s format
nox -s format_check

type-check:
name: Type-check
Expand All @@ -38,3 +42,21 @@ jobs:
run: |
pip install nox
nox -s mypy

slotscheck:
name: Slotscheck
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: "3.8"

- name: Run slotscheck
run: |
pip install nox
nox -s slotscheck
3 changes: 0 additions & 3 deletions .isort.cfg

This file was deleted.

2 changes: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ build:
python:
install:
- requirements: requirements.txt
- requirements: docs_requirements.txt
- requirements: dev-requirements/docs.txt
2 changes: 1 addition & 1 deletion docs_requirements.txt → dev-requirements/docs.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
furo~=2023.9.10
sphinx~=7.2.6
sphinx~=7.2.6
2 changes: 2 additions & 0 deletions dev-requirements/formatting.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
black~=23.9.1
ruff~=0.0.292
1 change: 1 addition & 0 deletions dev-requirements/mypy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mypy~=1.6.0
1 change: 1 addition & 0 deletions dev-requirements/slotscheck.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
slotscheck~=0.17.0
1 change: 0 additions & 1 deletion dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
-r requirements.txt
-r docs_requirements.txt
-r crontrigger_requirements.txt
nox~=2023.4.22
18 changes: 11 additions & 7 deletions lightbulb/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class BotApp(hikari.GatewayBot):
Defaults to ``False``.
**kwargs (Any): Additional keyword arguments passed to the constructor of the :obj:`~hikari.impl.gateway_bot.GatewayBot`
class.
"""
""" # noqa: E501

__slots__ = (
"get_prefix",
Expand Down Expand Up @@ -232,7 +232,8 @@ def __init__(
"""The default guilds that application commands will be enabled in."""

self.application: t.Optional[hikari.Application] = None
"""The :obj:`~hikari.applications.Application` for the bot account. This will always be ``None`` before the bot has logged in."""
"""The :obj:`~hikari.applications.Application` for the bot account.
This will always be ``None`` before the bot has logged in."""

self.d: data_store.DataStore = data_store.DataStore()
"""A :obj:`~.utils.data_store.DataStore` instance enabling storage of custom data without subclassing."""
Expand Down Expand Up @@ -388,7 +389,8 @@ async def _manage_application_commands(self, _: hikari.StartingEvent) -> None:
match = _APPLICATION_CMD_ERROR_REGEX.search(error_msg)
guild_id = "unknown" if match is None else match.group(1)
raise errors.ApplicationCommandCreationFailed(
f"Application command creation failed for guild {guild_id!r}. Is your bot in the guild and was it invited with the 'applications.commands' scope?"
f"Application command creation failed for guild {guild_id!r}. "
+ "Is your bot in the guild and was it invited with the 'applications.commands' scope?"
) from exc
finally:
await self.dispatch(events.LightbulbStartedEvent(app=self))
Expand Down Expand Up @@ -611,7 +613,7 @@ async def fetch_owner_ids(self) -> t.Sequence[hikari.Snowflakeish]:

self.application = self.application or await self.rest.fetch_application()

owner_ids = []
owner_ids: t.List[hikari.Snowflake] = []
if self.application.owner is not None:
owner_ids.append(self.application.owner.id)
if self.application.team is not None:
Expand Down Expand Up @@ -1221,9 +1223,11 @@ async def handle_interaction_create_for_autocomplete(self, event: hikari.Interac
assert event.interaction.command_type is hikari.CommandType.SLASH
assert event.interaction.options is not None and len(event.interaction.options) > 0

get_focused: t.Callable[
[t.Sequence[hikari.AutocompleteInteractionOption]], hikari.AutocompleteInteractionOption
] = lambda opts: next(filter(lambda o: o.is_focused, opts), opts[0])
def is_focused(opt: hikari.AutocompleteInteractionOption) -> bool:
return opt.is_focused

def get_focused(opts: t.Sequence[hikari.AutocompleteInteractionOption]) -> hikari.AutocompleteInteractionOption:
return next(filter(is_focused, opts), opts[0])

def flatten_command_option(
opt: hikari.AutocompleteInteractionOption,
Expand Down
23 changes: 15 additions & 8 deletions lightbulb/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ class OptionLike:
arg_type: t.Any = str
"""The type of the option."""
required: bool = True
"""Whether or not the option is required. This will be inferred from whether or not a default value was provided if unspecified."""
"""Whether or not the option is required. This will be inferred from whether or not
a default value was provided if unspecified."""
choices: t.Optional[t.Sequence[t.Union[str, int, float, hikari.CommandChoice]]] = None
"""The option's choices. This only affects slash commands."""
channel_types: t.Optional[t.Sequence[hikari.ChannelType]] = None
Expand Down Expand Up @@ -204,7 +205,8 @@ def as_application_command_option(self) -> hikari.CommandOption:
"""
if not OPTION_NAME_REGEX.fullmatch(self.name) or self.name != self.name.lower():
raise ValueError(
f"Application command option {self.name!r}: name must match regex '^[\\w-]{1,32}$' and be all lowercase"
f"Application command option {self.name!r}: "
+ "name must match regex '^[\\w-]{1, 32}$' and be all lowercase"
)
if len(self.description) < 1 or len(self.description) > 100:
raise ValueError(
Expand All @@ -213,27 +215,30 @@ def as_application_command_option(self) -> hikari.CommandOption:

arg_type = OPTION_TYPE_MAPPING.get(self.arg_type, self.arg_type)
if not isinstance(arg_type, hikari.OptionType):
arg_type = hikari.OptionType.STRING # type: ignore[unreachable]
arg_type = hikari.OptionType.STRING

if (self.min_value is not None or self.max_value is not None) and arg_type not in (
hikari.OptionType.INTEGER,
hikari.OptionType.FLOAT,
):
raise ValueError(
f"Application command option {self.name!r}: 'min_value' or 'max_value' was provided but the option type is not numeric"
f"Application command option {self.name!r}: "
+ "'min_value' or 'max_value' was provided but the option type is not numeric"
)

if (self.min_length is not None or self.max_length is not None) and arg_type is not hikari.OptionType.STRING:
raise ValueError(
f"Application command option {self.name!r}: 'min_length' or 'max_length' was provided but the option type is not string"
f"Application command option {self.name!r}: "
+ "'min_length' or 'max_length' was provided but the option type is not string"
)

if (
arg_type not in (hikari.OptionType.INTEGER, hikari.OptionType.FLOAT, hikari.OptionType.STRING)
and self.autocomplete
):
raise ValueError(
f"Application command option {self.name!r}: 'autocomplete' is True but the option type does not support choices"
f"Application command option {self.name!r}: "
+ "'autocomplete' is True but the option type does not support choices"
)

kwargs: t.MutableMapping[str, t.Any] = {
Expand Down Expand Up @@ -522,7 +527,7 @@ async def foo_autocomplete(
opt: hikari.AutocompleteInteractionOption, inter: hikari.AutocompleteInteraction
) -> Union[str, Sequence[str], hikari.api.AutocompleteChoiceBuilder, Sequence[hikari.api.AutocompleteChoiceBuilder]]:
...
"""
""" # noqa: E501

def decorate(func: AutocompleteCallbackT) -> AutocompleteCallbackT:
for opt in [opt1, *opts]:
Expand Down Expand Up @@ -867,7 +872,9 @@ def guilds(self) -> t.Sequence[int]:
def signature(self) -> str:
sig = self.qualname
if self.options:
sig += f" {' '.join(f'<{o.name}>' if o.required else f'[{o.name}={o.default}]' for o in self.options.values())}"
sig += " " + " ".join(
f"<{o.name}>" if o.required else f"[{o.name}={o.default}]" for o in self.options.values()
)
return sig

async def create(self, guild: t.Optional[int] = None) -> hikari.PartialCommand:
Expand Down
7 changes: 5 additions & 2 deletions lightbulb/commands/prefix.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ def create_subcommands(self, raw_cmds: t.Sequence[base.CommandLike], app: app_.B
for name in [cmd.name, *cmd.aliases]:
if name in self._subcommands:
raise errors.CommandAlreadyExists(
f"A prefix subcommand with name or alias {name!r} already exists for group {self.name!r}"
f"A prefix subcommand with name or alias {name!r} "
+ f"already exists for group {self.name!r}"
)
self._subcommands[name] = cmd

Expand Down Expand Up @@ -104,7 +105,9 @@ class PrefixCommand(base.Command):
def signature(self) -> str:
sig = self.qualname
if self.options:
sig += f" {' '.join(f'<{o.name}>' if o.required else f'[{o.name}={o.default}]' for o in self.options.values())}"
sig += " " + " ".join(
f"<{o.name}>" if o.required else f"[{o.name}={o.default}]" for o in self.options.values()
)
return sig

async def invoke(self, context: context_.base.Context, **kwargs: t.Any) -> None:
Expand Down
3 changes: 2 additions & 1 deletion lightbulb/commands/slash.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ def create_subcommands(

if cmd.name in self._subcommands:
raise errors.CommandAlreadyExists(
f"A prefix subcommand with name or alias {cmd.name!r} already exists for group {self.name!r}"
f"A prefix subcommand with name or alias {cmd.name!r} "
+ f"already exists for group {self.name!r}"
)
self._subcommands[cmd.name] = cmd

Expand Down
12 changes: 3 additions & 9 deletions lightbulb/context/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ async def respond(

.. versionadded:: 2.2.0
``delete_after`` kwarg.
"""
""" # noqa: E501

async def _cleanup(timeout: t.Union[int, float], proxy_: ResponseProxy) -> None:
await asyncio.sleep(timeout)
Expand All @@ -548,14 +548,8 @@ async def _cleanup(timeout: t.Union[int, float], proxy_: ResponseProxy) -> None:
except hikari.NotFoundError:
pass

includes_ephemeral: t.Callable[
[
t.Union[hikari.MessageFlag, int],
],
bool,
] = (
lambda flags: (hikari.MessageFlag.EPHEMERAL & flags) == hikari.MessageFlag.EPHEMERAL
)
def includes_ephemeral(flags: t.Union[hikari.MessageFlag, int]) -> bool:
return (hikari.MessageFlag.EPHEMERAL & flags) == hikari.MessageFlag.EPHEMERAL

kwargs.pop("reply", None)
kwargs.pop("mentions_reply", None)
Expand Down
2 changes: 1 addition & 1 deletion lightbulb/context/prefix.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ async def respond(

.. versionadded:: 2.2.0
``delete_after`` kwarg.
"""
""" # noqa: E501
self._deferred = False

kwargs.pop("flags", None)
Expand Down
24 changes: 12 additions & 12 deletions lightbulb/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def command(
``pass_options`` kwarg.
.. versionadded:: 2.3.0
``name_localizations`` and ``description_localizations`` kwargs.
"""
""" # noqa: E501

def decorate(func: CommandCallbackT) -> commands.base.CommandLike:
cmd = cls(func, name, description, **kwargs)
Expand Down Expand Up @@ -196,7 +196,7 @@ def option(
``min_value`` and ``max_value`` kwargs.
.. versionadded:: 2.3.2
``min_length`` and ``max_length`` kwargs.
"""
""" # noqa: E501

def decorate(c_like: commands.base.CommandLike) -> commands.base.CommandLike:
nonlocal default, required, autocomplete
Expand Down Expand Up @@ -328,18 +328,18 @@ def add_cooldown(
cooldowns in the context.
cls (Type[:obj:`~.cooldowns.CooldownManager`]): The cooldown manager class to use. Defaults to
:obj:`~.cooldowns.CooldownManager`.
"""
""" # noqa: E501
getter: t.Callable[[context.base.Context], t.Union[buckets.Bucket, t.Coroutine[t.Any, t.Any, buckets.Bucket]]]
if length is not None and uses is not None and bucket is not None:

def _get_bucket(
_: context.base.Context,
b: t.Type[buckets.Bucket],
l: float,
u: int,
a: t.Type[cooldown_algorithms.CooldownAlgorithm],
ctx: context.base.Context,
_bucket: t.Type[buckets.Bucket],
_length: float,
_max_usages: int,
_algorithm: t.Type[cooldown_algorithms.CooldownAlgorithm],
) -> buckets.Bucket:
return b(l, u, a)
return _bucket(_length, _max_usages, _algorithm)

getter = functools.partial(_get_bucket, b=bucket, l=length, u=uses, a=algorithm)
elif callback is not None:
Expand Down Expand Up @@ -375,7 +375,7 @@ def set_help(
Keyword Args:
docstring (:obj:`bool`): Whether the command help text should be extracted from the command's docstring.
If this is ``False`` (default) then a value **must** be provided for the ``text`` arg.
"""
""" # noqa: E501
if text is None and docstring is False:
raise ValueError("Either help text/callable or docstring=True must be provided")

Expand All @@ -384,12 +384,12 @@ def decorate(c_like: commands.base.CommandLike) -> commands.base.CommandLike:
raise SyntaxError("'set_help' decorator must be above the 'command' decorator")

if isinstance(text, str):
getter = lambda _, __: text
getter = lambda _, __: text # noqa: E731
elif docstring:
cmd_doc = inspect.getdoc(c_like.callback)
if cmd_doc is None:
raise ValueError("docstring=True was provided but the command does not have a docstring")
getter = lambda _, __: cmd_doc
getter = lambda _, __: cmd_doc # noqa: E731
else:
assert text is not None
getter = text
Expand Down
5 changes: 4 additions & 1 deletion lightbulb/ext/tasks/triggers.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ def __init__(

def __init__(self, crontab: t.Optional[str] = None, /, **kwargs: _CT) -> None:
if not crontab:
crontab = f"{kwargs.get('minute', '*')} {kwargs.get('hour', '*')} {kwargs.get('day', '*')} {kwargs.get('month', '*')} {kwargs.get('day_of_week', '*')} {kwargs.get('second', 0)}"
crontab = (
f"{kwargs.get('minute', '*')} {kwargs.get('hour', '*')} {kwargs.get('day', '*')} "
f"{kwargs.get('month', '*')} {kwargs.get('day_of_week', '*')} {kwargs.get('second', 0)}"
)

self._croniter = croniter.croniter(crontab, datetime.datetime.now(datetime.timezone.utc))

Expand Down
2 changes: 1 addition & 1 deletion lightbulb/utils/data_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class DataStore(t.Dict[str, t.Any]):
DataStore()

A DataStore instance is attached to :obj:`~.app.BotApp` instances as :attr:`bot.d <.app.BotApp.d>` for your convenience.
"""
""" # noqa: E501

__slots__ = ()

Expand Down
Loading