From dff692a731705ca0d8a8bc88a5ab3502f66e7979 Mon Sep 17 00:00:00 2001 From: ScuffedNewt Date: Fri, 2 Feb 2024 21:28:01 +0000 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=E2=9C=A8refactor=20|=20featu?= =?UTF-8?q?re:=20add=20precommit=20hooks=20for=20black=20and=20ruff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 12 +++++++ requirements.txt | 61 +++++++++++++++++++++++++++++++++-- src/bot.py | 1 + src/config.py | 6 ++-- src/extensions/boosts.py | 14 +++++--- src/extensions/hello_world.py | 25 ++++++++------ src/extensions/uptime.py | 8 +++-- src/extensions/user_roles.py | 33 ++++++++++--------- src/utils.py | 2 ++ 9 files changed, 124 insertions(+), 38 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5411c15 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,12 @@ +repos: + - repo: https://github.com/psf/black + rev: 24.1.1 + hooks: + - id: black + language_version: python3 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.2.0 + hooks: + - id: ruff + args: [ --fix ] + - id: ruff-format \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index d6e51dc..b17a226 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,58 @@ -hikari==2.0.0.dev122 -hikari-arc==1.1.0 -python-dotenv==1.0.1 \ No newline at end of file +aiohttp==3.9.3 +aiosignal==1.3.1 +alluka==0.1.4 +async-timeout==4.0.3 +attrs==23.2.0 +black==24.1.1 +blinker==1.4 +cfgv==3.4.0 +click==8.1.7 +colorlog==6.8.2 +command-not-found==0.3 +cryptography==3.4.8 +dbus-python==1.2.18 +distlib==0.3.8 +distro==1.7.0 +distro-info==1.1+ubuntu0.1 +filelock==3.13.1 +frozenlist==1.4.1 +hikari==2.0.0.dev122 +hikari-arc==1.1.0 +httplib2==0.20.2 +identify==2.5.33 +idna==3.6 +importlib-metadata==4.6.4 +jeepney==0.7.1 +keyring==23.5.0 +launchpadlib==1.10.16 +lazr.restfulclient==0.14.4 +lazr.uri==1.0.6 +more-itertools==8.10.0 +multidict==6.0.5 +mypy-extensions==1.0.0 +netifaces==0.11.0 +nodeenv==1.8.0 +oauthlib==3.2.0 +packaging==23.2 +pathspec==0.12.1 +platformdirs==4.2.0 +pre-commit==3.6.0 +PyGObject==3.42.1 +PyJWT==2.3.0 +pyparsing==2.4.7 +python-apt==2.4.0+ubuntu2 +python-dotenv==1.0.1 +PyYAML==5.4.1 +ruff==0.2.0 +SecretStorage==3.3.1 +six==1.16.0 +systemd-python==234 +tomli==2.0.1 +typing_extensions==4.9.0 +ubuntu-advantage-tools==8001 +ufw==0.36.1 +unattended-upgrades==0.1 +virtualenv==20.25.0 +wadllib==1.3.6 +yarl==1.9.4 +zipp==1.0.0 diff --git a/src/bot.py b/src/bot.py index 84cfbca..e078fcf 100644 --- a/src/bot.py +++ b/src/bot.py @@ -22,6 +22,7 @@ client = arc.GatewayClient(bot, is_dm_enabled=False) client.load_extensions_from("./src/extensions/") + @client.set_error_handler async def error_handler(ctx: arc.GatewayContext, exc: Exception) -> None: if DEBUG: diff --git a/src/config.py b/src/config.py index e2ed684..a4ef636 100644 --- a/src/config.py +++ b/src/config.py @@ -4,9 +4,7 @@ load_dotenv() -TOKEN = os.environ.get("TOKEN") # required +TOKEN = os.environ.get("TOKEN") # required DEBUG = os.environ.get("DEBUG", False) -CHANNEL_IDS = { - "lobby": "627542044390457350" -} +CHANNEL_IDS = {"lobby": "627542044390457350"} diff --git a/src/extensions/boosts.py b/src/extensions/boosts.py index 669a454..5f8593a 100644 --- a/src/extensions/boosts.py +++ b/src/extensions/boosts.py @@ -16,28 +16,32 @@ hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION, ] + def build_boost_message( message_type: hikari.MessageType | int, number_of_boosts: str | None, booster_user: hikari.Member, - guild: hikari.Guild + guild: hikari.Guild, ) -> str: assert message_type in BOOST_MESSAGE_TYPES base_message = f"{booster_user.display_name} just boosted the server" - multiple_boosts_message = f" **{number_of_boosts}** times" if number_of_boosts else "" + multiple_boosts_message = ( + f" **{number_of_boosts}** times" if number_of_boosts else "" + ) message = base_message + multiple_boosts_message + "!" - if (message_type in BOOST_TIERS): + if message_type in BOOST_TIERS: count = BOOST_TIERS.index(message_type) + 1 message += f"\n{guild.name} has reached **Level {count}!**" return message + @plugin.listen() async def on_message(event: hikari.GuildMessageCreateEvent): - if not event.message.type in BOOST_MESSAGE_TYPES: + if event.message.type not in BOOST_MESSAGE_TYPES: return assert event.member is not None @@ -45,7 +49,7 @@ async def on_message(event: hikari.GuildMessageCreateEvent): event.message.type, number_of_boosts=event.content, booster_user=event.member, - guild=await get_guild(plugin.client, event) + guild=await get_guild(plugin.client, event), ) await plugin.client.rest.create_message(CHANNEL_IDS["lobby"], content=message) diff --git a/src/extensions/hello_world.py b/src/extensions/hello_world.py index df2891f..1f018cc 100644 --- a/src/extensions/hello_world.py +++ b/src/extensions/hello_world.py @@ -1,54 +1,59 @@ """ Example extension with simple commands """ + import arc import hikari plugin = arc.GatewayPlugin(name="Hello World") + @plugin.include @arc.slash_command("hello", "Say hello!") async def hello(ctx: arc.GatewayContext) -> None: """A simple hello world command""" await ctx.respond("Hello from hikari!") + group = plugin.include_slash_group("base_command", "A base command, to expand on") + @group.include @arc.slash_subcommand("sub_command", "A sub command, to expand on") async def sub_command(ctx: arc.GatewayContext) -> None: """A simple sub command""" await ctx.respond("Hello, world! This is a sub command") + @plugin.include @arc.slash_command("options", "A command with options") async def options( ctx: arc.GatewayContext, option_str: arc.Option[str, arc.StrParams("A string option")], option_int: arc.Option[int, arc.IntParams("An integer option")], - option_attachment: arc.Option[hikari.Attachment, arc.AttachmentParams("An attachment option")], + option_attachment: arc.Option[ + hikari.Attachment, arc.AttachmentParams("An attachment option") + ], ) -> None: """A command with lots of options""" embed = hikari.Embed( - title="There are a lot of options here", - description="Maybe too many", - colour=0x5865F2 + title="There are a lot of options here", + description="Maybe too many", + colour=0x5865F2, ) embed.set_image(option_attachment) embed.add_field("String option", option_str, inline=False) embed.add_field("Integer option", str(option_int), inline=False) await ctx.respond(embed=embed) + @plugin.include @arc.slash_command("components", "A command with components") async def components(ctx: arc.GatewayContext) -> None: """A command with components""" builder = ctx.client.rest.build_message_action_row() select_menu = builder.add_text_menu( - "select_me", - placeholder="I wonder what this does", - min_values=1, - max_values=2 + "select_me", placeholder="I wonder what this does", min_values=1, max_values=2 ) for opt in ("Select me!", "No, select me!", "Select me too!"): select_menu.add_option(opt, opt) @@ -59,6 +64,7 @@ async def components(ctx: arc.GatewayContext) -> None: await ctx.respond("Here are some components", components=[builder, button]) + @plugin.listen() async def on_interaction(event: hikari.InteractionCreateEvent) -> None: interaction = event.interaction @@ -71,7 +77,7 @@ async def on_interaction(event: hikari.InteractionCreateEvent) -> None: if interaction.custom_id == "click_me": await interaction.create_initial_response( hikari.ResponseType.MESSAGE_CREATE, - f"{interaction.user.mention}, you clicked me!" + f"{interaction.user.mention}, you clicked me!", ) elif interaction.custom_id == "select_me": await interaction.create_initial_response( @@ -79,6 +85,7 @@ async def on_interaction(event: hikari.InteractionCreateEvent) -> None: f"{interaction.user.mention}, you selected {' '.join(interaction.values)}", ) + @arc.loader def loader(client: arc.GatewayClient) -> None: client.add_plugin(plugin) diff --git a/src/extensions/uptime.py b/src/extensions/uptime.py index 45ddb4d..2b1cf89 100644 --- a/src/extensions/uptime.py +++ b/src/extensions/uptime.py @@ -6,6 +6,7 @@ plugin = arc.GatewayPlugin("Blockbot Uptime") + @plugin.include @arc.slash_command("uptime", "Show formatted uptime of Blockbot") async def uptime(ctx): @@ -14,12 +15,15 @@ async def uptime(ctx): h, ms = divmod(up_time.seconds, 3600) m, s = divmod(ms, 60) - format = lambda val, str: f"{val} {str}{'s' if val != 1 else ''}" + def format(val, str): + return f"{val} {str}{'s' if val != 1 else ''}" + message_parts = [(d, "day"), (h, "hour"), (m, "minute"), (s, "second")] formatted_parts = [format(val, str) for val, str in message_parts if val] - + await ctx.respond(f"Uptime: **{', '.join(formatted_parts)}**") + @arc.loader def loader(client): client.add_plugin(plugin) diff --git a/src/extensions/user_roles.py b/src/extensions/user_roles.py index e8ba8a1..63892c2 100644 --- a/src/extensions/user_roles.py +++ b/src/extensions/user_roles.py @@ -13,52 +13,55 @@ hikari.CommandChoice(name="Croomer", value="1172696659097047050"), ] + @role.include @arc.slash_subcommand("add", "Add an assignable role.") async def add_role( ctx: arc.GatewayContext, - role: arc.Option[str, arc.StrParams("The role to add.", choices=role_choices)] + role: arc.Option[str, arc.StrParams("The role to add.", choices=role_choices)], ) -> None: assert ctx.guild_id assert ctx.member if int(role) in ctx.member.role_ids: return await ctx.respond( - f"You already have the {role_mention(role)} role.", - flags=hikari.MessageFlag.EPHEMERAL + f"You already have the {role_mention(role)} role.", + flags=hikari.MessageFlag.EPHEMERAL, ) await ctx.client.rest.add_role_to_member( ctx.guild_id, ctx.author, int(role), reason="Self-service role." ) await ctx.respond( - f"Done! Added {role_mention(role)} to your roles.", - flags=hikari.MessageFlag.EPHEMERAL + f"Done! Added {role_mention(role)} to your roles.", + flags=hikari.MessageFlag.EPHEMERAL, ) + @role.include @arc.slash_subcommand("remove", "Remove an assignable role.") async def remove_role( ctx: arc.GatewayContext, - role: arc.Option[str, arc.StrParams("The role to remove.", choices=role_choices)] + role: arc.Option[str, arc.StrParams("The role to remove.", choices=role_choices)], ) -> None: assert ctx.guild_id assert ctx.member if int(role) not in ctx.member.role_ids: return await ctx.respond( - f"You don't have the {role_mention(role)} role.", - flags=hikari.MessageFlag.EPHEMERAL + f"You don't have the {role_mention(role)} role.", + flags=hikari.MessageFlag.EPHEMERAL, ) await ctx.client.rest.remove_role_from_member( ctx.guild_id, ctx.author, int(role), reason=f"{ctx.author} removed role." ) await ctx.respond( - f"Done! Removed {role_mention(role)} from your roles.", - flags=hikari.MessageFlag.EPHEMERAL + f"Done! Removed {role_mention(role)} from your roles.", + flags=hikari.MessageFlag.EPHEMERAL, ) + @role.set_error_handler async def role_error_handler(ctx: arc.GatewayContext, exc: Exception) -> None: role = ctx.get_option("role", arc.OptionType.STRING) @@ -66,18 +69,18 @@ async def role_error_handler(ctx: arc.GatewayContext, exc: Exception) -> None: if isinstance(exc, hikari.ForbiddenError): return await ctx.respond( - f"❌ Blockbot is not permitted to self-service the {role_mention(role)} role.", - flags=hikari.MessageFlag.EPHEMERAL + f"❌ Blockbot is not permitted to self-service the {role_mention(role)} role.", + flags=hikari.MessageFlag.EPHEMERAL, ) - + if isinstance(exc, hikari.NotFoundError): return await ctx.respond( - f"❌ Blockbot can't find that role.", - flags=hikari.MessageFlag.EPHEMERAL + "❌ Blockbot can't find that role.", flags=hikari.MessageFlag.EPHEMERAL ) raise exc + @arc.loader def loader(client: arc.GatewayClient) -> None: client.add_plugin(plugin) diff --git a/src/utils.py b/src/utils.py index db38338..f4a1892 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,8 +1,10 @@ import hikari from arc import GatewayClient + async def get_guild(client: GatewayClient, event: hikari.GuildMessageCreateEvent): return event.get_guild() or await client.rest.fetch_guild(event.guild_id) + def role_mention(role_id: hikari.Snowflake | int | str): return f"<@&{role_id}>"