Sphinx

Sphinx est un outil écrit en python permettant la génération de documentation à partir de source écrit en RestructuredText.

le format de sortie peut être:

  • latex
  • html
  • html help windows
  • ebook / epub
  • text
  • doctest
  • man

Installation / Premier pas

Pour installer sphinx il faut:

puis lancer la commande

easy_install -U Sphinx

Sous Debian il suffit d’installer pip

apt-get install python-pip
pip install sphinx

Pour créer un nouveau projet rien de plus simple, créer un dossier contenant votre futur projet. Dans ce dossier lancer la commande suivante

sphinx-quickstart

cela va créer:

  • arborescence nécessaire au projet
  • le fichier de configuration conf.py
  • un buildeur du type make.bat

pour transformer vos sources en html rien de plus simple

make.bat html

ou

sphinx-build -b html sourcedir builddir

Themes et Plugins

Sphinx accepte de nombreux themes et plugins que vous retrouver respectivement dans le répertoire themes et ext.

les plugins ou extensions très utiles sont:

  • sphinx.ext.todo
  • sphinx.ext.graphviz
  • sphinx.ext.dotplus
  • sphinx.ext.sphinxgooglechart
  • sphinxcontrib.aafig

Pour le plugins sphinxcontrib.aafig il faut pour l’installer

pip install sphinxcontrib-aafig

puis dans son fichier conf.py rajouter l’extension

extensions = ['sphinxcontrib.aafig']

et enfin si besoin modifier le fichier sphinxcontrib/aafig.py en ajoutant

from docutils.parsers.rst import directives
#ADD BY FAO
from docutils.parsers.rst.directives import images
#END ADD BY FAO

ce plugin permet de générer des schéma via une description ASCII

premier exemple
.. aafig::
    :textual:

    +-------+         +-----------+
    | Hello +-------->+ aafigure! |
    +-------+         +-----------+

deuxième exemple
.. aafig::
    :textual:

+---------+         +---------+     +---------+
|  Shape  |         |  Line   |     |  Point  |
+---------+         +---------+   2 +---------+
| draw    +<--------+ start   +----O+ x       |
| move    +<-+      | end     |     | y       |
+---------+   \     +---------+     +---------+
               \
                \   +---------+
                 +--+ Circle  |
                    +---------+
                    | center  |
                    | radius  |
                    +---------+

Note

si vous souhaitez avec aafigure générer des images png ou jpg il faut installer PIL via

pip uninstall pil
pil install Pillow

un excellent thème est https://github.com/snide/sphinx_rtd_theme

On peut ajouter dans le fichier breadcrumbs.html de ce theme sous le bloc display_bitbucket les éléments suivant

{% elif show_source and has_source and sourcename %}
    <a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow" class="fa fa-code"></a>
{% endif %}
<a href="javascript:window.print()" class="fa fa-print"></a>
<a href="./Codiad" target="_blank" class="fa fa-edit"></a>

au lieu de

{% elif show_source and has_source and sourcename %}
    <a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow">Edit</a>
{% endif %}

Utilisation de flasksphinx

Il est possible d’utiliser le module perso flask-sphinx qui permet de maintenir un site sphinx via un navigateur.

Installation

l’installation du minimum

apt-get install python-pip
pip install flask
pip install flask-login
pip install flasksphinx
ln -s  /usr/local/lib/python2.7/dist-packages/flasksphinx/themes/rtdflask /usr/local/lib/python2.7/dist-packages/sphinx/themes/rtdflask

on génère des dossiers pour notre application

mkdir /var/www/mysite
mkdir /var/www/mydoc
cd /var/www/mydoc
sphinx-quickstart
Welcome to the Sphinx 1.3b1 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 [.]:

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]: y

Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
files. You can enter another prefix (such as ".") to replace the underscore.
> Name prefix for templates and static dir [_]:

The project name will occur in several places in the built documentation.
> Project name: mydoc
> Author name(s): Frédéric Aoustin

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: 1
> Project release [1]: 0

If the documents are to be written in a language other than English,
you can select a language here by its language code. Sphinx will then
translate text that it generates into that language.

For a list of supported codes, see
http://sphinx-doc.org/config.html#confval-language.
> Project language [en]: fr

The file name suffix for source files. Commonly, this is either ".txt"
or ".rst".  Only files with this suffix are considered documents.
> Source file suffix [.rst]:

One document is special in that it is considered the top node of the
"contents tree", that is, it is the root of the hierarchical structure
of the documents. Normally, this is "index", but if your "index"
document is a custom template, you can also set this to another filename.
> Name of your master document (without suffix) [index]:

Sphinx can also add configuration for epub output:
> Do you want to use the epub builder (y/n) [n]:

Please indicate if you want to use one of the following Sphinx extensions:
> autodoc: automatically insert docstrings from modules (y/n) [n]:
> doctest: automatically test code snippets in doctest blocks (y/n) [n]:
> intersphinx: link between Sphinx documentation of different projects (y/n) [n]:
> todo: write "todo" entries that can be shown or hidden on build (y/n) [n]:
> coverage: checks for documentation coverage (y/n) [n]:
> pngmath: include math, rendered as PNG images (y/n) [n]:
> mathjax: include math, rendered in the browser by MathJax (y/n) [n]:
> ifconfig: conditional inclusion of content based on config values (y/n) [n]:
> viewcode: include links to the source code of documented Python objects (y/n) [n]:

A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
directly.
> Create Makefile? (y/n) [y]:
> Create Windows command file? (y/n) [y]: n

Creating file ./source/conf.py.
Creating file ./source/index.rst.
Creating file ./Makefile.

Finished: An initial directory structure has been created.

You should now populate your master file ./source/index.rst and create other documentation
source files. Use the Makefile to build the docs, like so:
   make builder
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.cd
mkdir /var/www/mydoc/build
mkdir /var/www/mydoc/source/data
vi /var/www/mydoc/source/conf.py
extensions = ['sphinxcontrib.aafig','flasksphinx.todo']
# html_theme = "default"
html_theme = "rtdflask"
chmod -r 777 /var/www/mydoc
sphinx-build -b html /var/www/mydoc/source/ /var/www/mydoc/build/html/
mkdir /var/www/mydoc/wsgi-scripts
vi /var/www/mydoc/wsgi-scripts/myapp.wsgi
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os, os.path
import logging, logging.handlers

from flask import Flask

import flasksphinx

app = Flask(__name__)
app.config.from_pyfile(os.path.splitext(__file__)[0]+'.cfg')
flasksphinx.init(app)


#for mod wsgi
application = app

if __name__ == "__main__":
    handler = logging.StreamHandler()
    handler.setLevel(app.config['LEVEL'])
    app.logger.addHandler(handler)
    handler = logging.handlers.RotatingFileHandler(os.path.splitext(__file__)[0]+'.log', maxBytes=2000000, backupCount=5)
    handler.setLevel(app.config['LEVEL'])
    app.logger.addHandler(handler)
    app.run(host = app.config['HOST'],
            port = app.config['PORT'])
chmod +x /var/www/mydoc/wsgi-scripts/myapp.wsgi
vi /var/www/mydoc/wsgi-scripts/myapp.conf
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import logging

DEBUG = True
SPHINX_BUILD_DIR = '/var/www/mydoc/build'
SPHINX_CONF_DIR = '/var/www/mydoc/source'
UPLOAD_FOLDER = '/var/www/mydoc/source/data'
PORT = 5001
HOST = '0.0.0.0'
LEVEL = logging.DEBUG
SECRET_KEY = 'secret_key'
USERS = [
         {  'id'       : 1,
            'username' : 'admin',
            'password' : 'keyadmin'
         }
        ]

En ajoutant l’extension flasksphinx.todo il est possible de faire des listes à cocher

:x:`todo check`
:o:`todo no check`

Utilisation StandAlone

L’utilisation standAlone est assez simple

cd /var/www/mydoc/wsgi-scripts/
python myapp.wsgi

On a maintenant accès à notre application via http://localhost:5001/

Il est aussi possible de transformer notre application flask en service linux

Pour cela

cp /etc/init.d/skeleton /etc/init.d/mydoc
chmod +x /etc/init.d/mydoc
vi /etc/init.d/mydoc
...
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="flasksphinx for mydoc"
NAME=myapp.wsgi
DAEMON=/var/www/mydoc/wsgi-scripts/$NAME
DAEMON_ARGS=""
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
...
do_start()
{
     # Return
     #   0 if daemon has been started
     #   1 if daemon was already running
     #   2 if daemon could not be started
     start-stop-daemon --start --quiet --background --make-pidfile --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
         || return 1
     start-stop-daemon --start --quiet --background --make-pidfile --pidfile $PIDFILE --exec $DAEMON -- \
         $DAEMON_ARGS \
         || return 2
     # Add code here, if necessary, that waits for the process to be ready
     # to handle requests from services started subsequently which depend
     # on this one.  As a last resort, sleep for some time.
}
...
do_stop()
{
     # Return
     #   0 if daemon has been stopped
     #   1 if daemon was already stopped
     #   2 if daemon could not be stopped
     #   other if a failure occurred
     start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
     RETVAL="$?"
     [ "$RETVAL" = 2 ] && return 2
     # Wait for children to finish too if this is a daemon that forks
     # and if the daemon is only ever run from this initscript.
     # If the above conditions are not satisfied then add some other code
     # that waits for the process to drop all resources that could be
     # needed by services started subsequently.  A last resort is to
     # sleep for some time.
     start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
     [ "$?" = 2 ] && return 2
     # Many daemons don't delete their pidfiles when they exit.
     rm -f $PIDFILE
     return "$RETVAL"
}
...

on lance notre service

/etc/init.d/mydoc start

on a maintenant accès à notre application via le http://127.0.0.1:5001/

on peut installer notre service pour qu’il démarre automatiquement

update-rc.d mydoc defaults 99

Intégration dans Apache avec mod_python

On ajoute à l’installation minimum

apt-get install apache2 libapache2-mod-wsgi python-dev
mkdir /var/www/mysite
cd /var/www/mysite
echo "<html>hello mysite</html>" > index.html

et on edit le fichier conf du site dans /etc/apache2/site-enabled

<VirtualHost *:80>
     ServerAdmin webmaster@localhost

     DocumentRoot /var/www/mysite
     <Directory />
         Options FollowSymLinks
         AllowOverride None
     </Directory>
     <Directory /var/www/mysite>
         Options Indexes FollowSymLinks MultiViews
         AllowOverride None
         Order allow,deny
         allow from all
     </Directory>

# permet d optimiser les performances
Alias /mydoc/_static /var/www/mydoc/build/html/_static
Alias /mydoc/_static /var/www/mydoc/build/html/_images
Alias /mydoc/_static /var/www/mydoc/build/html/_sources
Alias /mydoc/_static /var/www/mydoc/build/html/_download

     ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
     <Directory "/usr/lib/cgi-bin">
         AllowOverride None
         Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
         Order allow,deny
         Allow from all
     </Directory>

    # WSGIScriptAlias /myapp "/var/www/myapp/wsgi-scripts/myapp.wsgi"
    # <Directory "/var/www/myapp/wsgi-scripts">
    #    Order allow,deny
    #    Allow from all
    #</Directory>
    WSGIScriptAlias /mydoc "/var/www/mydoc/wsgi-scripts/myapp.wsgi"
    <Directory "/var/www/mydoc/wsgi-scripts">
        Order allow,deny
        Allow from all
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

On redémarre Apache

/etc/init.d/apache2 restart

On a maintenant accès à notre application via http://localhost/mydoc

Note

on peut sur un même site ajouter plusieurs application, accessible par exemple par http://127.0.0.1/mydoc et http://127.0.0.1/myapp comme dans notre exemple

Note

il est possible d’augmenter les performances de l’application en laissant à apache de gérer différentes partie du site (alors non protégé par l’appli). Cela est réalisé par les “Alias” dans le fichier conf d’apache

Intégration dans Apache en mode proxy

Il faut dabord comme en mode StandAlone créer un service pour démarrer automatiquement notre application

On ajoute à l’installation minimum

apt-get install apache2
cd /var/www/mysite
echo "<html>hello mysite</html>" > index.html

On active le mode proxy

a2enmod proxy proxy_http
/etc/init.d/apache2 restart

On paramètre pour que toutes les requêtes sur le port 80 soit redirigé vers notre application

et on edit le fichier conf du site dans /etc/apache2/site-enabled

<VirtualHost *:80>
     ServerAdmin webmaster@localhost

     DocumentRoot /var/www/mysite
     <Directory />
         Options FollowSymLinks
         AllowOverride None
     </Directory>
     <Directory /var/www/mysite>
         Options Indexes FollowSymLinks MultiViews
         AllowOverride None
         Order allow,deny
         allow from all
     </Directory>

 ProxyPass / http://localhost:5001/
 ProxyPassReverse / http://localhost:5001/
 ProxyPreserveHost On

    ErrorLog ${APACHE_LOG_DIR}/error.log
    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

On redémarre tout les services

/etc/init.d/mydoc stop
/etc/init.d/apache2 stop
/etc/init.d/mydoc start
/etc/init.d/apache2 start

On a maintenant accès à notre application via http://localhost/

Note

Aujourd’hui il n’est pas possible de faire un proxy de http://localhost/mydoc vers notre application soucis dans la redirection de flasksphinx et dans le template lui même

Warning

  • et on ne gère pas le upload et doc en ligne
  • installer aafigure et voir avec eux pour ajout couleur
  • voir comment aller plus vite sur la production de sphinx (notament copie _download)
  • voir gestion des todos

rst2pdf

rst2pdf est un outil qui permet à partir de fichier rst de générer un fichier pdf. Il peut être utilisé comme une extension de sphinx.

Pour installer rst2pdf il suffit de faire

easy_install rst2pdf

Pour l’intégrer dans un projet sphinx il faut:

  1. modifier conf.py pour ajouter l’extensions rst2pdf

    extensions = ['sphinx.ext.autodoc','rst2pdf.pdfbuilder']
    
  2. ajouter dans conf.py les options de sortie pdf

    # -- Options for PDF output --------------------------------------------------
    # Grouping the document tree into PDF files. List of tuples
    # (source start file, target name, title, author, options).
    #
    # If there is more than one author, separate them with \\.
    # For example: r'Guido van Rossum\\Fred L. Drake, Jr., editor'
    #
    # The options element is a dictionary that lets you override
    # this config per-document.
    # For example,
    # ('index', u'MyProject', u'My Project', u'Author Name',
    # dict(pdf_compressed = True))
    # would mean that specific document would be compressed
    # regardless of the global pdf_compressed setting.
    pdf_documents = [
    ('index', u'MyProject', u'My Project', u'Author Name'),
    ]
    # A comma-separated list of custom stylesheets. Example:
    pdf_stylesheets = ['sphinx','kerning','a4']
    # Create a compressed PDF
    # Use True/False or 1/0
    # Example: compressed=True
    #pdf_compressed = False
    # A colon-separated list of folders to search for fonts. Example:
    # pdf_font_path = ['/usr/share/fonts', '/usr/share/texmf-dist/fonts/']
    # Language to be used for hyphenation support
    #pdf_language = "en_US"
    # Mode for literal blocks wider than the frame. Can be
    # overflow, shrink or truncate
    #pdf_fit_mode = "shrink"
    # Section level that forces a break page.
    # For example: 1 means top-level sections start in a new page
    # 0 means disabled
    #pdf_break_level = 0
    # When a section starts in a new page, force it to be 'even', 'odd',
    # or just use 'any'
    #pdf_breakside = 'any'
    # Insert footnotes where they are defined instead of
    # at the end.
    #pdf_inline_footnotes = True
    # verbosity level. 0 1 or 2
    #pdf_verbosity = 0
    # If false, no index is generated.
    #pdf_use_index = True
    # If false, no modindex is generated.
    #pdf_use_modindex = True
    # If false, no coverpage is generated.
    #pdf_use_coverpage = True
    # Name of the cover page template to use
    #pdf_cover_template = 'sphinxcover.tmpl'
    # Documents to append as an appendix to all manuals.
    #pdf_appendices = []
    # Enable experimental feature to split table cells. Use it
    # if you get "DelayedTable too big" errors
    #pdf_splittables = False
    # Set the default DPI for images
    #pdf_default_dpi = 72
    # Enable rst2pdf extension modules (default is empty list)
    # you need vectorpdf for better sphinx's graphviz support
    #pdf_extensions = ['vectorpdf']
    # Page template name for "regular" pages
    #pdf_page_template = 'cutePage'
    
  3. modifier vos builders, sous windows

    if "%1" == "pdf" (
    %SPHINXBUILD% -b pdf %ALLSPHINXOPTS% %BUILDDIR%/pdf
    echo.
    echo.Build finished. The PDF files are in %BUILDDIR%/pdf
    goto end
    )
    

sous unix

pdf:
    $(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) _build/pdf
    @echo
    @echo "Build finished. The PDF files are in _build/pdf."

et voilà

Note

on utilise la feuille de style sphinx qu’on peut modifier

Vous pouvez trouver la doc ici

Note

afin de gérer les images il faut installer PIL

easy_install PIL

Warning

pour que graphviz fonctionne il faut modifier le fichier rst2pdf/sphinxnodes.py rechercher HandleSphinxGraphviz et remplacer if hasattr(VectorPdf,’load_xobj’) par if hasattr(VectorPdf,’load_xobj’) and 1==0 pour forcer le passage par png

Vous pouvez trouver un exemple complet ici

la commande utilisée est:

C:\Python27\Scripts\rst2pdf.exe sampler.txt -s sampler.style -o sampler.pdf

il est aussi possible de rajouter dans son fichier rst

.. footer:: Page ###Page###/###Total###

.. header:: ###Title### - ###Section###

Un autre exemple complet

rst2pdf -o test.pdf -s style.style --footer "###Page###/###Total###" --header "###Title### - ###Section###" emile.rst

et la fiche de style est

pageSetup:
  size: A4
  width: null
  height: null
  margin-top: 1cm
  margin-bottom: 1cm
  margin-left: 1cm
  margin-right: 1cm
  margin-gutter: 0cm
  spacing-header: 5mm
  spacing-footer: 5mm
  firstTemplate: coverPage
  defaultFooter : ###Page###/###Total###
  defaultHeader : ###Section###


pageTemplates:
  coverPage:
    frames: []
        [0cm, 0cm, 100%, 100%]
    showHeader : false
    showFooter : false
    background : mascarille.pdf

styles:
  footer:
    parent: normal
    alignment: TA_CENTER

styles:
  admonition:
    parent: normal
    spaceBefore: 12
    spaceAfter: 6
    borderPadding: [4,4,4,4]
    backColor: null
    borderColor: null
    borderWidth: 0
    borderRadius : 5
    commands:[]
           [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ]

styles:
  note:
    parent:  admonition
    backColor: #EFF8FB
    borderColor: #EFF8FB

styles:
  attention:
    parent:  admonition
    backColor: #FBEFEF
    borderColor: #FBEFEF

styles:
  warning:
    parent:  admonition
    backColor: #FBF8EF
    borderColor: #FBF8EF


styles:
    admonition-title:
      parent: normal

styles:
  code:
    parent: literal
    leftIndent: 0
    spaceBefore: 8
    spaceAfter: 8
    backColor: null
    borderColor: darkgray
    borderWidth: 0.5
    borderPadding: 6

Il est possible de modifier le fonctionnement des admonitions en ajoutant l’extension fred dans le repertoire python de rst2pdf

Il est même possible via une extension de générer des presentions type powerpoint (ppt) en pdf ... dans ce cas il faut avoir des pdfs de page de taille A4.

Vous pouvez trouver cette extention ici.

Il faudra pour utiliser cette extension lancer la commande

rst2pdf -o out.pdf -e fred in.rst

Vous pouvez trouver un exemple complet ici