Skip to content

API Docs

iRedSC edited this page Jan 16, 2025 · 13 revisions

InvokeEngine

class InvokeEngine:
    commands: dict[str, Command]

In the following examples we will assume the following:

engine = InvokeEngine()

.command

engine.command(
        self,
        func: Union[callable, Command, meta] = None,
        name: str = None,
        aliases: list[str] = None,
    ) -> Command

Turns the decorated function into a Command object. This will also add the command to the engine's commands property, which is used to parse the command from a list of values.

By default name will be set to the name of the decorated function. Name is also not replaced when using aliases.

It is possible to add commands to multiple engines by stacking their decorators.

Examples:

Simple Decorator
@engine.command
def greet(user: str):
    ...
Change Command Name
@engine.command(name="welcome")
def greet(user: str):
    ...

assert greet.name == "welcome"
Change Aliases
@engine.command(aliases=["welcome", "hello"])
def greet(user: str):
    ...

assert greet.name == "greet"
assert greet.aliases == ["welcome", "hello"]

.parse

engine.parse(
        command_list: list[any],
        _command: Command = None,
        _callstack: list[Command] = None,
    ) -> tuple[Command, tuple[any, ...], tuple[Command, ...]]

Recursively traverses the engine's command list, and any subcommands until no match can be found. Returns a tuple with the following values:

  1. Command: The lowest command/subcommand that could be found.
  2. tuple[any, ...]: The rest of the list once no more subcommands could be found.
  3. tuple[Command, ...]: The callstack; A tuple of the all commands that were traversed.

The result can be unpacked like so:

cmd, args, cs = engine.parse(...)

# if you don't need any arguments or the callstack
cmd, *_ = engine.parse(...)

Examples:

Parse Single Command
@engine.command
def greet(user: str) -> str:
    return f"Hello {user}!"

cmd, args, _ = engine.parse(["greet", "iRedSC"])

result = cmd(*args)

assert result == "Hello iRedSC!"
Parse Subcommand
@engine.command
def greet(user: str) -> str:
    return f"Hello {user}!"

@greet.subcommand
def many(*users: str) -> str:
    return f"Hello {', '.join(users)}!"

cmd, args, _ = engine.parse(["greet", "many", "iRedSC", "Blibs"])
result = cmd(*args)
assert result == "Hello iRedSC, Blibs!"

cmd, args, _ = engine.parse(["greet", "Blibs"])
result = cmd(*args)
assert result == "Hello Blibs!"

Command

class Command:
    func: callable # The function or method that was transformed into a Command.
    name: str
    aliases: list[str] 
    requires: dict[str, bool] # The requirements for the command, this can be accessed for custom tests.
    injections: dict[str, any] # Objects that will be injected into the command as kwargs.
    children: dict[str, Command] # Similar to engine.commands; Lists the subcommands attached to a command.
    helptext: str = None

You will generally only create Command objects with either the @engine.command decorator, or the @command.subcommand decorator.

In the following examples we will assume the following:

@engine.command
def greet(user: str):
    ...

.subcommand

greet.subcommand(
        self,
        func: Union[callable, "Command", meta] = None,
        name: str = None,
        aliases: list[str] = None,
    ) -> Command

.requires

The requirements of a command. See meta.require for setting requirements.


.injections

The objects that will be injected into a command. See meta.inject for setting injections.


meta

class meta:
    requires: dict[str, bool]
    injections: dict[str, any]
    func: callable = None
    helptext: str = ""

The meta class allows you to inject metadata about a command into the command's callable.


.require

@engine.command
@meta.requires(req1=True, req2=True)
def greet(...):
    ...

assert greet.requires == {"req1": True, "req2": True}

You can use the meta class to insert requirements for a command. Arbitrary data can be passed without issue. Requiring command=True will automatically inject the command into the command's callable. Requiring engine=True will require an engine to be passed as a keyword argument, and will throw an EngineRequired exception if it isn't fulfilled.

Requiring a Command
@engine.command
@meta.require(command=True) # The command will automatically be injected.
def help(command):
    print(command.helptext)
Requiring an Engine
@engine.command
@meta.require(engine=True) # Sets requiring an engine, the engine will need to be manually passed.
def help(command):
    print(command.helptext)

If you want to automatically pass an engine in, please look at meta.inject.


.inject

var = 10

@engine.command
@meta.inject(num=var)
def greet(num):
    return num

assert greet() == 10

You can use the meta class to inject objects into the command's callable. The argument in the callable needs to match the parameter in the inject statement.


string_to_args

string_to_args(string: str) -> list[str, int, float, list]

Invokify has a simple string parser that will return a list of values, keeping things like "quoted strings" intact.

Words
user_input = "simple test string"

result = string_to_args(user_input)

assert result == ["simple", "test", "string"]
Numbers
user_input = "5 5.67 -76 -34.5 .5 9."

result = string_to_args(user_input)

assert result == [5, 5.67, -76, -34.5, 0.5, 9.0]
Quoted Strings
user_input = 'here are "some quoted strings"'

result = string_to_args(user_input)

assert result == ["here", "are", "some quoted strings"]
Lists
user_input = "here is [a, list of, values]"

result = string_to_args(user_input)

assert result == ["here", "is", ["a", "list of", "values"]]

Clone this wiki locally