diff --git a/asciidoc-to-tex.tex b/asciidoc-to-tex.tex index 2f6f9be..60d6776 100644 --- a/asciidoc-to-tex.tex +++ b/asciidoc-to-tex.tex @@ -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}} diff --git a/chapters/python.tex b/chapters/python.tex index 785b314..7716337 100644 --- a/chapters/python.tex +++ b/chapters/python.tex @@ -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}". + + diff --git a/images/napoleon-module-level-docstring.png b/images/napoleon-module-level-docstring.png new file mode 100644 index 0000000..55172fc Binary files /dev/null and b/images/napoleon-module-level-docstring.png differ diff --git a/main.tex b/main.tex index 49890ec..46dab3d 100644 --- a/main.tex +++ b/main.tex @@ -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