evennia/docs/source/Components/FuncParser.md

447 lines
21 KiB
Markdown
Raw Normal View History

2021-03-17 20:52:51 +01:00
# The Inline Function Parser
2021-10-21 21:04:14 +02:00
The [FuncParser](evennia.utils.funcparser.FuncParser) extracts and executes
2021-03-27 19:20:21 +01:00
'inline functions'
2021-10-21 21:04:14 +02:00
embedded in a string on the form `$funcname(args, kwargs)`. Under the hood, this will
lead to a call to a Python function you control. The inline function call will be replaced by
the return from the function.
2021-03-17 20:52:51 +01:00
2021-10-21 21:04:14 +02:00
```python
from evennia.utils.funcparser import FuncParser
2021-03-17 20:52:51 +01:00
def _power_callable(*args, **kwargs):
2022-06-12 00:40:36 +02:00
"""This will be callable as $pow(number, power=<num>) in string"""
pow = int(kwargs.get('power', 2))
return float(args[0]) ** pow
2022-06-12 00:40:36 +02:00
# create a parser and tell it that '$pow' means using _power_callable
parser = FuncParser({"pow": _power_callable})
2021-03-27 19:20:21 +01:00
```
2022-06-12 00:40:36 +02:00
Next, just pass a string into the parser, containing `$func(...)` markers:
2021-03-27 19:20:21 +01:00
```python
parser.parse("We have that 4 x 4 x 4 is $pow(4, power=3).")
"We have that 4 x 4 x 4 is 64."
```
2021-03-27 19:20:21 +01:00
Normally the return is always converted to a string but you can also get the actual data type from the call:
```python
parser.parse_to_any("$pow(4)")
16
```
2021-03-27 19:20:21 +01:00
To show a `$func()` verbatim in your code without parsing it, escape it as either `$$func()` or `\$func()`:
2021-03-27 19:20:21 +01:00
```python
parser.parse("This is an escaped $$pow(4) and so is this \$pow(3)")
"This is an escaped $pow(4) and so is this $pow(3)"
2021-03-27 19:20:21 +01:00
```
2021-03-27 19:20:21 +01:00
## Uses in default Evennia
2021-03-17 20:52:51 +01:00
2021-03-27 19:20:21 +01:00
The FuncParser can be applied to any string. Out of the box it's applied in a few situations:
2021-03-27 19:20:21 +01:00
- _Outgoing messages_. All messages sent from the server is processed through FuncParser and every
2021-10-21 21:04:14 +02:00
callable is provided the [Session](./Sessions.md) of the object receiving the message. This potentially
2021-03-27 19:20:21 +01:00
allows a message to be modified on the fly to look different for different recipients.
2021-10-21 21:04:14 +02:00
- _Prototype values_. A [Prototype](./Prototypes.md) dict's values are run through the parser such that every
2021-03-27 19:20:21 +01:00
callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders
to safely call functions to set non-string values to prototype values, get random values, reference
other fields of the prototype, and more.
- _Actor-stance in messages to others_. In the
2021-10-21 21:04:14 +02:00
[Object.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method,
2021-03-27 19:20:21 +01:00
the outgoing string is parsed for special `$You()` and `$conj()` callables to decide if a given recipient
should see "You" or the character's name.
2021-10-21 21:04:14 +02:00
```{important}
2021-03-27 19:20:21 +01:00
The inline-function parser is not intended as a 'softcode' programming language. It does not
2021-10-21 21:04:14 +02:00
have things like loops and conditionals, for example. While you could in principle extend it to
do very advanced things and allow builders a lot of power, all-out coding is something
2021-03-27 19:20:21 +01:00
Evennia expects you to do in a proper text editor, outside of the game, not from inside it.
2021-03-17 20:52:51 +01:00
```
2021-10-21 21:04:14 +02:00
## Using the FuncParser
You can apply inline function parsing to any string. The
[FuncParser](evennia.utils.funcparser.FuncParser) is imported as `evennia.utils.funcparser`.
2021-03-17 20:52:51 +01:00
```python
from evennia.utils import funcparser
parser = FuncParser(callables, **default_kwargs)
2022-06-12 00:40:36 +02:00
parsed_string = parser.parse(input_string, raise_errors=False,
2021-10-21 21:04:14 +02:00
escape=False, strip=False,
return_str=True, **reserved_kwargs)
2021-03-17 20:52:51 +01:00
# callables can also be passed as paths to modules
parser = FuncParser(["game.myfuncparser_callables", "game.more_funcparser_callables"])
2021-03-17 20:52:51 +01:00
```
2021-10-21 21:04:14 +02:00
Here, `callables` points to a collection of normal Python functions (see next section) for you to make
2021-03-27 19:20:21 +01:00
available to the parser as you parse strings with it. It can either be
- A `dict` of `{"functionname": callable, ...}`. This allows you do pick and choose exactly which callables
to include and how they should be named. Do you want a callable to be available under more than one name?
Just add it multiple times to the dict, with a different key.
2021-10-21 21:04:14 +02:00
- A `module` or (more commonly) a `python-path` to a module. This module can define a dict
`FUNCPARSER_CALLABLES = {"funcname": callable, ...}` - this will be imported and used like the `dict` above.
2021-10-21 21:04:14 +02:00
If no such variable is defined, _every_ top-level function in the module (whose name doesn't start with
an underscore `_`) will be considered a suitable callable. The name of the function will be the `$funcname`
2021-03-27 19:20:21 +01:00
by which it can be called.
- A `list` of modules/paths. This allows you to pull in modules from many sources for your parsing.
2022-06-12 00:40:36 +02:00
- The `**default` kwargs are optional kwargs that will be passed to _all_
callables every time this parser is used - unless the user overrides it explicitly in
their call. This is great for providing sensible standards that the user can
tweak as needed.
2021-10-21 21:04:14 +02:00
2022-06-12 00:40:36 +02:00
`FuncParser.parse` takes further arguments, and can vary for every string parsed.
2021-03-27 19:20:21 +01:00
2021-10-21 21:04:14 +02:00
- `raise_errors` - By default, any errors from a callable will be quietly ignored and the result
will be that the failing function call will show verbatim. If `raise_errors` is set,
then parsing will stop and whatever exception happened will be raised. It'd be up to you to handle
2021-03-27 19:20:21 +01:00
this properly.
- `escape` - Returns a string where every `$func(...)` has been escaped as `\$func()`.
- `strip` - Remove all `$func(...)` calls from string (as if each returned `''`).
2021-10-21 21:04:14 +02:00
- `return_str` - When `True` (default), `parser` always returns a string. If `False`, it may return
the return value of a single function call in the string. This is the same as using the `.parse_to_any`
method.
2022-06-12 00:40:36 +02:00
- The `**reserved_keywords` are _always_ passed to every callable in the string.
They override any `**defaults` given when instantiating the parser and cannot
be overridden by the user - if they enter the same kwarg it will be ignored.
This is great for providing the current session, settings etc.
- The `funcparser` and `raise_errors`
are always added as reserved keywords - the first is a
back-reference to the `FuncParser` instance and the second
is the `raise_errors` boolean given to `FuncParser.parse`.
2021-10-21 21:04:14 +02:00
Here's an example of using the default/reserved keywords:
2021-03-17 20:52:51 +01:00
```python
def _test(*args, **kwargs):
# do stuff
return something
2021-03-17 20:52:51 +01:00
parser = funcparser.FuncParser({"test": _test}, mydefault=2)
result = parser.parse("$test(foo, bar=4)", myreserved=[1, 2, 3])
2021-03-17 20:52:51 +01:00
```
2021-10-21 21:04:14 +02:00
Here the callable will be called as
2021-03-17 20:52:51 +01:00
2021-03-27 19:20:21 +01:00
```python
2021-10-21 21:04:14 +02:00
_test('foo', bar='4', mydefault=2, myreserved=[1, 2, 3],
funcparser=<FuncParser>, raise_errors=False)
2021-03-27 19:20:21 +01:00
```
2021-10-21 21:04:14 +02:00
The `mydefault=2` kwarg could be overwritten if we made the call as `$test(mydefault=...)`
but `myreserved=[1, 2, 3]` will _always_ be sent as-is and will override a call `$test(myreserved=...)`.
2021-03-27 19:20:21 +01:00
The `funcparser`/`raise_errors` kwargs are also always included as reserved kwargs.
2021-03-17 20:52:51 +01:00
## Defining custom callables
All callables made available to the parser must have the following signature:
2021-03-17 20:52:51 +01:00
```python
def funcname(*args, **kwargs):
# ...
return something
2021-03-17 20:52:51 +01:00
```
2021-10-21 21:04:14 +02:00
> The `*args` and `**kwargs` must always be included. If you are unsure how `*args` and `**kwargs` work in Python,
2021-03-27 19:20:21 +01:00
> [read about them here](https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3).
2021-03-17 20:52:51 +01:00
2021-10-21 21:04:14 +02:00
The input from the innermost `$funcname(...)` call in your callable will always be a `str`. Here's
2021-03-27 19:20:21 +01:00
an example of an `$toint` function; it converts numbers to integers.
2021-03-17 20:52:51 +01:00
2021-03-27 19:20:21 +01:00
"There's a $toint(22.0)% chance of survival."
2021-03-17 20:52:51 +01:00
2021-03-27 19:20:21 +01:00
What will enter the `$toint` callable (as `args[0]`) is the _string_ `"22.0"`. The function is responsible
2021-10-21 21:04:14 +02:00
for converting this to a number so that we can convert it to an integer. We must also properly handle invalid
inputs (like non-numbers).
2021-03-17 20:52:51 +01:00
2021-03-27 19:20:21 +01:00
If you want to mark an error, raise `evennia.utils.funcparser.ParsingError`. This stops the entire parsing
2021-10-21 21:04:14 +02:00
of the string and may or may not raise the exception depending on what you set `raise_errors` to when you
2021-03-27 19:20:21 +01:00
created the parser.
2021-03-17 20:52:51 +01:00
2021-10-21 21:04:14 +02:00
However, if you _nest_ functions, the return of the innermost function may be something other than
a string. Let's introduce the `$eval` function, which evaluates simple expressions using
2022-06-12 00:40:36 +02:00
Python's `literal_eval` and/or `simple_eval`. It returns whatever data type it
evaluates to.
2021-03-17 20:52:51 +01:00
2021-10-21 21:04:14 +02:00
"There's a $toint($eval(10 * 2.2))% chance of survival."
2021-10-21 21:04:14 +02:00
Since the `$eval` is the innermost call, it will get a string as input - the string `"10 * 2.2"`.
It evaluates this and returns the `float` `22.0`. This time the outermost `$toint` will be called with
this `float` instead of with a string.
2021-10-21 21:04:14 +02:00
> It's important to safely validate your inputs since users may end up nesting your callables in any order.
> See the next section for useful tools to help with this.
2021-10-21 21:04:14 +02:00
In these examples, the result will be embedded in the larger string, so the result of the entire parsing
will be a string:
2021-03-17 20:52:51 +01:00
```python
2021-03-27 19:20:21 +01:00
parser.parse(above_string)
"There's a 22% chance of survival."
2021-03-17 20:52:51 +01:00
```
2021-03-27 19:20:21 +01:00
2022-06-12 00:40:36 +02:00
However, if you use the `parse_to_any` (or `parse(..., return_str=False)`) and
_don't add any extra string around the outermost function call_,
2021-03-27 19:20:21 +01:00
you'll get the return type of the outermost callable back:
2021-03-17 20:52:51 +01:00
```python
2021-03-27 19:20:21 +01:00
parser.parse_to_any("$toint($eval(10 * 2.2)")
22
2022-06-12 00:40:36 +02:00
parser.parse_to_any("the number $toint($eval(10 * 2.2).")
"the number 22"
parser.parse_to_any("$toint($eval(10 * 2.2)%")
"22%"
```
### Escaping special character
When entering funcparser callables in strings, it looks like a regular
function call inside a string:
```python
"This is a $myfunc(arg1, arg2, kwarg=foo)."
```
Commas (`,`) and equal-signs (`=`) are considered to separate the arguments and
kwargs. In the same way, the right parenthesis (`)`) closes the argument list.
Sometimes you want to include commas in the argument without it breaking the
argument list.
```python
"The $format(forest's smallest meadow, with dandelions) is to the west."
```
2021-03-17 20:52:51 +01:00
2022-06-12 00:40:36 +02:00
You can escape in various ways.
- Prepending special characters like `,` and `=` with the escape character `\`
2022-06-12 00:40:36 +02:00
```python
"The $format(forest's smallest meadow\, with dandelions) is to the west."
```
2022-06-12 00:40:36 +02:00
- Wrapping your strings in double quotes. Unlike in raw Python, you
can't escape with single quotes `'` since these could also be apostrophes (like
`forest's` above). The result will be a verbatim string that contains
everything but the outermost double quotes.
2022-06-12 00:40:36 +02:00
```python
'The $format("forest's smallest meadow, with dandelions") is to the west.'
```
- If you want verbatim double-quotes to appear in your string, you can escape
them with `\"` in turn.
```python
'The $format("forest's smallest meadow, with \"dandelions\"') is to the west.'
```
2022-06-12 00:40:36 +02:00
2021-03-27 19:20:21 +01:00
### Safe convertion of inputs
2022-06-12 00:40:36 +02:00
Since you don't know in which order users may use your callables, they should
always check the types of its inputs and convert to the type the callable needs.
Note also that when converting from strings, there are limits what inputs you
can support. This is because FunctionParser strings can be used by
non-developer players/builders and some things (such as complex
classes/callables etc) are just not safe/possible to convert from string
representation.
2021-03-27 19:20:21 +01:00
2021-10-21 21:04:14 +02:00
In `evennia.utils.utils` is a helper called
[safe_convert_to_types](evennia.utils.utils.safe_convert_to_types). This function
2021-03-27 19:20:21 +01:00
automates the conversion of simple data types in a safe way:
2021-03-17 20:52:51 +01:00
```python
2021-03-27 19:20:21 +01:00
from evennia.utils.utils import safe_convert_to_types
def _process_callable(*args, **kwargs):
"""
2022-06-12 00:40:36 +02:00
$process(expression, local, extra1=34, extra2=foo)
2021-10-21 21:04:14 +02:00
2021-03-27 19:20:21 +01:00
"""
args, kwargs = safe_convert_to_type(
2022-06-12 00:40:36 +02:00
(('py', str), {'extra1': int, 'extra2': str}),
2021-03-27 19:20:21 +01:00
*args, **kwargs)
2021-10-21 21:04:14 +02:00
# args/kwargs should be correct types now
```
2022-06-12 00:40:36 +02:00
In other words, in the callable `$process(expression, local, extra1=..,
extra2=...)`, the first argument will be handled by the 'py' converter
(described below), the second will passed through regular Python `str`,
kwargs will be handled by `int` and `str` respectively. You can supply
your own converter function as long as it takes one argument and returns
the converted result.
2021-03-27 19:20:21 +01:00
In other words,
2021-10-21 21:04:14 +02:00
```python
2021-03-27 19:20:21 +01:00
args, kwargs = safe_convert_to_type(
(tuple_of_arg_converters, dict_of_kwarg_converters), *args, **kwargs)
```
2022-06-12 00:40:36 +02:00
The special converter `"py"` will try to convert a string argument to a Python structure with the help of the
2021-10-21 21:04:14 +02:00
following tools (which you may also find useful to experiment with on your own):
2021-03-27 19:20:21 +01:00
- [ast.literal_eval](https://docs.python.org/3.8/library/ast.html#ast.literal_eval) is an in-built Python
function. It
_only_ supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and `None`. That's
it - no arithmetic or modifications of data is allowed. This is good for converting individual values and
lists/dicts from the input line to real Python objects.
2021-10-21 21:04:14 +02:00
- [simpleeval](https://pypi.org/project/simpleeval/) is a third-party tool included with Evennia. This
allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings
with `+-/*` as well as do simple comparisons like `4 > 3` and more. It does _not_ accept more complex
2021-03-27 19:20:21 +01:00
containers like lists/dicts etc, so this and `literal_eval` are complementary to each other.
2021-03-17 20:52:51 +01:00
2021-10-21 21:04:14 +02:00
```{warning}
It may be tempting to run use Python's in-built ``eval()`` or ``exec()`` functions as converters since
these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
know that ONLY developers will ever modify the string going into the callable. The parser is intended
for untrusted users (if you were trusted you'd have access to Python already). Letting untrusted users
pass strings to ``eval``/``exec`` is a MAJOR security risk. It allows the caller to run arbitrary
Python code on your server. This is the path to maliciously deleted hard drives. Just don't do it and
2021-03-27 19:20:21 +01:00
sleep better at night.
2021-03-17 20:52:51 +01:00
```
2021-03-27 19:20:21 +01:00
## Default callables
2021-10-21 21:04:14 +02:00
These are some example callables you can import and add your parser. They are divided into
global-level dicts in `evennia.utils.funcparser`. Just import the dict(s) and merge/add one or
2021-03-27 19:20:21 +01:00
more to them when you create your `FuncParser` instance to have those callables be available.
### `evennia.utils.funcparser.FUNCPARSER_CALLABLES`
These are the 'base' callables.
2021-10-21 21:04:14 +02:00
- `$eval(expression)` ([code](evennia.utils.funcparser.funcparser_callable_eval)) -
this uses `literal_eval` and `simple_eval` (see previous section) attemt to convert a string expression
2021-03-27 19:20:21 +01:00
to a python object. This handles e.g. lists of literals `[1, 2, 3]` and simple expressions like `"1 + 2"`.
2021-10-21 21:04:14 +02:00
- `$toint(number)` ([code](evennia.utils.funcparser.funcparser_callable_toint)) -
2021-03-27 19:20:21 +01:00
always converts an output to an integer, if possible.
2021-10-21 21:04:14 +02:00
- `$add/sub/mult/div(obj1, obj2)` ([code](evennia.utils.funcparser.funcparser_callable_add)) -
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with
`$eval`, this could for example be used also to add two lists together, which is not possible with `eval`;
2021-03-27 19:20:21 +01:00
for example `$add($eval([1,2,3]), $eval([4,5,6])) -> [1, 2, 3, 4, 5, 6]`.
2021-10-21 21:04:14 +02:00
- `$round(float, significant)` ([code](evennia.utils.funcparser.funcparser_callable_round)) -
2021-03-27 19:20:21 +01:00
rounds an input float into the number of provided significant digits. For example `$round(3.54343, 3) -> 3.543`.
2021-10-21 21:04:14 +02:00
- `$random([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_random)) -
this works like the Python `random()` function, but will randomize to an integer value if both start/end are
2021-03-27 19:20:21 +01:00
integers. Without argument, will return a float between 0 and 1.
2021-10-21 21:04:14 +02:00
- `$randint([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_randint)) -
2021-03-27 19:20:21 +01:00
works like the `randint()` python function and always returns an integer.
2021-10-21 21:04:14 +02:00
- `$choice(list)` ([code](evennia.utils.funcparser.funcparser_callable_choice)) -
the input will automatically be parsed the same way as `$eval` and is expected to be an iterable. A random
2021-03-27 19:20:21 +01:00
element of this list will be returned.
2021-10-21 21:04:14 +02:00
- `$pad(text[, width, align, fillchar])` ([code](evennia.utils.funcparser.funcparser_callable_pad)) -
2021-03-27 19:20:21 +01:00
this will pad content. `$pad("Hello", 30, c, -)` will lead to a text centered in a 30-wide block surrounded by `-`
characters.
2021-10-21 21:04:14 +02:00
- `$crop(text, width=78, suffix='[...]')` ([code](evennia.utils.funcparser.funcparser_callable_crop)) -
2021-03-27 19:20:21 +01:00
this will crop a text longer than the width, by default ending it with a `[...]`-suffix that also fits within
the width. If no width is given, the client width or `settings.DEFAULT_CLIENT_WIDTH` will be used.
2021-10-21 21:04:14 +02:00
- `$space(num)` ([code](evennia.utils.funcparser.funcparser_callable_space)) -
2021-03-27 19:20:21 +01:00
this will insert `num` spaces.
2021-10-21 21:04:14 +02:00
- `$just(string, width=40, align=c, indent=2)` ([code](evennia.utils.funcparser.funcparser_callable_justify)) -
2021-03-27 19:20:21 +01:00
justifies the text to a given width, aligning it left/right/center or 'f' for full (spread text across width).
- `$ljust` - shortcut to justify-left. Takes all other kwarg of `$just`.
- `$rjust` - shortcut to right justify.
- `$cjust` - shortcut to center justify.
2021-10-21 21:04:14 +02:00
- `$clr(startcolor, text[, endcolor])` ([code](evennia.utils.funcparser.funcparser_callable_clr)) -
color text. The color is given with one or two characters without the preceeding `|`. If no endcolor is
2021-03-27 19:20:21 +01:00
given, the string will go back to neutral, so `$clr(r, Hello)` is equivalent to `|rHello|n`.
### `evennia.utils.funcparser.SEARCHING_CALLABLES`
These are callables that requires access-checks in order to search for objects. So they require some
extra reserved kwargs to be passed when running the parser:
```python
2021-10-21 21:04:14 +02:00
parser.parse_to_any(string, caller=<object or account>, access="control", ...)
2021-03-27 19:20:21 +01:00
```
2021-10-21 21:04:14 +02:00
The `caller` is required, it's the the object to do the access-check for. The `access` kwarg is the
[lock type](./Locks.md) to check, default being `"control"`.
2021-03-27 19:20:21 +01:00
2021-10-21 21:04:14 +02:00
- `$search(query,type=account|script,return_list=False)` ([code](evennia.utils.funcparser.funcparser_callable_search)) -
this will look up and try to match an object by key or alias. Use the `type` kwarg to
search for `account` or `script` instead. By default this will return nothing if there are more than one
2021-03-27 19:20:21 +01:00
match; if `return_list` is `True` a list of 0, 1 or more matches will be returned instead.
- `$obj(query)`, `$dbref(query)` - legacy aliases for `$search`.
- `$objlist(query)` - legacy alias for `$search`, always returning a list.
### `evennia.utils.funcparser.ACTOR_STANCE_CALLABLES`
2021-10-21 21:04:14 +02:00
These are used to implement actor-stance emoting. They are used by the
[DefaultObject.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method
by default. You can read a lot more about this on the page
[Change messages per receiver](../Concepts/Change-Messages-Per-Receiver.md).
2021-03-27 19:20:21 +01:00
On the parser side, all these inline functions require extra kwargs be passed into the parser
(done by `msg_contents` by default):
2021-03-27 19:20:21 +01:00
```python
parser.parse(string, caller=<obj>, receiver=<obj>, mapping={'key': <obj>, ...})
```
Here the `caller` is the one sending the message and `receiver` the one to see it. The `mapping` contains
references to other objects accessible via these callables.
2021-10-21 21:04:14 +02:00
- `$you([key])` ([code](evennia.utils.funcparser.funcparser_callable_you)) -
if no `key` is given, this represents the `caller`, otherwise an object from `mapping`
will be used. As this message is sent to different recipients, the `receiver` will change and this will
be replaced either with the string `you` (if you and the receiver is the same entity) or with the
2021-03-27 19:20:21 +01:00
result of `you_obj.get_display_name(looker=receiver)`. This allows for a single string to echo differently
depending on who sees it, and also to reference other people in the same way.
- `$You([key])` - same as `$you` but always capitalized.
2022-06-12 00:40:36 +02:00
- `$conj(verb)` ([code](evennia.utils.funcparser.funcparser_callable_conjugate)) - conjugates a verb
between 2nd person presens to 3rd person presence depending on who
sees the string. For example `"$You() $conj(smiles)".` will show as "You smile." and "Tom smiles." depending
2021-10-21 21:04:14 +02:00
on who sees it. This makes use of the tools in [evennia.utils.verb_conjugation](evennia.utils.verb_conjugation)
2021-03-27 19:20:21 +01:00
to do this, and only works for English verbs.
2022-06-12 00:40:36 +02:00
- `$pron(pronoun [,options])` ([code](evennia.utils.funcparser.funcparser_callable_pronoun)) - Dynamically
map pronouns (like his, herself, you, its etc) between 1st/2nd person to 3rd person.
2021-03-27 19:20:21 +01:00
### Example
2021-03-17 20:52:51 +01:00
2021-03-27 19:20:21 +01:00
Here's an example of including the default callables together with two custom ones.
2021-03-17 20:52:51 +01:00
```python
from evennia.utils import funcparser
from evennia.utils import gametime
2021-03-27 19:20:21 +01:00
def _dashline(*args, **kwargs):
2021-03-17 20:52:51 +01:00
if args:
2021-03-27 19:20:21 +01:00
return f"\n-------- {args[0]} --------"
2021-03-17 20:52:51 +01:00
return ''
def _uptime(*args, **kwargs):
return gametime.uptime()
callables = {
2021-03-27 19:20:21 +01:00
"dashline": _dashline,
"uptime": _uptime,
**funcparser.FUNCPARSER_CALLABLES,
**funcparser.ACTOR_STANCE_CALLABLES,
**funcparser.SEARCHING_CALLABLES
2021-03-17 20:52:51 +01:00
}
parser = funcparser.FuncParser(callables)
2021-03-27 19:20:21 +01:00
string = "This is the current uptime:$dashline($toint($uptime()) seconds)"
2021-03-17 20:52:51 +01:00
result = parser.parse(string)
```
2021-03-27 19:20:21 +01:00
Above we define two callables `_dashline` and `_uptime` and map them to names `"dashline"` and `"uptime"`,
2021-10-21 21:04:14 +02:00
which is what we then can call as `$header` and `$uptime` in the string. We also have access to
2021-03-27 19:20:21 +01:00
all the defaults (like `$toint()`).
2021-03-17 20:52:51 +01:00
2021-10-21 21:04:14 +02:00
The parsed result of the above would be something like this:
2021-03-17 20:52:51 +01:00
This is the current uptime:
2021-10-21 21:04:14 +02:00
------- 343 seconds -------