Dokumentace

Jednou ze zásadních součástí každého kvalitního Python projektu je dokumentace. Protože chceme, abyste vytvářeli kvalitní projekty, podíváme se tedy i na dokumentaci.

Sphinx

Nejpoužívanějším nástrojem na vytváření dokumentace Python projektů je Sphinx. Když jste se dívali do dokumentace Flasku, requests, clicku, flexmocku, pytestu, betamaxu či Pythonu samotného, viděli jste dokumentaci vytvořenou ve Sphinxu.

Pro vytvoření základní kostry dokumentace se používá jednoduchý průvodce, sphinx.quickstart.

Postupujte podle následující ukázky. Jsou v ní zobrazeny jen věci, kde nestačí nechat výchozí hodnota; u ostatních otázek stačí výchozí hodnotu potvrdit (Enter). K modulům autodoc a doctest se dostaneme později.

$ . __venv__/bin/activate
(__venv__) $ python -m pip install sphinx
(__venv__) $ python -m sphinx.quickstart
Welcome to the Sphinx 1.5.5 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Enter the root path for documentation.
> Root path for the documentation [.]: docs

...

The project name will occur in several places in the built documentation.
> Project name: coolthing
> Author name(s): Pythonista Dokumentarista

Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1.  If you don't need this dual structure,
just set both to the same value.
> Project version []: 0.1
> Project release [0.1]: 

...

Please indicate if you want to use one of the following Sphinx extensions:
> autodoc: automatically insert docstrings from modules (y/n) [n]: y
> doctest: automatically test code snippets in doctest blocks (y/n) [n]: y
> intersphinx: link between Sphinx documentation of different projects (y/n) [n]: y

...

Finished: An initial directory structure has been created.

Průvodce vytvoří složku docs a v ní několik souborů:

  • conf.py – konfigurační soubor,
  • index.rst – vlastní text dokumantace,
  • Makefile, make.bat – spouštěcí soubory,
  • _static – adresář na obrázky, CSS apod.,
  • _templates – Adresář na vlastní šablony,
  • _build – adresář pro výstup, tedy hotovou dokumentaci.

Do gitu patří všechny nyní vytvořené soubory, kromě složky docs/_build, která by měla být ignorována.

Zatím se nebudeme zabývat obsahem těchto souborů, ale zkusíme základní kostru dokumentace sestavit do HTML.

Sphinx umí generovat dokumentaci ve více formátech (LaTeX, manuálové stránky atd.), pro nás bude podstatné především HTML.

(__venv__) $ cd docs
(__venv__) $ make html
...
Build finished. The HTML pages are in _build/html.

Ve zmíněné složce byste měli najít index.html, ten si můžete prohlédnout v prohlížeči.

Textový obsah v dokumentaci

Text dokumentace začíná v souboru index.rst a píše se ve značkovacím formátu reStructuredText neboli rst. Bohužel nelze psát v Markdownu, ačkoli existují složité triky, jak docílit nějaké konverze.

reStructuredText se od Markdownu liší v syntaxi, která je komplikovanější na psaní, ale umožňuje dělat komplexnější věci.

Pro přehled o tom, co reStructuredText umí a jakou má syntaxi, můžete použít přehled z dokumentace Sphinxu, případně tahák.

V index.rst je seznam kapitol:

.. toctree::
   :maxdepth: 2

Tam můžete přidat další kapitoly:

.. toctree::
   :maxdepth: 2

   intro
   tutorial/foo
   tutorial/bar
   ...

Soubory s kapitolami je třeba vytvořit ve složce docs s příponou .rst (např. tutorial/foo.rst). Text lze pak přidávat samozřejmě do těchto souborů i do index.rst.

Chcete-li odkazovat na některou sekci, označíme si ji pomocí .. _label::

.. _my-reference-label:

Section to cross-reference
--------------------------

This is the text of the section.

Poté na ni lze odkazovat odkudkoli z dokumentace pomocí konstrukce ref:

It refers to the section itself, see :ref:`my-reference-label`.
It could refer to a different section as well :)

Co do dokumentace psát

Teď, když víte jak něco napsat, pojďme si povědět co vlastně psát. K čemu dokumentace vlastně je?

Dobrá dokumentace vysvětluje, proč a jak by váš projekt měl někdo používat. Jak říká Eric Holscher v jedné své prezentaci,

Když lidi neví, že váš projekt existuje,
nebudou ho používat.
Když lidi nepřijdou na to, jak váš projekt nainstalovat,
nebudou ho používat.
Když lidi nepřijdou na to, jak váš projekt použít,
nebudou ho používat.

Pokud pracujete v malém týmu, teoreticky jde to všechno kolegům prostě říct, ale potom se musíte spoléhat na to, že to nezapomenete (a neodejdete z týmu). Mnohem lepší je dokumentaci sepsat co nejdřív, dokud máte všechno čerstvě v hlavě.

Nechce-li se vám nastavovat Sphinx, můžete informace napsat aspoň do malého README. Ale i tam by měl být stejný druh informací jako ve „velké“ dokumentaci.

Na první stránce dokumentace (nebo v README) typicky najdeme:

  • krátký text o tom, co projekt dělá;
  • ukázku – u knihovny příklad kódu, u aplikace screenshot, u webové stránky odkaz na běžící instanci;
  • návod na instalaci;
  • odkazy na zbytek dokumentace;
  • odkazy pro přispěvatele – kde je repozitář, kde nahlásit chybu;
  • licenci.

Delší dokumentace knihoven pak většinou obsahuje:

  • tutoriál – návod, který uživatele provede použitím a možnostmi knihovny;
  • popis architektury, návrhu, použitých konceptů;
  • API dokumentaci – popis všech veřejných modulů, tříd, funkcí a podobně;
  • podrobný návod jak přispívat.

doctest

doctest je modul ze standardní knihovny, který najde v dokumentaci bloky kódu a otestuje, jestli odpovídají ukázanému výstupu.

Pro nás to bude způsob, jak testovat dokumentaci – tedy jestli jsou ukázky kódu v ní stále platné. Dá se sice použít i k testování samotného kódu, ale na to existují lepší nástroje.

V kombinaci se Sphinxem se dá použít rozšíření doctest, které jsme v průvodci aktivovali. Můžete to dělat dvěma způsoby. První je mít v dokumentaci příklad vypadající jako interaktivní konzole. Takový příklad nemusí být odsazený ani ničím uvozený; stačí >>> na začátku.

>>> 1 + 1
2

Doctest v tomto případě otestuje, že vše funguje, jak má. V tomto případě se provede součet a zkontroluje se, zda výsledek je 2.

Druhý způsob je mít v dokumentaci nejdříve kód:

print('foo')

A dále někde jinde výstup volání:

foo

K tomu všemu složí několik direktiv:

.. testsetup::

Direktiva pro potřebný kód, který se musí provést, aby příklad fungoval, ale nebude v dokumentaci zobrazen (např. kód pro vytvoření falešného objektu, import...).

.. testcleanup::

Podobná direktiva jako .. testsetup:: provedená po skončení testů. V dokumentaci nebude kód zobrazen.

.. doctest::

Test s interaktivní konzolí. V dokumentaci bude zobrazen, pokud nepoužijete flag :hide:.

.. testcode::

Kód testu bez interaktivní konzole, co chcete kontrolovat, musíte dát na standardní výstup. V dokumentaci bude zobrazen, pokud nepoužijete flag :hide:.

.. testoutput::

Výstup posledního testcode bloku. V dokumentaci bude kód zobrazen, pokud nepoužijete flag :hide:.

Kompletní příklad

Zde můžete vidět výše zmíněné direktivy použité dohromady. Jedná se o umělý příklad, kdy použitou třídu připravíme v direktivě testsetup. V praxi pak doctestem testujeme, jestli naše dokumentace odpovídá chování naší implementace, třídu Parrot bychom tedy odněkud naimportovali.

The parrot module
=================

.. testsetup::

   class Parrot:
       def voom(self, voltage):
           print('This parrot wouldn\'t voom if you put {} volts through it!'.format(voltage))

       def die(self):
           return 'RIP'


   parrot = Parrot()

The parrot module is a module about parrots.

Doctest example:

.. doctest::

   >>> parrot.voom(3000)
   This parrot wouldn't voom if you put 3000 volts through it!

Test-Output example:

.. testcode::

   parrot.voom(3000)

This would output:

.. testoutput::

   This parrot wouldn't voom if you put 3000 volts through it!

You can use other values:

.. testcode::

   parrot.voom(230)

.. testoutput::
   :hide:

   This parrot wouldn't voom if you put 230 volts through it!


.. testcleanup::

   parrot.die()

Testy se také dají zařazovat do skupin, více v dokumentaci.

(__venv__) $ make doctest
...
Document: intro
---------------
1 items passed all tests:
   3 tests in default
3 tests in 1 items.
3 passed and 0 failed.
Test passed.
1 items passed all tests:
   1 tests in default (cleanup code)
1 tests in 1 items.
1 passed and 0 failed.
Test passed.

Doctest summary
===============
    3 tests
    0 failures in tests
    0 failures in setup code
    0 failures in cleanup code
...

Import z vlastního kódu

Pokud nemáte nainstalovaný vlastní balíček a budete z něj chtít v doctestu importovat, pravděpodobně dostanete ImportError. V takovém případě pomůže drobná editace na začátku conf.py. Musíte přidat adresář, ze kterého lze váš kód importovat, do sys.path. Pokud jste postupovali podle návodu výše, máte dokumentaci v adresáři docs, je tedy potřeba přidat nadřazený adresář (..):

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('..'))

Travis CI

Neexistuje žádný unifikovaný způsob, jak specifikovat závislosti pro sestavení dokumentace. Proto, pokud chcete mít nějaký jednoduchý způsob, jak pouštět doctesty na Travisu, vytvořte například soubor docs/requirements.txt a do něj dejte závislosti potřebné pro sestavení dokumentace. Je na vás, jestli tam budou pouze extra závislosti oproti těm v setup.py (většinou pouze sphinx), nebo všechny závislosti, aby šel použít soubor samostatně.

Poté na Travisu můžete udělat něco jako:

language: python
python:
- '3.6'
install:
- python setup.py install
- pip install -r docs/requirements.txt
script:
- python setup.py test --addopts -v
- cd docs && make doctest

autodoc

Pro dokumentaci API lze použít autodoc, rozšíření Sphinxu, které jsme povolili v průvodci.

Nemáte-li toto rozšíření povolené, přidejte jej do conf.py:

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.doctest',
    'sphinx.ext.intersphinx',
]

Rozšíření autodoc se používá takto:

.. automodule:: mymodule
   :members:

Tento příklad na dané místo vygeneruje dokumentaci složenou z dokumentačních řetězců jednotlivých funkcí, tříd a metod v modulu mymodule.

Pokud chcete selektivně vybrat, dokumentaci čeho chcete generovat, můžete použít i jiné direktivy.

Pro vygenerování hezké struktury si můžete pomoci příkazem apidoc:

(__venv__) $ python -m sphinx.apidoc -o docs mymodule

V dokumentačních řetězcích samozřejmě můžete použít reStructuredText a je to dokonce žádoucí.

Zde je ukázka z betamaxu (Copyright 2013 Ian Cordasco):

class Betamax:

    """This object contains the main API of the request-vcr library.

    This object is entirely a context manager so all you have to do is:

    .. code::

        s = requests.Session()
        with Betamax(s) as vcr:
            vcr.use_cassette('example')
            r = s.get('https://httpbin.org/get')

    Or more concisely, you can do:

    .. code::

        s = requests.Session()
        with Betamax(s).use_cassette('example') as vcr:
            r = s.get('https://httpbin.org/get')

    This object allows for the user to specify the cassette library directory
    and default cassette options.

    .. code::

        s = requests.Session()
        with Betamax(s, cassette_library_dir='tests/cassettes') as vcr:
            vcr.use_cassette('example')
            r = s.get('https://httpbin.org/get')

        with Betamax(s, default_cassette_options={
                're_record_interval': 1000
                }) as vcr:
            vcr.use_cassette('example')
            r = s.get('https://httpbin.org/get')
    """

Existují různé způsoby, jak dokumentovat argumenty, návratové hodnoty apod. Zvídavým studentům doporučujeme podívat se na rozšíření Napoleon.

Odkazy na třídy a moduly

Máte-li zdokumentovaný modul, funkci, třídu, metodu apod., je možné na ni odkázat pomocí konstrukce :mod:, :func:, :class:, :meth: a dalších ze Sphinxové domény Python:

To test the parrot's electrical resistance, use :meth:`parrot.voom()`.

V této části dokumentace Sphinxu též najdete způsob, jak dokumentovat API bez použití autodoc.

Všechny zdokumentované objekty se automaticky přidávají do rejstříku. Chcete-li do rejstříku přidat něco navíc, použijte direktivu index.

README.rst

Když už se stejně zabýváme reStructuredTextem, je dobré váš README přepsat nebo převést do stejného formátu. Na PyPI pak bude váš projekt vypadat lépe.

Při přejmenování na README.rst dejte pozor na patřičné změny v setup.py.

Read the Docs

Pokud svůj repositář na GitHubu změníte na veřejný, můžete využít službu Read the Docs k hostování dokumentace ve Sphinxu. Dokumentace se sestaví při každém pushnutí na GitHub.

Pokud Read the Docs použijete, nezapomeňte na dokumentaci odkázat z README.rst.

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2017/pyknihovny-brno:docs:0",
      "title": "Dokumentace",
      "html": "\n          \n    \n\n    <h1>Dokumentace</h1>\n<p>Jednou ze z&#xE1;sadn&#xED;ch sou&#x10D;&#xE1;st&#xED; ka&#x17E;d&#xE9;ho kvalitn&#xED;ho Python projektu je dokumentace.\nProto&#x17E;e chceme, abyste vytv&#xE1;&#x159;eli kvalitn&#xED; projekty, pod&#xED;v&#xE1;me se tedy i na\ndokumentaci.</p>\n<h2>Sphinx</h2>\n<p>Nejpou&#x17E;&#xED;van&#x11B;j&#x161;&#xED;m n&#xE1;strojem na vytv&#xE1;&#x159;en&#xED; dokumentace Python projekt&#x16F; je <a href=\"http://www.sphinx-doc.org/\">Sphinx</a>.\nKdy&#x17E; jste se d&#xED;vali do dokumentace Flasku, requests, clicku, flexmocku, pytestu,\nbetamaxu &#x10D;i Pythonu samotn&#xE9;ho, vid&#x11B;li jste dokumentaci vytvo&#x159;enou ve Sphinxu.</p>\n<p>Pro vytvo&#x159;en&#xED; z&#xE1;kladn&#xED; kostry dokumentace se pou&#x17E;&#xED;v&#xE1; jednoduch&#xFD; pr&#x16F;vodce,\n<code>sphinx.quickstart</code>.</p>\n<p>Postupujte podle n&#xE1;sleduj&#xED;c&#xED; uk&#xE1;zky. Jsou v&#xA0;n&#xED; zobrazeny jen v&#x11B;ci,\nkde nesta&#x10D;&#xED; nechat v&#xFD;choz&#xED; hodnota; u ostatn&#xED;ch ot&#xE1;zek sta&#x10D;&#xED; v&#xFD;choz&#xED; hodnotu\npotvrdit (<kbd>Enter</kbd>).\nK modul&#x16F;m <code>autodoc</code> a <code>doctest</code> se dostaneme pozd&#x11B;ji.</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> . __venv__/bin/activate\n<span style=\"color: #00aaaa\">(__venv__) $</span> python -m pip install sphinx\n<span style=\"color: #00aaaa\">(__venv__) $</span> python -m sphinx.quickstart\n<span style=\"font-weight: bold\">Welcome to the Sphinx 1.5.5 quickstart utility.</span>\n\nPlease enter values for the following settings (just press Enter to\naccept a default value, if one is given in brackets).\n\nEnter the root path for documentation.\n<span style=\"color: #E850A8\">&gt; Root path for the documentation [.]: </span>docs\n\n...\n\nThe project name will occur in several places in the built documentation.\n<span style=\"color: #E850A8\">&gt; Project name: </span>coolthing\n<span style=\"color: #E850A8\">&gt; Author name(s): </span>Pythonista Dokumentarista\n\nSphinx has the notion of a &quot;version&quot; and a &quot;release&quot; for the\nsoftware. Each version can have multiple releases. For example, for\nPython the version is something like 2.5 or 3.0, while the release is\nsomething like 2.5.1 or 3.0a1.  If you don&apos;t need this dual structure,\njust set both to the same value.\n<span style=\"color: #E850A8\">&gt; Project version []: </span>0.1\n<span style=\"color: #E850A8\">&gt; Project release [0.1]: </span>\n\n...\n\nPlease indicate if you want to use one of the following Sphinx extensions:\n<span style=\"color: #E850A8\">&gt; autodoc: automatically insert docstrings from modules (y/n) [n]: </span>y\n<span style=\"color: #E850A8\">&gt; doctest: automatically test code snippets in doctest blocks (y/n) [n]: </span>y\n<span style=\"color: #E850A8\">&gt; intersphinx: link between Sphinx documentation of different projects (y/n) [n]: </span>y\n\n...\n\n<span style=\"font-weight: bold\">Finished: An initial directory structure has been created.</span></code></pre></div><p>Pr&#x16F;vodce vytvo&#x159;&#xED; slo&#x17E;ku <code>docs</code> a v&#xA0;n&#xED; n&#x11B;kolik soubor&#x16F;:</p>\n<ul>\n<li><code>conf.py</code> &#x2013; konfigura&#x10D;n&#xED; soubor,</li>\n<li><code>index.rst</code> &#x2013; vlastn&#xED; text dokumantace,</li>\n<li><code>Makefile</code>, <code>make.bat</code> &#x2013; spou&#x161;t&#x11B;c&#xED; soubory,</li>\n<li><code>_static</code> &#x2013;  adres&#xE1;&#x159; na obr&#xE1;zky, CSS apod.,</li>\n<li><code>_templates</code> &#x2013; Adres&#xE1;&#x159; na vlastn&#xED; &#x161;ablony,</li>\n<li><code>_build</code> &#x2013; adres&#xE1;&#x159; pro v&#xFD;stup, tedy hotovou dokumentaci.</li>\n</ul>\n<p>Do gitu pat&#x159;&#xED; v&#x161;echny nyn&#xED; vytvo&#x159;en&#xE9; soubory, krom&#x11B; slo&#x17E;ky <code>docs/_build</code>,\nkter&#xE1; by m&#x11B;la b&#xFD;t ignorov&#xE1;na.</p>\n<p>Zat&#xED;m se nebudeme zab&#xFD;vat obsahem t&#x11B;chto soubor&#x16F;, ale zkus&#xED;me z&#xE1;kladn&#xED; kostru\ndokumentace sestavit do HTML.</p>\n<div class=\"admonition note\"><p>Sphinx um&#xED; generovat dokumentaci ve v&#xED;ce form&#xE1;tech (LaTeX,\nmanu&#xE1;lov&#xE9; str&#xE1;nky atd.), pro n&#xE1;s bude podstatn&#xE9; p&#x159;edev&#x161;&#xED;m HTML.</p>\n</div><div class=\"highlight\"><pre><span></span><span class=\"gp\">(__venv__) $ </span><span class=\"nb\">cd</span> docs\n<span class=\"gp\">(__venv__) $ </span>make html\n<span class=\"go\">...</span>\n<span class=\"go\">Build finished. The HTML pages are in _build/html.</span>\n</pre></div><p>Ve zm&#xED;n&#x11B;n&#xE9; slo&#x17E;ce byste m&#x11B;li naj&#xED;t <code>index.html</code>, ten si m&#x16F;&#x17E;ete prohl&#xE9;dnout\nv prohl&#xED;&#x17E;e&#x10D;i.</p>\n<h2>Textov&#xFD; obsah v dokumentaci</h2>\n<p>Text dokumentace za&#x10D;&#xED;n&#xE1; v souboru <code>index.rst</code> a p&#xED;&#x161;e se ve zna&#x10D;kovac&#xED;m form&#xE1;tu\n<a href=\"http://www.sphinx-doc.org/en/stable/rest.html\">reStructuredText</a> neboli rst. Bohu&#x17E;el nelze ps&#xE1;t v Markdownu, a&#x10D;koli existuj&#xED;\nslo&#x17E;it&#xE9; triky, jak doc&#xED;lit n&#x11B;jak&#xE9; konverze.</p>\n<p>reStructuredText se od Markdownu li&#x161;&#xED; v syntaxi, kter&#xE1; je komplikovan&#x11B;j&#x161;&#xED; na\npsan&#xED;, ale umo&#x17E;&#x148;uje d&#x11B;lat komplexn&#x11B;j&#x161;&#xED; v&#x11B;ci.</p>\n<p>Pro p&#x159;ehled o tom, co reStructuredText um&#xED; a jakou m&#xE1; syntaxi,\nm&#x16F;&#x17E;ete pou&#x17E;&#xED;t <a href=\"http://www.sphinx-doc.org/en/stable/rest.html\">p&#x159;ehled</a> z&#xA0;dokumentace Sphinxu, p&#x159;&#xED;padn&#x11B; <a href=\"https://github.com/ralsina/rst-cheatsheet\">tah&#xE1;k</a>.</p>\n<p>V <code>index.rst</code> je seznam kapitol:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"p\">..</span> <span class=\"ow\">toctree</span><span class=\"p\">::</span>\n   <span class=\"nc\">:maxdepth:</span> <span class=\"nf\">2</span>\n</pre></div><p>Tam m&#x16F;&#x17E;ete p&#x159;idat dal&#x161;&#xED; kapitoly:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"p\">..</span> <span class=\"ow\">toctree</span><span class=\"p\">::</span>\n   <span class=\"nc\">:maxdepth:</span> <span class=\"nf\">2</span>\n\n   intro\n   tutorial/foo\n   tutorial/bar\n<span class=\"cp\">   ...</span>\n</pre></div><p>Soubory s kapitolami je t&#x159;eba vytvo&#x159;it ve slo&#x17E;ce <code>docs</code> s p&#x159;&#xED;ponou <code>.rst</code>\n(nap&#x159;. <code>tutorial/foo.rst</code>).\nText lze pak p&#x159;id&#xE1;vat samoz&#x159;ejm&#x11B; do t&#x11B;chto soubor&#x16F; i do\n<code>index.rst</code>.</p>\n<p>Chcete-li odkazovat na n&#x11B;kterou sekci, ozna&#x10D;&#xED;me si ji pomoc&#xED; <code>.. _label:</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"p\">..</span> <span class=\"nt\">_my-reference-label:</span>\n\n<span class=\"gh\">Section to cross-reference</span>\n<span class=\"gh\">--------------------------</span>\n\nThis is the text of the section.\n</pre></div><p>Pot&#xE9; na ni lze odkazovat odkudkoli z dokumentace pomoc&#xED;\n<a href=\"http://www.sphinx-doc.org/en/1.4.8/markup/inline.html#role-ref\">konstrukce ref</a>:</p>\n<div class=\"highlight\"><pre><span></span>It refers to the section itself, see <span class=\"na\">:ref:</span><span class=\"nv\">`my-reference-label`</span>.\nIt could refer to a different section as well :)\n</pre></div><h2>Co do dokumentace ps&#xE1;t</h2>\n<p>Te&#x10F;, kdy&#x17E; v&#xED;te jak n&#x11B;co napsat, poj&#x10F;me si pov&#x11B;d&#x11B;t <em>co</em> vlastn&#x11B; ps&#xE1;t.\nK&#xA0;&#x10D;emu dokumentace vlastn&#x11B; je?</p>\n<p>Dobr&#xE1; dokumentace vysv&#x11B;tluje, pro&#x10D; a jak by v&#xE1;&#x161; projekt m&#x11B;l n&#x11B;kdo pou&#x17E;&#xED;vat.\nJak &#x159;&#xED;k&#xE1; Eric Holscher v&#xA0;<a href=\"http://www.writethedocs.org/guide/writing/beginners-guide-to-docs/\">jedn&#xE9; sv&#xE9; prezentaci</a>,</p>\n<blockquote><p>Kdy&#x17E; lidi nev&#xED;, &#x17E;e v&#xE1;&#x161; projekt existuje,<br>\nnebudou ho pou&#x17E;&#xED;vat.<br>\nKdy&#x17E; lidi nep&#x159;ijdou na to, jak v&#xE1;&#x161; projekt nainstalovat,<br>\nnebudou ho pou&#x17E;&#xED;vat.<br>\nKdy&#x17E; lidi nep&#x159;ijdou na to, jak v&#xE1;&#x161; projekt pou&#x17E;&#xED;t,<br>\nnebudou ho pou&#x17E;&#xED;vat.<br></p>\n</blockquote>\n<p>Pokud pracujete v&#xA0;mal&#xE9;m t&#xFD;mu, teoreticky jde to v&#x161;echno koleg&#x16F;m prost&#x11B; &#x159;&#xED;ct,\nale potom se mus&#xED;te spol&#xE9;hat na to, &#x17E;e to nezapomenete (a neodejdete z&#xA0;t&#xFD;mu).\nMnohem lep&#x161;&#xED; je dokumentaci sepsat co nejd&#x159;&#xED;v, dokud m&#xE1;te v&#x161;echno &#x10D;erstv&#x11B;\nv&#xA0;hlav&#x11B;.</p>\n<p>Nechce-li se v&#xE1;m nastavovat Sphinx, m&#x16F;&#x17E;ete informace napsat aspo&#x148; do mal&#xE9;ho\nREADME. Ale i tam by m&#x11B;l b&#xFD;t stejn&#xFD; druh informac&#xED; jako ve &#x201E;velk&#xE9;&#x201C; dokumentaci.</p>\n<p>Na prvn&#xED; str&#xE1;nce dokumentace (nebo v&#xA0;README) typicky najdeme:</p>\n<ul>\n<li>kr&#xE1;tk&#xFD; text o tom, co projekt d&#x11B;l&#xE1;;</li>\n<li>uk&#xE1;zku &#x2013; u knihovny p&#x159;&#xED;klad k&#xF3;du, u aplikace screenshot, u webov&#xE9; str&#xE1;nky\nodkaz na b&#x11B;&#x17E;&#xED;c&#xED; instanci;</li>\n<li>n&#xE1;vod na instalaci;</li>\n<li>odkazy na zbytek dokumentace;</li>\n<li>odkazy pro p&#x159;isp&#x11B;vatele &#x2013; kde je repozit&#xE1;&#x159;, kde nahl&#xE1;sit chybu;</li>\n<li>licenci.</li>\n</ul>\n<p>Del&#x161;&#xED; dokumentace knihoven pak v&#x11B;t&#x161;inou obsahuje:</p>\n<ul>\n<li>tutori&#xE1;l &#x2013; n&#xE1;vod, kter&#xFD; u&#x17E;ivatele provede pou&#x17E;it&#xED;m a mo&#x17E;nostmi knihovny;</li>\n<li>popis architektury, n&#xE1;vrhu, pou&#x17E;it&#xFD;ch koncept&#x16F;;</li>\n<li>API dokumentaci &#x2013; popis v&#x161;ech ve&#x159;ejn&#xFD;ch modul&#x16F;, t&#x159;&#xED;d, funkc&#xED; a podobn&#x11B;;</li>\n<li>podrobn&#xFD; n&#xE1;vod jak p&#x159;isp&#xED;vat.</li>\n</ul>\n<h2>doctest</h2>\n<p><code>doctest</code> je modul ze standardn&#xED; knihovny, kter&#xFD; najde v dokumentaci bloky k&#xF3;du\na otestuje, jestli odpov&#xED;daj&#xED; uk&#xE1;zan&#xE9;mu v&#xFD;stupu.</p>\n<p>Pro n&#xE1;s to bude zp&#x16F;sob, jak testovat <em>dokumentaci</em> &#x2013; tedy jestli jsou uk&#xE1;zky\nk&#xF3;du v&#xA0;n&#xED; st&#xE1;le platn&#xE9;.\nD&#xE1; se sice pou&#x17E;&#xED;t i k&#xA0;testov&#xE1;n&#xED; samotn&#xE9;ho k&#xF3;du, ale na to existuj&#xED;\n<a href=\"/2017/pyknihovny-brno/intro/testing/\">lep&#x161;&#xED; n&#xE1;stroje</a>.</p>\n<p>V kombinaci se Sphinxem se d&#xE1; pou&#x17E;&#xED;t roz&#x161;&#xED;&#x159;en&#xED; <code>doctest</code>, kter&#xE9; jsme v pr&#x16F;vodci\naktivovali. M&#x16F;&#x17E;ete to d&#x11B;lat dv&#x11B;ma zp&#x16F;soby. Prvn&#xED; je m&#xED;t v dokumentaci\np&#x159;&#xED;klad vypadaj&#xED;c&#xED; jako interaktivn&#xED; konzole.\nTakov&#xFD; p&#x159;&#xED;klad nemus&#xED; b&#xFD;t odsazen&#xFD; ani ni&#x10D;&#xED;m uvozen&#xFD;; sta&#x10D;&#xED; <code>&gt;&gt;&gt;</code> na za&#x10D;&#xE1;tku.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"o\">&gt;&gt;&gt;</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n<span class=\"mi\">2</span>\n</pre></div><p>Doctest v tomto p&#x159;&#xED;pad&#x11B; otestuje, &#x17E;e v&#x161;e funguje, jak m&#xE1;.\nV tomto p&#x159;&#xED;pad&#x11B; se provede sou&#x10D;et a zkontroluje se, zda v&#xFD;sledek je 2.</p>\n<p>Druh&#xFD; zp&#x16F;sob je m&#xED;t v dokumentaci nejd&#x159;&#xED;ve k&#xF3;d:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;foo&apos;</span><span class=\"p\">)</span>\n</pre></div><p>A d&#xE1;le n&#x11B;kde jinde v&#xFD;stup vol&#xE1;n&#xED;:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">foo</span>\n</pre></div><p>K tomu v&#x161;emu slo&#x17E;&#xED; n&#x11B;kolik direktiv:</p>\n<h3>.. testsetup::</h3>\n<p>Direktiva pro pot&#x159;ebn&#xFD; k&#xF3;d, kter&#xFD; se mus&#xED; prov&#xE9;st, aby p&#x159;&#xED;klad fungoval, ale\nnebude v dokumentaci zobrazen (nap&#x159;. k&#xF3;d pro vytvo&#x159;en&#xED; fale&#x161;n&#xE9;ho objektu,\nimport...).</p>\n<h3>.. testcleanup::</h3>\n<p>Podobn&#xE1; direktiva jako <code>.. testsetup::</code> proveden&#xE1; po skon&#x10D;en&#xED; test&#x16F;.\nV dokumentaci nebude k&#xF3;d zobrazen.</p>\n<h3>.. doctest::</h3>\n<p>Test s interaktivn&#xED; konzol&#xED;. V dokumentaci bude zobrazen, pokud nepou&#x17E;ijete flag\n<code>:hide:</code>.</p>\n<h3>.. testcode::</h3>\n<p>K&#xF3;d testu bez interaktivn&#xED; konzole, co chcete kontrolovat, mus&#xED;te d&#xE1;t na\nstandardn&#xED; v&#xFD;stup. V dokumentaci bude zobrazen, pokud nepou&#x17E;ijete flag\n<code>:hide:</code>.</p>\n<h3>.. testoutput::</h3>\n<p>V&#xFD;stup posledn&#xED;ho testcode bloku. V dokumentaci bude k&#xF3;d zobrazen, pokud\nnepou&#x17E;ijete flag <code>:hide:</code>.</p>\n<h3>Kompletn&#xED; p&#x159;&#xED;klad</h3>\n<p>Zde m&#x16F;&#x17E;ete vid&#x11B;t v&#xFD;&#x161;e zm&#xED;n&#x11B;n&#xE9; direktivy pou&#x17E;it&#xE9; dohromady.\nJedn&#xE1; se o um&#x11B;l&#xFD; p&#x159;&#xED;klad, kdy pou&#x17E;itou t&#x159;&#xED;du p&#x159;iprav&#xED;me v direktiv&#x11B; <code>testsetup</code>.\nV praxi pak doctestem testujeme, jestli na&#x161;e dokumentace odpov&#xED;d&#xE1; chov&#xE1;n&#xED;\nna&#x161;&#xED; implementace, t&#x159;&#xED;du <code>Parrot</code> bychom tedy odn&#x11B;kud naimportovali.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gh\">The parrot module</span>\n<span class=\"gh\">=================</span>\n\n<span class=\"p\">..</span> <span class=\"ow\">testsetup</span><span class=\"p\">::</span>\n\n   class Parrot:\n       def voom(self, voltage):\n           print(&apos;This parrot wouldn\\&apos;t voom if you put {} volts through it!&apos;.format(voltage))\n\n       def die(self):\n           return &apos;RIP&apos;\n\n\n   parrot = Parrot()\n\nThe parrot module is a module about parrots.\n\nDoctest example:\n\n<span class=\"p\">..</span> <span class=\"ow\">doctest</span><span class=\"p\">::</span>\n\n   &gt;&gt;&gt; parrot.voom(3000)\n   This parrot wouldn&apos;t voom if you put 3000 volts through it!\n\nTest-Output example:\n\n<span class=\"p\">..</span> <span class=\"ow\">testcode</span><span class=\"p\">::</span>\n\n   parrot.voom(3000)\n\nThis would output:\n\n<span class=\"p\">..</span> <span class=\"ow\">testoutput</span><span class=\"p\">::</span>\n\n   This parrot wouldn&apos;t voom if you put 3000 volts through it!\n\nYou can use other values:\n\n<span class=\"p\">..</span> <span class=\"ow\">testcode</span><span class=\"p\">::</span>\n\n   parrot.voom(230)\n\n<span class=\"p\">..</span> <span class=\"ow\">testoutput</span><span class=\"p\">::</span>\n   <span class=\"nc\">:hide:</span>\n\n   This parrot wouldn&apos;t voom if you put 230 volts through it!\n\n\n<span class=\"p\">..</span> <span class=\"ow\">testcleanup</span><span class=\"p\">::</span>\n\n   parrot.die()\n</pre></div><p>Testy se tak&#xE9; daj&#xED; za&#x159;azovat do skupin, v&#xED;ce\nv <a href=\"http://www.sphinx-doc.org/en/1.4.8/ext/doctest.html\">dokumentaci</a>.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">(__venv__) $ </span>make doctest\n<span class=\"go\">...</span>\n<span class=\"go\">Document: intro</span>\n<span class=\"go\">---------------</span>\n<span class=\"go\">1 items passed all tests:</span>\n<span class=\"go\">   3 tests in default</span>\n<span class=\"go\">3 tests in 1 items.</span>\n<span class=\"go\">3 passed and 0 failed.</span>\n<span class=\"go\">Test passed.</span>\n<span class=\"go\">1 items passed all tests:</span>\n<span class=\"go\">   1 tests in default (cleanup code)</span>\n<span class=\"go\">1 tests in 1 items.</span>\n<span class=\"go\">1 passed and 0 failed.</span>\n<span class=\"go\">Test passed.</span>\n\n<span class=\"go\">Doctest summary</span>\n<span class=\"go\">===============</span>\n<span class=\"go\">    3 tests</span>\n<span class=\"go\">    0 failures in tests</span>\n<span class=\"go\">    0 failures in setup code</span>\n<span class=\"go\">    0 failures in cleanup code</span>\n<span class=\"go\">...</span>\n</pre></div><h3>Import z vlastn&#xED;ho k&#xF3;du</h3>\n<p>Pokud nem&#xE1;te nainstalovan&#xFD; vlastn&#xED; bal&#xED;&#x10D;ek a budete z n&#x11B;j cht&#xED;t v doctestu\nimportovat, pravd&#x11B;podobn&#x11B; dostanete <code>ImportError</code>.\nV takov&#xE9;m p&#x159;&#xED;pad&#x11B; pom&#x16F;&#x17E;e drobn&#xE1; editace na za&#x10D;&#xE1;tku <code>conf.py</code>.\nMus&#xED;te p&#x159;idat adres&#xE1;&#x159;, ze kter&#xE9;ho lze v&#xE1;&#x161; k&#xF3;d importovat, do <code>sys.path</code>.\nPokud jste postupovali podle n&#xE1;vodu v&#xFD;&#x161;e, m&#xE1;te dokumentaci v adres&#xE1;&#x159;i <code>docs</code>,\nje tedy pot&#x159;eba p&#x159;idat nad&#x159;azen&#xFD; adres&#xE1;&#x159; (<code>..</code>):</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\"># If extensions (or modules to document with autodoc) are in another directory,</span>\n<span class=\"c1\"># add these directories to sys.path here. If the directory is relative to the</span>\n<span class=\"c1\"># documentation root, use os.path.abspath to make it absolute, like shown here.</span>\n<span class=\"c1\">#</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s1\">&apos;..&apos;</span><span class=\"p\">))</span>\n</pre></div><h3>Travis CI</h3>\n<p>Neexistuje &#x17E;&#xE1;dn&#xFD; unifikovan&#xFD; zp&#x16F;sob, jak specifikovat z&#xE1;vislosti pro sestaven&#xED;\ndokumentace. Proto, pokud chcete m&#xED;t n&#x11B;jak&#xFD; jednoduch&#xFD; zp&#x16F;sob, jak pou&#x161;t&#x11B;t\ndoctesty na Travisu, vytvo&#x159;te nap&#x159;&#xED;klad soubor <code>docs/requirements.txt</code>\na do n&#x11B;j dejte z&#xE1;vislosti pot&#x159;ebn&#xE9; pro sestaven&#xED; dokumentace.\nJe na v&#xE1;s, jestli tam budou pouze extra z&#xE1;vislosti oproti t&#x11B;m v <code>setup.py</code>\n(v&#x11B;t&#x161;inou pouze <code>sphinx</code>), nebo v&#x161;echny z&#xE1;vislosti, aby &#x161;el pou&#x17E;&#xED;t soubor\nsamostatn&#x11B;.</p>\n<p>Pot&#xE9; na Travisu m&#x16F;&#x17E;ete ud&#x11B;lat n&#x11B;co jako:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nt\">language</span><span class=\"p\">:</span> <span class=\"l l-Scalar l-Scalar-Plain\">python</span>\n<span class=\"nt\">python</span><span class=\"p\">:</span>\n<span class=\"p p-Indicator\">-</span> <span class=\"s\">&apos;3.6&apos;</span>\n<span class=\"nt\">install</span><span class=\"p\">:</span>\n<span class=\"p p-Indicator\">-</span> <span class=\"l l-Scalar l-Scalar-Plain\">python setup.py install</span>\n<span class=\"p p-Indicator\">-</span> <span class=\"l l-Scalar l-Scalar-Plain\">pip install -r docs/requirements.txt</span>\n<span class=\"nt\">script</span><span class=\"p\">:</span>\n<span class=\"p p-Indicator\">-</span> <span class=\"l l-Scalar l-Scalar-Plain\">python setup.py test --addopts -v</span>\n<span class=\"p p-Indicator\">-</span> <span class=\"l l-Scalar l-Scalar-Plain\">cd docs &amp;&amp; make doctest</span>\n</pre></div><h2>autodoc</h2>\n<p>Pro dokumentaci API lze pou&#x17E;&#xED;t <code>autodoc</code>, roz&#x161;&#xED;&#x159;en&#xED; Sphinxu, kter&#xE9; jsme povolili\nv pr&#x16F;vodci.</p>\n<div class=\"admonition note\"><p>Nem&#xE1;te-li toto roz&#x161;&#xED;&#x159;en&#xED; povolen&#xE9;, p&#x159;idejte jej do <code>conf.py</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">extensions</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s1\">&apos;sphinx.ext.autodoc&apos;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&apos;sphinx.ext.doctest&apos;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&apos;sphinx.ext.intersphinx&apos;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</pre></div></div><p>Roz&#x161;&#xED;&#x159;en&#xED; <code>autodoc</code> se pou&#x17E;&#xED;v&#xE1; takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"p\">..</span> <span class=\"ow\">automodule</span><span class=\"p\">::</span> mymodule\n   <span class=\"nc\">:members:</span>\n</pre></div><p>Tento p&#x159;&#xED;klad na dan&#xE9; m&#xED;sto vygeneruje dokumentaci slo&#x17E;enou z dokumenta&#x10D;n&#xED;ch\n&#x159;et&#x11B;zc&#x16F; jednotliv&#xFD;ch funkc&#xED;, t&#x159;&#xED;d a metod v modulu <code>mymodule</code>.</p>\n<p>Pokud chcete selektivn&#x11B; vybrat, dokumentaci &#x10D;eho chcete generovat,\nm&#x16F;&#x17E;ete pou&#x17E;&#xED;t i\n<a href=\"http://www.sphinx-doc.org/en/1.4.8/ext/autodoc.html#directive-automodule\">jin&#xE9; direktivy</a>.</p>\n<p>Pro vygenerov&#xE1;n&#xED; hezk&#xE9; struktury si m&#x16F;&#x17E;ete pomoci p&#x159;&#xED;kazem <code>apidoc</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">(__venv__) $ </span>python -m sphinx.apidoc -o docs mymodule\n</pre></div><p>V dokumenta&#x10D;n&#xED;ch &#x159;et&#x11B;zc&#xED;ch samoz&#x159;ejm&#x11B; m&#x16F;&#x17E;ete pou&#x17E;&#xED;t <a href=\"http://www.sphinx-doc.org/en/stable/rest.html\">reStructuredText</a> a je to\ndokonce &#x17E;&#xE1;douc&#xED;.</p>\n<p>Zde je uk&#xE1;zka z betamaxu (<em>Copyright 2013 Ian Cordasco</em>):</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Betamax</span><span class=\"p\">:</span>\n\n    <span class=\"sd\">&quot;&quot;&quot;This object contains the main API of the request-vcr library.</span>\n\n<span class=\"sd\">    This object is entirely a context manager so all you have to do is:</span>\n\n<span class=\"sd\">    .. code::</span>\n\n<span class=\"sd\">        s = requests.Session()</span>\n<span class=\"sd\">        with Betamax(s) as vcr:</span>\n<span class=\"sd\">            vcr.use_cassette(&apos;example&apos;)</span>\n<span class=\"sd\">            r = s.get(&apos;https://httpbin.org/get&apos;)</span>\n\n<span class=\"sd\">    Or more concisely, you can do:</span>\n\n<span class=\"sd\">    .. code::</span>\n\n<span class=\"sd\">        s = requests.Session()</span>\n<span class=\"sd\">        with Betamax(s).use_cassette(&apos;example&apos;) as vcr:</span>\n<span class=\"sd\">            r = s.get(&apos;https://httpbin.org/get&apos;)</span>\n\n<span class=\"sd\">    This object allows for the user to specify the cassette library directory</span>\n<span class=\"sd\">    and default cassette options.</span>\n\n<span class=\"sd\">    .. code::</span>\n\n<span class=\"sd\">        s = requests.Session()</span>\n<span class=\"sd\">        with Betamax(s, cassette_library_dir=&apos;tests/cassettes&apos;) as vcr:</span>\n<span class=\"sd\">            vcr.use_cassette(&apos;example&apos;)</span>\n<span class=\"sd\">            r = s.get(&apos;https://httpbin.org/get&apos;)</span>\n\n<span class=\"sd\">        with Betamax(s, default_cassette_options={</span>\n<span class=\"sd\">                &apos;re_record_interval&apos;: 1000</span>\n<span class=\"sd\">                }) as vcr:</span>\n<span class=\"sd\">            vcr.use_cassette(&apos;example&apos;)</span>\n<span class=\"sd\">            r = s.get(&apos;https://httpbin.org/get&apos;)</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n</pre></div><p>Existuj&#xED; r&#x16F;zn&#xE9; zp&#x16F;soby, jak dokumentovat argumenty, n&#xE1;vratov&#xE9; hodnoty apod.\nZv&#xED;dav&#xFD;m student&#x16F;m doporu&#x10D;ujeme pod&#xED;vat se na roz&#x161;&#xED;&#x159;en&#xED; <a href=\"http://www.sphinx-doc.org/en/1.4.8/ext/napoleon.html\">Napoleon</a>.</p>\n<h2>Odkazy na t&#x159;&#xED;dy a moduly</h2>\n<p>M&#xE1;te-li zdokumentovan&#xFD; modul, funkci, t&#x159;&#xED;du, metodu apod., je mo&#x17E;n&#xE9; na ni\nodk&#xE1;zat pomoc&#xED; konstrukce <code>:mod:</code>, <code>:func:</code>, <code>:class:</code>, <code>:meth:</code> a dal&#x161;&#xED;ch\nze Sphinxov&#xE9; <a href=\"http://www.sphinx-doc.org/en/1.4.8/domains.html#cross-referencing-python-objects\">dom&#xE9;ny Python</a>:</p>\n<div class=\"highlight\"><pre><span></span>To test the parrot&apos;s electrical resistance, use <span class=\"na\">:meth:</span><span class=\"nv\">`parrot.voom()`</span>.\n</pre></div><p>V t&#xE9;to &#x10D;&#xE1;sti dokumentace Sphinxu t&#xE9;&#x17E; najdete zp&#x16F;sob, jak dokumentovat API\nbez pou&#x17E;it&#xED; <code>autodoc</code>.</p>\n<p>V&#x161;echny zdokumentovan&#xE9; objekty se automaticky p&#x159;id&#xE1;vaj&#xED; do rejst&#x159;&#xED;ku.\nChcete-li do rejst&#x159;&#xED;ku p&#x159;idat n&#x11B;co nav&#xED;c, pou&#x17E;ijte direktivu <a href=\"http://www.sphinx-doc.org/en/1.4.8/markup/misc.html#index-generating-markup\">index</a>.</p>\n<h2>README.rst</h2>\n<p>Kdy&#x17E; u&#x17E; se stejn&#x11B; zab&#xFD;v&#xE1;me <a href=\"http://www.sphinx-doc.org/en/stable/rest.html\">reStructuredText</a>em, je dobr&#xE9; v&#xE1;&#x161; README p&#x159;epsat\nnebo p&#x159;ev&#xE9;st do stejn&#xE9;ho form&#xE1;tu. Na PyPI pak bude v&#xE1;&#x161; projekt vypadat l&#xE9;pe.</p>\n<p>P&#x159;i p&#x159;ejmenov&#xE1;n&#xED; na <code>README.rst</code> dejte pozor na pat&#x159;i&#x10D;n&#xE9; zm&#x11B;ny v <code>setup.py</code>.</p>\n<h2>Read the Docs</h2>\n<p>Pokud sv&#x16F;j reposit&#xE1;&#x159; na GitHubu zm&#x11B;n&#xED;te na ve&#x159;ejn&#xFD;, m&#x16F;&#x17E;ete vyu&#x17E;&#xED;t slu&#x17E;bu\n<a href=\"https://readthedocs.org/\">Read the Docs</a> k hostov&#xE1;n&#xED; dokumentace ve Sphinxu.\nDokumentace se sestav&#xED; p&#x159;i ka&#x17E;d&#xE9;m pushnut&#xED; na GitHub.</p>\n<p>Pokud Read the Docs pou&#x17E;ijete, nezapome&#x148;te na dokumentaci odk&#xE1;zat\nz <code>README.rst</code>.</p>\n\n\n        "
    }
  }
}