1021 lines
125 KiB
HTML
1021 lines
125 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Commands</title>
|
||
<!-- end extra head -->
|
||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
|
||
<link rel="stylesheet" type="text/css" href="../../_static/basic.css" />
|
||
<link rel="stylesheet" href="../../_static/style.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../_static/codeblocks.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../_static/icons.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
|
||
<script data-url_root="../../" id="documentation_options" 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/custom.js"></script>
|
||
<script src="../../_static/settings.js"></script>
|
||
<script src="../../_static/copy.js"></script>
|
||
<script src="../../_static/sidebar.js"></script>
|
||
<link rel="shortcut icon" href="../../_static/discord_py_logo.ico"/>
|
||
<link rel="index" title="Index" href="../../genindex.html" />
|
||
<link rel="search" title="Search" href="../../search.html" />
|
||
<link rel="next" title="Cogs" href="cogs.html" />
|
||
<link rel="prev" title="discord.ext.commands – Bot commands framework" href="index.html" />
|
||
</head>
|
||
<body>
|
||
<div class="main-grid">
|
||
<header class="grid-item">
|
||
<nav>
|
||
<a href="../../index.html" class="main-heading">discord.py</a>
|
||
<a href="https://github.com/Rapptz/discord.py" title="GitHub"><span class="material-icons custom-icons">github</span></a>
|
||
<a href="https://discord.gg/TvqYBrGXEm" title="Discord"><span class="material-icons custom-icons">discord</span></a>
|
||
<a href="../../faq.html" title="FAQ"><span class="material-icons">help_center</span></a>
|
||
<a onclick="mobileSearch.open();" title="Search" id="open-search" class="mobile-only"><span class="material-icons">search</span></a>
|
||
<a onclick="mobileSearch.close();" title="Close" id="close-search" class="mobile-only" hidden><span class="material-icons">close</span></a>
|
||
</nav>
|
||
<nav class="mobile-only">
|
||
<form role="search" class="search" action="../../search.html" method="get">
|
||
<div class="search-wrapper">
|
||
<input type="search" name="q" placeholder="Search documentation" />
|
||
<button type="submit">
|
||
<span class="material-icons">search</span>
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</nav>
|
||
</header>
|
||
<div class="sub-header grid-item">
|
||
<label for="documentation_select">View Documentation For</label>
|
||
<select id="documentation_select" onchange="window.location = this.value;">
|
||
<option value="../../index.html">discord</option>
|
||
<option value="index.html" selected>discord.ext.commands</option>
|
||
<option value="../tasks/index.html" >discord.ext.tasks</option>
|
||
</select>
|
||
<form role="search" class="search" action="../../search.html" method="get">
|
||
<div class="search-wrapper">
|
||
<input type="search" name="q" placeholder="Search documentation" />
|
||
<button type="submit">
|
||
<span class="material-icons">search</span>
|
||
</button>
|
||
</div>
|
||
</form>
|
||
<a accesskey="S" class="settings" onclick="settingsModal.open();"><span class="material-icons">settings</span></a>
|
||
</div>
|
||
<aside class="grid-item">
|
||
<span id="hamburger-toggle">
|
||
<span class="material-icons">menu</span>
|
||
</span>
|
||
<span id="settings-toggle" class="settings" onclick="settingsModal.open();">
|
||
<span class="material-icons">settings</span>
|
||
</span>
|
||
<div id="sidebar">
|
||
<h3><a href="../../index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Commands</a><ul>
|
||
<li><a class="reference internal" href="#parameters">Parameters</a><ul>
|
||
<li><a class="reference internal" href="#positional">Positional</a></li>
|
||
<li><a class="reference internal" href="#variable">Variable</a></li>
|
||
<li><a class="reference internal" href="#keyword-only-arguments">Keyword-Only Arguments</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#invocation-context">Invocation Context</a></li>
|
||
<li><a class="reference internal" href="#converters">Converters</a><ul>
|
||
<li><a class="reference internal" href="#basic-converters">Basic Converters</a><ul>
|
||
<li><a class="reference internal" href="#bool">bool</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#advanced-converters">Advanced Converters</a></li>
|
||
<li><a class="reference internal" href="#inline-advanced-converters">Inline Advanced Converters</a></li>
|
||
<li><a class="reference internal" href="#discord-converters">Discord Converters</a></li>
|
||
<li><a class="reference internal" href="#special-converters">Special Converters</a><ul>
|
||
<li><a class="reference internal" href="#typing-union">typing.Union</a></li>
|
||
<li><a class="reference internal" href="#typing-optional">typing.Optional</a></li>
|
||
<li><a class="reference internal" href="#typing-literal">typing.Literal</a></li>
|
||
<li><a class="reference internal" href="#greedy">Greedy</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#flagconverter">FlagConverter</a><ul>
|
||
<li><a class="reference internal" href="#typing-list">typing.List</a></li>
|
||
<li><a class="reference internal" href="#typing-tuple">typing.Tuple</a></li>
|
||
<li><a class="reference internal" href="#typing-dict">typing.Dict</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#error-handling">Error Handling</a></li>
|
||
<li><a class="reference internal" href="#checks">Checks</a><ul>
|
||
<li><a class="reference internal" href="#global-checks">Global Checks</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
</div>
|
||
</aside>
|
||
<main class="grid-item" role="main">
|
||
|
||
<section id="commands">
|
||
<span id="ext-commands-commands"></span><h1>Commands<a class="headerlink" href="#commands" title="Permalink to this headline">¶</a></h1>
|
||
<p>One of the most appealing aspects of the command extension is how easy it is to define commands and
|
||
how you can arbitrarily nest groups and commands to have a rich sub-command system.</p>
|
||
<p>Commands are defined by attaching it to a regular Python function. The command is then invoked by the user using a similar
|
||
signature to the Python function.</p>
|
||
<p>For example, in the given command definition:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">arg</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>With the following prefix (<code class="docutils literal notranslate"><span class="pre">$</span></code>), it would be invoked by the user via:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>$foo abc
|
||
</pre></div>
|
||
</div>
|
||
<p>A command must always have at least one parameter, <code class="docutils literal notranslate"><span class="pre">ctx</span></code>, which is the <a class="reference internal" href="api.html#discord.ext.commands.Context" title="discord.ext.commands.Context"><code class="xref py py-class docutils literal notranslate"><span class="pre">Context</span></code></a> as the first one.</p>
|
||
<p>There are two ways of registering a command. The first one is by using <a class="reference internal" href="api.html#discord.ext.commands.Bot.command" title="discord.ext.commands.Bot.command"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Bot.command()</span></code></a> decorator,
|
||
as seen in the example above. The second is using the <a class="reference internal" href="api.html#discord.ext.commands.command" title="discord.ext.commands.command"><code class="xref py py-func docutils literal notranslate"><span class="pre">command()</span></code></a> decorator followed by
|
||
<a class="reference internal" href="api.html#discord.ext.commands.Bot.add_command" title="discord.ext.commands.Bot.add_command"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Bot.add_command()</span></code></a> on the instance.</p>
|
||
<p>Essentially, these two are equivalent:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">discord.ext</span> <span class="kn">import</span> <span class="n">commands</span>
|
||
|
||
<span class="n">bot</span> <span class="o">=</span> <span class="n">commands</span><span class="o">.</span><span class="n">Bot</span><span class="p">(</span><span class="n">command_prefix</span><span class="o">=</span><span class="s1">'$'</span><span class="p">)</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
|
||
<span class="c1"># or:</span>
|
||
|
||
<span class="nd">@commands</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
|
||
<span class="n">bot</span><span class="o">.</span><span class="n">add_command</span><span class="p">(</span><span class="n">test</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Since the <a class="reference internal" href="api.html#discord.ext.commands.Bot.command" title="discord.ext.commands.Bot.command"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Bot.command()</span></code></a> decorator is shorter and easier to comprehend, it will be the one used throughout the
|
||
documentation here.</p>
|
||
<p>Any parameter that is accepted by the <a class="reference internal" href="api.html#discord.ext.commands.Command" title="discord.ext.commands.Command"><code class="xref py py-class docutils literal notranslate"><span class="pre">Command</span></code></a> constructor can be passed into the decorator. For example, to change
|
||
the name to something other than the function would be as simple as doing this:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</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="s1">'list'</span><span class="p">)</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">_list</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">arg</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="parameters">
|
||
<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
|
||
<p>Since we define commands by making Python functions, we also define the argument passing behaviour by the function
|
||
parameters.</p>
|
||
<p>Certain parameter types do different things in the user side and most forms of parameter types are supported.</p>
|
||
<section id="positional">
|
||
<h3>Positional<a class="headerlink" href="#positional" title="Permalink to this headline">¶</a></h3>
|
||
<p>The most basic form of parameter passing is the positional parameter. This is where we pass a parameter as-is:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">arg</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>On the bot using side, you can provide positional arguments by just passing a regular string:</p>
|
||
<img alt="../../_images/positional1.png" src="../../_images/positional1.png" />
|
||
<p>To make use of a word with spaces in between, you should quote it:</p>
|
||
<img alt="../../_images/positional2.png" src="../../_images/positional2.png" />
|
||
<p>As a note of warning, if you omit the quotes, you will only get the first word:</p>
|
||
<img alt="../../_images/positional3.png" src="../../_images/positional3.png" />
|
||
<p>Since positional arguments are just regular Python arguments, you can have as many as you want:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'You passed </span><span class="si">{</span><span class="n">arg1</span><span class="si">}</span><span class="s1"> and </span><span class="si">{</span><span class="n">arg2</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="variable">
|
||
<h3>Variable<a class="headerlink" href="#variable" title="Permalink to this headline">¶</a></h3>
|
||
<p>Sometimes you want users to pass in an undetermined number of parameters. The library supports this
|
||
similar to how variable list parameters are done in Python:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
|
||
<span class="n">arguments</span> <span class="o">=</span> <span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s1"> arguments: </span><span class="si">{</span><span class="n">arguments</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This allows our user to accept either one or many arguments as they please. This works similar to positional arguments,
|
||
so multi-word parameters should be quoted.</p>
|
||
<p>For example, on the bot side:</p>
|
||
<img alt="../../_images/variable1.png" src="../../_images/variable1.png" />
|
||
<p>If the user wants to input a multi-word argument, they have to quote it like earlier:</p>
|
||
<img alt="../../_images/variable2.png" src="../../_images/variable2.png" />
|
||
<p>Do note that similar to the Python function behaviour, a user can technically pass no arguments
|
||
at all:</p>
|
||
<img alt="../../_images/variable3.png" src="../../_images/variable3.png" />
|
||
<p>Since the <code class="docutils literal notranslate"><span class="pre">args</span></code> variable is a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#tuple" title="(in Python v3.9)"><code class="docutils literal notranslate"><span class="pre">tuple</span></code></a>,
|
||
you can do anything you would usually do with one.</p>
|
||
<div class="admonition-slash-command-only admonition">
|
||
<p class="admonition-title">Slash Command Only</p>
|
||
<p>This functionally is currently not supported by the slash command API, so is turned into
|
||
a single <code class="docutils literal notranslate"><span class="pre">STRING</span></code> parameter on discord’s end which we do our own parsing on.</p>
|
||
</div>
|
||
</section>
|
||
<section id="keyword-only-arguments">
|
||
<h3>Keyword-Only Arguments<a class="headerlink" href="#keyword-only-arguments" title="Permalink to this headline">¶</a></h3>
|
||
<p>When you want to handle parsing of the argument yourself or do not feel like you want to wrap multi-word user input into
|
||
quotes, you can ask the library to give you the rest as a single argument. We do this by using a <strong>keyword-only argument</strong>,
|
||
seen below:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">arg</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>You can only have one keyword-only argument due to parsing ambiguities.</p>
|
||
</div>
|
||
<p>On the bot side, we do not need to quote input with spaces:</p>
|
||
<img alt="../../_images/keyword1.png" src="../../_images/keyword1.png" />
|
||
<p>Do keep in mind that wrapping it in quotes leaves it as-is:</p>
|
||
<img alt="../../_images/keyword2.png" src="../../_images/keyword2.png" />
|
||
<p>By default, the keyword-only arguments are stripped of white space to make it easier to work with. This behaviour can be
|
||
toggled by the <a class="reference internal" href="api.html#discord.ext.commands.Command.rest_is_raw" title="discord.ext.commands.Command.rest_is_raw"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Command.rest_is_raw</span></code></a> argument in the decorator.</p>
|
||
</section>
|
||
</section>
|
||
<section id="invocation-context">
|
||
<span id="ext-commands-context"></span><h2>Invocation Context<a class="headerlink" href="#invocation-context" title="Permalink to this headline">¶</a></h2>
|
||
<p>As seen earlier, every command must take at least a single parameter, called the <a class="reference internal" href="api.html#discord.ext.commands.Context" title="discord.ext.commands.Context"><code class="xref py py-class docutils literal notranslate"><span class="pre">Context</span></code></a>.</p>
|
||
<p>This parameter gives you access to something called the “invocation context”. Essentially all the information you need to
|
||
know how the command was executed. It contains a lot of useful information:</p>
|
||
<ul class="simple">
|
||
<li><p><a class="reference internal" href="api.html#discord.ext.commands.Context.guild" title="discord.ext.commands.Context.guild"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Context.guild</span></code></a> to fetch the <a class="reference internal" href="../../api.html#discord.Guild" title="discord.Guild"><code class="xref py py-class docutils literal notranslate"><span class="pre">Guild</span></code></a> of the command, if any.</p></li>
|
||
<li><p><a class="reference internal" href="api.html#discord.ext.commands.Context.message" title="discord.ext.commands.Context.message"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Context.message</span></code></a> to fetch the <a class="reference internal" href="../../api.html#discord.Message" title="discord.Message"><code class="xref py py-class docutils literal notranslate"><span class="pre">Message</span></code></a> of the command.</p></li>
|
||
<li><p><a class="reference internal" href="api.html#discord.ext.commands.Context.author" title="discord.ext.commands.Context.author"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Context.author</span></code></a> to fetch the <a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">Member</span></code></a> or <a class="reference internal" href="../../api.html#discord.User" title="discord.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> that called the command.</p></li>
|
||
<li><p><a class="reference internal" href="api.html#discord.ext.commands.Context.send" title="discord.ext.commands.Context.send"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Context.send()</span></code></a> to send a message to the channel the command was used in.</p></li>
|
||
</ul>
|
||
<p>The context implements the <a class="reference internal" href="../../api.html#discord.abc.Messageable" title="discord.abc.Messageable"><code class="xref py py-class docutils literal notranslate"><span class="pre">abc.Messageable</span></code></a> interface, so anything you can do on a <a class="reference internal" href="../../api.html#discord.abc.Messageable" title="discord.abc.Messageable"><code class="xref py py-class docutils literal notranslate"><span class="pre">abc.Messageable</span></code></a> you
|
||
can do on the <a class="reference internal" href="api.html#discord.ext.commands.Context" title="discord.ext.commands.Context"><code class="xref py py-class docutils literal notranslate"><span class="pre">Context</span></code></a>.</p>
|
||
<div class="admonition-slash-command-only admonition">
|
||
<p class="admonition-title">Slash Command Only</p>
|
||
<p><a class="reference internal" href="api.html#discord.ext.commands.Context.message" title="discord.ext.commands.Context.message"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Context.message</span></code></a> will be fake if in a slash command, it is not
|
||
recommended to access if <code class="xref py py-attr docutils literal notranslate"><span class="pre">Context.interaction</span></code> is not None as most
|
||
methods will error due to the message not actually existing.</p>
|
||
</div>
|
||
</section>
|
||
<section id="converters">
|
||
<h2>Converters<a class="headerlink" href="#converters" title="Permalink to this headline">¶</a></h2>
|
||
<p>Adding bot arguments with function parameters is only the first step in defining your bot’s command interface. To actually
|
||
make use of the arguments, we usually want to convert the data into a target type. We call these
|
||
<a class="reference internal" href="api.html#ext-commands-api-converters"><span class="std std-ref">Converters</span></a>.</p>
|
||
<p>Converters come in a few flavours:</p>
|
||
<ul>
|
||
<li><p>A regular callable object that takes an argument as a sole parameter and returns a different type.</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li><p>These range from your own function, to something like <a class="reference external" href="https://docs.python.org/3/library/functions.html#bool" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code></a> or <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>.</p></li>
|
||
</ul>
|
||
</div></blockquote>
|
||
</li>
|
||
<li><p>A custom class that inherits from <a class="reference internal" href="api.html#discord.ext.commands.Converter" title="discord.ext.commands.Converter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Converter</span></code></a>.</p></li>
|
||
</ul>
|
||
<section id="basic-converters">
|
||
<span id="ext-commands-basic-converters"></span><h3>Basic Converters<a class="headerlink" href="#basic-converters" title="Permalink to this headline">¶</a></h3>
|
||
<p>At its core, a basic converter is a callable that takes in an argument and turns it into something else.</p>
|
||
<p>For example, if we wanted to add two numbers together, we could request that they are turned into integers
|
||
for us by specifying the converter:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>We specify converters by using something called a <strong>function annotation</strong>. This is a Python 3 exclusive feature that was
|
||
introduced in <span class="target" id="index-0"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-3107"><strong>PEP 3107</strong></a>.</p>
|
||
<p>This works with any callable, such as a function that would convert a string to all upper-case:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">to_upper</span><span class="p">(</span><span class="n">argument</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">argument</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">up</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="n">to_upper</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="bool">
|
||
<h4>bool<a class="headerlink" href="#bool" title="Permalink to this headline">¶</a></h4>
|
||
<p>Unlike the other basic converters, the <a class="reference external" href="https://docs.python.org/3/library/functions.html#bool" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code></a> converter is treated slightly different. Instead of casting directly to the <a class="reference external" href="https://docs.python.org/3/library/functions.html#bool" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code></a> type, which would result in any non-empty argument returning <code class="docutils literal notranslate"><span class="pre">True</span></code>, it instead evaluates the argument as <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code> based on its given content:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">lowered</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">'yes'</span><span class="p">,</span> <span class="s1">'y'</span><span class="p">,</span> <span class="s1">'true'</span><span class="p">,</span> <span class="s1">'t'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">,</span> <span class="s1">'enable'</span><span class="p">,</span> <span class="s1">'on'</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="kc">True</span>
|
||
<span class="k">elif</span> <span class="n">lowered</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">'no'</span><span class="p">,</span> <span class="s1">'n'</span><span class="p">,</span> <span class="s1">'false'</span><span class="p">,</span> <span class="s1">'f'</span><span class="p">,</span> <span class="s1">'0'</span><span class="p">,</span> <span class="s1">'disable'</span><span class="p">,</span> <span class="s1">'off'</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="kc">False</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="advanced-converters">
|
||
<span id="ext-commands-adv-converters"></span><h3>Advanced Converters<a class="headerlink" href="#advanced-converters" title="Permalink to this headline">¶</a></h3>
|
||
<p>Sometimes a basic converter doesn’t have enough information that we need. For example, sometimes we want to get some
|
||
information from the <a class="reference internal" href="../../api.html#discord.Message" title="discord.Message"><code class="xref py py-class docutils literal notranslate"><span class="pre">Message</span></code></a> that called the command or we want to do some asynchronous processing.</p>
|
||
<p>For this, the library provides the <a class="reference internal" href="api.html#discord.ext.commands.Converter" title="discord.ext.commands.Converter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Converter</span></code></a> interface. This allows you to have access to the
|
||
<a class="reference internal" href="api.html#discord.ext.commands.Context" title="discord.ext.commands.Context"><code class="xref py py-class docutils literal notranslate"><span class="pre">Context</span></code></a> and have the callable be asynchronous. Defining a custom converter using this interface requires
|
||
overriding a single method, <a class="reference internal" href="api.html#discord.ext.commands.Converter.convert" title="discord.ext.commands.Converter.convert"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Converter.convert()</span></code></a>.</p>
|
||
<p>An example converter:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">random</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Slapper</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">Converter</span><span class="p">):</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">convert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ctx</span><span class="p">,</span> <span class="n">argument</span><span class="p">):</span>
|
||
<span class="n">to_slap</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">ctx</span><span class="o">.</span><span class="n">guild</span><span class="o">.</span><span class="n">members</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">ctx</span><span class="o">.</span><span class="n">author</span><span class="si">}</span><span class="s1"> slapped </span><span class="si">{</span><span class="n">to_slap</span><span class="si">}</span><span class="s1"> because *</span><span class="si">{</span><span class="n">argument</span><span class="si">}</span><span class="s1">*'</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">slap</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">reason</span><span class="p">:</span> <span class="n">Slapper</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">reason</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The converter provided can either be constructed or not. Essentially these two are equivalent:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">slap</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">reason</span><span class="p">:</span> <span class="n">Slapper</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">reason</span><span class="p">)</span>
|
||
|
||
<span class="c1"># is the same as...</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">slap</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">reason</span><span class="p">:</span> <span class="n">Slapper</span><span class="p">()):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">reason</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Having the possibility of the converter be constructed allows you to set up some state in the converter’s <code class="docutils literal notranslate"><span class="pre">__init__</span></code> for
|
||
fine tuning the converter. An example of this is actually in the library, <a class="reference internal" href="api.html#discord.ext.commands.clean_content" title="discord.ext.commands.clean_content"><code class="xref py py-class docutils literal notranslate"><span class="pre">clean_content</span></code></a>.</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="n">commands</span><span class="o">.</span><span class="n">clean_content</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
|
||
|
||
<span class="c1"># or for fine-tuning</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="n">commands</span><span class="o">.</span><span class="n">clean_content</span><span class="p">(</span><span class="n">use_nicknames</span><span class="o">=</span><span class="kc">False</span><span class="p">)):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If a converter fails to convert an argument to its designated target type, the <a class="reference internal" href="api.html#discord.ext.commands.BadArgument" title="discord.ext.commands.BadArgument"><code class="xref py py-exc docutils literal notranslate"><span class="pre">BadArgument</span></code></a> exception must be
|
||
raised.</p>
|
||
</section>
|
||
<section id="inline-advanced-converters">
|
||
<h3>Inline Advanced Converters<a class="headerlink" href="#inline-advanced-converters" title="Permalink to this headline">¶</a></h3>
|
||
<p>If we don’t want to inherit from <a class="reference internal" href="api.html#discord.ext.commands.Converter" title="discord.ext.commands.Converter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Converter</span></code></a>, we can still provide a converter that has the
|
||
advanced functionalities of an advanced converter and save us from specifying two types.</p>
|
||
<p>For example, a common idiom would be to have a class and a converter for that class:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">JoinDistance</span><span class="p">:</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">joined</span><span class="p">,</span> <span class="n">created</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">joined</span> <span class="o">=</span> <span class="n">joined</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">created</span> <span class="o">=</span> <span class="n">created</span>
|
||
|
||
<span class="nd">@property</span>
|
||
<span class="k">def</span> <span class="nf">delta</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">joined</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">created</span>
|
||
|
||
<span class="k">class</span> <span class="nc">JoinDistanceConverter</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">MemberConverter</span><span class="p">):</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">convert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ctx</span><span class="p">,</span> <span class="n">argument</span><span class="p">):</span>
|
||
<span class="n">member</span> <span class="o">=</span> <span class="k">await</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">argument</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">JoinDistance</span><span class="p">(</span><span class="n">member</span><span class="o">.</span><span class="n">joined_at</span><span class="p">,</span> <span class="n">member</span><span class="o">.</span><span class="n">created_at</span><span class="p">)</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">delta</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">member</span><span class="p">:</span> <span class="n">JoinDistanceConverter</span><span class="p">):</span>
|
||
<span class="n">is_new</span> <span class="o">=</span> <span class="n">member</span><span class="o">.</span><span class="n">delta</span><span class="o">.</span><span class="n">days</span> <span class="o"><</span> <span class="mi">100</span>
|
||
<span class="k">if</span> <span class="n">is_new</span><span class="p">:</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s2">"Hey you're pretty new!"</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s2">"Hm you're not so new."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This can get tedious, so an inline advanced converter is possible through a <a class="reference external" href="https://docs.python.org/3/library/functions.html#classmethod" title="(in Python v3.9)"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a> inside the type:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">JoinDistance</span><span class="p">:</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">joined</span><span class="p">,</span> <span class="n">created</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">joined</span> <span class="o">=</span> <span class="n">joined</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">created</span> <span class="o">=</span> <span class="n">created</span>
|
||
|
||
<span class="nd">@classmethod</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">convert</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">ctx</span><span class="p">,</span> <span class="n">argument</span><span class="p">):</span>
|
||
<span class="n">member</span> <span class="o">=</span> <span class="k">await</span> <span class="n">commands</span><span class="o">.</span><span class="n">MemberConverter</span><span class="p">()</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">argument</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">member</span><span class="o">.</span><span class="n">joined_at</span><span class="p">,</span> <span class="n">member</span><span class="o">.</span><span class="n">created_at</span><span class="p">)</span>
|
||
|
||
<span class="nd">@property</span>
|
||
<span class="k">def</span> <span class="nf">delta</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">joined</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">created</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">delta</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">member</span><span class="p">:</span> <span class="n">JoinDistance</span><span class="p">):</span>
|
||
<span class="n">is_new</span> <span class="o">=</span> <span class="n">member</span><span class="o">.</span><span class="n">delta</span><span class="o">.</span><span class="n">days</span> <span class="o"><</span> <span class="mi">100</span>
|
||
<span class="k">if</span> <span class="n">is_new</span><span class="p">:</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s2">"Hey you're pretty new!"</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s2">"Hm you're not so new."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="discord-converters">
|
||
<h3>Discord Converters<a class="headerlink" href="#discord-converters" title="Permalink to this headline">¶</a></h3>
|
||
<p>Working with <a class="reference internal" href="../../api.html#discord-api-models"><span class="std std-ref">Discord Models</span></a> is a fairly common thing when defining commands, as a result the library makes
|
||
working with them easy.</p>
|
||
<p>For example, to receive a <a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">Member</span></code></a> you can just pass it as a converter:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">joined</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">member</span><span class="p">:</span> <span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">member</span><span class="si">}</span><span class="s1"> joined on </span><span class="si">{</span><span class="n">member</span><span class="o">.</span><span class="n">joined_at</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When this command is executed, it attempts to convert the string given into a <a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">Member</span></code></a> and then passes it as a
|
||
parameter for the function. This works by checking if the string is a mention, an ID, a nickname, a username + discriminator,
|
||
or just a regular username. The default set of converters have been written to be as easy to use as possible.</p>
|
||
<p>A lot of discord models work out of the gate as a parameter:</p>
|
||
<ul class="simple">
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Object" title="discord.Object"><code class="xref py py-class docutils literal notranslate"><span class="pre">Object</span></code></a> (since v2.0)</p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">Member</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.User" title="discord.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Message" title="discord.Message"><code class="xref py py-class docutils literal notranslate"><span class="pre">Message</span></code></a> (since v1.1)</p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.PartialMessage" title="discord.PartialMessage"><code class="xref py py-class docutils literal notranslate"><span class="pre">PartialMessage</span></code></a> (since v1.7)</p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.abc.GuildChannel" title="discord.abc.GuildChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">abc.GuildChannel</span></code></a> (since 2.0)</p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.TextChannel" title="discord.TextChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">TextChannel</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.VoiceChannel" title="discord.VoiceChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">VoiceChannel</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.StageChannel" title="discord.StageChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">StageChannel</span></code></a> (since v1.7)</p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.StoreChannel" title="discord.StoreChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">StoreChannel</span></code></a> (since v1.7)</p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.CategoryChannel" title="discord.CategoryChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">CategoryChannel</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Invite" title="discord.Invite"><code class="xref py py-class docutils literal notranslate"><span class="pre">Invite</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Guild" title="discord.Guild"><code class="xref py py-class docutils literal notranslate"><span class="pre">Guild</span></code></a> (since v1.7)</p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Role" title="discord.Role"><code class="xref py py-class docutils literal notranslate"><span class="pre">Role</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Game" title="discord.Game"><code class="xref py py-class docutils literal notranslate"><span class="pre">Game</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Colour" title="discord.Colour"><code class="xref py py-class docutils literal notranslate"><span class="pre">Colour</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Emoji" title="discord.Emoji"><code class="xref py py-class docutils literal notranslate"><span class="pre">Emoji</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.PartialEmoji" title="discord.PartialEmoji"><code class="xref py py-class docutils literal notranslate"><span class="pre">PartialEmoji</span></code></a></p></li>
|
||
<li><p><a class="reference internal" href="../../api.html#discord.Thread" title="discord.Thread"><code class="xref py py-class docutils literal notranslate"><span class="pre">Thread</span></code></a> (since v2.0)</p></li>
|
||
</ul>
|
||
<p>Having any of these set as the converter will intelligently convert the argument to the appropriate target type you
|
||
specify.</p>
|
||
<p>Under the hood, these are implemented by the <a class="reference internal" href="#ext-commands-adv-converters"><span class="std std-ref">Advanced Converters</span></a> interface. A table of the equivalent
|
||
converter is given below:</p>
|
||
<div class="table-wrapper"><table class="docutils align-default">
|
||
<colgroup>
|
||
<col style="width: 25%" />
|
||
<col style="width: 47%" />
|
||
<col style="width: 28%" />
|
||
</colgroup>
|
||
<tbody>
|
||
<tr class="row-odd"><td><p>Discord Class</p></td>
|
||
<td><p>Converter</p></td>
|
||
<td><p>Supported By Slash Commands</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.Object" title="discord.Object"><code class="xref py py-class docutils literal notranslate"><span class="pre">Object</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.ObjectConverter" title="discord.ext.commands.ObjectConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">ObjectConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">Member</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.MemberConverter" title="discord.ext.commands.MemberConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">MemberConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 6 (USER)</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.User" title="discord.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.UserConverter" title="discord.ext.commands.UserConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">UserConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 6 (USER)</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.Message" title="discord.Message"><code class="xref py py-class docutils literal notranslate"><span class="pre">Message</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.MessageConverter" title="discord.ext.commands.MessageConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">MessageConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.PartialMessage" title="discord.PartialMessage"><code class="xref py py-class docutils literal notranslate"><span class="pre">PartialMessage</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.PartialMessageConverter" title="discord.ext.commands.PartialMessageConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">PartialMessageConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.abc.GuildChannel" title="discord.abc.GuildChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">GuildChannel</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.GuildChannelConverter" title="discord.ext.commands.GuildChannelConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">GuildChannelConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 7 (CHANNEL)</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.TextChannel" title="discord.TextChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">TextChannel</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.TextChannelConverter" title="discord.ext.commands.TextChannelConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">TextChannelConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 7 (CHANNEL)</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.VoiceChannel" title="discord.VoiceChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">VoiceChannel</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.VoiceChannelConverter" title="discord.ext.commands.VoiceChannelConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">VoiceChannelConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 7 (CHANNEL)</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.StageChannel" title="discord.StageChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">StageChannel</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.StageChannelConverter" title="discord.ext.commands.StageChannelConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">StageChannelConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 7 (CHANNEL)</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.StoreChannel" title="discord.StoreChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">StoreChannel</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.StoreChannelConverter" title="discord.ext.commands.StoreChannelConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">StoreChannelConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 7 (CHANNEL)</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.CategoryChannel" title="discord.CategoryChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">CategoryChannel</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.CategoryChannelConverter" title="discord.ext.commands.CategoryChannelConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">CategoryChannelConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 7 (CHANNEL)</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.Thread" title="discord.Thread"><code class="xref py py-class docutils literal notranslate"><span class="pre">Thread</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.ThreadConverter" title="discord.ext.commands.ThreadConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">ThreadConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 7 (CHANNEL)</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.Invite" title="discord.Invite"><code class="xref py py-class docutils literal notranslate"><span class="pre">Invite</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.InviteConverter" title="discord.ext.commands.InviteConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">InviteConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.Guild" title="discord.Guild"><code class="xref py py-class docutils literal notranslate"><span class="pre">Guild</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.GuildConverter" title="discord.ext.commands.GuildConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">GuildConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.Role" title="discord.Role"><code class="xref py py-class docutils literal notranslate"><span class="pre">Role</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.RoleConverter" title="discord.ext.commands.RoleConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">RoleConverter</span></code></a></p></td>
|
||
<td><p>Yes, as type 8 (ROLE)</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.Game" title="discord.Game"><code class="xref py py-class docutils literal notranslate"><span class="pre">Game</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.GameConverter" title="discord.ext.commands.GameConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">GameConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.Colour" title="discord.Colour"><code class="xref py py-class docutils literal notranslate"><span class="pre">Colour</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.ColourConverter" title="discord.ext.commands.ColourConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">ColourConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p><a class="reference internal" href="../../api.html#discord.Emoji" title="discord.Emoji"><code class="xref py py-class docutils literal notranslate"><span class="pre">Emoji</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.EmojiConverter" title="discord.ext.commands.EmojiConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">EmojiConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p><a class="reference internal" href="../../api.html#discord.PartialEmoji" title="discord.PartialEmoji"><code class="xref py py-class docutils literal notranslate"><span class="pre">PartialEmoji</span></code></a></p></td>
|
||
<td><p><a class="reference internal" href="api.html#discord.ext.commands.PartialEmojiConverter" title="discord.ext.commands.PartialEmojiConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">PartialEmojiConverter</span></code></a></p></td>
|
||
<td><p>Not currently</p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div><div class="admonition-slash-command-only admonition">
|
||
<p class="admonition-title">Slash Command Only</p>
|
||
<p>If a slash command is not marked on the table above as supported, it will be sent as type 3 (STRING)
|
||
and parsed by normal content parsing, see
|
||
<a class="reference external" href="https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type">the discord documentation</a>
|
||
for all supported types by the API.</p>
|
||
</div>
|
||
<p>By providing the converter it allows us to use them as building blocks for another converter:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MemberRoles</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">MemberConverter</span><span class="p">):</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">convert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ctx</span><span class="p">,</span> <span class="n">argument</span><span class="p">):</span>
|
||
<span class="n">member</span> <span class="o">=</span> <span class="k">await</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">argument</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="p">[</span><span class="n">role</span><span class="o">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">role</span> <span class="ow">in</span> <span class="n">member</span><span class="o">.</span><span class="n">roles</span><span class="p">[</span><span class="mi">1</span><span class="p">:]]</span> <span class="c1"># Remove everyone role!</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">roles</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">member</span><span class="p">:</span> <span class="n">MemberRoles</span><span class="p">):</span>
|
||
<span class="sd">"""Tells you a member's roles."""</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s1">'I see the following roles: '</span> <span class="o">+</span> <span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">member</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="special-converters">
|
||
<span id="ext-commands-special-converters"></span><h3>Special Converters<a class="headerlink" href="#special-converters" title="Permalink to this headline">¶</a></h3>
|
||
<p>The command extension also has support for certain converters to allow for more advanced and intricate use cases that go
|
||
beyond the generic linear parsing. These converters allow you to introduce some more relaxed and dynamic grammar to your
|
||
commands in an easy to use manner.</p>
|
||
<section id="typing-union">
|
||
<h4>typing.Union<a class="headerlink" href="#typing-union" title="Permalink to this headline">¶</a></h4>
|
||
<p>A <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Union" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Union</span></code></a> is a special type hint that allows for the command to take in any of the specific types instead of
|
||
a singular type. For example, given the following:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">typing</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">union</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">what</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="n">discord</span><span class="o">.</span><span class="n">TextChannel</span><span class="p">,</span> <span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">]):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">what</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">what</span></code> parameter would either take a <a class="reference internal" href="../../api.html#discord.TextChannel" title="discord.TextChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">discord.TextChannel</span></code></a> converter or a <a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">discord.Member</span></code></a> converter.
|
||
The way this works is through a left-to-right order. It first attempts to convert the input to a
|
||
<a class="reference internal" href="../../api.html#discord.TextChannel" title="discord.TextChannel"><code class="xref py py-class docutils literal notranslate"><span class="pre">discord.TextChannel</span></code></a>, and if it fails it tries to convert it to a <a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">discord.Member</span></code></a>. If all converters fail,
|
||
then a special error is raised, <a class="reference internal" href="api.html#discord.ext.commands.BadUnionArgument" title="discord.ext.commands.BadUnionArgument"><code class="xref py py-exc docutils literal notranslate"><span class="pre">BadUnionArgument</span></code></a>.</p>
|
||
<p>Note that any valid converter discussed above can be passed in to the argument list of a <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Union" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Union</span></code></a>.</p>
|
||
<div class="admonition-slash-command-only admonition">
|
||
<p class="admonition-title">Slash Command Only</p>
|
||
<p>These are not currently supported by the Discord API and will be sent as type 3 (STRING)</p>
|
||
</div>
|
||
</section>
|
||
<section id="typing-optional">
|
||
<h4>typing.Optional<a class="headerlink" href="#typing-optional" title="Permalink to this headline">¶</a></h4>
|
||
<p>A <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Optional" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Optional</span></code></a> is a special type hint that allows for “back-referencing” behaviour. If the converter fails to
|
||
parse into the specified type, the parser will skip the parameter and then either <code class="docutils literal notranslate"><span class="pre">None</span></code> or the specified default will be
|
||
passed into the parameter instead. The parser will then continue on to the next parameters and converters, if any.</p>
|
||
<p>Consider the following example:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">typing</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">bottles</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">amount</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="mi">99</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">liquid</span><span class="o">=</span><span class="s2">"beer"</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">amount</span><span class="si">}</span><span class="s1"> bottles of </span><span class="si">{</span><span class="n">liquid</span><span class="si">}</span><span class="s1"> on the wall!'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<img alt="../../_images/optional1.png" src="../../_images/optional1.png" />
|
||
<p>In this example, since the argument could not be converted into an <code class="docutils literal notranslate"><span class="pre">int</span></code>, the default of <code class="docutils literal notranslate"><span class="pre">99</span></code> is passed and the parser
|
||
resumes handling, which in this case would be to pass it into the <code class="docutils literal notranslate"><span class="pre">liquid</span></code> parameter.</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>This converter only works in regular positional parameters, not variable parameters or keyword-only parameters.</p>
|
||
</div>
|
||
</section>
|
||
<section id="typing-literal">
|
||
<h4>typing.Literal<a class="headerlink" href="#typing-literal" title="Permalink to this headline">¶</a></h4>
|
||
<p>A <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Literal" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Literal</span></code></a> is a special type hint that requires the passed parameter to be equal to one of the listed values
|
||
after being converted to the same type. For example, given the following:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Literal</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">shop</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">buy_sell</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s1">'buy'</span><span class="p">,</span> <span class="s1">'sell'</span><span class="p">],</span> <span class="n">amount</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="o">*</span><span class="p">,</span> <span class="n">item</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">buy_sell</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span><span class="si">}</span><span class="s1">ing </span><span class="si">{</span><span class="n">amount</span><span class="si">}</span><span class="s1"> </span><span class="si">{</span><span class="n">item</span><span class="si">}</span><span class="s1">(s)!'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">buy_sell</span></code> parameter must be either the literal string <code class="docutils literal notranslate"><span class="pre">"buy"</span></code> or <code class="docutils literal notranslate"><span class="pre">"sell"</span></code> and <code class="docutils literal notranslate"><span class="pre">amount</span></code> must convert to the
|
||
<code class="docutils literal notranslate"><span class="pre">int</span></code> <code class="docutils literal notranslate"><span class="pre">1</span></code> or <code class="docutils literal notranslate"><span class="pre">2</span></code>. If <code class="docutils literal notranslate"><span class="pre">buy_sell</span></code> or <code class="docutils literal notranslate"><span class="pre">amount</span></code> don’t match any value, then a special error is raised,
|
||
<a class="reference internal" href="api.html#discord.ext.commands.BadLiteralArgument" title="discord.ext.commands.BadLiteralArgument"><code class="xref py py-exc docutils literal notranslate"><span class="pre">BadLiteralArgument</span></code></a>. Any literal values can be mixed and matched within the same <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Literal" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Literal</span></code></a> converter.</p>
|
||
<p>Note that <code class="docutils literal notranslate"><span class="pre">typing.Literal[True]</span></code> and <code class="docutils literal notranslate"><span class="pre">typing.Literal[False]</span></code> still follow the <a class="reference external" href="https://docs.python.org/3/library/functions.html#bool" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code></a> converter rules.</p>
|
||
</section>
|
||
<section id="greedy">
|
||
<h4>Greedy<a class="headerlink" href="#greedy" title="Permalink to this headline">¶</a></h4>
|
||
<p>The <a class="reference internal" href="api.html#discord.ext.commands.Greedy" title="discord.ext.commands.Greedy"><code class="xref py py-class docutils literal notranslate"><span class="pre">Greedy</span></code></a> converter is a generalisation of the <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Optional" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Optional</span></code></a> converter, except applied
|
||
to a list of arguments. In simple terms, this means that it tries to convert as much as it can until it can’t convert
|
||
any further.</p>
|
||
<p>Consider the following example:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">slap</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">members</span><span class="p">:</span> <span class="n">commands</span><span class="o">.</span><span class="n">Greedy</span><span class="p">[</span><span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">],</span> <span class="o">*</span><span class="p">,</span> <span class="n">reason</span><span class="o">=</span><span class="s1">'no reason'</span><span class="p">):</span>
|
||
<span class="n">slapped</span> <span class="o">=</span> <span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">members</span><span class="p">)</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">slapped</span><span class="si">}</span><span class="s1"> just got slapped for </span><span class="si">{</span><span class="n">reason</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When invoked, it allows for any number of members to be passed in:</p>
|
||
<img alt="../../_images/greedy1.png" src="../../_images/greedy1.png" />
|
||
<p>The type passed when using this converter depends on the parameter type that it is being attached to:</p>
|
||
<ul class="simple">
|
||
<li><p>Positional parameter types will receive either the default parameter or a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#list" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a> of the converted values.</p></li>
|
||
<li><p>Variable parameter types will be a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#tuple" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">tuple</span></code></a> as usual.</p></li>
|
||
<li><p>Keyword-only parameter types will be the same as if <a class="reference internal" href="api.html#discord.ext.commands.Greedy" title="discord.ext.commands.Greedy"><code class="xref py py-class docutils literal notranslate"><span class="pre">Greedy</span></code></a> was not passed at all.</p></li>
|
||
</ul>
|
||
<p><a class="reference internal" href="api.html#discord.ext.commands.Greedy" title="discord.ext.commands.Greedy"><code class="xref py py-class docutils literal notranslate"><span class="pre">Greedy</span></code></a> parameters can also be made optional by specifying an optional value.</p>
|
||
<p>When mixed with the <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Optional" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Optional</span></code></a> converter you can provide simple and expressive command invocation syntaxes:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">typing</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">ban</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">members</span><span class="p">:</span> <span class="n">commands</span><span class="o">.</span><span class="n">Greedy</span><span class="p">[</span><span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">],</span>
|
||
<span class="n">delete_days</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span>
|
||
<span class="n">reason</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
|
||
<span class="sd">"""Mass bans members with an optional delete_days parameter"""</span>
|
||
<span class="k">for</span> <span class="n">member</span> <span class="ow">in</span> <span class="n">members</span><span class="p">:</span>
|
||
<span class="k">await</span> <span class="n">member</span><span class="o">.</span><span class="n">ban</span><span class="p">(</span><span class="n">delete_message_days</span><span class="o">=</span><span class="n">delete_days</span><span class="p">,</span> <span class="n">reason</span><span class="o">=</span><span class="n">reason</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This command can be invoked any of the following ways:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>$ban @Member @Member2 spam bot
|
||
$ban @Member @Member2 7 spam bot
|
||
$ban @Member spam
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>The usage of <a class="reference internal" href="api.html#discord.ext.commands.Greedy" title="discord.ext.commands.Greedy"><code class="xref py py-class docutils literal notranslate"><span class="pre">Greedy</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Optional" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Optional</span></code></a> are powerful and useful, however as a
|
||
price, they open you up to some parsing ambiguities that might surprise some people.</p>
|
||
<p>For example, a signature expecting a <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Optional" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Optional</span></code></a> of a <a class="reference internal" href="../../api.html#discord.Member" title="discord.Member"><code class="xref py py-class docutils literal notranslate"><span class="pre">discord.Member</span></code></a> followed by a
|
||
<a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> could catch a member named after a number due to the different ways a
|
||
<a class="reference internal" href="api.html#discord.ext.commands.MemberConverter" title="discord.ext.commands.MemberConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">MemberConverter</span></code></a> decides to fetch members. You should take care to not introduce
|
||
unintended parsing ambiguities in your code. One technique would be to clamp down the expected syntaxes
|
||
allowed through custom converters or reordering the parameters to minimise clashes.</p>
|
||
<p>To help aid with some parsing ambiguities, <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a>, <code class="docutils literal notranslate"><span class="pre">None</span></code>, <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Optional" title="(in Python v3.9)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Optional</span></code></a> and
|
||
<a class="reference internal" href="api.html#discord.ext.commands.Greedy" title="discord.ext.commands.Greedy"><code class="xref py py-class docutils literal notranslate"><span class="pre">Greedy</span></code></a> are forbidden as parameters for the <a class="reference internal" href="api.html#discord.ext.commands.Greedy" title="discord.ext.commands.Greedy"><code class="xref py py-class docutils literal notranslate"><span class="pre">Greedy</span></code></a> converter.</p>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="flagconverter">
|
||
<span id="ext-commands-flag-converter"></span><h3>FlagConverter<a class="headerlink" href="#flagconverter" title="Permalink to this headline">¶</a></h3>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">New in version 2.0.</span></p>
|
||
</div>
|
||
<p>A <a class="reference internal" href="api.html#discord.ext.commands.FlagConverter" title="discord.ext.commands.FlagConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">FlagConverter</span></code></a> allows the user to specify user-friendly “flags” using <span class="target" id="index-1"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0526"><strong>PEP 526</strong></a> type annotations
|
||
or a syntax more reminiscent of the <a class="reference external" href="https://docs.python.org/3/library/dataclasses.html#module-dataclasses" title="(in Python v3.9)"><code class="docutils literal notranslate"><span class="pre">dataclasses</span></code></a> module.</p>
|
||
<p>For example, the following code:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">discord.ext</span> <span class="kn">import</span> <span class="n">commands</span>
|
||
<span class="kn">import</span> <span class="nn">discord</span>
|
||
|
||
<span class="k">class</span> <span class="nc">BanFlags</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">):</span>
|
||
<span class="n">member</span><span class="p">:</span> <span class="n">discord</span><span class="o">.</span><span class="n">Member</span>
|
||
<span class="n">reason</span><span class="p">:</span> <span class="nb">str</span>
|
||
<span class="n">days</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span>
|
||
|
||
<span class="nd">@commands</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">ban</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">flags</span><span class="p">:</span> <span class="n">BanFlags</span><span class="p">):</span>
|
||
<span class="n">plural</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">flags</span><span class="o">.</span><span class="n">days</span><span class="si">}</span><span class="s1"> days'</span> <span class="k">if</span> <span class="n">flags</span><span class="o">.</span><span class="n">days</span> <span class="o">!=</span> <span class="mi">1</span> <span class="k">else</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">flags</span><span class="o">.</span><span class="n">days</span><span class="si">}</span><span class="s1"> day'</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Banned </span><span class="si">{</span><span class="n">flags</span><span class="o">.</span><span class="n">member</span><span class="si">}</span><span class="s1"> for </span><span class="si">{</span><span class="n">flags</span><span class="o">.</span><span class="n">reason</span><span class="si">!r}</span><span class="s1"> (deleted </span><span class="si">{</span><span class="n">plural</span><span class="si">}</span><span class="s1"> worth of messages)'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Allows the user to invoke the command using a simple flag-like syntax:</p>
|
||
<img alt="../../_images/flags1.png" src="../../_images/flags1.png" />
|
||
<p>Flags use a syntax that allows the user to not require quotes when passing in values to the flag. The goal of the
|
||
flag syntax is to be as user-friendly as possible. This makes flags a good choice for complicated commands that can have
|
||
multiple knobs to turn or simulating keyword-only parameters in your external command interface. <strong>It is recommended to use
|
||
keyword-only parameters with the flag converter</strong>. This ensures proper parsing and behaviour with quoting.</p>
|
||
<p>Internally, the <a class="reference internal" href="api.html#discord.ext.commands.FlagConverter" title="discord.ext.commands.FlagConverter"><code class="xref py py-class docutils literal notranslate"><span class="pre">FlagConverter</span></code></a> class examines the class to find flags. A flag can either be a
|
||
class variable with a type annotation or a class variable that’s been assigned the result of the <a class="reference internal" href="api.html#discord.ext.commands.flag" title="discord.ext.commands.flag"><code class="xref py py-func docutils literal notranslate"><span class="pre">flag()</span></code></a>
|
||
function. These flags are then used to define the interface that your users will use. The annotations correspond to
|
||
the converters that the flag arguments must adhere to.</p>
|
||
<p>For most use cases, no extra work is required to define flags. However, if customisation is needed to control the flag name
|
||
or the default value then the <a class="reference internal" href="api.html#discord.ext.commands.flag" title="discord.ext.commands.flag"><code class="xref py py-func docutils literal notranslate"><span class="pre">flag()</span></code></a> function can come in handy:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span>
|
||
|
||
<span class="k">class</span> <span class="nc">BanFlags</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">):</span>
|
||
<span class="n">members</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">]</span> <span class="o">=</span> <span class="n">commands</span><span class="o">.</span><span class="n">flag</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'member'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="k">lambda</span> <span class="n">ctx</span><span class="p">:</span> <span class="p">[])</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This tells the parser that the <code class="docutils literal notranslate"><span class="pre">members</span></code> attribute is mapped to a flag named <code class="docutils literal notranslate"><span class="pre">member</span></code> and that
|
||
the default value is an empty list. For greater customisability, the default can either be a value or a callable
|
||
that takes the <a class="reference internal" href="api.html#discord.ext.commands.Context" title="discord.ext.commands.Context"><code class="xref py py-class docutils literal notranslate"><span class="pre">Context</span></code></a> as a sole parameter. This callable can either be a function or a coroutine.</p>
|
||
<p>In order to customise the flag syntax we also have a few options that can be passed to the class parameter list:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># --hello world syntax</span>
|
||
<span class="k">class</span> <span class="nc">PosixLikeFlags</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">,</span> <span class="n">delimiter</span><span class="o">=</span><span class="s1">' '</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s1">'--'</span><span class="p">):</span>
|
||
<span class="n">hello</span><span class="p">:</span> <span class="nb">str</span>
|
||
|
||
|
||
<span class="c1"># /make food</span>
|
||
<span class="k">class</span> <span class="nc">WindowsLikeFlags</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s1">'/'</span><span class="p">,</span> <span class="n">delimiter</span><span class="o">=</span><span class="s1">''</span><span class="p">):</span>
|
||
<span class="n">make</span><span class="p">:</span> <span class="nb">str</span>
|
||
|
||
<span class="c1"># TOPIC: not allowed nsfw: yes Slowmode: 100</span>
|
||
<span class="k">class</span> <span class="nc">Settings</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">,</span> <span class="n">case_insensitive</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
|
||
<span class="n">topic</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
|
||
<span class="n">nsfw</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span>
|
||
<span class="n">slowmode</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>Despite the similarities in these examples to command like arguments, the syntax and parser is not
|
||
a command line parser. The syntax is mainly inspired by Discord’s search bar input and as a result
|
||
all flags need a corresponding value.</p>
|
||
</div>
|
||
<div class="admonition-slash-command-only admonition">
|
||
<p class="admonition-title">Slash Command Only</p>
|
||
<p>As these are built very similar to slash command options, they are converted into options and parsed
|
||
back into flags when the slash command is executed.</p>
|
||
</div>
|
||
<p>The flag converter is similar to regular commands and allows you to use most types of converters
|
||
(with the exception of <a class="reference internal" href="api.html#discord.ext.commands.Greedy" title="discord.ext.commands.Greedy"><code class="xref py py-class docutils literal notranslate"><span class="pre">Greedy</span></code></a>) as the type annotation. Some extra support is added for specific
|
||
annotations as described below.</p>
|
||
<section id="typing-list">
|
||
<h4>typing.List<a class="headerlink" href="#typing-list" title="Permalink to this headline">¶</a></h4>
|
||
<p>If a list is given as a flag annotation it tells the parser that the argument can be passed multiple times.</p>
|
||
<p>For example, augmenting the example above:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">discord.ext</span> <span class="kn">import</span> <span class="n">commands</span>
|
||
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span>
|
||
<span class="kn">import</span> <span class="nn">discord</span>
|
||
|
||
<span class="k">class</span> <span class="nc">BanFlags</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">):</span>
|
||
<span class="n">members</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">]</span> <span class="o">=</span> <span class="n">commands</span><span class="o">.</span><span class="n">flag</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'member'</span><span class="p">)</span>
|
||
<span class="n">reason</span><span class="p">:</span> <span class="nb">str</span>
|
||
<span class="n">days</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span>
|
||
|
||
<span class="nd">@commands</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">ban</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">flags</span><span class="p">:</span> <span class="n">BanFlags</span><span class="p">):</span>
|
||
<span class="k">for</span> <span class="n">member</span> <span class="ow">in</span> <span class="n">flags</span><span class="o">.</span><span class="n">members</span><span class="p">:</span>
|
||
<span class="k">await</span> <span class="n">member</span><span class="o">.</span><span class="n">ban</span><span class="p">(</span><span class="n">reason</span><span class="o">=</span><span class="n">flags</span><span class="o">.</span><span class="n">reason</span><span class="p">,</span> <span class="n">delete_message_days</span><span class="o">=</span><span class="n">flags</span><span class="o">.</span><span class="n">days</span><span class="p">)</span>
|
||
|
||
<span class="n">members</span> <span class="o">=</span> <span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">member</span><span class="p">)</span> <span class="k">for</span> <span class="n">member</span> <span class="ow">in</span> <span class="n">flags</span><span class="o">.</span><span class="n">members</span><span class="p">)</span>
|
||
<span class="n">plural</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">flags</span><span class="o">.</span><span class="n">days</span><span class="si">}</span><span class="s1"> days'</span> <span class="k">if</span> <span class="n">flags</span><span class="o">.</span><span class="n">days</span> <span class="o">!=</span> <span class="mi">1</span> <span class="k">else</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">flags</span><span class="o">.</span><span class="n">days</span><span class="si">}</span><span class="s1"> day'</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Banned </span><span class="si">{</span><span class="n">members</span><span class="si">}</span><span class="s1"> for </span><span class="si">{</span><span class="n">flags</span><span class="o">.</span><span class="n">reason</span><span class="si">!r}</span><span class="s1"> (deleted </span><span class="si">{</span><span class="n">plural</span><span class="si">}</span><span class="s1"> worth of messages)'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This is called by repeatedly specifying the flag:</p>
|
||
<img alt="../../_images/flags2.png" src="../../_images/flags2.png" />
|
||
</section>
|
||
<section id="typing-tuple">
|
||
<h4>typing.Tuple<a class="headerlink" href="#typing-tuple" title="Permalink to this headline">¶</a></h4>
|
||
<p>Since the above syntax can be a bit repetitive when specifying a flag many times, the <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#tuple" title="(in Python v3.9)"><code class="docutils literal notranslate"><span class="pre">tuple</span></code></a> type annotation
|
||
allows for “greedy-like” semantics using a variadic tuple:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">discord.ext</span> <span class="kn">import</span> <span class="n">commands</span>
|
||
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Tuple</span>
|
||
<span class="kn">import</span> <span class="nn">discord</span>
|
||
|
||
<span class="k">class</span> <span class="nc">BanFlags</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">):</span>
|
||
<span class="n">members</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
|
||
<span class="n">reason</span><span class="p">:</span> <span class="nb">str</span>
|
||
<span class="n">days</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This allows the previous <code class="docutils literal notranslate"><span class="pre">ban</span></code> command to be called like this:</p>
|
||
<img alt="../../_images/flags3.png" src="../../_images/flags3.png" />
|
||
<p>The <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#tuple" title="(in Python v3.9)"><code class="docutils literal notranslate"><span class="pre">tuple</span></code></a> annotation also allows for parsing of pairs. For example, given the following code:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># point: 10 11 point: 12 13</span>
|
||
<span class="k">class</span> <span class="nc">Coordinates</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">FlagConverter</span><span class="p">):</span>
|
||
<span class="n">point</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Due to potential parsing ambiguities, the parser expects tuple arguments to be quoted
|
||
if they require spaces. So if one of the inner types is <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> and the argument requires spaces
|
||
then quotes should be used to disambiguate it from the other element of the tuple.</p>
|
||
</div>
|
||
</section>
|
||
<section id="typing-dict">
|
||
<h4>typing.Dict<a class="headerlink" href="#typing-dict" title="Permalink to this headline">¶</a></h4>
|
||
<p>A <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a> annotation is functionally equivalent to <code class="docutils literal notranslate"><span class="pre">List[Tuple[K,</span> <span class="pre">V]]</span></code> except with the return type
|
||
given as a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a> rather than a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#list" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a>.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
<section id="error-handling">
|
||
<span id="ext-commands-error-handler"></span><h2>Error Handling<a class="headerlink" href="#error-handling" title="Permalink to this headline">¶</a></h2>
|
||
<p>When our commands fail to parse we will, by default, receive a noisy error in <code class="docutils literal notranslate"><span class="pre">stderr</span></code> of our console that tells us
|
||
that an error has happened and has been silently ignored.</p>
|
||
<p>In order to handle our errors, we must use something called an error handler. There is a global error handler, called
|
||
<a class="reference internal" href="api.html#discord.discord.ext.commands.on_command_error" title="discord.discord.ext.commands.on_command_error"><code class="xref py py-func docutils literal notranslate"><span class="pre">on_command_error()</span></code></a> which works like any other event in the <a class="reference internal" href="../../api.html#discord-api-events"><span class="std std-ref">Event Reference</span></a>. This global error handler is
|
||
called for every error reached.</p>
|
||
<p>Most of the time however, we want to handle an error local to the command itself. Luckily, commands come with local error
|
||
handlers that allow us to do just that. First we decorate an error handler function with <a class="reference internal" href="api.html#discord.ext.commands.Command.error" title="discord.ext.commands.Command.error"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Command.error()</span></code></a>:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">info</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">member</span><span class="p">:</span> <span class="n">discord</span><span class="o">.</span><span class="n">Member</span><span class="p">):</span>
|
||
<span class="sd">"""Tells you some info about the member."""</span>
|
||
<span class="n">msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">member</span><span class="si">}</span><span class="s1"> joined on </span><span class="si">{</span><span class="n">member</span><span class="o">.</span><span class="n">joined_at</span><span class="si">}</span><span class="s1"> and has </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">member</span><span class="o">.</span><span class="n">roles</span><span class="p">)</span><span class="si">}</span><span class="s1"> roles.'</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
|
||
|
||
<span class="nd">@info</span><span class="o">.</span><span class="n">error</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">info_error</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">error</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">error</span><span class="p">,</span> <span class="n">commands</span><span class="o">.</span><span class="n">BadArgument</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s1">'I could not find that member...'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The first parameter of the error handler is the <a class="reference internal" href="api.html#discord.ext.commands.Context" title="discord.ext.commands.Context"><code class="xref py py-class docutils literal notranslate"><span class="pre">Context</span></code></a> while the second one is an exception that is derived from
|
||
<a class="reference internal" href="api.html#discord.ext.commands.CommandError" title="discord.ext.commands.CommandError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">CommandError</span></code></a>. A list of errors is found in the <a class="reference internal" href="api.html#ext-commands-api-errors"><span class="std std-ref">Exceptions</span></a> page of the documentation.</p>
|
||
</section>
|
||
<section id="checks">
|
||
<h2>Checks<a class="headerlink" href="#checks" title="Permalink to this headline">¶</a></h2>
|
||
<p>There are cases when we don’t want a user to use our commands. They don’t have permissions to do so or maybe we blocked
|
||
them from using our bot earlier. The commands extension comes with full support for these things in a concept called a
|
||
<a class="reference internal" href="api.html#ext-commands-api-checks"><span class="std std-ref">Checks</span></a>.</p>
|
||
<p>A check is a basic predicate that can take in a <a class="reference internal" href="api.html#discord.ext.commands.Context" title="discord.ext.commands.Context"><code class="xref py py-class docutils literal notranslate"><span class="pre">Context</span></code></a> as its sole parameter. Within it, you have the following
|
||
options:</p>
|
||
<ul>
|
||
<li><p>Return <code class="docutils literal notranslate"><span class="pre">True</span></code> to signal that the person can run the command.</p></li>
|
||
<li><p>Return <code class="docutils literal notranslate"><span class="pre">False</span></code> to signal that the person cannot run the command.</p></li>
|
||
<li><p>Raise a <a class="reference internal" href="api.html#discord.ext.commands.CommandError" title="discord.ext.commands.CommandError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">CommandError</span></code></a> derived exception to signal the person cannot run the command.</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li><p>This allows you to have custom error messages for you to handle in the
|
||
<a class="reference internal" href="#ext-commands-error-handler"><span class="std std-ref">error handlers</span></a>.</p></li>
|
||
</ul>
|
||
</div></blockquote>
|
||
</li>
|
||
</ul>
|
||
<p>To register a check for a command, we would have two ways of doing so. The first is using the <a class="reference internal" href="api.html#discord.ext.commands.check" title="discord.ext.commands.check"><code class="xref py py-meth docutils literal notranslate"><span class="pre">check()</span></code></a>
|
||
decorator. For example:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">is_owner</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">ctx</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">316026178463072268</span>
|
||
|
||
<span class="nd">@bot</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="s1">'eval'</span><span class="p">)</span>
|
||
<span class="nd">@commands</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">is_owner</span><span class="p">)</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">_eval</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">code</span><span class="p">):</span>
|
||
<span class="sd">"""A bad example of an eval command"""</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="nb">eval</span><span class="p">(</span><span class="n">code</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This would only evaluate the command if the function <code class="docutils literal notranslate"><span class="pre">is_owner</span></code> returns <code class="docutils literal notranslate"><span class="pre">True</span></code>. Sometimes we re-use a check often and
|
||
want to split it into its own decorator. To do that we can just add another level of depth:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">is_owner</span><span class="p">():</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">predicate</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">ctx</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">316026178463072268</span>
|
||
<span class="k">return</span> <span class="n">commands</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">predicate</span><span class="p">)</span>
|
||
|
||
<span class="nd">@bot</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="s1">'eval'</span><span class="p">)</span>
|
||
<span class="nd">@is_owner</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">_eval</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">code</span><span class="p">):</span>
|
||
<span class="sd">"""A bad example of an eval command"""</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="nb">eval</span><span class="p">(</span><span class="n">code</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Since an owner check is so common, the library provides it for you (<a class="reference internal" href="api.html#discord.ext.commands.is_owner" title="discord.ext.commands.is_owner"><code class="xref py py-func docutils literal notranslate"><span class="pre">is_owner()</span></code></a>):</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</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="s1">'eval'</span><span class="p">)</span>
|
||
<span class="nd">@commands</span><span class="o">.</span><span class="n">is_owner</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">_eval</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">code</span><span class="p">):</span>
|
||
<span class="sd">"""A bad example of an eval command"""</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="nb">eval</span><span class="p">(</span><span class="n">code</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When multiple checks are specified, <strong>all</strong> of them must be <code class="docutils literal notranslate"><span class="pre">True</span></code>:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">is_in_guild</span><span class="p">(</span><span class="n">guild_id</span><span class="p">):</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">predicate</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">ctx</span><span class="o">.</span><span class="n">guild</span> <span class="ow">and</span> <span class="n">ctx</span><span class="o">.</span><span class="n">guild</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">guild_id</span>
|
||
<span class="k">return</span> <span class="n">commands</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">predicate</span><span class="p">)</span>
|
||
|
||
<span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="nd">@commands</span><span class="o">.</span><span class="n">is_owner</span><span class="p">()</span>
|
||
<span class="nd">@is_in_guild</span><span class="p">(</span><span class="mi">41771983423143937</span><span class="p">)</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">secretguilddata</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="sd">"""super secret stuff"""</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s1">'secret stuff'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If any of those checks fail in the example above, then the command will not be run.</p>
|
||
<p>When an error happens, the error is propagated to the <a class="reference internal" href="#ext-commands-error-handler"><span class="std std-ref">error handlers</span></a>. If you do not
|
||
raise a custom <a class="reference internal" href="api.html#discord.ext.commands.CommandError" title="discord.ext.commands.CommandError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">CommandError</span></code></a> derived exception, then it will get wrapped up into a
|
||
<a class="reference internal" href="api.html#discord.ext.commands.CheckFailure" title="discord.ext.commands.CheckFailure"><code class="xref py py-exc docutils literal notranslate"><span class="pre">CheckFailure</span></code></a> exception as so:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
|
||
<span class="nd">@commands</span><span class="o">.</span><span class="n">is_owner</span><span class="p">()</span>
|
||
<span class="nd">@is_in_guild</span><span class="p">(</span><span class="mi">41771983423143937</span><span class="p">)</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">secretguilddata</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="sd">"""super secret stuff"""</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s1">'secret stuff'</span><span class="p">)</span>
|
||
|
||
<span class="nd">@secretguilddata</span><span class="o">.</span><span class="n">error</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">secretguilddata_error</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">error</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">error</span><span class="p">,</span> <span class="n">commands</span><span class="o">.</span><span class="n">CheckFailure</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s1">'nothing to see here comrade.'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If you want a more robust error system, you can derive from the exception and raise it instead of returning <code class="docutils literal notranslate"><span class="pre">False</span></code>:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">NoPrivateMessages</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">CheckFailure</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
|
||
<span class="k">def</span> <span class="nf">guild_only</span><span class="p">():</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">predicate</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">ctx</span><span class="o">.</span><span class="n">guild</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="n">NoPrivateMessages</span><span class="p">(</span><span class="s1">'Hey no DMs!'</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="kc">True</span>
|
||
<span class="k">return</span> <span class="n">commands</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">predicate</span><span class="p">)</span>
|
||
|
||
<span class="nd">@guild_only</span><span class="p">()</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s1">'Hey this is not a DM! Nice.'</span><span class="p">)</span>
|
||
|
||
<span class="nd">@test</span><span class="o">.</span><span class="n">error</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">test_error</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">error</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">error</span><span class="p">,</span> <span class="n">NoPrivateMessages</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>Since having a <code class="docutils literal notranslate"><span class="pre">guild_only</span></code> decorator is pretty common, it comes built-in via <a class="reference internal" href="api.html#discord.ext.commands.guild_only" title="discord.ext.commands.guild_only"><code class="xref py py-func docutils literal notranslate"><span class="pre">guild_only()</span></code></a>.</p>
|
||
</div>
|
||
<section id="global-checks">
|
||
<h3>Global Checks<a class="headerlink" href="#global-checks" title="Permalink to this headline">¶</a></h3>
|
||
<p>Sometimes we want to apply a check to <strong>every</strong> command, not just certain commands. The library supports this as well
|
||
using the global check concept.</p>
|
||
<p>Global checks work similarly to regular checks except they are registered with the <a class="reference internal" href="api.html#discord.ext.commands.Bot.check" title="discord.ext.commands.Bot.check"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Bot.check()</span></code></a> decorator.</p>
|
||
<p>For example, to block all DMs we could do the following:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nd">@bot</span><span class="o">.</span><span class="n">check</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">globally_block_dms</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">ctx</span><span class="o">.</span><span class="n">guild</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Be careful on how you write your global checks, as it could also lock you out of your own bot.</p>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</main>
|
||
<footer class="grid-item">
|
||
© Copyright 2015-present, Rapptz.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.2.0.
|
||
</footer>
|
||
</div>
|
||
|
||
<div id="settings" class="modal" onclick="if (event.target == this){ settingsModal.close(); }" hidden>
|
||
<div class="modal-content">
|
||
<span class="close" onclick="settingsModal.close();" title="Close">
|
||
<span class="material-icons">close</span>
|
||
</span>
|
||
<h1>Settings</h1>
|
||
|
||
<h2>Font</h2>
|
||
<div class="setting">
|
||
<h3>Use a serif font:
|
||
<label class="toggle"
|
||
title="Use a serif font? Your system font will be used, falling back to serif.">
|
||
<input type="checkbox" name="useSerifFont" onclick="updateSetting(this);">
|
||
<span class="toggle-slider"></span>
|
||
</label>
|
||
</h3>
|
||
</div>
|
||
|
||
<h2>Theme</h2>
|
||
<div class="setting">
|
||
<h3>
|
||
<label class="toggle" title="Set your theme based on your system preferences">
|
||
<input type="radio" name="setTheme" onclick="updateSetting(this);" value="automatic" checked>
|
||
</label>
|
||
Automatic
|
||
</h3>
|
||
<h3>
|
||
<label class="toggle" title="Set your theme to light theme">
|
||
<input type="radio" name="setTheme" onclick="updateSetting(this);" value="light">
|
||
</label>
|
||
Light
|
||
</h3>
|
||
<h3>
|
||
<label class="toggle" title="Set your theme to dark theme">
|
||
<input type="radio" name="setTheme" onclick="updateSetting(this);" value="dark">
|
||
</label>
|
||
Dark
|
||
</h3>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div id="to-top" onclick="scrollToTop()" hidden>
|
||
<span><span class="material-icons">arrow_upward</span> to top</span>
|
||
</div>
|
||
|
||
</body>
|
||
</html> |