Exercice 4.3 - fancy operations - Packages, scripts et tests

4.3.1 Créer un script avec des paramètres documentés grâce à docopt

Le point de départ des exercices 4.3 à 4.5 est une librairie de calcul extrêment simple ennuyeuse puisqu’elle fournit des fonctions fancy_add, fancy_substract et fancy_product. Pour illustrer la réutilisation du code et des bonnes pratiques de développement, nous allons cependant la packager et l’utiliser pour contruire un outil de calcul en ligne de commande, et un autre basé sur une application web (cli_calculator.py et web_calculator).

  • Récupérez avec git clone le projet de base à l’adresse https://github.com/e-lie/python202011-exercice-fancy-ops.git. Ouvrez le dans VSCode.

  • Créez un environnement virtuel python3 dans un dossier venv pour travailler de façon isolée des autres projets et de l’environnement python du système: virtualenv -p python3 venv.

  • Activez l’environnement dans votre terminal courant : source ./venv/bin/activate (deactivate pour desactiver l’environnement).

  • Observer les fonctions de calculs présentes dans fancy_operations.py. Créez un script cli_calculator.py qui importe ces trois fonctions et les utilise pour faire des calculs simples.

  • Essayez de debugger le script dans VSCode (normalement la configuration de debug est déjà présente dans car fournit dans le fichier .vscode/launch.json du projet).

  • Installons la librairie externe docopt dans notre environnement virtuel:

    • Ajoutez docopt à un fichier requirements.txt à la racine du projet.
    • Installez cette dépendance grâce au gestionnaire de paquet pip : pip install -r requirements.txt (vérifiez bien que votre venv est activé avec source venv/bin/activate).
  • En vous inspirant du cours et de la documentation de docopt utilisez cette librairie pour faire en sorte que cli_calculator listops affiche la liste des operations disponibles dans fancy_operations.py. On pourra pour cela ajouter dans fancy_operations.py un dictionnaire fancy_operations répertoriant les operations au format { 'add': fancy_add, ... }.

4.3.2 Déplacer les fonctions de calcul dans un package de librairie

Pour ajouter une nouvelle classe vector2d à notre librairie nous allons la réorganiser en plusieurs fichiers et sous dossiers.

  • Créez un dossier computation_libs pour la librairie à la racine du projet. À l’intérieur créer un sous dossier fancy_int_operations pour ranger nos fonctions.

  • Déplacez et rangez les fonctions fancy_add, fancy_product et le dictionnaire fancy_operations à la racine de fancy_int_operations dans un fichier __init__.py de façon à pouvoir les importer dans cli_calculator.py sous la forme from computation_libs.fancy_int_operations import fancy_add, fancy_product, fancy_operations.

  • Déplacez de même fancy_substract de façon à pouvoir l’importer comme suit : from computation_libs.fancy_int_operations.more_fancy_operations import fancy_substract.

  • Vérifiez que votre script cli_calculator.py fonctionne toujours.

  • Ajoutez finalement la classe Vector2d suivante dans un fichier computation_libs/vector2d.py:

vector2d

`computation_libs/vector2d.py`
  • Documentez cette classe grâce à un doctype contenant le texte suivant A 2-dimensional vector class from the fluent python book chapter 9.

4.3.3 Finir cli_calculator

  • Ajoutez dans cli_calculator.py un deuxième cas d’usage docopt permettant d’appeler le script pour effectuer une operation comme suit: python3 cli_calculator.py substract 3 4 affichera 3 - 4 = -1. On pourra préciser le symbole -, +, * en complexifiant le dictionnaire fancy_operations pour indiquer le symbole correspondant à chaque opération.

  • Gérer les mauvaises entrées utilisateurs grâce à un try: ... except:. On pourra afficher un message d’erreur tel que Bad operation or operand (should be integers) et finir le script en erreur grâce à exit(1).

4.3.4 Créer un package python d’application web : web_calculator

  • Dans le dépot du projet récupérez la correction intermédiaire et le début du projet flask en allant sur la branche correction_inter_flask (git checkout <branche>).

  • Ajoutez la librairie web flask aux dépendances du projet et installez la avec pip.

  • Créez un script web_calculator.py avec le code d’une application web de base:

from flask import Flask, render_template

web_app = Flask(__name__)

@web_app.route('/')
def index():
    return render_template("index.html", title="Webcalculator Home")
  • Testez l’application avec flask run ou le lancement VSCode Webcalculator puis visitez http://localhost:5000 dans votre navigateur.

Maintenant que cette application minimale fonction une bonne pratique est d’en faire un package:

  • Créez un package web_app initialisant une application flask quand on l’importe avec le code :
from flask import Flask

web_app = Flask(__name__)
  • Créez un fichier routes.py dans le package avec notre route index et en important correctement les modules nécessaires.

  • Déplacez le dossier templates dans le package également et gardez dans web_calculator.py uniquement from web_app import web_app.

  • Retestez l’application comme précédemment : comment cela fonctionne-t-il au niveau de l’import ?

  • Créez une seconde route def compute(operation, int_n, int_m): en mode GET avec comme url /<operation>/<int_n>/<int_m> qui

    • utilisez la librairie fancy_int_operations pour effectuer des opérations sur des entier int_n et int_m
    • utilise le template jinja operation.html pour afficher le résultat
    • on pourra bien sur debugger l’application dans VSCode ou avec ipdb pour bien comprendre l’exécution et trouver les erreurs.
    • Testez votre application dans le navigateur.

Pour utiliser la librairie computation_libs.fancy_int_operations nous avons du déplacer le package à l’intérieur de web_app pour le rendre accessible à l’application web. Notre cli_calculator ne fonctionne plus du coup.

  • La bonne méthode pour travailler avec des packages indépendants consiste à créer un paquet pip “editable” à partir de notre package:
    • remettez computation_libs à la racine du projet.
    • ajoutez dans computation_libs un fichier de packaging setup.py utilisé par setuptools pour packer notre librairie.
    • mettez à l’intérieur:
from setuptools import setup, find_packages

setup(name='computation-libs', version='0.1', packages=find_packages())
- Installez la librairie avec `pip install -e ./computation_libs`
  • Gérez les mauvaises entrées utilisateur avec un try: except: renvoyant le cas échéant vers le template invalid.html. Testez.

4.3.4 Tester nos modules avec Pytest

  • Ecrire des tests unitaires pytest sur les 3 opérations de notre librairie.

  • Ecrire des test d’intégration sur notre application flask.

Correction:

La correction finale est dans la branche correction_finale du dépôt visible sur github ici