Differences

This shows you the differences between two versions of the page.

Link to this comparison view

asc:teme:tema1 [2024/03/23 21:18]
giorgiana.vlasceanu [Tema 1 - Le Stats Sportif]
asc:teme:tema1 [2025/04/06 09:17] (current)
giorgiana.vlasceanu [Tema 1 - Le Stats Sportif]
Line 2: Line 2:
  
 <note important> ​   ​ <note important> ​   ​
-  ​* **Deadline:​** 7 aprilie ​2024, ora 23:55. Primiți un bonus de 10% pentru trimiterea temei cu 2 zile înaintea acestui termen, adică înainte de 5 aprilie 2024, ora 23:55. +    ​* **Deadline ​soft:** <del>7 aprilie ​2025</​del> ​**9 aprilie 2025**, ora 23:55. Veți primi o depunctare de 10% din punctajul maxim al temei pentru fiecare zi de întârziere,​ până la maxim 7 zile, adică până pe <del>14 aprilie ​2025</​del>​ 16 aprilie 2025, ora 23:55. 
-    ​* **Deadline hard:** 14 aprilie 2024, ora 23:55. Veți primi o depunctare de 10% din punctajul maxim al temei pentru fiecare zi de întârziere,​ până la maxim 7 zile, adică până pe 14 aprilie ​2024, ora 23:55. +    * **Deadline hard:** <​del>​14 aprilie 2025</​del>​ **16 aprilie 2025**, ora 23:55. 
-    * **Responsabili:​** [[ andreicatalin.ouatu@gmail.com | Andrei Ouatu]], [[andreitrifu.acs@gmail.com|Andrei Trifu]], [[ adumitrescu2708@stud.acs.upb.ro| Alexandra Dumitrescu]],​[[eduard.staniloiu@cs.pub.ro | Eduard Stăniloiu]], [[ radunichita99@gmail.com | Radu Nichita]], [[ioana.profeanu@gmail.com| Ioana Profeanu]], [[giorgiana.vlasceanu@gmail.com | Giorgiana Vlăsceanu]] ​+    * **Responsabili:​** [[ andreicatalin.ouatu@gmail.com | Andrei Ouatu]], [[eduard.staniloiu@cs.pub.ro | Eduard Stăniloiu]],​ [[giorgiana.vlasceanu@gmail.com | Giorgiana Vlăsceanu]] ​
     * **Autori:** [[eduard.staniloiu@cs.pub.ro | Eduard Stăniloiu]],​ [[giorgiana.vlasceanu@gmail.com | Giorgiana Vlăsceanu]]     * **Autori:** [[eduard.staniloiu@cs.pub.ro | Eduard Stăniloiu]],​ [[giorgiana.vlasceanu@gmail.com | Giorgiana Vlăsceanu]]
 </​note>​ </​note>​
  
 <note tip> <note tip>
-  * Dată publicare: ​25 martie+  * Dată publicare: ​24 martie 
 +  * Dată actualizare deadline: 6 aprilie
 </​note>​ </​note>​
  
Line 47: Line 48:
 Întrucât procesarea datelor din csv poate dura mai mult timp, modelul implementat de către server va fi următorul: Întrucât procesarea datelor din csv poate dura mai mult timp, modelul implementat de către server va fi următorul:
  * un endpoit (ex. '/​api/​states_mean'​) care primește requestul și va întoarce clientului un **job_id** (ex. "​job_id_1",​ "​job_id_2",​ ..., "​job_id_n"​)  * un endpoit (ex. '/​api/​states_mean'​) care primește requestul și va întoarce clientului un **job_id** (ex. "​job_id_1",​ "​job_id_2",​ ..., "​job_id_n"​)
- * endpointul '/api/results/​job_id'​ care va verifica dacă job_id-ul este valid, rezultatul calculului este gata sau nu și va returna un răspuns corespunzător (detalii mai jos)+ * endpointul '/api/get_results/​job_id'​ care va verifica dacă job_id-ul este valid, rezultatul calculului este gata sau nu și va returna un răspuns corespunzător (detalii mai jos)
  
 === Mecanica unui request === === Mecanica unui request ===
Line 54: Line 55:
  
 Un thread va prelua un job din coada de joburi, va efectua operația asociată (ceea ce a fost capturat de către closure) și va scrie rezultatul calculului într-un fișier cu numele job_id-ului în directorul **results/​**. Un thread va prelua un job din coada de joburi, va efectua operația asociată (ceea ce a fost capturat de către closure) și va scrie rezultatul calculului într-un fișier cu numele job_id-ului în directorul **results/​**.
 +
 +<​note>​
 +Prin scrierea rezultatelor pe disc, în directorul **results/​**,​ simulăm interacțiunea cu o bază de date (poor man's db).
 +
 +Nu rețineți rezultatul într-o structură de date în memorie, este abordarea greșită.
 +Priviți problema din unghiul: dacă primesc 2k de requesturi de tipul fă-mi calculul x, voi rămâne fără memorie RAM înainte de a oferi un rezultat.
 +
 +Dacă vreți să folosiți o bază de date, go for it. Checkerul nu va verifica asta.
 +</​note>​
  
 === Requesturile pe care trebuie să le implementați sunt === === Requesturile pe care trebuie să le implementați sunt ===
Line 75: Line 85:
 <note tip> <note tip>
 În funcție de întrebare, primele state pot să aibă fie cel mai mic sau cel mai mare scor. În funcție de întrebare, primele state pot să aibă fie cel mai mic sau cel mai mare scor.
-De ex, pentru întrebarea:​ "​Percent of adults who engage in no leisure-time physical activity",​ primele state (best) vor avea scorurile cele mai mici, iar worst vor avea scorurile cele mai mari.+De exemplu, pentru întrebarea:​ "​Percent of adults who engage in no leisure-time physical activity",​ primele state (best) vor avea scorurile cele mai mici, iar worst vor avea scorurile cele mai mari.
 Pentru întrebarea:​ "​Percent of adults who engage in muscle-strengthening activities on 2 or more days a week", primele state (best) vor avea scorurile cele mai mari, iar worst vor avea scorurile cele mai mici. Pentru întrebarea:​ "​Percent of adults who engage in muscle-strengthening activities on 2 or more days a week", primele state (best) vor avea scorurile cele mai mari, iar worst vor avea scorurile cele mai mici.
 </​note>​ </​note>​
Line 99: Line 109:
 Primește o întrebare (din **setul de întrebări** de mai sus) și un stat, și calculează valoarea medie pentru fiecare segment (**Stratification1**) din categoriile (**StratificationCategory1**). Primește o întrebare (din **setul de întrebări** de mai sus) și un stat, și calculează valoarea medie pentru fiecare segment (**Stratification1**) din categoriile (**StratificationCategory1**).
  
-== /​graceful_shutdown ==+== /api/​graceful_shutdown ==
  
 Răspunde la un apel de tipul GET și va duce la notificarea Thread Poolului despre încheierea procesării. Răspunde la un apel de tipul GET și va duce la notificarea Thread Poolului despre încheierea procesării.
 Scopul acesteia este de a închide aplicația într-un mod graceful: nu se mai acceptă requesturi noi, se termină de procesat requesturile înregistrate până în acel moment (drain mode) și apoi aplicația poate fi oprită. Scopul acesteia este de a închide aplicația într-un mod graceful: nu se mai acceptă requesturi noi, se termină de procesat requesturile înregistrate până în acel moment (drain mode) și apoi aplicația poate fi oprită.
 +Endpointul **graceful_shutdown** va întoarce un JSON cu statusul **running** dacă încă sunt requesturi de procesat în coadă, sau cu statusul **done** atunci când coada este goală:
 +<​code>​
 +{
 +  "​status:​ "​running"​
 +}
 +</​code>​
  
-== /num_jobs == +În cazul în care se mai fac requesturi de tip procesare, de exemplu **states_mean**,​ se va întoarce un JSON: 
 +<​code>​ 
 +
 +  "​status:​ "​error",​ 
 +  "​reason":​ "​shutting down"​ 
 +
 +</code>
  
-Răspunde cu numărul joburilor rămase de procesat. +Requesturile de tipul **get_results**,​ **jobs**, **num_jobs** se acceptă și după **graceful_shutdown**. 
-După un /​graceful_shutdown și o perioadă de timp, aceasta ar trebui să întoarcă valoarea 0, semnalând astfel că serverul flask poate fi oprit.+ 
 +== /api/jobs == 
 + 
 +Răspunde ​la un apel de tipul GET cu un JSON care conține toate JOB_ID-urile de până la acel moment și statusul lor. 
 +De exemplu: 
 +<​code>​ 
 +
 +  "​status":​ "​done"​ 
 +  "​data":​ [ 
 +    { "​job_id_1":​ "​done"​},​ 
 +    { "​job_id_2":​ "​running"​},​ 
 +    { "​job_id_3":​ "​running"​} 
 +  ] 
 +
 +</​code>​ 
 + 
 +== /​api/​num_jobs ==  
 + 
 +Răspunde la un apel de tipul GET cu numărul joburilor rămase de procesat. 
 +După un **/api/​graceful_shutdown** și o perioadă de timp, aceasta ar trebui să întoarcă valoarea 0, semnalând astfel că serverul flask poate fi oprit. 
 + 
 +== /​api/​get_results/<​job_id>​ == 
 + 
 +Răspunde la un apel de tipul GET (job_id-ul este parte din URL). 
 +Acesta verifică dacă job_id-ul primit este valid și răspunde cu un JSON corespunzător,​ după cum urmează: 
 + 
 +1. JOB_ID-ul este invalid 
 +<​code>​ 
 +
 +  "​status":​ "​error",​ 
 +  "​reason":​ "​Invalid job_id"​ 
 +
 +</​code>​ 
 + 
 +2. JOB_ID-ul este valid, dar rezultatul procesării nu este gata 
 +<​code>​ 
 +
 +  "​status":​ "​running",​ 
 +
 +</​code>​ 
 + 
 +3. JOB_ID-ul este valid și rezultatul procesării este gata 
 +<​code>​ 
 +
 +  "​status":​ "​done",​ 
 +  "​data":​ <​JSON_REZULTAT_PROCESARE>​ 
 +
 +</​code>​
  
 === Server === === Server ===
Line 134: Line 203:
 <​code>​ <​code>​
 $ python -m pip install -r requirements.txt $ python -m pip install -r requirements.txt
 +</​code>​
 +
 +Pașii de creare a mediului virtual și de instalare a pachetelor se regăsesc în fișierul Makefile.
 +Astfel, pentru a vă crea spațiul de lucru, rulați următoarele comenzi în interpretorul vostru de comenzi (verificat în ''​bash''​ și ''​zsh''​)
 +<​code>​
 +make create_venv
 +source venv/​bin/​activate
 +make install
 </​code>​ </​code>​
  
Line 180: Line 257:
         return jsonify({"​error":​ "​Method not allowed"​}),​ 405         return jsonify({"​error":​ "​Method not allowed"​}),​ 405
 </​code>​ </​code>​
 +
 +=== Structura input-ului și a output-ului ===
 +
 +Interacțiunea cu serverul se va face pe bază de mesaje JSON, după cum este descris mai jos.
 +Vă recomandăm să vă uitați în suita de teste, în directoarele input și output pentru a vedea informațiile mult mai detaliat.
 +
 +== Input ==
 +
 +Un input pentru un request care primește doar o întrebare în următorul format:
 +<​code>​
 +{
 +  "​question":​ "​Percent of adults aged 18 years and older who have an overweight classification"​
 +}
 +</​code>​
 +
 +Unul care așteaptă o întrebare și un stat are următorul format:
 +<​code>​
 +{
 +  "​question":​ "​Percent of adults who engage in no leisure-time physical activity",​
 +  "​state":​ "South Carolina"​
 +}
 +</​code>​
 +
 +== Output ==
 +
 +Un răspuns JSON va avea mereu structura:
 +<​code>​
 +{
 +  "​status":​ "​done",​
 +  "​data":​ <​JSON_REZULTAT_PROCESARE>​
 +}
 +</​code>​
 +
 +**JSON_REZULTAT_PROCESARE** este un obiect JSON așa cum se regăsește în directorul output, pentru fiecare endpoint din directorul tests.
  
 ===== Testare ===== ===== Testare =====
  
 Testarea se va realiza folosind atât unitteste, cât și teste funcționale. Testarea se va realiza folosind atât unitteste, cât și teste funcționale.
 +
 +==== Rularea testelor ====
 +
 +Pentru a rula testele, folosiți fișierul ''​Makefile''​.
 +Într-un shell 1) activați mediul virtual și 2) porniți serverul
 +<​code>​
 +source venv/​bin/​activate
 +make run_server
 +</​code>​
 +
 +Într-un alt shell 1) activați mediul virtual și 2) porniți checkerul
 +<​code>​
 +source venv/​bin/​activate
 +make run_tests
 +</​code>​
 +
 +<note important>​
 +Comenzile de mai jos sunt valabile pentru **Linux**.
 +Dacă dezvoltați tema pe alt sistem de operare, adaptați comenzile pentru sistemul vostru (de regulă, diferă foarte puțin calea către scriptul de activare al mediului virtual).
 +Trebuie să vă asigurați că ați activat mediul virtual înainte de a rula comenzile din make.
 +<​code>​
 +source venv/​bin/​activate
 +</​code>​
 +
 +Dacă nu ați activat mediul virtual, ''​make''​ vă va arunca următoarea eroare (linia, ex 8, poate să difere).
 +<​code>​
 +Makefile:8: *** "You must activate your virtual environment. Exiting..."​. ​ Stop.
 +</​code>​
 +
 +</​note>​
  
 ==== Unittesting ==== ==== Unittesting ====
Line 211: Line 352:
 </​spoiler>​ </​spoiler>​
  
-Pentru a testa comportamentul definiți în fișierul ''​TestWebserver.py''​ o clasă de testare numită ''​TestWebserver''​.+Pentru a testa comportamentul definiți în fișierul ''​unittests/TestWebserver.py''​ o clasă de testare numită ''​TestWebserver''​.
 Clasa ''​TestWebserver''​ va testa funcționalitatea tuturor rutelor definite de voi. Clasa ''​TestWebserver''​ va testa funcționalitatea tuturor rutelor definite de voi.
 Dacă definiți alte metode, va trebui să adăugați teste și pentru acestea. Dacă definiți alte metode, va trebui să adăugați teste și pentru acestea.
Line 217: Line 358:
 Vă recomandăm să folosiți metoda [[https://​docs.python.org/​3/​library/​unittest.html#​unittest.TestCase.setUp | setUp]] pentru a inițializa o instanță a clasei testate și orice altceva ce vă ajută în testarea codului. Vă recomandăm să folosiți metoda [[https://​docs.python.org/​3/​library/​unittest.html#​unittest.TestCase.setUp | setUp]] pentru a inițializa o instanță a clasei testate și orice altceva ce vă ajută în testarea codului.
 Un exemplu de utilizare a metodei ''​setUp''​ este disponibil în [[https://​docs.python.org/​3/​library/​unittest.html#​organizing-test-code | documentație]]. Un exemplu de utilizare a metodei ''​setUp''​ este disponibil în [[https://​docs.python.org/​3/​library/​unittest.html#​organizing-test-code | documentație]].
 +
 +<​note>​
 +În arhivă aveți un exemplu, dar nu ceva fix, doar structura trebuie respectată. De exemplu, puteți adăuga fișiere de referință în directorul `unittests` sau ce vă este necesar pentru a vă rula testele.
 +</​note>​
 +
 +<note tip>
 +Checkerul testează end-to-end: atât răspunsul, cât și faptul că serverul este în picioare și api-ul este cel așteptat.
 +
 +Scopul unittestelor este să validați că implementarea calculelor este ok.
 +De ex, pentru un csv de 2 linii, dat de voi ca input, funcția state_mean întoarce valoarea X (unde X l-ați calculat voi în alt mod și știți că este răspunsul corect).
 +
 +Recomandarea noastră este să vă scrieți funcțiile care implemetează calculele în așa fel încât să puteți "​injecta"​ input a.î. să puteți valida outputul.
 +Vă recomandăm clipul acesta de pe YT despre [[https://​www.youtube.com/​watch?​v=J1f5b4vcxCQ | dependency injection]].
 +</​note>​
  
 ===== Logging ===== ===== Logging =====
Line 234: Line 389:
  
 O descriere completă a cum puteți utiliza modului de logging este prezentă în categoria [[https://​docs.python.org/​3/​howto/​logging.html | HOWTO]] a documentației. O descriere completă a cum puteți utiliza modului de logging este prezentă în categoria [[https://​docs.python.org/​3/​howto/​logging.html | HOWTO]] a documentației.
 +
 +===== Precizări biblioteci =====
 +
 +În fișierul **requirements.txt** aveți specificate bibliotecile pe care le puteți folosi, pe lângă cele standard.
 +Nu se vor putea folosi alte biblioteci.
  
 ===== Precizări încărcare ===== ===== Precizări încărcare =====
  
-Arhiva temei va fi încărcată pe [[https://​curs.upb.ro/​2022/​mod/​assign/​view.php?​id=156013|moodle ​- TODO]]+Arhiva temei va fi încărcată pe [[https://​curs.upb.ro/​2024/​mod/​assign/​view.php?​id=115677 ​| moodle ]]
  
 /* Arhiva temei (fişier .zip) va fi uploadată pe site-ul cursului şi trebuie să conţină: */ /* Arhiva temei (fişier .zip) va fi uploadată pe site-ul cursului şi trebuie să conţină: */
  
-Arhiva trebuie să conțină:​ +Arhiva ​(fișier .zip) trebuie să conțină:​ 
-  * fișierele temei: ''​TODO''​ +  * fișierele temei și alte fișiere ''​.py''​ folosite în dezvoltare
-  * alte fișiere ''​.py''​ folosite în dezvoltare+
   * ''​README''​   * ''​README''​
-  * (opțional) directorul ​''​.git'' ​redenumit în ''​git'' ​pentru a permite verificarea automată a temei+  * fișierul ​''​git-log'' ​(Îl obțineți rulând comanda ​''​git ​log > git-log''​
 +  * un exemplu de conținut al arhivei este mai jos 
 +    <​code>​ 
 +    api_server.py 
 +    app/ 
 +    app/​routes.py 
 +    app/​task_runner.py 
 +    app/​data_ingestor.py 
 +    app/​__init__.py 
 +    README 
 +    unittests/​ 
 +    unittests/​mytests.py 
 +    git-log 
 +    </​code> ​    
 + 
 +<​note>​ 
 +Repository-ul pe care îl folosiți în procesul de implementare este necesar să fie privat. 
 +</​note>​
  
 <note tip> <note tip>
Line 273: Line 449:
   * fişier README sumar (până la -5 pct)   * fişier README sumar (până la -5 pct)
   * nerespectarea formatului .zip al arhivei (-2 pct)   * nerespectarea formatului .zip al arhivei (-2 pct)
 +  * lipsa fișierului ''​git-log''​ (-10 pct)
   * alte situaţii nespecificate,​ dar considerate inadecvate având în vedere obiectivele temei; în special situațiile de modificare a interfeței oferite   * alte situaţii nespecificate,​ dar considerate inadecvate având în vedere obiectivele temei; în special situațiile de modificare a interfeței oferite
  
-Se acordă bonus 5 pct pentru adăugarea directorului ''​.git''​ și utilizarea versionării în cadrul repository-ului. 
  
 <note warning> <note warning>
Line 288: Line 464:
 Deoarece apar diferențe de scor între versiuni diferite de pylint, vom testa temele doar cu [[https://​www.pylint.org/#​install| ultima versiune]]. Vă recomandăm să o folosiți și voi tot pe aceasta. Deoarece apar diferențe de scor între versiuni diferite de pylint, vom testa temele doar cu [[https://​www.pylint.org/#​install| ultima versiune]]. Vă recomandăm să o folosiți și voi tot pe aceasta.
  
-Vom face depunctări de până la -5pct dacă verificarea făcută cu pylint vă dă un scor mai mic de 8.+Vom face depunctări de până la 10pct dacă verificarea făcută cu pylint vă dă un scor mai mic de 8.
  
 ==== Observații ==== ==== Observații ====
Line 294: Line 470:
   * Pot exista depunctări mai mari decât este specificat în secţiunea [[ #notare | Notare]] pentru implementări care nu respectă obiectivele temei și pentru situatii care nu sunt acoperite în mod automat de către sistemul de testare   * Pot exista depunctări mai mari decât este specificat în secţiunea [[ #notare | Notare]] pentru implementări care nu respectă obiectivele temei și pentru situatii care nu sunt acoperite în mod automat de către sistemul de testare
   * Implementarea şi folosirea metodelor oferite în schelet este obligatorie   * Implementarea şi folosirea metodelor oferite în schelet este obligatorie
-  * Puteți adăuga variabile/​metode/​clase, însă nu puteți schimba antetul metodelor oferite în schelet+  * Puteți adăuga variabile/​metode/​clase ​etc.
   * Bug-urile de sincronizare,​ prin natura lor sunt nedeterministe;​ o temă care conţine astfel de bug-uri poate obţine punctaje diferite la rulări succesive; în acest caz punctajul temei va fi cel dat de tester în momentul corectării   * Bug-urile de sincronizare,​ prin natura lor sunt nedeterministe;​ o temă care conţine astfel de bug-uri poate obţine punctaje diferite la rulări succesive; în acest caz punctajul temei va fi cel dat de tester în momentul corectării
   * Recomandăm testarea temei în cât mai multe situații de load al sistemului și pe cât mai multe sisteme pentru a descoperi bug-urile de sincronizare   * Recomandăm testarea temei în cât mai multe situații de load al sistemului și pe cât mai multe sisteme pentru a descoperi bug-urile de sincronizare
Line 311: Line 487:
 ===== Suport, întrebări și clarificări ===== ===== Suport, întrebări și clarificări =====
  
-Pentru întrebări sau nelămuriri legate de temă folosiți [[https://​curs.upb.ro/​2022/​mod/​forum/​view.php?​id=144437|forumul temei - TODO]]. +Pentru întrebări sau nelămuriri legate de temă folosiți [[https://​curs.upb.ro/​2024/​mod/​forum/​view.php?​id=115669 ​| forumul temei]]. ​
  
 <note important>​ <note important>​
Line 319: Line 495:
  
 </​note>​ </​note>​
- 
- 
- 
  
asc/teme/tema1.1711221506.txt.gz · Last modified: 2024/03/23 21:18 by giorgiana.vlasceanu
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