<pclass="last">You are reading an old version of the Evennia documentation. <ahref="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
<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 the cause of the issue. The traceback is not informative or even non-existing.</p>
<p>Running a <em>debugger</em> can then be very helpful and save a lot of time. Debugging 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>
</ul>
<sectionid="debugging-evennia">
<h2>Debugging Evennia<aclass="headerlink"href="#debugging-evennia"title="Permalink to this headline">¶</a></h2>
<p>To run Evennia with the debugger, follow these steps:</p>
<ol>
<li><p>Find the point in the code where you want to have more insight. Add the following line at that
<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>
</section>
<sectionid="a-simple-example-using-pdb">
<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>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># In file commands/command.py</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="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>
</pre></div>
</div>
<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>
<sectionid="listing-surrounding-lines-of-code">
<h3>Listing surrounding lines of code<aclass="headerlink"href="#listing-surrounding-lines-of-code"title="Permalink to this headline">¶</a></h3>
<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 soon see how).</p>
</section>
<sectionid="examining-variables">
<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 you were in the Python interpreter:</p>
<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>
</div></blockquote>
</section>
<sectionid="executing-the-current-line">
<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 change our line:</p>
<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>) command:</p>
<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 command again.</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>
<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>
<p>Let’s allow the command to continue and try to use an object name as parameter (although, we should
<p>Notice that you’ll have an error in the game this time. Let’s try with a valid parameter. I have another character, <codeclass="docutils literal notranslate"><spanclass="pre">barkeep</span></code>, in this room:</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>
<li><p>Run the code again and see the debugger open.</p></li>
<li><p>Run the program line by line, examining variables, checking the logic of instructions.</p></li>
<li><p>Continue and try again, each step a bit further toward the truth and the working feature.</p></li>
</ol>
</section>
</section>
<sectionid="cheat-sheet-of-pdb-pudb-commands">
<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>
<td><p></p></td>
</tr>
</tbody>
</table>
<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 topic here</a>.</p>
<pclass="last">You are reading an old version of the Evennia documentation. <ahref="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.