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í beze jména, ale záleží u nich na pořadí. Používají se ve dvou případech: pro povinné parametry a pro parametry, kterých může být zadán libovolný počet. Na všechno ostatní radši použijte přepínače.
Například příkaz cd potřebuje jeden argument: jméno adresáře,
do kterého má přepnout.
Jeho rozhraní by v Clicku vypadalo takto:
@click.command()
@click.argument('directory')
def cd(directory):
"""Change the current directory"""
click.echo('Changing to directory {}'.format(directory))
Proměnný počet argumentů se zadává pomocí nargs=-1 (0 nebo víc argumentů)
nebo nargs=-1, required=True (1 nebo víc).
Například příkaz mv bere N souborů a adresář, kam je přesune.
Takové rozhraní by v Clicku vypadalo následovně:
@click.command()
@click.argument('source', nargs=-1, required=True)
@click.argument('destination')
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:2018/mipyt-zima: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 <a href=\"http://click.pocoo.org/6/arguments/\"><em>argumenty</em></a>.\nPřepínače musí uživatel na řádce pojmenovat; argumenty se zadávají beze jména,\nale záleží u nich na pořadí.\nPoužívají se ve dvou případech: pro povinné parametry a pro parametry, kterých\nmůže být zadán libovolný počet.\nNa všechno ostatní radši použijte přepínače.</p>\n<p>Například příkaz <code>cd</code> potřebuje jeden argument: jméno adresáře,\ndo kterého má přepnout.\nJeho rozhraní by v Clicku vypadalo takto:</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</pre></div><p>Proměnný počet argumentů se zadává pomocí <code>nargs=-1</code> (0 nebo víc argumentů)\nnebo <code>nargs=-1, required=True</code> (1 nebo víc).</p>\n<p>Například příkaz <code>mv</code> bere <var>N</var> souborů a adresář, kam je přesune.\nTakové rozhraní by v Clicku vypadalo následovně:</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\">'source'</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=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</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>\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 "
}
}
}