Continue switch to latex
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Fred Pauchet 2022-03-28 21:27:00 +02:00
parent 80b6ccb26f
commit 32e8fc9ada
4 changed files with 515 additions and 674 deletions

View File

@ -1436,693 +1436,20 @@ l'organigramme (ou le diagramme), et ceux qui changent souvent plus bas,
dans le sens de stabilité du flux. Les composants les plus bas sont
considérés comme volatiles
\hypertarget{_architecture}{%
\section{Architecture}\label{_architecture}}
\hypertarget{_politiques_et_ruxe8gles_muxe9tiers}{%
\subsection{Politiques et règles
métiers}\label{_politiques_et_ruxe8gles_muxe9tiers}}
TODO: Un p'tit bout à ajouter sur les méthodes de conception ;)
\hypertarget{_considuxe9ration_sur_les_frameworks}{%
\subsection{Considération sur les
frameworks}\label{_considuxe9ration_sur_les_frameworks}}
\hypertarget{_un_point_sur_linversion_de_duxe9pendances}{%
\subsection{Un point sur l'inversion de
dépendances}\label{_un_point_sur_linversion_de_duxe9pendances}}
\hypertarget{_tests_et_intuxe9gration}{%
\section{Tests et intégration}\label{_tests_et_intuxe9gration}}
\begin{quote}
Tests are part of the system. You can think of tests as the outermost
circle in the architecture. Nothing within in the system depends on the
tests, and the tests always depend inward on the components of the
system~».
--- Robert C. Martin Clean Architecture
\end{quote}
\hypertarget{_le_langage_python}{%
\section{Le langage Python}\label{_le_langage_python}}
Il fonctionne avec un système d'améliorations basées sur des
propositions: les PEP, ou "\textbf{Python Enhancement Proposal}".
Chacune d'entre elles doit être approuvée par le
\href{http://fr.wikipedia.org/wiki/Benevolent_Dictator_for_Life}{Benevolent
Dictator For Life}.
Le langage Python utilise un typage dynamique appelé
\href{https://fr.wikipedia.org/wiki/Duck_typing}{\textbf{duck typing}}:
"\emph{When I see a bird that quacks like a duck, walks like a duck, has
feathers and webbed feet and associates with ducks --- I'm certainly
going to assume that he is a duck}" Source:
\href{http://en.wikipedia.org/wiki/Duck_test}{Wikipedia}.
Les morceaux de code que vous trouverez ci-dessous seront développés
pour Python3.9+ et Django 3.2+. Ils nécessiteront peut-être quelques
adaptations pour fonctionner sur une version antérieure.
\hypertarget{_eluxe9ments_de_langage}{%
\subsection{Eléments de langage}\label{_eluxe9ments_de_langage}}
En fonction de votre niveau d'apprentissage du langage, plusieurs
ressources pourraient vous aider:
\begin{itemize}
\item
\textbf{Pour les débutants},
\href{https://automatetheboringstuff.com/}{Automate the Boring Stuff
with Python} cite:{[}boring\_stuff{]}, aka. \emph{Practical
Programming for Total Beginners}
\item
\textbf{Pour un (gros) niveau au dessus} et pour un état de l'art du
langage, nous ne pouvons que vous recommander le livre Expert Python
Programming cite:{[}expert\_python{]}, qui aborde énormément d'aspects
du langage en détails (mais pas toujours en profondeur): les
différents types d'interpréteurs, les éléments de langage avancés,
différents outils de productivité, métaprogrammation, optimisation de
code, programmation orientée évènements, multithreading et
concurrence, tests, \ldots\hspace{0pt} A ce jour, c'est le concentré
de sujets liés au langage le plus intéressant qui ait pu arriver entre
nos mains.
\end{itemize}
En parallèle, si vous avez besoin d'un aide-mémoire ou d'une liste
exhaustive des types et structures de données du langage, référez-vous
au lien suivant:
\href{https://gto76.github.io/python-cheatsheet/}{Python Cheat Sheet}.
\hypertarget{_protocoles_de_langage}{%
\subsubsection{Protocoles de langage}\label{_protocoles_de_langage}}
dunder
Le modèle de données du langage spécifie un ensemble de méthodes qui
peuvent être surchargées. Ces méthodes suivent une convention de nommage
et leur nom est toujours encadré par un double tiret souligné; d'où leur
nom de "\emph{dunder methods}" ou "\emph{double-underscore methods}". La
méthode la plus couramment utilisée est la méthode \texttt{init()}, qui
permet de surcharger l'initialisation d'une instance de classe.
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{class}\NormalTok{ CustomUserClass:}
\KeywordTok{def} \FunctionTok{\_\_init\_\_}\NormalTok{(}\VariableTok{self}\NormalTok{, initiatization\_argument):}
\NormalTok{ ...}
\end{Highlighting}
\end{Shaded}
cite:{[}expert\_python(142-144){]}
Ces méthodes, utilisées seules ou selon des combinaisons spécifiques,
constituent les \emph{protocoles de langage}. Une liste complètement des
\emph{dunder methods} peut être trouvée dans la section
\texttt{Data\ Model} de
\href{https://docs.python.org/3/reference/datamodel.html}{la
documentation du langage Python}.
All operators are also exposed as ordinary functions in the operators
module. The documentation of that module gives a good overview of Python
operators. It can be found at
\url{https://docs.python.org/3.9/library/operator.html}
If we say that an object implements a specific language protocol, it
means that it is compatible with a specific part of the Python language
syntax.
The following is a table of the most common protocols within the Python
language.
Protocol nameMethodsDescriptionCallable protocol\emph{call}()Allows
objects to be called with parentheses:instance()Descriptor
protocols\emph{set}(), \emph{get}(), and \emph{del}()Allows us to
manipulate the attribute access pattern of classes (see the Descriptors
section)Container protocol\emph{contains}()Allows us to test whether or
not an object contains some value using the in keyword:value in instance
Python in Comparison with Other LanguagesIterable
protocol\emph{iter}()Allows objects to be iterated using the
forkeyword:for value in instance: \ldots\hspace{0pt}Sequence
protocol\emph{getitem}(),\emph{len}()Allows objects to be indexed with
square bracket syntax and queried for length using a built-in
function:item = instance{[}index{]}length = len(instance)Each operator
available in Python has its own protocol and operator overloading
happens by implementing the dunder methods of that protocol. Python
provides over 50 overloadable operators that can be divided into five
main groups:• Arithmetic operators • In-place assignment operators•
Comparison operators• Identity operators• Bitwise operatorsThat's a lot
of protocols so we won't discuss all of them here. We will instead take
a look at a practical example that will allow you to better understand
how to implement operator overloading on your own
The \texttt{add()} method is responsible for overloading the \texttt{+}
(plus sign) operator and here it allows us to add two matrices together.
Only matrices of the same dimensions can be added together. This is a
fairly simple operation that involves adding all matrix elements one by
one to form a new matrix.
The \texttt{sub()} method is responsible for overloading the \texttt{}
(minus sign) operator that will be responsible for matrix subtraction.
To subtract two matrices, we use a similar technique as in the --
operator:
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{def} \FunctionTok{\_\_sub\_\_}\NormalTok{(}\VariableTok{self}\NormalTok{, other):}
\ControlFlowTok{if}\NormalTok{ (}\BuiltInTok{len}\NormalTok{(}\VariableTok{self}\NormalTok{.rows) }\OperatorTok{!=} \BuiltInTok{len}\NormalTok{(other.rows) }\KeywordTok{or} \BuiltInTok{len}\NormalTok{(}\VariableTok{self}\NormalTok{.rows[}\DecValTok{0}\NormalTok{]) }\OperatorTok{!=} \BuiltInTok{len}\NormalTok{(other.rows[}\DecValTok{0}\NormalTok{])):}
\ControlFlowTok{raise} \PreprocessorTok{ValueError}\NormalTok{(}\StringTok{"Matrix dimensions don\textquotesingle{}t match"}\NormalTok{)}
\ControlFlowTok{return}\NormalTok{ Matrix([[a }\OperatorTok{{-}}\NormalTok{ b }\ControlFlowTok{for}\NormalTok{ a, b }\KeywordTok{in} \BuiltInTok{zip}\NormalTok{(a\_row, b\_row)] }\ControlFlowTok{for}\NormalTok{ a\_row, b\_row }\KeywordTok{in} \BuiltInTok{zip}\NormalTok{(}\VariableTok{self}\NormalTok{.rows, other.rows) ])}
\end{Highlighting}
\end{Shaded}
And the following is the last method we add to our class:
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{def} \FunctionTok{\_\_mul\_\_}\NormalTok{(}\VariableTok{self}\NormalTok{, other):}
\ControlFlowTok{if} \KeywordTok{not} \BuiltInTok{isinstance}\NormalTok{(other, Matrix):}
\ControlFlowTok{raise} \PreprocessorTok{TypeError}\NormalTok{(}\SpecialStringTok{f"Don\textquotesingle{}t know how to multiply }\SpecialCharTok{\{}\BuiltInTok{type}\NormalTok{(other)}\SpecialCharTok{\}}\SpecialStringTok{ with Matrix"}\NormalTok{)}
\ControlFlowTok{if} \BuiltInTok{len}\NormalTok{(}\VariableTok{self}\NormalTok{.rows[}\DecValTok{0}\NormalTok{]) }\OperatorTok{!=} \BuiltInTok{len}\NormalTok{(other.rows):}
\ControlFlowTok{raise} \PreprocessorTok{ValueError}\NormalTok{(}\StringTok{"Matrix dimensions don\textquotesingle{}t match"}\NormalTok{)}
\NormalTok{ rows }\OperatorTok{=}\NormalTok{ [[}\DecValTok{0} \ControlFlowTok{for}\NormalTok{ \_ }\KeywordTok{in}\NormalTok{ other.rows[}\DecValTok{0}\NormalTok{]] }\ControlFlowTok{for}\NormalTok{ \_ }\KeywordTok{in} \VariableTok{self}\NormalTok{.rows]}
\ControlFlowTok{for}\NormalTok{ i }\KeywordTok{in} \BuiltInTok{range}\NormalTok{(}\BuiltInTok{len}\NormalTok{ (}\VariableTok{self}\NormalTok{.rows)):}
\ControlFlowTok{for}\NormalTok{ j }\KeywordTok{in} \BuiltInTok{range}\NormalTok{(}\BuiltInTok{len}\NormalTok{ (other.rows[}\DecValTok{0}\NormalTok{])):}
\ControlFlowTok{for}\NormalTok{ k }\KeywordTok{in} \BuiltInTok{range}\NormalTok{(}\BuiltInTok{len}\NormalTok{ (other.rows)):}
\NormalTok{ rows[i][j] }\OperatorTok{+=} \VariableTok{self}\NormalTok{.rows[i][k] }\OperatorTok{*}\NormalTok{ other.rows[k][j]}
\ControlFlowTok{return}\NormalTok{ Matrix(rows)}
\end{Highlighting}
\end{Shaded}
The last overloaded operator is the most complex one. This is the
\texttt{*} operator, which is implemented through the \texttt{mul()}
method. In linear algebra, matrices don't have the same multiplication
operation as real numbers. Two matrices can be multiplied if the first
matrix has a number of columns equal to the number of rows of the second
matrix. The result of that operation is a new matrix where each element
is a dot product of the corresponding row of the first matrix and the
corresponding column of the second matrix. Here we've built our own
implementation of the matrix to present the idea of operators
overloading. Although Python lacks a built-in type for matrices, you
don't need to build them from scratch. The NumPy package is one of the
best Python mathematical packages and among others provides native
support for matrix algebra. You can easily obtain the NumPy package from
PyPI
En fait, l'intérêt concerne surtout la représentation de nos modèles,
puisque chaque classe du modèle est représentée par la définition d'un
objet Python. Nous pouvons donc utiliser ces mêmes \textbf{dunder
methods} (\textbf{double-underscores methods}) pour étoffer les
protocoles du langage.
\hypertarget{_the_zen_of_python}{%
\subsection{The Zen of Python}\label{_the_zen_of_python}}
\begin{Shaded}
\begin{Highlighting}[]
\OperatorTok{\textgreater{}\textgreater{}\textgreater{}} \ImportTok{import}\NormalTok{ this}
\end{Highlighting}
\end{Shaded}
\begin{verbatim}
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
\end{verbatim}
\hypertarget{_pep8_style_guide_for_python_code}{%
\subsection{PEP8 - Style Guide for Python
Code}\label{_pep8_style_guide_for_python_code}}
La première PEP qui va nous intéresser est la
\href{https://www.python.org/dev/peps/pep-0008/}{PEP 8---Style Guide
for Python Code}. Elle spécifie comment du code Python doit être
organisé ou formaté, quelles sont les conventions pour l'indentation, le
nommage des variables et des classes, \ldots\hspace{0pt} En bref, elle
décrit comment écrire du code proprement, afin que d'autres développeurs
puissent le reprendre facilement, ou simplement que votre base de code
ne dérive lentement vers un seuil de non-maintenabilité.
Dans cet objectif, un outil existe et listera l'ensemble des conventions
qui ne sont pas correctement suivies dans votre projet: pep8. Pour
l'installer, passez par pip. Lancez ensuite la commande pep8 suivie du
chemin à analyser (\texttt{.}, le nom d'un répertoire, le nom d'un
fichier \texttt{.py}, \ldots\hspace{0pt}). Si vous souhaitez uniquement
avoir le nombre d'erreur de chaque type, saisissez les options
\texttt{-\/-statistics\ -qq}.
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{$ }\ExtensionTok{pep8}\NormalTok{ . {-}{-}statistics {-}qq}
\ExtensionTok{7}\NormalTok{ E101 indentation contains mixed spaces and tabs}
\ExtensionTok{6}\NormalTok{ E122 continuation line missing indentation or outdented}
\ExtensionTok{8}\NormalTok{ E127 continuation line over{-}indented for visual indent}
\ExtensionTok{23}\NormalTok{ E128 continuation line under{-}indented for visual indent}
\ExtensionTok{3}\NormalTok{ E131 continuation line unaligned for hanging indent}
\ExtensionTok{12}\NormalTok{ E201 whitespace after }\StringTok{\textquotesingle{}\{\textquotesingle{}}
\ExtensionTok{13}\NormalTok{ E202 whitespace before }\StringTok{\textquotesingle{}\}\textquotesingle{}}
\ExtensionTok{86}\NormalTok{ E203 whitespace before }\StringTok{\textquotesingle{}:\textquotesingle{}}
\end{Highlighting}
\end{Shaded}
Si vous ne voulez pas être dérangé sur votre manière de coder, et que
vous voulez juste avoir un retour sur une analyse de votre code, essayez
\texttt{pyflakes}: cette librairie analysera vos sources à la recherche
de sources d'erreurs possibles (imports inutilisés, méthodes inconnues,
etc.).
\hypertarget{_pep257_docstring_conventions}{%
\subsection{PEP257 - Docstring
Conventions}\label{_pep257_docstring_conventions}}
Python étant un langage interprété fortement typé, il est plus que
conseillé, au même titre que les tests unitaires que nous verrons plus
bas, de documenter son code. Cela impose une certaine rigueur, mais
améliore énormément la qualité, la compréhension et la reprise du code
par une tierce personne. Cela implique aussi de \textbf{tout}
documenter: les modules, les paquets, les classes, les fonctions,
méthodes, \ldots\hspace{0pt} Ce qui peut également aller à contrecourant
d'autres pratiques cite:{[}clean\_code(53-74){]}; il y a une juste
mesure à prendre entre "tout documenter" et "tout bien documenter":
\begin{itemize}
\item
Inutile d'ajouter des watermarks, auteurs, \ldots\hspace{0pt} Git ou
tout VCS s'en sortira très bien et sera beaucoup plus efficace que
n'importe quelle chaîne de caractères que vous pourriez indiquer et
qui sera fausse dans six mois,
\item
Inutile de décrire quelque chose qui est évident; documenter la
méthode \texttt{get\_age()} d'une personne n'aura pas beaucoup
d'intérêt
\item
S'il est nécessaire de décrire un comportement au sein-même d'une
fonction, c'est que ce comportement pourrait être extrait dans une
nouvelle fonction (qui, elle, pourra être documentée)
\end{itemize}
Documentation: be obsessed! Mais \textbf{le code reste la référence}
Il existe plusieurs types de conventions de documentation:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
PEP 257
\item
Numpy
\item
Google Style (parfois connue sous l'intitulé \texttt{Napoleon})
\item
\ldots\hspace{0pt}
\end{enumerate}
Les
\href{https://google.github.io/styleguide/pyguide.html\#38-comments-and-docstrings}{conventions
proposées par Google} nous semblent plus faciles à lire que du
RestructuredText, mais sont parfois moins bien intégrées que les
docstrings officiellement supportées (par exemple,
\href{https://clize.readthedocs.io/en/stable/}{clize} ne reconnait que
du RestructuredText;
\href{https://docs.djangoproject.com/en/stable/ref/contrib/admin/admindocs/}{l'auto-documentation}
de Django également). L'exemple donné dans les guides de style de Google
est celui-ci:
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{def}\NormalTok{ fetch\_smalltable\_rows(table\_handle: smalltable.Table,}
\NormalTok{ keys: Sequence[Union[}\BuiltInTok{bytes}\NormalTok{, }\BuiltInTok{str}\NormalTok{]],}
\NormalTok{ require\_all\_keys: }\BuiltInTok{bool} \OperatorTok{=} \VariableTok{False}\NormalTok{,}
\NormalTok{) }\OperatorTok{{-}\textgreater{}}\NormalTok{ Mapping[}\BuiltInTok{bytes}\NormalTok{, Tuple[}\BuiltInTok{str}\NormalTok{]]:}
\CommentTok{"""Fetches rows from a Smalltable.}
\CommentTok{ Retrieves rows pertaining to the given keys from the Table instance}
\CommentTok{ represented by table\_handle. String keys will be UTF{-}8 encoded.}
\CommentTok{ Args:}
\CommentTok{ table\_handle: An open smalltable.Table instance.}
\CommentTok{ keys: A sequence of strings representing the key of each table}
\CommentTok{ row to fetch. String keys will be UTF{-}8 encoded.}
\CommentTok{ require\_all\_keys: Optional; If require\_all\_keys is True only}
\CommentTok{ rows with values set for all keys will be returned.}
\CommentTok{ Returns:}
\CommentTok{ A dict mapping keys to the corresponding table row data}
\CommentTok{ fetched. Each row is represented as a tuple of strings. For}
\CommentTok{ example:}
\CommentTok{ \{b\textquotesingle{}Serak\textquotesingle{}: (\textquotesingle{}Rigel VII\textquotesingle{}, \textquotesingle{}Preparer\textquotesingle{}),}
\CommentTok{ b\textquotesingle{}Zim\textquotesingle{}: (\textquotesingle{}Irk\textquotesingle{}, \textquotesingle{}Invader\textquotesingle{}),}
\CommentTok{ b\textquotesingle{}Lrrr\textquotesingle{}: (\textquotesingle{}Omicron Persei 8\textquotesingle{}, \textquotesingle{}Emperor\textquotesingle{})\}}
\CommentTok{ Returned keys are always bytes. If a key from the keys argument is}
\CommentTok{ missing from the dictionary, then that row was not found in the}
\CommentTok{ table (and require\_all\_keys must have been False).}
\CommentTok{ Raises:}
\CommentTok{ IOError: An error occurred accessing the smalltable.}
\CommentTok{ """}
\end{Highlighting}
\end{Shaded}
C'est-à-dire:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
Une courte ligne d'introduction, descriptive, indiquant ce que la
fonction ou la méthode réalise. Attention, la documentation ne doit
pas indiquer \emph{comment} la fonction/méthode est implémentée, mais
ce qu'elle fait concrètement (et succintement).
\item
Une ligne vide
\item
Une description plus complète et plus verbeuse, si vous le jugez
nécessaire
\item
Une ligne vide
\item
La description des arguments et paramètres, des valeurs de retour, des
exemples et les exceptions qui peuvent être levées.
\end{enumerate}
Un exemple (encore) plus complet peut être trouvé
\href{https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html\#example-google}{dans
le dépôt sphinxcontrib-napoleon}. Et ici, nous tombons peut-être dans
l'excès de zèle:
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{def}\NormalTok{ module\_level\_function(param1, param2}\OperatorTok{=}\VariableTok{None}\NormalTok{, }\OperatorTok{*}\NormalTok{args, }\OperatorTok{**}\NormalTok{kwargs):}
\CommentTok{"""This is an example of a module level function.}
\CommentTok{ Function parameters should be documented in the \textasciigrave{}\textasciigrave{}Args\textasciigrave{}\textasciigrave{} section. The name}
\CommentTok{ of each parameter is required. The type and description of each parameter}
\CommentTok{ is optional, but should be included if not obvious.}
\CommentTok{ If \textbackslash{}*args or \textbackslash{}*\textbackslash{}*kwargs are accepted,}
\CommentTok{ they should be listed as \textasciigrave{}\textasciigrave{}*args\textasciigrave{}\textasciigrave{} and \textasciigrave{}\textasciigrave{}**kwargs\textasciigrave{}\textasciigrave{}.}
\CommentTok{ The format for a parameter is::}
\CommentTok{ name (type): description}
\CommentTok{ The description may span multiple lines. Following}
\CommentTok{ lines should be indented. The "(type)" is optional.}
\CommentTok{ Multiple paragraphs are supported in parameter}
\CommentTok{ descriptions.}
\CommentTok{ Args:}
\CommentTok{ param1 (int): The first parameter.}
\CommentTok{ param2 (:obj:\textasciigrave{}str\textasciigrave{}, optional): The second parameter. Defaults to None.}
\CommentTok{ Second line of description should be indented.}
\CommentTok{ *args: Variable length argument list.}
\CommentTok{ **kwargs: Arbitrary keyword arguments.}
\CommentTok{ Returns:}
\CommentTok{ bool: True if successful, False otherwise.}
\CommentTok{ The return type is optional and may be specified at the beginning of}
\CommentTok{ the \textasciigrave{}\textasciigrave{}Returns\textasciigrave{}\textasciigrave{} section followed by a colon.}
\CommentTok{ The \textasciigrave{}\textasciigrave{}Returns\textasciigrave{}\textasciigrave{} section may span multiple lines and paragraphs.}
\CommentTok{ Following lines should be indented to match the first line.}
\CommentTok{ The \textasciigrave{}\textasciigrave{}Returns\textasciigrave{}\textasciigrave{} section supports any reStructuredText formatting,}
\CommentTok{ including literal blocks::}
\CommentTok{ \{}
\CommentTok{ \textquotesingle{}param1\textquotesingle{}: param1,}
\CommentTok{ \textquotesingle{}param2\textquotesingle{}: param2}
\CommentTok{ \}}
\CommentTok{ Raises:}
\CommentTok{ AttributeError: The \textasciigrave{}\textasciigrave{}Raises\textasciigrave{}\textasciigrave{} section is a list of all exceptions}
\CommentTok{ that are relevant to the interface.}
\CommentTok{ ValueError: If \textasciigrave{}param2\textasciigrave{} is equal to \textasciigrave{}param1\textasciigrave{}.}
\CommentTok{ """}
\ControlFlowTok{if}\NormalTok{ param1 }\OperatorTok{==}\NormalTok{ param2:}
\ControlFlowTok{raise} \PreprocessorTok{ValueError}\NormalTok{(}\StringTok{\textquotesingle{}param1 may not be equal to param2\textquotesingle{}}\NormalTok{)}
\ControlFlowTok{return} \VariableTok{True}
\end{Highlighting}
\end{Shaded}
Pour ceux que cela pourrait intéresser, il existe
\href{https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring}{une
extension pour Codium}, comme nous le verrons juste après, qui permet de
générer automatiquement le squelette de documentation d'un bloc de code:
\begin{figure}
\centering
\includegraphics{images/environment/python-docstring-vscode.png}
\caption{autodocstring}
\end{figure}
Nous le verrons plus loin, Django permet de rendre la documentation
immédiatement accessible depuis son interface d'administration. Toute
information pertinente peut donc lier le code à un cas d'utilisation
concret.
\hypertarget{_linters}{%
\subsection{Linters}\label{_linters}}
Il existe plusieurs niveaux de \emph{linters}:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
Le premier niveau concerne
\href{https://pypi.org/project/pycodestyle/}{pycodestyle}
(anciennement, \texttt{pep8} justement\ldots\hspace{0pt}), qui analyse
votre code à la recherche d'erreurs de convention.
\item
Le deuxième niveau concerne
\href{https://pypi.org/project/pyflakes/}{pyflakes}. Pyflakes est un
\emph{simple} \footnote{Ce n'est pas moi qui le dit, c'est la doc du
projet} programme qui recherchera des erreurs parmi vos fichiers
Python.
\item
Le troisième niveau est
\href{https://pypi.org/project/flake8/}{Flake8}, qui regroupe les deux
premiers niveaux, en plus d'y ajouter flexibilité, extensions et une
analyse de complexité de McCabe.
\item
Le quatrième niveau \footnote{Oui, en Python, il n'y a que quatre
cercles à l'Enfer} est \href{https://pylint.org/}{PyLint}.
\end{enumerate}
PyLint est le meilleur ami de votre \emph{moi} futur, un peu comme quand
vous prenez le temps de faire la vaisselle pour ne pas avoir à la faire
le lendemain: il rendra votre code soyeux et brillant, en posant des
affirmations spécifiques. A vous de les traiter en corrigeant le code ou
en apposant un \emph{tag} indiquant que vous avez pris connaissance de
la remarque, que vous en avez tenu compte, et que vous choisissez malgré
tout de faire autrement.
Pour vous donner une idée, voici ce que cela pourrait donner avec un
code pas très propre et qui ne sert à rien:
\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{from}\NormalTok{ datetime }\ImportTok{import}\NormalTok{ datetime}
\CommentTok{"""On stocke la date du jour dans la variable ToD4y"""}
\NormalTok{ToD4y }\OperatorTok{=}\NormalTok{ datetime.today()}
\KeywordTok{def}\NormalTok{ print\_today(ToD4y):}
\NormalTok{ today }\OperatorTok{=}\NormalTok{ ToD4y}
\BuiltInTok{print}\NormalTok{(ToD4y)}
\KeywordTok{def}\NormalTok{ GetToday():}
\ControlFlowTok{return}\NormalTok{ ToD4y}
\ControlFlowTok{if} \VariableTok{\_\_name\_\_} \OperatorTok{==} \StringTok{"\_\_main\_\_"}\NormalTok{:}
\NormalTok{ t }\OperatorTok{=}\NormalTok{ Get\_Today()}
\BuiltInTok{print}\NormalTok{(t)}
\end{Highlighting}
\end{Shaded}
Avec Flake8, nous obtiendrons ceci:
\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{test.py}\NormalTok{:7:1: E302 expected 2 blank lines, found 1}
\ExtensionTok{test.py}\NormalTok{:8:5: F841 local variable }\StringTok{\textquotesingle{}today\textquotesingle{}}\NormalTok{ is assigned to but never used}
\ExtensionTok{test.py}\NormalTok{:11:1: E302 expected 2 blank lines, found 1}
\ExtensionTok{test.py}\NormalTok{:16:8: E222 multiple spaces after operator}
\ExtensionTok{test.py}\NormalTok{:16:11: F821 undefined name }\StringTok{\textquotesingle{}Get\_Today\textquotesingle{}}
\ExtensionTok{test.py}\NormalTok{:18:1: W391 blank line at end of file}
\end{Highlighting}
\end{Shaded}
Nous trouvons des erreurs:
\begin{itemize}
\item
de \textbf{conventions}: le nombre de lignes qui séparent deux
fonctions, le nombre d'espace après un opérateur, une ligne vide à la
fin du fichier, \ldots\hspace{0pt} Ces \emph{erreurs} n'en sont pas
vraiment, elles indiquent juste de potentiels problèmes de
communication si le code devait être lu ou compris par une autre
personne.
\item
de \textbf{définition}: une variable assignée mais pas utilisée ou une
lexème non trouvé. Cette dernière information indique clairement un
bug potentiel. Ne pas en tenir compte nuira sans doute à la santé de
votre code (et risque de vous réveiller à cinq heures du mat', quand
votre application se prendra méchamment les pieds dans le tapis).
\end{itemize}
L'étape d'après consiste à invoquer pylint. Lui, il est directement
moins conciliant:
\begin{verbatim}
$ pylint test.py
************* Module test
test.py:16:6: C0326: Exactly one space required after assignment
t = Get_Today()
^ (bad-whitespace)
test.py:18:0: C0305: Trailing newlines (trailing-newlines)
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
test.py:3:0: W0105: String statement has no effect (pointless-string-statement)
test.py:5:0: C0103: Constant name "ToD4y" doesn't conform to UPPER_CASE naming style (invalid-name)
test.py:7:16: W0621: Redefining name 'ToD4y' from outer scope (line 5) (redefined-outer-name)
test.py:7:0: C0103: Argument name "ToD4y" doesn't conform to snake_case naming style (invalid-name)
test.py:7:0: C0116: Missing function or method docstring (missing-function-docstring)
test.py:8:4: W0612: Unused variable 'today' (unused-variable)
test.py:11:0: C0103: Function name "GetToday" doesn't conform to snake_case naming style (invalid-name)
test.py:11:0: C0116: Missing function or method docstring (missing-function-docstring)
test.py:16:4: C0103: Constant name "t" doesn't conform to UPPER_CASE naming style (invalid-name)
test.py:16:10: E0602: Undefined variable 'Get_Today' (undefined-variable)
--------------------------------------------------------------------
Your code has been rated at -5.45/10
\end{verbatim}
En gros, j'ai programmé comme une grosse bouse anémique (et oui: le
score d'évaluation du code permet bien d'aller en négatif). En vrac,
nous trouvons des problèmes liés:
\begin{itemize}
\item
au nommage (C0103) et à la mise en forme (C0305, C0326, W0105)
\item
à des variables non définies (E0602)
\item
de la documentation manquante (C0114, C0116)
\item
de la redéfinition de variables (W0621).
\end{itemize}
Pour reprendre la
\href{http://pylint.pycqa.org/en/latest/user_guide/message-control.html}{documentation},
chaque code possède sa signification (ouf!):
\begin{itemize}
\item
C convention related checks
\item
R refactoring related checks
\item
W various warnings
\item
E errors, for probable bugs in the code
\item
F fatal, if an error occurred which prevented pylint from doing
further* processing.
\end{itemize}
TODO: Expliquer comment faire pour tagger une explication.
TODO: Voir si la sortie de pylint est obligatoirement 0 s'il y a un
warning
TODO: parler de \texttt{pylint\ -\/-errors-only}
\hypertarget{_formatage_de_code}{%
\subsection{Formatage de code}\label{_formatage_de_code}}
Nous avons parlé ci-dessous de style de codage pour Python (PEP8), de
style de rédaction pour la documentation (PEP257), d'un \emph{linter}
pour nous indiquer quels morceaux de code doivent absolument être revus,
\ldots\hspace{0pt} Reste que ces tâches sont parfois (très) souvent
fastidieuses: écrire un code propre et systématiquement cohérent est une
tâche ardue. Heureusement, il existe des outils pour nous aider (un
peu).
A nouveau, il existe plusieurs possibilités de formatage automatique du
code. Même si elle n'est pas parfaite,
\href{https://black.readthedocs.io/en/stable/}{Black} arrive à un
compromis entre clarté du code, facilité d'installation et d'intégration
et résultat.
Est-ce que ce formatage est idéal et accepté par tout le monde ?
\textbf{Non}. Même Pylint arrivera parfois à râler. Mais ce formatage
conviendra dans 97,83\% des cas (au moins).
\begin{quote}
By using Black, you agree to cede control over minutiae of
hand-formatting. In return, Black gives you speed, determinism, and
freedom from pycodestyle nagging about formatting. You will save time
and mental energy for more important matters.
Black makes code review faster by producing the smallest diffs possible.
Blackened code looks the same regardless of the project you're reading.
Formatting becomes transparent after a while and you can focus on the
content instead.
\end{quote}
Traduit rapidement à partir de la langue de Batman: "\emph{En utilisant
Black, vous cédez le contrôle sur le formatage de votre code. En retour,
Black vous fera gagner un max de temps, diminuera votre charge mentale
et fera revenir l'être aimé}". Mais la partie réellement intéressante
concerne le fait que "\emph{Tout code qui sera passé par Black aura la
même forme, indépendamment du project sur lequel vous serez en train de
travailler. L'étape de formatage deviendra transparente, et vous pourrez
vous concentrer sur le contenu}".
\hypertarget{_complexituxe9_cyclomatique}{%
\subsection{Complexité cyclomatique}\label{_complexituxe9_cyclomatique}}

View File

@ -24,3 +24,513 @@ going to assume that he is a duck}"
-- Source: \href{http://en.wikipedia.org/wiki/Duck_test}{Wikipedia}.
\end{quote}
En fonction de votre niveau d'apprentissage du langage, plusieurs
ressources pourraient vous aider:
\begin{itemize}
\item
\textbf{Pour les débutants},
\href{https://automatetheboringstuff.com/}{Automate the Boring Stuff
with Python} cite:{[}boring\_stuff{]}, aka. \emph{Practical
Programming for Total Beginners}
\item
\textbf{Pour un (gros) niveau au dessus} et pour un état de l'art du
langage, nous ne pouvons que vous recommander le livre Expert Python
Programming cite:{[}expert\_python{]}, qui aborde énormément d'aspects
du langage en détails (mais pas toujours en profondeur): les
différents types d'interpréteurs, les éléments de langage avancés,
différents outils de productivité, métaprogrammation, optimisation de
code, programmation orientée évènements, multithreading et
concurrence, tests, \ldots\hspace{0pt} A ce jour, c'est le concentré
de sujets liés au langage le plus intéressant qui ait pu arriver entre
nos mains.
\end{itemize}
En parallèle, si vous avez besoin d'un aide-mémoire ou d'une liste
exhaustive des types et structures de données du langage, référez-vous
au lien suivant:
\href{https://gto76.github.io/python-cheatsheet/}{Python Cheat Sheet}.
\section{Protocoles de langage}
Le modèle de données du langage spécifie un ensemble de méthodes qui
peuvent être surchargées. Ces méthodes suivent une convention de nommage
et leur nom est toujours encadré par un double tiret souligné; d'où leur
nom de "\emph{dunder methods}\index{dunder}" ou "\emph{double-underscore methods}". La
méthode la plus couramment utilisée est la méthode \texttt{init()}, qui
permet de surcharger l'initialisation d'une instance de classe.
\begin{listing}[!ht]
\begin{minted}{python}
class CustomUserClass:
def __init__(self, initiatization_argument):
...
\end{minted}
\end{listing}
Ces méthodes, utilisées seules ou selon des combinaisons spécifiques,
constituent les \emph{protocoles de langage}. Une liste complètement des
\emph{dunder methods} peut être trouvée dans la section
\texttt{Data\ Model} de
\href{https://docs.python.org/3/reference/datamodel.html}{la
documentation du langage Python}.
All operators are also exposed as ordinary functions in the operators
module. The documentation of that module gives a good overview of Python
operators. It can be found at
\url{https://docs.python.org/3.9/library/operator.html}
If we say that an object implements a specific language protocol, it
means that it is compatible with a specific part of the Python language
syntax.
The following is a table of the most common protocols within the Python
language.
Protocol nameMethodsDescriptionCallable protocol\emph{call}()Allows
objects to be called with parentheses:instance()Descriptor
protocols\emph{set}(), \emph{get}(), and \emph{del}()Allows us to
manipulate the attribute access pattern of classes (see the Descriptors
section)Container protocol\emph{contains}()Allows us to test whether or
not an object contains some value using the in keyword:value in instance
Python in Comparison with Other LanguagesIterable
protocol\emph{iter}()Allows objects to be iterated using the
forkeyword:for value in instance: \ldots\hspace{0pt}Sequence
protocol\emph{getitem}(),\emph{len}()Allows objects to be indexed with
square bracket syntax and queried for length using a built-in
function:item = instance{[}index{]}length = len(instance)Each operator
available in Python has its own protocol and operator overloading
happens by implementing the dunder methods of that protocol. Python
provides over 50 overloadable operators that can be divided into five
main groups:• Arithmetic operators • In-place assignment operators•
Comparison operators• Identity operators• Bitwise operatorsThat's a lot
of protocols so we won't discuss all of them here. We will instead take
a look at a practical example that will allow you to better understand
how to implement operator overloading on your own
The \texttt{add()} method is responsible for overloading the \texttt{+}
(plus sign) operator and here it allows us to add two matrices together.
Only matrices of the same dimensions can be added together. This is a
fairly simple operation that involves adding all matrix elements one by
one to form a new matrix.
The \texttt{sub()} method is responsible for overloading the \texttt{}
(minus sign) operator that will be responsible for matrix subtraction.
To subtract two matrices, we use a similar technique as in the --
operator:
\begin{listing}
\begin{minted}{python}
def __sub__(self, other):
if (len(self.rows) != len(other.rows) or len(self.rows[0]) != len(other.rows[0])):
raise ValueError("Matrix dimensions don't match")
return Matrix([[a - b for a, b in zip(a_row, b_row)] for a_row, b_row in zip(self.rows, other.rows) ])
\end{minted}
\end{listing}
The last overloaded operator is the most complex one. This is the
\texttt{*} operator, which is implemented through the \texttt{mul()}
method. In linear algebra, matrices don't have the same multiplication
operation as real numbers. Two matrices can be multiplied if the first
matrix has a number of columns equal to the number of rows of the second
matrix. The result of that operation is a new matrix where each element
is a dot product of the corresponding row of the first matrix and the
corresponding column of the second matrix. Here we've built our own
implementation of the matrix to present the idea of operators
overloading. Although Python lacks a built-in type for matrices, you
don't need to build them from scratch. The NumPy package is one of the
best Python mathematical packages and among others provides native
support for matrix algebra. You can easily obtain the NumPy package from
PyPI
En fait, l'intérêt concerne surtout la représentation de nos modèles,
puisque chaque classe du modèle est représentée par la définition d'un
objet Python. Nous pouvons donc utiliser ces mêmes \textbf{dunder
methods} (\textbf{double-underscores methods}) pour étoffer les
protocoles du langage.
\section{The Zen of Python}
\begin{listing}[!ht]
\begin{verbatim}
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
\end{verbatim}
\caption{The Zen of Python}
\end{listing}
\section{Guide de style}
La première PEP qui va nous intéresser est la PEP8.
Elle spécifie comment du code Python doit être organisé ou formaté, quelles sont les conventions pour l'indentation, le nommage des variables et des classes, ...
En bref, elle décrit comment écrire du code proprement, afin que d'autres développeurs puissent le reprendre facilement, ou simplement que votre base de code ne dérive lentement vers un seuil de non-maintenabilité.
Dans cet objectif, un outil existe et listera l'ensemble des conventions qui ne sont pas correctement suivies dans votre projet: pep8. Pour l'installer, passez par pip.
Lancez ensuite la commande pep8 suivie du chemin à analyser (\texttt{.}, le nom d'un répertoire, le nom d'un fichier \texttt{.py}, \ldots\hspace{0pt}).
Si vous souhaitez uniquement avoir le nombre d'erreur de chaque type, saisissez les options \texttt{-\/-statistics\ -qq}.
\begin{listing}[!ht]
\begin{verbatim}
$ pep8 . --statistics -qq
7 E101 indentation contains mixed spaces and tabs
6 E122 continuation line missing indentation or outdented
8 E127 continuation line over-indented for visual indent
23 E128 continuation line under-indented for visual indent
3 E131 continuation line unaligned for hanging indent
12 E201 whitespace after '{'
13 E202 whitespace before '}'
86 E203 whitespace before ':'
\end{verbatim}
\caption{Une utilisation de pep8}
\end{listing}
Si vous ne voulez pas être dérangé sur votre manière de coder, et que vous voulez juste avoir un retour sur une analyse de votre code, essayez \texttt{pyflakes}: cette librairie analysera vos sources à la recherche de sources d'erreurs possibles (imports inutilisés, méthodes inconnues, etc.).
\section{Conventions de documentation}
Python étant un langage interprété fortement typé, il est plus que conseillé, au même titre que les tests unitaires que nous verrons plus bas, de documenter son code.
Cela impose une certaine rigueur, mais améliore énormément la qualité, la compréhension et la reprise du code par une tierce personne.
Cela implique aussi de \textbf{tout} documenter: les modules, les paquets, les classes, les fonctions, méthodes, \ldots\hspace{0pt}
Ce qui peut également aller à contrecourant d'autres pratiques \cite[53-74]{clean_code}; il y a une juste
mesure à prendre entre "tout documenter" et "tout bien documenter":
\begin{itemize}
\item
Inutile d'ajouter des watermarks, auteurs, \ldots\hspace{0pt} Git ou
tout VCS s'en sortira très bien et sera beaucoup plus efficace que
n'importe quelle chaîne de caractères que vous pourriez indiquer et
qui sera fausse dans six mois,
\item
Inutile de décrire quelque chose qui est évident; documenter la
méthode \texttt{get\_age()} d'une personne n'aura pas beaucoup
d'intérêt
\item
S'il est nécessaire de décrire un comportement au sein-même d'une
fonction, c'est que ce comportement pourrait être extrait dans une
nouvelle fonction (qui, elle, pourra être documentée)
\end{itemize}
Documentation: be obsessed! Mais \textbf{le code reste la référence}
Il existe plusieurs types de conventions de documentation:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
PEP 257
\item
Numpy
\item
Google Style (parfois connue sous l'intitulé \texttt{Napoleon})
\item
\ldots\hspace{0pt}
\end{enumerate}
Les
\href{https://google.github.io/styleguide/pyguide.html\#38-comments-and-docstrings}{conventions
proposées par Google} nous semblent plus faciles à lire que du
RestructuredText, mais sont parfois moins bien intégrées que les
docstrings officiellement supportées (par exemple,
\href{https://clize.readthedocs.io/en/stable/}{clize} ne reconnait que
du RestructuredText;
\href{https://docs.djangoproject.com/en/stable/ref/contrib/admin/admindocs/}{l'auto-documentation}
de Django également). L'exemple donné dans les guides de style de Google
est celui-ci:
\begin{listing}[!ht]
\begin{minted}{python}
def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False,) -> Mapping[bytes, Tuple[str]]:
"""Fetches rows from a Smalltable.
Retrieves rows pertaining to the given keys from the Table instance
represented by table_handle. String keys will be UTF-8 encoded.
Args:
table_handle: An open smalltable.Table instance.
keys: A sequence of strings representing the key of each table
row to fetch. String keys will be UTF-8 encoded.
require_all_keys: Optional; If require_all_keys is True only
rows with values set for all keys will be returned.
Returns:
A dict mapping keys to the corresponding table row data
fetched. Each row is represented as a tuple of strings. For
example:
{b'Serak': ('Rigel VII', 'Preparer'),
b'Zim': ('Irk', 'Invader'),
b'Lrrr': ('Omicron Persei 8', 'Emperor')}
Returned keys are always bytes. If a key from the keys argument is
missing from the dictionary, then that row was not found in the
table (and require_all_keys must have been False).
Raises:
IOError: An error occurred accessing the smalltable.
"""
\end{minted}
\caption{Un exemple de documentation Napoleon}
\end{listing}
C'est-à-dire:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
Une courte ligne d'introduction, descriptive, indiquant ce que la
fonction ou la méthode réalise. Attention, la documentation ne doit
pas indiquer \emph{comment} la fonction/méthode est implémentée, mais
ce qu'elle fait concrètement (et succintement).
\item
Une ligne vide
\item
Une description plus complète et plus verbeuse, si vous le jugez
nécessaire
\item
Une ligne vide
\item
La description des arguments et paramètres, des valeurs de retour, des
exemples et les exceptions qui peuvent être levées.
\end{enumerate}
Un exemple (encore) plus complet peut être trouvé
\href{https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html\#example-google}{dans
le dépôt sphinxcontrib-napoleon}. Et ici, nous tombons peut-être dans
l'excès de zèle:
\begin{figure}[!ht]
\centering
\scalebox{1.0}{\includegraphics[max size={\textwidth}{\textheight}]{images/napoleon-module-level-docstring.png}}
\caption{\url{https://xkcd.com/353/}}
\end{figure}
Pour ceux que cela pourrait intéresser, il existe
\href{https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring}{une
extension pour Codium}, comme nous le verrons juste après, qui permet de
générer automatiquement le squelette de documentation d'un bloc de code:
Nous le verrons plus loin, Django permet de rendre la documentation immédiatement accessible depuis l'interface d'administration.
Toute information pertinente peut donc lier le code à un cas d'utilisation concret, et rien n'est jamais réellement perdu.
\section{Vérification du code (lint)\index{lint}}
Il existe plusieurs niveaux de \emph{linters}:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
Le premier niveau concerne
\href{https://pypi.org/project/pycodestyle/}{pycodestyle}
(anciennement, \texttt{pep8} justement\ldots\hspace{0pt}), qui analyse
votre code à la recherche d'erreurs de convention.
\item
Le deuxième niveau concerne
\href{https://pypi.org/project/pyflakes/}{pyflakes}. Pyflakes est un
\emph{simple} \footnote{Ce n'est pas moi qui le dit, c'est la doc du
projet} programme qui recherchera des erreurs parmi vos fichiers
Python.
\item
Le troisième niveau est
\href{https://pypi.org/project/flake8/}{Flake8}, qui regroupe les deux
premiers niveaux, en plus d'y ajouter flexibilité, extensions et une
analyse de complexité de McCabe.
\item
Le quatrième niveau \footnote{Oui, en Python, il n'y a que quatre
cercles à l'Enfer} est \href{https://pylint.org/}{PyLint}.
\end{enumerate}
PyLint est le meilleur ami de votre \emph{moi} futur, un peu comme quand
vous prenez le temps de faire la vaisselle pour ne pas avoir à la faire
le lendemain: il rendra votre code soyeux et brillant, en posant des
affirmations spécifiques. A vous de les traiter en corrigeant le code ou
en apposant un \emph{tag} indiquant que vous avez pris connaissance de
la remarque, que vous en avez tenu compte, et que vous choisissez malgré
tout de faire autrement.
Pour vous donner une idée, voici ce que cela pourrait donner avec un
code pas très propre et qui ne sert à rien:
\begin{listing}[!ht]
\begin{minted}{python}
from datetime import datetime
"""On stocke la date du jour dans la variable ToD4y"""
ToD4y = datetime.today()
def print_today(ToD4y):
today = ToD4y
print(ToD4y)
def GetToday():
return ToD4y
if __name__ == "__main__":
t = Get_Today()
print(t)
\end{minted}
\caption{Un morceau de code qui ne sert à rien}
\end{listing}
Avec Flake8, nous obtiendrons ceci:
\begin{listing}[!ht]
\begin{verbatim}
test.py:7:1: E302 expected 2 blank lines, found 1
test.py:8:5: F841 local variable 'today' is assigned to but never used
test.py:11:1: E302 expected 2 blank lines, found 1
test.py:16:8: E222 multiple spaces after operator
test.py:16:11: F821 undefined name 'Get_Today'
test.py:18:1: W391 blank line at end of file
\end{verbatim}
\end{listing}
Nous trouvons des erreurs:
\begin{itemize}
\item
de \textbf{conventions}: le nombre de lignes qui séparent deux
fonctions, le nombre d'espace après un opérateur, une ligne vide à la
fin du fichier, \ldots\hspace{0pt} Ces \emph{erreurs} n'en sont pas
vraiment, elles indiquent juste de potentiels problèmes de
communication si le code devait être lu ou compris par une autre
personne.
\item
de \textbf{définition}: une variable assignée mais pas utilisée ou une
lexème non trouvé. Cette dernière information indique clairement un
bug potentiel. Ne pas en tenir compte nuira sans doute à la santé de
votre code (et risque de vous réveiller à cinq heures du mat', quand
votre application se prendra méchamment les pieds dans le tapis).
\end{itemize}
L'étape d'après consiste à invoquer pylint. Lui, il est directement
moins conciliant:
\begin{verbatim}
$ pylint test.py
************* Module test
test.py:16:6: C0326: Exactly one space required after assignment
t = Get_Today()
^ (bad-whitespace)
test.py:18:0: C0305: Trailing newlines (trailing-newlines)
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
test.py:3:0: W0105: String statement has no effect (pointless-string-statement)
test.py:5:0: C0103: Constant name "ToD4y" doesn't conform to UPPER_CASE naming style (invalid-name)
test.py:7:16: W0621: Redefining name 'ToD4y' from outer scope (line 5) (redefined-outer-name)
test.py:7:0: C0103: Argument name "ToD4y" doesn't conform to snake_case naming style (invalid-name)
test.py:7:0: C0116: Missing function or method docstring (missing-function-docstring)
test.py:8:4: W0612: Unused variable 'today' (unused-variable)
test.py:11:0: C0103: Function name "GetToday" doesn't conform to snake_case naming style (invalid-name)
test.py:11:0: C0116: Missing function or method docstring (missing-function-docstring)
test.py:16:4: C0103: Constant name "t" doesn't conform to UPPER_CASE naming style (invalid-name)
test.py:16:10: E0602: Undefined variable 'Get_Today' (undefined-variable)
--------------------------------------------------------------------
Your code has been rated at -5.45/10
\end{verbatim}
En gros, j'ai programmé comme une grosse bouse anémique (et oui: le
score d'évaluation du code permet bien d'aller en négatif). En vrac,
nous trouvons des problèmes liés:
\begin{itemize}
\item
au nommage (C0103) et à la mise en forme (C0305, C0326, W0105)
\item
à des variables non définies (E0602)
\item
de la documentation manquante (C0114, C0116)
\item
de la redéfinition de variables (W0621).
\end{itemize}
Pour reprendre la
\href{http://pylint.pycqa.org/en/latest/user_guide/message-control.html}{documentation},
chaque code possède sa signification (ouf!):
\begin{itemize}
\item
C convention related checks
\item
R refactoring related checks
\item
W various warnings
\item
E errors, for probable bugs in the code
\item
F fatal, if an error occurred which prevented pylint from doing
further* processing.
\end{itemize}
TODO: Expliquer comment faire pour tagger une explication.
TODO: Voir si la sortie de pylint est obligatoirement 0 s'il y a un
warning
TODO: parler de \texttt{pylint\ -\/-errors-only}
\section{Formatage de code}
Nous avons parlé ci-dessous de style de codage pour Python (PEP8), de
style de rédaction pour la documentation (PEP257), d'un \emph{linter}
pour nous indiquer quels morceaux de code doivent absolument être revus,
\ldots\hspace{0pt} Reste que ces tâches sont parfois (très) souvent
fastidieuses: écrire un code propre et systématiquement cohérent est une
tâche ardue. Heureusement, il existe des outils pour nous aider (un
peu).
A nouveau, il existe plusieurs possibilités de formatage automatique du
code. Même si elle n'est pas parfaite,
\href{https://black.readthedocs.io/en/stable/}{Black} arrive à un
compromis entre clarté du code, facilité d'installation et d'intégration
et résultat.
Est-ce que ce formatage est idéal et accepté par tout le monde ?
\textbf{Non}. Même Pylint arrivera parfois à râler. Mais ce formatage
conviendra dans 97,83\% des cas (au moins).
\begin{quote}
By using Black, you agree to cede control over minutiae of
hand-formatting. In return, Black gives you speed, determinism, and
freedom from pycodestyle nagging about formatting. You will save time
and mental energy for more important matters.
Black makes code review faster by producing the smallest diffs possible.
Blackened code looks the same regardless of the project you're reading.
Formatting becomes transparent after a while and you can focus on the
content instead.
\end{quote}
Traduit rapidement à partir de la langue de Batman: "\emph{En utilisant
Black, vous cédez le contrôle sur le formatage de votre code. En retour,
Black vous fera gagner un max de temps, diminuera votre charge mentale
et fera revenir l'être aimé}". Mais la partie réellement intéressante
concerne le fait que "\emph{Tout code qui sera passé par Black aura la
même forme, indépendamment du project sur lequel vous serez en train de
travailler. L'étape de formatage deviendra transparente, et vous pourrez
vous concentrer sur le contenu}".

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

View File

@ -10,6 +10,9 @@
\usepackage{graphics}
\usepackage[export]{adjustbox}
\renewcommand\listlistingname{Liste des morceaux de code}
\onehalfspacing
\makeindex
@ -32,7 +35,8 @@
\tableofcontents
\listoffigures
\listoftables
\listoflistings
%\listoflistings
\addcontentsline{toc}{chapter}{\listlistingname}{\listoflistings}
\mainmatter