### Example Extension Usage Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/070_extensions.md Complete example showing how to load extensions during the bot's startup event. ```python import hikari import lightbulb bot = hikari.GatewayBot(...) client = lightbulb.client_from_app(bot) @bot.listen(hikari.StartingEvent) async def on_starting(_: hikari.StartingEvent) -> None: # Load any extensions await client.load_extensions("extensions.foo", "extensions.bar", "extensions.baz") # Start the bot - make sure commands are synced properly await client.start() bot.run() ``` -------------------------------- ### Basic Hikari Bot and Lightbulb Client Setup Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md This code sets up a basic Hikari bot and a Lightbulb client, subscribing to the bot's starting event to initiate the client. ```python import hikari import lightbulb bot = hikari.GatewayBot("YOUR_TOKEN") client = lightbulb.client_from_app(bot) bot.subscribe(hikari.StartingEvent, client.start) ``` -------------------------------- ### Start the Lightbulb Client Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/000_preface.md Register the client start method to the bot's startup lifecycle events. ```python bot.subscribe(hikari.StartingEvent, client.start) ``` ```python bot.add_startup_callback(client.start) ``` -------------------------------- ### Implement Basic Dependency Injection Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md A complete example showing how to register a factory with teardown logic and inject it into a slash command. ```python import aiohttp import hikari import lightbulb # Returns a random 200x200 image when fetched with a GET request RANDOM_IMAGE_URL = "https://picsum.photos/200" # Initialise the bot and Lightbulb client bot = hikari.GatewayBot("your token") client = lightbulb.client_from_app(bot) # Hook client into bot's lifecycle bot.subscribe(hikari.StartingEvent, client.start) bot.subscribe(hikari.StoppingEvent, client.stop) # Define the dependency teardown method async def close_client_session(cs: aiohttp.ClientSession) -> None: await cs.close() # Register the dependency we want to use later client.di.registry_for(lightbulb.di.Contexts.DEFAULT).register_factory( aiohttp.ClientSession, lambda: aiohttp.ClientSession(), teardown=close_client_session, ) @client.register class RandomImage( lightbulb.SlashCommand, name="random-image", description="Generates a random image using the picsum API" ): # The 'lightbulb.invoke` decorator enables dependency injection on the function, so we # do not need to include the 'lightbulb.di.with_di' decorator here @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context, cs: aiohttp.ClientSession) -> None: # Fetch the image using the injected ClientSession dependency async with cs.get(RANDOM_IMAGE_URL) as resp: image = await resp.read() # Respond to the command with the image await ctx.respond(hikari.Bytes(image, "image.jpg")) # Run the bot bot.run() ``` -------------------------------- ### Create a Poll with Select Menu Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt This example demonstrates how to create an interactive poll using a select menu. It defines callbacks for handling votes and displaying results. Ensure the `hikari` and `lightbulb` libraries are installed. ```python import hikari import lightbulb from lightbulb.components import menus @client.register() class Poll( lightbulb.SlashCommand, name="poll", description="Create a poll", ): question = lightbulb.string("question", "Poll question") @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: votes = {} async def on_vote(menu_ctx: menus.MenuContext) -> None: selected = menu_ctx.selected_values_for(select) if selected: votes[menu_ctx.user.id] = selected[0] await menu_ctx.respond("Vote recorded!", ephemeral=True) async def on_results(menu_ctx: menus.MenuContext) -> None: results = {} for vote in votes.values(): results[vote] = results.get(vote, 0) + 1 result_text = "\n".join(f"{k}: {v} votes" for k, v in results.items()) menu_ctx.stop_interacting() await menu_ctx.respond(f"**Results:**\n{result_text}", edit=True) menu = menus.Menu() select = menu.add_text_select( options=["Option A", "Option B", "Option C"], on_select=on_vote, placeholder="Cast your vote" ) menu.add_interactive_button(hikari.ButtonStyle.PRIMARY, on_results, label="Show Results") await ctx.respond(f"**Poll:** {self.question}", components=menu) await menu.attach(ctx.client, timeout=300) ``` -------------------------------- ### Full Autocomplete Command Example Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/080_autocomplete.md A complete example of a slash command with an autocomplete-able string option. The callback generates 10 random strings prefixed with the user's current input. ```python import string import random import lightbulb ALL_CHARS = string.ascii_letters + string.digits async def autocomplete_callback(ctx: lightbulb.AutocompleteContext[str]) -> None: current_value: str = ctx.focused.value or "" values_to_recommend = [ current_value + "".join(random.choices(ALL_CHARS, k=5)) for _ in range(10) ] await ctx.respond(values_to_recommend) class RandomCharacters( lightbulb.SlashCommand, name="randomchars", description="autocomplete demo command" ): text = lightbulb.string("text", "autocompleted option", autocomplete=autocomplete_callback) @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(self.text) ``` -------------------------------- ### Implement DictLocalizationProvider for Command Localization Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/090_localization.md This example shows how to set up `DictLocalizationProvider` to manage localized command names, descriptions, and option names. Ensure `localize=True` is set for the command and its options to enable localization resolution. ```python import hikari import lightbulb bot = hikari.GatewayBot(...) localization_provider = lightbulb.DictLocalizationProvider({ hikari.Locale.EN_US: { "commands.echo.name": "echo", "commands.echo.description": "repeats the given text", "commands.echo.options.text.name": "text", "commands.echo.options.text.description": "text to repeat" }, hikari.Locale.ES_ES: { "commands.echo.name": "eco", "commands.echo.description": "repite el texto dado", "commands.echo.options.text.name": "texto", "commands.echo.options.text.description": "texto a repetir" } }) client = lightbulb.client_from_app(bot, localization_provider=localization_provider) bot.subscribe(hikari.StartingEvent, client.start) @client.register class Echo( lightbulb.SlashCommand, # The below values are used as the keys from which to resolve the correct localizations from name="commands.echo.name", description="commands.echo.description", # This command should be localized localize=True, ): text = lightbulb.string( "commands.echo.options.text.name", "commands.echo.options.text.description", localize=True, ) @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(self.text) bot.run() ``` -------------------------------- ### Basic Discord Bot with Lightbulb Command Handler Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/README.md This example demonstrates how to set up a basic Discord bot using Hikari and Lightbulb. It includes importing necessary libraries, creating a bot instance, registering a simple 'ping' slash command, and running the bot. Ensure you replace 'your_token_here' with your actual bot token. ```python # Import the libraries import hikari import lightbulb # Create a GatewayBot instance bot = hikari.GatewayBot("your_token_here") client = lightbulb.client_from_app(bot) # Ensure the client starts once the bot is run bot.subscribe(hikari.StartingEvent, client.start) # Register the command with the client @client.register() class Ping( # Command type - builtins include SlashCommand, UserCommand, and MessageCommand lightbulb.SlashCommand, # Command declaration parameters name="ping", description="checks the bot is alive", ): # Define the command's invocation method. This method must take the context as the first # argument (excluding self) which contains information about the command invocation. @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: # Send a message to the channel the command was used in await ctx.respond("Pong!") # Run the bot # Note that this is blocking meaning no code after this line will run # until the bot is shut off bot.run() ``` -------------------------------- ### Demonstrate Context Methods Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt This example showcases various methods available on the `lightbulb.Context` object for interacting with Discord. It covers basic responses, editing messages, sending follow-ups, ephemeral messages, and accessing context properties like user, channel, and guild information. ```python import lightbulb @client.register() class ContextDemo( lightbulb.SlashCommand, name="demo", description="Demonstrates context methods", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: # Basic response response_id = await ctx.respond("Processing...") # Edit the response await ctx.edit_response(response_id, content="Done processing!") # Send a follow-up message await ctx.respond("Here's a follow-up message!") # Ephemeral response (only visible to the user) await ctx.respond("Only you can see this!", ephemeral=True) # Access context properties print(f"User: {ctx.user.username}") print(f"Channel: {ctx.channel_id}") print(f"Guild: {ctx.guild_id}") print(f"Member: {ctx.member}") ``` -------------------------------- ### Install hikari-lightbulb with pip Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/README.md Use pip to install the hikari-lightbulb library. This is the standard method for installing Python packages. ```bash pip install hikari-lightbulb ``` -------------------------------- ### Hook Client into Bot Lifecycle Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Subscribe the client's start and stop methods to the bot's lifecycle events. ```python bot.subscribe(hikari.StartingEvent, client.start) bot.subscribe(hikari.StoppingEvent, client.stop) ``` -------------------------------- ### Create a Basic Discord Bot with a Slash Command Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/quickstart.md Create a simple Discord bot using Hikari-Lightbulb. This example includes a 'ping' slash command that responds with 'Pong!'. Ensure your token is correctly set. ```python # Import the libraries import hikari import lightbulb # Create a GatewayBot instance bot = hikari.GatewayBot("your_token_here") client = lightbulb.client_from_app(bot) # Ensure the client will be started when the bot is run bot.subscribe(hikari.StartingEvent, client.start) # Register the command with the client @client.register() class Ping( # Command type - builtins include SlashCommand, UserCommand, and MessageCommand lightbulb.SlashCommand, # Command declaration parameters name="ping", description="checks the bot is alive", ): # Define the command's invocation method. This method must take the context as the first # argument (excluding self) which contains information about the command invocation. @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: # Send a message to the channel the command was used in await ctx.respond("Pong!") # Run the bot # Note that this is blocking meaning no code after this line will run # until the bot is shut off bot.run() ``` -------------------------------- ### Load Extensions Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/070_extensions.md Methods for loading extensions via import paths or packages. Note that these methods are asynchronous and should be called before starting the client. ```python await client.load_extensions("extensions.echo", "extensions.ping") ``` ```python import extensions await client.load_extensions_from_package(extensions) ``` -------------------------------- ### Define All Supported Option Types Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/020_options.md Demonstrates how to declare various option types supported by Lightbulb, including string, integer, boolean, number, user, channel, role, mentionable, and attachment. Usage for each type mirrors the string option example. ```python class YourCommand( lightbulb.SlashCommand, ... ): string = lightbulb.string(...) integer = lightbulb.integer(...) boolean = lightbulb.boolean(...) number = lightbulb.number(...) user = lightbulb.user(...) channel = lightbulb.channel(...) role = lightbulb.role(...) mentionable = lightbulb.mentionable(...) attachment = lightbulb.attachment(...) @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: ... ``` -------------------------------- ### Defer Response for Slow Commands Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt This example demonstrates how to defer a response for commands that might take a long time to complete. This is useful for long-running operations, preventing the Discord API from timing out the interaction. The `ctx.defer()` method should be called before any significant processing. ```python import lightbulb @client.register() class DeferExample( lightbulb.SlashCommand, name="slow", description="A slow command that defers", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: # Defer the response for long operations await ctx.defer() # Simulate long operation import asyncio await asyncio.sleep(5) # Now respond (edits the deferred response) await ctx.respond("Finally done!") ``` -------------------------------- ### Registering a dependency in the DEFAULT context Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Demonstrates how to retrieve the registry for the default context and register a factory for an aiohttp.ClientSession. ```python import aiohttp import lightbulb client = lightbulb.client_from_app(...) # Get the registry for the default context registry = client.di.registry_for(lightbulb.di.Contexts.DEFAULT) # Register our new dependency registry.register_factory(aiohttp.ClientSession, lambda: aiohttp.ClientSession()) ``` -------------------------------- ### Run the Bot Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Standard Python entry point to run the bot application. ```python if __name__ == "__main__": bot.run() ``` -------------------------------- ### Initialize Lightbulb Client with Hikari Bots Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/000_preface.md Create a Lightbulb client instance from either a GatewayBot or a RESTBot application. ```python import hikari import lightbulb bot = hikari.GatewayBot( token="...", ) # Set up the lightbulb client client = lightbulb.client_from_app(bot) ``` ```python import hikari import lightbulb bot = hikari.RESTBot( token="...", token_type="...", public_key="...", ) # Set up the lightbulb client client = lightbulb.client_from_app(bot) ``` -------------------------------- ### Create a Command Group Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/040_groups.md Instantiate a new command group with a name and description. ```python group = lightbulb.Group("group", "a command group") ``` -------------------------------- ### Create a Loader Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/070_extensions.md Initialize a new loader instance to define an extension. ```python import lightbulb loader = lightbulb.Loader() ``` -------------------------------- ### Injecting dependencies into a SlashCommand Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Demonstrates registering a factory for a dependency and injecting it into a command method. ```python import aiohttp import hikari import lightbulb bot = hikari.GatewayBot(...) client = lightbulb.client_from_app(bot) # Register the dependency - as seen before client.di.registry_for(lightbulb.di.Contexts.DEFAULT).register_factory( aiohttp.ClientSession, lambda: aiohttp.ClientSession() ) class ExampleCommand(lightbulb.SlashCommand, name="example", description="example"): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context, cs: aiohttp.ClientSession): # The 'cs' parameter will be injected upon the command being called ... ``` -------------------------------- ### Implement Flow-scoped Dependencies Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Demonstrates a wallet system using Redis where dependencies are saved back to the store via teardown logic. ```python import os import hikari import lightbulb import redis.asyncio as redis class Wallet: def __init__(self, r: redis.Redis, user_id: str, balance: int = 0) -> None: self.r = r self.user_id = user_id self.balance = balance # We are going to call this in our teardown function for the Wallet dependency # so that it gets saved back to Redis automatically async def save(self) -> None: await self.r.set(self.user_id, str(self.balance)) # Initialise the bot and Lightbulb client bot = hikari.GatewayBot("your token") client = lightbulb.client_from_app(bot) ``` -------------------------------- ### Define User and Message Commands Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Define context menu commands using `lightbulb.UserCommand` or `lightbulb.MessageCommand`. These commands automatically have a `target` attribute containing the user or message. Ensure the client is registered. ```python import lightbulb @client.register() class GetUserInfo( lightbulb.UserCommand, name="Get User Info", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: user = self.target await ctx.respond( f"**User:** {user.username}\n" f"**ID:** {user.id}\n" f"**Created:** {user.created_at}" ) @client.register() class WordCount( lightbulb.MessageCommand, name="Word Count", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: message = self.target word_count = len(message.content.split()) if message.content else 0 await ctx.respond(f"Message has {word_count} words", ephemeral=True) ``` -------------------------------- ### Declare a Basic Slash Command Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/010_commands.md Subclass lightbulb.SlashCommand and provide name and description parameters for your command. ```python class YourCommand(lightbulb.SlashCommand, name="test-command", description="a test slash command"): ... ``` -------------------------------- ### Implement GnuLocalizationProvider for Commands Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/090_localization.md Use GnuLocalizationProvider to localize command names, descriptions, and options. Ensure the `.po` files are correctly structured and named according to the provider's configuration. ```python import hikari import lightbulb bot = hikari.GatewayBot(...) client = lightbulb.client_from_app(bot, localization_provider=lightbulb.GnuLocalizationProvider("commands.po")) bot.subscribe(hikari.StartingEvent, client.start) @client.register class Echo( lightbulb.SlashCommand, # The below values are used as the keys from which to resolve the correct localizations from name="commands.echo.name", description="commands.echo.description", # This command should be localized localize=True, ): text = lightbulb.string( "commands.echo.options.text.name", "commands.echo.options.text.description", localize=True, ) @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(self.text) bot.run() ``` -------------------------------- ### Create Lightbulb Client Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Use `client_from_app` to create a Lightbulb client from a Hikari application instance. It automatically detects gateway or REST mode. Ensure to subscribe to `hikari.StartingEvent` for `client.start` and run the bot. ```python import hikari import lightbulb # Create a gateway bot with Lightbulb client bot = hikari.GatewayBot(token="YOUR_BOT_TOKEN") client = lightbulb.client_from_app( bot, default_enabled_guilds=[123456789], # Guild IDs for command registration delete_unknown_commands=True, # Remove commands not defined in code ) # Start the client when the bot starts bot.subscribe(hikari.StartingEvent, client.start) # Run the bot bot.run() ``` -------------------------------- ### Register Command using Method Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/010_commands.md Register a command by passing the command class as an argument to the client.register method. ```python class HelloWorld( lightbulb.SlashCommand, name="hello-world", description="Makes the bot say hello world" ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Hello World!") client.register(HelloWorld) # <--- ``` -------------------------------- ### Implement a custom execution step and hook Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/060_hooks.md Configures a custom execution step for automatic response deferral and registers it in the client's execution order. ```python import hikari import lightbulb # Define our custom execution step AUTO_DEFER = lightbulb.ExecutionStep("AUTO_DEFER") bot = hikari.GatewayBot(...) client = lightbulb.client_from_app( bot, # Add our custom step to the step order. Our step will run first, followed by all the # default steps lightbulb would usually use. execution_step_order=[AUTO_DEFER, *lightbulb.DEFAULT_EXECUTION_STEP_ORDER] ) bot.subscribe(hikari.StartingEvent, client.start) # Define our hook to defer the command response @lightbulb.hook(AUTO_DEFER) async def auto_defer_command_response(_: lightbulb.ExecutionPipeline, ctx: lightbulb.Context) -> None: await ctx.defer() @client.register class AutoDeferredCommand( lightbulb.SlashCommand, name="auto-defer", description="auto defer test", # Add our hook to the command hooks=[auto_defer_command_response] ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("This command was auto-deferred!") bot.run() ``` -------------------------------- ### Register Command using Decorator Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/010_commands.md Register a command directly to the Lightbulb client by using the @client.register decorator above the command class definition. ```python @client.register # <--- class HelloWorld( lightbulb.SlashCommand, name="hello-world", description="Makes the bot say hello world" ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Hello World!") ``` -------------------------------- ### Registering client shutdown callbacks Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Shows how to hook into bot lifecycle events to ensure dependency cleanup occurs on shutdown. ```python import hikari import lightbulb bot = hikari.GatewayBot(...) client = lightbulb.client_from_app(bot) # Register Client.stop to be called when the bot is stopped bot.subscribe(hikari.StoppingEvent, client.stop) ``` ```python import hikari import lightbulb bot = hikari.RESTBot(...) client = lightbulb.client_from_app(bot) # Register Client.stop to be called when the bot is stopped bot.add_shutdown_callback(client.stop) ``` -------------------------------- ### Define Basic Slash Command Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Define a slash command by subclassing `lightbulb.SlashCommand` and using the `@client.register()` decorator. The `@lightbulb.invoke` decorator marks the command's execution method. Ensure the bot and client are set up. ```python import hikari import lightbulb bot = hikari.GatewayBot(token="YOUR_BOT_TOKEN") client = lightbulb.client_from_app(bot) bot.subscribe(hikari.StartingEvent, client.start) @client.register() class Ping( lightbulb.SlashCommand, name="ping", description="Check if the bot is alive", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Pong!") bot.run() ``` -------------------------------- ### Organize Commands with Extensions and Loaders Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Loaders allow splitting commands into separate modules for better project organization. Use client.load_extensions to register these modules at runtime. ```python # extensions/greetings.py import lightbulb loader = lightbulb.Loader() @loader.command class Hello( lightbulb.SlashCommand, name="hello", description="Say hello", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Hello!") @loader.command class Goodbye( lightbulb.SlashCommand, name="goodbye", description="Say goodbye", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Goodbye!") ``` ```python # main.py import hikari import lightbulb bot = hikari.GatewayBot(token="YOUR_BOT_TOKEN") client = lightbulb.client_from_app(bot) async def on_starting(event: hikari.StartingEvent) -> None: await client.load_extensions("extensions.greetings") await client.start() bot.subscribe(hikari.StartingEvent, on_starting) bot.run() ``` -------------------------------- ### Configure Bot Logging with Specific Levels Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/quickstart.md Configure different logging levels for 'hikari' and 'lightbulb' using a dictionary for the 'logs' argument in the GatewayBot constructor. This allows fine-grained control over log verbosity. ```python import hikari # Set different logging levels for both lightbulb and hikari bot = hikari.GatewayBot( ..., logs={ "version": 1, "incremental": True, "loggers": { "hikari": {"level": "INFO"}, "hikari.ratelimits": {"level": "TRACE_HIKARI"}, "lightbulb": {"level": "DEBUG"}, }, }, ) ... bot.run() ``` -------------------------------- ### Using an Injected aiohttp.ClientSession in a Command Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Demonstrates how to inject an aiohttp.ClientSession into a command's invoke method. The 'cs' parameter will automatically receive the registered ClientSession. ```python @client.register class YourCommand(...): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context, cs: aiohttp.ClientSession) -> None: # The 'cs' parameter was passed the client session for you to use in your function ... ``` -------------------------------- ### Create Command Groups and Subgroups Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Organize related commands under a parent group and create nested subgroups for deeper command hierarchy. Register the group with the client to make commands available. ```python import lightbulb # Create a command group settings = lightbulb.Group("settings", "Configure bot settings") # Create a subgroup within the group notifications = settings.subgroup("notifications", "Notification settings") @settings.register class SetPrefix( lightbulb.SlashCommand, name="prefix", description="Set the command prefix", ): prefix = lightbulb.string("prefix", "New prefix") @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(f"Prefix set to: {self.prefix}") @notifications.register class EnableNotifications( lightbulb.SlashCommand, name="enable", description="Enable notifications", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Notifications enabled!") # Register the group with the client client.register(settings) ``` -------------------------------- ### Use Try Meta-Annotation for Resolution Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Forces the injection system to attempt creation of a dependency and fall back to the next in the union if creation fails. ```python from lightbulb.di import Try async def dependency_factory(foo: Try[Bar] | Baz) -> Bork: ... ``` -------------------------------- ### Implement Command Invocation Logic Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/010_commands.md Use the @lightbulb.invoke decorator on an async method to define the command's execution logic. This method must accept a lightbulb.Context object. ```python class HelloWorld( lightbulb.SlashCommand, name="hello-world", description="Makes the bot say hello world" ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Hello World!") ``` -------------------------------- ### Compare Default and If Meta-Annotation Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Demonstrates that omitting a meta-annotation is functionally equivalent to using the If annotation. ```python async def dependency_factory(foo: Bar) -> Baz: ... ``` ```python from lightbulb.di import If async def dependency_factory(foo: If[Bar]) -> Baz: ... ``` -------------------------------- ### Define Slash Command with Options Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Define slash commands with options by declaring class attributes using type-specific functions like `lightbulb.string()` or `lightbulb.integer()`. Options can have defaults, choices, and constraints. Ensure the client is registered. ```python import lightbulb @client.register() class Echo( lightbulb.SlashCommand, name="echo", description="Repeats the user's input", ): text = lightbulb.string("text", "Text to repeat", min_length=1, max_length=100) times = lightbulb.integer("times", "Number of repetitions", default=1, min_value=1, max_value=5) @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(self.text * self.times) @client.register() class Add( lightbulb.SlashCommand, name="add", description="Adds two numbers together", ): num1 = lightbulb.integer("num1", "First number") num2 = lightbulb.integer("num2", "Second number") @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(f"{self.num1} + {self.num2} = {self.num1 + self.num2}") @client.register() class Greet( lightbulb.SlashCommand, name="greet", description="Greets a user", ): user = lightbulb.user("user", "User to greet") greeting = lightbulb.string( "greeting", "Greeting type", default="Hello", choices=[ lightbulb.Choice("Hello", "Hello"), lightbulb.Choice("Hi", "Hi"), lightbulb.Choice("Hey", "Hey"), ] ) @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(f"{self.greeting}, {self.user.mention}!") ``` -------------------------------- ### Create a Subgroup Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/040_groups.md Link a subgroup to an existing command group using the subgroup method. ```python subgroup = group.subgroup("subgroup", "a command subgroup") ``` -------------------------------- ### Implement Prefab Cooldowns and Role Checks Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Apply rate limiting using prefab hooks like `fixed_window` to restrict command usage frequency per user. Also, use `has_roles` to ensure users possess specific roles to access commands. ```python import hikari import lightbulb @client.register() class CooldownCommand( lightbulb.SlashCommand, name="limited", description="Rate limited command", hooks=[lightbulb.prefab.fixed_window(60, 3, "user")], # 3 uses per 60 seconds per user ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Command executed!") @client.register() class RoleRequired( lightbulb.SlashCommand, name="vip", description="VIP role required", hooks=[lightbulb.prefab.has_roles(123456789, 987654321, mode="any")], # Needs any of these roles ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Welcome, VIP!") ``` -------------------------------- ### Create Interactive Component Menus Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Use the menus module to attach interactive buttons to responses. Call menu.attach to enable interaction handling for the specified timeout duration. ```python import hikari import lightbulb from lightbulb.components import menus @client.register() class Counter( lightbulb.SlashCommand, name="counter", description="Interactive counter", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: count = 0 async def on_increment(menu_ctx: menus.MenuContext) -> None: nonlocal count count += 1 await menu_ctx.respond(f"Count: {count}", edit=True, rebuild_menu=True) async def on_decrement(menu_ctx: menus.MenuContext) -> None: nonlocal count count -= 1 await menu_ctx.respond(f"Count: {count}", edit=True, rebuild_menu=True) async def on_reset(menu_ctx: menus.MenuContext) -> None: nonlocal count count = 0 await menu_ctx.respond(f"Count: {count}", edit=True, rebuild_menu=True) async def on_done(menu_ctx: menus.MenuContext) -> None: menu_ctx.stop_interacting() await menu_ctx.respond(f"Final count: {count}", edit=True) menu = menus.Menu() menu.add_interactive_button(hikari.ButtonStyle.PRIMARY, on_increment, label="+1") menu.add_interactive_button(hikari.ButtonStyle.PRIMARY, on_decrement, label="-1") menu.add_interactive_button(hikari.ButtonStyle.SECONDARY, on_reset, label="Reset") menu.add_interactive_button(hikari.ButtonStyle.DANGER, on_done, label="Done") await ctx.respond(f"Count: {count}", components=menu) await menu.attach(ctx.client, timeout=60) ``` -------------------------------- ### Implement a User Context Menu Command Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/030_context_menus.md Defines a command triggered by right-clicking a user, accessing the user ID via self.target. ```python class GetUserId( lightbulb.UserCommand, name="Get ID", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: # 'self.target' contains the user object the command was executed on await ctx.respond(self.target.id) ``` -------------------------------- ### Define Slash Command with Dependency Injection Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Define a slash command that automatically injects a Wallet instance into its invoke method. ```python @client.register class Balance( lightbulb.SlashCommand, name="balance", description="Get your current balance", ): # The 'lightbulb.invoke` decorator enables dependency injection on the function, so we # do not need to include the 'lightbulb.di.with_di' decorator here @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context, wallet: Wallet) -> None: # The injected value for 'wallet' will be the wallet for the person who invoked the command await ctx.respond(f"Your current balance is `{wallet.balance}`.") ``` -------------------------------- ### Register Wallet Factory for Command Context Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Register the Wallet factory for the COMMAND injection context, specifying a teardown function to save the wallet. ```python client.di.registry_for(lightbulb.di.Contexts.COMMAND).register_factory( Wallet, get_wallet, teardown=lambda w: w.save() ) ``` -------------------------------- ### Create an Echo Command Using a String Option Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/020_options.md Implement an echo command that repeats user-provided text. Access the option's value within the `invoke` method using `self.`. ```python class Echo( lightbulb.SlashCommand, name="echo", description="echo", ): text = lightbulb.string("text", "the text to repeat") @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(self.text) ``` -------------------------------- ### Define Extension Components Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/070_extensions.md Use decorators to register commands, listeners, and error handlers within a loader. ```python @loader.command class YourCommand( ... ): ... ``` ```python @loader.listener(...) async def your_listener(...) -> None: ... ``` ```python @loader.error_handler async def your_error_handler(...) -> bool: ... ``` -------------------------------- ### Use Prefab Permission Checks Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Utilize built-in prefab hooks for common permission checks like administrator privileges or owner-only access. These hooks simplify command access control. ```python import hikari import lightbulb @client.register() class AdminCommand( lightbulb.SlashCommand, name="admin", description="Admin only command", hooks=[lightbulb.prefab.has_permissions(hikari.Permissions.ADMINISTRATOR)], ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("You have admin permissions!") @client.register() class OwnerCommand( lightbulb.SlashCommand, name="owner", description="Bot owner only", hooks=[lightbulb.prefab.owner_only], ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond("Hello, owner!") ``` -------------------------------- ### Implement Generic Error Handling Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Set up a general error handler with a lower priority to catch any unhandled exceptions during command execution. This ensures a fallback response for unexpected errors. ```python import lightbulb @client.error_handler(priority=-10) # Lower priority, runs last async def handle_unknown_errors(exc: lightbulb.exceptions.ExecutionPipelineFailedException) -> bool: await exc.context.respond("An unexpected error occurred!", ephemeral=True) return True ``` -------------------------------- ### Define Wallet Factory Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Define an asynchronous factory function to create Wallet instances, retrieving user balance from Redis. ```python async def get_wallet(r: redis.Redis, ctx: lightbulb.Context) -> Wallet: balance: bytes | None = await r.get(user_id := str(ctx.user.id)) return Wallet(r, user_id, 0 if balance is None else int(balance.decode("utf-8"))) ``` -------------------------------- ### Attach hooks to a command Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/060_hooks.md Demonstrates passing a list of hooks to the hooks parameter of a command class. ```python class YourCommand( lightbulb.SlashCommand, ..., hooks=[fail_if_not_thommo] ): ... ``` -------------------------------- ### English Localization File (en-US) Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/090_localization.md This `.po` file contains English translations for command names, descriptions, and options. It's used by the GnuLocalizationProvider when the locale is set to 'en-US'. ```po msgid "" msgstr "" "Project-Id-Version: Lightbulb Demo\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-07-02 15:25+0000\n" "PO-Revision-Date: 2024-07-02 15:25+0000\n" "Last-Translator: \n" "Language-Team: English\n" "Language: en-US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "commands.echo.name" msgstr "echo" msgid "commands.echo.description" msgstr "repeats the given text" msgid "commands.echo.options.text.name" msgstr "text" msgid "commands.echo.options.text.description" msgstr "text to repeat" ``` -------------------------------- ### Registering Dependencies with Factories Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Register a factory method that requires other dependencies, ensuring they are fulfilled before the factory is called. ```python import aiohttp import lightbulb class Config: base_url: str client = lightbulb.client_from_app(...) registry = client.di.registry_for(lightbulb.di.Contexts.DEFAULT) registry.register_value(Config, Config()) # Define the factory dependencies using type hints. # A valid factory must pass all the following conditions for every parameter: # - MUST not have a default value, unless the default value is exactly 'lightbulb.di.INJECTED' # - MUST not be positional only, var positional (*args), or var keyword (**kwargs) # - SHOULD have a type-hint. If no type-hint provided, a dependency will attempt to be resolved from the parameter name # ^^^ this **ONLY** applies to factory methods - for injectable methods, type-hints MUST be provided def create_client_session(cfg: Config) -> aiohttp.ClientSession: return aiohttp.ClientSession(cfg.base_url) registry.register_factory(aiohttp.ClientSession, create_client_session) ``` -------------------------------- ### Define a String Option for a Slash Command Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/020_options.md Define a simple string option for a slash command by declaring it as a class variable using `lightbulb.string()`. Ensure options are defined in the correct order, with required options preceding optional ones. ```python class YourCommand( lightbulb.SlashCommand, ... ): # Simple string option. text = lightbulb.string("text", "text option") @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: ... ``` -------------------------------- ### Configure Bot Logging with 'DEBUG' Level Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/quickstart.md Set the logging level for both Hikari and Lightbulb to 'DEBUG' using the 'logs' argument in the GatewayBot constructor. This can provide more detailed output for debugging. ```python import hikari # Set to debug for both lightbulb and hikari bot = hikari.GatewayBot(..., logs="DEBUG") ... bot.run() ``` -------------------------------- ### Implement Autocomplete for Slash Commands Source: https://context7.com/tandemdude/hikari-lightbulb/llms.txt Use AutocompleteContext to filter and return suggestions to Discord. Discord limits the response to a maximum of 25 choices. ```python import lightbulb async def color_autocomplete(ctx: lightbulb.AutocompleteContext[str]) -> None: colors = ["red", "green", "blue", "yellow", "purple", "orange"] current = ctx.focused.value or "" filtered = [c for c in colors if current.lower() in c.lower()] await ctx.respond(filtered[:25]) # Discord limits to 25 choices @client.register() class ColorPicker( lightbulb.SlashCommand, name="color", description="Pick a color", ): color = lightbulb.string("color", "Choose a color", autocomplete=color_autocomplete) @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: await ctx.respond(f"You chose: {self.color}") ``` -------------------------------- ### Registering Multiple Dependencies of the Same Type Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Use typing.NewType to distinguish between multiple dependencies of the same underlying type. ```python from typing import NewType import aiohttp import lightbulb client = lightbulb.client_from_app(...) registry = client.di.registry_for(lightbulb.di.Contexts.DEFAULT) # Create a new type to represent your dependency ClientSession1 = NewType("ClientSession1", aiohttp.ClientSession) ClientSession2 = NewType("ClientSession2", aiohttp.ClientSession) # Register the dependencies registry.register_factory(ClientSession1, lambda: aiohttp.ClientSession()) registry.register_factory(ClientSession2, lambda: aiohttp.ClientSession()) # You must then refer using the new type where you want them to be injected # For this reason it is recommended you define the new types within a separate file, so they can be easily reused @lightbulb.di.with_di async def example(cs1: ClientSession1, cs2: ClientSession2) -> None: ... ``` -------------------------------- ### Spanish Localization File (es-ES) Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/090_localization.md This `.po` file contains Spanish translations for command names, descriptions, and options. It's used by the GnuLocalizationProvider when the locale is set to 'es-ES'. ```po msgid "" msgstr "" "Project-Id-Version: Lightbulb Demo\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-07-02 15:25+0000\n" "PO-Revision-Date: 2024-07-02 15:25+0000\n" "Last-Translator: \n" "Language-Team: Spanish\n" "Language: es-ES\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "commands.echo.name" msgstr "eco" msgid "commands.echo.description" msgstr "repite el texto dado" msgid "commands.echo.options.text.name" msgstr "texto" msgid "commands.echo.options.text.description" msgstr "texto a repetir" ``` -------------------------------- ### Registering an aiohttp.ClientSession Dependency Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Registers an aiohttp.ClientSession as a dependency using a factory function. This session will be available for injection into DI-enabled functions. ```python import aiohttp client.di.registry_for(lightbulb.di.Contexts.DEFAULT).register_factory( aiohttp.ClientSession, lambda: aiohttp.ClientSession() ) ``` -------------------------------- ### Create a command hook Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/060_hooks.md Defines a hook using the lightbulb.hook decorator that validates the user ID. Raising an exception within the hook will fail the execution pipeline. ```python @lightbulb.hook(lightbulb.ExecutionSteps.CHECKS) def fail_if_not_thommo(_: lightbulb.ExecutionPipeline, ctx: lightbulb.Context) -> None: if ctx.user.id != 215061635574792192: raise RuntimeError("only thomm.o can use this command") ``` -------------------------------- ### Implement a Message Context Menu Command Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/030_context_menus.md Defines a command triggered by right-clicking a message, accessing the message ID via self.target. ```python class GetMessageId( lightbulb.MessageCommand, name="Get ID", ): @lightbulb.invoke async def invoke(self, ctx: lightbulb.Context) -> None: # 'self.target' contains the message object the command was executed on await ctx.respond(self.target.id) ``` -------------------------------- ### Define a custom execution step Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/060_hooks.md Creates a new execution step instance with a unique ID. ```python YOUR_STEP = lightbulb.ExecutionStep("YOUR_STEP_ID") ``` -------------------------------- ### Register Redis Client Factory Source: https://github.com/tandemdude/hikari-lightbulb/blob/master/docs/source/by-examples/050_dependencies.md Register a factory for the redis.Redis client, creating it from an environment variable and defining a teardown function. ```python client.di.registry_for(lightbulb.di.Contexts.DEFAULT).register_factory( redis.Redis, lambda: redis.from_url(os.environ["REDIS_URL"]), teardown=redis.Redis.aclose ) ```