Training software PCIe400
-
- 09:00 → 09:10
-
09:10
→
10:10
Environnement de développement
-
09:10
Git et GitLab 20mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
Serveur de développement
- 10.10.0.6
- Répertoire par personne / binôme : formation_pcie400/userN ou N=1, ...
Projet GitLab dédié à cette formation
Les raccourcis git
-
Recommandons d'utiliser les raccourcis clavier à définir dans le fichier
/home/me/.gitconfig
[user]
name = Prénom Nom
email = nom@mylab.in2p3.fr
[alias]
co = checkout
br = branch
ci = commit
st = status
lo = log --oneline --decorate
rso = remote show origin-
Ne pas oublier de configurer son nom et son adresse email
-
Ils sont actifs sur le serveur
git branch → git br
git checkout → git co
git log → git lo
git status → git st
git remote show origin → git rso- Mais aussi :
$ git pull
$ git pushSe connecter sans mot de passe
- La méthode privilégiée pour interagir avec les dépôts git est SSH.
- Aide pour configurer votre clef SSH
-
09:30
p400-model -- épisode 1 20mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
Installer le projet GitLab
p400-model
Comment installer
p400-model
dans son environnement de développement est détaillé dans la documentation du projet README/install ou p400-model/docs/install_stableLa suite est adaptée à la configuration du serveur que nous utilisons pour cette formation
Activer python3.7
- Dépend de votre distribution
- Recommandé d'utiliser python 3.7 ou ses successeurs
- Semble fonctionner aussi avec Centos7 et python 3.6.8
- Recommandé d'utiliser les instructions de base et de se limiter à celles de Python3.7
$ conda deactivate
$ conda activate py37Préférer
pyenv
àconda
si la version native de python est trop ancienne.Cloner le projet GitLab
$ cd formation_pcie400/userN
$ git clone https://gitlab.in2p3.fr/legac/p400-model.gitPréférer un clonage via SSH (pas possible ici)
Créer un environnement virtuel et l'activer
$ python -m venv venv
$ source venv/bin/activateMettre à jour pip et le configurer pour accéder aux packages du projet PCIe40
(venv) (py37) $ pip install -U pip
- Copier le fichier
pip.conf
dans le répertoireformation_pcie400/userN/venv
(venv) (py37) $ cp ../../pip.conf venv/
Installer les packages PyPI requis pour le dévelopement
(venv) (py37) $ cd p400-model
(venv) (py37) $ pip install -r requirements-dev.txtTester l'installation
(venv) (py37) $ pip list | grep p400rw → 0.3.1
(venv) (py37) $ pip list | grep pyftdi → 0.54.0(venv) (py37) $ python
import p400rw as rw
print(rw.read)Anatomie du projet GitLab p400-model (pdf)
Le package p400rw
- Permet d'accéder à un bus I²C à travers un contrôleur FTDI
- Opération de lecture et d'écriture
- Documentation du package
Contrôleur FTDI
- Des commandes sont disponibles pour lister les contrôleurs FTDI connectées au serveur :
$ ftdi_urls.py
- Documentation du package PiPY pyftdi: https://eblot.github.io/pyftdi/
-
09:50
Pause Café 20m
-
09:10
-
10:10
→
11:30
Exercice
-
10:10
Présentation Module DC/DC 10mOrateur: Paul Bibron (Aix Marseille Université, CNRS/IN2P3, CPPM, Marseille, France)
-
10:20
Présentation module PLL 10mOrateur: Jean-Pierre Cachemiche (Aix Marseille Univ, CNRS/IN2P3, CPPM, Marseille, France)
-
10:30
Développement d'une classe pour lire ou écrire les valeurs 1h
-
10:10
-
11:30
→
12:30
Discussion sur le code
-
12:30
→
14:00
Repas 1h 30m
-
14:00
→
18:00
Flux et méthodes de development
-
14:00
Flux de dévelopement 20mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
Flux de développement
- Étudier la fiche technique du composant
- Discuter avec les développeurs hardware des méthodes les plus utiles
- Préparer un brouillon de la classe python avec uniquement la signature des méthodes et leurs documentations (i.e Ltm46xx)
- Itérer avec les développeurs hardware
- Développer le code python en appliquant les règles de nommages et les normes de codage
- Développer les tests unitaires pour valider le code python
- Intégrer le module et ses tests dans le projet
p400-model
-
14:20
Flux GitLab 20mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
Flux GitLab
Créer une issue dans GitLab
- Créer une issue et la documenter (composant, référence à la fiche technique, mécanisme d'héritage, etc) :
Gitab > Issue > New issue
- Remplir le Titre et la description.
Le titre et la description doivent être compréhensibles
- Cliquer sur le bouton Create issue
Garder en mémoire le numéro de l'issue, i.e 123.
Il est aussi visible à travers la liste des issues
Créer une branche dans son environnement de développement
- le nom de la branche commence par le numéro de l'issue, i.e 123-si5394
Le nom doit être compréhensible, chaque mot séparé par un tiret ou un underscore
$
cd p400-model
$ git co master
$ git pull
$ git co -b 123-si5394
$ git push --set-upstream origin 123-si5394
Créer un module pour le composant et un module pour les tests unitaires
$ cd p400-model/src/p400model
$ touch si5394.py$ cd p400-model/tests/
$ touch test_si5394_1000.pyDévelopper simultanément la classe et les tests des méthodes
- Très régulièrement, à chaque étape, commit et push du code dans GitLab
$
cd p400-model/src/p400model
$ git add si5394.py
$ git ci -m"Update si5394.py to add the method part_number"
$ git push$
cd p400-model/tests
$ git add test_si5394_1000.py
$ git ci -m"Update test_si5394_1000.py to add tests of Si5394.part_number"
$ git pushAppliquer les normes de codage
- Commit et pousser votre code dans GitLab
- Pour obtenir un état des lieux :
$ cd p400-model
$ isort --diff src
$ black --diff --color src
$ flake8 src- Modifier le code automatiquement :
$ cd p400-model
$ isort -v src
$ black -v src- Les violations des règles PEP8, identifiées par
flake8
, doivent être corrigées à la main. Une technique est de configurer l'IDE pour les détecter lors du codage.
- Vérifier une dernière fois le code, pousser le code dans GitLab
Créer un merge request dans GitLab
GitLab > Merge requests > New merge request
- Sélectionner la branche source,
123-si5394
et celle de destination,master
Cliquez sur Compare branches and continue - Compléter la description pour expliquer ce qui a été fait
- Vérifier que la description se termine par :
Close #123
- Vérifier que la case
Delete source branch when merge request is accepted
est cochée - Cliquer sur le bouton Create merge request
- Quand le merge request est accepté par GitLab, il sera regardé par un membre d'une autre équipe qui aura la charge de l'accepter ou de discuter avec vous d'améliorations à apporter.
Intégration Continue dans GitLab (pdf)
- Les scripts d'Intégration Continue démarrent dès qu'un merge request est créé.
- Vérifie que les imports sont classés par groupes et par ordre alphabétique (
isort
) - Vérifie que le code est formaté selon les standards du moment (
black
) - Vérifie que les règles PEP8 sont satisfaites (
flake8
) - Vérifie que l'historique de GitLab est limpide (pdf)
- Si l'un de ces tests échoue, le merge request est rejeté.
Il reste actif en attente de correction.
- L'état des scripts d'intégration Continue sont visibles dans :
GitLab > CI/CD > Pipelines
GitLab > CI/CD > Jobs
- Corriger le code dans la branche de travail, puis pousser les modifications dans GitLab
Les scripts d'intégration sont exécutés à nouveau.
- Si le merge request échoue, car l'historique n'est pas limpide, il faut rebaser ma branche de travail par rapport à la branche
master
$ cd p400-model
$ git co master
$ git pull
$ git remote show origin
$ git co 123-si5394
$ git rebase master
$ git push --forceCette dernière opération est délicate. Il faut prendre des précautions quand plusieurs développeurs travaillent sur la même branche. Il faut alors les prévenir en leur demandant de mettre à jour leur copie et de régler les confits qui pourraient apparaitre.
Mettre à jour la branche master
- Quand le merge request est accepté et fermé :
$ git co master
$ git pull
$ git remote show origin
$ git br -d 123-si5394 -
14:40
Application le flux GitLab sur l'exercice 20m
-
15:00
Les nomes de codage 10mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
Les normes de codage du code Python (PEP8)
Références
Nom des modules
Nom court en minuscule
L'underscore peut être utilisé si il améliore la lisibilitéNom des classes
Utiliser la convention CapWord
Nom des méthodes et des fonctions
Nom en minuscule
L'underscore peut être utilisé si il améliore la lisibilitéNom des variables
En minuscules avec un underscore pour séparer les mots
Le nom de la variable doit faire sens pour un non-expertNom des constantes
Défini au niveau du module
En majuscules avec underscore pour séparer les mots, i.e MAX_OVERFLOWLes chaînes de caractères
Entre double quote, i.e
"Hello"
Mise en forme du code
- Pris en charge par les outils
isort
etblack
- Longueur de la ligne est limitée à 79 caractères
- Indentation est de 4 espaces (pas de caractères TAB)
- Deux lignes blanches avant la définition d'une classe ou d'une fonction
- Une seule ligne banche avant la définition d'une méthode
- Pris en charge par les outils
-
15:10
Les docs string 10m
Les docs string
- Chaque module, classe, méthode et fonction sont documentés.
- Le système d'intégration continue de GitLab, génère automatiquement la documentation quand une version est publiée
- Cette documentation est publique. Elle est disponible à l'adresse
https://in2p3-readout400.pages.in2p3.fr/software/p400-xyz/
pour le projet GitLabp400-xyz
- Exemple : le module p400rw.fdti.py
- Pour chaque projet, voir
docs/devguide/docsting.md
- La langue est l'anglais
Exception
Pas de doc string quand :
- l'objet n'est pas exposé
- la fonction / méthode est très courte ou évidente
Documenter le module
""" * Wrapper around the ``pydfti`` packages. * Read and write to device connected to an I²C bus. The bus is managed by an FTDI controller. * Documentation: https://eblot.github.io/pyftdi/ Note: * The best way to import read / write functions in your python code, is the following:: import p400rw as rw value = rw.read(master, slave, register) * In the current release, it uses the I²C bus via an FTDI device. * In the future, read and write operations can be done via different paths: FTDI, Jtag, PCIe, etc. * The selection of the path will be performed by the syntactic sugar ``import p400rw as rw`` as well as by an environment variable. * Signature for ``read`` and ``write`` functions will stay the same and don't depend on the path. """
Documenter une classe et son constructeur
class ExampleClass(object): """The summary line for a class docstring should fit on one line. The __init__ method may be documented the class level docstring. Note: * Do not include the `self` parameter in the ``Args`` section. * Multiple line are supported for the description of parameters Args: param1 (str): Description of `param1`. param2 (int, optional): Description of `param2`. Multiple lines are supported. param3 (list(str)): Description of `param3`. """ def __init__(self, param1, param2, param3):
Documenter une méthode ou une fonction
def read( master_url, devadd, regadd, master=None, readlen=1, relax=True, start=True ): """Read a register content. Args: master_url (str): URL of the FTDI master: ftdi://:232h:FT0FMF6V/1 devadd (int): address of the slave on the I²C bus regadd (int): slave register address to read from master (pyftdi.i2c.I2cController) master controlling slave readlen (int): count of bytes to read out relax (bool): whether to relax the bus (emit STOP) or not start (bool): whether to emit a start sequence (w/ address) Returns: bytes Raises: pyftdi.i2c.I2cIOError """
Autres exemples
Utilisation des commentaires dans le code
- Les commentaires dans le code ne sont pas publiés dans la documentation
- Ils ont là pour aider le lecteur à comprendre un passage difficile
- Afin de faciliter la lecture, éviter les commentaires inline :
x = x + 1 # Compensate for border
-
15:20
Application les normes de codage sur l'exercice 20m
-
15:40
Pause café 30m
-
16:10
Organisation du software 20mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
-
16:30
Discussion p400-rw 40m
Discussion p400-rw
Le problème (pdf)
Approche envisagée
- Un RPM par chemin d'accès avec les drivers :
p400-rpm-ftdi
p400-rpm-pcie-intel- Un module python par chemin d'accès avec les fonctions
read
,write
etclose
p400-rw/
src/p400rw/
fdti.py
pcie_intel.py- Une variable d'environnement qui définit le chemin, avec une valeur par défaut PCIe:
$ export P400_RW="FDTI"
- La logique de sélection des fonctions dans le module __init__.py
import os
P400_RW = os.environment["P400_RW"]
if p400_RW == "FDTI":
from .fdti import close, read, write
else:
from .pcie_intel import close, read, write- Signature d'une fonction
read
:
def read(controller, device, register, hwarg1=None, kwarg2=True):
Les keyword arguments dependent du chemin.
Les valeurs par défaut couvrent l'utilisation usuelle. -
17:10
EDI Pycharm 20mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
Environnement Développement Intégré PyCharm
- Pour développer des codes complexe, il est recommandé d'utiliser un Environnement de Développement Intégré (EDI) plutôt qu'un simple éditeur de texte et une console.
- Pour projet le
p400-model
, utiliser les outils avec lesquels vous êtes à l'aise.
- Au CPPM, nous utilisons PyCharm CE qui pourrait vous simplifier la tâche :
- Éditeur de code python
- Gestion de Git et GitLab
- Exécution de test unitaire et d'outils externe
- Débogage
- Vérification orthographe et grammaire anglaise
- Rendu des pages écrites en MarkDown
- etc
Installer PyCharm
- Espace utilisateur
- Installer PyCharm via la ToolBox de JetBrain
Nombre de caractères maximum par lignes
File > Settings > Editor > Code Style > Python: Wrapping sand BracesHard wrap at 79
Ensure that right margin is not exceedFile > Settings > General > Editor > AppearanceShow hard wrap and visual guideIndentation 4 espaces
File > Settings > Editor > Code Style > Python: Tabs and indentsNuméro des lignes
File > Settings > General > Editor > Appearance
Show line numberOrthographe et grammaire
File > Settings > Apparence > Editor > Natural LanguagesRègles PEP 8
- Actif par défaut
File > Settings > Apparence > Editor > Inspections: pythonOrganisation des projets
p400/
p400-model/
p400-xyz/
venv/Configurer python et son environnent virtuel
File > Settings > Project: p400 > Python Interpreter → p400/venv/bin/pythonConfigurer les outils externes (isort, black, flake8)
File > Settings > Tools > External Tools
Program: $ProjectFileDir$/venv/bin/isort
Arguments: $FilePath$
Working directory: $ProjectFileDir$ - Pour développer des codes complexe, il est recommandé d'utiliser un Environnement de Développement Intégré (EDI) plutôt qu'un simple éditeur de texte et une console.
-
14:00
-
-
09:00
→
12:10
Pytest
-
09:00
Introduction Pytest 30mOrateur: Renaud Le Gac (CPPM CNRS/IN2P3)
Tests unitaires avec pytest
Référence : https://pytest.org/en/7.1.x/
Le code pour les tests
p400-model/
tests/- un module par composant, i.e test_si5394_1000.py
- une fonction par méthode
Importer la classe du composant Si5394 dans le module de test
from p400model.si5394 import Si5394
Convention de nommage
- module:
test_composant_ijkl.py
ou ijkl = 1000, 2000, 3000, etc- fonction:
def test_composant_method_iuvw() ou uvw = 001, 002, ..., 999
Tester une méthode d'un composant
- module
test_si5394_1000.py
from p400model.si5394 import Si5394
def test_si5394_part_number_1001():
pll = Si5394(controler, device)
value = pll.part_number()
assert value == "5394"- NOTE : il est possible de mettre plusieurs
assert
par fonction - Exécuter le test
$ cd p400-model
$ pytestTester deux méthodes d'un composant
import pytest
from p400model.si5394 import Si5394
@pytest.fixture
def pll():
return Si5394(controler, device)
def test_si5394_part_number_1001(pll):
value = pll.part_number()
assert value == "5394"
def test_si5394_is_locked_1002(pll)
assert pll.is_locked()- Les fixtures peuvent dépendre d'autres fixtures. Elles sont aussi paramétrables (https://pytest.org/en/7.1.x/how-to/fixtures.html)
Tester une exception
import pytest
from p400model.exception import P400ModelException
def test_si5394_my_method(pll):
with pytest.raises(P400ModelException):
pll.my_method(port=4)
La liste des tests
$ cd p400-model
$ pytest --collect-only -qFiltrer les tests
$ cd p400-model
$ pytest -k si5394_part_number
$ pytest -k 1001
$ pytest -k test_si5394
$ ...Print pour comprendre ce qui se passe
import logging
def test_si5394_part_number_1001(pll):
value = pll.part_number()
logging.debug(f"part number: {value}")
assert value == "5394"
- Pour voir les messages de type debug et au-delà:
$ cd p400-model
$ pytest -k 1001 --log-cli-level DEBUG
- Le niveau de logging :
CRITICAL 50
ERROR 40
WARNING 30
INFO 20 (défaut)
DEBUG 10
NOSET 0- En cas de problèmes
$ cd p400-model
$ pytest -k 1001 --tb auto -
09:30
Exercice 1h
-
10:30
p400-model -- épisode 2 10m
p400-model -- épisode 2
Guide développement
- Tous nos packages python ont un Guide de développement
- Écrit en Markdown, il est accessible à partir de GitLab ou directement dans le code
via le README
Access directe : devguide$ cd p400-model
$ more README$ cd p400-model/docs/devguide
- Le Markdown est aussi interprété par PyCharm
Unité de mesure
- Unité de base du système international (Ampère, Hertz, Volt, Watt, °C, etc)
Héritage
- Des composants de la même famille, mais avec quelques variations, i.e.
Ltm4677
etLtm4681
- La classe
Ltm46xx
contient les méthodes communes aux deux composants - La classe
Ltm4677
hérite de la classeLtm46xx.
Elle contient les méthodes qui lui sont spécifiques
from .ltm46xx import Ltm46xx
class Ltm4677(Ltm46xx):
def my_method(self):
...- Idem pour la classe
Ltm4681
Fonctions communes à plusieurs composants
- Essentiellement des fonctions de conversions
- Concentrées dans le module
p400model/tools.py
Les exceptions
- En cas de problème, une exception est toujours générée
- Soit une des exceptions du langage python ou
P400ModelException
from .exception import P400ModelException
class Ltm46xx:
def part_number(self):
...
if error:
msg = "bla bla"
raise P400ModelException(msg)Manipuler les adresses des registres
- Définit l'adresse dans la méthode, ne pas utiliser de constante
def part_number(self):
value = rw.read(0x67)Méthodes status et info ?
- La méthode status est optimisée pour extraire tous les paramètres vitaux ou tous les paramètres en une seule fois
- Le résultat est retourné sous la forme d'un dictionnaire
- Exemple de nommage des clés :
v_in_12v
v_out_0.9v
i_out_0.9v_0
f_240mhz_0
pn- la méthode info print le status (user friendly)
from pprint import pprint
...
def info(self):
pprint(self.status()) -
10:40
Pause café 20m
-
11:00
Les composants à développer 20mOrateur: Paul Bibron (Aix Marseille Université, CNRS/IN2P3, CPPM, Marseille, France)
Trouver les datasheet des composants sur boxIN2P3
-
11:20
Organisation et plans 40m
-
09:00
-
12:10
→
13:30
Repas 1h 20m
-
13:30
→
15:00
Hackathon
-
09:00
→
12:10