Nechme internety na chvíli být a pojďme se podívat na úplně jinou knihovnu, click.
Knihovna click
slouží k vytváření rozhraní pro příkazovou řádku
(angl. command line interface, CLI).
Primárně to je zpracování argumentů, ale click umí zjednodušit i výstup.
Click je dobré používat s knihovnou colorama
, která se stará o obarvování
textu na příkazové řádce ve Windows (a na Unixu nedělá nic).
Nainstalujte si tedy obě:
$ python -m pip install click colorama
Nástroje na zpracování argumentů z CLI jsou i přímo ve standardní knihovně,
a dokonce jich není málo: os.environ, argparse, optparse, getopt.
S knihovnou click
je ale práce mnohem příjemnější a výsledky většinou
lépe odpovídají zavedeným konvencím.
Cena za jednoduchost a konzistenci je, že některé styly návrhu CLI click nepodporuje. Máte-li existující rozhraní, které chcete jen převést do Pythonu, click nejspíš nebude nejlepší volba.
Takto jednoduše se dá vytvořit aplikace s přepínači:
import click
@click.command()
@click.option('--count', default=1, metavar='COUNT',
help='Number of greetings.')
@click.option('--name', prompt='Your name', metavar='NAME',
help='The person to greet.')
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for x in range(count):
click.echo('Hello {}!'.format(name))
if __name__ == '__main__':
hello()
Vyzkoušejte si ji! Máte-li ji uloženou jako hello.py
, zkuste:
$ python hello.py
$ python hello.py --help
$ python hello.py --name Pythonista
$ python hello.py --count 5
Funkce s dekorátorem @click.command
je příkaz – když ji zavoláte,
click zpracuje argumenty příkazové řádky a zavolá původní funkci
s příslušnými pythonními hodnotami.
Proto se dává do bloku if __name__ == '__main__':
, který se spustí, jen
když se pythonní soubor spoustí „přímo“.
Když je soubor importován, tenhle blok se neprovede.
Dekorátory @click.option
a @click.argument
pak přidávají přepínače
a argumenty.
Přepínače (angl. options), přidávané pomocí option
, jsou nepovinné
parametry, kterými se nějak obměňuje chování programu.
Pokud uživatel nějaký přepínač nezadá, použije se hodnota zadaná jako default
(nebo None
, když default
chybí).
Podle default
se řídí i typ argumentu, není-li dán explicitně.
Takže count
v příkladu výše je celé číslo.
Jména přepínačů začínají, podle Unixové konvence, pomlčkami: jednou pomlčkou pro jednopísmenné zkratky, dvěma pomlčkami pro vícepísmenná jména. Jeden přepínač může mít i víc jmen.
Speciální případ jsou booleovské přepínače, které mají jedno jméno
pro True
a jiné pro False
.
import click
@click.command()
@click.option('-n', '--name', default='world',
help='Name of the person to greet')
@click.option('-c/-C', '--color/--no-color',
help='Make the output colorful')
def hello(name, color):
if color:
name = click.style(name, fg='blue')
click.echo('Hello {}!'.format(name))
if __name__ == '__main__':
hello()
$ python hello.py
Hello world!
$ python hello.py --name Guido
Hello Guido!
$ python hello.py -n 'Mr. Git'
Hello Mr. Git!
$ python hello.py --help
Usage: hello.py [OPTIONS]
Options:
-n, --name TEXT Name of the person to greet
-c, --color / -C, --no-color Make the output colorful
--help Show this message and exit.
Přepínač --help
přidává click sám.
Kromě přepínačů podporuje click i argumenty. Přepínače musí uživatel na řádce pojmenovat; argumenty se zadávají pozičně. Používají se ve dvou případech: pro povinné informace a pro argumenty, kterých může být libovolný počet. Na všechno ostatní radši použijte přepínače.
@click.command()
@click.argument('directory')
def cd(directory):
"""Change the current directory"""
click.echo('Changing to directory {}'.format(directory))
@click.command()
@click.argument('source', nargs=-1)
@click.argument('destination', nargs=1)
def mv(source, destination):
"""Move any number of files to one destination"""
for filename in source:
click.echo('Moving {} to {}'.format(filename, destination))
Má-li uživatel zadat jméno souboru, nepoužívejte řetězce, ale speciální typ
click.File()
.
Click za vás soubor automaticky otevře a zavře.
Kromě toho podporuje unixovskou konvenci, že -
znamená standardní
vstup/výstup.
Argument pro File
je mód, ve kterém se soubor otevírá, podobně jako pro
funkci open
:
'r'
pro čtení, 'w'
pro zápis.
@click.command()
@click.argument('files', nargs=-1, type=click.File('r'))
def cat(files):
"""Print out the contents of the given files"""
for file in files:
print(file.read(), end='')
Existuje i varianta click.Path()
,
která soubor neotvírá. Pomocí ní jde např. zadat jméno adresáře.
Click má dobrou podporu pro podpříkazy známé z verzovacích systémů jako git:
příkaz git
sám o sobě nedělá nic, jen sdružuje podpříkazy jako git add
a git commit
.
Umí-li váš program více akcí, souhrnný příkaz označte @click.group()
a jednotlivé podpříkazy pak přidávejte pomocí command()
:
@click.group()
def git2():
pass
@git2.command()
def commit():
message = click.edit('Made some changes')
click.echo('Making commit with message: {}'.format(message))
@git2.command()
@click.argument('files', nargs=-1)
def add(files):
for file in files:
click.echo('Adding {}'.format(file))
Tahle lekce není popis všeho, co click umí – je to jen ochutnávka, abyste věděli, co od téhle knihovny očekávat.
Click má velice dobrou dokumentaci, ve které najdete detaily i všechny ostatní možnosti.
{ "data": { "sessionMaterial": { "id": "session-material:2017/mipyt-kam:requests-click:2", "title": "Click – Rozhraní pro příkazovou řádku", "html": "\n \n \n\n <h1>click</h1>\n<p>Nechme internety na chvíli být a pojďme se podívat na úplně jinou knihovnu,\n<a href=\"http://click.pocoo.org/6/\">click</a>.</p>\n<p>Knihovna <code>click</code> slouží k vytváření rozhraní pro příkazovou řádku\n(angl. <em>command line interface</em>, CLI).\nPrimárně to je zpracování argumentů, ale click umí zjednodušit i výstup.</p>\n<p>Click je dobré používat s knihovnou <code>colorama</code>, která se stará o obarvování\ntextu na příkazové řádce ve Windows (a na Unixu nedělá nic).\nNainstalujte si tedy obě:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">$ </span>python -m pip install click colorama\n</pre></div><h2>Argumenty příkazové řádky</h2>\n<p>Nástroje na zpracování argumentů z CLI jsou i přímo ve standardní knihovně,\na dokonce jich není málo: <a href=\"https://docs.python.org/3/library/os.html#os.environ\">os.environ</a>, <a href=\"https://docs.python.org/3/library/argparse.html\">argparse</a>, <a href=\"https://docs.python.org/3/library/optparse.html\">optparse</a>, <a href=\"https://docs.python.org/3/library/getopt.html\">getopt</a>.\nS knihovnou <code>click</code> je ale práce mnohem příjemnější a výsledky většinou\nlépe odpovídají zavedeným konvencím.</p>\n<div class=\"admonition note\"><p>Cena za jednoduchost a konzistenci je, že některé styly návrhu CLI click\nnepodporuje.\nMáte-li existující rozhraní, které chcete jen převést do Pythonu,\nclick nejspíš nebude nejlepší volba.</p>\n</div><p>Takto jednoduše se dá vytvořit aplikace s přepínači:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">click</span>\n\n<span class=\"nd\">@click.command</span><span class=\"p\">()</span>\n<span class=\"nd\">@click.option</span><span class=\"p\">(</span><span class=\"s1\">'--count'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">metavar</span><span class=\"o\">=</span><span class=\"s1\">'COUNT'</span><span class=\"p\">,</span>\n <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s1\">'Number of greetings.'</span><span class=\"p\">)</span>\n<span class=\"nd\">@click.option</span><span class=\"p\">(</span><span class=\"s1\">'--name'</span><span class=\"p\">,</span> <span class=\"n\">prompt</span><span class=\"o\">=</span><span class=\"s1\">'Your name'</span><span class=\"p\">,</span> <span class=\"n\">metavar</span><span class=\"o\">=</span><span class=\"s1\">'NAME'</span><span class=\"p\">,</span>\n <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s1\">'The person to greet.'</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hello</span><span class=\"p\">(</span><span class=\"n\">count</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Simple program that greets NAME for a total of COUNT times."""</span>\n <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">count</span><span class=\"p\">):</span>\n <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">echo</span><span class=\"p\">(</span><span class=\"s1\">'Hello {}!'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">))</span>\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s1\">'__main__'</span><span class=\"p\">:</span>\n <span class=\"n\">hello</span><span class=\"p\">()</span>\n</pre></div><p>Vyzkoušejte si ji! Máte-li ji uloženou jako <code>hello.py</code>, zkuste:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">$ </span>python hello.py\n<span class=\"gp\">$ </span>python hello.py --help\n<span class=\"gp\">$ </span>python hello.py --name Pythonista\n<span class=\"gp\">$ </span>python hello.py --count <span class=\"m\">5</span>\n</pre></div><h2>Příkazy a přepínače</h2>\n<p>Funkce s dekorátorem <code>@click.command</code> je <em>příkaz</em> – když ji zavoláte,\nclick zpracuje argumenty příkazové řádky a zavolá původní funkci\ns příslušnými pythonními hodnotami.\nProto se dává do bloku <code>if __name__ == '__main__':</code>, který se spustí, jen\nkdyž se pythonní soubor spoustí „přímo“.\nKdyž je soubor importován, tenhle blok se neprovede.</p>\n<p>Dekorátory <code>@click.option</code> a <code>@click.argument</code> pak přidávají přepínače\na argumenty.</p>\n<p><em>Přepínače</em> (angl. <em>options</em>), přidávané pomocí <code>option</code>, jsou nepovinné\nparametry, kterými se nějak obměňuje chování programu.\nPokud uživatel nějaký přepínač nezadá, použije se hodnota zadaná jako <code>default</code>\n(nebo <code>None</code>, když <code>default</code> chybí).</p>\n<p>Podle <code>default</code> se řídí i typ argumentu, není-li dán explicitně.\nTakže <code>count</code> v příkladu výše je celé číslo.</p>\n<p>Jména přepínačů začínají, podle Unixové konvence, pomlčkami: jednou pomlčkou\npro jednopísmenné zkratky, dvěma pomlčkami pro vícepísmenná jména.\nJeden přepínač může mít i víc jmen.</p>\n<p>Speciální případ jsou booleovské přepínače, které mají jedno jméno\npro <code>True</code> a jiné pro <code>False</code>.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">click</span>\n\n<span class=\"nd\">@click.command</span><span class=\"p\">()</span>\n<span class=\"nd\">@click.option</span><span class=\"p\">(</span><span class=\"s1\">'-n'</span><span class=\"p\">,</span> <span class=\"s1\">'--name'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s1\">'world'</span><span class=\"p\">,</span>\n <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s1\">'Name of the person to greet'</span><span class=\"p\">)</span>\n<span class=\"nd\">@click.option</span><span class=\"p\">(</span><span class=\"s1\">'-c/-C'</span><span class=\"p\">,</span> <span class=\"s1\">'--color/--no-color'</span><span class=\"p\">,</span>\n <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s1\">'Make the output colorful'</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hello</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">):</span>\n <span class=\"k\">if</span> <span class=\"n\">color</span><span class=\"p\">:</span>\n <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">style</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">fg</span><span class=\"o\">=</span><span class=\"s1\">'blue'</span><span class=\"p\">)</span>\n <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">echo</span><span class=\"p\">(</span><span class=\"s1\">'Hello {}!'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">))</span>\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s1\">'__main__'</span><span class=\"p\">:</span>\n <span class=\"n\">hello</span><span class=\"p\">()</span>\n</pre></div><div class=\"highlight\"><pre><span></span><span class=\"gp\">$ </span>python hello.py\n<span class=\"go\">Hello world!</span>\n<span class=\"gp\">$ </span>python hello.py --name Guido\n<span class=\"go\">Hello Guido!</span>\n<span class=\"gp\">$ </span>python hello.py -n <span class=\"s1\">'Mr. Git'</span>\n<span class=\"go\">Hello Mr. Git!</span>\n<span class=\"gp\">$ </span>python hello.py --help\n<span class=\"go\">Usage: hello.py [OPTIONS]</span>\n\n<span class=\"go\">Options:</span>\n<span class=\"go\"> -n, --name TEXT Name of the person to greet</span>\n<span class=\"go\"> -c, --color / -C, --no-color Make the output colorful</span>\n<span class=\"go\"> --help Show this message and exit.</span>\n</pre></div><p>Přepínač <code>--help</code> přidává click sám.</p>\n<h2>Argumenty</h2>\n<p>Kromě přepínačů podporuje click i <em>argumenty</em>.\nPřepínače musí uživatel na řádce pojmenovat; argumenty se zadávají pozičně.\nPoužívají se ve dvou případech: pro povinné informace a pro argumenty, kterých\nmůže být libovolný počet.\nNa všechno ostatní radši použijte přepínače.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@click.command</span><span class=\"p\">()</span>\n<span class=\"nd\">@click.argument</span><span class=\"p\">(</span><span class=\"s1\">'directory'</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">cd</span><span class=\"p\">(</span><span class=\"n\">directory</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Change the current directory"""</span>\n <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">echo</span><span class=\"p\">(</span><span class=\"s1\">'Changing to directory {}'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">directory</span><span class=\"p\">))</span>\n\n<span class=\"nd\">@click.command</span><span class=\"p\">()</span>\n<span class=\"nd\">@click.argument</span><span class=\"p\">(</span><span class=\"s1\">'source'</span><span class=\"p\">,</span> <span class=\"n\">nargs</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"nd\">@click.argument</span><span class=\"p\">(</span><span class=\"s1\">'destination'</span><span class=\"p\">,</span> <span class=\"n\">nargs</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">mv</span><span class=\"p\">(</span><span class=\"n\">source</span><span class=\"p\">,</span> <span class=\"n\">destination</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Move any number of files to one destination"""</span>\n <span class=\"k\">for</span> <span class=\"n\">filename</span> <span class=\"ow\">in</span> <span class=\"n\">source</span><span class=\"p\">:</span>\n <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">echo</span><span class=\"p\">(</span><span class=\"s1\">'Moving {} to {}'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">destination</span><span class=\"p\">))</span>\n</pre></div><h2>Soubory</h2>\n<p>Má-li uživatel zadat jméno souboru, nepoužívejte řetězce, ale speciální typ\n<a href=\"http://click.pocoo.org/6/api/#click.File\"><code>click.File()</code></a>.\nClick za vás soubor automaticky otevře a zavře.\nKromě toho podporuje unixovskou konvenci, že <code>-</code> znamená standardní\nvstup/výstup.</p>\n<p>Argument pro <code>File</code> je mód, ve kterém se soubor otevírá, podobně jako pro\nfunkci <a href=\"https://docs.python.org/3/library/functions.html#open\"><code>open</code></a>:\n<code>'r'</code> pro čtení, <code>'w'</code> pro zápis.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@click.command</span><span class=\"p\">()</span>\n<span class=\"nd\">@click.argument</span><span class=\"p\">(</span><span class=\"s1\">'files'</span><span class=\"p\">,</span> <span class=\"n\">nargs</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">File</span><span class=\"p\">(</span><span class=\"s1\">'r'</span><span class=\"p\">))</span>\n<span class=\"k\">def</span> <span class=\"nf\">cat</span><span class=\"p\">(</span><span class=\"n\">files</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Print out the contents of the given files"""</span>\n <span class=\"k\">for</span> <span class=\"nb\">file</span> <span class=\"ow\">in</span> <span class=\"n\">files</span><span class=\"p\">:</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">(),</span> <span class=\"n\">end</span><span class=\"o\">=</span><span class=\"s1\">''</span><span class=\"p\">)</span>\n</pre></div><p>Existuje i varianta <a href=\"http://click.pocoo.org/6/api/#click.Path\"><code>click.Path()</code></a>,\nkterá soubor neotvírá. Pomocí ní jde např. zadat jméno adresáře.</p>\n<h2>Podpříkazy</h2>\n<p>Click má dobrou podporu pro <em>podpříkazy</em> známé z verzovacích systémů jako git:\npříkaz <code>git</code> sám o sobě nedělá nic, jen sdružuje podpříkazy jako <code>git add</code>\na <code>git commit</code>.</p>\n<p>Umí-li váš program více akcí, souhrnný příkaz označte <code>@click.group()</code>\na jednotlivé podpříkazy pak přidávejte pomocí <code>command()</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@click.group</span><span class=\"p\">()</span>\n<span class=\"k\">def</span> <span class=\"nf\">git2</span><span class=\"p\">():</span>\n <span class=\"k\">pass</span>\n\n<span class=\"nd\">@git2.command</span><span class=\"p\">()</span>\n<span class=\"k\">def</span> <span class=\"nf\">commit</span><span class=\"p\">():</span>\n <span class=\"n\">message</span> <span class=\"o\">=</span> <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">edit</span><span class=\"p\">(</span><span class=\"s1\">'Made some changes'</span><span class=\"p\">)</span>\n <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">echo</span><span class=\"p\">(</span><span class=\"s1\">'Making commit with message: {}'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">))</span>\n\n<span class=\"nd\">@git2.command</span><span class=\"p\">()</span>\n<span class=\"nd\">@click.argument</span><span class=\"p\">(</span><span class=\"s1\">'files'</span><span class=\"p\">,</span> <span class=\"n\">nargs</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">add</span><span class=\"p\">(</span><span class=\"n\">files</span><span class=\"p\">):</span>\n <span class=\"k\">for</span> <span class=\"nb\">file</span> <span class=\"ow\">in</span> <span class=\"n\">files</span><span class=\"p\">:</span>\n <span class=\"n\">click</span><span class=\"o\">.</span><span class=\"n\">echo</span><span class=\"p\">(</span><span class=\"s1\">'Adding {}'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">))</span>\n</pre></div><h2>A další</h2>\n<p>Tahle lekce není popis všeho, co click umí – je to jen ochutnávka,\nabyste věděli, co od téhle knihovny očekávat.</p>\n<p>Click má velice dobrou <a href=\"http://click.pocoo.org/6/\">dokumentaci</a>, ve které najdete detaily i všechny\nostatní možnosti.</p>\n\n\n " } } }