evennia/docs/6.x/Components/FuncParser.html
2026-02-15 19:06:04 +01:00

544 lines
No EOL
65 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" data-content_root="../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>FuncParser inline text parsing &#8212; Evennia latest documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=d75fae25" />
<link rel="stylesheet" type="text/css" href="../_static/nature.css?v=279e0f84" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css?v=e4a91a55" />
<script src="../_static/documentation_options.js?v=c6e86fd7"></script>
<script src="../_static/doctools.js?v=9bcbadda"></script>
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
<link rel="icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="MonitorHandler" href="MonitorHandler.html" />
<link rel="prev" title="EvTable" href="EvTable.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="EvTable.html" title="EvTable"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">FuncParser inline text parsing</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="funcparser-inline-text-parsing">
<h1>FuncParser inline text parsing<a class="headerlink" href="#funcparser-inline-text-parsing" title="Link to this heading"></a></h1>
<p>The <a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.FuncParser" title="evennia.utils.funcparser.FuncParser"><span class="xref myst py py-class">FuncParser</span></a> extracts and executes inline functions embedded in a string on the form <code class="docutils literal notranslate"><span class="pre">$funcname(args,</span> <span class="pre">kwargs)</span></code>, executes the matching inline function and replaces the call with the return from the call.</p>
<p>To test it, lets tell Evennia to apply the Funcparser on every outgoing message. This is disabled by default (not everyone needs this functionality). To activate, add to your settings file:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = True
</pre></div>
</div>
<p>After a reload, you can try this in-game</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>&gt;<span class="w"> </span>say<span class="w"> </span>I<span class="w"> </span>got<span class="w"> </span><span class="nv">$randint</span><span class="o">(</span><span class="m">1</span>,5<span class="o">)</span><span class="w"> </span>gold!
You<span class="w"> </span>say<span class="w"> </span><span class="s2">&quot;I got 3 gold!&quot;</span>
</pre></div>
</div>
<p>To escape the inlinefunc (e.g. to explain to someone how it works, use <code class="docutils literal notranslate"><span class="pre">$$</span></code>)</p>
<p>While <code class="docutils literal notranslate"><span class="pre">randint</span></code> may look and work just like <code class="docutils literal notranslate"><span class="pre">random.randint</span></code> from the standard Python library, it is <em>not</em>. Instead its an <code class="docutils literal notranslate"><span class="pre">inlinefunc</span></code> named <code class="docutils literal notranslate"><span class="pre">randint</span></code> made available to Evennia (which in turn uses the standard library function). For security reasons, only functions explicitly assigned to be used as inlinefuncs are viable.</p>
<p>You can apply the <code class="docutils literal notranslate"><span class="pre">FuncParser</span></code> manually. The parser is initialized with the inlinefunc(s) its supposed to recognize in that string. Below is an example of a parser only understanding a single <code class="docutils literal notranslate"><span class="pre">$pow</span></code> inlinefunc:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils.funcparser</span><span class="w"> </span><span class="kn">import</span> <span class="n">FuncParser</span>
<span class="k">def</span><span class="w"> </span><span class="nf">_power_callable</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;This will be callable as $pow(number, power=&lt;num&gt;) in string&quot;&quot;&quot;</span>
<span class="nb">pow</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;power&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="nb">pow</span>
<span class="c1"># create a parser and tell it that &#39;$pow&#39; means using _power_callable</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">FuncParser</span><span class="p">({</span><span class="s2">&quot;pow&quot;</span><span class="p">:</span> <span class="n">_power_callable</span><span class="p">})</span>
</pre></div>
</div>
<p>Next, just pass a string into the parser, containing <code class="docutils literal notranslate"><span class="pre">$func(...)</span></code> markers:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s2">&quot;We have that 4 x 4 x 4 is $pow(4, power=3).&quot;</span><span class="p">)</span>
<span class="s2">&quot;We have that 4 x 4 x 4 is 64.&quot;</span>
</pre></div>
</div>
<p>Normally the return is always converted to a string but you can also get the actual data type from the call:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;$pow(4)&quot;</span><span class="p">)</span>
<span class="mi">16</span>
</pre></div>
</div>
<p>You dont have to define all your inline functions from scratch. In <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser</span></code> youll find ready-made dicts of inline-funcs you can import and plug into your parsers. See <a class="reference internal" href="#default-funcparser-callables">default funcparser callables</a> below for the defails.</p>
<section id="working-with-funcparser">
<h2>Working with FuncParser<a class="headerlink" href="#working-with-funcparser" title="Link to this heading"></a></h2>
<p>The FuncParser can be applied to any string. Out of the box its applied in a few situations:</p>
<ul class="simple">
<li><p><em>Outgoing messages</em>. All messages sent from the server is processed through FuncParser and every callable is provided the <a class="reference internal" href="Sessions.html"><span class="std std-doc">Session</span></a> of the object receiving the message. This potentially allows a message to be modified on the fly to look different for different recipients.</p></li>
<li><p><em>Prototype values</em>. A <a class="reference internal" href="Prototypes.html"><span class="std std-doc">Prototype</span></a> dicts values are run through the parser such that every 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.</p></li>
<li><p><em>Actor-stance in messages to others</em>. In the <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">Object.msg_contents</span></a> method, the outgoing string is parsed for special <code class="docutils literal notranslate"><span class="pre">$You()</span></code> and <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> callables to decide if a given recipient
should see “You” or the characters name.</p></li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>The inline-function parser is not intended as a softcode programming language. It does not 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 Evennia expects you to do in a proper text editor, outside of the game, not from inside it.</p>
</div>
<p>You can apply inline function parsing to any string. The
<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.FuncParser" title="evennia.utils.funcparser.FuncParser"><span class="xref myst py py-class">FuncParser</span></a> is imported as <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">funcparser</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">FuncParser</span><span class="p">(</span><span class="n">callables</span><span class="p">,</span> <span class="o">**</span><span class="n">default_kwargs</span><span class="p">)</span>
<span class="n">parsed_string</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">input_string</span><span class="p">,</span> <span class="n">raise_errors</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">escape</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">strip</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">return_str</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">**</span><span class="n">reserved_kwargs</span><span class="p">)</span>
<span class="c1"># callables can also be passed as paths to modules</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">FuncParser</span><span class="p">([</span><span class="s2">&quot;game.myfuncparser_callables&quot;</span><span class="p">,</span> <span class="s2">&quot;game.more_funcparser_callables&quot;</span><span class="p">])</span>
</pre></div>
</div>
<p>Here, <code class="docutils literal notranslate"><span class="pre">callables</span></code> points to a collection of normal Python functions (see next section) for you to make
available to the parser as you parse strings with it. It can either be</p>
<ul class="simple">
<li><p>A <code class="docutils literal notranslate"><span class="pre">dict</span></code> of <code class="docutils literal notranslate"><span class="pre">{&quot;functionname&quot;:</span> <span class="pre">callable,</span> <span class="pre">...}</span></code>. This allows you to 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.</p></li>
<li><p>A <code class="docutils literal notranslate"><span class="pre">module</span></code> or (more commonly) a <code class="docutils literal notranslate"><span class="pre">python-path</span></code> to a module. This module can define a dict
<code class="docutils literal notranslate"><span class="pre">FUNCPARSER_CALLABLES</span> <span class="pre">=</span> <span class="pre">{&quot;funcname&quot;:</span> <span class="pre">callable,</span> <span class="pre">...}</span></code> - this will be imported and used like the <code class="docutils literal notranslate"><span class="pre">dict</span></code> above.
If no such variable is defined, <em>every</em> top-level function in the module (whose name doesnt start with
an underscore <code class="docutils literal notranslate"><span class="pre">_</span></code>) will be considered a suitable callable. The name of the function will be the <code class="docutils literal notranslate"><span class="pre">$funcname</span></code>
by which it can be called.</p></li>
<li><p>A <code class="docutils literal notranslate"><span class="pre">list</span></code> of modules/paths. This allows you to pull in modules from many sources for your parsing.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">**default</span></code> kwargs are optional kwargs that will be passed to <em>all</em>
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.</p></li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">FuncParser.parse</span></code> takes further arguments, and can vary for every string parsed.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> - 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 <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> is set,
then parsing will stop and whatever exception happened will be raised. Itd be up to you to handle
this properly.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">escape</span></code> - Returns a string where every <code class="docutils literal notranslate"><span class="pre">$func(...)</span></code> has been escaped as <code class="docutils literal notranslate"><span class="pre">\$func()</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">strip</span></code> - Remove all <code class="docutils literal notranslate"><span class="pre">$func(...)</span></code> calls from string (as if each returned <code class="docutils literal notranslate"><span class="pre">''</span></code>).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">return_str</span></code> - When <code class="docutils literal notranslate"><span class="pre">True</span></code> (default), <code class="docutils literal notranslate"><span class="pre">parser</span></code> always returns a string. If <code class="docutils literal notranslate"><span class="pre">False</span></code>, it may return
the return value of a single function call in the string. This is the same as using the <code class="docutils literal notranslate"><span class="pre">.parse_to_any</span></code>
method.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">**reserved_keywords</span></code> are <em>always</em> passed to every callable in the string.
They override any <code class="docutils literal notranslate"><span class="pre">**defaults</span></code> 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.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">funcparser</span></code> and <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code>
are always added as reserved keywords - the first is a
back-reference to the <code class="docutils literal notranslate"><span class="pre">FuncParser</span></code> instance and the second
is the <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> boolean given to <code class="docutils literal notranslate"><span class="pre">FuncParser.parse</span></code>.</p></li>
</ul>
<p>Heres an example of using the default/reserved keywords:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">_test</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># do stuff</span>
<span class="k">return</span> <span class="n">something</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">funcparser</span><span class="o">.</span><span class="n">FuncParser</span><span class="p">({</span><span class="s2">&quot;test&quot;</span><span class="p">:</span> <span class="n">_test</span><span class="p">},</span> <span class="n">mydefault</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s2">&quot;$test(foo, bar=4)&quot;</span><span class="p">,</span> <span class="n">myreserved</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
</pre></div>
</div>
<p>Here the callable will be called as</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">_test</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="n">bar</span><span class="o">=</span><span class="s1">&#39;4&#39;</span><span class="p">,</span> <span class="n">mydefault</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">myreserved</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span>
<span class="n">funcparser</span><span class="o">=&lt;</span><span class="n">FuncParser</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">raise_errors</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">mydefault=2</span></code> kwarg could be overwritten if we made the call as <code class="docutils literal notranslate"><span class="pre">$test(mydefault=...)</span></code> but <code class="docutils literal notranslate"><span class="pre">myreserved=[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> will <em>always</em> be sent as-is and will override a call <code class="docutils literal notranslate"><span class="pre">$test(myreserved=...)</span></code>.
The <code class="docutils literal notranslate"><span class="pre">funcparser</span></code>/<code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> kwargs are also always included as reserved kwargs.</p>
</section>
<section id="defining-custom-callables">
<h2>Defining custom callables<a class="headerlink" href="#defining-custom-callables" title="Link to this heading"></a></h2>
<p>All callables made available to the parser must have the following signature:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">funcname</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># ...</span>
<span class="k">return</span> <span class="n">something</span>
</pre></div>
</div>
<blockquote>
<div><p>The <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> must always be included. If you are unsure how <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> work in Python, <a class="reference external" href="https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3">read about them here</a>.</p>
</div></blockquote>
<p>The input from the innermost <code class="docutils literal notranslate"><span class="pre">$funcname(...)</span></code> call in your callable will always be a <code class="docutils literal notranslate"><span class="pre">str</span></code>. Heres
an example of an <code class="docutils literal notranslate"><span class="pre">$toint</span></code> function; it converts numbers to integers.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&quot;There&#39;s a $toint(22.0)% chance of survival.&quot;
</pre></div>
</div>
<p>What will enter the <code class="docutils literal notranslate"><span class="pre">$toint</span></code> callable (as <code class="docutils literal notranslate"><span class="pre">args[0]</span></code>) is the <em>string</em> <code class="docutils literal notranslate"><span class="pre">&quot;22.0&quot;</span></code>. The function is responsible 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).</p>
<p>If you want to mark an error, raise <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ParsingError</span></code>. This stops the entire parsing of the string and may or may not raise the exception depending on what you set <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> to when you created the parser.</p>
<p>However, if you <em>nest</em> functions, the return of the innermost function may be something other than
a string. Lets introduce the <code class="docutils literal notranslate"><span class="pre">$eval</span></code> function, which evaluates simple expressions using
Pythons <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> and/or <code class="docutils literal notranslate"><span class="pre">simple_eval</span></code>. It returns whatever data type it
evaluates to.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&quot;There&#39;s a $toint($eval(10 * 2.2))% chance of survival.&quot;
</pre></div>
</div>
<p>Since the <code class="docutils literal notranslate"><span class="pre">$eval</span></code> is the innermost call, it will get a string as input - the string <code class="docutils literal notranslate"><span class="pre">&quot;10</span> <span class="pre">*</span> <span class="pre">2.2&quot;</span></code>.
It evaluates this and returns the <code class="docutils literal notranslate"><span class="pre">float</span></code> <code class="docutils literal notranslate"><span class="pre">22.0</span></code>. This time the outermost <code class="docutils literal notranslate"><span class="pre">$toint</span></code> will be called with
this <code class="docutils literal notranslate"><span class="pre">float</span></code> instead of with a string.</p>
<blockquote>
<div><p>Its 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.</p>
</div></blockquote>
<p>In these examples, the result will be embedded in the larger string, so the result of the entire parsing will be a string:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">above_string</span><span class="p">)</span>
<span class="s2">&quot;There&#39;s a 22</span><span class="si">% c</span><span class="s2">hance of survival.&quot;</span>
</pre></div>
</div>
<p>However, if you use the <code class="docutils literal notranslate"><span class="pre">parse_to_any</span></code> (or <code class="docutils literal notranslate"><span class="pre">parse(...,</span> <span class="pre">return_str=False)</span></code>) and <em>dont add any extra string around the outermost function call</em>, youll get the return type of the outermost callable back:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;$toint($eval(10 * 2.2)&quot;</span><span class="p">)</span>
<span class="mi">22</span>
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;the number $toint($eval(10 * 2.2).&quot;</span><span class="p">)</span>
<span class="s2">&quot;the number 22&quot;</span>
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;$toint($eval(10 * 2.2)%&quot;</span><span class="p">)</span>
<span class="s2">&quot;22%&quot;</span>
</pre></div>
</div>
<section id="escaping-special-character">
<h3>Escaping special character<a class="headerlink" href="#escaping-special-character" title="Link to this heading"></a></h3>
<p>When entering funcparser callables in strings, it looks like a regular
function call inside a string:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;This is a $myfunc(arg1, arg2, kwarg=foo).&quot;</span>
</pre></div>
</div>
<p>Commas (<code class="docutils literal notranslate"><span class="pre">,</span></code>) and equal-signs (<code class="docutils literal notranslate"><span class="pre">=</span></code>) are considered to separate the arguments and
kwargs. In the same way, the right parenthesis (<code class="docutils literal notranslate"><span class="pre">)</span></code>) closes the argument list.
Sometimes you want to include commas in the argument without it breaking the
argument list.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;The $format(forest&#39;s smallest meadow, with dandelions) is to the west.&quot;</span>
</pre></div>
</div>
<p>You can escape in various ways.</p>
<ul class="simple">
<li><p>Prepending special characters like <code class="docutils literal notranslate"><span class="pre">,</span></code> and <code class="docutils literal notranslate"><span class="pre">=</span></code> with the escape character <code class="docutils literal notranslate"><span class="pre">\</span></code></p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;The $format(forest&#39;s smallest meadow\, with dandelions) is to the west.&quot;</span>
</pre></div>
</div>
<ul class="simple">
<li><p>Wrapping your strings in double quotes. Unlike in raw Python, you
cant escape with single quotes <code class="docutils literal notranslate"><span class="pre">'</span></code> since these could also be apostrophes (like
<code class="docutils literal notranslate"><span class="pre">forest's</span></code> above). The result will be a verbatim string that contains
everything but the outermost double quotes.</p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;The $format(&quot;forest&#39;</span><span class="n">s</span> <span class="n">smallest</span> <span class="n">meadow</span><span class="p">,</span> <span class="k">with</span> <span class="n">dandelions</span><span class="s2">&quot;) is to the west.&#39;</span>
</pre></div>
</div>
<ul class="simple">
<li><p>If you want verbatim double-quotes to appear in your string, you can escape
them with <code class="docutils literal notranslate"><span class="pre">\&quot;</span></code> in turn.</p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;The $format(&quot;forest&#39;</span><span class="n">s</span> <span class="n">smallest</span> <span class="n">meadow</span><span class="p">,</span> <span class="k">with</span> \<span class="s2">&quot;dandelions</span><span class="se">\&quot;</span><span class="s2">&#39;) is to the west.&#39;</span>
</pre></div>
</div>
</section>
<section id="safe-convertion-of-inputs">
<h3>Safe convertion of inputs<a class="headerlink" href="#safe-convertion-of-inputs" title="Link to this heading"></a></h3>
<p>Since you dont 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 on 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.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">evennia.utils.utils</span></code> is a helper called <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.safe_convert_to_types" title="evennia.utils.utils.safe_convert_to_types"><span class="xref myst py py-func">safe_convert_to_types</span></a>. This function automates the conversion of simple data types in a safe way:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">safe_convert_to_types</span>
<span class="k">def</span><span class="w"> </span><span class="nf">_process_callable</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> $process(expression, local, extra1=34, extra2=foo)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">safe_convert_to_type</span><span class="p">(</span>
<span class="p">((</span><span class="s1">&#39;py&#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">),</span> <span class="p">{</span><span class="s1">&#39;extra1&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="s1">&#39;extra2&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}),</span>
<span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="c1"># args/kwargs should be correct types now</span>
</pre></div>
</div>
<p>In other words, in the callable <code class="docutils literal notranslate"><span class="pre">$process(expression,</span> <span class="pre">local,</span> <span class="pre">extra1=..,</span> <span class="pre">extra2=...)</span></code>, the first argument will be handled by the py converter (described below), the second will passed through regular Python <code class="docutils literal notranslate"><span class="pre">str</span></code>, kwargs will be handled by <code class="docutils literal notranslate"><span class="pre">int</span></code> and <code class="docutils literal notranslate"><span class="pre">str</span></code> respectively. You can supply your own converter function as long as it takes one argument and returns the converted result.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">safe_convert_to_type</span><span class="p">(</span>
<span class="p">(</span><span class="n">tuple_of_arg_converters</span><span class="p">,</span> <span class="n">dict_of_kwarg_converters</span><span class="p">),</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</div>
<p>The special converter <code class="docutils literal notranslate"><span class="pre">&quot;py&quot;</span></code> will try to convert a string argument to a Python structure with the help of the following tools (which you may also find useful to experiment with on your own):</p>
<ul class="simple">
<li><p><a class="reference external" href="https://docs.python.org/3.8/library/ast.html#ast.literal_eval">ast.literal_eval</a> is an in-built Python function. It <em>only</em> supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and <code class="docutils literal notranslate"><span class="pre">None</span></code>. Thats 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.</p></li>
<li><p><a class="reference external" href="https://pypi.org/project/simpleeval/">simpleeval</a> 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 <code class="docutils literal notranslate"><span class="pre">+-/*</span></code> as well as do simple comparisons like <code class="docutils literal notranslate"><span class="pre">4</span> <span class="pre">&gt;</span> <span class="pre">3</span></code> and more. It does <em>not</em> accept more complex containers like lists/dicts etc, so this and <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> are complementary to each other.</p></li>
</ul>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>It may be tempting to run use Pythons in-built <code class="docutils literal notranslate"><span class="pre">eval()</span></code> or <code class="docutils literal notranslate"><span class="pre">exec()</span></code> 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 youd have access to Python already). Letting untrusted users pass strings to <code class="docutils literal notranslate"><span class="pre">eval</span></code>/<code class="docutils literal notranslate"><span class="pre">exec</span></code> 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 dont do it and sleep better at night.</p>
</div>
</section>
</section>
<section id="default-funcparser-callables">
<h2>Default funcparser callables<a class="headerlink" href="#default-funcparser-callables" title="Link to this heading"></a></h2>
<p>These are some example callables you can import and add your parser. They are divided into global-level dicts in <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser</span></code>. Just import the dict(s) and merge/add one or more to them when you create your <code class="docutils literal notranslate"><span class="pre">FuncParser</span></code> instance to have those callables be available.</p>
<section id="evennia-utils-funcparser-funcparser-callables">
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.FUNCPARSER_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-funcparser-callables" title="Link to this heading"></a></h3>
<p>These are the base callables.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">$eval(expression)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_eval" title="evennia.utils.funcparser.funcparser_callable_eval"><span class="xref myst py py-func">code</span></a>) - this uses <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> and <code class="docutils literal notranslate"><span class="pre">simple_eval</span></code> (see previous section) attemt to convert a string expression to a python object. This handles e.g. lists of literals <code class="docutils literal notranslate"><span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> and simple expressions like <code class="docutils literal notranslate"><span class="pre">&quot;1</span> <span class="pre">+</span> <span class="pre">2&quot;</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$toint(number)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_toint" title="evennia.utils.funcparser.funcparser_callable_toint"><span class="xref myst py py-func">code</span></a>) - always converts an output to an integer, if possible.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$add/sub/mult/div(obj1,</span> <span class="pre">obj2)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_add" title="evennia.utils.funcparser.funcparser_callable_add"><span class="xref myst py py-func">code</span></a>) -
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with <code class="docutils literal notranslate"><span class="pre">$eval</span></code>, this could for example be used also to add two lists together, which is not possible with <code class="docutils literal notranslate"><span class="pre">eval</span></code>; for example <code class="docutils literal notranslate"><span class="pre">$add($eval([1,2,3]),</span> <span class="pre">$eval([4,5,6]))</span> <span class="pre">-&gt;</span> <span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3,</span> <span class="pre">4,</span> <span class="pre">5,</span> <span class="pre">6]</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$round(float,</span> <span class="pre">significant)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_round" title="evennia.utils.funcparser.funcparser_callable_round"><span class="xref myst py py-func">code</span></a>) - rounds an input float into the number of provided significant digits. For example <code class="docutils literal notranslate"><span class="pre">$round(3.54343,</span> <span class="pre">3)</span> <span class="pre">-&gt;</span> <span class="pre">3.543</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$random([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_random" title="evennia.utils.funcparser.funcparser_callable_random"><span class="xref myst py py-func">code</span></a>) - this works like the Python <code class="docutils literal notranslate"><span class="pre">random()</span></code> function, but will randomize to an integer value if both start/end are
integers. Without argument, will return a float between 0 and 1.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$randint([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_randint" title="evennia.utils.funcparser.funcparser_callable_randint"><span class="xref myst py py-func">code</span></a>) - works like the <code class="docutils literal notranslate"><span class="pre">randint()</span></code> python function and always returns an integer.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$choice(list)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_choice" title="evennia.utils.funcparser.funcparser_callable_choice"><span class="xref myst py py-func">code</span></a>) - the input will automatically be parsed the same way as <code class="docutils literal notranslate"><span class="pre">$eval</span></code> and is expected to be an iterable. A random element of this list will be returned.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$pad(text[,</span> <span class="pre">width,</span> <span class="pre">align,</span> <span class="pre">fillchar])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_pad" title="evennia.utils.funcparser.funcparser_callable_pad"><span class="xref myst py py-func">code</span></a>) - this will pad content. <code class="docutils literal notranslate"><span class="pre">$pad(&quot;Hello&quot;,</span> <span class="pre">30,</span> <span class="pre">c,</span> <span class="pre">-)</span></code> will lead to a text centered in a 30-wide block surrounded by <code class="docutils literal notranslate"><span class="pre">-</span></code> characters.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$crop(text,</span> <span class="pre">width=78,</span> <span class="pre">suffix='[...]')</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_crop" title="evennia.utils.funcparser.funcparser_callable_crop"><span class="xref myst py py-func">code</span></a>) - this will crop a text longer than the width, by default ending it with a <code class="docutils literal notranslate"><span class="pre">[...]</span></code>-suffix that also fits within the width. If no width is given, the client width or <code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_CLIENT_WIDTH</span></code> will be used.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$space(num)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_space" title="evennia.utils.funcparser.funcparser_callable_space"><span class="xref myst py py-func">code</span></a>) - this will insert <code class="docutils literal notranslate"><span class="pre">num</span></code> spaces.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$just(string,</span> <span class="pre">width=40,</span> <span class="pre">align=c,</span> <span class="pre">indent=2)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_justify" title="evennia.utils.funcparser.funcparser_callable_justify"><span class="xref myst py py-func">code</span></a>) - justifies the text to a given width, aligning it left/right/center or f for full (spread text across width).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$ljust</span></code> - shortcut to justify-left. Takes all other kwarg of <code class="docutils literal notranslate"><span class="pre">$just</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$rjust</span></code> - shortcut to right justify.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$cjust</span></code> - shortcut to center justify.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$clr(startcolor,</span> <span class="pre">text[,</span> <span class="pre">endcolor])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_clr" title="evennia.utils.funcparser.funcparser_callable_clr"><span class="xref myst py py-func">code</span></a>) - color text. The color is given with one or two characters without the preceeding <code class="docutils literal notranslate"><span class="pre">|</span></code>. If no endcolor is given, the string will go back to neutral, so <code class="docutils literal notranslate"><span class="pre">$clr(r,</span> <span class="pre">Hello)</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">|rHello|n</span></code>.</p></li>
</ul>
</section>
<section id="evennia-utils-funcparser-searching-callables">
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.SEARCHING_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-searching-callables" title="Link to this heading"></a></h3>
<p>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:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">caller</span><span class="o">=&lt;</span><span class="nb">object</span> <span class="ow">or</span> <span class="n">account</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">access</span><span class="o">=</span><span class="s2">&quot;control&quot;</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">caller</span></code> is required, its the the object to do the access-check for. The <code class="docutils literal notranslate"><span class="pre">access</span></code> kwarg is the
<a class="reference internal" href="Locks.html"><span class="std std-doc">lock type</span></a> to check, default being <code class="docutils literal notranslate"><span class="pre">&quot;control&quot;</span></code>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">$search(query,type=account|script,return_list=False)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_search" title="evennia.utils.funcparser.funcparser_callable_search"><span class="xref myst py py-func">code</span></a>) - this will look up and try to match an object by key or alias. Use the <code class="docutils literal notranslate"><span class="pre">type</span></code> kwarg to search for <code class="docutils literal notranslate"><span class="pre">account</span></code> or <code class="docutils literal notranslate"><span class="pre">script</span></code> instead. By default this will return nothing if there are more than one match; if <code class="docutils literal notranslate"><span class="pre">return_list</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code> a list of 0, 1 or more matches will be returned instead.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$obj(query)</span></code>, <code class="docutils literal notranslate"><span class="pre">$dbref(query)</span></code> - legacy aliases for <code class="docutils literal notranslate"><span class="pre">$search</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$objlist(query)</span></code> - legacy alias for <code class="docutils literal notranslate"><span class="pre">$search</span></code>, always returning a list.</p></li>
</ul>
</section>
<section id="evennia-utils-funcparser-actor-stance-callables">
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ACTOR_STANCE_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-actor-stance-callables" title="Link to this heading"></a></h3>
<p>These are used to implement actor-stance emoting. They are used by the <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">DefaultObject.msg_contents</span></a> method by default. You can read a lot more about this on the page
<a class="reference internal" href="../Concepts/Change-Message-Per-Receiver.html"><span class="std std-doc">Change messages per receiver</span></a>.</p>
<p>On the parser side, all these inline functions require extra kwargs be passed into the parser (done by <code class="docutils literal notranslate"><span class="pre">msg_contents</span></code> by default):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">caller</span><span class="o">=&lt;</span><span class="n">obj</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">receiver</span><span class="o">=&lt;</span><span class="n">obj</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">mapping</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">obj</span><span class="o">&gt;</span><span class="p">,</span> <span class="o">...</span><span class="p">})</span>
</pre></div>
</div>
<p>Here the <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the one sending the message and <code class="docutils literal notranslate"><span class="pre">receiver</span></code> the one to see it. The <code class="docutils literal notranslate"><span class="pre">mapping</span></code> contains references to other objects accessible via these callables.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">$you([key])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_you" title="evennia.utils.funcparser.funcparser_callable_you"><span class="xref myst py py-func">code</span></a>) -
if no <code class="docutils literal notranslate"><span class="pre">key</span></code> is given, this represents the <code class="docutils literal notranslate"><span class="pre">caller</span></code>, otherwise an object from <code class="docutils literal notranslate"><span class="pre">mapping</span></code>
will be used. As this message is sent to different recipients, the <code class="docutils literal notranslate"><span class="pre">receiver</span></code> will change and this will
be replaced either with the string <code class="docutils literal notranslate"><span class="pre">you</span></code> (if you and the receiver is the same entity) or with the
result of <code class="docutils literal notranslate"><span class="pre">you_obj.get_display_name(looker=receiver)</span></code>. This allows for a single string to echo differently
depending on who sees it, and also to reference other people in the same way.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$You([key])</span></code> - same as <code class="docutils literal notranslate"><span class="pre">$you</span></code> but always capitalized.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$conj(verb</span> <span class="pre">[,key])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_conjugate" title="evennia.utils.funcparser.funcparser_callable_conjugate"><span class="xref myst py py-func">code</span></a>) - conjugates a verb
between 2nd person presence to 3rd person presence depending on who
sees the string. For example <code class="docutils literal notranslate"><span class="pre">&quot;$You()</span> <span class="pre">$conj(smiles)&quot;.</span></code> will show as “You smile.” and “Tom smiles.” depending
on who sees it. This makes use of the tools in <a class="reference internal" href="../api/evennia.utils.verb_conjugation.html#evennia-utils-verb-conjugation"><span class="std std-ref">evennia.utils.verb_conjugation</span></a>
to do this, and only works for English verbs.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$pron(pronoun</span> <span class="pre">[,options]</span> <span class="pre">[,key])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_pronoun" title="evennia.utils.funcparser.funcparser_callable_pronoun"><span class="xref myst py py-func">code</span></a>) - Dynamically
map pronouns (like his, herself, you, its etc) between 1st/2nd person to 3rd person.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$pconj(verb,</span> <span class="pre">[,key])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_conjugate_for_pronouns" title="evennia.utils.funcparser.funcparser_callable_conjugate_for_pronouns"><span class="xref myst py py-func">code</span></a>) - conjugates
a verb between 2nd and 3rd person, like <code class="docutils literal notranslate"><span class="pre">$conj</span></code>, but for pronouns instead of nouns to account for plural
gendering. For example <code class="docutils literal notranslate"><span class="pre">&quot;$Pron(you)</span> <span class="pre">$pconj(smiles)&quot;</span></code> will show to others as “He smiles” for a gender of “male”, or
“They smile” for a gender of “plural”.</p></li>
</ul>
</section>
<section id="evennia-prototypes-protfuncs">
<h3><code class="docutils literal notranslate"><span class="pre">evennia.prototypes.protfuncs</span></code><a class="headerlink" href="#evennia-prototypes-protfuncs" title="Link to this heading"></a></h3>
<p>This is used by the <a class="reference internal" href="Prototypes.html"><span class="std std-doc">Prototype system</span></a> and allows for adding references inside the prototype. The funcparsing will happen before the spawn.</p>
<p>Available inlinefuncs to prototypes:</p>
<ul class="simple">
<li><p>All <code class="docutils literal notranslate"><span class="pre">FUNCPARSER_CALLABLES</span></code> and <code class="docutils literal notranslate"><span class="pre">SEARCHING_CALLABLES</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$protkey(key)</span></code> - returns the value of another key within the same prototype. Note that the system will try to convert this to a real value (like turning the string “3” into the integer 3), for security reasons, not all embedded values can be converted this way. Note however that you can do nested calls with inlinefuncs, including adding your own converters.</p></li>
</ul>
</section>
<section id="example">
<h3>Example<a class="headerlink" href="#example" title="Link to this heading"></a></h3>
<p>Heres an example of including the default callables together with two custom ones.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">funcparser</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">gametime</span>
<span class="k">def</span><span class="w"> </span><span class="nf">_dashline</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">if</span> <span class="n">args</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">-------- </span><span class="si">{</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2"> --------&quot;</span>
<span class="k">return</span> <span class="s1">&#39;&#39;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">_uptime</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="n">gametime</span><span class="o">.</span><span class="n">uptime</span><span class="p">()</span>
<span class="n">callables</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;dashline&quot;</span><span class="p">:</span> <span class="n">_dashline</span><span class="p">,</span>
<span class="s2">&quot;uptime&quot;</span><span class="p">:</span> <span class="n">_uptime</span><span class="p">,</span>
<span class="o">**</span><span class="n">funcparser</span><span class="o">.</span><span class="n">FUNCPARSER_CALLABLES</span><span class="p">,</span>
<span class="o">**</span><span class="n">funcparser</span><span class="o">.</span><span class="n">ACTOR_STANCE_CALLABLES</span><span class="p">,</span>
<span class="o">**</span><span class="n">funcparser</span><span class="o">.</span><span class="n">SEARCHING_CALLABLES</span>
<span class="p">}</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">funcparser</span><span class="o">.</span><span class="n">FuncParser</span><span class="p">(</span><span class="n">callables</span><span class="p">)</span>
<span class="n">string</span> <span class="o">=</span> <span class="s2">&quot;This is the current uptime:$dashline($toint($uptime()) seconds)&quot;</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
</pre></div>
</div>
<p>Above we define two callables <code class="docutils literal notranslate"><span class="pre">_dashline</span></code> and <code class="docutils literal notranslate"><span class="pre">_uptime</span></code> and map them to names <code class="docutils literal notranslate"><span class="pre">&quot;dashline&quot;</span></code> and <code class="docutils literal notranslate"><span class="pre">&quot;uptime&quot;</span></code>,
which is what we then can call as <code class="docutils literal notranslate"><span class="pre">$header</span></code> and <code class="docutils literal notranslate"><span class="pre">$uptime</span></code> in the string. We also have access to
all the defaults (like <code class="docutils literal notranslate"><span class="pre">$toint()</span></code>).</p>
<p>The parsed result of the above would be something like this:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>This is the current uptime:
------- 343 seconds -------
</pre></div>
</div>
</section>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo of Evennia"/>
</a></p>
<search id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">FuncParser inline text parsing</a><ul>
<li><a class="reference internal" href="#working-with-funcparser">Working with FuncParser</a></li>
<li><a class="reference internal" href="#defining-custom-callables">Defining custom callables</a><ul>
<li><a class="reference internal" href="#escaping-special-character">Escaping special character</a></li>
<li><a class="reference internal" href="#safe-convertion-of-inputs">Safe convertion of inputs</a></li>
</ul>
</li>
<li><a class="reference internal" href="#default-funcparser-callables">Default funcparser callables</a><ul>
<li><a class="reference internal" href="#evennia-utils-funcparser-funcparser-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.FUNCPARSER_CALLABLES</span></code></a></li>
<li><a class="reference internal" href="#evennia-utils-funcparser-searching-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.SEARCHING_CALLABLES</span></code></a></li>
<li><a class="reference internal" href="#evennia-utils-funcparser-actor-stance-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ACTOR_STANCE_CALLABLES</span></code></a></li>
<li><a class="reference internal" href="#evennia-prototypes-protfuncs"><code class="docutils literal notranslate"><span class="pre">evennia.prototypes.protfuncs</span></code></a></li>
<li><a class="reference internal" href="#example">Example</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div>
<h4>Previous topic</h4>
<p class="topless"><a href="EvTable.html"
title="previous chapter">EvTable</a></p>
</div>
<div>
<h4>Next topic</h4>
<p class="topless"><a href="MonitorHandler.html"
title="next chapter">MonitorHandler</a></p>
</div>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/FuncParser.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Doc Versions</h3>
<ul>
<li>
<a href="https://www.evennia.com/docs/latest/index.html">latest (main branch)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/5.x/index.html">v5.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/4.x/index.html">v4.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/3.x/index.html">v3.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/2.x/index.html">v2.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/1.x/index.html">v1.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/0.x/index.html">v0.9.5 branch (outdated)</a>
</li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
>next</a> |</li>
<li class="right" >
<a href="EvTable.html" title="EvTable"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">FuncParser inline text parsing</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2024, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
</div>
</body>
</html>