before rendu

This commit is contained in:
Mael G. 2024-03-27 15:20:10 +01:00
parent 89c17187ba
commit c84d872927
42 changed files with 261 additions and 83 deletions

9
Makefile Normal file
View file

@ -0,0 +1,9 @@
.PHONY: test
test:
pytest -v ./athlete/tests
pytest -v ./medaille/tests
pytest -v ./discipline/tests
clear_before_rendreTP:
rm -rf ./data ./__pycache__ ./athlete/__pycache__ ./medaille/__pycache__ ./discipline/__pycache__

View file

@ -34,7 +34,9 @@ python app.py
## How to test
```bash
pytest -vvv .
pytest -v athlete/tests
pytest -v discipline/tests
pytest -v medaille/tests
```
## How to build the docker images

View file

@ -41,7 +41,7 @@ class ListeAthlete(RootModel):
for athlete in data:
self.root.append(Athlete(**athlete))
except FileNotFoundError:
print("Fichier introuvable")
print(f"Le fichier {path} n'existe pas")
def loadFromJsonData(self, data: str):
"""
Charge les données depuis une chaine json

View file

@ -2,6 +2,7 @@ import pytest
import shutil
from pathlib import Path
from app import create_app
from flask import request
@pytest.fixture()
def app():

View file

@ -1,13 +1,14 @@
from flask import Flask, jsonify, request
from pathlib import Path
import json
from discipline import Discipline, ListeDiscipline
from models import Discipline, ListeDiscipline
# noinspection PyUnresolvedReferences
from flask_swagger_ui import get_swaggerui_blueprint
import os
app = Flask(__name__)
app.config['DISCIPLINE_FILE'] = os.getenv('DISCIPLINE_FILE', Path(__file__).parent.parent / 'data' / 'disciplines.json')
print(app.config['DISCIPLINE_FILE'])
@app.route('/ping', methods=["GET"])
def ping():
@ -50,9 +51,9 @@ def deleteDiscipline(id: int):
"""
listeDisciplines = ListeDiscipline()
listeDisciplines.loadFromJson(app.config['DISCIPLINE_FILE'])
for athlete in listeDisciplines.root:
if athlete.id == id:
listeDisciplines.root.remove(athlete)
for discipline in listeDisciplines.root:
if discipline.id == id:
listeDisciplines.root.remove(discipline)
with open(app.config['DISCIPLINE_FILE'], 'w') as f:
json.dump(listeDisciplines.model_dump(), f, indent=4)
return jsonify({"message": "Discipline supprimé"}), 200
@ -102,7 +103,7 @@ def addDiscipline():
listeDisciplines = ListeDiscipline()
listeDisciplines.loadFromJson(app.config['DISCIPLINE_FILE'])
discipline = Discipline(**json.loads(request.data))
discipline.id = max([athlete.id for athlete in listeDisciplines.root]) + 1
discipline.id = max([discipline.id for discipline in listeDisciplines.root]) + 1
listeDisciplines.root.append(discipline)
with open(app.config['DISCIPLINE_FILE'], 'w') as f:
json.dump(listeDisciplines.model_dump(), f, indent=4)

View file

@ -35,10 +35,10 @@ class ListeDiscipline(RootModel):
try:
with open(path) as f:
data = json.load(f)
for athlete in data:
self.root.append(Discipline(**athlete))
for discipline in data:
self.root.append(Discipline(**discipline))
except FileNotFoundError:
print("Fichier introuvable")
print(f"Le fichier {path} n'existe pas")
def loadFromJsonData(self, data: str):
"""
Charge les données depuis une chaine json
@ -46,5 +46,5 @@ class ListeDiscipline(RootModel):
:return: None
"""
data = json.loads(data)
for athlete in data:
self.root.append(Discipline(**athlete))
for discipline in data:
self.root.append(Discipline(**discipline))

View file

@ -1,4 +1,4 @@
from discipline import Discipline
from models import Discipline
def test_getDiscipline(client):
response = client.get("/1")

View file

@ -1,9 +1,9 @@
from discipline import ListeDiscipline
def test_listeAthlete(client):
from models import ListeDiscipline
def test_listeDiscipline(client):
response = client.get("/")
listeDiscipline = ListeDiscipline()
listeDiscipline.loadFromJsonData(response.data)
assert listeDiscipline.root is not None
assert len(listeDiscipline.root) > 0
assert listeDiscipline.root[0].id == 0
assert listeDiscipline.root[0].nom is not None
assert listeDiscipline.root[0].id == 1
assert listeDiscipline.root[0].intitule is not None

View file

@ -1,4 +1,4 @@
from discipline import Discipline
from models import Discipline
def test_postDiscipline(client):
discipline = Discipline(

View file

@ -1,7 +1,7 @@
from flask import Flask, jsonify, request
from pathlib import Path
import json
from athlete import ListeAthlete, Athlete
from models import ListeMedaille, Medaille
from flask_swagger_ui import get_swaggerui_blueprint
import os
@ -11,98 +11,102 @@ app.config['MEDAILLE_FILE'] = os.getenv('MEDAILLE_FILE', Path(__file__).parent.p
def ping():
return jsonify({"message": "pong"}), 200
@app.route('/', methods=["GET"])
def listeAthlete():
def listeMedaille():
"""
Renvoie la liste des athlètes
Renvoie la liste des médilles
"""
# Offset / Limit
offset = request.args.get('offset', 0)
limit = request.args.get('limit', 10)
listeAthletes = ListeAthlete()
listeAthletes.loadFromJson(app.config['MEDAILLE_FILE'])
listeMedailles = ListeMedaille()
listeMedailles.loadFromJson(app.config['MEDAILLE_FILE'])
if limit != 0:
listeAthletes.root = listeAthletes.root[int(offset):int(offset)+int(limit)]
listeMedailles.root = listeMedailles.root[int(offset):int(offset)+int(limit)]
else:
listeAthletes.root = listeAthletes.root[int(offset):]
listeMedailles.root = listeMedailles.root[int(offset):]
return jsonify(listeAthletes.model_dump()), 200
return jsonify(listeMedailles.model_dump()), 200
@app.route('/<int:id>', methods=["GET"])
def getAthlete(id: int):
def getMedaille(id: int):
"""
Renvoie un athlète par son id
Renvoie un médille par son id
"""
listeAthletes = ListeAthlete()
listeAthletes.loadFromJson(app.config['MEDAILLE_FILE'])
for athlete in listeAthletes.root:
if athlete.id == id:
return jsonify(athlete.model_dump()), 200
return jsonify({"message": "Athlete introuvable"}), 404
listeMedailles = ListeMedaille()
listeMedailles.loadFromJson(app.config['MEDAILLE_FILE'])
for medaille in listeMedailles.root:
if medaille.id == id:
return jsonify(medaille.model_dump()), 200
return jsonify({"message": "Medaille introuvable"}), 404
@app.route('/<int:id>', methods=["DELETE"])
def deleteAthlete(id: int):
def deleteMedaille(id: int):
"""
Supprime un athlète par son id
Supprime un médille par son id
"""
listeAthletes = ListeAthlete()
listeAthletes.loadFromJson(app.config['MEDAILLE_FILE'])
for athlete in listeAthletes.root:
if athlete.id == id:
listeAthletes.root.remove(athlete)
listeMedailles = ListeMedaille()
listeMedailles.loadFromJson(app.config['MEDAILLE_FILE'])
for medaille in listeMedailles.root:
if medaille.id == id:
listeMedailles.root.remove(medaille)
with open(app.config['MEDAILLE_FILE'], 'w') as f:
json.dump(listeAthletes.model_dump(), f, indent=4)
return jsonify({"message": "Athlete supprimé"}), 200
return jsonify({"message": "Athlete introuvable"}), 404
json.dump(listeMedailles.model_dump(), f, indent=4)
return jsonify({"message": "Medaille supprimé"}), 200
return jsonify({"message": "Medaille introuvable"}), 404
@app.route('/<int:id>', methods=["PUT"])
def updateAthlete(id: int):
def updateMedaille(id: int):
"""
Met à jour un athlète par son id
Met à jour un médille par son id
"""
listeAthletes = ListeAthlete()
listeAthletes.loadFromJson(app.config['MEDAILLE_FILE'])
for athlete in listeAthletes.root:
if athlete.id == id:
listeMedailles = ListeMedaille()
listeMedailles.loadFromJson(app.config['MEDAILLE_FILE'])
for medaille in listeMedailles.root:
if medaille.id == id:
data = json.loads(request.data)
for key, value in data.items():
setattr(athlete, key, value)
setattr(medaille, key, value)
with open(app.config['MEDAILLE_FILE'], 'w') as f:
json.dump(listeAthletes.model_dump(), f, indent=4)
return jsonify({"message": "Athlete mis à jour"}), 200
return jsonify({"message": "Athlete introuvable"}), 404
json.dump(listeMedailles.model_dump(), f, indent=4)
return jsonify({"message": "Medaille mis à jour"}), 200
return jsonify({"message": "Medaille introuvable"}), 404
@app.route('/<int:id>', methods=["PATCH"])
def patchAthlete(id: int):
def patchMedaille(id: int):
"""
Met à jour un athlète par son id
Met à jour un médille par son id
"""
listeAthletes = ListeAthlete()
listeAthletes.loadFromJson(app.config['MEDAILLE_FILE'])
for athlete in listeAthletes.root:
if athlete.id == id:
listeMedailles = ListeMedaille()
listeMedailles.loadFromJson(app.config['MEDAILLE_FILE'])
for medaille in listeMedailles.root:
if medaille.id == id:
data = json.loads(request.data)
data["id"] = athlete.id # On ne peut pas changer l'id
data["id"] = medaille.id # On ne peut pas changer l'id
for key, value in data.items():
if hasattr(athlete, key):
setattr(athlete, key, value)
if hasattr(medaille, key):
setattr(medaille, key, value)
if not medaille.validate():
return jsonify({"message": "Données invalides"}), 400
with open(app.config['MEDAILLE_FILE'], 'w') as f:
json.dump(listeAthletes.model_dump(), f, indent=4)
return jsonify({"message": "Athlete mis à jour"}), 200
return jsonify({"message": "Athlete introuvable"}), 404
json.dump(listeMedailles.model_dump(), f, indent=4)
return jsonify({"message": "Medaille mis à jour"}), 200
return jsonify({"message": "Medaille introuvable"}), 404
@app.route('/', methods=["POST"])
def addAthlete():
def addMedaille():
"""
Ajoute un athlète
Ajoute un médille
"""
listeAthletes = ListeAthlete()
listeAthletes.loadFromJson(app.config['MEDAILLE_FILE'])
athlete = Athlete(**json.loads(request.data))
athlete.id = max([athlete.id for athlete in listeAthletes.root]) + 1
listeAthletes.root.append(athlete)
listeMedailles = ListeMedaille()
listeMedailles.loadFromJson(app.config['MEDAILLE_FILE'])
medaille = Medaille(**json.loads(request.data))
if not medaille.validate():
return jsonify({"message": "Données invalides"}), 400
medaille.id = max([medaille.id for medaille in listeMedailles.root]) + 1
listeMedailles.root.append(medaille)
with open(app.config['MEDAILLE_FILE'], 'w') as f:
json.dump(listeAthletes.model_dump(), f, indent=4)
return jsonify(athlete.model_dump()), 200
json.dump(listeMedailles.model_dump(), f, indent=4)
return jsonify(medaille.model_dump()), 200
swaggerui_blueprint = get_swaggerui_blueprint(
"/swagger",

60
medaille/models.py Normal file
View file

@ -0,0 +1,60 @@
from pydantic import BaseModel, RootModel
from typing import Optional, List
import json
class Medaille(BaseModel):
"""
Modèle Medaille
"""
id: Optional[int] = 0
type: str # Or, Argent, Bronze
sport: str
categorie: str # ex : 80kg pour le judo
pays: str # Nom FR du pays
def loadFromJsonData(self, data: str):
"""
Charge les données depuis une chaine json
:param data: Données json
:return: None
"""
data = json.loads(data)
for key, value in data.items():
setattr(self, key, value)
def validate(self) -> bool:
"""
Valide les données
:return: True si les données sont valides, False sinon
"""
if self.type not in ["Or", "Argent", "Bronze"]:
return False
return True
class ListeMedaille(RootModel):
root: List[Medaille] = []
def loadFromJson(self, path: str):
"""
Charge les données depuis un fichier json
:param path: Chemin du fichier json
:return: None
"""
try:
with open(path) as f:
data = json.load(f)
for discipline in data:
self.root.append(Medaille(**discipline))
except FileNotFoundError:
print(f"Le fichier {path} n'existe pas")
def loadFromJsonData(self, data: str):
"""
Charge les données depuis une chaine json
:param data: Données json
:return: None
"""
data = json.loads(data)
for discipline in data:
self.root.append(Medaille(**discipline))

View file

@ -118,15 +118,12 @@ components:
sport:
type: integer
example: 1234567
disclipine:
type: integer
example: 1234567
categorie:
type: str
example: +80kg
pays:
type: string
example: France
logo:
type: string
example: https://olympics.com/images/static/sports/pictograms/v2/kte.svg
requestBodies:
User:
description: Objet médaille à ajouter

View file

@ -0,0 +1,6 @@
def test_delMedaille(client):
response = client.delete("/1")
assert response.status_code == 200
response = client.get("/1")
assert response.status_code == 404

View file

@ -0,0 +1,13 @@
from models import Medaille
def test_getMedaille(client):
response = client.get("/1")
medaille = Medaille(
id=1,
type="Or",
sport="Judo",
categorie="80kg",
pays="France"
)
assert medaille.model_dump() == response.json
assert response.status_code == 200

View file

@ -0,0 +1,8 @@
from models import ListeMedaille
def test_listeMedaille(client):
response = client.get("/")
listeMedailles = ListeMedaille()
listeMedailles.loadFromJsonData(response.data)
assert listeMedailles.root is not None
assert len(listeMedailles.root) > 0
assert listeMedailles.root[0].id == 1

View file

@ -0,0 +1,3 @@
def test_ping_medaille(client):
response = client.get("/ping")
assert b"{\"message\":\"pong\"}\n" in response.data

View file

@ -0,0 +1,30 @@
from models import Medaille
def test_postMedaille(client):
medaille = Medaille(
id=1,
type="Argent",
sport="Escrime",
categorie="Fleuret",
pays="Italie"
)
response = client.post("/", json=medaille.model_dump())
assert response.status_code == 200
medaille.id = response.json["id"]
response = client.get(f"/{medaille.id}")
assert response.json == medaille.model_dump()
def test_postMedaille_erreur(client):
medaille = Medaille(
id=1,
type="NexistePas",
sport="Escrime",
categorie="Fleuret",
pays="Italie"
)
response = client.post("/", json=medaille.model_dump())
assert response.status_code == 400
assert response.json == {'message': 'Données invalides'}

View file

@ -18,13 +18,13 @@
"intitule": "100m",
"type": "Course",
"description": "Le 100 mètres est une épreuve de sprint en athlétisme. C'est l'épreuve reine des sprinteurs.",
"logo": "https://upload.wikimedia.org/wikipedia/commons/1/1b/Athletics_pictogram.svg",
"logo": "https://upload.wikimedia.org/wikipedia/commons/1/1b/Athletics_pictogram.svg"
},
{
"id": 4,
"intitule": "Natation",
"type": "Nage",
"description": "La natation est un sport consistant à parcourir une certaine distance dans l'eau, en utilisant les bras et les jambes.",
"logo": "https://upload.wikimedia.org/wikipedia/commons/0/0d/Swimming_pictogram.svg",
"logo": "https://upload.wikimedia.org/wikipedia/commons/0/0d/Swimming_pictogram.svg"
}
]

44
sample/medailles.json Normal file
View file

@ -0,0 +1,44 @@
[
{
"id": 1,
"type": "Or",
"sport": "Judo",
"categorie": "80kg",
"pays": "France"
},
{
"id": 2,
"type": "Argent",
"sport": "Judo",
"categorie": "80kg",
"pays": "France"
},
{
"id": 3,
"type": "Bronze",
"sport": "Judo",
"categorie": "80kg",
"pays": "France"
},
{
"id": 4,
"type": "Or",
"sport": "Judo",
"categorie": "80kg",
"pays": "France"
},
{
"id": 5,
"type": "Argent",
"sport": "Judo",
"categorie": "80kg",
"pays": "France"
},
{
"id": 6,
"type": "Bronze",
"sport": "Judo",
"categorie": "80kg",
"pays": "France"
}
]