evennia/docs/1.0-dev/_modules/evennia/utils/utils.html
Evennia docbuilder action 1d3843edb2 Updated HTML docs
2022-10-29 15:12:43 +00:00

2994 lines
No EOL
333 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.utils.utils &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<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="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" accesskey="U">evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.utils.utils</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div 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" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/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>Versions</h3>
<ul>
<li><a href="utils.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.utils.utils</h1><div class="highlight"><pre>
<span></span><span class="c1"># -*- encoding: utf-8 -*-</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">General helper functions that don&#39;t fit neatly under any given category.</span>
<span class="sd">They provide some useful string and conversion methods that might</span>
<span class="sd">be of use when designing your own game.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">gc</span>
<span class="kn">import</span> <span class="nn">importlib</span>
<span class="kn">import</span> <span class="nn">importlib.machinery</span>
<span class="kn">import</span> <span class="nn">importlib.util</span>
<span class="kn">import</span> <span class="nn">inspect</span>
<span class="kn">import</span> <span class="nn">math</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">textwrap</span>
<span class="kn">import</span> <span class="nn">threading</span>
<span class="kn">import</span> <span class="nn">traceback</span>
<span class="kn">import</span> <span class="nn">types</span>
<span class="kn">from</span> <span class="nn">ast</span> <span class="kn">import</span> <span class="n">literal_eval</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span><span class="p">,</span> <span class="n">defaultdict</span>
<span class="kn">from</span> <span class="nn">inspect</span> <span class="kn">import</span> <span class="n">getmembers</span><span class="p">,</span> <span class="n">getmodule</span><span class="p">,</span> <span class="n">getmro</span><span class="p">,</span> <span class="n">ismodule</span><span class="p">,</span> <span class="n">trace</span>
<span class="kn">from</span> <span class="nn">os.path</span> <span class="kn">import</span> <span class="n">join</span> <span class="k">as</span> <span class="n">osjoin</span>
<span class="kn">from</span> <span class="nn">string</span> <span class="kn">import</span> <span class="n">punctuation</span>
<span class="kn">from</span> <span class="nn">unicodedata</span> <span class="kn">import</span> <span class="n">east_asian_width</span>
<span class="kn">from</span> <span class="nn">django.apps</span> <span class="kn">import</span> <span class="n">apps</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.core.exceptions</span> <span class="kn">import</span> <span class="n">ValidationError</span> <span class="k">as</span> <span class="n">DjangoValidationError</span>
<span class="kn">from</span> <span class="nn">django.core.validators</span> <span class="kn">import</span> <span class="n">validate_email</span> <span class="k">as</span> <span class="n">django_validate_email</span>
<span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
<span class="kn">from</span> <span class="nn">django.utils.html</span> <span class="kn">import</span> <span class="n">strip_tags</span>
<span class="kn">from</span> <span class="nn">django.utils.translation</span> <span class="kn">import</span> <span class="n">gettext</span> <span class="k">as</span> <span class="n">_</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="kn">from</span> <span class="nn">simpleeval</span> <span class="kn">import</span> <span class="n">simple_eval</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span><span class="p">,</span> <span class="n">threads</span>
<span class="kn">from</span> <span class="nn">twisted.internet.defer</span> <span class="kn">import</span> <span class="n">returnValue</span> <span class="c1"># noqa - used as import target</span>
<span class="kn">from</span> <span class="nn">twisted.internet.task</span> <span class="kn">import</span> <span class="n">deferLater</span>
<span class="n">_MULTIMATCH_TEMPLATE</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">SEARCH_MULTIMATCH_TEMPLATE</span>
<span class="n">_EVENNIA_DIR</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">EVENNIA_DIR</span>
<span class="n">_GAME_DIR</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">GAME_DIR</span>
<span class="n">_IS_MAIN_THREAD</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">current_thread</span><span class="p">()</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s2">&quot;MainThread&quot;</span>
<span class="n">ENCODINGS</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">ENCODINGS</span>
<span class="n">_TASK_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_TICKER_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_STRIP_UNSAFE_TOKENS</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_GA</span> <span class="o">=</span> <span class="nb">object</span><span class="o">.</span><span class="fm">__getattribute__</span>
<span class="n">_SA</span> <span class="o">=</span> <span class="nb">object</span><span class="o">.</span><span class="fm">__setattr__</span>
<span class="n">_DA</span> <span class="o">=</span> <span class="nb">object</span><span class="o">.</span><span class="fm">__delattr__</span>
<div class="viewcode-block" id="is_iter"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.is_iter">[docs]</a><span class="k">def</span> <span class="nf">is_iter</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Checks if an object behaves iterably.</span>
<span class="sd"> Args:</span>
<span class="sd"> obj (any): Entity to check for iterability.</span>
<span class="sd"> Returns:</span>
<span class="sd"> is_iterable (bool): If `obj` is iterable or not.</span>
<span class="sd"> Notes:</span>
<span class="sd"> Strings are *not* accepted as iterable (although they are</span>
<span class="sd"> actually iterable), since string iterations are usually not</span>
<span class="sd"> what we want to do with a string.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">)):</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">iter</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="ow">and</span> <span class="kc">True</span>
<span class="k">except</span> <span class="ne">TypeError</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="make_iter"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.make_iter">[docs]</a><span class="k">def</span> <span class="nf">make_iter</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Makes sure that the object is always iterable.</span>
<span class="sd"> Args:</span>
<span class="sd"> obj (any): Object to make iterable.</span>
<span class="sd"> Returns:</span>
<span class="sd"> iterable (list or iterable): The same object</span>
<span class="sd"> passed-through or made iterable.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="ow">not</span> <span class="n">is_iter</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="ow">and</span> <span class="p">[</span><span class="n">obj</span><span class="p">]</span> <span class="ow">or</span> <span class="n">obj</span></div>
<div class="viewcode-block" id="wrap"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.wrap">[docs]</a><span class="k">def</span> <span class="nf">wrap</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Safely wrap text to a certain number of characters.</span>
<span class="sd"> Args:</span>
<span class="sd"> text (str): The text to wrap.</span>
<span class="sd"> width (int, optional): The number of characters to wrap to.</span>
<span class="sd"> indent (int): How much to indent each line (with whitespace).</span>
<span class="sd"> Returns:</span>
<span class="sd"> text (str): Properly wrapped text.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">width</span> <span class="o">=</span> <span class="n">width</span> <span class="k">if</span> <span class="n">width</span> <span class="k">else</span> <span class="n">settings</span><span class="o">.</span><span class="n">CLIENT_DEFAULT_WIDTH</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">text</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;&quot;</span>
<span class="n">indent</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">indent</span>
<span class="k">return</span> <span class="n">to_str</span><span class="p">(</span><span class="n">textwrap</span><span class="o">.</span><span class="n">fill</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">initial_indent</span><span class="o">=</span><span class="n">indent</span><span class="p">,</span> <span class="n">subsequent_indent</span><span class="o">=</span><span class="n">indent</span><span class="p">))</span></div>
<span class="c1"># alias - fill</span>
<span class="n">fill</span> <span class="o">=</span> <span class="n">wrap</span>
<div class="viewcode-block" id="pad"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.pad">[docs]</a><span class="k">def</span> <span class="nf">pad</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">align</span><span class="o">=</span><span class="s2">&quot;c&quot;</span><span class="p">,</span> <span class="n">fillchar</span><span class="o">=</span><span class="s2">&quot; &quot;</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Pads to a given width.</span>
<span class="sd"> Args:</span>
<span class="sd"> text (str): Text to pad.</span>
<span class="sd"> width (int, optional): The width to pad to, in characters.</span>
<span class="sd"> align (str, optional): This is one of &#39;c&#39;, &#39;l&#39; or &#39;r&#39; (center,</span>
<span class="sd"> left or right).</span>
<span class="sd"> fillchar (str, optional): The character to fill with.</span>
<span class="sd"> Returns:</span>
<span class="sd"> text (str): The padded text.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">width</span> <span class="o">=</span> <span class="n">width</span> <span class="k">if</span> <span class="n">width</span> <span class="k">else</span> <span class="n">settings</span><span class="o">.</span><span class="n">CLIENT_DEFAULT_WIDTH</span>
<span class="n">align</span> <span class="o">=</span> <span class="n">align</span> <span class="k">if</span> <span class="n">align</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;c&quot;</span><span class="p">,</span> <span class="s2">&quot;l&quot;</span><span class="p">,</span> <span class="s2">&quot;r&quot;</span><span class="p">)</span> <span class="k">else</span> <span class="s2">&quot;c&quot;</span>
<span class="n">fillchar</span> <span class="o">=</span> <span class="n">fillchar</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">fillchar</span> <span class="k">else</span> <span class="s2">&quot; &quot;</span>
<span class="k">if</span> <span class="n">align</span> <span class="o">==</span> <span class="s2">&quot;l&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">fillchar</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">align</span> <span class="o">==</span> <span class="s2">&quot;r&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">rjust</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">fillchar</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">fillchar</span><span class="p">)</span></div>
<div class="viewcode-block" id="crop"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.crop">[docs]</a><span class="k">def</span> <span class="nf">crop</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s2">&quot;[...]&quot;</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Crop text to a certain width, throwing away text from too-long</span>
<span class="sd"> lines.</span>
<span class="sd"> Args:</span>
<span class="sd"> text (str): Text to crop.</span>
<span class="sd"> width (int, optional): Width of line to crop, in characters.</span>
<span class="sd"> suffix (str, optional): This is appended to the end of cropped</span>
<span class="sd"> lines to show that the line actually continues. Cropping</span>
<span class="sd"> will be done so that the suffix will also fit within the</span>
<span class="sd"> given width. If width is too small to fit both crop and</span>
<span class="sd"> suffix, the suffix will be dropped.</span>
<span class="sd"> Returns:</span>
<span class="sd"> text (str): The cropped text.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">width</span> <span class="o">=</span> <span class="n">width</span> <span class="k">if</span> <span class="n">width</span> <span class="k">else</span> <span class="n">settings</span><span class="o">.</span><span class="n">CLIENT_DEFAULT_WIDTH</span>
<span class="n">ltext</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ltext</span> <span class="o">&lt;=</span> <span class="n">width</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">lsuffix</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">suffix</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="p">[:</span><span class="n">width</span><span class="p">]</span> <span class="k">if</span> <span class="n">lsuffix</span> <span class="o">&gt;=</span> <span class="n">width</span> <span class="k">else</span> <span class="s2">&quot;</span><span class="si">%s%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">text</span><span class="p">[:</span> <span class="n">width</span> <span class="o">-</span> <span class="n">lsuffix</span><span class="p">],</span> <span class="n">suffix</span><span class="p">)</span>
<span class="k">return</span> <span class="n">to_str</span><span class="p">(</span><span class="n">text</span><span class="p">)</span></div>
<div class="viewcode-block" id="dedent"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.dedent">[docs]</a><span class="k">def</span> <span class="nf">dedent</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">baseline_index</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Safely clean all whitespace at the left of a paragraph.</span>
<span class="sd"> Args:</span>
<span class="sd"> text (str): The text to dedent.</span>
<span class="sd"> baseline_index (int, optional): Which row to use as a &#39;base&#39;</span>
<span class="sd"> for the indentation. Lines will be dedented to this level but</span>
<span class="sd"> no further. If None, indent so as to completely deindent the</span>
<span class="sd"> least indented text.</span>
<span class="sd"> indent (int, optional): If given, force all lines to this indent.</span>
<span class="sd"> This bypasses `baseline_index`.</span>
<span class="sd"> Returns:</span>
<span class="sd"> text (str): Dedented string.</span>
<span class="sd"> Notes:</span>
<span class="sd"> This is useful for preserving triple-quoted string indentation</span>
<span class="sd"> while still shifting it all to be next to the left edge of the</span>
<span class="sd"> display.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">text</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;&quot;</span>
<span class="k">if</span> <span class="n">indent</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">ind</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">indent</span>
<span class="n">indline</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</span> <span class="n">ind</span>
<span class="k">return</span> <span class="n">ind</span> <span class="o">+</span> <span class="n">indline</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">baseline_index</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="n">textwrap</span><span class="o">.</span><span class="n">dedent</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">baseline</span> <span class="o">=</span> <span class="n">lines</span><span class="p">[</span><span class="n">baseline_index</span><span class="p">]</span>
<span class="n">spaceremove</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">baseline</span><span class="p">)</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">baseline</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">))</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="n">line</span><span class="p">[</span><span class="nb">min</span><span class="p">(</span><span class="n">spaceremove</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">line</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">)))</span> <span class="p">:]</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="justify"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.justify">[docs]</a><span class="k">def</span> <span class="nf">justify</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">align</span><span class="o">=</span><span class="s2">&quot;f&quot;</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Fully justify a text so that it fits inside `width`. When using</span>
<span class="sd"> full justification (default) this will be done by padding between</span>
<span class="sd"> words with extra whitespace where necessary. Paragraphs will</span>
<span class="sd"> be retained.</span>
<span class="sd"> Args:</span>
<span class="sd"> text (str): Text to justify.</span>
<span class="sd"> width (int, optional): The length of each line, in characters.</span>
<span class="sd"> align (str, optional): The alignment, &#39;l&#39;, &#39;c&#39;, &#39;r&#39; or &#39;f&#39;</span>
<span class="sd"> for left, center, right or full justification respectively.</span>
<span class="sd"> indent (int, optional): Number of characters indentation of</span>
<span class="sd"> entire justified text block.</span>
<span class="sd"> Returns:</span>
<span class="sd"> justified (str): The justified and indented block of text.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">width</span> <span class="o">=</span> <span class="n">width</span> <span class="k">if</span> <span class="n">width</span> <span class="k">else</span> <span class="n">settings</span><span class="o">.</span><span class="n">CLIENT_DEFAULT_WIDTH</span>
<span class="k">def</span> <span class="nf">_process_line</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> helper function that distributes extra spaces between words. The number</span>
<span class="sd"> of gaps is nwords - 1 but must be at least 1 for single-word lines. We</span>
<span class="sd"> distribute odd spaces randomly to one of the gaps.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">line_rest</span> <span class="o">=</span> <span class="n">width</span> <span class="o">-</span> <span class="p">(</span><span class="n">wlen</span> <span class="o">+</span> <span class="n">ngaps</span><span class="p">)</span>
<span class="n">gap</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="c1"># minimum gap between words</span>
<span class="k">if</span> <span class="n">line_rest</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">align</span> <span class="o">==</span> <span class="s2">&quot;l&quot;</span><span class="p">:</span>
<span class="k">if</span> <span class="n">line</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">&quot;</span><span class="p">:</span>
<span class="n">line</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="p">(</span><span class="n">line_rest</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">width</span> <span class="o">+</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">width</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">line</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">line_rest</span>
<span class="k">elif</span> <span class="n">align</span> <span class="o">==</span> <span class="s2">&quot;r&quot;</span><span class="p">:</span>
<span class="n">line</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">line_rest</span> <span class="o">+</span> <span class="n">line</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">elif</span> <span class="n">align</span> <span class="o">==</span> <span class="s2">&quot;c&quot;</span><span class="p">:</span>
<span class="n">pad</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="p">(</span><span class="n">line_rest</span> <span class="o">//</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">line</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">pad</span> <span class="o">+</span> <span class="n">line</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="n">line</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">&quot;</span><span class="p">:</span>
<span class="n">line</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="p">(</span>
<span class="n">pad</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="p">(</span><span class="n">line_rest</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">width</span> <span class="o">+</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">width</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">line</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">line</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">pad</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="p">(</span><span class="n">line_rest</span> <span class="o">%</span> <span class="mi">2</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># align &#39;f&#39;</span>
<span class="n">gap</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="p">(</span><span class="n">line_rest</span> <span class="o">//</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">ngaps</span><span class="p">))</span>
<span class="n">rest_gap</span> <span class="o">=</span> <span class="n">line_rest</span> <span class="o">%</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">ngaps</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">rest_gap</span><span class="p">):</span>
<span class="n">line</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span>
<span class="k">elif</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
<span class="k">return</span> <span class="p">[</span><span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">width</span><span class="p">]</span>
<span class="k">return</span> <span class="n">gap</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
<span class="c1"># split into paragraphs and words</span>
<span class="n">paragraphs</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">\s*?</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">MULTILINE</span><span class="p">)</span>
<span class="n">words</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">ip</span><span class="p">,</span> <span class="n">paragraph</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">paragraphs</span><span class="p">):</span>
<span class="k">if</span> <span class="n">ip</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">words</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="n">words</span><span class="o">.</span><span class="n">extend</span><span class="p">((</span><span class="n">word</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">word</span><span class="p">))</span> <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">paragraph</span><span class="o">.</span><span class="n">split</span><span class="p">())</span>
<span class="n">ngaps</span><span class="p">,</span> <span class="n">wlen</span><span class="p">,</span> <span class="n">line</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[]</span>
<span class="n">lines</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">while</span> <span class="n">words</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">line</span><span class="p">:</span>
<span class="c1"># start a new line</span>
<span class="n">word</span> <span class="o">=</span> <span class="n">words</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">wlen</span> <span class="o">=</span> <span class="n">word</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">line</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">word</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">elif</span> <span class="p">(</span><span class="n">words</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">wlen</span> <span class="o">+</span> <span class="n">ngaps</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">width</span><span class="p">:</span>
<span class="c1"># next word would exceed word length of line + smallest gaps</span>
<span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_process_line</span><span class="p">(</span><span class="n">line</span><span class="p">))</span>
<span class="n">ngaps</span><span class="p">,</span> <span class="n">wlen</span><span class="p">,</span> <span class="n">line</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># put a new word on the line</span>
<span class="n">word</span> <span class="o">=</span> <span class="n">words</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">line</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">word</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">if</span> <span class="n">word</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="c1"># a new paragraph, process immediately</span>
<span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_process_line</span><span class="p">(</span><span class="n">line</span><span class="p">))</span>
<span class="n">ngaps</span><span class="p">,</span> <span class="n">wlen</span><span class="p">,</span> <span class="n">line</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">wlen</span> <span class="o">+=</span> <span class="n">word</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">ngaps</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">line</span><span class="p">:</span> <span class="c1"># catch any line left behind</span>
<span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_process_line</span><span class="p">(</span><span class="n">line</span><span class="p">))</span>
<span class="n">indentstring</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">indent</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">indentstring</span> <span class="o">+</span> <span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">])</span></div>
<div class="viewcode-block" id="columnize"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.columnize">[docs]</a><span class="k">def</span> <span class="nf">columnize</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">columns</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">spacing</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">align</span><span class="o">=</span><span class="s2">&quot;l&quot;</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Break a string into a number of columns, using as little</span>
<span class="sd"> vertical space as possible.</span>
<span class="sd"> Args:</span>
<span class="sd"> string (str): The string to columnize.</span>
<span class="sd"> columns (int, optional): The number of columns to use.</span>
<span class="sd"> spacing (int, optional): How much space to have between columns.</span>
<span class="sd"> width (int, optional): The max width of the columns.</span>
<span class="sd"> Defaults to client&#39;s default width.</span>
<span class="sd"> Returns:</span>
<span class="sd"> columns (str): Text divided into columns.</span>
<span class="sd"> Raises:</span>
<span class="sd"> RuntimeError: If given invalid values.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">columns</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">columns</span><span class="p">)</span>
<span class="n">spacing</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">spacing</span><span class="p">)</span>
<span class="n">width</span> <span class="o">=</span> <span class="n">width</span> <span class="k">if</span> <span class="n">width</span> <span class="k">else</span> <span class="n">settings</span><span class="o">.</span><span class="n">CLIENT_DEFAULT_WIDTH</span>
<span class="n">w_spaces</span> <span class="o">=</span> <span class="p">(</span><span class="n">columns</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">spacing</span>
<span class="n">w_txt</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">width</span> <span class="o">-</span> <span class="n">w_spaces</span><span class="p">)</span>
<span class="k">if</span> <span class="n">w_spaces</span> <span class="o">+</span> <span class="n">columns</span> <span class="o">&gt;</span> <span class="n">width</span><span class="p">:</span> <span class="c1"># require at least 1 char per column</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Width too small to fit columns&quot;</span><span class="p">)</span>
<span class="n">colwidth</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">w_txt</span> <span class="o">/</span> <span class="p">(</span><span class="mf">1.0</span> <span class="o">*</span> <span class="n">columns</span><span class="p">))</span>
<span class="c1"># first make a single column which we then split</span>
<span class="n">onecol</span> <span class="o">=</span> <span class="n">justify</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">colwidth</span><span class="p">,</span> <span class="n">align</span><span class="o">=</span><span class="n">align</span><span class="p">)</span>
<span class="n">onecol</span> <span class="o">=</span> <span class="n">onecol</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">nrows</span><span class="p">,</span> <span class="n">dangling</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">onecol</span><span class="p">),</span> <span class="n">columns</span><span class="p">)</span>
<span class="n">nrows</span> <span class="o">=</span> <span class="p">[</span><span class="n">nrows</span> <span class="o">+</span> <span class="mi">1</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">dangling</span> <span class="k">else</span> <span class="n">nrows</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">columns</span><span class="p">)]</span>
<span class="n">height</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">nrows</span><span class="p">)</span>
<span class="n">cols</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">istart</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">irows</span> <span class="ow">in</span> <span class="n">nrows</span><span class="p">:</span>
<span class="n">cols</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">onecol</span><span class="p">[</span><span class="n">istart</span> <span class="p">:</span> <span class="n">istart</span> <span class="o">+</span> <span class="n">irows</span><span class="p">])</span>
<span class="n">istart</span> <span class="o">=</span> <span class="n">istart</span> <span class="o">+</span> <span class="n">irows</span>
<span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">cols</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">col</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">height</span><span class="p">:</span>
<span class="n">col</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">colwidth</span><span class="p">)</span>
<span class="n">sep</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">spacing</span>
<span class="n">rows</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">irow</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">height</span><span class="p">):</span>
<span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sep</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">col</span><span class="p">[</span><span class="n">irow</span><span class="p">]</span> <span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">cols</span><span class="p">))</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">rows</span><span class="p">)</span></div>
<div class="viewcode-block" id="iter_to_str"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.iter_to_str">[docs]</a><span class="k">def</span> <span class="nf">iter_to_str</span><span class="p">(</span><span class="n">iterable</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot;,&quot;</span><span class="p">,</span> <span class="n">endsep</span><span class="o">=</span><span class="s2">&quot;, and&quot;</span><span class="p">,</span> <span class="n">addquote</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This pretty-formats an iterable list as string output, adding an optional</span>
<span class="sd"> alternative separator to the second to last entry. If `addquote`</span>
<span class="sd"> is `True`, the outgoing strings will be surrounded by quotes.</span>
<span class="sd"> Args:</span>
<span class="sd"> iterable (any): Usually an iterable to print. Each element must be possible to</span>
<span class="sd"> present with a string. Note that if this is a generator, it will be</span>
<span class="sd"> consumed by this operation.</span>
<span class="sd"> sep (str, optional): The string to use as a separator for each item in the iterable.</span>
<span class="sd"> endsep (str, optional): The last item separator will be replaced with this value.</span>
<span class="sd"> addquote (bool, optional): This will surround all outgoing</span>
<span class="sd"> values with double quotes.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str: The list represented as a string.</span>
<span class="sd"> Notes:</span>
<span class="sd"> Default is to use &#39;Oxford comma&#39;, like 1, 2, 3, and 4.</span>
<span class="sd"> Examples:</span>
<span class="sd"> ```python</span>
<span class="sd"> &gt;&gt;&gt; iter_to_string([1,2,3], endsep=&#39;,&#39;)</span>
<span class="sd"> &#39;1, 2, 3&#39;</span>
<span class="sd"> &gt;&gt;&gt; iter_to_string([1,2,3], endsep=&#39;&#39;)</span>
<span class="sd"> &#39;1, 2 3&#39;</span>
<span class="sd"> &gt;&gt;&gt; iter_to_string([1,2,3], ensdep=&#39;and&#39;)</span>
<span class="sd"> &#39;1, 2 and 3&#39;</span>
<span class="sd"> &gt;&gt;&gt; iter_to_string([1,2,3], sep=&#39;;&#39;, endsep=&#39;;&#39;)</span>
<span class="sd"> &#39;1; 2; 3&#39;</span>
<span class="sd"> &gt;&gt;&gt; iter_to_string([1,2,3], addquote=True)</span>
<span class="sd"> &#39;&quot;1&quot;, &quot;2&quot;, and &quot;3&quot;&#39;</span>
<span class="sd"> ```</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">iterable</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">make_iter</span><span class="p">(</span><span class="n">iterable</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">iterable</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;&quot;</span>
<span class="n">len_iter</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">iterable</span><span class="p">)</span>
<span class="k">if</span> <span class="n">addquote</span><span class="p">:</span>
<span class="n">iterable</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;&quot;</span><span class="si">{</span><span class="n">val</span><span class="si">}</span><span class="s1">&quot;&#39;</span> <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">iterable</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">)</span>
<span class="k">if</span> <span class="n">endsep</span><span class="p">:</span>
<span class="k">if</span> <span class="n">endsep</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">sep</span><span class="p">):</span>
<span class="c1"># oxford comma alternative</span>
<span class="n">endsep</span> <span class="o">=</span> <span class="n">endsep</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="k">if</span> <span class="n">len_iter</span> <span class="o">&lt;</span> <span class="mi">3</span> <span class="k">else</span> <span class="n">endsep</span>
<span class="k">elif</span> <span class="n">endsep</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">punctuation</span><span class="p">:</span>
<span class="c1"># add a leading space if endsep is a word</span>
<span class="n">endsep</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">endsep</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="c1"># also add a leading space if separator is a word</span>
<span class="k">if</span> <span class="n">sep</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">punctuation</span><span class="p">:</span>
<span class="n">sep</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span> <span class="o">+</span> <span class="n">sep</span>
<span class="k">if</span> <span class="n">len_iter</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">iterable</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">elif</span> <span class="n">len_iter</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">endsep</span><span class="si">}</span><span class="s2"> &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">sep</span><span class="si">}</span><span class="s2"> &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">endsep</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">iterable</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span></div>
<span class="c1"># legacy aliases</span>
<span class="n">list_to_string</span> <span class="o">=</span> <span class="n">iter_to_str</span>
<span class="n">iter_to_string</span> <span class="o">=</span> <span class="n">iter_to_str</span>
<div class="viewcode-block" id="wildcard_to_regexp"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.wildcard_to_regexp">[docs]</a><span class="k">def</span> <span class="nf">wildcard_to_regexp</span><span class="p">(</span><span class="n">instring</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Converts a player-supplied string that may have wildcards in it to</span>
<span class="sd"> regular expressions. This is useful for name matching.</span>
<span class="sd"> Args:</span>
<span class="sd"> instring (string): A string that may potentially contain</span>
<span class="sd"> wildcards (`*` or `?`).</span>
<span class="sd"> Returns:</span>
<span class="sd"> regex (str): A string where wildcards were replaced with</span>
<span class="sd"> regular expressions.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">regexp_string</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="c1"># If the string starts with an asterisk, we can&#39;t impose the beginning of</span>
<span class="c1"># string (^) limiter.</span>
<span class="k">if</span> <span class="n">instring</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;*&quot;</span><span class="p">:</span>
<span class="n">regexp_string</span> <span class="o">+=</span> <span class="s2">&quot;^&quot;</span>
<span class="c1"># Replace any occurances of * or ? with the appropriate groups.</span>
<span class="n">regexp_string</span> <span class="o">+=</span> <span class="n">instring</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;*&quot;</span><span class="p">,</span> <span class="s2">&quot;(.*)&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;?&quot;</span><span class="p">,</span> <span class="s2">&quot;(.</span><span class="si">{1}</span><span class="s2">)&quot;</span><span class="p">)</span>
<span class="c1"># If there&#39;s an asterisk at the end of the string, we can&#39;t impose the</span>
<span class="c1"># end of string ($) limiter.</span>
<span class="k">if</span> <span class="n">instring</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;*&quot;</span><span class="p">:</span>
<span class="n">regexp_string</span> <span class="o">+=</span> <span class="s2">&quot;$&quot;</span>
<span class="k">return</span> <span class="n">regexp_string</span></div>
<div class="viewcode-block" id="time_format"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.time_format">[docs]</a><span class="k">def</span> <span class="nf">time_format</span><span class="p">(</span><span class="n">seconds</span><span class="p">,</span> <span class="n">style</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Function to return a &#39;prettified&#39; version of a value in seconds.</span>
<span class="sd"> Args:</span>
<span class="sd"> seconds (int): Number if seconds to format.</span>
<span class="sd"> style (int): One of the following styles:</span>
<span class="sd"> 0. &quot;1d 08:30&quot;</span>
<span class="sd"> 1. &quot;1d&quot;</span>
<span class="sd"> 2. &quot;1 day, 8 hours, 30 minutes&quot;</span>
<span class="sd"> 3. &quot;1 day, 8 hours, 30 minutes, 10 seconds&quot;</span>
<span class="sd"> 4. highest unit (like &quot;3 years&quot; or &quot;8 months&quot; or &quot;1 second&quot;)</span>
<span class="sd"> Returns:</span>
<span class="sd"> timeformatted (str): A pretty time string.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">seconds</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">seconds</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># We&#39;ll just use integer math, no need for decimal precision.</span>
<span class="n">seconds</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">seconds</span><span class="p">)</span>
<span class="n">days</span> <span class="o">=</span> <span class="n">seconds</span> <span class="o">//</span> <span class="mi">86400</span>
<span class="n">seconds</span> <span class="o">-=</span> <span class="n">days</span> <span class="o">*</span> <span class="mi">86400</span>
<span class="n">hours</span> <span class="o">=</span> <span class="n">seconds</span> <span class="o">//</span> <span class="mi">3600</span>
<span class="n">seconds</span> <span class="o">-=</span> <span class="n">hours</span> <span class="o">*</span> <span class="mi">3600</span>
<span class="n">minutes</span> <span class="o">=</span> <span class="n">seconds</span> <span class="o">//</span> <span class="mi">60</span>
<span class="n">seconds</span> <span class="o">-=</span> <span class="n">minutes</span> <span class="o">*</span> <span class="mi">60</span>
<span class="n">retval</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">if</span> <span class="n">style</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Standard colon-style output.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">days</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">retval</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2">d </span><span class="si">%02i</span><span class="s2">:</span><span class="si">%02i</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">days</span><span class="p">,</span> <span class="n">hours</span><span class="p">,</span> <span class="n">minutes</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">retval</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%02i</span><span class="s2">:</span><span class="si">%02i</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">hours</span><span class="p">,</span> <span class="n">minutes</span><span class="p">)</span>
<span class="k">return</span> <span class="n">retval</span>
<span class="k">elif</span> <span class="n">style</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Simple, abbreviated form that only shows the highest time amount.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">days</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2">d&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">days</span><span class="p">,)</span>
<span class="k">elif</span> <span class="n">hours</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2">h&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">hours</span><span class="p">,)</span>
<span class="k">elif</span> <span class="n">minutes</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2">m&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">minutes</span><span class="p">,)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2">s&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">seconds</span><span class="p">,)</span>
<span class="k">elif</span> <span class="n">style</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Full-detailed, long-winded format. We ignore seconds.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">days_str</span> <span class="o">=</span> <span class="n">hours_str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="n">minutes_str</span> <span class="o">=</span> <span class="s2">&quot;0 minutes&quot;</span>
<span class="k">if</span> <span class="n">days</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">days</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">days_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> day, &quot;</span> <span class="o">%</span> <span class="n">days</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">days_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> days, &quot;</span> <span class="o">%</span> <span class="n">days</span>
<span class="k">if</span> <span class="n">days</span> <span class="ow">or</span> <span class="n">hours</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">hours</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">hours_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> hour, &quot;</span> <span class="o">%</span> <span class="n">hours</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">hours_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> hours, &quot;</span> <span class="o">%</span> <span class="n">hours</span>
<span class="k">if</span> <span class="n">hours</span> <span class="ow">or</span> <span class="n">minutes</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">minutes</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">minutes_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> minute &quot;</span> <span class="o">%</span> <span class="n">minutes</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">minutes_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> minutes &quot;</span> <span class="o">%</span> <span class="n">minutes</span>
<span class="n">retval</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s%s%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">days_str</span><span class="p">,</span> <span class="n">hours_str</span><span class="p">,</span> <span class="n">minutes_str</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">style</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Full-detailed, long-winded format. Includes seconds.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">days_str</span> <span class="o">=</span> <span class="n">hours_str</span> <span class="o">=</span> <span class="n">minutes_str</span> <span class="o">=</span> <span class="n">seconds_str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">if</span> <span class="n">days</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">days</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">days_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> day, &quot;</span> <span class="o">%</span> <span class="n">days</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">days_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> days, &quot;</span> <span class="o">%</span> <span class="n">days</span>
<span class="k">if</span> <span class="n">days</span> <span class="ow">or</span> <span class="n">hours</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">hours</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">hours_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> hour, &quot;</span> <span class="o">%</span> <span class="n">hours</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">hours_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> hours, &quot;</span> <span class="o">%</span> <span class="n">hours</span>
<span class="k">if</span> <span class="n">hours</span> <span class="ow">or</span> <span class="n">minutes</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">minutes</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">minutes_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> minute &quot;</span> <span class="o">%</span> <span class="n">minutes</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">minutes_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> minutes &quot;</span> <span class="o">%</span> <span class="n">minutes</span>
<span class="k">if</span> <span class="n">minutes</span> <span class="ow">or</span> <span class="n">seconds</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">seconds</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">seconds_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> second &quot;</span> <span class="o">%</span> <span class="n">seconds</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">seconds_str</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2"> seconds &quot;</span> <span class="o">%</span> <span class="n">seconds</span>
<span class="n">retval</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s%s%s%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">days_str</span><span class="p">,</span> <span class="n">hours_str</span><span class="p">,</span> <span class="n">minutes_str</span><span class="p">,</span> <span class="n">seconds_str</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">style</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Only return the highest unit.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">days</span> <span class="o">&gt;=</span> <span class="mi">730</span><span class="p">:</span> <span class="c1"># Several years</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">{}</span><span class="s2"> years&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">days</span> <span class="o">//</span> <span class="mi">365</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">days</span> <span class="o">&gt;=</span> <span class="mi">365</span><span class="p">:</span> <span class="c1"># One year</span>
<span class="k">return</span> <span class="s2">&quot;a year&quot;</span>
<span class="k">elif</span> <span class="n">days</span> <span class="o">&gt;=</span> <span class="mi">62</span><span class="p">:</span> <span class="c1"># Several months</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">{}</span><span class="s2"> months&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">days</span> <span class="o">//</span> <span class="mi">31</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">days</span> <span class="o">&gt;=</span> <span class="mi">31</span><span class="p">:</span> <span class="c1"># One month</span>
<span class="k">return</span> <span class="s2">&quot;a month&quot;</span>
<span class="k">elif</span> <span class="n">days</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span> <span class="c1"># Several days</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">{}</span><span class="s2"> days&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">days</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">days</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;a day&quot;</span>
<span class="k">elif</span> <span class="n">hours</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span> <span class="c1"># Several hours</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">{}</span><span class="s2"> hours&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">hours</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">hours</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># One hour</span>
<span class="k">return</span> <span class="s2">&quot;an hour&quot;</span>
<span class="k">elif</span> <span class="n">minutes</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span> <span class="c1"># Several minutes</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">{}</span><span class="s2"> minutes&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">minutes</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">minutes</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># One minute</span>
<span class="k">return</span> <span class="s2">&quot;a minute&quot;</span>
<span class="k">elif</span> <span class="n">seconds</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span> <span class="c1"># Several seconds</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">{}</span><span class="s2"> seconds&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">seconds</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">seconds</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;a second&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;0 seconds&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Unknown style for time format: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">style</span><span class="p">)</span>
<span class="k">return</span> <span class="n">retval</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span></div>
<div class="viewcode-block" id="datetime_format"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.datetime_format">[docs]</a><span class="k">def</span> <span class="nf">datetime_format</span><span class="p">(</span><span class="n">dtobj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Pretty-prints the time since a given time.</span>
<span class="sd"> Args:</span>
<span class="sd"> dtobj (datetime): An datetime object, e.g. from Django&#39;s</span>
<span class="sd"> `DateTimeField`.</span>
<span class="sd"> Returns:</span>
<span class="sd"> deltatime (str): A string describing how long ago `dtobj`</span>
<span class="sd"> took place.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">now</span> <span class="o">=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="k">if</span> <span class="n">dtobj</span><span class="o">.</span><span class="n">year</span> <span class="o">&lt;</span> <span class="n">now</span><span class="o">.</span><span class="n">year</span><span class="p">:</span>
<span class="c1"># another year (Apr 5, 2019)</span>
<span class="n">timestring</span> <span class="o">=</span> <span class="n">dtobj</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;%b </span><span class="si">{</span><span class="n">dtobj</span><span class="o">.</span><span class="n">day</span><span class="si">}</span><span class="s2">, %Y&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">dtobj</span><span class="o">.</span><span class="n">date</span><span class="p">()</span> <span class="o">&lt;</span> <span class="n">now</span><span class="o">.</span><span class="n">date</span><span class="p">():</span>
<span class="c1"># another date, same year (Apr 5)</span>
<span class="n">timestring</span> <span class="o">=</span> <span class="n">dtobj</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;%b </span><span class="si">{</span><span class="n">dtobj</span><span class="o">.</span><span class="n">day</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">dtobj</span><span class="o">.</span><span class="n">hour</span> <span class="o">&lt;</span> <span class="n">now</span><span class="o">.</span><span class="n">hour</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
<span class="c1"># same day, more than 1 hour ago (10:45)</span>
<span class="n">timestring</span> <span class="o">=</span> <span class="n">dtobj</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%H:%M&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># same day, less than 1 hour ago (10:45:33)</span>
<span class="n">timestring</span> <span class="o">=</span> <span class="n">dtobj</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%H:%M:%S&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">timestring</span></div>
<div class="viewcode-block" id="host_os_is"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.host_os_is">[docs]</a><span class="k">def</span> <span class="nf">host_os_is</span><span class="p">(</span><span class="n">osname</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check to see if the host OS matches the query.</span>
<span class="sd"> Args:</span>
<span class="sd"> osname (str): Common names are &quot;posix&quot; (linux/unix/mac) and</span>
<span class="sd"> &quot;nt&quot; (windows).</span>
<span class="sd"> Args:</span>
<span class="sd"> is_os (bool): If the os matches or not.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">osname</span></div>
<div class="viewcode-block" id="get_evennia_version"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.get_evennia_version">[docs]</a><span class="k">def</span> <span class="nf">get_evennia_version</span><span class="p">(</span><span class="n">mode</span><span class="o">=</span><span class="s2">&quot;long&quot;</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Helper method for getting the current evennia version.</span>
<span class="sd"> Args:</span>
<span class="sd"> mode (str, optional): One of:</span>
<span class="sd"> - long: 0.9.0 rev342453534</span>
<span class="sd"> - short: 0.9.0</span>
<span class="sd"> - pretty: Evennia 0.9.0</span>
<span class="sd"> Returns:</span>
<span class="sd"> version (str): The version string.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">evennia</span>
<span class="n">vers</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">__version__</span>
<span class="k">if</span> <span class="n">mode</span> <span class="o">==</span> <span class="s2">&quot;short&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="n">vers</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">elif</span> <span class="n">mode</span> <span class="o">==</span> <span class="s2">&quot;pretty&quot;</span><span class="p">:</span>
<span class="n">vers</span> <span class="o">=</span> <span class="n">vers</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;Evennia </span><span class="si">{</span><span class="n">vers</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># mode &quot;long&quot;:</span>
<span class="k">return</span> <span class="n">vers</span></div>
<div class="viewcode-block" id="pypath_to_realpath"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.pypath_to_realpath">[docs]</a><span class="k">def</span> <span class="nf">pypath_to_realpath</span><span class="p">(</span><span class="n">python_path</span><span class="p">,</span> <span class="n">file_ending</span><span class="o">=</span><span class="s2">&quot;.py&quot;</span><span class="p">,</span> <span class="n">pypath_prefixes</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Converts a dotted Python path to an absolute path under the</span>
<span class="sd"> Evennia library directory or under the current game directory.</span>
<span class="sd"> Args:</span>
<span class="sd"> python_path (str): A dot-python path</span>
<span class="sd"> file_ending (str): A file ending, including the period.</span>
<span class="sd"> pypath_prefixes (list): A list of paths to test for existence. These</span>
<span class="sd"> should be on python.path form. EVENNIA_DIR and GAME_DIR are automatically</span>
<span class="sd"> checked, they need not be added to this list.</span>
<span class="sd"> Returns:</span>
<span class="sd"> abspaths (list): All existing, absolute paths created by</span>
<span class="sd"> converting `python_path` to an absolute paths and/or</span>
<span class="sd"> prepending `python_path` by `settings.EVENNIA_DIR`,</span>
<span class="sd"> `settings.GAME_DIR` and by`pypath_prefixes` respectively.</span>
<span class="sd"> Notes:</span>
<span class="sd"> This will also try a few combinations of paths to allow cases</span>
<span class="sd"> where pypath is given including the &quot;evennia.&quot; or &quot;mygame.&quot;</span>
<span class="sd"> prefixes.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">python_path</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>
<span class="n">plong</span> <span class="o">=</span> <span class="n">osjoin</span><span class="p">(</span><span class="o">*</span><span class="n">path</span><span class="p">)</span> <span class="o">+</span> <span class="n">file_ending</span>
<span class="n">pshort</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">osjoin</span><span class="p">(</span><span class="o">*</span><span class="n">path</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span> <span class="o">+</span> <span class="n">file_ending</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">else</span> <span class="n">plong</span>
<span class="p">)</span> <span class="c1"># in case we had evennia. or mygame.</span>
<span class="n">prefixlong</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="o">*</span><span class="n">ppath</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">))</span> <span class="k">for</span> <span class="n">ppath</span> <span class="ow">in</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">pypath_prefixes</span><span class="p">)]</span>
<span class="k">if</span> <span class="n">pypath_prefixes</span>
<span class="k">else</span> <span class="p">[]</span>
<span class="p">)</span>
<span class="n">prefixshort</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">[</span>
<span class="n">osjoin</span><span class="p">(</span><span class="o">*</span><span class="n">ppath</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">:])</span>
<span class="k">for</span> <span class="n">ppath</span> <span class="ow">in</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">pypath_prefixes</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">ppath</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">1</span>
<span class="p">]</span>
<span class="k">if</span> <span class="n">pypath_prefixes</span>
<span class="k">else</span> <span class="p">[]</span>
<span class="p">)</span>
<span class="n">paths</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">[</span><span class="n">plong</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_EVENNIA_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">plong</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixlong</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_GAME_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">plong</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixlong</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_EVENNIA_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">plong</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixshort</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_GAME_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">plong</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixshort</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_EVENNIA_DIR</span><span class="p">,</span> <span class="n">plong</span><span class="p">),</span> <span class="n">osjoin</span><span class="p">(</span><span class="n">_GAME_DIR</span><span class="p">,</span> <span class="n">plong</span><span class="p">)]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_EVENNIA_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">pshort</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixshort</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_GAME_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">pshort</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixshort</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_EVENNIA_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">pshort</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixlong</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_GAME_DIR</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">pshort</span><span class="p">)</span> <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">prefixlong</span><span class="p">]</span>
<span class="o">+</span> <span class="p">[</span><span class="n">osjoin</span><span class="p">(</span><span class="n">_EVENNIA_DIR</span><span class="p">,</span> <span class="n">pshort</span><span class="p">),</span> <span class="n">osjoin</span><span class="p">(</span><span class="n">_GAME_DIR</span><span class="p">,</span> <span class="n">pshort</span><span class="p">)]</span>
<span class="p">)</span>
<span class="c1"># filter out non-existing paths</span>
<span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">paths</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">p</span><span class="p">)))</span></div>
<div class="viewcode-block" id="dbref"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.dbref">[docs]</a><span class="k">def</span> <span class="nf">dbref</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="n">reqhash</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Converts/checks if input is a valid dbref.</span>
<span class="sd"> Args:</span>
<span class="sd"> inp (int, str): A database ref on the form N or #N.</span>
<span class="sd"> reqhash (bool, optional): Require the #N form to accept</span>
<span class="sd"> input as a valid dbref.</span>
<span class="sd"> Returns:</span>
<span class="sd"> dbref (int or None): The integer part of the dbref or `None`</span>
<span class="sd"> if input was not a valid dbref.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">reqhash</span><span class="p">:</span>
<span class="n">num</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">int</span><span class="p">(</span><span class="n">inp</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">&quot;#&quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="ow">and</span> <span class="n">inp</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;#&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">inp</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">&quot;#&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">isdigit</span><span class="p">())</span>
<span class="k">else</span> <span class="kc">None</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">num</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span> <span class="ow">and</span> <span class="n">num</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="kc">None</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="n">inp</span> <span class="o">=</span> <span class="n">inp</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">&quot;#&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">inp</span><span class="p">)</span> <span class="k">if</span> <span class="n">inp</span><span class="o">.</span><span class="n">isdigit</span><span class="p">()</span> <span class="ow">and</span> <span class="nb">int</span><span class="p">(</span><span class="n">inp</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="kc">None</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">inp</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span> <span class="k">else</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="dbref_to_obj"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.dbref_to_obj">[docs]</a><span class="k">def</span> <span class="nf">dbref_to_obj</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="n">objclass</span><span class="p">,</span> <span class="n">raise_errors</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Convert a #dbref to a valid object.</span>
<span class="sd"> Args:</span>
<span class="sd"> inp (str or int): A valid #dbref.</span>
<span class="sd"> objclass (class): A valid django model to filter against.</span>
<span class="sd"> raise_errors (bool, optional): Whether to raise errors</span>
<span class="sd"> or return `None` on errors.</span>
<span class="sd"> Returns:</span>
<span class="sd"> obj (Object or None): An entity loaded from the dbref.</span>
<span class="sd"> Raises:</span>
<span class="sd"> Exception: If `raise_errors` is `True` and</span>
<span class="sd"> `objclass.objects.get(id=dbref)` did not return a valid</span>
<span class="sd"> object.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">dbid</span> <span class="o">=</span> <span class="n">dbref</span><span class="p">(</span><span class="n">inp</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">dbid</span><span class="p">:</span>
<span class="c1"># we only convert #dbrefs</span>
<span class="k">return</span> <span class="n">inp</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">dbid</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="c1"># if we get to this point, inp is an integer dbref; get the matching object</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">objclass</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">dbid</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="k">if</span> <span class="n">raise_errors</span><span class="p">:</span>
<span class="k">raise</span>
<span class="k">return</span> <span class="n">inp</span></div>
<span class="c1"># legacy alias</span>
<span class="n">dbid_to_obj</span> <span class="o">=</span> <span class="n">dbref_to_obj</span>
<span class="c1"># some direct translations for the latinify</span>
<span class="n">_UNICODE_MAP</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;EM DASH&quot;</span><span class="p">:</span> <span class="s2">&quot;-&quot;</span><span class="p">,</span>
<span class="s2">&quot;FIGURE DASH&quot;</span><span class="p">:</span> <span class="s2">&quot;-&quot;</span><span class="p">,</span>
<span class="s2">&quot;EN DASH&quot;</span><span class="p">:</span> <span class="s2">&quot;-&quot;</span><span class="p">,</span>
<span class="s2">&quot;HORIZONTAL BAR&quot;</span><span class="p">:</span> <span class="s2">&quot;-&quot;</span><span class="p">,</span>
<span class="s2">&quot;HORIZONTAL ELLIPSIS&quot;</span><span class="p">:</span> <span class="s2">&quot;...&quot;</span><span class="p">,</span>
<span class="s2">&quot;LEFT SINGLE QUOTATION MARK&quot;</span><span class="p">:</span> <span class="s2">&quot;&#39;&quot;</span><span class="p">,</span>
<span class="s2">&quot;RIGHT SINGLE QUOTATION MARK&quot;</span><span class="p">:</span> <span class="s2">&quot;&#39;&quot;</span><span class="p">,</span>
<span class="s2">&quot;LEFT DOUBLE QUOTATION MARK&quot;</span><span class="p">:</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">,</span>
<span class="s2">&quot;RIGHT DOUBLE QUOTATION MARK&quot;</span><span class="p">:</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">,</span>
<span class="p">}</span>
<div class="viewcode-block" id="latinify"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.latinify">[docs]</a><span class="k">def</span> <span class="nf">latinify</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">&quot;?&quot;</span><span class="p">,</span> <span class="n">pure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Convert a unicode string to &quot;safe&quot; ascii/latin-1 characters.</span>
<span class="sd"> This is used as a last resort when normal encoding does not work.</span>
<span class="sd"> Arguments:</span>
<span class="sd"> string (str): A string to convert to &#39;safe characters&#39; convertible</span>
<span class="sd"> to an latin-1 bytestring later.</span>
<span class="sd"> default (str, optional): Characters resisting mapping will be replaced</span>
<span class="sd"> with this character or string. The intent is to apply an encode operation</span>
<span class="sd"> on the string soon after.</span>
<span class="sd"> Returns:</span>
<span class="sd"> string (str): A &#39;latinified&#39; string where each unicode character has been</span>
<span class="sd"> replaced with a &#39;safe&#39; equivalent available in the ascii/latin-1 charset.</span>
<span class="sd"> Notes:</span>
<span class="sd"> This is inspired by the gist by Ricardo Murri:</span>
<span class="sd"> https://gist.github.com/riccardomurri/3c3ccec30f037be174d3</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">unicodedata</span> <span class="kn">import</span> <span class="n">name</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf8&quot;</span><span class="p">)</span>
<span class="n">converted</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">unich</span> <span class="ow">in</span> <span class="nb">iter</span><span class="p">(</span><span class="n">string</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">ch</span> <span class="o">=</span> <span class="n">unich</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf8&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;ascii&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">UnicodeDecodeError</span><span class="p">:</span>
<span class="c1"># deduce a latin letter equivalent from the Unicode data</span>
<span class="c1"># point name; e.g., since `name(u&#39;á&#39;) == &#39;LATIN SMALL</span>
<span class="c1"># LETTER A WITH ACUTE&#39;` translate `á` to `a`. However, in</span>
<span class="c1"># some cases the unicode name is still &quot;LATIN LETTER&quot;</span>
<span class="c1"># although no direct equivalent in the Latin alphabet</span>
<span class="c1"># exists (e.g., Þ, &quot;LATIN CAPITAL LETTER THORN&quot;) -- we can</span>
<span class="c1"># avoid these cases by checking that the letter name is</span>
<span class="c1"># composed of one letter only.</span>
<span class="c1"># We also supply some direct-translations for some particular</span>
<span class="c1"># common cases.</span>
<span class="n">what</span> <span class="o">=</span> <span class="n">name</span><span class="p">(</span><span class="n">unich</span><span class="p">)</span>
<span class="k">if</span> <span class="n">what</span> <span class="ow">in</span> <span class="n">_UNICODE_MAP</span><span class="p">:</span>
<span class="n">ch</span> <span class="o">=</span> <span class="n">_UNICODE_MAP</span><span class="p">[</span><span class="n">what</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">what</span> <span class="o">=</span> <span class="n">what</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
<span class="k">if</span> <span class="n">what</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;LATIN&quot;</span> <span class="ow">and</span> <span class="n">what</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;LETTER&quot;</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">what</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">ch</span> <span class="o">=</span> <span class="n">what</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">if</span> <span class="n">what</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;SMALL&quot;</span> <span class="k">else</span> <span class="n">what</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">ch</span> <span class="o">=</span> <span class="n">default</span>
<span class="n">converted</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="n">ch</span><span class="p">)))</span>
<span class="k">return</span> <span class="s2">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">converted</span><span class="p">)</span></div>
<div class="viewcode-block" id="to_bytes"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.to_bytes">[docs]</a><span class="k">def</span> <span class="nf">to_bytes</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Try to encode the given text to bytes, using encodings from settings or from Session. Will</span>
<span class="sd"> always return a bytes, even if given something that is not str or bytes.</span>
<span class="sd"> Args:</span>
<span class="sd"> text (any): The text to encode to bytes. If bytes, return unchanged. If not a str, convert</span>
<span class="sd"> to str before converting.</span>
<span class="sd"> session (Session, optional): A Session to get encoding info from. Will try this before</span>
<span class="sd"> falling back to settings.ENCODINGS.</span>
<span class="sd"> Returns:</span>
<span class="sd"> encoded_text (bytes): the encoded text following the session&#39;s protocol flag followed by the</span>
<span class="sd"> encodings specified in settings.ENCODINGS. If all attempt fail, log the error and send</span>
<span class="sd"> the text with &quot;?&quot; in place of problematic characters. If the specified encoding cannot</span>
<span class="sd"> be found, the protocol flag is reset to utf-8. In any case, returns bytes.</span>
<span class="sd"> Notes:</span>
<span class="sd"> If `text` is already bytes, return it as is.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="k">return</span> <span class="n">text</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="c1"># convert to a str representation before encoding</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">text</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="n">text</span> <span class="o">=</span> <span class="nb">repr</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">default_encoding</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">protocol_flags</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;ENCODING&quot;</span><span class="p">,</span> <span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">session</span> <span class="k">else</span> <span class="s2">&quot;utf-8&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">default_encoding</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">LookupError</span><span class="p">,</span> <span class="ne">UnicodeEncodeError</span><span class="p">):</span>
<span class="k">for</span> <span class="n">encoding</span> <span class="ow">in</span> <span class="n">settings</span><span class="o">.</span><span class="n">ENCODINGS</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">encoding</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">LookupError</span><span class="p">,</span> <span class="ne">UnicodeEncodeError</span><span class="p">):</span>
<span class="k">pass</span>
<span class="c1"># no valid encoding found. Replace unconvertable parts with ?</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">default_encoding</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s2">&quot;replace&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="to_str"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.to_str">[docs]</a><span class="k">def</span> <span class="nf">to_str</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Try to decode a bytestream to a python str, using encoding schemas from settings</span>
<span class="sd"> or from Session. Will always return a str(), also if not given a str/bytes.</span>
<span class="sd"> Args:</span>
<span class="sd"> text (any): The text to encode to bytes. If a str, return it. If also not bytes, convert</span>
<span class="sd"> to str using str() or repr() as a fallback.</span>
<span class="sd"> session (Session, optional): A Session to get encoding info from. Will try this before</span>
<span class="sd"> falling back to settings.ENCODINGS.</span>
<span class="sd"> Returns:</span>
<span class="sd"> decoded_text (str): The decoded text.</span>
<span class="sd"> Notes:</span>
<span class="sd"> If `text` is already str, return it as is.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">return</span> <span class="n">text</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="c1"># not a byte, convert directly to str</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">repr</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">default_encoding</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">protocol_flags</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;ENCODING&quot;</span><span class="p">,</span> <span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">session</span> <span class="k">else</span> <span class="s2">&quot;utf-8&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">default_encoding</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">LookupError</span><span class="p">,</span> <span class="ne">UnicodeDecodeError</span><span class="p">):</span>
<span class="k">for</span> <span class="n">encoding</span> <span class="ow">in</span> <span class="n">settings</span><span class="o">.</span><span class="n">ENCODINGS</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">encoding</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">LookupError</span><span class="p">,</span> <span class="ne">UnicodeDecodeError</span><span class="p">):</span>
<span class="k">pass</span>
<span class="c1"># no valid encoding found. Replace unconvertable parts with ?</span>
<span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">default_encoding</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s2">&quot;replace&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="validate_email_address"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.validate_email_address">[docs]</a><span class="k">def</span> <span class="nf">validate_email_address</span><span class="p">(</span><span class="n">emailaddress</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Checks if an email address is syntactically correct. Makes use</span>
<span class="sd"> of the django email-validator for consistency.</span>
<span class="sd"> Args:</span>
<span class="sd"> emailaddress (str): Email address to validate.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: If this is a valid email or not.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">django_validate_email</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">emailaddress</span><span class="p">))</span>
<span class="k">except</span> <span class="n">DjangoValidationError</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">()</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span></div>
<div class="viewcode-block" id="inherits_from"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.inherits_from">[docs]</a><span class="k">def</span> <span class="nf">inherits_from</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">parent</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Takes an object and tries to determine if it inherits at *any*</span>
<span class="sd"> distance from parent.</span>
<span class="sd"> Args:</span>
<span class="sd"> obj (any): Object to analyze. This may be either an instance or</span>
<span class="sd"> a class.</span>
<span class="sd"> parent (any): Can be either an instance, a class or the python</span>
<span class="sd"> path to the class.</span>
<span class="sd"> Returns:</span>
<span class="sd"> inherits_from (bool): If `parent` is a parent to `obj` or not.</span>
<span class="sd"> Notes:</span>
<span class="sd"> What differentiates this function from Python&#39;s `isinstance()` is the</span>
<span class="sd"> flexibility in the types allowed for the object and parent being compared.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">callable</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
<span class="c1"># this is a class</span>
<span class="n">obj_paths</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">mod</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="n">mod</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span> <span class="k">for</span> <span class="n">mod</span> <span class="ow">in</span> <span class="n">obj</span><span class="o">.</span><span class="n">mro</span><span class="p">()]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">obj_paths</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">mod</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="n">mod</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span> <span class="k">for</span> <span class="n">mod</span> <span class="ow">in</span> <span class="n">obj</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="n">mro</span><span class="p">()]</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">parent</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="c1"># a given string path, for direct matching</span>
<span class="n">parent_path</span> <span class="o">=</span> <span class="n">parent</span>
<span class="k">elif</span> <span class="n">callable</span><span class="p">(</span><span class="n">parent</span><span class="p">):</span>
<span class="c1"># this is a class</span>
<span class="n">parent_path</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">parent</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="n">parent</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">parent_path</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">parent</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="n">parent</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">any</span><span class="p">(</span><span class="mi">1</span> <span class="k">for</span> <span class="n">obj_path</span> <span class="ow">in</span> <span class="n">obj_paths</span> <span class="k">if</span> <span class="n">obj_path</span> <span class="o">==</span> <span class="n">parent_path</span><span class="p">)</span></div>
<div class="viewcode-block" id="server_services"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.server_services">[docs]</a><span class="k">def</span> <span class="nf">server_services</span><span class="p">():</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Lists all services active on the Server. Observe that since</span>
<span class="sd"> services are launched in memory, this function will only return</span>
<span class="sd"> any results if called from inside the game.</span>
<span class="sd"> Returns:</span>
<span class="sd"> services (dict): A dict of available services.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">evennia.server.sessionhandler</span> <span class="kn">import</span> <span class="n">SESSIONS</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">SESSIONS</span><span class="p">,</span> <span class="s2">&quot;server&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">SESSIONS</span><span class="o">.</span><span class="n">server</span><span class="p">,</span> <span class="s2">&quot;services&quot;</span><span class="p">):</span>
<span class="n">server</span> <span class="o">=</span> <span class="n">SESSIONS</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">namedServices</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># This function must be called from inside the evennia process.</span>
<span class="n">server</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">del</span> <span class="n">SESSIONS</span>
<span class="k">return</span> <span class="n">server</span></div>
<div class="viewcode-block" id="uses_database"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.uses_database">[docs]</a><span class="k">def</span> <span class="nf">uses_database</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;sqlite3&quot;</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Checks if the game is currently using a given database. This is a</span>
<span class="sd"> shortcut to having to use the full backend name.</span>
<span class="sd"> Args:</span>
<span class="sd"> name (str): One of &#39;sqlite3&#39;, &#39;mysql&#39;, &#39;postgresql&#39; or &#39;oracle&#39;.</span>
<span class="sd"> Returns:</span>
<span class="sd"> uses (bool): If the given database is used or not.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">DATABASES</span><span class="p">[</span><span class="s2">&quot;default&quot;</span><span class="p">][</span><span class="s2">&quot;ENGINE&quot;</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">DATABASE_ENGINE</span>
<span class="k">return</span> <span class="n">engine</span> <span class="o">==</span> <span class="s2">&quot;django.db.backends.</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">name</span></div>
<div class="viewcode-block" id="delay"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.delay">[docs]</a><span class="k">def</span> <span class="nf">delay</span><span class="p">(</span><span class="n">timedelay</span><span class="p">,</span> <span class="n">callback</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="sd">&quot;&quot;&quot;</span>
<span class="sd"> Delay the calling of a callback (function).</span>
<span class="sd"> Args:</span>
<span class="sd"> timedelay (int or float): The delay in seconds.</span>
<span class="sd"> callback (callable): Will be called as `callback(*args, **kwargs)`</span>
<span class="sd"> after `timedelay` seconds.</span>
<span class="sd"> *args: Will be used as arguments to callback</span>
<span class="sd"> Keyword Args:</span>
<span class="sd"> persistent (bool, optional): If True the delay remains after a server restart.</span>
<span class="sd"> persistent is False by default.</span>
<span class="sd"> any (any): Will be used as keyword arguments to callback.</span>
<span class="sd"> Returns:</span>
<span class="sd"> task (TaskHandlerTask): An instance of a task.</span>
<span class="sd"> Refer to, evennia.scripts.taskhandler.TaskHandlerTask</span>
<span class="sd"> Notes:</span>
<span class="sd"> The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will</span>
<span class="sd"> be called for persistent or non-persistent tasks.</span>
<span class="sd"> If persistent is set to True, the callback, its arguments</span>
<span class="sd"> and other keyword arguments will be saved (serialized) in the database,</span>
<span class="sd"> assuming they can be. The callback will be executed even after</span>
<span class="sd"> a server restart/reload, taking into account the specified delay</span>
<span class="sd"> (and server down time).</span>
<span class="sd"> Keep in mind that persistent tasks arguments and callback should not</span>
<span class="sd"> use memory references.</span>
<span class="sd"> If persistent is set to True the delay function will return an int</span>
<span class="sd"> which is the task&#39;s id intended for use with TASK_HANDLER&#39;s do_task</span>
<span class="sd"> and remove methods.</span>
<span class="sd"> All persistent tasks whose time delays have passed will be called on server startup.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">global</span> <span class="n">_TASK_HANDLER</span>
<span class="k">if</span> <span class="n">_TASK_HANDLER</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">evennia.scripts.taskhandler</span> <span class="kn">import</span> <span class="n">TASK_HANDLER</span> <span class="k">as</span> <span class="n">_TASK_HANDLER</span>
<span class="k">return</span> <span class="n">_TASK_HANDLER</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">timedelay</span><span class="p">,</span> <span class="n">callback</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></div>
<div class="viewcode-block" id="repeat"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.repeat">[docs]</a><span class="k">def</span> <span class="nf">repeat</span><span class="p">(</span>
<span class="n">interval</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">store_key</span><span class="o">=</span><span class="kc">None</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="sd">&quot;&quot;&quot;</span>
<span class="sd"> Start a repeating task using the TickerHandler.</span>
<span class="sd"> Args:</span>
<span class="sd"> interval (int): How often to call callback.</span>
<span class="sd"> callback (callable): This will be called with `*args, **kwargs` every</span>
<span class="sd"> `interval` seconds. This must be possible to pickle regardless</span>
<span class="sd"> of if `persistent` is set or not!</span>
<span class="sd"> persistent (bool, optional): If ticker survives a server reload.</span>
<span class="sd"> idstring (str, optional): Separates multiple tickers. This is useful</span>
<span class="sd"> mainly if wanting to set up multiple repeats for the same</span>
<span class="sd"> interval/callback but with different args/kwargs.</span>
<span class="sd"> stop (bool, optional): If set, use the given parameters to _stop_ a running</span>
<span class="sd"> ticker instead of creating a new one.</span>
<span class="sd"> store_key (tuple, optional): This is only used in combination with `stop` and</span>
<span class="sd"> should be the return given from the original `repeat` call. If this</span>
<span class="sd"> is given, all other args except `stop` are ignored.</span>
<span class="sd"> *args: Used as arguments to `callback`.</span>
<span class="sd"> **kwargs: Keyword-arguments to pass to `callback`.</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple or None: The tuple is the `store_key` - the identifier for the</span>
<span class="sd"> created ticker. Store this and pass into unrepat() in order to to stop</span>
<span class="sd"> this ticker later. Returns `None` if `stop=True`.</span>
<span class="sd"> Raises:</span>
<span class="sd"> KeyError: If trying to stop a ticker that was not found.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">global</span> <span class="n">_TICKER_HANDLER</span>
<span class="k">if</span> <span class="n">_TICKER_HANDLER</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">evennia.scripts.tickerhandler</span> <span class="kn">import</span> <span class="n">TICKER_HANDLER</span> <span class="k">as</span> <span class="n">_TICKER_HANDLER</span>
<span class="k">if</span> <span class="n">stop</span><span class="p">:</span>
<span class="c1"># we pass all args, but only store_key matters if given</span>
<span class="n">_TICKER_HANDLER</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span>
<span class="n">interval</span><span class="o">=</span><span class="n">interval</span><span class="p">,</span>
<span class="n">callback</span><span class="o">=</span><span class="n">callback</span><span class="p">,</span>
<span class="n">idstring</span><span class="o">=</span><span class="n">idstring</span><span class="p">,</span>
<span class="n">persistent</span><span class="o">=</span><span class="n">persistent</span><span class="p">,</span>
<span class="n">store_key</span><span class="o">=</span><span class="n">store_key</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_TICKER_HANDLER</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
<span class="n">interval</span><span class="o">=</span><span class="n">interval</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="n">callback</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="n">idstring</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="n">persistent</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="unrepeat"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.unrepeat">[docs]</a><span class="k">def</span> <span class="nf">unrepeat</span><span class="p">(</span><span class="n">store_key</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is used to stop a ticker previously started with `repeat`.</span>
<span class="sd"> Args:</span>
<span class="sd"> store_key (tuple): This is the return from `repeat`, used to uniquely</span>
<span class="sd"> identify the ticker to stop. Without the store_key, the ticker</span>
<span class="sd"> must be stopped by passing its parameters to `TICKER_HANDLER.remove`</span>
<span class="sd"> directly.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if a ticker was stopped, False if not (for example because no</span>
<span class="sd"> matching ticker was found or it was already stopped).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">repeat</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">store_key</span><span class="o">=</span><span class="n">store_key</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span></div>
<span class="n">_PPOOL</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_PCMD</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_PROC_ERR</span> <span class="o">=</span> <span class="s2">&quot;A process has ended with a probable error condition: process ended by signal 9.&quot;</span>
<div class="viewcode-block" id="run_async"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.run_async">[docs]</a><span class="k">def</span> <span class="nf">run_async</span><span class="p">(</span><span class="n">to_execute</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="sd">&quot;&quot;&quot;</span>
<span class="sd"> Runs a function or executes a code snippet asynchronously.</span>
<span class="sd"> Args:</span>
<span class="sd"> to_execute (callable): If this is a callable, it will be</span>
<span class="sd"> executed with `*args` and non-reserved `**kwargs` as arguments.</span>
<span class="sd"> The callable will be executed using ProcPool, or in a thread</span>
<span class="sd"> if ProcPool is not available.</span>
<span class="sd"> Keyword Args:</span>
<span class="sd"> at_return (callable): Should point to a callable with one</span>
<span class="sd"> argument. It will be called with the return value from</span>
<span class="sd"> to_execute.</span>
<span class="sd"> at_return_kwargs (dict): This dictionary will be used as</span>
<span class="sd"> keyword arguments to the at_return callback.</span>
<span class="sd"> at_err (callable): This will be called with a Failure instance</span>
<span class="sd"> if there is an error in to_execute.</span>
<span class="sd"> at_err_kwargs (dict): This dictionary will be used as keyword</span>
<span class="sd"> arguments to the at_err errback.</span>
<span class="sd"> Notes:</span>
<span class="sd"> All other `*args` and `**kwargs` will be passed on to</span>
<span class="sd"> `to_execute`. Run_async will relay executed code to a thread</span>
<span class="sd"> or procpool.</span>
<span class="sd"> Use this function with restrain and only for features/commands</span>
<span class="sd"> that you know has no influence on the cause-and-effect order of your</span>
<span class="sd"> game (commands given after the async function might be executed before</span>
<span class="sd"> it has finished). Accessing the same property from different threads</span>
<span class="sd"> can lead to unpredicted behaviour if you are not careful (this is called a</span>
<span class="sd"> &quot;race condition&quot;).</span>
<span class="sd"> Also note that some databases, notably sqlite3, don&#39;t support access from</span>
<span class="sd"> multiple threads simultaneously, so if you do heavy database access from</span>
<span class="sd"> your `to_execute` under sqlite3 you will probably run very slow or even get</span>
<span class="sd"> tracebacks.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># handle special reserved input kwargs</span>
<span class="n">callback</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;at_return&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">errback</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;at_err&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">callback_kwargs</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;at_return_kwargs&quot;</span><span class="p">,</span> <span class="p">{})</span>
<span class="n">errback_kwargs</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;at_err_kwargs&quot;</span><span class="p">,</span> <span class="p">{})</span>
<span class="k">if</span> <span class="n">callable</span><span class="p">(</span><span class="n">to_execute</span><span class="p">):</span>
<span class="c1"># no process pool available, fall back to old deferToThread mechanism.</span>
<span class="n">deferred</span> <span class="o">=</span> <span class="n">threads</span><span class="o">.</span><span class="n">deferToThread</span><span class="p">(</span><span class="n">to_execute</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">else</span><span class="p">:</span>
<span class="c1"># no appropriate input for this server setup</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;&#39;</span><span class="si">%s</span><span class="s2">&#39; could not be handled by run_async&quot;</span> <span class="o">%</span> <span class="n">to_execute</span><span class="p">)</span>
<span class="c1"># attach callbacks</span>
<span class="k">if</span> <span class="n">callback</span><span class="p">:</span>
<span class="n">deferred</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">callback</span><span class="p">,</span> <span class="o">**</span><span class="n">callback_kwargs</span><span class="p">)</span>
<span class="n">deferred</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">errback</span><span class="p">,</span> <span class="o">**</span><span class="n">errback_kwargs</span><span class="p">)</span></div>
<div class="viewcode-block" id="check_evennia_dependencies"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.check_evennia_dependencies">[docs]</a><span class="k">def</span> <span class="nf">check_evennia_dependencies</span><span class="p">():</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Checks the versions of Evennia&#39;s dependencies including making</span>
<span class="sd"> some checks for runtime libraries.</span>
<span class="sd"> Returns:</span>
<span class="sd"> result (bool): `False` if a show-stopping version mismatch is</span>
<span class="sd"> found.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># check main dependencies</span>
<span class="kn">from</span> <span class="nn">evennia.server.evennia_launcher</span> <span class="kn">import</span> <span class="n">check_main_evennia_dependencies</span>
<span class="n">not_error</span> <span class="o">=</span> <span class="n">check_main_evennia_dependencies</span><span class="p">()</span>
<span class="n">errstring</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="c1"># South is no longer used ...</span>
<span class="k">if</span> <span class="s2">&quot;south&quot;</span> <span class="ow">in</span> <span class="n">settings</span><span class="o">.</span><span class="n">INSTALLED_APPS</span><span class="p">:</span>
<span class="n">errstring</span> <span class="o">+=</span> <span class="p">(</span>
<span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> ERROR: &#39;south&#39; found in settings.INSTALLED_APPS. &quot;</span>
<span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> South is no longer used. If this was added manually, remove it.&quot;</span>
<span class="p">)</span>
<span class="n">not_error</span> <span class="o">=</span> <span class="kc">False</span>
<span class="c1"># IRC support</span>
<span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">IRC_ENABLED</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="kn">import</span> <span class="nn">twisted.words</span>
<span class="n">twisted</span><span class="o">.</span><span class="n">words</span> <span class="c1"># set to avoid debug info about not-used import</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
<span class="n">errstring</span> <span class="o">+=</span> <span class="p">(</span>
<span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> ERROR: IRC is enabled, but twisted.words is not installed. Please install it.&quot;</span>
<span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> Linux Debian/Ubuntu users should install package &#39;python-twisted-words&#39;, &quot;</span>
<span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> others can get it from http://twistedmatrix.com/trac/wiki/TwistedWords.&quot;</span>
<span class="p">)</span>
<span class="n">not_error</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">errstring</span> <span class="o">=</span> <span class="n">errstring</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">if</span> <span class="n">errstring</span><span class="p">:</span>
<span class="n">mlen</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">errstring</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">))</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_err</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">%s</span><span class="se">\n</span><span class="si">%s</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="s2">&quot;-&quot;</span> <span class="o">*</span> <span class="n">mlen</span><span class="p">,</span> <span class="n">errstring</span><span class="p">,</span> <span class="s2">&quot;-&quot;</span> <span class="o">*</span> <span class="n">mlen</span><span class="p">))</span>
<span class="k">return</span> <span class="n">not_error</span></div>
<div class="viewcode-block" id="has_parent"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.has_parent">[docs]</a><span class="k">def</span> <span class="nf">has_parent</span><span class="p">(</span><span class="n">basepath</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Checks if `basepath` is somewhere in obj&#39;s parent tree.</span>
<span class="sd"> Args:</span>
<span class="sd"> basepath (str): Python dotpath to compare against obj path.</span>
<span class="sd"> obj (any): Object whose path is to be checked.</span>
<span class="sd"> Returns:</span>
<span class="sd"> has_parent (bool): If the check was successful or not.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">any</span><span class="p">(</span>
<span class="bp">cls</span>
<span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="n">obj</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="n">mro</span><span class="p">()</span>
<span class="k">if</span> <span class="n">basepath</span> <span class="o">==</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">TypeError</span><span class="p">,</span> <span class="ne">AttributeError</span><span class="p">):</span>
<span class="c1"># this can occur if we tried to store a class object, not an</span>
<span class="c1"># instance. Not sure if one should defend against this.</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="mod_import_from_path"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.mod_import_from_path">[docs]</a><span class="k">def</span> <span class="nf">mod_import_from_path</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Load a Python module at the specified path.</span>
<span class="sd"> Args:</span>
<span class="sd"> path (str): An absolute path to a Python module to load.</span>
<span class="sd"> Returns:</span>
<span class="sd"> (module or None): An imported module if the path was a valid</span>
<span class="sd"> Python module. Returns `None` if the import failed.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isabs</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
<span class="n">dirpath</span><span class="p">,</span> <span class="n">filename</span> <span class="o">=</span> <span class="n">path</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">sep</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">modname</span> <span class="o">=</span> <span class="n">filename</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">&quot;.py&quot;</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">importlib</span><span class="o">.</span><span class="n">machinery</span><span class="o">.</span><span class="n">SourceFileLoader</span><span class="p">(</span><span class="n">modname</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span><span class="o">.</span><span class="n">load_module</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">OSError</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Could not find module &#39;</span><span class="si">{</span><span class="n">modname</span><span class="si">}</span><span class="s2">&#39; (</span><span class="si">{</span><span class="n">modname</span><span class="si">}</span><span class="s2">.py) at path &#39;</span><span class="si">{</span><span class="n">dirpath</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="mod_import"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.mod_import">[docs]</a><span class="k">def</span> <span class="nf">mod_import</span><span class="p">(</span><span class="n">module</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A generic Python module loader.</span>
<span class="sd"> Args:</span>
<span class="sd"> module (str, module): This can be either a Python path</span>
<span class="sd"> (dot-notation like `evennia.objects.models`), an absolute path</span>
<span class="sd"> (e.g. `/home/eve/evennia/evennia/objects/models.py`) or an</span>
<span class="sd"> already imported module object (e.g. `models`)</span>
<span class="sd"> Returns:</span>
<span class="sd"> (module or None): An imported module. If the input argument was</span>
<span class="sd"> already a module, this is returned as-is, otherwise the path is</span>
<span class="sd"> parsed and imported. Returns `None` and logs error if import failed.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">module</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">types</span><span class="o">.</span><span class="n">ModuleType</span><span class="p">):</span>
<span class="c1"># if this is already a module, we are done</span>
<span class="k">return</span> <span class="n">module</span>
<span class="k">if</span> <span class="n">module</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;.py&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">module</span><span class="p">):</span>
<span class="k">return</span> <span class="n">mod_import_from_path</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="all_from_module"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.all_from_module">[docs]</a><span class="k">def</span> <span class="nf">all_from_module</span><span class="p">(</span><span class="n">module</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return all global-level variables defined in a module.</span>
<span class="sd"> Args:</span>
<span class="sd"> module (str, module): This can be either a Python path</span>
<span class="sd"> (dot-notation like `evennia.objects.models`), an absolute path</span>
<span class="sd"> (e.g. `/home/eve/evennia/evennia/objects.models.py`) or an</span>
<span class="sd"> already imported module object (e.g. `models`)</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: A dict of {variablename: variable} for all</span>
<span class="sd"> variables in the given module.</span>
<span class="sd"> Notes:</span>
<span class="sd"> Ignores modules and variable names starting with an underscore, as well</span>
<span class="sd"> as variables imported into the module from other modules.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">mod</span> <span class="o">=</span> <span class="n">mod_import</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">mod</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="c1"># make sure to only return variables actually defined in this</span>
<span class="c1"># module if available (try to avoid imports)</span>
<span class="n">members</span> <span class="o">=</span> <span class="n">getmembers</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">predicate</span><span class="o">=</span><span class="k">lambda</span> <span class="n">obj</span><span class="p">:</span> <span class="n">getmodule</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="ow">in</span> <span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="kc">None</span><span class="p">))</span>
<span class="k">return</span> <span class="nb">dict</span><span class="p">((</span><span class="n">key</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">members</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">key</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;_&quot;</span><span class="p">))</span></div>
<div class="viewcode-block" id="callables_from_module"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.callables_from_module">[docs]</a><span class="k">def</span> <span class="nf">callables_from_module</span><span class="p">(</span><span class="n">module</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return all global-level callables defined in a module.</span>
<span class="sd"> Args:</span>
<span class="sd"> module (str, module): A python-path to a module or an actual</span>
<span class="sd"> module object.</span>
<span class="sd"> Returns:</span>
<span class="sd"> callables (dict): A dict of {name: callable, ...} from the module.</span>
<span class="sd"> Notes:</span>
<span class="sd"> Will ignore callables whose names start with underscore &quot;_&quot;.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">mod</span> <span class="o">=</span> <span class="n">mod_import</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">mod</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="c1"># make sure to only return callables actually defined in this module (not imports)</span>
<span class="n">members</span> <span class="o">=</span> <span class="n">getmembers</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">predicate</span><span class="o">=</span><span class="k">lambda</span> <span class="n">obj</span><span class="p">:</span> <span class="n">callable</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="ow">and</span> <span class="n">getmodule</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">==</span> <span class="n">mod</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">dict</span><span class="p">((</span><span class="n">key</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">members</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">key</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;_&quot;</span><span class="p">))</span></div>
<div class="viewcode-block" id="variable_from_module"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.variable_from_module">[docs]</a><span class="k">def</span> <span class="nf">variable_from_module</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">variable</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Retrieve a variable or list of variables from a module. The</span>
<span class="sd"> variable(s) must be defined globally in the module. If no variable</span>
<span class="sd"> is given (or a list entry is `None`), all global variables are</span>
<span class="sd"> extracted from the module.</span>
<span class="sd"> Args:</span>
<span class="sd"> module (string or module): Python path, absolute path or a module.</span>
<span class="sd"> variable (string or iterable, optional): Single variable name or iterable</span>
<span class="sd"> of variable names to extract. If not given, all variables in</span>
<span class="sd"> the module will be returned.</span>
<span class="sd"> default (string, optional): Default value to use if a variable fails to</span>
<span class="sd"> be extracted. Ignored if `variable` is not given.</span>
<span class="sd"> Returns:</span>
<span class="sd"> variables (value or list): A single value or a list of values</span>
<span class="sd"> depending on if `variable` is given or not. Errors in lists</span>
<span class="sd"> are replaced by the `default` argument.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">module</span><span class="p">:</span>
<span class="k">return</span> <span class="n">default</span>
<span class="n">mod</span> <span class="o">=</span> <span class="n">mod_import</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">mod</span><span class="p">:</span>
<span class="k">return</span> <span class="n">default</span>
<span class="k">if</span> <span class="n">variable</span><span class="p">:</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">var</span> <span class="ow">in</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">variable</span><span class="p">):</span>
<span class="k">if</span> <span class="n">var</span><span class="p">:</span>
<span class="c1"># try to pick a named variable</span>
<span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">mod</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">default</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># get all</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">val</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">mod</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">key</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;_&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">ismodule</span><span class="p">(</span><span class="n">val</span><span class="p">))</span>
<span class="p">]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="n">result</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">result</span></div>
<div class="viewcode-block" id="string_from_module"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.string_from_module">[docs]</a><span class="k">def</span> <span class="nf">string_from_module</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">variable</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is a wrapper for `variable_from_module` that requires return</span>
<span class="sd"> value to be a string to pass. It&#39;s primarily used by login screen.</span>
<span class="sd"> Args:</span>
<span class="sd"> module (string or module): Python path, absolute path or a module.</span>
<span class="sd"> variable (string or iterable, optional): Single variable name or iterable</span>
<span class="sd"> of variable names to extract. If not given, all variables in</span>
<span class="sd"> the module will be returned.</span>
<span class="sd"> default (string, optional): Default value to use if a variable fails to</span>
<span class="sd"> be extracted. Ignored if `variable` is not given.</span>
<span class="sd"> Returns:</span>
<span class="sd"> variables (value or list): A single (string) value or a list of values</span>
<span class="sd"> depending on if `variable` is given or not. Errors in lists (such</span>
<span class="sd"> as the value not being a string) are replaced by the `default` argument.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">val</span> <span class="o">=</span> <span class="n">variable_from_module</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">variable</span><span class="o">=</span><span class="n">variable</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">default</span><span class="p">)</span>
<span class="k">if</span> <span class="n">val</span><span class="p">:</span>
<span class="k">if</span> <span class="n">variable</span><span class="p">:</span>
<span class="k">return</span> <span class="n">val</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">[</span><span class="n">v</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">str</span><span class="p">)]</span>
<span class="k">return</span> <span class="n">result</span> <span class="k">if</span> <span class="n">result</span> <span class="k">else</span> <span class="n">default</span>
<span class="k">return</span> <span class="n">default</span></div>
<div class="viewcode-block" id="random_string_from_module"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.random_string_from_module">[docs]</a><span class="k">def</span> <span class="nf">random_string_from_module</span><span class="p">(</span><span class="n">module</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Returns a random global string from a module.</span>
<span class="sd"> Args:</span>
<span class="sd"> module (string or module): Python path, absolute path or a module.</span>
<span class="sd"> Returns:</span>
<span class="sd"> random (string): A random stribg variable from `module`.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">string_from_module</span><span class="p">(</span><span class="n">module</span><span class="p">))</span></div>
<div class="viewcode-block" id="fuzzy_import_from_module"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.fuzzy_import_from_module">[docs]</a><span class="k">def</span> <span class="nf">fuzzy_import_from_module</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">variable</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">defaultpaths</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Import a variable based on a fuzzy path. First the literal</span>
<span class="sd"> `path` will be tried, then all given `defaultpaths` will be</span>
<span class="sd"> prepended to see a match is found.</span>
<span class="sd"> Args:</span>
<span class="sd"> path (str): Full or partial python path.</span>
<span class="sd"> variable (str): Name of variable to import from module.</span>
<span class="sd"> default (string, optional): Default value to use if a variable fails to</span>
<span class="sd"> be extracted. Ignored if `variable` is not given.</span>
<span class="sd"> defaultpaths (iterable, options): Python paths to attempt in order if</span>
<span class="sd"> importing directly from `path` doesn&#39;t work.</span>
<span class="sd"> Returns:</span>
<span class="sd"> value (any): The variable imported from the module, or `default`, if</span>
<span class="sd"> not found.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">paths</span> <span class="o">=</span> <span class="p">[</span><span class="n">path</span><span class="p">]</span> <span class="o">+</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">defaultpaths</span><span class="p">)</span>
<span class="k">for</span> <span class="n">modpath</span> <span class="ow">in</span> <span class="n">paths</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">mod</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">modpath</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ImportError</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">str</span><span class="p">(</span><span class="n">ex</span><span class="p">)</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;No module named </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">modpath</span><span class="p">):</span>
<span class="c1"># this means the module was found but it</span>
<span class="c1"># triggers an ImportError on import.</span>
<span class="k">raise</span> <span class="n">ex</span>
<span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">variable</span><span class="p">,</span> <span class="n">default</span><span class="p">)</span>
<span class="k">return</span> <span class="n">default</span></div>
<div class="viewcode-block" id="class_from_module"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.class_from_module">[docs]</a><span class="k">def</span> <span class="nf">class_from_module</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">defaultpaths</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return a class from a module, given the class&#39; full python path. This is</span>
<span class="sd"> primarily used to convert db_typeclass_path:s to classes.</span>
<span class="sd"> Args:</span>
<span class="sd"> path (str): Full Python dot-path to module.</span>
<span class="sd"> defaultpaths (iterable, optional): If a direct import from `path` fails,</span>
<span class="sd"> try subsequent imports by prepending those paths to `path`.</span>
<span class="sd"> fallback (str): If all other attempts fail, use this path as a fallback.</span>
<span class="sd"> This is intended as a last-resort. In the example of Evennia</span>
<span class="sd"> loading, this would be a path to a default parent class in the</span>
<span class="sd"> evennia repo itself.</span>
<span class="sd"> Returns:</span>
<span class="sd"> class (Class): An uninstantiated class recovered from path.</span>
<span class="sd"> Raises:</span>
<span class="sd"> ImportError: If all loading failed.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">cls</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">err</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">if</span> <span class="n">defaultpaths</span><span class="p">:</span>
<span class="n">paths</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">[</span><span class="n">path</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">dpath</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span> <span class="k">for</span> <span class="n">dpath</span> <span class="ow">in</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">defaultpaths</span><span class="p">)]</span>
<span class="k">if</span> <span class="n">defaultpaths</span>
<span class="k">else</span> <span class="p">[]</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">paths</span> <span class="o">=</span> <span class="p">[</span><span class="n">path</span><span class="p">]</span>
<span class="k">for</span> <span class="n">testpath</span> <span class="ow">in</span> <span class="n">paths</span><span class="p">:</span>
<span class="k">if</span> <span class="s2">&quot;.&quot;</span> <span class="ow">in</span> <span class="n">path</span><span class="p">:</span>
<span class="n">testpath</span><span class="p">,</span> <span class="n">clsname</span> <span class="o">=</span> <span class="n">testpath</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="s2">&quot;the path &#39;</span><span class="si">%s</span><span class="s2">&#39; is not on the form modulepath.Classname.&quot;</span> <span class="o">%</span> <span class="n">path</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">importlib</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">find_spec</span><span class="p">(</span><span class="n">testpath</span><span class="p">,</span> <span class="n">package</span><span class="o">=</span><span class="s2">&quot;evennia&quot;</span><span class="p">):</span>
<span class="k">continue</span>
<span class="k">except</span> <span class="ne">ModuleNotFoundError</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">mod</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">testpath</span><span class="p">,</span> <span class="n">package</span><span class="o">=</span><span class="s2">&quot;evennia&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ModuleNotFoundError</span><span class="p">:</span>
<span class="n">err</span> <span class="o">=</span> <span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">(</span><span class="mi">30</span><span class="p">)</span>
<span class="k">break</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">cls</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">clsname</span><span class="p">)</span>
<span class="k">break</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">trace</span><span class="p">())</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
<span class="c1"># AttributeError within the module, don&#39;t hide it</span>
<span class="n">err</span> <span class="o">=</span> <span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">(</span><span class="mi">30</span><span class="p">)</span>
<span class="k">break</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">cls</span><span class="p">:</span>
<span class="n">err</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Could not load typeclass &#39;</span><span class="si">{}</span><span class="s2">&#39;</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">path</span><span class="p">,</span> <span class="s2">&quot; with the following traceback:</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</span> <span class="n">err</span> <span class="k">if</span> <span class="n">err</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">defaultpaths</span><span class="p">:</span>
<span class="n">err</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Paths searched:</span><span class="se">\n</span><span class="s2"> </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">paths</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">err</span> <span class="o">+=</span> <span class="s2">&quot;.&quot;</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_err</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
<span class="k">if</span> <span class="n">fallback</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_warn</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Falling back to </span><span class="si">{</span><span class="n">fallback</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">class_from_module</span><span class="p">(</span><span class="n">fallback</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># even fallback fails</span>
<span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span></div>
<span class="c1"># alias</span>
<span class="n">object_from_module</span> <span class="o">=</span> <span class="n">class_from_module</span>
<div class="viewcode-block" id="init_new_account"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.init_new_account">[docs]</a><span class="k">def</span> <span class="nf">init_new_account</span><span class="p">(</span><span class="n">account</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Deprecated.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_dep</span><span class="p">(</span><span class="s2">&quot;evennia.utils.utils.init_new_account is DEPRECATED and should not be used.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="string_similarity"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.string_similarity">[docs]</a><span class="k">def</span> <span class="nf">string_similarity</span><span class="p">(</span><span class="n">string1</span><span class="p">,</span> <span class="n">string2</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This implements a &quot;cosine-similarity&quot; algorithm as described for example in</span>
<span class="sd"> *Proceedings of the 22nd International Conference on Computation</span>
<span class="sd"> Linguistics* (Coling 2008), pages 593-600, Manchester, August 2008.</span>
<span class="sd"> The measure-vectors used is simply a &quot;bag of words&quot; type histogram</span>
<span class="sd"> (but for letters).</span>
<span class="sd"> Args:</span>
<span class="sd"> string1 (str): String to compare (may contain any number of words).</span>
<span class="sd"> string2 (str): Second string to compare (any number of words).</span>
<span class="sd"> Returns:</span>
<span class="sd"> similarity (float): A value 0...1 rating how similar the two</span>
<span class="sd"> strings are.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">vocabulary</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">string1</span> <span class="o">+</span> <span class="n">string2</span><span class="p">))</span>
<span class="n">vec1</span> <span class="o">=</span> <span class="p">[</span><span class="n">string1</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">vocabulary</span><span class="p">]</span>
<span class="n">vec2</span> <span class="o">=</span> <span class="p">[</span><span class="n">string2</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">vocabulary</span><span class="p">]</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="n">vec1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">vec2</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">vocabulary</span><span class="p">))))</span> <span class="o">/</span> <span class="p">(</span>
<span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="n">v1</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">v1</span> <span class="ow">in</span> <span class="n">vec1</span><span class="p">))</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="n">v2</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">v2</span> <span class="ow">in</span> <span class="n">vec2</span><span class="p">))</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">ZeroDivisionError</span><span class="p">:</span>
<span class="c1"># can happen if empty-string cmdnames appear for some reason.</span>
<span class="c1"># This is a no-match.</span>
<span class="k">return</span> <span class="mi">0</span></div>
<div class="viewcode-block" id="string_suggestions"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.string_suggestions">[docs]</a><span class="k">def</span> <span class="nf">string_suggestions</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">vocabulary</span><span class="p">,</span> <span class="n">cutoff</span><span class="o">=</span><span class="mf">0.6</span><span class="p">,</span> <span class="n">maxnum</span><span class="o">=</span><span class="mi">3</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Given a `string` and a `vocabulary`, return a match or a list of</span>
<span class="sd"> suggestions based on string similarity.</span>
<span class="sd"> Args:</span>
<span class="sd"> string (str): A string to search for.</span>
<span class="sd"> vocabulary (iterable): A list of available strings.</span>
<span class="sd"> cutoff (int, 0-1): Limit the similarity matches (the higher</span>
<span class="sd"> the value, the more exact a match is required).</span>
<span class="sd"> maxnum (int): Maximum number of suggestions to return.</span>
<span class="sd"> Returns:</span>
<span class="sd"> suggestions (list): Suggestions from `vocabulary` with a</span>
<span class="sd"> similarity-rating that higher than or equal to `cutoff`.</span>
<span class="sd"> Could be empty if there are no matches.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[</span>
<span class="n">tup</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">for</span> <span class="n">tup</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span>
<span class="p">[(</span><span class="n">string_similarity</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">sugg</span><span class="p">),</span> <span class="n">sugg</span><span class="p">)</span> <span class="k">for</span> <span class="n">sugg</span> <span class="ow">in</span> <span class="n">vocabulary</span><span class="p">],</span>
<span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">tup</span><span class="p">:</span> <span class="n">tup</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
<span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">tup</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">cutoff</span>
<span class="p">][:</span><span class="n">maxnum</span><span class="p">]</span></div>
<div class="viewcode-block" id="string_partial_matching"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.string_partial_matching">[docs]</a><span class="k">def</span> <span class="nf">string_partial_matching</span><span class="p">(</span><span class="n">alternatives</span><span class="p">,</span> <span class="n">inp</span><span class="p">,</span> <span class="n">ret_index</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Partially matches a string based on a list of `alternatives`.</span>
<span class="sd"> Matching is made from the start of each subword in each</span>
<span class="sd"> alternative. Case is not important. So e.g. &quot;bi sh sw&quot; or just</span>
<span class="sd"> &quot;big&quot; or &quot;shiny&quot; or &quot;sw&quot; will match &quot;Big shiny sword&quot;. Scoring is</span>
<span class="sd"> done to allow to separate by most common denominator. You will get</span>
<span class="sd"> multiple matches returned if appropriate.</span>
<span class="sd"> Args:</span>
<span class="sd"> alternatives (list of str): A list of possible strings to</span>
<span class="sd"> match.</span>
<span class="sd"> inp (str): Search criterion.</span>
<span class="sd"> ret_index (bool, optional): Return list of indices (from alternatives</span>
<span class="sd"> array) instead of strings.</span>
<span class="sd"> Returns:</span>
<span class="sd"> matches (list): String-matches or indices if `ret_index` is `True`.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">alternatives</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">inp</span><span class="p">:</span>
<span class="k">return</span> <span class="p">[]</span>
<span class="n">matches</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
<span class="n">inp_words</span> <span class="o">=</span> <span class="n">inp</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
<span class="k">for</span> <span class="n">altindex</span><span class="p">,</span> <span class="n">alt</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">alternatives</span><span class="p">):</span>
<span class="n">alt_words</span> <span class="o">=</span> <span class="n">alt</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
<span class="n">last_index</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">score</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">inp_word</span> <span class="ow">in</span> <span class="n">inp_words</span><span class="p">:</span>
<span class="c1"># loop over parts, making sure only to visit each part once</span>
<span class="c1"># (this will invalidate input in the wrong word order)</span>
<span class="n">submatch</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">last_index</span> <span class="o">+</span> <span class="n">alt_num</span>
<span class="k">for</span> <span class="n">alt_num</span><span class="p">,</span> <span class="n">alt_word</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">alt_words</span><span class="p">[</span><span class="n">last_index</span><span class="p">:])</span>
<span class="k">if</span> <span class="n">alt_word</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">inp_word</span><span class="p">)</span>
<span class="p">]</span>
<span class="k">if</span> <span class="n">submatch</span><span class="p">:</span>
<span class="n">last_index</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">submatch</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
<span class="n">score</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">score</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">break</span>
<span class="k">if</span> <span class="n">score</span><span class="p">:</span>
<span class="k">if</span> <span class="n">ret_index</span><span class="p">:</span>
<span class="n">matches</span><span class="p">[</span><span class="n">score</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">altindex</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">matches</span><span class="p">[</span><span class="n">score</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">alt</span><span class="p">)</span>
<span class="k">if</span> <span class="n">matches</span><span class="p">:</span>
<span class="k">return</span> <span class="n">matches</span><span class="p">[</span><span class="nb">max</span><span class="p">(</span><span class="n">matches</span><span class="p">)]</span>
<span class="k">return</span> <span class="p">[]</span></div>
<div class="viewcode-block" id="format_table"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.format_table">[docs]</a><span class="k">def</span> <span class="nf">format_table</span><span class="p">(</span><span class="n">table</span><span class="p">,</span> <span class="n">extra_space</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Format a 2D array of strings into a multi-column table.</span>
<span class="sd"> Args:</span>
<span class="sd"> table (list): A list of lists to represent columns in the</span>
<span class="sd"> table: `[[val,val,val,...], [val,val,val,...], ...]`, where</span>
<span class="sd"> each val will be placed on a separate row in the</span>
<span class="sd"> column. All columns must have the same number of rows (some</span>
<span class="sd"> positions may be empty though).</span>
<span class="sd"> extra_space (int, optional): Sets how much *minimum* extra</span>
<span class="sd"> padding (in characters) should be left between columns.</span>
<span class="sd"> Returns:</span>
<span class="sd"> list: A list of lists representing the rows to print out one by one.</span>
<span class="sd"> Notes:</span>
<span class="sd"> The function formats the columns to be as wide as the widest member</span>
<span class="sd"> of each column.</span>
<span class="sd"> `evennia.utils.evtable` is more powerful than this, but this</span>
<span class="sd"> function can be useful when the number of columns and rows are</span>
<span class="sd"> unknown and must be calculated on the fly.</span>
<span class="sd"> Examples: ::</span>
<span class="sd"> ftable = format_table([[1,2,3], [4,5,6]])</span>
<span class="sd"> string = &quot;&quot;</span>
<span class="sd"> for ir, row in enumerate(ftable):</span>
<span class="sd"> if ir == 0:</span>
<span class="sd"> # make first row white</span>
<span class="sd"> string += &quot;\\n|w&quot; + &quot;&quot;.join(row) + &quot;|n&quot;</span>
<span class="sd"> else:</span>
<span class="sd"> string += &quot;\\n&quot; + &quot;&quot;.join(row)</span>
<span class="sd"> print(string)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">table</span><span class="p">:</span>
<span class="k">return</span> <span class="p">[[]]</span>
<span class="n">max_widths</span> <span class="o">=</span> <span class="p">[</span><span class="nb">max</span><span class="p">([</span><span class="nb">len</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">val</span><span class="p">))</span> <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">col</span><span class="p">])</span> <span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">table</span><span class="p">]</span>
<span class="n">ftable</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">irow</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">table</span><span class="p">[</span><span class="mi">0</span><span class="p">])):</span>
<span class="n">ftable</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="p">[</span>
<span class="nb">str</span><span class="p">(</span><span class="n">col</span><span class="p">[</span><span class="n">irow</span><span class="p">])</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="n">max_widths</span><span class="p">[</span><span class="n">icol</span><span class="p">])</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="n">extra_space</span>
<span class="k">for</span> <span class="n">icol</span><span class="p">,</span> <span class="n">col</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">table</span><span class="p">)</span>
<span class="p">]</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">ftable</span></div>
<div class="viewcode-block" id="percent"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.percent">[docs]</a><span class="k">def</span> <span class="nf">percent</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">minval</span><span class="p">,</span> <span class="n">maxval</span><span class="p">,</span> <span class="n">formatting</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{:3.1f}</span><span class="s2">%&quot;</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get a value in an interval as a percentage of its position</span>
<span class="sd"> in that interval. This also understands negative numbers.</span>
<span class="sd"> Args:</span>
<span class="sd"> value (number): This should be a value minval&lt;=value&lt;=maxval.</span>
<span class="sd"> minval (number or None): Smallest value in interval. This could be None</span>
<span class="sd"> for an open interval (then return will always be 100%)</span>
<span class="sd"> maxval (number or None): Biggest value in interval. This could be None</span>
<span class="sd"> for an open interval (then return will always be 100%)</span>
<span class="sd"> formatted (str, optional): This is a string that should</span>
<span class="sd"> accept one formatting tag. This will receive the</span>
<span class="sd"> current value as a percentage. If None, the</span>
<span class="sd"> raw float will be returned instead.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str or float: The formatted value or the raw percentage as a float.</span>
<span class="sd"> Notes:</span>
<span class="sd"> We try to handle a weird interval gracefully.</span>
<span class="sd"> - If either maxval or minval is None (open interval), we (aribtrarily) assume 100%.</span>
<span class="sd"> - If minval &gt; maxval, we return 0%.</span>
<span class="sd"> - If minval == maxval == value we are looking at a single value match and return 100%.</span>
<span class="sd"> - If minval == maxval != value we return 0%.</span>
<span class="sd"> - If value not in [minval..maxval], we set value to the closest</span>
<span class="sd"> boundary, so the result will be 0% or 100%, respectively.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">result</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="kc">None</span> <span class="ow">in</span> <span class="p">(</span><span class="n">minval</span><span class="p">,</span> <span class="n">maxval</span><span class="p">):</span>
<span class="c1"># we have no boundaries, percent calculation makes no sense,</span>
<span class="c1"># we set this to 100% since it</span>
<span class="n">result</span> <span class="o">=</span> <span class="mf">100.0</span>
<span class="k">elif</span> <span class="n">minval</span> <span class="o">&gt;</span> <span class="n">maxval</span><span class="p">:</span>
<span class="c1"># interval has no width so we cannot</span>
<span class="c1"># occupy any position within it.</span>
<span class="n">result</span> <span class="o">=</span> <span class="mf">0.0</span>
<span class="k">elif</span> <span class="n">minval</span> <span class="o">==</span> <span class="n">maxval</span> <span class="o">==</span> <span class="n">value</span><span class="p">:</span>
<span class="c1"># this is a single value that we match</span>
<span class="n">result</span> <span class="o">=</span> <span class="mf">100.0</span>
<span class="k">elif</span> <span class="n">minval</span> <span class="o">==</span> <span class="n">maxval</span> <span class="o">!=</span> <span class="n">value</span><span class="p">:</span>
<span class="c1"># interval has no width so we cannot be in it.</span>
<span class="n">result</span> <span class="o">=</span> <span class="mf">0.0</span>
<span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># constrain value to interval</span>
<span class="n">value</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="n">minval</span><span class="p">,</span> <span class="n">value</span><span class="p">),</span> <span class="n">maxval</span><span class="p">)</span>
<span class="c1"># these should both be &gt;0</span>
<span class="n">dpart</span> <span class="o">=</span> <span class="n">value</span> <span class="o">-</span> <span class="n">minval</span>
<span class="n">dfull</span> <span class="o">=</span> <span class="n">maxval</span> <span class="o">-</span> <span class="n">minval</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="n">dpart</span> <span class="o">/</span> <span class="n">dfull</span><span class="p">)</span> <span class="o">*</span> <span class="mf">100.0</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">formatting</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">return</span> <span class="n">formatting</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="k">return</span> <span class="n">result</span></div>
<span class="kn">import</span> <span class="nn">functools</span> <span class="c1"># noqa</span>
<div class="viewcode-block" id="percentile"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.percentile">[docs]</a><span class="k">def</span> <span class="nf">percentile</span><span class="p">(</span><span class="n">iterable</span><span class="p">,</span> <span class="n">percent</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Find the percentile of a list of values.</span>
<span class="sd"> Args:</span>
<span class="sd"> iterable (iterable): A list of values. Note N MUST BE already sorted.</span>
<span class="sd"> percent (float): A value from 0.0 to 1.0.</span>
<span class="sd"> key (callable, optional). Function to compute value from each element of N.</span>
<span class="sd"> Returns:</span>
<span class="sd"> float: The percentile of the values</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">iterable</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="n">k</span> <span class="o">=</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">iterable</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">percent</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">floor</span><span class="p">(</span><span class="n">k</span><span class="p">)</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">ceil</span><span class="p">(</span><span class="n">k</span><span class="p">)</span>
<span class="k">if</span> <span class="n">f</span> <span class="o">==</span> <span class="n">c</span><span class="p">:</span>
<span class="k">return</span> <span class="n">key</span><span class="p">(</span><span class="n">iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">k</span><span class="p">)])</span>
<span class="n">d0</span> <span class="o">=</span> <span class="n">key</span><span class="p">(</span><span class="n">iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">f</span><span class="p">)])</span> <span class="o">*</span> <span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="n">k</span><span class="p">)</span>
<span class="n">d1</span> <span class="o">=</span> <span class="n">key</span><span class="p">(</span><span class="n">iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">c</span><span class="p">)])</span> <span class="o">*</span> <span class="p">(</span><span class="n">k</span> <span class="o">-</span> <span class="n">f</span><span class="p">)</span>
<span class="k">return</span> <span class="n">d0</span> <span class="o">+</span> <span class="n">d1</span></div>
<div class="viewcode-block" id="format_grid"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.format_grid">[docs]</a><span class="k">def</span> <span class="nf">format_grid</span><span class="p">(</span><span class="n">elements</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mi">78</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot; &quot;</span><span class="p">,</span> <span class="n">verbatim_elements</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">line_prefix</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This helper function makes a &#39;grid&#39; output, where it distributes the given</span>
<span class="sd"> string-elements as evenly as possible to fill out the given width.</span>
<span class="sd"> will not work well if the variation of length is very big!</span>
<span class="sd"> Args:</span>
<span class="sd"> elements (iterable): A 1D list of string elements to put in the grid.</span>
<span class="sd"> width (int, optional): The width of the grid area to fill.</span>
<span class="sd"> sep (str, optional): The extra separator to put between words. If</span>
<span class="sd"> set to the empty string, words may run into each other.</span>
<span class="sd"> verbatim_elements (list, optional): This is a list of indices pointing to</span>
<span class="sd"> specific items in the `elements` list. An element at this index will</span>
<span class="sd"> not be included in the calculation of the slot sizes. It will still</span>
<span class="sd"> be inserted into the grid at the correct position and may be surrounded</span>
<span class="sd"> by padding unless filling the entire line. This is useful for embedding</span>
<span class="sd"> decorations in the grid, such as horizontal bars.</span>
<span class="sd"> ignore_ansi (bool, optional): Ignore ansi markups when calculating white spacing.</span>
<span class="sd"> line_prefix (str, optional): A prefix to add at the beginning of each line.</span>
<span class="sd"> This can e.g. be used to preserve line color across line breaks.</span>
<span class="sd"> Returns:</span>
<span class="sd"> list: The grid as a list of ready-formatted rows. We return it</span>
<span class="sd"> like this to make it easier to insert decorations between rows, such</span>
<span class="sd"> as horizontal bars.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">_minimal_rows</span><span class="p">(</span><span class="n">elements</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Minimalistic distribution with minimal spacing, good for single-line</span>
<span class="sd"> grids but will look messy over many lines.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">rows</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;&quot;</span><span class="p">]</span>
<span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">elements</span><span class="p">:</span>
<span class="n">rowlen</span> <span class="o">=</span> <span class="n">display_len</span><span class="p">((</span><span class="n">rows</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span>
<span class="n">elen</span> <span class="o">=</span> <span class="n">display_len</span><span class="p">((</span><span class="n">element</span><span class="p">))</span>
<span class="k">if</span> <span class="n">rowlen</span> <span class="o">+</span> <span class="n">elen</span> <span class="o">&lt;=</span> <span class="n">width</span><span class="p">:</span>
<span class="n">rows</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">element</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>
<span class="k">return</span> <span class="n">rows</span>
<span class="k">def</span> <span class="nf">_weighted_rows</span><span class="p">(</span><span class="n">elements</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Dynamic-space, good for making even columns in a multi-line grid but</span>
<span class="sd"> will look strange for a single line.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">wls</span> <span class="o">=</span> <span class="p">[</span><span class="n">display_len</span><span class="p">((</span><span class="n">elem</span><span class="p">))</span> <span class="k">for</span> <span class="n">elem</span> <span class="ow">in</span> <span class="n">elements</span><span class="p">]</span>
<span class="n">wls_percentile</span> <span class="o">=</span> <span class="p">[</span><span class="n">wl</span> <span class="k">for</span> <span class="n">iw</span><span class="p">,</span> <span class="n">wl</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">wls</span><span class="p">)</span> <span class="k">if</span> <span class="n">iw</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">verbatim_elements</span><span class="p">]</span>
<span class="k">if</span> <span class="n">wls_percentile</span><span class="p">:</span>
<span class="c1"># get the nth percentile as a good representation of average width</span>
<span class="n">averlen</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">percentile</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">wls_percentile</span><span class="p">),</span> <span class="mf">0.9</span><span class="p">))</span> <span class="o">+</span> <span class="mi">2</span> <span class="c1"># include extra space</span>
<span class="n">aver_per_row</span> <span class="o">=</span> <span class="n">width</span> <span class="o">//</span> <span class="n">averlen</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># no adjustable rows, just keep all as-is</span>
<span class="n">aver_per_row</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">aver_per_row</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="c1"># one line per row, output directly since this is trivial</span>
<span class="c1"># we use rstrip here to remove extra spaces added by sep</span>
<span class="k">return</span> <span class="p">[</span>
<span class="n">crop</span><span class="p">(</span><span class="n">element</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(),</span> <span class="n">width</span><span class="p">)</span>
<span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">width</span> <span class="o">-</span> <span class="n">display_len</span><span class="p">((</span><span class="n">element</span><span class="o">.</span><span class="n">rstrip</span><span class="p">())))</span>
<span class="k">for</span> <span class="n">iel</span><span class="p">,</span> <span class="n">element</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">elements</span><span class="p">)</span>
<span class="p">]</span>
<span class="n">indices</span> <span class="o">=</span> <span class="p">[</span><span class="n">averlen</span> <span class="o">*</span> <span class="n">ind</span> <span class="k">for</span> <span class="n">ind</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">aver_per_row</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)]</span>
<span class="n">rows</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">ic</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">row</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">ie</span><span class="p">,</span> <span class="n">element</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">elements</span><span class="p">):</span>
<span class="n">wl</span> <span class="o">=</span> <span class="n">wls</span><span class="p">[</span><span class="n">ie</span><span class="p">]</span>
<span class="n">lrow</span> <span class="o">=</span> <span class="n">display_len</span><span class="p">((</span><span class="n">row</span><span class="p">))</span>
<span class="c1"># debug = row.replace(&quot; &quot;, &quot;.&quot;)</span>
<span class="k">if</span> <span class="n">lrow</span> <span class="o">+</span> <span class="n">wl</span> <span class="o">&gt;</span> <span class="n">width</span><span class="p">:</span>
<span class="c1"># this slot extends outside grid, move to next line</span>
<span class="n">row</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="p">(</span><span class="n">width</span> <span class="o">-</span> <span class="n">lrow</span><span class="p">)</span>
<span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
<span class="k">if</span> <span class="n">wl</span> <span class="o">&gt;=</span> <span class="n">width</span><span class="p">:</span>
<span class="c1"># remove sep if this fills the entire line</span>
<span class="n">element</span> <span class="o">=</span> <span class="n">element</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span>
<span class="n">row</span> <span class="o">=</span> <span class="n">crop</span><span class="p">(</span><span class="n">element</span><span class="p">,</span> <span class="n">width</span><span class="p">)</span>
<span class="n">ic</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">elif</span> <span class="n">ic</span> <span class="o">&gt;=</span> <span class="n">aver_per_row</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
<span class="c1"># no more slots available on this line</span>
<span class="n">row</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">(</span><span class="n">width</span> <span class="o">-</span> <span class="n">lrow</span><span class="p">))</span>
<span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
<span class="n">row</span> <span class="o">=</span> <span class="n">crop</span><span class="p">(</span><span class="n">element</span><span class="p">,</span> <span class="n">width</span><span class="p">)</span>
<span class="n">ic</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">while</span> <span class="n">lrow</span> <span class="o">&gt;</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">indices</span><span class="p">[</span><span class="n">ic</span><span class="p">]):</span>
<span class="c1"># slot too wide, extend into adjacent slot</span>
<span class="n">ic</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">row</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">indices</span><span class="p">[</span><span class="n">ic</span><span class="p">]</span> <span class="o">-</span> <span class="n">lrow</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">IndexError</span><span class="p">:</span>
<span class="c1"># we extended past edge of grid, crop or move to next line</span>
<span class="k">if</span> <span class="n">ic</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">row</span> <span class="o">=</span> <span class="n">crop</span><span class="p">(</span><span class="n">element</span><span class="p">,</span> <span class="n">width</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">row</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">width</span> <span class="o">-</span> <span class="n">lrow</span><span class="p">)</span>
<span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
<span class="n">row</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="n">ic</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># add a new slot</span>
<span class="n">row</span> <span class="o">+=</span> <span class="n">element</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">averlen</span> <span class="o">-</span> <span class="n">wl</span><span class="p">)</span>
<span class="n">ic</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">ie</span> <span class="o">&gt;=</span> <span class="n">nelements</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
<span class="c1"># last element, make sure to store</span>
<span class="n">row</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">width</span> <span class="o">-</span> <span class="n">display_len</span><span class="p">((</span><span class="n">row</span><span class="p">)))</span>
<span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
<span class="k">return</span> <span class="n">rows</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">elements</span><span class="p">:</span>
<span class="k">return</span> <span class="p">[]</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">verbatim_elements</span><span class="p">:</span>
<span class="n">verbatim_elements</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">nelements</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">elements</span><span class="p">)</span>
<span class="c1"># add sep to all but the very last element</span>
<span class="n">elements</span> <span class="o">=</span> <span class="p">[</span><span class="n">elements</span><span class="p">[</span><span class="n">ie</span><span class="p">]</span> <span class="o">+</span> <span class="n">sep</span> <span class="k">for</span> <span class="n">ie</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">nelements</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)]</span> <span class="o">+</span> <span class="p">[</span><span class="n">elements</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]]</span>
<span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="n">display_len</span><span class="p">((</span><span class="n">element</span><span class="p">))</span> <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">elements</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">width</span><span class="p">:</span>
<span class="c1"># grid fits in one line</span>
<span class="n">rows</span> <span class="o">=</span> <span class="n">_minimal_rows</span><span class="p">(</span><span class="n">elements</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># full multi-line grid</span>
<span class="n">rows</span> <span class="o">=</span> <span class="n">_weighted_rows</span><span class="p">(</span><span class="n">elements</span><span class="p">)</span>
<span class="k">if</span> <span class="n">line_prefix</span><span class="p">:</span>
<span class="k">return</span> <span class="p">[</span><span class="n">line_prefix</span> <span class="o">+</span> <span class="n">row</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">]</span>
<span class="k">return</span> <span class="n">rows</span></div>
<div class="viewcode-block" id="get_evennia_pids"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.get_evennia_pids">[docs]</a><span class="k">def</span> <span class="nf">get_evennia_pids</span><span class="p">():</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get the currently valid PIDs (Process IDs) of the Portal and</span>
<span class="sd"> Server by trying to access a PID file.</span>
<span class="sd"> Returns:</span>
<span class="sd"> server, portal (tuple): The PIDs of the respective processes,</span>
<span class="sd"> or two `None` values if not found.</span>
<span class="sd"> Examples:</span>
<span class="sd"> This can be used to determine if we are in a subprocess by</span>
<span class="sd"> ```python</span>
<span class="sd"> self_pid = os.getpid()</span>
<span class="sd"> server_pid, portal_pid = get_evennia_pids()</span>
<span class="sd"> is_subprocess = self_pid not in (server_pid, portal_pid)</span>
<span class="sd"> ```</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">server_pidfile</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">GAME_DIR</span><span class="p">,</span> <span class="s2">&quot;server.pid&quot;</span><span class="p">)</span>
<span class="n">portal_pidfile</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">GAME_DIR</span><span class="p">,</span> <span class="s2">&quot;portal.pid&quot;</span><span class="p">)</span>
<span class="n">server_pid</span><span class="p">,</span> <span class="n">portal_pid</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">server_pidfile</span><span class="p">):</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">server_pidfile</span><span class="p">,</span> <span class="s2">&quot;r&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">server_pid</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">portal_pidfile</span><span class="p">):</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">portal_pidfile</span><span class="p">,</span> <span class="s2">&quot;r&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">portal_pid</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">if</span> <span class="n">server_pid</span> <span class="ow">and</span> <span class="n">portal_pid</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">server_pid</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">portal_pid</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="deepsize"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.deepsize">[docs]</a><span class="k">def</span> <span class="nf">deepsize</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">max_depth</span><span class="o">=</span><span class="mi">4</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get not only size of the given object, but also the size of</span>
<span class="sd"> objects referenced by the object, down to `max_depth` distance</span>
<span class="sd"> from the object.</span>
<span class="sd"> Args:</span>
<span class="sd"> obj (object): the object to be measured.</span>
<span class="sd"> max_depth (int, optional): maximum referential distance</span>
<span class="sd"> from `obj` that `deepsize()` should cover for</span>
<span class="sd"> measuring objects referenced by `obj`.</span>
<span class="sd"> Returns:</span>
<span class="sd"> size (int): deepsize of `obj` in Bytes.</span>
<span class="sd"> Notes:</span>
<span class="sd"> This measure is necessarily approximate since some</span>
<span class="sd"> memory is shared between objects. The `max_depth` of 4 is roughly</span>
<span class="sd"> tested to give reasonable size information about database models</span>
<span class="sd"> and their handlers.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">_recurse</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="n">dct</span><span class="p">,</span> <span class="n">depth</span><span class="p">):</span>
<span class="k">if</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">max_depth</span> <span class="o">&lt;</span> <span class="n">depth</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">for</span> <span class="n">ref</span> <span class="ow">in</span> <span class="n">gc</span><span class="o">.</span><span class="n">get_referents</span><span class="p">(</span><span class="n">o</span><span class="p">):</span>
<span class="n">idr</span> <span class="o">=</span> <span class="nb">id</span><span class="p">(</span><span class="n">ref</span><span class="p">)</span>
<span class="k">if</span> <span class="n">idr</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">dct</span><span class="p">:</span>
<span class="n">dct</span><span class="p">[</span><span class="n">idr</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">ref</span><span class="p">,</span> <span class="n">sys</span><span class="o">.</span><span class="n">getsizeof</span><span class="p">(</span><span class="n">ref</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span>
<span class="n">_recurse</span><span class="p">(</span><span class="n">ref</span><span class="p">,</span> <span class="n">dct</span><span class="p">,</span> <span class="n">depth</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">sizedict</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">_recurse</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">sizedict</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">size</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">getsizeof</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">+</span> <span class="nb">sum</span><span class="p">([</span><span class="n">p</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">sizedict</span><span class="o">.</span><span class="n">values</span><span class="p">()])</span>
<span class="k">return</span> <span class="n">size</span></div>
<span class="c1"># lazy load handler</span>
<span class="n">_missing</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span>
<div class="viewcode-block" id="lazy_property"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.lazy_property">[docs]</a><span class="k">class</span> <span class="nc">lazy_property</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Delays loading of property until first access. Credit goes to the</span>
<span class="sd"> Implementation in the werkzeug suite:</span>
<span class="sd"> http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.cached_property</span>
<span class="sd"> This should be used as a decorator in a class and in Evennia is</span>
<span class="sd"> mainly used to lazy-load handlers:</span>
<span class="sd"> ```python</span>
<span class="sd"> @lazy_property</span>
<span class="sd"> def attributes(self):</span>
<span class="sd"> return AttributeHandler(self)</span>
<span class="sd"> ```</span>
<span class="sd"> Once initialized, the `AttributeHandler` will be available as a</span>
<span class="sd"> property &quot;attributes&quot; on the object. This is read-only since</span>
<span class="sd"> this functionality is pretty much exclusively used by handlers.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="lazy_property.__init__"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.lazy_property.__init__">[docs]</a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Store all properties for now&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">=</span> <span class="n">name</span> <span class="ow">or</span> <span class="n">func</span><span class="o">.</span><span class="vm">__name__</span>
<span class="bp">self</span><span class="o">.</span><span class="vm">__module__</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="vm">__module__</span>
<span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span> <span class="o">=</span> <span class="n">doc</span> <span class="ow">or</span> <span class="n">func</span><span class="o">.</span><span class="vm">__doc__</span>
<span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span></div>
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Triggers initialization&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">_missing</span><span class="p">)</span>
<span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="n">_missing</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="n">obj</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="vm">__name__</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">return</span> <span class="n">value</span>
<span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Protect against setting&quot;&quot;&quot;</span>
<span class="n">handlername</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__name__</span>
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span>
<span class="s2">&quot;</span><span class="si">{obj}</span><span class="s2">.</span><span class="si">{handlername}</span><span class="s2"> is a handler and can&#39;t be set directly. &quot;</span>
<span class="s2">&quot;To add values, use `</span><span class="si">{obj}</span><span class="s2">.</span><span class="si">{handlername}</span><span class="s2">.add()` instead.&quot;</span>
<span class="p">)</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">obj</span><span class="p">,</span> <span class="n">handlername</span><span class="o">=</span><span class="n">handlername</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">def</span> <span class="fm">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Protect against deleting&quot;&quot;&quot;</span>
<span class="n">handlername</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__name__</span>
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span>
<span class="s2">&quot;</span><span class="si">{obj}</span><span class="s2">.</span><span class="si">{handlername}</span><span class="s2"> is a handler and can&#39;t be deleted directly. &quot;</span>
<span class="s2">&quot;To remove values, use `</span><span class="si">{obj}</span><span class="s2">.</span><span class="si">{handlername}</span><span class="s2">.remove()` instead.&quot;</span>
<span class="p">)</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">obj</span><span class="p">,</span> <span class="n">handlername</span><span class="o">=</span><span class="n">handlername</span><span class="p">)</span>
<span class="p">)</span></div>
<span class="n">_STRIP_ANSI</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_RE_CONTROL_CHAR</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span>
<span class="s2">&quot;[</span><span class="si">%s</span><span class="s2">]&quot;</span> <span class="o">%</span> <span class="n">re</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">32</span><span class="p">)]))</span>
<span class="p">)</span> <span class="c1"># + range(127,160)])))</span>
<div class="viewcode-block" id="strip_control_sequences"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.strip_control_sequences">[docs]</a><span class="k">def</span> <span class="nf">strip_control_sequences</span><span class="p">(</span><span class="n">string</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Remove non-print text sequences.</span>
<span class="sd"> Args:</span>
<span class="sd"> string (str): Text to strip.</span>
<span class="sd"> Returns.</span>
<span class="sd"> text (str): Stripped text.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">global</span> <span class="n">_STRIP_ANSI</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_STRIP_ANSI</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">evennia.utils.ansi</span> <span class="kn">import</span> <span class="n">strip_raw_ansi</span> <span class="k">as</span> <span class="n">_STRIP_ANSI</span>
<span class="k">return</span> <span class="n">_RE_CONTROL_CHAR</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">_STRIP_ANSI</span><span class="p">(</span><span class="n">string</span><span class="p">))</span></div>
<div class="viewcode-block" id="calledby"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.calledby">[docs]</a><span class="k">def</span> <span class="nf">calledby</span><span class="p">(</span><span class="n">callerdepth</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Only to be used for debug purposes. Insert this debug function in</span>
<span class="sd"> another function; it will print which function called it.</span>
<span class="sd"> Args:</span>
<span class="sd"> callerdepth (int): Must be larger than 0. When &gt; 1, it will</span>
<span class="sd"> print the caller of the caller etc.</span>
<span class="sd"> Returns:</span>
<span class="sd"> calledby (str): A debug string detailing which routine called</span>
<span class="sd"> us.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">inspect</span>
<span class="n">stack</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">stack</span><span class="p">()</span>
<span class="c1"># we must step one extra level back in stack since we don&#39;t want</span>
<span class="c1"># to include the call of this function itself.</span>
<span class="n">callerdepth</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">callerdepth</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">stack</span><span class="p">()[</span><span class="n">callerdepth</span><span class="p">]</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">sep</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">frame</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">sep</span><span class="p">,</span> <span class="mi">2</span><span class="p">)[</span><span class="o">-</span><span class="mi">2</span><span class="p">:])</span>
<span class="k">return</span> <span class="s2">&quot;[called by &#39;</span><span class="si">%s</span><span class="s2">&#39;: </span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">]&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">frame</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">path</span><span class="p">,</span> <span class="n">frame</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">frame</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span></div>
<div class="viewcode-block" id="m_len"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.m_len">[docs]</a><span class="k">def</span> <span class="nf">m_len</span><span class="p">(</span><span class="n">target</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Provides length checking for strings with MXP patterns, and falls</span>
<span class="sd"> back to normal len for other objects.</span>
<span class="sd"> Args:</span>
<span class="sd"> target (str): A string with potential MXP components</span>
<span class="sd"> to search.</span>
<span class="sd"> Returns:</span>
<span class="sd"> length (int): The length of `target`, ignoring MXP components.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Would create circular import if in module root.</span>
<span class="kn">from</span> <span class="nn">evennia.utils.ansi</span> <span class="kn">import</span> <span class="n">ANSI_PARSER</span>
<span class="k">if</span> <span class="n">inherits_from</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="ow">and</span> <span class="s2">&quot;|lt&quot;</span> <span class="ow">in</span> <span class="n">target</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">ANSI_PARSER</span><span class="o">.</span><span class="n">strip_mxp</span><span class="p">(</span><span class="n">target</span><span class="p">))</span>
<span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">target</span><span class="p">)</span></div>
<div class="viewcode-block" id="display_len"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.display_len">[docs]</a><span class="k">def</span> <span class="nf">display_len</span><span class="p">(</span><span class="n">target</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Calculate the &#39;visible width&#39; of text. This is not necessarily the same as the</span>
<span class="sd"> number of characters in the case of certain asian characters. This will also</span>
<span class="sd"> strip MXP patterns.</span>
<span class="sd"> Args:</span>
<span class="sd"> target (any): Something to measure the length of. If a string, it will be</span>
<span class="sd"> measured keeping asian-character and MXP links in mind.</span>
<span class="sd"> Return:</span>
<span class="sd"> int: The visible width of the target.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Would create circular import if in module root.</span>
<span class="kn">from</span> <span class="nn">evennia.utils.ansi</span> <span class="kn">import</span> <span class="n">ANSI_PARSER</span>
<span class="k">if</span> <span class="n">inherits_from</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="c1"># str or ANSIString</span>
<span class="n">target</span> <span class="o">=</span> <span class="n">ANSI_PARSER</span><span class="o">.</span><span class="n">strip_mxp</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
<span class="n">target</span> <span class="o">=</span> <span class="n">ANSI_PARSER</span><span class="o">.</span><span class="n">parse_ansi</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">strip_ansi</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">extra_wide</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;F&quot;</span><span class="p">,</span> <span class="s2">&quot;W&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="mi">2</span> <span class="k">if</span> <span class="n">east_asian_width</span><span class="p">(</span><span class="n">char</span><span class="p">)</span> <span class="ow">in</span> <span class="n">extra_wide</span> <span class="k">else</span> <span class="mi">1</span> <span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">target</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">target</span><span class="p">)</span></div>
<span class="c1"># -------------------------------------------------------------------</span>
<span class="c1"># Search handler function</span>
<span class="c1"># -------------------------------------------------------------------</span>
<span class="c1">#</span>
<span class="c1"># Replace this hook function by changing settings.SEARCH_AT_RESULT.</span>
<div class="viewcode-block" id="at_search_result"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.at_search_result">[docs]</a><span class="k">def</span> <span class="nf">at_search_result</span><span class="p">(</span><span class="n">matches</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">query</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">quiet</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is a generic hook for handling all processing of a search</span>
<span class="sd"> result, including error reporting. This is also called by the cmdhandler</span>
<span class="sd"> to manage errors in command lookup.</span>
<span class="sd"> Args:</span>
<span class="sd"> matches (list): This is a list of 0, 1 or more typeclass</span>
<span class="sd"> instances or Command instances, the matched result of the</span>
<span class="sd"> search. If 0, a nomatch error should be echoed, and if &gt;1,</span>
<span class="sd"> multimatch errors should be given. Only if a single match</span>
<span class="sd"> should the result pass through.</span>
<span class="sd"> caller (Object): The object performing the search and/or which should</span>
<span class="sd"> receive error messages.</span>
<span class="sd"> query (str, optional): The search query used to produce `matches`.</span>
<span class="sd"> quiet (bool, optional): If `True`, no messages will be echoed to caller</span>
<span class="sd"> on errors.</span>
<span class="sd"> Keyword Args:</span>
<span class="sd"> nofound_string (str): Replacement string to echo on a notfound error.</span>
<span class="sd"> multimatch_string (str): Replacement string to echo on a multimatch error.</span>
<span class="sd"> Returns:</span>
<span class="sd"> processed_result (Object or None): This is always a single result</span>
<span class="sd"> or `None`. If `None`, any error reporting/handling should</span>
<span class="sd"> already have happened. The returned object is of the type we are</span>
<span class="sd"> checking multimatches for (e.g. Objects or Commands)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">error</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">matches</span><span class="p">:</span>
<span class="c1"># no results.</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;nofound_string&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">_</span><span class="p">(</span><span class="s2">&quot;Could not find &#39;</span><span class="si">{query}</span><span class="s2">&#39;.&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">query</span><span class="o">=</span><span class="n">query</span><span class="p">)</span>
<span class="n">matches</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">matches</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">multimatch_string</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;multimatch_string&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">multimatch_string</span><span class="p">:</span>
<span class="n">error</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">multimatch_string</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">_</span><span class="p">(</span><span class="s2">&quot;More than one match for &#39;</span><span class="si">{query}</span><span class="s2">&#39; (please narrow target):</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">query</span><span class="o">=</span><span class="n">query</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">num</span><span class="p">,</span> <span class="n">result</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">matches</span><span class="p">):</span>
<span class="c1"># we need to consider that result could be a Command, where .aliases</span>
<span class="c1"># is a list of strings</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">aliases</span><span class="p">,</span> <span class="s2">&quot;all&quot;</span><span class="p">):</span>
<span class="c1"># result is a typeclassed entity where `.aliases` is an AliasHandler.</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">(</span><span class="n">return_objs</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="c1"># remove pluralization aliases</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="n">alias</span> <span class="k">for</span> <span class="n">alias</span> <span class="ow">in</span> <span class="n">aliases</span> <span class="k">if</span> <span class="n">alias</span><span class="o">.</span><span class="n">category</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;plural_key&quot;</span><span class="p">,)]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># result is likely a Command, where `.aliases` is a list of strings.</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">aliases</span>
<span class="n">error</span> <span class="o">+=</span> <span class="n">_MULTIMATCH_TEMPLATE</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">number</span><span class="o">=</span><span class="n">num</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span>
<span class="n">name</span><span class="o">=</span><span class="n">result</span><span class="o">.</span><span class="n">get_display_name</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s2">&quot;get_display_name&quot;</span><span class="p">)</span>
<span class="k">else</span> <span class="n">query</span><span class="p">,</span>
<span class="n">aliases</span><span class="o">=</span><span class="s2">&quot; [</span><span class="si">{alias}</span><span class="s2">]&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">alias</span><span class="o">=</span><span class="s2">&quot;;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">aliases</span><span class="p">)</span> <span class="k">if</span> <span class="n">aliases</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span><span class="p">),</span>
<span class="n">info</span><span class="o">=</span><span class="n">result</span><span class="o">.</span><span class="n">get_extra_info</span><span class="p">(</span><span class="n">caller</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">matches</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># exactly one match</span>
<span class="n">matches</span> <span class="o">=</span> <span class="n">matches</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="n">error</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">quiet</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">error</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="k">return</span> <span class="n">matches</span></div>
<div class="viewcode-block" id="LimitedSizeOrderedDict"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.LimitedSizeOrderedDict">[docs]</a><span class="k">class</span> <span class="nc">LimitedSizeOrderedDict</span><span class="p">(</span><span class="n">OrderedDict</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This dictionary subclass is both ordered and limited to a maximum</span>
<span class="sd"> number of elements. Its main use is to hold a cache that can never</span>
<span class="sd"> grow out of bounds.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="LimitedSizeOrderedDict.__init__"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.LimitedSizeOrderedDict.__init__">[docs]</a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</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="sd">&quot;&quot;&quot;</span>
<span class="sd"> Limited-size ordered dict.</span>
<span class="sd"> Keyword Args:</span>
<span class="sd"> size_limit (int): Use this to limit the number of elements</span>
<span class="sd"> alloweds to be in this list. By default the overshooting elements</span>
<span class="sd"> will be removed in FIFO order.</span>
<span class="sd"> fifo (bool, optional): Defaults to `True`. Remove overshooting elements</span>
<span class="sd"> in FIFO order. If `False`, remove in FILO order.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">size_limit</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;size_limit&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">filo</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;fifo&quot;</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span> <span class="c1"># FIFO inverse of FILO</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_check_size</span><span class="p">()</span></div>
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="n">ret</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__eq__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ret</span><span class="p">:</span>
<span class="k">return</span> <span class="p">(</span>
<span class="n">ret</span>
<span class="ow">and</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="s2">&quot;size_limit&quot;</span><span class="p">)</span>
<span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">size_limit</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">size_limit</span>
<span class="ow">and</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="s2">&quot;fifo&quot;</span><span class="p">)</span>
<span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">fifo</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">fifo</span>
<span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">def</span> <span class="fm">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="fm">__eq__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_check_size</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">filo</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">filo</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">size_limit</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">while</span> <span class="bp">self</span><span class="o">.</span><span class="n">size_limit</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">popitem</span><span class="p">(</span><span class="n">last</span><span class="o">=</span><span class="n">filo</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__setitem__</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_check_size</span><span class="p">()</span>
<div class="viewcode-block" id="LimitedSizeOrderedDict.update"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.LimitedSizeOrderedDict.update">[docs]</a> <span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</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="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">update</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="bp">self</span><span class="o">.</span><span class="n">_check_size</span><span class="p">()</span></div></div>
<div class="viewcode-block" id="get_game_dir_path"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.get_game_dir_path">[docs]</a><span class="k">def</span> <span class="nf">get_game_dir_path</span><span class="p">():</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is called by settings_default in order to determine the path</span>
<span class="sd"> of the game directory.</span>
<span class="sd"> Returns:</span>
<span class="sd"> path (str): Full OS path to the game dir</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># current working directory, assumed to be somewhere inside gamedir.</span>
<span class="k">for</span> <span class="n">inum</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
<span class="n">gpath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
<span class="k">if</span> <span class="s2">&quot;server&quot;</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">gpath</span><span class="p">):</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&quot;server&quot;</span><span class="p">,</span> <span class="s2">&quot;conf&quot;</span><span class="p">,</span> <span class="s2">&quot;settings.py&quot;</span><span class="p">)):</span>
<span class="k">return</span> <span class="n">gpath</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">pardir</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;server/conf/settings.py not found: Must start from inside game dir.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="get_all_typeclasses"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.get_all_typeclasses">[docs]</a><span class="k">def</span> <span class="nf">get_all_typeclasses</span><span class="p">(</span><span class="n">parent</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> List available typeclasses from all available modules.</span>
<span class="sd"> Args:</span>
<span class="sd"> parent (str, optional): If given, only return typeclasses inheriting</span>
<span class="sd"> (at any distance) from this parent.</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: On the form `{&quot;typeclass.path&quot;: typeclass, ...}`</span>
<span class="sd"> Notes:</span>
<span class="sd"> This will dynamically retrieve all abstract django models inheriting at</span>
<span class="sd"> any distance from the TypedObject base (aka a Typeclass) so it will</span>
<span class="sd"> work fine with any custom classes being added.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">evennia.typeclasses.models</span> <span class="kn">import</span> <span class="n">TypedObject</span>
<span class="n">typeclasses</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;</span><span class="si">{}</span><span class="s2">.</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="n">model</span><span class="o">.</span><span class="vm">__name__</span><span class="p">):</span> <span class="n">model</span>
<span class="k">for</span> <span class="n">model</span> <span class="ow">in</span> <span class="n">apps</span><span class="o">.</span><span class="n">get_models</span><span class="p">()</span>
<span class="k">if</span> <span class="n">TypedObject</span> <span class="ow">in</span> <span class="n">getmro</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">if</span> <span class="n">parent</span><span class="p">:</span>
<span class="n">typeclasses</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">name</span><span class="p">:</span> <span class="n">typeclass</span>
<span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">typeclass</span> <span class="ow">in</span> <span class="n">typeclasses</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="k">if</span> <span class="n">inherits_from</span><span class="p">(</span><span class="n">typeclass</span><span class="p">,</span> <span class="n">parent</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">typeclasses</span></div>
<div class="viewcode-block" id="get_all_cmdsets"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.get_all_cmdsets">[docs]</a><span class="k">def</span> <span class="nf">get_all_cmdsets</span><span class="p">(</span><span class="n">parent</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> List available cmdsets from all available modules.</span>
<span class="sd"> Args:</span>
<span class="sd"> parent (str, optional): If given, only return cmdsets inheriting (at</span>
<span class="sd"> any distance) from this parent.</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: On the form {&quot;cmdset.path&quot;: cmdset, ...}</span>
<span class="sd"> Notes:</span>
<span class="sd"> This will dynamically retrieve all abstract django models inheriting at</span>
<span class="sd"> any distance from the CmdSet base so it will work fine with any custom</span>
<span class="sd"> classes being added.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">evennia.commands.cmdset</span> <span class="kn">import</span> <span class="n">CmdSet</span>
<span class="n">base_cmdset</span> <span class="o">=</span> <span class="n">class_from_module</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span> <span class="k">if</span> <span class="n">parent</span> <span class="k">else</span> <span class="n">CmdSet</span>
<span class="n">cmdsets</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;</span><span class="si">{}</span><span class="s2">.</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">subclass</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="n">subclass</span><span class="o">.</span><span class="vm">__name__</span><span class="p">):</span> <span class="n">subclass</span>
<span class="k">for</span> <span class="n">subclass</span> <span class="ow">in</span> <span class="n">base_cmdset</span><span class="o">.</span><span class="n">__subclasses__</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">cmdsets</span></div>
<div class="viewcode-block" id="interactive"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.interactive">[docs]</a><span class="k">def</span> <span class="nf">interactive</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Decorator to make a method pausable with `yield(seconds)`</span>
<span class="sd"> and able to ask for user-input with `response=yield(question)`.</span>
<span class="sd"> For the question-asking to work, one of the args or kwargs to the</span>
<span class="sd"> decorated function must be named &#39;caller&#39;.</span>
<span class="sd"> Raises:</span>
<span class="sd"> ValueError: If asking an interactive question but the decorated</span>
<span class="sd"> function has no arg or kwarg named &#39;caller&#39;.</span>
<span class="sd"> ValueError: If passing non int/float to yield using for pausing.</span>
<span class="sd"> Examples:</span>
<span class="sd"> ```python</span>
<span class="sd"> @interactive</span>
<span class="sd"> def myfunc(caller):</span>
<span class="sd"> caller.msg(&quot;This is a test&quot;)</span>
<span class="sd"> # wait five seconds</span>
<span class="sd"> yield(5)</span>
<span class="sd"> # ask user (caller) a question</span>
<span class="sd"> response = yield(&quot;Do you want to continue waiting?&quot;)</span>
<span class="sd"> if response == &quot;yes&quot;:</span>
<span class="sd"> yield(5)</span>
<span class="sd"> else:</span>
<span class="sd"> # ...</span>
<span class="sd"> ```</span>
<span class="sd"> Notes:</span>
<span class="sd"> This turns the decorated function or method into a generator.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">evennia.utils.evmenu</span> <span class="kn">import</span> <span class="n">get_input</span>
<span class="k">def</span> <span class="nf">_process_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">generator</span><span class="p">):</span>
<span class="n">deferLater</span><span class="p">(</span><span class="n">reactor</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">_iterate</span><span class="p">,</span> <span class="n">generator</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">response</span><span class="o">=</span><span class="n">result</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">_iterate</span><span class="p">(</span><span class="n">generator</span><span class="p">,</span> <span class="n">caller</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">response</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">response</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">generator</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">generator</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">StopIteration</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">)):</span>
<span class="n">delay</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">_iterate</span><span class="p">,</span> <span class="n">generator</span><span class="p">,</span> <span class="n">caller</span><span class="o">=</span><span class="n">caller</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">caller</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;To retrieve input from a @pausable method, that method &quot;</span>
<span class="s2">&quot;must be called with a &#39;caller&#39; argument)&quot;</span>
<span class="p">)</span>
<span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">_process_input</span><span class="p">,</span> <span class="n">generator</span><span class="o">=</span><span class="n">generator</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;yield(val) in a @pausable method must have an int/float as arg.&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">decorator</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="n">argnames</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">getfullargspec</span><span class="p">(</span><span class="n">func</span><span class="p">)</span><span class="o">.</span><span class="n">args</span>
<span class="n">caller</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="s2">&quot;caller&quot;</span> <span class="ow">in</span> <span class="n">argnames</span><span class="p">:</span>
<span class="c1"># we assume this is an object</span>
<span class="n">caller</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="n">argnames</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="s2">&quot;caller&quot;</span><span class="p">)]</span>
<span class="n">ret</span> <span class="o">=</span> <span class="n">func</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="nb">isinstance</span><span class="p">(</span><span class="n">ret</span><span class="p">,</span> <span class="n">types</span><span class="o">.</span><span class="n">GeneratorType</span><span class="p">):</span>
<span class="n">_iterate</span><span class="p">(</span><span class="n">ret</span><span class="p">,</span> <span class="n">caller</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">ret</span>
<span class="k">return</span> <span class="n">decorator</span></div>
<div class="viewcode-block" id="safe_convert_to_types"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.safe_convert_to_types">[docs]</a><span class="k">def</span> <span class="nf">safe_convert_to_types</span><span class="p">(</span><span class="n">converters</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">raise_errors</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Helper function to safely convert inputs to expected data types.</span>
<span class="sd"> Args:</span>
<span class="sd"> converters (tuple): A tuple `((converter, converter,...), {kwarg: converter, ...})` to</span>
<span class="sd"> match a converter to each element in `*args` and `**kwargs`.</span>
<span class="sd"> Each converter will will be called with the arg/kwarg-value as the only argument.</span>
<span class="sd"> If there are too few converters given, the others will simply not be converter. If the</span>
<span class="sd"> converter is given as the string &#39;py&#39;, it attempts to run</span>
<span class="sd"> `safe_eval`/`literal_eval` on the input arg or kwarg value. It&#39;s possible to</span>
<span class="sd"> skip the arg/kwarg part of the tuple, an empty tuple/dict will then be assumed.</span>
<span class="sd"> *args: The arguments to convert with `argtypes`.</span>
<span class="sd"> raise_errors (bool, optional): If set, raise any errors. This will</span>
<span class="sd"> abort the conversion at that arg/kwarg. Otherwise, just skip the</span>
<span class="sd"> conversion of the failing arg/kwarg. This will be set by the FuncParser if</span>
<span class="sd"> this is used as a part of a FuncParser callable.</span>
<span class="sd"> **kwargs: The kwargs to convert with `kwargtypes`</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple: `(args, kwargs)` in converted form.</span>
<span class="sd"> Raises:</span>
<span class="sd"> utils.funcparser.ParsingError: If parsing failed in the `&#39;py&#39;`</span>
<span class="sd"> converter. This also makes this compatible with the FuncParser</span>
<span class="sd"> interface.</span>
<span class="sd"> any: Any other exception raised from other converters, if raise_errors is True.</span>
<span class="sd"> Notes:</span>
<span class="sd"> This function is often used to validate/convert input from untrusted sources. For</span>
<span class="sd"> security, the &quot;py&quot;-converter is deliberately limited and uses `safe_eval`/`literal_eval`</span>
<span class="sd"> which only supports simple expressions or simple containers with literals. NEVER</span>
<span class="sd"> use the python `eval` or `exec` methods as a converter for any untrusted input! Allowing</span>
<span class="sd"> untrusted sources to execute arbitrary python on your server is a severe security risk,</span>
<span class="sd"> Example:</span>
<span class="sd"> ::</span>
<span class="sd"> $funcname(1, 2, 3.0, c=[1,2,3])</span>
<span class="sd"> def _funcname(*args, **kwargs):</span>
<span class="sd"> args, kwargs = safe_convert_input(((int, int, float), {&#39;c&#39;: &#39;py&#39;}), *args, **kwargs)</span>
<span class="sd"> # ...</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">container_end_char</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;(&quot;</span><span class="p">:</span> <span class="s2">&quot;)&quot;</span><span class="p">,</span> <span class="s2">&quot;[&quot;</span><span class="p">:</span> <span class="s2">&quot;]&quot;</span><span class="p">,</span> <span class="s2">&quot;{&quot;</span><span class="p">:</span> <span class="s2">&quot;}&quot;</span><span class="p">}</span> <span class="c1"># tuples, lists, sets</span>
<span class="k">def</span> <span class="nf">_manual_parse_containers</span><span class="p">(</span><span class="n">inp</span><span class="p">):</span>
<span class="n">startchar</span> <span class="o">=</span> <span class="n">inp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">endchar</span> <span class="o">=</span> <span class="n">inp</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="n">endchar</span> <span class="o">!=</span> <span class="n">container_end_char</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">startchar</span><span class="p">):</span>
<span class="k">return</span>
<span class="k">return</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">part</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">inp</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)]</span>
<span class="k">def</span> <span class="nf">_safe_eval</span><span class="p">(</span><span class="n">inp</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">inp</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="c1"># already converted</span>
<span class="k">return</span> <span class="n">inp</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">literal_eval</span><span class="p">(</span><span class="n">inp</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="n">parts</span> <span class="o">=</span> <span class="n">_manual_parse_containers</span><span class="p">(</span><span class="n">inp</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">parts</span><span class="p">:</span>
<span class="k">raise</span>
<span class="k">return</span> <span class="n">parts</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">literal_err</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">err</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">err</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">simple_eval</span><span class="p">(</span><span class="n">inp</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">simple_err</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">err</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">err</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">if</span> <span class="n">raise_errors</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">evennia.utils.funcparser</span> <span class="kn">import</span> <span class="n">ParsingError</span>
<span class="n">err</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Errors converting &#39;</span><span class="si">{</span><span class="n">inp</span><span class="si">}</span><span class="s2">&#39; to python:</span><span class="se">\n</span><span class="s2">&quot;</span>
<span class="sa">f</span><span class="s2">&quot;literal_eval raised </span><span class="si">{</span><span class="n">literal_err</span><span class="si">}</span><span class="se">\n</span><span class="s2">&quot;</span>
<span class="sa">f</span><span class="s2">&quot;simple_eval raised </span><span class="si">{</span><span class="n">simple_err</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">raise</span> <span class="n">ParsingError</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># fallback - convert to str</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">inp</span><span class="p">)</span>
<span class="c1"># handle an incomplete/mixed set of input converters</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">converters</span><span class="p">:</span>
<span class="k">return</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span>
<span class="n">arg_converters</span><span class="p">,</span> <span class="o">*</span><span class="n">kwarg_converters</span> <span class="o">=</span> <span class="n">converters</span>
<span class="n">arg_converters</span> <span class="o">=</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">arg_converters</span><span class="p">)</span>
<span class="n">kwarg_converters</span> <span class="o">=</span> <span class="n">kwarg_converters</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">kwarg_converters</span> <span class="k">else</span> <span class="p">{}</span>
<span class="c1"># apply the converters</span>
<span class="k">if</span> <span class="n">args</span> <span class="ow">and</span> <span class="n">arg_converters</span><span class="p">:</span>
<span class="n">args</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="n">arg_converters</span> <span class="o">=</span> <span class="n">make_iter</span><span class="p">(</span><span class="n">arg_converters</span><span class="p">)</span>
<span class="k">for</span> <span class="n">iarg</span><span class="p">,</span> <span class="n">arg</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">args</span><span class="p">[:</span> <span class="nb">len</span><span class="p">(</span><span class="n">arg_converters</span><span class="p">)]):</span>
<span class="n">converter</span> <span class="o">=</span> <span class="n">arg_converters</span><span class="p">[</span><span class="n">iarg</span><span class="p">]</span>
<span class="n">converter</span> <span class="o">=</span> <span class="n">_safe_eval</span> <span class="k">if</span> <span class="n">converter</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;py&quot;</span><span class="p">,</span> <span class="s2">&quot;python&quot;</span><span class="p">)</span> <span class="k">else</span> <span class="n">converter</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">args</span><span class="p">[</span><span class="n">iarg</span><span class="p">]</span> <span class="o">=</span> <span class="n">converter</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="k">if</span> <span class="n">raise_errors</span><span class="p">:</span>
<span class="k">raise</span>
<span class="n">args</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="n">kwarg_converters</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">kwarg_converters</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">converter</span> <span class="ow">in</span> <span class="n">kwarg_converters</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">converter</span> <span class="o">=</span> <span class="n">_safe_eval</span> <span class="k">if</span> <span class="n">converter</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;py&quot;</span><span class="p">,</span> <span class="s2">&quot;python&quot;</span><span class="p">)</span> <span class="k">else</span> <span class="n">converter</span>
<span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="p">{</span><span class="o">**</span><span class="n">kwargs</span><span class="p">}:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">converter</span><span class="p">(</span><span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="k">if</span> <span class="n">raise_errors</span><span class="p">:</span>
<span class="k">raise</span>
<span class="k">return</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span></div>
<div class="viewcode-block" id="strip_unsafe_input"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.strip_unsafe_input">[docs]</a><span class="k">def</span> <span class="nf">strip_unsafe_input</span><span class="p">(</span><span class="n">txt</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">bypass_perms</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Remove &#39;unsafe&#39; text codes from text; these are used to elimitate</span>
<span class="sd"> exploits in user-provided data, such as html-tags, line breaks etc.</span>
<span class="sd"> Args:</span>
<span class="sd"> txt (str): The text to clean.</span>
<span class="sd"> session (Session, optional): A Session in order to determine if</span>
<span class="sd"> the check should be bypassed by permission (will be checked</span>
<span class="sd"> with the &#39;perm&#39; lock, taking permission hierarchies into account).</span>
<span class="sd"> bypass_perms (list, optional): Iterable of permission strings</span>
<span class="sd"> to check for bypassing the strip. If not given, use</span>
<span class="sd"> `settings.INPUT_CLEANUP_BYPASS_PERMISSIONS`.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str: The cleaned string.</span>
<span class="sd"> Notes:</span>
<span class="sd"> The `INPUT_CLEANUP_BYPASS_PERMISSIONS` list defines what account</span>
<span class="sd"> permissions are required to bypass this strip.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">global</span> <span class="n">_STRIP_UNSAFE_TOKENS</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_STRIP_UNSAFE_TOKENS</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">evennia.utils.ansi</span> <span class="kn">import</span> <span class="n">strip_unsafe_tokens</span> <span class="k">as</span> <span class="n">_STRIP_UNSAFE_TOKENS</span>
<span class="k">if</span> <span class="n">session</span><span class="p">:</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">puppet</span> <span class="k">if</span> <span class="n">session</span><span class="o">.</span><span class="n">puppet</span> <span class="k">else</span> <span class="n">session</span><span class="o">.</span><span class="n">account</span>
<span class="n">bypass_perms</span> <span class="o">=</span> <span class="n">bypass_perms</span> <span class="ow">or</span> <span class="n">settings</span><span class="o">.</span><span class="n">INPUT_CLEANUP_BYPASS_PERMISSIONS</span>
<span class="k">if</span> <span class="n">obj</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="o">*</span><span class="n">bypass_perms</span><span class="p">):</span>
<span class="k">return</span> <span class="n">txt</span>
<span class="c1"># remove html codes</span>
<span class="n">txt</span> <span class="o">=</span> <span class="n">strip_tags</span><span class="p">(</span><span class="n">txt</span><span class="p">)</span>
<span class="n">txt</span> <span class="o">=</span> <span class="n">_STRIP_UNSAFE_TOKENS</span><span class="p">(</span><span class="n">txt</span><span class="p">)</span>
<span class="k">return</span> <span class="n">txt</span></div>
<div class="viewcode-block" id="copy_word_case"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.copy_word_case">[docs]</a><span class="k">def</span> <span class="nf">copy_word_case</span><span class="p">(</span><span class="n">base_word</span><span class="p">,</span> <span class="n">new_word</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Converts a word to use the same capitalization as a first word.</span>
<span class="sd"> Args:</span>
<span class="sd"> base_word (str): A word to get the capitalization from.</span>
<span class="sd"> new_word (str): A new word to capitalize in the same way as `base_word`.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str: The `new_word` with capitalization matching the first word.</span>
<span class="sd"> Notes:</span>
<span class="sd"> This is meant for words. Longer sentences may get unexpected results.</span>
<span class="sd"> If the two words have a mix of capital/lower letters _and_ `new_word`</span>
<span class="sd"> is longer than `base_word`, the excess will retain its original case.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Word</span>
<span class="k">if</span> <span class="n">base_word</span><span class="o">.</span><span class="n">istitle</span><span class="p">():</span>
<span class="k">return</span> <span class="n">new_word</span><span class="o">.</span><span class="n">title</span><span class="p">()</span>
<span class="c1"># word</span>
<span class="k">elif</span> <span class="n">base_word</span><span class="o">.</span><span class="n">islower</span><span class="p">():</span>
<span class="k">return</span> <span class="n">new_word</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="c1"># WORD</span>
<span class="k">elif</span> <span class="n">base_word</span><span class="o">.</span><span class="n">isupper</span><span class="p">():</span>
<span class="k">return</span> <span class="n">new_word</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># WorD - a mix. Handle each character</span>
<span class="n">maxlen</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">base_word</span><span class="p">)</span>
<span class="n">shared</span><span class="p">,</span> <span class="n">excess</span> <span class="o">=</span> <span class="n">new_word</span><span class="p">[:</span><span class="n">maxlen</span><span class="p">],</span> <span class="n">new_word</span><span class="p">[</span><span class="n">maxlen</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">:]</span>
<span class="k">return</span> <span class="p">(</span>
<span class="s2">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="n">char</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span> <span class="k">if</span> <span class="n">base_word</span><span class="p">[</span><span class="n">ic</span><span class="p">]</span><span class="o">.</span><span class="n">isupper</span><span class="p">()</span> <span class="k">else</span> <span class="n">char</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="k">for</span> <span class="n">ic</span><span class="p">,</span> <span class="n">char</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">new_word</span><span class="p">)</span>
<span class="p">)</span>
<span class="o">+</span> <span class="n">excess</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="run_in_main_thread"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.run_in_main_thread">[docs]</a><span class="k">def</span> <span class="nf">run_in_main_thread</span><span class="p">(</span><span class="n">function_or_method</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="sd">&quot;&quot;&quot;</span>
<span class="sd"> Force a callable to execute in the main Evennia thread. This is only relevant when</span>
<span class="sd"> calling code from e.g. web views, which run in a separate threadpool. Use this</span>
<span class="sd"> to avoid race conditions.</span>
<span class="sd"> Args:</span>
<span class="sd"> function_or_method (callable): A function or method to fire.</span>
<span class="sd"> *args: Will be passed into the callable.</span>
<span class="sd"> **kwargs: Will be passed into the callable.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">_IS_MAIN_THREAD</span><span class="p">:</span>
<span class="k">return</span> <span class="n">function_or_method</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">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">threads</span><span class="o">.</span><span class="n">blockingCallFromThread</span><span class="p">(</span><span class="n">reactor</span><span class="p">,</span> <span class="n">function_or_method</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></div>
<span class="n">_INT2STR_MAP_NOUN</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="p">:</span> <span class="s2">&quot;no&quot;</span><span class="p">,</span>
<span class="mi">1</span><span class="p">:</span> <span class="s2">&quot;one&quot;</span><span class="p">,</span>
<span class="mi">2</span><span class="p">:</span> <span class="s2">&quot;two&quot;</span><span class="p">,</span>
<span class="mi">3</span><span class="p">:</span> <span class="s2">&quot;three&quot;</span><span class="p">,</span>
<span class="mi">4</span><span class="p">:</span> <span class="s2">&quot;four&quot;</span><span class="p">,</span>
<span class="mi">5</span><span class="p">:</span> <span class="s2">&quot;five&quot;</span><span class="p">,</span>
<span class="mi">6</span><span class="p">:</span> <span class="s2">&quot;six&quot;</span><span class="p">,</span>
<span class="mi">7</span><span class="p">:</span> <span class="s2">&quot;seven&quot;</span><span class="p">,</span>
<span class="mi">8</span><span class="p">:</span> <span class="s2">&quot;eight&quot;</span><span class="p">,</span>
<span class="mi">9</span><span class="p">:</span> <span class="s2">&quot;nine&quot;</span><span class="p">,</span>
<span class="mi">10</span><span class="p">:</span> <span class="s2">&quot;ten&quot;</span><span class="p">,</span>
<span class="mi">11</span><span class="p">:</span> <span class="s2">&quot;eleven&quot;</span><span class="p">,</span>
<span class="mi">12</span><span class="p">:</span> <span class="s2">&quot;twelve&quot;</span><span class="p">,</span>
<span class="p">}</span>
<span class="n">_INT2STR_MAP_ADJ</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">:</span> <span class="s2">&quot;1st&quot;</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s2">&quot;2nd&quot;</span><span class="p">,</span> <span class="mi">3</span><span class="p">:</span> <span class="s2">&quot;3rd&quot;</span><span class="p">}</span> <span class="c1"># rest is Xth.</span>
<div class="viewcode-block" id="int2str"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.int2str">[docs]</a><span class="k">def</span> <span class="nf">int2str</span><span class="p">(</span><span class="n">number</span><span class="p">,</span> <span class="n">adjective</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Convert a number to an English string for better display; so 1 -&gt; one, 2 -&gt; two etc</span>
<span class="sd"> up until 12, after which it will be &#39;13&#39;, &#39;14&#39; etc.</span>
<span class="sd"> Args:</span>
<span class="sd"> number (int): The number to convert. Floats will be converted to ints.</span>
<span class="sd"> adjective (int): If set, map 1-&gt;1st, 2-&gt;2nd etc. If unset, map 1-&gt;one, 2-&gt;two etc.</span>
<span class="sd"> up to twelve.</span>
<span class="sd"> Return:</span>
<span class="sd"> str: The number expressed as a string.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">number</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
<span class="k">if</span> <span class="n">adjective</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_INT2STR_MAP_ADJ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">number</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">number</span><span class="si">}</span><span class="s2">th&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_INT2STR_MAP_NOUN</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">number</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">number</span><span class="p">))</span></div>
<span class="n">_STR2INT_MAP</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;one&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s2">&quot;two&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
<span class="s2">&quot;three&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
<span class="s2">&quot;four&quot;</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
<span class="s2">&quot;five&quot;</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
<span class="s2">&quot;six&quot;</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span>
<span class="s2">&quot;seven&quot;</span><span class="p">:</span> <span class="mi">7</span><span class="p">,</span>
<span class="s2">&quot;eight&quot;</span><span class="p">:</span> <span class="mi">8</span><span class="p">,</span>
<span class="s2">&quot;nine&quot;</span><span class="p">:</span> <span class="mi">9</span><span class="p">,</span>
<span class="s2">&quot;ten&quot;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
<span class="s2">&quot;eleven&quot;</span><span class="p">:</span> <span class="mi">11</span><span class="p">,</span>
<span class="s2">&quot;twelve&quot;</span><span class="p">:</span> <span class="mi">12</span><span class="p">,</span>
<span class="s2">&quot;thirteen&quot;</span><span class="p">:</span> <span class="mi">13</span><span class="p">,</span>
<span class="s2">&quot;fourteen&quot;</span><span class="p">:</span> <span class="mi">14</span><span class="p">,</span>
<span class="s2">&quot;fifteen&quot;</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span>
<span class="s2">&quot;sixteen&quot;</span><span class="p">:</span> <span class="mi">16</span><span class="p">,</span>
<span class="s2">&quot;seventeen&quot;</span><span class="p">:</span> <span class="mi">17</span><span class="p">,</span>
<span class="s2">&quot;eighteen&quot;</span><span class="p">:</span> <span class="mi">18</span><span class="p">,</span>
<span class="s2">&quot;nineteen&quot;</span><span class="p">:</span> <span class="mi">19</span><span class="p">,</span>
<span class="s2">&quot;twenty&quot;</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
<span class="s2">&quot;thirty&quot;</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span>
<span class="s2">&quot;forty&quot;</span><span class="p">:</span> <span class="mi">40</span><span class="p">,</span>
<span class="s2">&quot;fifty&quot;</span><span class="p">:</span> <span class="mi">50</span><span class="p">,</span>
<span class="s2">&quot;sixty&quot;</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
<span class="s2">&quot;seventy&quot;</span><span class="p">:</span> <span class="mi">70</span><span class="p">,</span>
<span class="s2">&quot;eighty&quot;</span><span class="p">:</span> <span class="mi">80</span><span class="p">,</span>
<span class="s2">&quot;ninety&quot;</span><span class="p">:</span> <span class="mi">90</span><span class="p">,</span>
<span class="s2">&quot;hundred&quot;</span><span class="p">:</span> <span class="mi">100</span><span class="p">,</span>
<span class="s2">&quot;thousand&quot;</span><span class="p">:</span> <span class="mi">1000</span><span class="p">,</span>
<span class="p">}</span>
<span class="n">_STR2INT_ADJS</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;first&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s2">&quot;second&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
<span class="s2">&quot;third&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
<span class="p">}</span>
<div class="viewcode-block" id="str2int"><a class="viewcode-back" href="../../../api/evennia.utils.utils.html#evennia.commands.default.building.str2int">[docs]</a><span class="k">def</span> <span class="nf">str2int</span><span class="p">(</span><span class="n">number</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Converts a string to an integer.</span>
<span class="sd"> Args:</span>
<span class="sd"> number (str): The string to convert. It can be a digit such as &quot;1&quot;, or a number word such as &quot;one&quot;.</span>
<span class="sd"> Returns:</span>
<span class="sd"> int: The string represented as an integer.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">number</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
<span class="n">original_input</span> <span class="o">=</span> <span class="n">number</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># it&#39;s a digit already</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="c1"># if it&#39;s an ordinal number such as &quot;1st&quot;, it&#39;ll convert to int with the last two characters chopped off</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">number</span><span class="p">[:</span><span class="o">-</span><span class="mi">2</span><span class="p">])</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">pass</span>
<span class="c1"># convert sound changes for generic ordinal numbers</span>
<span class="k">if</span> <span class="n">number</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">:]</span> <span class="o">==</span> <span class="s2">&quot;th&quot;</span><span class="p">:</span>
<span class="c1"># remove &quot;th&quot;</span>
<span class="n">number</span> <span class="o">=</span> <span class="n">number</span><span class="p">[:</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span>
<span class="k">if</span> <span class="n">number</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;f&quot;</span><span class="p">:</span>
<span class="c1"># e.g. twelfth, fifth</span>
<span class="n">number</span> <span class="o">=</span> <span class="n">number</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;ve&quot;</span>
<span class="k">elif</span> <span class="n">number</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">:]</span> <span class="o">==</span> <span class="s2">&quot;ie&quot;</span><span class="p">:</span>
<span class="c1"># e.g. twentieth, fortieth</span>
<span class="n">number</span> <span class="o">=</span> <span class="n">number</span><span class="p">[:</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;y&quot;</span>
<span class="c1"># custom case for ninth</span>
<span class="k">elif</span> <span class="n">number</span><span class="p">[</span><span class="o">-</span><span class="mi">3</span><span class="p">:]</span> <span class="o">==</span> <span class="s2">&quot;nin&quot;</span><span class="p">:</span>
<span class="n">number</span> <span class="o">+=</span> <span class="s2">&quot;e&quot;</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">:=</span> <span class="n">_STR2INT_MAP</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">number</span><span class="p">):</span>
<span class="c1"># it&#39;s a single number, return it</span>
<span class="k">return</span> <span class="n">i</span>
<span class="c1"># remove optional &quot;and&quot;s</span>
<span class="n">number</span> <span class="o">=</span> <span class="n">number</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot; and &quot;</span><span class="p">,</span> <span class="s2">&quot; &quot;</span><span class="p">)</span>
<span class="c1"># split number words by spaces, hyphens and commas, to accommodate multiple styles</span>
<span class="n">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="n">word</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;[-\s\,]&quot;</span><span class="p">,</span> <span class="n">number</span><span class="p">)</span> <span class="k">if</span> <span class="n">word</span><span class="p">]</span>
<span class="n">sums</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">numbers</span><span class="p">:</span>
<span class="c1"># check if it&#39;s a known number-word</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">:=</span> <span class="n">_STR2INT_MAP</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">word</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">len</span><span class="p">(</span><span class="n">sums</span><span class="p">):</span>
<span class="c1"># initialize the list with the current value</span>
<span class="n">sums</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># if the previous number was smaller, it&#39;s a multiplier</span>
<span class="c1"># e.g. the &quot;two&quot; in &quot;two hundred&quot;</span>
<span class="k">if</span> <span class="n">sums</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">i</span><span class="p">:</span>
<span class="n">sums</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">sums</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">i</span>
<span class="c1"># otherwise, it&#39;s added on, like the &quot;five&quot; in &quot;twenty five&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sums</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">i</span> <span class="o">:=</span> <span class="n">_STR2INT_ADJS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">word</span><span class="p">):</span>
<span class="c1"># it&#39;s a special adj word; ordinal case will never be a multiplier</span>
<span class="n">sums</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># invalid number-word, raise ValueError</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;String </span><span class="si">{</span><span class="n">original_input</span><span class="si">}</span><span class="s2"> cannot be converted to int.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">sums</span><span class="p">)</span></div>
</pre></div>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<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="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.utils.utils</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>