# sphinx-lint

<!-- .slide: data-background="static/background.jpg" -->

Un linter pour ta doc.

<br/>

<b>Julien Palard</b>

CPython core dev<br/>
Sysadmin de l’AFPy<br/>
hackinscience.org<br/>
…<br/>



# Pourquoi ?

Trouver des fautes de frappe dans du rst, ni plus, ni moins.

## Depuis quand ?

```text
Author: Georg Brandl <georg@python.org>
Date:   Sat Jan 3 20:30:15 2009 +0000
```

Dans `cpython` dans `Doc/tools/rstlint.py` !

::: notes

Oui oui, Georg, l'auteur de Sphinx-doc.


## Depuis quand, quoi ?

Et dans `cpython` on en avait un autre, `make suspicious`.

Bien connu pour ses faux positifs.

::: notes

Lui il date du portage de la doc de LaTeX à Sphinx, 2009 aussi.


## La motivation

Remplacer `make suspicious` par un outil qui n’aurait **aucun** faux positif.

::: notes

Et qui serait rapide !

Parler de la lenteur de `make suspicious`.


## La motivation

Sortir l’outil de `cpython/Doc/tools` pour que tout le monde puisse l'utiliser.


# Parsons du rst !

## Le reStructuredText

Le balisage :

```text
*En italique*
**En gras**
`Interprété` (dont le rôle peut changer)
``litéral``
Lien_
`Autre lien`_
`Encore un lien <https://...>`_
`Un lien anonyme <https://...>`__
```


## Le reStructuredText

Les textes interprétés :

```text
`while`  C'est du texte interprété.
:keyword:`while`  Du texte interprété avec un « role marker »
`while`:keyword:  Ça lui donne un sens particulier.
```


## Le reStructuredText

Donc oui le balisage et le texte interprété peuvent jouer le même rôle :

```text
*ça* c'est pareil que :emphasis:`ça`.
**ça** c'est pareil que :strong:`ça`.
``ça`` c'est pareil que :literal:`ça`.
```

::: notes

Mais comme en Python on a plus de méthodes que d'opérateurs…

En rst on a plus de rôles que de balises !


## Le reStructuredText

Les directives :

```text
 .. image:: Lenna.jpg

 .. important::
    Elle s’appelle Lena Sjööblom.
```

::: notes

Je prends un gros raccourci : les directives ne sont qu'un bout de
tout le balisage "explicite" comme les commentaires, les notes de bas
de page, ...


## Parsons du rst !

C'est facile ! Ou pas…

Exemple, comment on interprète :

```text
*2 * x  *a **b *.txt*
```
::: notes

C'est tout en italique !


## Parsons du rst !

Vous voyez des balises, vous ?

```text
2 * x ** 2 + 3 * x ** 3

a || b

"*" '|' (*) [*] {*} <*> ‘*’

2*x a**b O(N**2) e**(x*y)
```

::: notes

Pas le parseur. Mais bon les règles sont bien documentées ♥

Mais on voit que les humains peuvent facilement faire des erreurs ici.


## Parsons du rst !

Regardons du côté des directives :

```text
.. code-block:: python

   def fib(x):
       if n in (0, 1):
           return 1
       x = n // 2
       return fib(x - 1) * fib(n - x - 1) + fib(x) * fib(n - x)
```

::: notes

Une directive peut avoir un corps, ici du code.


## Parsons du rst !

Regardons du côté des directives :

```text
.. image:: Lenna.jpg
   :height: 330px
   :width: 330px
   :scale: 50 %
   :alt: Lenna Sjööblom
```

::: notes

Une directive peut avoir des options mais **pas de corps**.


## Parsons du rst !

Regardons du côté des directives :

```text
.. csv-table:: Domaines d'organismes publics
   :header: "name", "http_status", "https_status"
   :widths: 20, 10, 10

   cgf.pf, 200, 200
   dun.fr, 200, 200
   caf.pf, 200, 200
   aze.fr, 200, 200
```

::: notes

Une directive peut avoir des options **et** un corps.


## Quiz !

```text
.. code-block:: python

   items = ["titi", "tata", "toto"]
   print(*items)


.. important::

   items = ["titi", "tata", "toto"]
   print(*items)
```


## Quiz !

```text
.. csv-table:: Domaines d'organismes publics
   :header: "name", "http_status", "https_status"
   :widths: 20, 10, 10

   cgf.pf, 200, 200, OK
   dun.fr, 200, 200, OK

.. csv-table:: Domaines d'organismes publics
   :header: "name", "http_status", "https_status"
   :widths: 20, 10, 10

   caf.pf
   aze.fr
```

::: notes

Les valeurs manquantes sont moins graves que les valeurs surnuméraires.


## Ne parsons pas de rst...

De toutes façons `sphinx-lint` ne cherche pas du rst valide, il cherche du rst invalide !


# C’est utilisé ?

- CPython (depuis longtemps), devguide, peps, traductions, ...
- neo4j-python-driver
- pandas
- Spyder IDE
- Sympy
- Sphinx !!!


# Ça trouve des bugs ?

## Dans les PEPS

```diff
-`vcs <https://pythonhosted.org/vcs/>` library as
+`vcs <https://pythonhosted.org/vcs/>`_ library as
```


## Dans sympy

```diff
-... autoclass:: sympy.assumptions.predicates.order
+.. autoclass:: sympy.assumptions.predicates.order
```

```diff
-:data:``sympy.parsing.sympy_parser.transformations``
+:data:`sympy.parsing.sympy_parser.transformations`
```

```diff
-  `KanesMethod`` objects.
+  ``KanesMethod`` objects.
```


## Dans la traduction

> I just run the tool against library/ as a whole and it spit out a loooot of messages, so I thought that maybe it didn't work with our po files.


## Dans la traduction

> After closer inspecting two of these files I found that they were indeed proper errors

```diff
-"datetime`. :const:`MINYEAR` es` `1``."
+"datetime`. :const:`MINYEAR` es ``1``."
```

... notes

Ils ont réparé plus de 300 erreurs !


# Et les faux positifs ?

Ils se cachent bien :

- Aucun dans la doc de Sphinx, c’est un bon test (beaucoup de rst dans du rst).
- Aucun dans la doc de Python, c’est un bon test (286k lignes de rst).


# OK, vendu !

Mais comment ça s’utilise ?

```text
$ python -m pip install sphinx-lint
$ sphinx-lint
```

# Bouh c’est pas packagé pour [distrib]

Bah, fais-le.


# Questions ?

- <s>Twitter : [@sizeof](https://twitter.com/sizeof)</s>
- Mastodon : [@mdk@mamot.fr](https://mamot.fr/@mdk)
- XMPP : mdk@chapril.org
- HTTP : https://mdk.fr
- SMTP : julien@python.org
- Whatsapp : HAHAHA jamais.
- Instagram : Et puis quoi encore ?
- TikTok : Euh, stop maintenant ?
