<h1>Debugging<aclass="headerlink"href="#debugging"title="Permalink to this headline">¶</a></h1>
<p>Sometimes, an error is not trivial to resolve. A few simple <codeclass="docutils literal notranslate"><spanclass="pre">print</span></code> statements is not enough to find
means running Evennia under control of a special <em>debugger</em> program. This allows you to stop the
action at a given point, view the current state and step forward through the program to see how its
logic works.</p>
<p>Evennia natively supports these debuggers:</p>
<ulclass="simple">
<li><p><aclass="reference external"href="https://docs.python.org/2/library/pdb.html">Pdb</a> is a part of the Python distribution and
available out-of-the-box.</p></li>
<li><p><aclass="reference external"href="https://pypi.org/project/pudb/">PuDB</a> is a third-party debugger that has a slightly more
‘graphical’, curses-based user interface than pdb. It is installed with <codeclass="docutils literal notranslate"><spanclass="pre">pip</span><spanclass="pre">install</span><spanclass="pre">pudb</span></code>.</p></li>
<li><p>(Re-)start Evennia in interactive (foreground) mode with <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">istart</span></code>. This is important -
without this step the debugger will not start correctly - it will start in this interactive
terminal.</p></li>
<li><p>Perform the steps that will trigger the line where you added the <codeclass="docutils literal notranslate"><spanclass="pre">set_trace()</span></code> call. The debugger
will start in the terminal from which Evennia was interactively started.</p></li>
</ol>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">evennia.set_trace</span></code> function takes the following arguments:</p>
<p>Here, <codeclass="docutils literal notranslate"><spanclass="pre">debugger</span></code> is one of <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">pudb</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">auto</span></code>. If <codeclass="docutils literal notranslate"><spanclass="pre">auto</span></code>, use <codeclass="docutils literal notranslate"><spanclass="pre">pudb</span></code> if available, otherwise
use <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code>. The <codeclass="docutils literal notranslate"><spanclass="pre">term_size</span></code> tuple sets the viewport size for <codeclass="docutils literal notranslate"><spanclass="pre">pudb</span></code> only (it’s ignored by <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code>).</p>
<h2>A simple example using pdb<aclass="headerlink"href="#a-simple-example-using-pdb"title="Permalink to this headline">¶</a></h2>
<p>The debugger is useful in different cases, but to begin with, let’s see it working in a command.
Add the following test command (which has a range of deliberate errors) and also add it to your
default cmdset. Then restart Evennia in interactive mode with <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">istart</span></code>.</p>
<spanclass="kn">from</span><spanclass="nn">evennia</span><spanclass="kn">import</span><spanclass="n">set_trace</span><spanclass="p">;</span><spanclass="n">set_trace</span><spanclass="p">()</span><spanclass="c1"># <--- start of debugger</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You've found </span><spanclass="si">{}</span><spanclass="s2">."</span><spanclass="o">.</span><spanclass="n">format</span><spanclass="p">(</span><spanclass="n">obj</span><spanclass="o">.</span><spanclass="n">get_display_name</span><spanclass="p">()))</span>
<p>If you type <codeclass="docutils literal notranslate"><spanclass="pre">test</span></code> in your game, everything will freeze. You won’t get any feedback from the game,
and you won’t be able to enter any command (nor anyone else). It’s because the debugger has started
in your console, and you will find it here. Below is an example with <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code>.</p>
<p><codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> notes where it has stopped execution and, what line is about to be executed (in our case, <codeclass="docutils literal notranslate"><spanclass="pre">obj</span><spanclass="pre">=</span><spanclass="pre">self.search(self.args)</span></code>), and ask what you would like to do.</p>
<p>When you have the <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> prompt <codeclass="docutils literal notranslate"><spanclass="pre">(Pdb)</span></code>, you can type in different commands to explore the code. The
first one you should know is <codeclass="docutils literal notranslate"><spanclass="pre">list</span></code> (you can type <codeclass="docutils literal notranslate"><spanclass="pre">l</span></code> for short):</p>
<spanclass="mi">47</span><spanclass="kn">from</span><spanclass="nn">evennia</span><spanclass="kn">import</span><spanclass="n">set_trace</span><spanclass="p">;</span><spanclass="n">set_trace</span><spanclass="p">()</span><spanclass="c1"># <--- start of debugger</span>
<spanclass="mi">49</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You've found </span><spanclass="si">{}</span><spanclass="s2">."</span><spanclass="o">.</span><spanclass="n">format</span><spanclass="p">(</span><spanclass="n">obj</span><spanclass="o">.</span><spanclass="n">get_display_name</span><spanclass="p">()))</span>
<p>Okay, this didn’t do anything spectacular, but when you become more confident with <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> and find
yourself in lots of different files, you sometimes need to see what’s around in code. Notice that
there is a little arrow (<codeclass="docutils literal notranslate"><spanclass="pre">-></span></code>) before the line that is about to be executed.</p>
<p>This is important: <strong>about to be</strong>, not <strong>has just been</strong>. You need to tell <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> to go on (we’ll
<h3>Examining variables<aclass="headerlink"href="#examining-variables"title="Permalink to this headline">¶</a></h3>
<p><codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> allows you to examine variables (or really, to run any Python instruction). It is very useful
to know the values of variables at a specific line. To see a variable, just type its name (as if
<p>That figures, since at this point, we haven’t created the variable yet.</p>
<blockquote>
<div><p>Examining variable in this way is quite powerful. You can even run Python code and keep on
executing, which can help to check that your fix is actually working when you have identified an
error. If you have variable names that will conflict with <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> commands (like a <codeclass="docutils literal notranslate"><spanclass="pre">list</span></code>
variable), you can prefix your variable with <codeclass="docutils literal notranslate"><spanclass="pre">!</span></code>, to tell <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> that what follows is Python code.</p>
<h3>Executing the current line<aclass="headerlink"href="#executing-the-current-line"title="Permalink to this headline">¶</a></h3>
<p>It’s time we asked <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> to execute the current line. To do so, use the <codeclass="docutils literal notranslate"><spanclass="pre">next</span></code> command. You can
shorten it by just typing <codeclass="docutils literal notranslate"><spanclass="pre">n</span></code>:</p>
<spanclass="ne">AttributeError</span><spanclass="p">:</span><spanclass="s2">"'CmdTest' object has no attribute 'search'"</span>
<p><codeclass="docutils literal notranslate"><spanclass="pre">Pdb</span></code> is complaining that you try to call the <codeclass="docutils literal notranslate"><spanclass="pre">search</span></code> method on a command… whereas there’s no
<codeclass="docutils literal notranslate"><spanclass="pre">search</span></code> method on commands. The character executing the command is in <codeclass="docutils literal notranslate"><spanclass="pre">self.caller</span></code>, so we might
<h3>Letting the program run<aclass="headerlink"href="#letting-the-program-run"title="Permalink to this headline">¶</a></h3>
<p><codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> is waiting to execute the same instruction… it provoked an error but it’s ready to try
again, just in case. We have fixed it in theory, but we need to reload, so we need to enter a
command. To tell <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> to terminate and keep on running the program, use the <codeclass="docutils literal notranslate"><spanclass="pre">continue</span></code> (or <codeclass="docutils literal notranslate"><spanclass="pre">c</span></code>)
<p>You see an error being caught, that’s the error we have fixed… or hope to have. Let’s reload the
game and try again. You need to run <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">istart</span></code> again and then run <codeclass="docutils literal notranslate"><spanclass="pre">test</span></code> to get into the
<spanclass="o">-></span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You've found </span><spanclass="si">{}</span><spanclass="s2">."</span><spanclass="o">.</span><spanclass="n">format</span><spanclass="p">(</span><spanclass="n">obj</span><spanclass="o">.</span><spanclass="n">get_display_name</span><spanclass="p">()))</span>
<p>This time the line ran without error. Let’s see what is in the <codeclass="docutils literal notranslate"><spanclass="pre">obj</span></code> variable:</p>
<p>We have entered the <codeclass="docutils literal notranslate"><spanclass="pre">test</span></code> command without parameter, so no object could be found in the search
(<codeclass="docutils literal notranslate"><spanclass="pre">self.args</span></code> is an empty string).</p>
<spanclass="o">-></span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You've found </span><spanclass="si">{}</span><spanclass="s2">."</span><spanclass="o">.</span><spanclass="n">format</span><spanclass="p">(</span><spanclass="n">obj</span><spanclass="o">.</span><spanclass="n">get_display_name</span><spanclass="p">()))</span>
<spanclass="o">-></span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You've found </span><spanclass="si">{}</span><spanclass="s2">."</span><spanclass="o">.</span><spanclass="n">format</span><spanclass="p">(</span><spanclass="n">obj</span><spanclass="o">.</span><spanclass="n">get_display_name</span><spanclass="p">()))</span>
<h3>Stepping through a function<aclass="headerlink"href="#stepping-through-a-function"title="Permalink to this headline">¶</a></h3>
<p><codeclass="docutils literal notranslate"><spanclass="pre">n</span></code> is useful, but it will avoid stepping inside of functions if it can. But most of the time, when
we have an error we don’t understand, it’s because we use functions or methods in a way that wasn’t
intended by the developer of the API. Perhaps using wrong arguments, or calling the function in a
situation that would cause a bug. When we have a line in the debugger that calls a function or
method, we can “step” to examine it further. For instance, in the previous example, when <codeclass="docutils literal notranslate"><spanclass="pre">pdb</span></code> was
about to execute <codeclass="docutils literal notranslate"><spanclass="pre">obj</span><spanclass="pre">=</span><spanclass="pre">self.caller.search(self.args)</span></code>, we may want to see what happens inside of
the <codeclass="docutils literal notranslate"><spanclass="pre">search</span></code> method.</p>
<p>To do so, use the <codeclass="docutils literal notranslate"><spanclass="pre">step</span></code> (or <codeclass="docutils literal notranslate"><spanclass="pre">s</span></code>) command. This command will show you the definition of the
function/method and you can then use <codeclass="docutils literal notranslate"><spanclass="pre">n</span></code> as before to see it line-by-line. In our little example,
stepping through a function or method isn’t that useful, but when you have an impressive set of
commands, functions and so on, it might really be handy to examine some feature and make sure they
<h2>Cheat-sheet of pdb/pudb commands<aclass="headerlink"href="#cheat-sheet-of-pdb-pudb-commands"title="Permalink to this headline">¶</a></h2>
<p>PuDB and Pdb share the same commands. The only real difference is how it’s presented. The <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code>
command is not needed much in <codeclass="docutils literal notranslate"><spanclass="pre">pudb</span></code> since it displays the code directly in its user interface.</p>
<td><p>List the lines around the point of execution (not needed for <codeclass="docutils literal notranslate"><spanclass="pre">pudb</span></code>, it will show</p></td>
<td><p>Repeat the last command (don’t type <codeclass="docutils literal notranslate"><spanclass="pre">n</span></code> repeatedly, just type it once and then press</p></td>
</tr>
<trclass="row-even"><td><p><codeclass="docutils literal notranslate"><spanclass="pre"><RETURN></span></code> to repeat it).</p></td>
<p>If you want to learn more about debugging with Pdb, you will find an <aclass="reference external"href="https://pymotw.com/3/pdb/">interesting tutorial on that