evennia/docs/latest/_modules/evennia/scripts/taskhandler.html
Evennia docbuilder action eaa16b1646 Updated HTML docs.
2024-09-29 11:09:06 +00:00

737 lines
No EOL
72 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.scripts.taskhandler &#8212; Evennia latest 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 latest</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.scripts.taskhandler</a></li>
</ul>
</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/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Doc Versions</h3>
<ul>
<li><a href="taskhandler.html">latest (main branch)</a></li>
<li><a href="../4.x/index.html">v4.0.0 branch (outdated)</a></li>
<li><a href="../3.x/index.html">v3.0.0 branch (outdated)</a></li>
<li><a href="../2.x/index.html">v2.0.0 branch (outdated)</a></li>
<li><a href="../1.x/index.html">v1.0.0 branch (outdated)</a></li>
<li><a href="../0.x/index.html">v0.9.5 branch (outdated)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.scripts.taskhandler</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Module containing the task handler for Evennia deferred tasks, persistent or not.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span>
<span class="kn">from</span> <span class="nn">pickle</span> <span class="kn">import</span> <span class="n">PickleError</span>
<span class="kn">from</span> <span class="nn">evennia.server.models</span> <span class="kn">import</span> <span class="n">ServerConfig</span>
<span class="kn">from</span> <span class="nn">evennia.utils.dbserialize</span> <span class="kn">import</span> <span class="n">dbserialize</span><span class="p">,</span> <span class="n">dbunserialize</span>
<span class="kn">from</span> <span class="nn">evennia.utils.logger</span> <span class="kn">import</span> <span class="n">log_err</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span>
<span class="kn">from</span> <span class="nn">twisted.internet.defer</span> <span class="kn">import</span> <span class="n">CancelledError</span> <span class="k">as</span> <span class="n">DefCancelledError</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">TASK_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<div class="viewcode-block" id="handle_error"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.handle_error">[docs]</a><span class="k">def</span> <span class="nf">handle_error</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Handle errors within deferred objects.&quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args</span><span class="p">:</span>
<span class="c1"># suppress cancel errors</span>
<span class="k">if</span> <span class="n">arg</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">DefCancelledError</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">raise</span> <span class="n">arg</span></div>
<div class="viewcode-block" id="TaskHandlerTask"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask">[docs]</a><span class="k">class</span> <span class="nc">TaskHandlerTask</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;An object to represent a single TaskHandler task.</span>
<span class="sd"> Instance Attributes:</span>
<span class="sd"> task_id (int): the global id for this task</span>
<span class="sd"> deferred (deferred): a reference to this task&#39;s deferred</span>
<span class="sd"> Property Attributes:</span>
<span class="sd"> paused (bool): check if the deferred instance of a task has been paused.</span>
<span class="sd"> called(self): A task attribute to check if the deferred instance of a task has been called.</span>
<span class="sd"> Methods:</span>
<span class="sd"> pause(): Pause the callback of a task.</span>
<span class="sd"> unpause(): Process all callbacks made since pause() was called.</span>
<span class="sd"> do_task(): Execute the task (call its callback).</span>
<span class="sd"> call(): Call the callback of this task.</span>
<span class="sd"> remove(): Remove a task without executing it.</span>
<span class="sd"> cancel(): Stop a task from automatically executing.</span>
<span class="sd"> active(): Check if a task is active (has not been called yet).</span>
<span class="sd"> exists(): Check if a task exists.</span>
<span class="sd"> get_id(): Returns the global id for this task. For use with</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="TaskHandlerTask.__init__"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.__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">task_id</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">task_id</span> <span class="o">=</span> <span class="n">task_id</span>
<span class="bp">self</span><span class="o">.</span><span class="n">deferred</span> <span class="o">=</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">get_deferred</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandlerTask.get_deferred"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.get_deferred">[docs]</a> <span class="k">def</span> <span class="nf">get_deferred</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the instance of the deferred the task id is using.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool or deferred: An instance of a deferred or False if there is no task with the id.</span>
<span class="sd"> None is returned if there is no deferred affiliated with this id.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">get_deferred</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandlerTask.pause"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.pause">[docs]</a> <span class="k">def</span> <span class="nf">pause</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Pause the callback of a task.</span>
<span class="sd"> To resume use `TaskHandlerTask.unpause`.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">d</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">deferred</span>
<span class="k">if</span> <span class="n">d</span><span class="p">:</span>
<span class="n">d</span><span class="o">.</span><span class="n">pause</span><span class="p">()</span></div>
<div class="viewcode-block" id="TaskHandlerTask.unpause"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.unpause">[docs]</a> <span class="k">def</span> <span class="nf">unpause</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Unpause a task, run the task if it has passed delay time.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">d</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">deferred</span>
<span class="k">if</span> <span class="n">d</span><span class="p">:</span>
<span class="n">d</span><span class="o">.</span><span class="n">unpause</span><span class="p">()</span></div>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">paused</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A task attribute to check if the deferred instance of a task has been paused.</span>
<span class="sd"> This exists to mock usage of a twisted deferred object.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool or None: True if the task was properly paused. None if the task does not have</span>
<span class="sd"> a deferred instance.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">d</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">deferred</span>
<span class="k">if</span> <span class="n">d</span><span class="p">:</span>
<span class="k">return</span> <span class="n">d</span><span class="o">.</span><span class="n">paused</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<div class="viewcode-block" id="TaskHandlerTask.do_task"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.do_task">[docs]</a> <span class="k">def</span> <span class="nf">do_task</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Execute the task (call its callback).</span>
<span class="sd"> If calling before timedelay, cancel the deferred instance affliated to this task.</span>
<span class="sd"> Remove the task from the dictionary of current tasks on a successful</span>
<span class="sd"> callback.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool or any: Set to `False` if the task does not exist in task</span>
<span class="sd"> handler. Otherwise it will be the return of the task&#39;s callback.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">do_task</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandlerTask.call"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.call">[docs]</a> <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Call the callback of a task.</span>
<span class="sd"> Leave the task unaffected otherwise.</span>
<span class="sd"> This does not use the task&#39;s deferred instance.</span>
<span class="sd"> The only requirement is that the task exist in task handler.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool or any: Set to `False` if the task does not exist in task</span>
<span class="sd"> handler. Otherwise it will be the return of the task&#39;s callback.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">call_task</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandlerTask.remove"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.remove">[docs]</a> <span class="k">def</span> <span class="nf">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Remove a task without executing it.</span>
<span class="sd"> Deletes the instance of the task&#39;s deferred.</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): an existing task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if the removal completed successfully.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandlerTask.cancel"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.cancel">[docs]</a> <span class="k">def</span> <span class="nf">cancel</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Stop a task from automatically executing.</span>
<span class="sd"> This will not remove the task.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if the cancel completed successfully.</span>
<span class="sd"> False if the cancel did not complete successfully.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">cancel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandlerTask.active"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.active">[docs]</a> <span class="k">def</span> <span class="nf">active</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Check if a task is active (has not been called yet).</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if a task is active (has not been called yet). False if</span>
<span class="sd"> it is not (has been called) or if the task does not exist.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">active</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">)</span></div>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">called</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A task attribute to check if the deferred instance of a task has been called.</span>
<span class="sd"> This exists to mock usage of a twisted deferred object.</span>
<span class="sd"> It will not set to True if Task.call has been called. This only happens if</span>
<span class="sd"> task&#39;s deferred instance calls the callback.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if the deferred instance of this task has called the callback.</span>
<span class="sd"> False if the deferred instnace of this task has not called the callback.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">d</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">deferred</span>
<span class="k">if</span> <span class="n">d</span><span class="p">:</span>
<span class="k">return</span> <span class="n">d</span><span class="o">.</span><span class="n">called</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<div class="viewcode-block" id="TaskHandlerTask.exists"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.exists">[docs]</a> <span class="k">def</span> <span class="nf">exists</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check if a task exists.</span>
<span class="sd"> Most task handler methods check for existence for you.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True the task exists False if it does not.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandlerTask.get_id"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandlerTask.get_id">[docs]</a> <span class="k">def</span> <span class="nf">get_id</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Returns the global id for this task. For use with</span>
<span class="sd"> `evennia.scripts.taskhandler.TASK_HANDLER`.</span>
<span class="sd"> Returns:</span>
<span class="sd"> task_id (int): global task id for this task.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">task_id</span></div></div>
<div class="viewcode-block" id="TaskHandler"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler">[docs]</a><span class="k">class</span> <span class="nc">TaskHandler</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;A light singleton wrapper allowing to access permanent tasks.</span>
<span class="sd"> When `utils.delay` is called, the task handler is used to create</span>
<span class="sd"> the task.</span>
<span class="sd"> Task handler will automatically remove uncalled but canceled from task</span>
<span class="sd"> handler. By default this will not occur until a canceled task</span>
<span class="sd"> has been uncalled for 60 second after the time it should have been called.</span>
<span class="sd"> To adjust this time use TASK_HANDLER.stale_timeout. If stale_timeout is 0</span>
<span class="sd"> stale tasks will not be automatically removed.</span>
<span class="sd"> This is not done on a timer. I is done as new tasks are added or the load method is called.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="TaskHandler.__init__"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.__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="bp">self</span><span class="o">.</span><span class="n">tasks</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">to_save</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">clock</span> <span class="o">=</span> <span class="n">reactor</span>
<span class="c1"># number of seconds before an uncalled canceled task is removed from TaskHandler</span>
<span class="bp">self</span><span class="o">.</span><span class="n">stale_timeout</span> <span class="o">=</span> <span class="mi">60</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_now</span> <span class="o">=</span> <span class="kc">False</span> <span class="c1"># used in unit testing to manually set now time</span></div>
<div class="viewcode-block" id="TaskHandler.load"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.load">[docs]</a> <span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Load from the ServerConfig.</span>
<span class="sd"> This should be automatically called when Evennia starts.</span>
<span class="sd"> It populates `self.tasks` according to the ServerConfig.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">to_save</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">ServerConfig</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">conf</span><span class="p">(</span><span class="s2">&quot;delayed_tasks&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">dict</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="nb">str</span><span class="p">):</span>
<span class="n">tasks</span> <span class="o">=</span> <span class="n">dbunserialize</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">tasks</span> <span class="o">=</span> <span class="n">value</span>
<span class="c1"># At this point, `tasks` contains a dictionary of still-serialized tasks</span>
<span class="k">for</span> <span class="n">task_id</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">tasks</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">dbunserialize</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">callback</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="c1"># `callback` can be an object and name for instance methods</span>
<span class="n">obj</span><span class="p">,</span> <span class="n">method</span> <span class="o">=</span> <span class="n">callback</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="n">to_save</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">continue</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">callback</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">method</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">log_err</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;TaskHandler: Unable to load task </span><span class="si">{</span><span class="n">task_id</span><span class="si">}</span><span class="s2"> (disabling it): </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">to_save</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">continue</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">stale_timeout</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># cleanup stale tasks.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">clean_stale_tasks</span><span class="p">()</span>
<span class="k">if</span> <span class="n">to_save</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">save</span><span class="p">()</span></div>
<div class="viewcode-block" id="TaskHandler.clean_stale_tasks"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.clean_stale_tasks">[docs]</a> <span class="k">def</span> <span class="nf">clean_stale_tasks</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;remove uncalled but canceled from task handler.</span>
<span class="sd"> By default this will not occur until a canceled task</span>
<span class="sd"> has been uncalled for 60 second after the time it should have been called.</span>
<span class="sd"> To adjust this time use TASK_HANDLER.stale_timeout.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">clean_ids</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">task_id</span><span class="p">,</span> <span class="p">(</span><span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">persistent</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</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="bp">self</span><span class="o">.</span><span class="n">active</span><span class="p">(</span><span class="n">task_id</span><span class="p">):</span>
<span class="n">stale_date</span> <span class="o">=</span> <span class="n">date</span> <span class="o">+</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">seconds</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">stale_timeout</span><span class="p">)</span>
<span class="c1"># if a now time is provided use it (intended for unit testing)</span>
<span class="n">now</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_now</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_now</span> <span class="k">else</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="c1"># the task was canceled more than stale_timeout seconds ago</span>
<span class="k">if</span> <span class="n">now</span> <span class="o">&gt;</span> <span class="n">stale_date</span><span class="p">:</span>
<span class="n">clean_ids</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">for</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="n">clean_ids</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span></div>
<div class="viewcode-block" id="TaskHandler.save"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.save">[docs]</a> <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Save the tasks in ServerConfig.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">task_id</span><span class="p">,</span> <span class="p">(</span><span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">persistent</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">to_save</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">persistent</span><span class="p">:</span>
<span class="k">continue</span>
<span class="n">safe_callback</span> <span class="o">=</span> <span class="n">callback</span>
<span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">callback</span><span class="p">,</span> <span class="s2">&quot;__self__&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
<span class="c1"># `callback` is an instance method</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">callback</span><span class="o">.</span><span class="vm">__self__</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">callback</span><span class="o">.</span><span class="vm">__name__</span>
<span class="n">safe_callback</span> <span class="o">=</span> <span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="c1"># Check if callback can be pickled. args and kwargs have been checked</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">dbserialize</span><span class="p">(</span><span class="n">safe_callback</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="n">PickleError</span><span class="p">)</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;the specified callback </span><span class="si">{callback}</span><span class="s2"> cannot be pickled. &quot;</span>
<span class="s2">&quot;It must be a top-level function in a module or an &quot;</span>
<span class="s2">&quot;instance method (</span><span class="si">{err}</span><span class="s2">).&quot;</span><span class="o">.</span><span class="n">format</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">err</span><span class="o">=</span><span class="n">err</span><span class="p">)</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">to_save</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">dbserialize</span><span class="p">((</span><span class="n">date</span><span class="p">,</span> <span class="n">safe_callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">))</span>
<span class="n">ServerConfig</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">conf</span><span class="p">(</span><span class="s2">&quot;delayed_tasks&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">to_save</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandler.add"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.add">[docs]</a> <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</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="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Add a new task.</span>
<span class="sd"> If the persistent kwarg is truthy:</span>
<span class="sd"> The callback, args and values for kwarg will be serialized. Type</span>
<span class="sd"> and attribute errors during the serialization will be logged,</span>
<span class="sd"> but will not throw exceptions.</span>
<span class="sd"> For persistent tasks do not use memory references in the callback</span>
<span class="sd"> function or arguments. After a restart those memory references are no</span>
<span class="sd"> longer accurate.</span>
<span class="sd"> Args:</span>
<span class="sd"> timedelay (int or float): time in seconds before calling the callback.</span>
<span class="sd"> callback (function or instance method): the callback itself</span>
<span class="sd"> any (any): any additional positional arguments to send to the callback</span>
<span class="sd"> *args: positional arguments to pass to callback.</span>
<span class="sd"> **kwargs: keyword arguments to pass to callback.</span>
<span class="sd"> - persistent (bool, optional): persist the task (stores it).</span>
<span class="sd"> Persistent key and value is removed from kwargs it will</span>
<span class="sd"> not be passed to callback.</span>
<span class="sd"> Returns:</span>
<span class="sd"> TaskHandlerTask: An object to represent a task.</span>
<span class="sd"> Reference `evennia.scripts.taskhandler.TaskHandlerTask` for complete details.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># set the completion time</span>
<span class="c1"># Only used on persistent tasks after a restart</span>
<span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="n">delta</span> <span class="o">=</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">seconds</span><span class="o">=</span><span class="n">timedelay</span><span class="p">)</span>
<span class="n">comp_time</span> <span class="o">=</span> <span class="n">now</span> <span class="o">+</span> <span class="n">delta</span>
<span class="c1"># get an open task id</span>
<span class="n">used_ids</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
<span class="n">task_id</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="n">used_ids</span><span class="p">:</span>
<span class="n">task_id</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="c1"># record the task to the tasks dictionary</span>
<span class="n">persistent</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;persistent&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;persistent&quot;</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
<span class="k">del</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;persistent&quot;</span><span class="p">]</span>
<span class="k">if</span> <span class="n">persistent</span><span class="p">:</span>
<span class="n">safe_args</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">safe_kwargs</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># Check that args and kwargs contain picklable information</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">dbserialize</span><span class="p">(</span><span class="n">arg</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="n">PickleError</span><span class="p">):</span>
<span class="n">log_err</span><span class="p">(</span>
<span class="s2">&quot;The positional argument </span><span class="si">{}</span><span class="s2"> cannot be &quot;</span>
<span class="s2">&quot;pickled and will not be present in the arguments &quot;</span>
<span class="s2">&quot;fed to the callback </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">arg</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">safe_args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">dbserialize</span><span class="p">(</span><span class="n">value</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="n">PickleError</span><span class="p">):</span>
<span class="n">log_err</span><span class="p">(</span>
<span class="s2">&quot;The </span><span class="si">{}</span><span class="s2"> keyword argument </span><span class="si">{}</span><span class="s2"> cannot be &quot;</span>
<span class="s2">&quot;pickled and will not be present in the arguments &quot;</span>
<span class="s2">&quot;fed to the callback </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">key</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">safe_kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">comp_time</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">safe_args</span><span class="p">,</span> <span class="n">safe_kwargs</span><span class="p">,</span> <span class="n">persistent</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">save</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># this is a non-persitent task</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">comp_time</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">persistent</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="c1"># defer the task</span>
<span class="n">callback</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">do_task</span>
<span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="n">task_id</span><span class="p">]</span>
<span class="n">kwargs</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">deferLater</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">clock</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="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">handle_error</span><span class="p">)</span>
<span class="c1"># some tasks may complete before the deferred can be added</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="n">task</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="n">task</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
<span class="n">task</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">persistent</span>
<span class="n">task</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="n">d</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">task</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># the task already completed</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">stale_timeout</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">clean_stale_tasks</span><span class="p">()</span>
<span class="k">return</span> <span class="n">TaskHandlerTask</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span></div>
<div class="viewcode-block" id="TaskHandler.exists"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.exists">[docs]</a> <span class="k">def</span> <span class="nf">exists</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">task_id</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check if a task exists.</span>
<span class="sd"> Most task handler methods check for existence for you.</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): an existing task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True the task exists False if it does not.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="TaskHandler.active"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.active">[docs]</a> <span class="k">def</span> <span class="nf">active</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">task_id</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check if a task is active (has not been called yet).</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): an existing task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if a task is active (has not been called yet). False if</span>
<span class="sd"> it is not (has been called) or if the task does not exist.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="c1"># if the task has not been run, cancel it</span>
<span class="n">deferred</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_deferred</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">return</span> <span class="ow">not</span> <span class="p">(</span><span class="n">deferred</span> <span class="ow">and</span> <span class="n">deferred</span><span class="o">.</span><span class="n">called</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="TaskHandler.cancel"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.cancel">[docs]</a> <span class="k">def</span> <span class="nf">cancel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">task_id</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Stop a task from automatically executing.</span>
<span class="sd"> This will not remove the task.</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): an existing task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if the cancel completed successfully.</span>
<span class="sd"> False if the cancel did not complete successfully.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="c1"># if the task has not been run, cancel it</span>
<span class="n">d</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_deferred</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">if</span> <span class="n">d</span><span class="p">:</span> <span class="c1"># it is remotely possible for a task to not have a deferred</span>
<span class="k">if</span> <span class="n">d</span><span class="o">.</span><span class="n">called</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="c1"># the callback has not been called yet.</span>
<span class="n">d</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># this task has no deferred instance</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">False</span></div>
<div class="viewcode-block" id="TaskHandler.remove"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.remove">[docs]</a> <span class="k">def</span> <span class="nf">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">task_id</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Remove a task without executing it.</span>
<span class="sd"> Deletes the instance of the task&#39;s deferred.</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): an existing task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True if the removal completed successfully.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">d</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># delete the task from the tasks dictionary</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="c1"># if the task has not been run, cancel it</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cancel</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="c1"># delete the task from the tasks dictionary</span>
<span class="c1"># remove the task from the persistent dictionary and ServerConfig</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">to_save</span><span class="p">:</span>
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">to_save</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> <span class="c1"># remove from ServerConfig.objects</span>
<span class="c1"># delete the instance of the deferred</span>
<span class="k">if</span> <span class="n">d</span><span class="p">:</span>
<span class="k">del</span> <span class="n">d</span>
<span class="k">return</span> <span class="kc">True</span></div>
<div class="viewcode-block" id="TaskHandler.clear"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.clear">[docs]</a> <span class="k">def</span> <span class="nf">clear</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">save</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">cancel</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Clear all tasks. By default tasks are canceled and removed from the database as well.</span>
<span class="sd"> Args:</span>
<span class="sd"> save=True (bool): Should changes to persistent tasks be saved to database.</span>
<span class="sd"> cancel=True (bool): Cancel scheduled tasks before removing it from task handler.</span>
<span class="sd"> Returns:</span>
<span class="sd"> True (bool): if the removal completed successfully.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="k">for</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
<span class="k">if</span> <span class="n">cancel</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cancel</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">to_save</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">to_save</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">if</span> <span class="n">save</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="k">return</span> <span class="kc">True</span></div>
<div class="viewcode-block" id="TaskHandler.call_task"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.call_task">[docs]</a> <span class="k">def</span> <span class="nf">call_task</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">task_id</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Call the callback of a task.</span>
<span class="sd"> Leave the task unaffected otherwise.</span>
<span class="sd"> This does not use the task&#39;s deferred instance.</span>
<span class="sd"> The only requirement is that the task exist in task handler.</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): an existing task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool or any: Set to `False` if the task does not exist in task</span>
<span class="sd"> handler. Otherwise it will be the return of the task&#39;s callback.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">persistent</span><span class="p">,</span> <span class="n">d</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># the task does not exist</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</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="TaskHandler.do_task"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.do_task">[docs]</a> <span class="k">def</span> <span class="nf">do_task</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">task_id</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Execute the task (call its callback).</span>
<span class="sd"> If calling before timedelay cancel the deferred instance affliated to this task.</span>
<span class="sd"> Remove the task from the dictionary of current tasks on a successful</span>
<span class="sd"> callback.</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): a valid task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool or any: Set to `False` if the task does not exist in task</span>
<span class="sd"> handler. Otherwise it will be the return of the task&#39;s callback.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">callback_return</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">persistent</span><span class="p">,</span> <span class="n">d</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># the task does not exist</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">if</span> <span class="n">d</span><span class="p">:</span> <span class="c1"># it is remotely possible for a task to not have a deferred</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">d</span><span class="o">.</span><span class="n">called</span><span class="p">:</span> <span class="c1"># the task&#39;s deferred has not been called yet</span>
<span class="n">d</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span> <span class="c1"># cancel the automated callback</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># this task has no deferred, and should not be called</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="n">callback_return</span> <span class="o">=</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="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span>
<span class="k">return</span> <span class="n">callback_return</span></div>
<div class="viewcode-block" id="TaskHandler.get_deferred"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.get_deferred">[docs]</a> <span class="k">def</span> <span class="nf">get_deferred</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">task_id</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return the instance of the deferred the task id is using.</span>
<span class="sd"> Args:</span>
<span class="sd"> task_id (int): a valid task ID.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool or deferred: An instance of a deferred or False if there is no task with the id.</span>
<span class="sd"> None is returned if there is no deferred affiliated with this id.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">task_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="TaskHandler.create_delays"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.create_delays">[docs]</a> <span class="k">def</span> <span class="nf">create_delays</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Create the delayed tasks for the persistent tasks.</span>
<span class="sd"> This method should be automatically called when Evennia starts.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="k">for</span> <span class="n">task_id</span><span class="p">,</span> <span class="p">(</span><span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="kc">None</span>
<span class="n">seconds</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">date</span> <span class="o">-</span> <span class="n">now</span><span class="p">)</span><span class="o">.</span><span class="n">total_seconds</span><span class="p">())</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">deferLater</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">clock</span><span class="p">,</span> <span class="n">seconds</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">do_task</span><span class="p">,</span> <span class="n">task_id</span><span class="p">)</span>
<span class="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">handle_error</span><span class="p">)</span>
<span class="c1"># some tasks may complete before the deferred can be added</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">task_id</span><span class="p">,</span> <span class="kc">False</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="n">task_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">date</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="n">d</span></div></div>
<span class="c1"># Create the soft singleton</span>
<span class="n">TASK_HANDLER</span> <span class="o">=</span> <span class="n">TaskHandler</span><span class="p">()</span>
</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 latest</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.scripts.taskhandler</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2024, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>