<h1>Parsing command arguments, theory and best practices<aclass="headerlink"href="#parsing-command-arguments-theory-and-best-practices"title="Permalink to this headline">¶</a></h1>
<p>This tutorial will elaborate on the many ways one can parse command arguments. The first step after
<aclass="reference internal"href="Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.html"><spanclass="doc std std-doc">adding a command</span></a> usually is to parse its arguments. There are lots of
ways to do it, but some are indeed better than others and this tutorial will try to present them.</p>
<p>If you’re a Python beginner, this tutorial might help you a lot. If you’re already familiar with
Python syntax, this tutorial might still contain useful information. There are still a lot of
things I find in the standard library that come as a surprise, though they were there all along.
This might be true for others.</p>
<p>In this tutorial we will:</p>
<ulclass="simple">
<li><p>Parse arguments with numbers.</p></li>
<li><p>Parse arguments with delimiters.</p></li>
<li><p>Take a look at optional arguments.</p></li>
<h2>What are command arguments?<aclass="headerlink"href="#what-are-command-arguments"title="Permalink to this headline">¶</a></h2>
<p>I’m going to talk about command arguments and parsing a lot in this tutorial. So let’s be sure we
talk about the same thing before going any further:</p>
<blockquote>
<div><p>A command is an Evennia object that handles specific user input.</p>
</div></blockquote>
<p>For instance, the default <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> is a command. After having created your Evennia game, and
connected to it, you should be able to type <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> to see what’s around. In this context, <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> is
a command.</p>
<blockquote>
<div><p>Command arguments are additional text passed after the command.</p>
</div></blockquote>
<p>Following the same example, you can type <codeclass="docutils literal notranslate"><spanclass="pre">look</span><spanclass="pre">self</span></code> to look at yourself. In this context, <codeclass="docutils literal notranslate"><spanclass="pre">self</span></code>
is the text specified after <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code>. <codeclass="docutils literal notranslate"><spanclass="pre">"</span><spanclass="pre">self"</span></code> is the argument to the <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> command.</p>
<p>Part of our task as a game developer is to connect user inputs (mostly commands) with actions in the
game. And most of the time, entering commands is not enough, we have to rely on arguments for
specifying actions with more accuracy.</p>
<p>Take the <codeclass="docutils literal notranslate"><spanclass="pre">say</span></code> command. If you couldn’t specify what to say as a command argument (<codeclass="docutils literal notranslate"><spanclass="pre">say</span><spanclass="pre">hello!</span></code>),
you would have trouble communicating with others in the game. One would need to create a different
command for every kind of word or sentence, which is, of course, not practical.</p>
<p>We don’t usually use the command argument as is (which is just text, of type <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> in Python). We
need to extract useful information. We might want to ask the user for a number, or the name of
another character present in the same room. We’re going to see how to do all that now.</p>
</section>
<sectionid="working-with-strings">
<h2>Working with strings<aclass="headerlink"href="#working-with-strings"title="Permalink to this headline">¶</a></h2>
<p>In object terms, when you write a command in Evennia (when you write the Python class), the
arguments are stored in the <codeclass="docutils literal notranslate"><spanclass="pre">args</span></code> attribute. Which is to say, inside your <codeclass="docutils literal notranslate"><spanclass="pre">func</span></code> method, you can
access the command arguments in <codeclass="docutils literal notranslate"><spanclass="pre">self.args</span></code>.</p>
<sectionid="self-args">
<h3>self.args<aclass="headerlink"href="#self-args"title="Permalink to this headline">¶</a></h3>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You have entered: </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">args</span><spanclass="si">}</span><spanclass="s2">."</span><spanclass="p">)</span>
</pre></div>
</div>
<p>If you add this command and test it, you will receive exactly what you have entered without any
<div><p>The lines starting with <codeclass="docutils literal notranslate"><spanclass="pre">></span></code> indicate what you enter into your client. The other lines are what
you receive from the game server.</p>
</div></blockquote>
<p>Notice two things here:</p>
<olclass="simple">
<li><p>The left space between our command key (“test”, here) and our command argument is not removed.
That’s why there are two spaces in our output at line 2. Try entering something like “testok”.</p></li>
<li><p>Even if you don’t enter command arguments, the command will still be called with an empty string
in <codeclass="docutils literal notranslate"><spanclass="pre">self.args</span></code>.</p></li>
</ol>
<p>Perhaps a slight modification to our code would be appropriate to see what’s happening. We will
force Python to display the command arguments as a debug string using a little shortcut.</p>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You have entered: </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">args</span><spanclass="si">!r}</span><spanclass="s2">."</span><spanclass="p">)</span>
</pre></div>
</div>
<p>The only line we have changed is the last one, and we have added <codeclass="docutils literal notranslate"><spanclass="pre">!r</span></code> between our braces to tell
Python to print the debug version of the argument (the repr-ed version). Let’s see the result:</p>
<spanclass="n">You</span><spanclass="n">have</span><spanclass="n">entered</span><spanclass="p">:</span><spanclass="s2">" And something with '?"</span><spanclass="o">.</span>
</pre></div>
</div>
<p>This displays the string in a way you could see in the Python interpreter. It might be easier to
read… to debug, anyway.</p>
<p>I insist so much on that point because it’s crucial: the command argument is just a string (of type
<codeclass="docutils literal notranslate"><spanclass="pre">str</span></code>) and we will use this to parse it. What you will see is mostly not Evennia-specific, it’s
Python-specific and could be used in any other project where you have the same need.</p>
</section>
<sectionid="stripping">
<h3>Stripping<aclass="headerlink"href="#stripping"title="Permalink to this headline">¶</a></h3>
<p>As you’ve seen, our command arguments are stored with the space. And the space between the command
and the arguments is often of no importance.</p>
<blockquote>
<div><p>Why is it ever there?</p>
</div></blockquote>
<p>Evennia will try its best to find a matching command. If the user enters your command key with
arguments (but omits the space), Evennia will still be able to find and call the command. You might
have seen what happened if the user entered <codeclass="docutils literal notranslate"><spanclass="pre">testok</span></code>. In this case, <codeclass="docutils literal notranslate"><spanclass="pre">testok</span></code> could very well be a
command (Evennia checks for that) but seeing none, and because there’s a <codeclass="docutils literal notranslate"><spanclass="pre">test</span></code> command, Evennia
calls it with the arguments <codeclass="docutils literal notranslate"><spanclass="pre">"ok"</span></code>.</p>
<p>But most of the time, we don’t really care about this left space, so you will often see code to
remove it. There are different ways to do it in Python, but a command use case is the <codeclass="docutils literal notranslate"><spanclass="pre">strip</span></code>
method on <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> and its cousins, <codeclass="docutils literal notranslate"><spanclass="pre">lstrip</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">rstrip</span></code>.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">strip</span></code>: removes one or more characters (either spaces or other characters) from both ends of the
string.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">lstrip</span></code>: same thing but only removes from the left end (left strip) of the string.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">rstrip</span></code>: same thing but only removes from the right end (right strip) of the string.</p></li>
</ul>
<p>Some Python examples might help:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="gp">>>></span><spanclass="s1">' this is '</span><spanclass="o">.</span><spanclass="n">strip</span><spanclass="p">()</span><spanclass="c1"># remove spaces by default</span>
<spanclass="go">'this is'</span>
<spanclass="gp">>>></span><spanclass="s2">" What if I'm right? "</span><spanclass="o">.</span><spanclass="n">lstrip</span><spanclass="p">()</span><spanclass="c1"># strip spaces from the left</span>
<spanclass="go">"What if I'm right? "</span>
<spanclass="gp">>>></span><spanclass="s1">'Looks good to me...'</span><spanclass="o">.</span><spanclass="n">strip</span><spanclass="p">(</span><spanclass="s1">'.'</span><spanclass="p">)</span><spanclass="c1"># removes '.'</span>
<spanclass="go">'Looks good to me'</span>
<spanclass="gp">>>></span><spanclass="s1">'"Now, what is it?"'</span><spanclass="o">.</span><spanclass="n">strip</span><spanclass="p">(</span><spanclass="s1">'"?'</span><spanclass="p">)</span><spanclass="c1"># removes '"' and '?' from both ends</span>
<spanclass="go">'Now, what is it'</span>
</pre></div>
</div>
<p>Usually, since we don’t need the space separator, but still want our command to work if there’s no
separator, we call <codeclass="docutils literal notranslate"><spanclass="pre">lstrip</span></code> on the command arguments:</p>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You have entered: </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">args</span><spanclass="si">!r}</span><spanclass="s2">."</span><spanclass="p">)</span>
</pre></div>
</div>
<blockquote>
<div><p>We are now beginning to override the command’s <codeclass="docutils literal notranslate"><spanclass="pre">parse</span></code> method, which is typically useful just for
argument parsing. This method is executed before <codeclass="docutils literal notranslate"><spanclass="pre">func</span></code> and so <codeclass="docutils literal notranslate"><spanclass="pre">self.args</span></code> in <codeclass="docutils literal notranslate"><spanclass="pre">func()</span></code> will contain
<spanclass="n">You</span><spanclass="n">have</span><spanclass="n">entered</span><spanclass="p">:</span><spanclass="s2">"And something with '?"</span><spanclass="o">.</span>
<spanclass="n">You</span><spanclass="n">have</span><spanclass="n">entered</span><spanclass="p">:</span><spanclass="s1">'And something with lots of spaces'</span><spanclass="o">.</span>
</pre></div>
</div>
<p>Spaces at the end of the string are kept, but all spaces at the beginning are removed:</p>
<blockquote>
<div><p><codeclass="docutils literal notranslate"><spanclass="pre">strip</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">lstrip</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">rstrip</span></code> without arguments will strip spaces, line breaks and other common
separators. You can specify one or more characters as a parameter. If you specify more than one
character, all of them will be stripped from your original string.</p>
</div></blockquote>
</section>
<sectionid="convert-arguments-to-numbers">
<h3>Convert arguments to numbers<aclass="headerlink"href="#convert-arguments-to-numbers"title="Permalink to this headline">¶</a></h3>
<p>As pointed out, <codeclass="docutils literal notranslate"><spanclass="pre">self.args</span></code> is a string (of type <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code>). What if we want the user to enter a
number?</p>
<p>Let’s take a very simple example: creating a command, <codeclass="docutils literal notranslate"><spanclass="pre">roll</span></code>, that allows to roll a six-sided die.
The player has to guess the number, specifying the number as argument. To win, the player has to
match the number with the die. Let’s see an example:</p>
<divclass="highlight-default notranslate"><divclass="highlight"><pre><span></span>> roll 3
You roll a die. It lands on the number 4.
You played 3, you have lost.
> dice 1
You roll a die. It lands on the number 2.
You played 1, you have lost.
> dice 1
You roll a die. It lands on the number 1.
You played 1, you have won!
</pre></div>
</div>
<p>If that’s your first command, it’s a good opportunity to try to write it. A command with a simple
and finite role always is a good starting choice. Here’s how we could (first) write it… but it
<spanclass="n">figure</span><spanclass="o">=</span><spanclass="n">randint</span><spanclass="p">(</span><spanclass="mi">1</span><spanclass="p">,</span><spanclass="mi">6</span><spanclass="p">)</span><spanclass="c1"># return a pseudo-random number between 1 and 6, including both</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You roll a die. It lands on the number </span><spanclass="si">{</span><spanclass="n">figure</span><spanclass="si">}</span><spanclass="s2">."</span><spanclass="p">)</span>
<spanclass="k">if</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">args</span><spanclass="o">==</span><spanclass="n">figure</span><spanclass="p">:</span><spanclass="c1"># THAT WILL BREAK!</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">args</span><spanclass="si">}</span><spanclass="s2">, you have won!"</span><spanclass="p">)</span>
<spanclass="k">else</span><spanclass="p">:</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">args</span><spanclass="si">}</span><spanclass="s2">, you have lost."</span><spanclass="p">)</span>
</pre></div>
</div>
<p>If you try this code, Python will complain that you try to compare a number with a string: <codeclass="docutils literal notranslate"><spanclass="pre">figure</span></code>
is a number and <codeclass="docutils literal notranslate"><spanclass="pre">self.args</span></code> is a string and can’t be compared as-is in Python. Python doesn’t do
“implicit converting” as some languages do. By the way, this might be annoying sometimes, and other
times you will be glad it tries to encourage you to be explicit rather than implicit about what to
do. This is an ongoing debate between programmers. Let’s move on!</p>
<p>So we need to convert the command argument from a <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> into an <codeclass="docutils literal notranslate"><spanclass="pre">int</span></code>. There are a few ways to do
it. But the proper way is to try to convert and deal with the <codeclass="docutils literal notranslate"><spanclass="pre">ValueError</span></code> Python exception.</p>
<p>Converting a <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> into an <codeclass="docutils literal notranslate"><spanclass="pre">int</span></code> in Python is extremely simple: just use the <codeclass="docutils literal notranslate"><spanclass="pre">int</span></code> function, give it
the string and it returns an integer, if it could. If it can’t, it will raise <codeclass="docutils literal notranslate"><spanclass="pre">ValueError</span></code>. So
we’ll need to catch that. However, we also have to indicate to Evennia that, should the number be
invalid, no further parsing should be done. Here’s a new attempt at our command with this
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"</span><spanclass="si">{</span><spanclass="n">args</span><spanclass="si">}</span><spanclass="s2"> is not a valid number."</span><spanclass="p">)</span>
<spanclass="n">figure</span><spanclass="o">=</span><spanclass="n">randint</span><spanclass="p">(</span><spanclass="mi">1</span><spanclass="p">,</span><spanclass="mi">6</span><spanclass="p">)</span><spanclass="c1"># return a pseudo-random number between 1 and 6, including both</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You roll a die. It lands on the number </span><spanclass="si">{</span><spanclass="n">figure</span><spanclass="si">}</span><spanclass="s2">."</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">entered</span><spanclass="si">}</span><spanclass="s2">, you have won!"</span><spanclass="p">)</span>
<spanclass="k">else</span><spanclass="p">:</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">entered</span><spanclass="si">}</span><spanclass="s2">, you have lost."</span><spanclass="p">)</span>
</pre></div>
</div>
<p>Before enjoying the result, let’s examine the <codeclass="docutils literal notranslate"><spanclass="pre">parse</span></code> method a little more: what it does is try to
convert the entered argument from a <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> to an <codeclass="docutils literal notranslate"><spanclass="pre">int</span></code>. This might fail (if a user enters <codeclass="docutils literal notranslate"><spanclass="pre">roll</span><spanclass="pre">something</span></code>). In such a case, Python raises a <codeclass="docutils literal notranslate"><spanclass="pre">ValueError</span></code> exception. We catch it in our
<codeclass="docutils literal notranslate"><spanclass="pre">try/except</span></code> block, send a message to the user and raise the <codeclass="docutils literal notranslate"><spanclass="pre">InterruptCommand</span></code> exception in
response to tell Evennia to not run <codeclass="docutils literal notranslate"><spanclass="pre">func()</span></code>, since we have no valid number to give it.</p>
<p>In the <codeclass="docutils literal notranslate"><spanclass="pre">func</span></code> method, instead of using <codeclass="docutils literal notranslate"><spanclass="pre">self.args</span></code>, we use <codeclass="docutils literal notranslate"><spanclass="pre">self.entered</span></code> which we have defined in
our <codeclass="docutils literal notranslate"><spanclass="pre">parse</span></code> method. You can expect that, if <codeclass="docutils literal notranslate"><spanclass="pre">func()</span></code> is run, then <codeclass="docutils literal notranslate"><spanclass="pre">self.entered</span></code> contains a valid
number.</p>
<p>If you try this command, it will work as expected this time: the number is converted as it should
and compared to the die roll. You might spend some minutes playing this game. Time out!</p>
<p>Something else we could want to address: in our small example, we only want the user to enter a
positive number between 1 and 6. And the user can enter <codeclass="docutils literal notranslate"><spanclass="pre">roll</span><spanclass="pre">0</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">roll</span><spanclass="pre">-8</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">roll</span><spanclass="pre">208</span></code> for
that matter, the game still works. It might be worth addressing. Again, you could write a
condition to do that, but since we’re catching an exception, we might end up with something cleaner
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"</span><spanclass="si">{</span><spanclass="n">args</span><spanclass="si">}</span><spanclass="s2"> is not a valid number."</span><spanclass="p">)</span>
<spanclass="n">figure</span><spanclass="o">=</span><spanclass="n">randint</span><spanclass="p">(</span><spanclass="mi">1</span><spanclass="p">,</span><spanclass="mi">6</span><spanclass="p">)</span><spanclass="c1"># return a pseudo-random number between 1 and 6, including both</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You roll a die. It lands on the number </span><spanclass="si">{</span><spanclass="n">figure</span><spanclass="si">}</span><spanclass="s2">."</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">entered</span><spanclass="si">}</span><spanclass="s2">, you have won!"</span><spanclass="p">)</span>
<spanclass="k">else</span><spanclass="p">:</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">entered</span><spanclass="si">}</span><spanclass="s2">, you have lost."</span><spanclass="p">)</span>
</pre></div>
</div>
<p>Using grouped exceptions like that makes our code easier to read, but if you feel more comfortable
checking, afterward, that the number the user entered is in the right range, you can do so in a
latter condition.</p>
<blockquote>
<div><p>Notice that we have updated our <codeclass="docutils literal notranslate"><spanclass="pre">parse</span></code> method only in this last attempt, not our <codeclass="docutils literal notranslate"><spanclass="pre">func()</span></code> method
which remains the same. This is one goal of separating argument parsing from command processing,
these two actions are best kept isolated.</p>
</div></blockquote>
</section>
<sectionid="working-with-several-arguments">
<h3>Working with several arguments<aclass="headerlink"href="#working-with-several-arguments"title="Permalink to this headline">¶</a></h3>
<p>Often a command expects several arguments. So far, in our example with the “roll” command, we only
expect one argument: a number and just a number. What if we want the user to specify several
numbers? First the number of dice to roll, then the guess?</p>
<blockquote>
<div><p>You won’t win often if you roll 5 dice but that’s for the example.</p>
</div></blockquote>
<p>So we would like to interpret a command like this:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>> roll 3 12
</pre></div>
</div>
<p>(To be understood: roll 3 dice, my guess is the total number will be 12.)</p>
<p>What we need is to cut our command argument, which is a <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code>, break it at the space (we use the
space as a delimiter). Python provides the <codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code> method which we’ll use. Again, here are
<p>As you can see, <codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code> will “convert” our strings into a list of strings. The specified
argument (<codeclass="docutils literal notranslate"><spanclass="pre">"</span><spanclass="pre">"</span></code> in our case) is used as delimiter. So Python browses our original string. When it
sees a delimiter, it takes whatever is before this delimiter and append it to a list.</p>
<p>The point here is that <codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code> will be used to split our argument. But, as you can see from the
above output, we can never be sure of the length of the list at this point:</p>
<p>Again we could use a condition to check the number of split arguments, but Python offers a better
approach, making use of its exception mechanism. We’ll give a second argument to <codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code>, the
maximum number of splits to do. Let’s see an example, this feature might be confusing at first
glance:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>>>> args = "that is something great"
>>> args.split("", 1) # one split, that is a list with two elements (before, after)
</pre></div>
</div>
<p>[‘that’, ‘is something great’]</p>
<blockquote>
<div><blockquote>
<div></div></blockquote>
</div></blockquote>
<p>Read this example as many times as needed to understand it. The second argument we give to
<codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code> is not the length of the list that should be returned, but the number of times we have
to split. Therefore, we specify 1 here, but we get a list of two elements (before the separator,
after the separator).</p>
<blockquote>
<div><p>What will happen if Python can’t split the number of times we ask?</p>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"Invalid usage. Enter two numbers separated by a space."</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"</span><spanclass="si">{</span><spanclass="n">number</span><spanclass="si">}</span><spanclass="s2"> is not a valid number of dice."</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"</span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">guess</span><spanclass="si">}</span><spanclass="s2"> is not a valid guess."</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You roll </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">number</span><spanclass="si">}</span><spanclass="s2"> dice and obtain the sum </span><spanclass="si">{</span><spanclass="n">figure</span><spanclass="si">}</span><spanclass="s2">."</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">guess</span><spanclass="si">}</span><spanclass="s2">, you have won!"</span><spanclass="p">)</span>
<spanclass="k">else</span><spanclass="p">:</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"You played </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">guess</span><spanclass="si">}</span><spanclass="s2">, you have lost."</span><spanclass="p">)</span>
</pre></div>
</div>
<p>The beginning of the <codeclass="docutils literal notranslate"><spanclass="pre">parse()</span></code> method is what interests us most:</p>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"Invalid usage. Enter two numbers separated by a space."</span><spanclass="p">)</span>
<p>We split the argument using <codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code> but we capture the result in two variables. Python is smart
enough to know that we want what’s left of the space in the first variable, what’s right of the
space in the second variable. If there is not even a space in the string, Python will raise a
<p>This code is much easier to read than browsing through the returned strings of <codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code>. We can
convert both variables the way we did previously. Actually there are not so many changes in this
version and the previous one, most of it is due to name changes for clarity.</p>
<blockquote>
<div><p>Splitting a string with a maximum of splits is a common occurrence while parsing command
arguments. You can also see the <codeclass="docutils literal notranslate"><spanclass="pre">str.rspli8t</span></code> method that does the same thing but from the right of
the string. Therefore, it will attempt to find delimiters at the end of the string and work toward
the beginning of it.</p>
</div></blockquote>
<p>We have used a space as a delimiter. This is absolutely not necessary. You might remember that
most default Evennia commands can take an <codeclass="docutils literal notranslate"><spanclass="pre">=</span></code> sign as a delimiter. Now you know how to parse them
>>> left, right = cmd_args.split("=") # mighht raise ValueError!
>>> left
'book '
>>> right
' chest'
>>>
</pre></div>
</div>
</section>
<sectionid="optional-arguments">
<h3>Optional arguments<aclass="headerlink"href="#optional-arguments"title="Permalink to this headline">¶</a></h3>
<p>Sometimes, you’ll come across commands that have optional arguments. These arguments are not
necessary but they can be set if more information is needed. I will not provide the entire command
code here but just enough code to show the mechanism in Python:</p>
<p>Again, we’ll use <codeclass="docutils literal notranslate"><spanclass="pre">str.split</span></code>, knowing that we might not have any delimiter at all. For instance,
the player could enter the “tel” command like this:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>> tel book
> tell book = chest
</pre></div>
</div>
<p>The equal sign is optional along with whatever is specified after it. A possible solution in our
<codeclass="docutils literal notranslate"><spanclass="pre">parse</span></code> method would be:</p>
<p>This code would place everything the user entered in <codeclass="docutils literal notranslate"><spanclass="pre">obj</span></code> if she didn’t specify any equal sign.
Otherwise, what’s before the equal sign will go in <codeclass="docutils literal notranslate"><spanclass="pre">obj</span></code>, what’s after the equal sign will go in
<codeclass="docutils literal notranslate"><spanclass="pre">destination</span></code>. This makes for quick testing after that, more robust code with less conditions that
might too easily break your code if you’re not careful.</p>
<blockquote>
<div><p>Again, here we specified a maximum numbers of splits. If the users enters:</p>
</div></blockquote>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>> tel book = chest = chair
</pre></div>
</div>
<p>Then <codeclass="docutils literal notranslate"><spanclass="pre">destination</span></code> will contain: <codeclass="docutils literal notranslate"><spanclass="pre">"</span><spanclass="pre">chest</span><spanclass="pre">=</span><spanclass="pre">chair"</span></code>. This is often desired, but it’s up to you to
set parsing however you like.</p>
</section>
</section>
<sectionid="evennia-searches">
<h2>Evennia searches<aclass="headerlink"href="#evennia-searches"title="Permalink to this headline">¶</a></h2>
<p>After this quick tour of some <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> methods, we’ll take a look at some Evennia-specific features
that you won’t find in standard Python.</p>
<p>One very common task is to convert a <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> into an Evennia object. Take the previous example:
having <codeclass="docutils literal notranslate"><spanclass="pre">"book"</span></code> in a variable is great, but we would prefer to know what the user is talking
about… what is this <codeclass="docutils literal notranslate"><spanclass="pre">"book"</span></code>?</p>
<p>To get an object from a string, we perform an Evennia search. Evennia provides a <codeclass="docutils literal notranslate"><spanclass="pre">search</span></code> method on
all typeclassed objects (you will most likely use the one on characters or accounts). This method
supports a very wide array of arguments and has <aclass="reference internal"href="Beginner-Tutorial/Part1/Beginner-Tutorial-Searching-Things.html"><spanclass="doc std std-doc">its own tutorial</span></a>.
Some examples of useful cases follow:</p>
<sectionid="local-searches">
<h3>Local searches<aclass="headerlink"href="#local-searches"title="Permalink to this headline">¶</a></h3>
<p>When an account or a character enters a command, the account or character is found in the <codeclass="docutils literal notranslate"><spanclass="pre">caller</span></code>
attribute. Therefore, <codeclass="docutils literal notranslate"><spanclass="pre">self.caller</span></code> will contain an account or a character (or a session if that’s
a session command, though that’s not as frequent). The <codeclass="docutils literal notranslate"><spanclass="pre">search</span></code> method will be available on this
caller.</p>
<p>Let’s take the same example of our little “tel” command. The user can specify an object as
<p>We specify only one argument to the <codeclass="docutils literal notranslate"><spanclass="pre">search</span></code> method here: the string to search. If Evennia finds a
match, it will return it and we keep it in the <codeclass="docutils literal notranslate"><spanclass="pre">obj</span></code> attribute. If it can’t find anything, it will
return <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code> so we need to check for that:</p>
<p>That’s it. After this condition, you know that whatever is in <codeclass="docutils literal notranslate"><spanclass="pre">self.obj</span></code> is a valid Evennia object
(another character, an object, an exit…).</p>
</section>
<sectionid="quiet-searches">
<h3>Quiet searches<aclass="headerlink"href="#quiet-searches"title="Permalink to this headline">¶</a></h3>
<p>By default, Evennia will handle the case when more than one match is found in the search. The user
will be asked to narrow down and re-enter the command. You can, however, ask to be returned the
list of matches and handle this list yourself:</p>
<spanclass="c1"># This is an empty list, so no match</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"No </span><spanclass="si">{</span><spanclass="n">name</span><spanclass="si">!r}</span><spanclass="s2"> was found."</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">obj</span><spanclass="o">=</span><spanclass="n">objs</span><spanclass="p">[</span><spanclass="mi">0</span><spanclass="p">]</span><spanclass="c1"># Take the first match even if there are several</span>
</pre></div>
</div>
<p>All we have changed to obtain a list is a keyword argument in the <codeclass="docutils literal notranslate"><spanclass="pre">search</span></code> method: <codeclass="docutils literal notranslate"><spanclass="pre">quiet</span></code>. If set
to <codeclass="docutils literal notranslate"><spanclass="pre">True</span></code>, then errors are ignored and a list is always returned, so we need to handle it as such.
Notice in this example, <codeclass="docutils literal notranslate"><spanclass="pre">self.obj</span></code> will contain a valid object too, but if several matches are
found, <codeclass="docutils literal notranslate"><spanclass="pre">self.obj</span></code> will contain the first one, even if more matches are available.</p>
</section>
<sectionid="global-searches">
<h3>Global searches<aclass="headerlink"href="#global-searches"title="Permalink to this headline">¶</a></h3>
<p>By default, Evennia will perform a local search, that is, a search limited by the location in which
the caller is. If you want to perform a global search (search in the entire database), just set the
<codeclass="docutils literal notranslate"><spanclass="pre">global_search</span></code> keyword argument to <codeclass="docutils literal notranslate"><spanclass="pre">True</span></code>:</p>