Laborator ​10 - Static Checking ​

1. Objectives ​

Verificarea automată a calității codului reprezintă unul dintre primii pași în garantarea corectitudinii codului. Așa cum ne putem imagina, un program formatat inconsistent și cu greșeli frecvente de structură e predispus la a avea probleme ulterioare, chit că inițial el e funcțional. De asemenea, mai ales în proiectele open-source, ne dorim ca programele noastre să fie cât mai prezentabile pentru a atrage contribuitori și utilizatori, cât și pentru a face contribuțiile mai consistente. Dacă fiecare contribuitor ar avea un stil de formatare al codului diferit, s-ar ajunge garantat la neînțelegeri.

Aceste idei sunt întărite când este vorba de limbaje interpretate precum Python. După cum știm, în Python tipul variabilelor este determinat la rulare, deci nu putem ști cu siguranță că avem un cod funcțional, până când nu rulăm cu succes pe toate căile posibile de execuție. Totodată, codul Python este bazat pe indentare și o formatare cât de cât corectă, deci fără să respectăm un minim de formatare, este posibil ca interpretorul de Python să refuze sa ne ruleze programul cu totul. Deoarece Python este mai lax în scriere, trebuie să folosim folosim aplicații terțe pentru a ne formata codul, comparat cu limbaje mult mai stricte ca Rust.

Dacă combinăm toate aceste idei cu o formatare automată și folosirea sistemelor de CI/CD, precum în laboratoarele precedente, putem să ne asigurăm că în proiectul nostru nu pătrunde cod de o calitate inferioară celei dorite.

1.1 Linters ​

Linterele, sau uneltele de verificare a calității codului, reprezintă prima metodă de verificare a codului. De multe ori acestea sunt integrate în editorul folosit de developeri, în așa fel încât codul este evidențiat, sau chiar formatat automat la fiecare salvare a fișierului.

Deoarece procesul de linting poate semnala multe probleme, este recomandat să fie integrat în dezvoltarea unui program cât mai devreme, pentru a evita schimbări fundamentale ale codului ulterior. Dificultatea principală în procesul de linting vine din stabilirea unui standard de formatare a codului care să corespundă cu așteptările tuturor contribuitorilor. În cazul nostru, configurările de bază sunt mai mult decât suficiente.

1.2 Static Checking ​

Static checkerele, sau unelte de verificare statică a codului, reprezintă o verificare mai amănunțită a codului. Acestea parcurg codul și încearcă să îl înțeleagă în amănunt pentru a deduce folosiri eronate ale anumitor funcții și/sau cod. Un bun exemplu de astfel de verificări sunt cele de securitate. Prin anumite static checkere putem descoperi automat parole, tokene, și alte date de autentificare uitate în cod, înainte de a face public codul și a ne compromite. Totodată, vom vedea că există și unelte mai amănunțite, ce realizează o detecție automată a tipurilor fiecărei variabile, pentru a ne garanta că nu există erori de runtime generate de acestea.

Static checkerele reprezintă, pe scurt, următorul pas al verificării codului de către developer, înainte de rulare și de publicarea efectivă a codului.

2. Exercises ​

În exercițiile din laborator vom explora cinci unelte de linting și static checking. Pentru fiecare va trebui să o rulați, să rezolvați (pe cât se poate) problemele semnalate, și să realizați un commit descriptiv în legătură cu schimbările. Vom folosi un repository open source pentru a rula exercițiile. Din acesta va trebui să alegeți 2-3 mini-proiecte pe care să rulați uneltele și să rezolvați problemele.

Dacă proiectul ales nu mai are destule probleme pentru a fi util, sau ați rezolvat deja toate problemele, puteți încerca altul.

2.0 Environment Setup

1. Instalăm pip dacă lipsește: https://pip.pypa.io/en/stable/installation

	$ python3 -m ensurepip --upgrade

2. Pentru început va trebui să instalăm tool-urile ce le vom folosi:

	$ pip3 install pylint ruff black bandit pytype

3. Apoi clonăm repository-ul peste care o sa rulăm uneltele:

	$ git clone https://github.com/Ingineria-Calculatoarelor-ACS-UPB/python-mini-project.git

Rulați comenzile din timp, eventual la început de laborator, deoarece instalarea poate să dureze.

2.1 Pylint - Basic Checks

Pylint este unul dintre cele mai cunoscute unelte de linting. Acesta oferă informații simple, cât și avansate în legătură cu codul pe care îl analizează, și apoi generează un raport cu toate erorile și acordă o notă acestuia. Acesta are și integrare cu VSCode, precum și alte editoare, ce ușurează folosirea lui.

Observăm că fiecare linie din raport menționează un cod de verificare, prin care e identificată fiecare problemă. Putem avea probleme de tip error, warning, comment, etc.

 1. Rulați Pylint și observați problemele semnalate de acesta.
 2. Rezolvați problemele semnalate pentru proiectul ales.
 3. Realizați un commit prin care să salvați modificările aduse.

2.2 Ruff - Advanced Checks

De cele mai multe ori, un singur linter nu poate prinde toate erorile ce le avem în cod, de aceea suntem nevoiți să folosim mai multe. Ruff este o suită de verificatoare de cod ce este des folosită în proiectele mari. Aceasta ne poate ajuta să descoperim probleme ce au fost ratate de Pylint. De asemenea, înglobează verificări de la diferite alte unelte.

 1. Rulați Ruff și observați problemele semnalate de acesta.
 2. Rezolvați problemele semnalate pentru proiectul ales.
 3. Realizați un commit prin care să salvați modificările aduse.

2.3 Black - Automatic Checks

Am observat că este destul de obositor să facem atatea modificări și timpul consumat pe formatarea codului ar fi putut să fie investit în adăugarea de funcționalități noi. Black vine cu o paradigmă nouă, cea de cedare a controlului asupra linting-ului către linter. Pe lângă semnalarea problemelor, acesta le și rezolvă după un standard propus de dezvoltatori. Desigur, noi putem să rulăm fără a aplica modificările.

 1. Rulați Black în mod de diff color precizând argumentele --diff și --color la rulare și observați problemele.
 2. Rulați Black fără argumente adiționale pentru a aplica schimbările.
 3. Rezolvați problemele rămase semnalate pentru proiectul ales (dacă mai există).
 4. Realizați un commit prin care să salvați modificările aduse.

2.4 Bandit - Security Checks

Bandit este o unealtă de static checking concentrată pe partea de securitate. Aceasta se asigură că programul nostru nu poate fi exploatat de alte persoane și că este sigur în timpul folosirii. Pe lângă verificarea existenței unor parole/tokene uitate, acesta analizează și cod ce ar putea fi exploatat în anumite circumstanțe.

În cazul de față, avem o singură problemă, aceea că descărcăm o pagină fără a menționa un timp de oprire. Un utilizator malițios poate să apeleze funcția cu un url invalid și să blocheze execuția programului.

 1. Rulați Bandit și observați problemele.
 2. Rezolvați problemele semnalate pentru proiectul ales.
 3. Realizați un commit prin care să salvați modificările aduse.

2.5 Pytype - Type Checks

Pytype este un tool de static checking mai avansat față de cele precedente. Se folosește de un engine de analiză statică pentru a garanta corectitudinea tipurilor variabilelor din codul nostru. Acesta ideal este folosit în timpul dezvoltării programului, sau atunci când avem bug-uri. Este foarte probabil ca acesta să nu întoarcă nimic, în cazul proiectelor analizate în cadrul laboratorului, deoarece acestea sunt deja funcționale.

Fără a rula codul, acesta a analizat operațiile realizate și a detectat adunarea unui întreg cu un șir de caractere. În Python astfel de problemă ar fi apărut doar la rulare, și dacă nu am testat acel caz posibil să treacă nedetectată și să ajungă în mediu de producție.

 1. Rulați Pytype și observați problemele.
 2. Rezolvați problemele semnalate pentru proiectul ales (dacă există).
 3. Realizați un commit prin care să salvați modificările aduse.

3. Bonus

Pentru a realiza bonusul va trebui să creăm și un fork în care să adăugăm pipeline-urile:

3.1 CI Pipeline

În fork-ul realizat în partea de setup, adăugați un fișier python-checks.yaml în calea .github/workflows și completați conform specificației următoare:

  • Verificarea trebuie să se realizeze pe tot codul.
  • Verificarea trebuie sa pornească atunci când este deschis un nou Pull Request.
  • Workflow-ul trebuie să aibă 5 pași, corespunzător fiecărei unelte: Pylint, Ruff, Black, Bandit, Pytype. (Black poate sa aplice automat modificările).
  • Workflow-ul trebuie să eșueze atunci când oricare dintre cele 5 tool-uri a detectat erori, dar să își continue execuția.
  • Workflow-ul este complet doar atunci când niciun tool nu a semnalat erori.

Aveți grijă să rulați uneltele în mod neinteractiv (dacă este disponibil), și să verificați codurile de eroare întoarse de acestea.

4. Resources

icalc/laboratoare/laborator-10.txt · Last modified: 2023/04/15 17:26 by cezar.craciunoiu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0