Skip to content

Parsers

These are a handful of built-in parsers that you can use with niobot.Argument.

How do I use these?

To use a parser, you simply pass parser=<function> when creating Argument(). For example:

from niobot import Argument, command, NioBot
from niobot.utils.parsers import float_parser

bot = NioBot(...)

@bot.command(
    name="sum", 
    arguments=[
        Argument("num1", parser=float_parser),
        Argument("num2", parser=float_parser)
    ]
)
async def add_numbers(ctx: Context, num1: float, num2: float):
    await ctx.respond("{!s} + {!s} = {!s}".format(num1, num2, num1 + num2))

bot.run(...)

While this is roughly equivalent to Argument("num1", type=float), it can be helpful in cases like json_parser where you need to parse complex types.

Tip

You can also create your own parsers! See Creating Parsers for more information.

This utility modules contains a handful of simple off-the-shelf parser for some basic python types.

Parser

Bases: ABC

A base model class for parsers.

This ABC defines one uniform method, which is __call__, which takes a Context instance, Argument instance, and the user-provided string value.

This parser is designed to be instantiated, and then called with the above arguments. If you want to make a simple parser that does not take additional configuration, it is recommended to use StatelessParser instead.

StatelessParser

Bases: Parser, ABC

A parser base that will not be instantiated, but rather called directly.

This is useful for parsers that do not take any configuration (such as the simple BooleanParser), where a simple one-off call is enough.

Traditionally, you'd call a Parser like this:

parser = Parser(my_argument=True)
result = parser(ctx, arg, value)
# or, in one line
result = Parser(my_argument=True)(ctx, arg, value)

However, for some simple parsers, there's no need to instantiate them. Instead, you can call them directly. The StatelessParser ABC adds the parse classmethod, meaning you can simply do the following:

result = Parser.parse(ctx, arg, value)
Which is just a shortand for the above one-liner. This offers little to no performance benefit, however can make code look cleaner.

As this ABC subclasses the regular Parser, you can still use the traditional instantiation+call method.

parse classmethod

parse(
    ctx: Context, arg: Argument, value: str
) -> Optional[Any]

Parses the given value using this parser without needing to call __init__() first.

Parameters:

Name Type Description Default
ctx Context

The context instance

required
arg Argument

The argument instance

required
value str

The value to parse

required

Returns:

Type Description
typing.Optional[typing.Any]

The parsed value

BooleanParser

Bases: StatelessParser

Converts a given string into a boolean. Value is casefolded before being parsed.

The following resolves to true: * 1, y, yes, true, on

The following resolves to false: * 0, n, no, false, off

The following will raise a command argument error: anything else

Returns:

Type Description
bool

A parsed boolean

FloatParser

Bases: StatelessParser

Converts a given string into a floating point number.

Returns:

Type Description
float

A parsed floating point number

Raises:

Type Description
CommandParserError

if the value is not a valid number.

IntegerParser

Bases: Parser

Parses an integer, or optionally a real number.

Parameters:

Name Type Description Default
allow_floats bool

Whether to simply defer non-explicit-integer values to the float parser. This results in the return type being float

False
base int

The base to parse the integer in. Defaults to 10 (denary). 2 is Binary, and 16 is Hexadecimal.

10

Returns:

Type Description
Union[int, float]

A parsed integer or float, depending on input & allow_floats

Raises:

Type Description
CommandParserError

if the value is not a valid number.

JSONParser

Bases: StatelessParser

Converts a given string into a JSON object.

Performance boost

If you want this to be fast, you should install orjson. It is a drop-in replacement for the standard library. While the parser will still work without it, it may be slower, especially for larger payloads.

Returns:

Type Description
Union[dict, list, str, int, float, None, bool]

The parsed JSON object

Raises:

Type Description
CommandParserError

if the value is not a valid JSON object.

RoomParser

Bases: StatelessParser

Parses a room ID, alias, or matrix.to link into a MatrixRoom object.

This parser is async

This parser is async, and should be awaited when used manually.

Returns:

Type Description
nio.MatrixRoom

The parsed room instance

EventParser

Bases: Parser

Parses an event reference from either its ID, or matrix.to link.

Parameters:

Name Type Description Default
event_type Optional[str]

The event type to expect (such as m.room.message). If None, any event type is allowed.

None

Returns:

Type Description
typing.Coroutine

The actual internal (async) parser.

MatrixDotToParser

Bases: Parser

Converts a matrix.to link into a MatrixRoomLink namedtuple, which consists of the room, event, and any query passed to the URL.

Parameters:

Name Type Description Default
domain str

The domain to check for. Defaults to matrix.to, consistent with average client behaviour.

'matrix.to'
require_room bool

Whether to require the room part of this url to be present

True
require_event bool

Whether to require the event part of this url to be present

False
allow_user_as_room bool

Whether to allow user links as room links

True
stateless bool

If true, the link will only be parsed, not resolved. This means rooms will stay as their IDs, etc.

False

Returns:

Type Description
typing.Coroutine

The actual internal (async) parser.

MXCParser

Bases: StatelessParser

Parses an MXC URL into a MatrixMXCUrl namedtuple, which consists of the server and media ID.

Returns:

Type Description
MatrixMXCUrl (namedtuple)

The parsed MXC URL

MatrixUserParser

Bases: StatelessParser

Parses a string into a MatrixUser instance from matrix-nio.


Creating Parsers

The old way (pre-1.1.0)

Creating your own parser is actually really easy. All the library needs from you is a function that:

  • Takes niobot.Context as its first argument
  • Takes niobot.Argument as its second argument
  • Takes a string (the user's input) as its third argument
  • Returns a sensible value
  • Or, raises CommandArgumentsError with a helpful error message.

Do all of this, and you can very easily just pass this to Argument!

For example, if you wanted to take a datetime, you could write your own parser like this:

from datetime import datetime
from niobot import Argument, command, NioBot


def datetime_parser(ctx: Context, arg: Argument, user_input: str):
    try:
        return datetime.strptime(user_input, "%Y-%m-%d %H:%M:%S")
    except ValueError:
        raise CommandArgumentsError("Invalid datetime format. Expected YYYY-MM-DD HH:MM:SS")

bot = NioBot(...)


@bot.command(name="remindme", arguments=[Argument("time", arg_type=datetime, parser=datetime_parser)])
async def remind_me(ctx: Context, time: datetime):
    await ctx.respond("I'll remind you at {}!".format(time.strftime("%c")))

bot.run(...)

Creating custom parsers for nio-bot is really simple. All you need to do is subclass either Parser or StatelessParser and implement the parse method.

However, if you want some detailed information, seek the guide