mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-30 15:04:18 +00:00
555 lines
48 KiB
HTML
555 lines
48 KiB
HTML
|
|
|||
|
|
|||
|
<!DOCTYPE html>
|
|||
|
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
|||
|
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
|||
|
<head>
|
|||
|
<meta charset="utf-8">
|
|||
|
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
|||
|
<title>Adding a Command to the Pack — Royalnet 5.4a2 documentation</title>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<script type="text/javascript" src="../_static/js/modernizr.min.js"></script>
|
|||
|
|
|||
|
|
|||
|
<script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
|||
|
<script type="text/javascript" src="../_static/jquery.js"></script>
|
|||
|
<script type="text/javascript" src="../_static/underscore.js"></script>
|
|||
|
<script type="text/javascript" src="../_static/doctools.js"></script>
|
|||
|
<script type="text/javascript" src="../_static/language_data.js"></script>
|
|||
|
|
|||
|
<script type="text/javascript" src="../_static/js/theme.js"></script>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
|
|||
|
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
|||
|
<link rel="stylesheet" href="../_static/rygdocs.css" type="text/css" />
|
|||
|
<link rel="index" title="Index" href="../genindex.html" />
|
|||
|
<link rel="search" title="Search" href="../search.html" />
|
|||
|
<link rel="next" title="Adding a Star to the Pack" href="star.html" />
|
|||
|
<link rel="prev" title="Creating a Royalnet Pack" href="pack.html" />
|
|||
|
</head>
|
|||
|
|
|||
|
<body class="wy-body-for-nav">
|
|||
|
|
|||
|
|
|||
|
<div class="wy-grid-for-nav">
|
|||
|
|
|||
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
|||
|
<div class="wy-side-scroll">
|
|||
|
<div class="wy-side-nav-search" >
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<a href="../index.html" class="icon icon-home"> Royalnet
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</a>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="version">
|
|||
|
5.4a2
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div role="search">
|
|||
|
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
|
|||
|
<input type="text" name="q" placeholder="Search docs" />
|
|||
|
<input type="hidden" name="check_keywords" value="yes" />
|
|||
|
<input type="hidden" name="area" value="default" />
|
|||
|
</form>
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<ul class="current">
|
|||
|
<li class="toctree-l1 current"><a class="reference internal" href="pack.html">Creating a Royalnet Pack</a><ul class="current">
|
|||
|
<li class="toctree-l2 current"><a class="current reference internal" href="#">Adding a Command to the Pack</a><ul>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#creating-a-new-command">Creating a new Command</a></li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#command-arguments">Command arguments</a><ul>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#direct-access">Direct access</a></li>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#optional-access">Optional access</a></li>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#full-string">Full string</a></li>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#regular-expressions">Regular expressions</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#raising-errors">Raising errors</a></li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#coroutines-and-slow-operations">Coroutines and slow operations</a></li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#delete-the-invoking-message">Delete the invoking message</a></li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#using-the-database">Using the database</a><ul>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#querying-the-database">Querying the database</a></li>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#adding-filters-to-the-query">Adding filters to the query</a></li>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#ordering-the-results-of-a-query">Ordering the results of a query</a></li>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#fetching-the-results-of-a-query">Fetching the results of a query</a></li>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#more-alchemy">More Alchemy</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#calling-events">Calling Events</a></li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#displaying-keyboards">Displaying Keyboards</a></li>
|
|||
|
<li class="toctree-l3"><a class="reference internal" href="#running-code-at-the-initialization-of-the-bot">Running code at the initialization of the bot</a><ul>
|
|||
|
<li class="toctree-l4"><a class="reference internal" href="#running-repeating-jobs">Running repeating jobs</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li class="toctree-l2"><a class="reference internal" href="star.html">Adding a Star to the Pack</a></li>
|
|||
|
<li class="toctree-l2"><a class="reference internal" href="event.html">Using Events</a></li>
|
|||
|
<li class="toctree-l2"><a class="reference internal" href="table.html">Using Tables and databases</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li class="toctree-l1"><a class="reference internal" href="../randomdiscoveries.html">Random discoveries</a></li>
|
|||
|
<li class="toctree-l1"><a class="reference internal" href="../apireference.html">API Reference</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</nav>
|
|||
|
|
|||
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
|||
|
|
|||
|
|
|||
|
<nav class="wy-nav-top" aria-label="top navigation">
|
|||
|
|
|||
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
|||
|
<a href="../index.html">Royalnet</a>
|
|||
|
|
|||
|
</nav>
|
|||
|
|
|||
|
|
|||
|
<div class="wy-nav-content">
|
|||
|
|
|||
|
<div class="rst-content">
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
|||
|
|
|||
|
<ul class="wy-breadcrumbs">
|
|||
|
|
|||
|
<li><a href="../index.html">Docs</a> »</li>
|
|||
|
|
|||
|
<li><a href="pack.html">Creating a Royalnet Pack</a> »</li>
|
|||
|
|
|||
|
<li>Adding a Command to the Pack</li>
|
|||
|
|
|||
|
|
|||
|
<li class="wy-breadcrumbs-aside">
|
|||
|
|
|||
|
|
|||
|
<a href="../_sources/packs/command.rst.txt" rel="nofollow"> View page source</a>
|
|||
|
|
|||
|
|
|||
|
</li>
|
|||
|
|
|||
|
</ul>
|
|||
|
|
|||
|
|
|||
|
<hr/>
|
|||
|
</div>
|
|||
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
|||
|
<div itemprop="articleBody">
|
|||
|
|
|||
|
<div class="section" id="adding-a-command-to-the-pack">
|
|||
|
<h1>Adding a Command to the Pack<a class="headerlink" href="#adding-a-command-to-the-pack" title="Permalink to this headline">¶</a></h1>
|
|||
|
<p>A Royalnet Command is a small script that is run whenever a specific message is sent to a Royalnet interface.</p>
|
|||
|
<p>A Command code looks like this:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">royalnet.commands</span> <span class="k">as</span> <span class="nn">rc</span>
|
|||
|
|
|||
|
<span class="k">class</span> <span class="nc">PingCommand</span><span class="p">(</span><span class="n">rc</span><span class="o">.</span><span class="n">Command</span><span class="p">):</span>
|
|||
|
<span class="n">name</span> <span class="o">=</span> <span class="s2">"ping"</span>
|
|||
|
|
|||
|
<span class="n">description</span> <span class="o">=</span> <span class="s2">"Play ping-pong with the bot."</span>
|
|||
|
|
|||
|
<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">interface</span><span class="p">):</span>
|
|||
|
<span class="c1"># This code is run just once, while the bot is starting</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="k">async</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">rc</span><span class="o">.</span><span class="n">CommandArgs</span><span class="p">,</span> <span class="n">data</span><span class="p">:</span> <span class="n">rc</span><span class="o">.</span><span class="n">CommandData</span><span class="p">):</span>
|
|||
|
<span class="c1"># This code is run every time the command is called</span>
|
|||
|
<span class="k">await</span> <span class="n">data</span><span class="o">.</span><span class="n">reply</span><span class="p">(</span><span class="s2">"Pong!"</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<div class="section" id="creating-a-new-command">
|
|||
|
<h2>Creating a new Command<a class="headerlink" href="#creating-a-new-command" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>First, think of a <code class="docutils literal notranslate"><span class="pre">name</span></code> for your command.
|
|||
|
It’s the name your command will be called with: for example, the “spaghetti” command will be called by typing <strong>/spaghetti</strong> in chat.
|
|||
|
Try to keep the name as short as possible, while staying specific enough so no other command will have the same name.</p>
|
|||
|
<p>Next, create a new Python file with the <code class="docutils literal notranslate"><span class="pre">name</span></code> you have thought of.
|
|||
|
The previously mentioned “spaghetti” command should have a file called <code class="docutils literal notranslate"><span class="pre">spaghetti.py</span></code>.</p>
|
|||
|
<p>Then, in the first row of the file, import the <a class="reference internal" href="../apireference.html#royalnet.commands.Command" title="royalnet.commands.Command"><code class="xref py py-class docutils literal notranslate"><span class="pre">Command</span></code></a> class from royalnet, and create a new class inheriting from it:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">royalnet.commands</span> <span class="k">as</span> <span class="nn">rc</span>
|
|||
|
|
|||
|
<span class="k">class</span> <span class="nc">SpaghettiCommand</span><span class="p">(</span><span class="n">rc</span><span class="o">.</span><span class="n">Command</span><span class="p">):</span>
|
|||
|
<span class="o">...</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Inside the class, override the attributes <code class="docutils literal notranslate"><span class="pre">name</span></code> and <code class="docutils literal notranslate"><span class="pre">description</span></code> with respectively the <strong>name of the command</strong> and a <strong>small description of what the command will do</strong>:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">royalnet.commands</span> <span class="k">as</span> <span class="nn">rc</span>
|
|||
|
|
|||
|
<span class="k">class</span> <span class="nc">SpaghettiCommand</span><span class="p">(</span><span class="n">rc</span><span class="o">.</span><span class="n">Command</span><span class="p">):</span>
|
|||
|
<span class="n">name</span> <span class="o">=</span> <span class="s2">"spaghetti"</span>
|
|||
|
|
|||
|
<span class="n">description</span> <span class="o">=</span> <span class="s2">"Send a spaghetti emoji in the chat."</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Now override the <a class="reference internal" href="../apireference.html#royalnet.commands.Command.run" title="royalnet.commands.Command.run"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Command.run()</span></code></a> method, adding the code you want the bot to run when the command is called.</p>
|
|||
|
<p>To send a message in the chat the command was called in, you can use the <a class="reference internal" href="../apireference.html#royalnet.commands.CommandData.reply" title="royalnet.commands.CommandData.reply"><code class="xref py py-meth docutils literal notranslate"><span class="pre">CommandData.reply()</span></code></a> coroutine:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">royalnet.commands</span> <span class="k">as</span> <span class="nn">rc</span>
|
|||
|
|
|||
|
<span class="k">class</span> <span class="nc">SpaghettiCommand</span><span class="p">(</span><span class="n">rc</span><span class="o">.</span><span class="n">Command</span><span class="p">):</span>
|
|||
|
<span class="n">name</span> <span class="o">=</span> <span class="s2">"spaghetti"</span>
|
|||
|
|
|||
|
<span class="n">description</span> <span class="o">=</span> <span class="s2">"Send a spaghetti emoji in the chat."</span>
|
|||
|
|
|||
|
<span class="k">async</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">rc</span><span class="o">.</span><span class="n">CommandArgs</span><span class="p">,</span> <span class="n">data</span><span class="p">:</span> <span class="n">rc</span><span class="o">.</span><span class="n">CommandData</span><span class="p">):</span>
|
|||
|
<span class="k">await</span> <span class="n">data</span><span class="o">.</span><span class="n">reply</span><span class="p">(</span><span class="s2">"🍝"</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>And… it’s done! The command is ready to be <a class="reference internal" href="pack.html"><span class="doc">added to your pack</span></a>!</p>
|
|||
|
</div>
|
|||
|
<div class="section" id="command-arguments">
|
|||
|
<h2>Command arguments<a class="headerlink" href="#command-arguments" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>A command can have some arguments passed by the user: for example, on Telegram an user may type <cite>/spaghetti carbonara al-dente</cite>
|
|||
|
to pass the <a class="reference external" href="https://docs.python.org/3.8/library/stdtypes.html#str" title="(in Python v3.8)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> <cite>“carbonara al-dente”</cite> to the command code.</p>
|
|||
|
<p>These arguments can be accessed in multiple ways through the <code class="docutils literal notranslate"><span class="pre">args</span></code> parameter passed to the <a class="reference internal" href="../apireference.html#royalnet.commands.Command.run" title="royalnet.commands.Command.run"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Command.run()</span></code></a>
|
|||
|
method.</p>
|
|||
|
<p>If you want your command to use arguments, override the <code class="docutils literal notranslate"><span class="pre">syntax</span></code> class attribute with a brief description of the
|
|||
|
syntax of your command, possibly using {curly braces} for required arguments and [square brackets] for optional
|
|||
|
ones.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">royalnet.commands</span> <span class="k">as</span> <span class="nn">rc</span>
|
|||
|
|
|||
|
<span class="k">class</span> <span class="nc">SpaghettiCommand</span><span class="p">(</span><span class="n">rc</span><span class="o">.</span><span class="n">Command</span><span class="p">):</span>
|
|||
|
<span class="n">name</span> <span class="o">=</span> <span class="s2">"spaghetti"</span>
|
|||
|
|
|||
|
<span class="n">description</span> <span class="o">=</span> <span class="s2">"Send a spaghetti emoji in the chat."</span>
|
|||
|
|
|||
|
<span class="n">syntax</span> <span class="o">=</span> <span class="s2">"(requestedpasta)"</span>
|
|||
|
|
|||
|
<span class="k">async</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">rc</span><span class="o">.</span><span class="n">CommandArgs</span><span class="p">,</span> <span class="n">data</span><span class="p">:</span> <span class="n">rc</span><span class="o">.</span><span class="n">CommandData</span><span class="p">):</span>
|
|||
|
<span class="k">await</span> <span class="n">data</span><span class="o">.</span><span class="n">reply</span><span class="p">(</span><span class="sa">f</span><span class="s2">"🍝 Here's your </span><span class="si">{args[0]}</span><span class="s2">!"</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<div class="section" id="direct-access">
|
|||
|
<h3>Direct access<a class="headerlink" href="#direct-access" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>You can consider arguments as if they were separated by spaces.</p>
|
|||
|
<p>You can then access command arguments directly by number as if the args object was a list of <a class="reference external" href="https://docs.python.org/3.8/library/stdtypes.html#str" title="(in Python v3.8)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a>.</p>
|
|||
|
<p>If you request an argument with a certain number, but the argument does not exist, an
|
|||
|
<a class="reference internal" href="../apireference.html#royalnet.commands.InvalidInputError" title="royalnet.commands.InvalidInputError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">InvalidInputError</span></code></a> is raised, making the arguments accessed in this way <strong>required</strong>.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
|||
|
<span class="c1"># "carbonara"</span>
|
|||
|
|
|||
|
<span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
|||
|
<span class="c1"># "al-dente"</span>
|
|||
|
|
|||
|
<span class="n">args</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
|||
|
<span class="c1"># raises InvalidInputError</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="optional-access">
|
|||
|
<h3>Optional access<a class="headerlink" href="#optional-access" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>If you don’t want arguments to be required, you can access them through the <a class="reference internal" href="../apireference.html#royalnet.commands.CommandArgs.optional" title="royalnet.commands.CommandArgs.optional"><code class="xref py py-meth docutils literal notranslate"><span class="pre">CommandArgs.optional()</span></code></a> method: it
|
|||
|
will return <code class="docutils literal notranslate"><span class="pre">None</span></code> if the argument wasn’t passed, making it <strong>optional</strong>.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="o">.</span><span class="n">optional</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
|||
|
<span class="c1"># "carbonara"</span>
|
|||
|
|
|||
|
<span class="n">args</span><span class="o">.</span><span class="n">optional</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
|||
|
<span class="c1"># "al-dente"</span>
|
|||
|
|
|||
|
<span class="n">args</span><span class="o">.</span><span class="n">optional</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
|
|||
|
<span class="c1"># None</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>You can specify a default result too, so that the method will return it instead of returning <code class="docutils literal notranslate"><span class="pre">None</span></code>:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="o">.</span><span class="n">optional</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">"banana"</span><span class="p">)</span>
|
|||
|
<span class="c1"># "banana"</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="full-string">
|
|||
|
<h3>Full string<a class="headerlink" href="#full-string" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>If you want the full argument string, you can use the <a class="reference internal" href="../apireference.html#royalnet.commands.CommandArgs.joined" title="royalnet.commands.CommandArgs.joined"><code class="xref py py-meth docutils literal notranslate"><span class="pre">CommandArgs.joined()</span></code></a> method.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="o">.</span><span class="n">joined</span><span class="p">()</span>
|
|||
|
<span class="c1"># "carbonara al-dente"</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>You can specify a minimum number of arguments too, so that an <a class="reference internal" href="../apireference.html#royalnet.commands.InvalidInputError" title="royalnet.commands.InvalidInputError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">InvalidInputError</span></code></a> will be
|
|||
|
raised if not enough arguments are present:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="o">.</span><span class="n">joined</span><span class="p">(</span><span class="n">require_at_least</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
|
|||
|
<span class="c1"># raises InvalidInputError</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="regular-expressions">
|
|||
|
<h3>Regular expressions<a class="headerlink" href="#regular-expressions" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>For more complex commands, you may want to get arguments through <a class="reference external" href="https://regexr.com/">regular expressions</a>.</p>
|
|||
|
<p>You can then use the <a class="reference internal" href="../apireference.html#royalnet.commands.CommandArgs.match" title="royalnet.commands.CommandArgs.match"><code class="xref py py-meth docutils literal notranslate"><span class="pre">CommandArgs.match()</span></code></a> method, which tries to match a pattern to the command argument string,
|
|||
|
which returns a tuple of the matched groups and raises an <a class="reference internal" href="../apireference.html#royalnet.commands.InvalidInputError" title="royalnet.commands.InvalidInputError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">InvalidInputError</span></code></a> if there is no match.</p>
|
|||
|
<p>To match a pattern, <a class="reference external" href="https://docs.python.org/3.8/library/re.html#re.match" title="(in Python v3.8)"><code class="xref py py-func docutils literal notranslate"><span class="pre">re.match()</span></code></a> is used, meaning that Python will try to match only at the beginning of the string.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">"(carb\w+)"</span><span class="p">)</span>
|
|||
|
<span class="c1"># ("carbonara",)</span>
|
|||
|
|
|||
|
<span class="n">args</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">"(al-\w+)"</span><span class="p">)</span>
|
|||
|
<span class="c1"># raises InvalidInputError</span>
|
|||
|
|
|||
|
<span class="n">args</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">"\s*(al-\w+)"</span><span class="p">)</span>
|
|||
|
<span class="c1"># ("al-dente",)</span>
|
|||
|
|
|||
|
<span class="n">args</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">"\s*(carb\w+)\s*(al-\w+)"</span><span class="p">)</span>
|
|||
|
<span class="c1"># ("carbonara", "al-dente")</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="raising-errors">
|
|||
|
<h2>Raising errors<a class="headerlink" href="#raising-errors" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>If you want to display an error message to the user, you can raise a <a class="reference internal" href="../apireference.html#royalnet.commands.CommandError" title="royalnet.commands.CommandError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">CommandError</span></code></a> using the error message as argument:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="ow">not</span> <span class="n">kitchen</span><span class="o">.</span><span class="n">is_open</span><span class="p">():</span>
|
|||
|
<span class="k">raise</span> <span class="n">CommandError</span><span class="p">(</span><span class="s2">"The kitchen is closed. Come back later!"</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>There are some subclasses of <a class="reference internal" href="../apireference.html#royalnet.commands.CommandError" title="royalnet.commands.CommandError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">CommandError</span></code></a> that can be used for some more specific cases:</p>
|
|||
|
<dl class="simple">
|
|||
|
<dt><a class="reference internal" href="../apireference.html#royalnet.commands.UserError" title="royalnet.commands.UserError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">UserError</span></code></a></dt><dd><p>The user did something wrong, it is not a problem with the bot.</p>
|
|||
|
</dd>
|
|||
|
<dt><a class="reference internal" href="../apireference.html#royalnet.commands.InvalidInputError" title="royalnet.commands.InvalidInputError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">InvalidInputError</span></code></a></dt><dd><p>The arguments the user passed to the command by the user are invalid.
|
|||
|
Displays the command syntax in the error message.</p>
|
|||
|
</dd>
|
|||
|
<dt><a class="reference internal" href="../apireference.html#royalnet.commands.UnsupportedError" title="royalnet.commands.UnsupportedError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">UnsupportedError</span></code></a></dt><dd><p>The command is not supported on the interface it is being called.</p>
|
|||
|
</dd>
|
|||
|
<dt><a class="reference internal" href="../apireference.html#royalnet.commands.ConfigurationError" title="royalnet.commands.ConfigurationError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ConfigurationError</span></code></a></dt><dd><p>The <code class="docutils literal notranslate"><span class="pre">config.toml</span></code> file was misconfigured (a value is missing or invalid).</p>
|
|||
|
</dd>
|
|||
|
<dt><a class="reference internal" href="../apireference.html#royalnet.commands.ExternalError" title="royalnet.commands.ExternalError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ExternalError</span></code></a></dt><dd><p>An external API the command depends on is unavailable or returned an error.</p>
|
|||
|
</dd>
|
|||
|
<dt><a class="reference internal" href="../apireference.html#royalnet.commands.ProgramError" title="royalnet.commands.ProgramError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ProgramError</span></code></a></dt><dd><p>An error caused by a programming mistake. Equivalent to <a class="reference external" href="https://docs.python.org/3.8/library/exceptions.html#AssertionError" title="(in Python v3.8)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">AssertionError</span></code></a>, but includes a message to facilitate debugging.</p>
|
|||
|
</dd>
|
|||
|
</dl>
|
|||
|
</div>
|
|||
|
<div class="section" id="coroutines-and-slow-operations">
|
|||
|
<h2>Coroutines and slow operations<a class="headerlink" href="#coroutines-and-slow-operations" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>You may have noticed that in the previous examples we used <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">data.reply("🍝")</span></code> instead of just <code class="docutils literal notranslate"><span class="pre">data.reply("🍝")</span></code>.</p>
|
|||
|
<p>This is because <a class="reference internal" href="../apireference.html#royalnet.commands.CommandData.reply" title="royalnet.commands.CommandData.reply"><code class="xref py py-meth docutils literal notranslate"><span class="pre">CommandData.reply()</span></code></a> isn’t a simple method: it is a coroutine, a special kind of function that
|
|||
|
can be executed separately from the rest of the code, allowing the bot to do other things in the meantime.</p>
|
|||
|
<p>By adding the <code class="docutils literal notranslate"><span class="pre">await</span></code> keyword before the <code class="docutils literal notranslate"><span class="pre">data.reply("🍝")</span></code>, we tell the bot that it can do other things, like
|
|||
|
receiving new messages, while the message is being sent.</p>
|
|||
|
<p>You should avoid running slow normal functions inside bot commands, as they will stop the bot from working until they
|
|||
|
are finished and may cause bugs in other parts of the code!</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
|
|||
|
<span class="c1"># Don't do this!</span>
|
|||
|
<span class="n">image</span> <span class="o">=</span> <span class="n">download_1_terabyte_of_spaghetti</span><span class="p">(</span><span class="s2">"right_now"</span><span class="p">,</span> <span class="n">from</span><span class="o">=</span><span class="s2">"italy"</span><span class="p">)</span>
|
|||
|
<span class="o">...</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>If the slow function you want does not cause any side effect, you can wrap it with the <a class="reference internal" href="../apireference.html#royalnet.utils.asyncify" title="royalnet.utils.asyncify"><code class="xref py py-func docutils literal notranslate"><span class="pre">royalnet.utils.asyncify()</span></code></a>
|
|||
|
function:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
|
|||
|
<span class="c1"># If the called function has no side effect, you can do this!</span>
|
|||
|
<span class="n">image</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">download_1_terabyte_of_spaghetti</span><span class="p">,</span> <span class="s2">"right_now"</span><span class="p">,</span> <span class="n">from</span><span class="o">=</span><span class="s2">"italy"</span><span class="p">)</span>
|
|||
|
<span class="o">...</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Avoid using <a class="reference external" href="https://docs.python.org/3.8/library/time.html#time.sleep" title="(in Python v3.8)"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.sleep()</span></code></a> function, as it is considered a slow operation: use instead <a class="reference external" href="https://docs.python.org/3.8/library/asyncio-task.html#asyncio.sleep" title="(in Python v3.8)"><code class="xref py py-func docutils literal notranslate"><span class="pre">asyncio.sleep()</span></code></a>,
|
|||
|
a coroutine that does the same exact thing but in an asyncronous way.</p>
|
|||
|
</div>
|
|||
|
<div class="section" id="delete-the-invoking-message">
|
|||
|
<h2>Delete the invoking message<a class="headerlink" href="#delete-the-invoking-message" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>The invoking message of a command is the message that the user sent that the bot recognized as a command; for example,
|
|||
|
the message <code class="docutils literal notranslate"><span class="pre">/spaghetti</span> <span class="pre">carbonara</span></code> is the invoking message for the <code class="docutils literal notranslate"><span class="pre">spaghetti</span></code> command run.</p>
|
|||
|
<p>You can have the bot delete the invoking message for a command by calling the <a class="reference internal" href="../apireference.html#royalnet.commands.CommandData.delete_invoking" title="royalnet.commands.CommandData.delete_invoking"><code class="xref py py-class docutils literal notranslate"><span class="pre">CommandData.delete_invoking</span></code></a>
|
|||
|
method:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
|
|||
|
<span class="k">await</span> <span class="n">data</span><span class="o">.</span><span class="n">delete_invoking</span><span class="p">()</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Not all interfaces support deleting messages; by default, if the interface does not support deletions, the call is
|
|||
|
ignored.</p>
|
|||
|
<p>You can have the method raise an error if the message can’t be deleted by setting the <code class="docutils literal notranslate"><span class="pre">error_if_unavailable</span></code> parameter
|
|||
|
to True:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
|
|||
|
<span class="k">try</span><span class="p">:</span>
|
|||
|
<span class="k">await</span> <span class="n">data</span><span class="o">.</span><span class="n">delete_invoking</span><span class="p">(</span><span class="n">error_if_unavailable</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|||
|
<span class="k">except</span> <span class="n">royalnet</span><span class="o">.</span><span class="n">error</span><span class="o">.</span><span class="n">UnsupportedError</span><span class="p">:</span>
|
|||
|
<span class="k">await</span> <span class="n">data</span><span class="o">.</span><span class="n">reply</span><span class="p">(</span><span class="s2">"🚫 The message could not be deleted."</span><span class="p">)</span>
|
|||
|
<span class="k">else</span><span class="p">:</span>
|
|||
|
<span class="k">await</span> <span class="n">data</span><span class="o">.</span><span class="n">reply</span><span class="p">(</span><span class="s2">"✅ The message was deleted!"</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="using-the-database">
|
|||
|
<h2>Using the database<a class="headerlink" href="#using-the-database" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>Bots can be connected to a PostgreSQL database through a special SQLAlchemy interface called
|
|||
|
<a class="reference internal" href="../apireference.html#royalnet.alchemy.Alchemy" title="royalnet.alchemy.Alchemy"><code class="xref py py-class docutils literal notranslate"><span class="pre">royalnet.alchemy.Alchemy</span></code></a>.</p>
|
|||
|
<p>If the connection is established, the <code class="docutils literal notranslate"><span class="pre">self.alchemy</span></code> and <code class="docutils literal notranslate"><span class="pre">data.session</span></code> fields will be
|
|||
|
available for use in commands.</p>
|
|||
|
<p><code class="docutils literal notranslate"><span class="pre">self.alchemy</span></code> is an instance of <a class="reference internal" href="../apireference.html#royalnet.alchemy.Alchemy" title="royalnet.alchemy.Alchemy"><code class="xref py py-class docutils literal notranslate"><span class="pre">royalnet.alchemy.Alchemy</span></code></a>, which contains the
|
|||
|
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/connections.html#sqlalchemy.engine.Engine" title="(in SQLAlchemy v1.3)"><code class="xref py py-class docutils literal notranslate"><span class="pre">sqlalchemy.engine.Engine</span></code></a>, metadata and tables, while <code class="docutils literal notranslate"><span class="pre">data.session</span></code> is a
|
|||
|
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session" title="(in SQLAlchemy v1.3)"><code class="xref py py-class docutils literal notranslate"><span class="pre">sqlalchemy.orm.session.Session</span></code></a>, and can be interacted in the same way as one.</p>
|
|||
|
<div class="section" id="querying-the-database">
|
|||
|
<h3>Querying the database<a class="headerlink" href="#querying-the-database" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>You can <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query" title="(in SQLAlchemy v1.3)"><code class="xref py py-class docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query</span></code></a> the database using the SQLAlchemy ORM.</p>
|
|||
|
<p>The SQLAlchemy tables can be found inside <a class="reference internal" href="../apireference.html#royalnet.alchemy.Alchemy" title="royalnet.alchemy.Alchemy"><code class="xref py py-class docutils literal notranslate"><span class="pre">royalnet.alchemy.Alchemy</span></code></a> with the <a class="reference internal" href="../apireference.html#royalnet.alchemy.Alchemy.get" title="royalnet.alchemy.Alchemy.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">royalnet.alchemy.Alchemy.get()</span></code></a> method:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">royalnet.backpack.tables</span> <span class="k">as</span> <span class="nn">rbt</span>
|
|||
|
<span class="n">User</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">alchemy</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">rbt</span><span class="o">.</span><span class="n">User</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="adding-filters-to-the-query">
|
|||
|
<h3>Adding filters to the query<a class="headerlink" href="#adding-filters-to-the-query" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>You can filter the query results with the <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.filter" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.filter()</span></code></a> method.</p>
|
|||
|
<div class="admonition note">
|
|||
|
<p class="admonition-title">Note</p>
|
|||
|
<p>Remember to always use a table column as first comparision element, as it won’t work otherwise.</p>
|
|||
|
</div>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">role</span> <span class="o">==</span> <span class="s2">"Member"</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="ordering-the-results-of-a-query">
|
|||
|
<h3>Ordering the results of a query<a class="headerlink" href="#ordering-the-results-of-a-query" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>You can order the query results in <strong>ascending order</strong> with the <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.order_by" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.order_by()</span></code></a> method.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Additionally, you can append the <cite>.desc()</cite> method to a table column to sort in <strong>descending order</strong>:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">username</span><span class="o">.</span><span class="n">desc</span><span class="p">())</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="fetching-the-results-of-a-query">
|
|||
|
<h3>Fetching the results of a query<a class="headerlink" href="#fetching-the-results-of-a-query" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>You can fetch the query results with the <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.all" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.all()</span></code></a>,
|
|||
|
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.first" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.first()</span></code></a>, <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one()</span></code></a> and
|
|||
|
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one_or_none" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one_or_none()</span></code></a> methods.</p>
|
|||
|
<p>Remember to use <a class="reference internal" href="../apireference.html#royalnet.utils.asyncify" title="royalnet.utils.asyncify"><code class="xref py py-func docutils literal notranslate"><span class="pre">royalnet.utils.asyncify()</span></code></a> when fetching results, as it may take a while!</p>
|
|||
|
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.all" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.all()</span></code></a> if you want a <a class="reference external" href="https://docs.python.org/3.8/library/stdtypes.html#list" title="(in Python v3.8)"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a> of <strong>all results</strong>:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">results</span><span class="p">:</span> <span class="nb">list</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">all</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.first" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.first()</span></code></a> if you want <strong>the first result</strong> of the list, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if
|
|||
|
there are no results:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">first</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one()</span></code></a> if you expect to have <strong>a single result</strong>, and you want the command to
|
|||
|
raise an error if any different number of results is returned:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">:</span> <span class="o">...</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">one</span><span class="p">)</span> <span class="c1"># Raises an error if there are no results or more than a result.</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one_or_none" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one_or_none()</span></code></a> if you expect to have <strong>a single result</strong>, or <strong>nothing</strong>, and
|
|||
|
if you want the command to raise an error if the number of results is greater than one.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">one_or_none</span><span class="p">)</span> <span class="c1"># Raises an error if there is more than a result.</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="more-alchemy">
|
|||
|
<h3>More Alchemy<a class="headerlink" href="#more-alchemy" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>You can read more about <code class="xref py py-mod docutils literal notranslate"><span class="pre">sqlalchemy</span></code> at their <a class="reference external" href="https://www.sqlalchemy.org/">website</a>.</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="section" id="calling-events">
|
|||
|
<h2>Calling Events<a class="headerlink" href="#calling-events" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>This section is not documented yet.</p>
|
|||
|
</div>
|
|||
|
<div class="section" id="displaying-keyboards">
|
|||
|
<h2>Displaying Keyboards<a class="headerlink" href="#displaying-keyboards" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>This section is not documented yet.</p>
|
|||
|
</div>
|
|||
|
<div class="section" id="running-code-at-the-initialization-of-the-bot">
|
|||
|
<h2>Running code at the initialization of the bot<a class="headerlink" href="#running-code-at-the-initialization-of-the-bot" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>This section is not documented yet.</p>
|
|||
|
<div class="section" id="running-repeating-jobs">
|
|||
|
<h3>Running repeating jobs<a class="headerlink" href="#running-repeating-jobs" title="Permalink to this headline">¶</a></h3>
|
|||
|
<p>This section is not documented yet.</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
</div>
|
|||
|
<footer>
|
|||
|
|
|||
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
|||
|
|
|||
|
<a href="star.html" class="btn btn-neutral float-right" title="Adding a Star to the Pack" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
|
|||
|
|
|||
|
|
|||
|
<a href="pack.html" class="btn btn-neutral float-left" title="Creating a Royalnet Pack" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
<hr/>
|
|||
|
|
|||
|
<div role="contentinfo">
|
|||
|
<p>
|
|||
|
© Copyright 2019, Stefano Pigozzi
|
|||
|
|
|||
|
</p>
|
|||
|
</div>
|
|||
|
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
|||
|
|
|||
|
</footer>
|
|||
|
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</section>
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<script type="text/javascript">
|
|||
|
jQuery(function () {
|
|||
|
SphinxRtdTheme.Navigation.enable(true);
|
|||
|
});
|
|||
|
</script>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</body>
|
|||
|
</html>
|