forked from ScoDoc/ScoDoc
Génération doc API (WIP)
This commit is contained in:
parent
9ca86e7900
commit
71639606fa
@ -48,6 +48,8 @@ def assiduite(assiduite_id: int = None):
|
|||||||
"""Retourne un objet assiduité à partir de son id
|
"""Retourne un objet assiduité à partir de son id
|
||||||
|
|
||||||
Exemple de résultat:
|
Exemple de résultat:
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"assiduite_id": 1,
|
"assiduite_id": 1,
|
||||||
"etudid": 2,
|
"etudid": 2,
|
||||||
@ -61,6 +63,7 @@ def assiduite(assiduite_id: int = None):
|
|||||||
"user_nom_complet": "Marie Dupont"
|
"user_nom_complet": "Marie Dupont"
|
||||||
"est_just": False or True,
|
"est_just": False or True,
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return get_model_api_object(Assiduite, assiduite_id, Identite)
|
return get_model_api_object(Assiduite, assiduite_id, Identite)
|
||||||
@ -78,15 +81,18 @@ def assiduite(assiduite_id: int = None):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def assiduite_justificatifs(assiduite_id: int = None, long: bool = False):
|
def assiduite_justificatifs(assiduite_id: int = None, long: bool = False):
|
||||||
"""Retourne la liste des justificatifs qui justifie cette assiduitée
|
"""Retourne la liste des justificatifs qui justifient cette assiduité.
|
||||||
|
|
||||||
Exemple de résultat:
|
Exemple de résultat:
|
||||||
|
|
||||||
|
```json
|
||||||
[
|
[
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return get_assiduites_justif(assiduite_id, long)
|
return get_assiduites_justif(assiduite_id, long)
|
||||||
@ -124,22 +130,20 @@ def assiduites_count(
|
|||||||
etudid: int = None, nip: str = None, ine: str = None, with_query: bool = False
|
etudid: int = None, nip: str = None, ine: str = None, with_query: bool = False
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Retourne le nombre d'assiduités d'un étudiant
|
Retourne le nombre d'assiduités d'un étudiant.
|
||||||
chemin : /assiduites/<int:etudid>/count
|
|
||||||
|
|
||||||
Un filtrage peut être donné avec une query
|
Un filtrage peut être donné avec une `query`.
|
||||||
chemin : /assiduites/<int:etudid>/count/query?
|
|
||||||
|
|
||||||
Les différents filtres :
|
Les différents filtres :
|
||||||
Type (type de comptage -> journee, demi, heure, nombre d'assiduite):
|
- Type (type de comptage -> journee, demi, heure, nombre d'assiduite):
|
||||||
query?type=(journee, demi, heure) -> une seule valeur parmis les trois
|
query?type=(journee, demi, heure) -> une seule valeur parmis les trois
|
||||||
ex: .../query?type=heure
|
ex: .../query?type=heure
|
||||||
Comportement par défaut : compte le nombre d'assiduité enregistrée
|
Comportement par défaut : compte le nombre d'assiduité enregistrée
|
||||||
|
|
||||||
Etat (etat de l'étudiant -> absent, present ou retard):
|
- Etat (etat de l'étudiant -> absent, present ou retard):
|
||||||
query?etat=[- liste des états séparé par une virgule -]
|
`query?etat=[- liste des états séparé par une virgule -]`
|
||||||
ex: .../query?etat=present,retard
|
ex: .../query?etat=present,retard
|
||||||
Date debut
|
- Date debut
|
||||||
(date de début de l'assiduité, sont affichés les assiduités
|
(date de début de l'assiduité, sont affichés les assiduités
|
||||||
dont la date de début est supérieur ou égale à la valeur donnée):
|
dont la date de début est supérieur ou égale à la valeur donnée):
|
||||||
query?date_debut=[- date au format iso -]
|
query?date_debut=[- date au format iso -]
|
||||||
|
@ -414,13 +414,14 @@ def bulletin(
|
|||||||
"""
|
"""
|
||||||
Retourne le bulletin d'un étudiant dans un formsemestre.
|
Retourne le bulletin d'un étudiant dans un formsemestre.
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
formsemestre_id : l'id d'un formsemestre
|
formsemestre_id : l'id d'un formsemestre
|
||||||
code_type : "etudid", "nip" ou "ine"
|
code_type : "etudid", "nip" ou "ine"
|
||||||
code : valeur du code INE, NIP ou etudid, selon code_type.
|
code : valeur du code INE, NIP ou etudid, selon code_type.
|
||||||
version : type de bulletin (par défaut, "selectedevals"): short, long, selectedevals, butcourt
|
version : type de bulletin (par défaut, "selectedevals"): short, long, selectedevals, butcourt
|
||||||
pdf : si spécifié, bulletin au format PDF (et non JSON).
|
pdf : si spécifié, bulletin au format PDF (et non JSON).
|
||||||
|
|
||||||
Exemple de résultat : voir https://scodoc.org/ScoDoc9API/#bulletin
|
|
||||||
"""
|
"""
|
||||||
if version == "pdf":
|
if version == "pdf":
|
||||||
version = "long"
|
version = "long"
|
||||||
@ -599,7 +600,10 @@ def etudiant_edit(
|
|||||||
code_type: str = "etudid",
|
code_type: str = "etudid",
|
||||||
code: str = None,
|
code: str = None,
|
||||||
):
|
):
|
||||||
"""Edition des données étudiant (identité, admission, adresses)"""
|
"""Édition des données étudiant (identité, admission, adresses).
|
||||||
|
|
||||||
|
`code_type`: `etudid`, `ine` ou `nip`.
|
||||||
|
"""
|
||||||
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
||||||
if not ok:
|
if not ok:
|
||||||
return etud # json error
|
return etud # json error
|
||||||
|
@ -104,6 +104,8 @@ def formsemestres_query():
|
|||||||
Retourne les formsemestres filtrés par
|
Retourne les formsemestres filtrés par
|
||||||
étape Apogée ou année scolaire ou département (acronyme ou id) ou état ou code étudiant
|
étape Apogée ou année scolaire ou département (acronyme ou id) ou état ou code étudiant
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
etape_apo : un code étape apogée
|
etape_apo : un code étape apogée
|
||||||
annee_scolaire : année de début de l'année scolaire
|
annee_scolaire : année de début de l'année scolaire
|
||||||
dept_acronym : acronyme du département (eg "RT")
|
dept_acronym : acronyme du département (eg "RT")
|
||||||
|
@ -348,7 +348,7 @@ class Assiduite(ScoDocModel):
|
|||||||
"""
|
"""
|
||||||
Retourne le module associé à l'assiduité
|
Retourne le module associé à l'assiduité
|
||||||
Si traduire est vrai, retourne le titre du module précédé du code
|
Si traduire est vrai, retourne le titre du module précédé du code
|
||||||
Sinon rentourne l'objet Module ou None
|
Sinon retourne l'objet Module ou None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.moduleimpl_id is not None:
|
if self.moduleimpl_id is not None:
|
||||||
@ -358,7 +358,7 @@ class Assiduite(ScoDocModel):
|
|||||||
return f"{mod.code} {mod.titre}"
|
return f"{mod.code} {mod.titre}"
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
elif self.external_data is not None and "module" in self.external_data:
|
if self.external_data is not None and "module" in self.external_data:
|
||||||
return (
|
return (
|
||||||
"Autre module (pas dans la liste)"
|
"Autre module (pas dans la liste)"
|
||||||
if self.external_data["module"] == "Autre"
|
if self.external_data["module"] == "Autre"
|
||||||
|
15
scodoc.py
15
scodoc.py
@ -748,6 +748,19 @@ def generate_ens_calendars(): # generate-ens-calendars
|
|||||||
help="Endpoint à partir duquel générer la carte des routes",
|
help="Endpoint à partir duquel générer la carte des routes",
|
||||||
)
|
)
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def gen_api_map(endpoint):
|
def gen_api_map(endpoint): # gen-api-map
|
||||||
"""Génère la carte des routes de l'API."""
|
"""Génère la carte des routes de l'API."""
|
||||||
tools.gen_api_map(app, endpoint_start=endpoint)
|
tools.gen_api_map(app, endpoint_start=endpoint)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cli.command()
|
||||||
|
@click.option(
|
||||||
|
"-e",
|
||||||
|
"--endpoint",
|
||||||
|
default="api.",
|
||||||
|
help="Endpoint à partir duquel générer la documentation des routes",
|
||||||
|
)
|
||||||
|
@with_appcontext
|
||||||
|
def gen_api_doc(endpoint): # gen-api-map
|
||||||
|
"""Génère la documentation des routes de l'API."""
|
||||||
|
tools.gen_api_doc(app, endpoint_start=endpoint)
|
||||||
|
@ -10,4 +10,4 @@ from tools.migrate_scodoc7_archives import migrate_scodoc7_dept_archives
|
|||||||
from tools.migrate_scodoc7_logos import migrate_scodoc7_dept_logos
|
from tools.migrate_scodoc7_logos import migrate_scodoc7_dept_logos
|
||||||
from tools.migrate_abs_to_assiduites import migrate_abs_to_assiduites
|
from tools.migrate_abs_to_assiduites import migrate_abs_to_assiduites
|
||||||
from tools.downgrade_assiduites import downgrade_module
|
from tools.downgrade_assiduites import downgrade_module
|
||||||
from tools.create_api_map import gen_api_map
|
from tools.create_api_map import gen_api_map, gen_api_doc
|
||||||
|
@ -439,21 +439,15 @@ def _create_question_mark_group(coords, href):
|
|||||||
return group
|
return group
|
||||||
|
|
||||||
|
|
||||||
# point d'entrée de la commande `flask gen-api-map`
|
def analyze_api_routes(app, endpoint_start: str) -> tuple:
|
||||||
def gen_api_map(app, endpoint_start="api"):
|
"""Parcours de toutes les routes de l'application
|
||||||
|
analyse docstrings
|
||||||
"""
|
"""
|
||||||
Fonction permettant de générer une carte SVG de l'API de ScoDoc
|
|
||||||
Elle récupère les routes de l'API et les transforme en un arbre de Token
|
|
||||||
puis génère un fichier SVG à partir de cet arbre
|
|
||||||
"""
|
|
||||||
|
|
||||||
print("DEBUG", app.view_functions["apiweb.user_info"].scodoc_permission)
|
|
||||||
# Création du token racine
|
# Création du token racine
|
||||||
api_map = Token("")
|
api_map = Token("")
|
||||||
|
|
||||||
doctable_lines: dict[str, dict] = {}
|
doctable_lines: dict[str, dict] = {}
|
||||||
|
|
||||||
# Parcours de toutes les routes de l'application
|
|
||||||
for rule in app.url_map.iter_rules():
|
for rule in app.url_map.iter_rules():
|
||||||
# On ne garde que les routes de l'API / APIWEB
|
# On ne garde que les routes de l'API / APIWEB
|
||||||
if not rule.endpoint.lower().startswith(endpoint_start.lower()):
|
if not rule.endpoint.lower().startswith(endpoint_start.lower()):
|
||||||
@ -468,8 +462,8 @@ def gen_api_map(app, endpoint_start="api"):
|
|||||||
|
|
||||||
# Récupération de la fonction associée à la route
|
# Récupération de la fonction associée à la route
|
||||||
func = app.view_functions[rule.endpoint]
|
func = app.view_functions[rule.endpoint]
|
||||||
func_name = parse_doc_name(func.__doc__ or "") or func.__name__
|
doc_dict = _parse_doc_string(func.__doc__ or "")
|
||||||
|
func_name = doc_dict.get("DOC_ANCHOR", [None])[0] or func.__name__
|
||||||
# Pour chaque segment de la route
|
# Pour chaque segment de la route
|
||||||
for i, segment in enumerate(segments):
|
for i, segment in enumerate(segments):
|
||||||
# On cherche si le segment est déjà un enfant du token courant
|
# On cherche si le segment est déjà un enfant du token courant
|
||||||
@ -521,16 +515,37 @@ def gen_api_map(app, endpoint_start="api"):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
permissions = "Aucune permission requise"
|
permissions = "Aucune permission requise"
|
||||||
|
|
||||||
|
if func_name not in doctable_lines:
|
||||||
doctable_lines[func_name] = {
|
doctable_lines[func_name] = {
|
||||||
"doctable": doctable,
|
"doctable": doctable,
|
||||||
"method": method,
|
"method": method,
|
||||||
"nom": func_name,
|
"nom": func_name,
|
||||||
"href": href,
|
"href": href,
|
||||||
"permission": permissions,
|
"permission": permissions,
|
||||||
|
"description": doc_dict.get("", ""),
|
||||||
|
"params": doc_dict.get("PARAMS", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
# On met à jour le token courant pour le prochain segment
|
# On met à jour le token courant pour le prochain segment
|
||||||
current_token = child
|
current_token = child
|
||||||
|
if func_name in doctable_lines: # endpoint déjà ajouté, ajoute au besoin route
|
||||||
|
doctable_lines[func_name]["routes"] = doctable_lines[func_name].get(
|
||||||
|
"routes", []
|
||||||
|
) + [rule.rule]
|
||||||
|
return api_map, doctable_lines
|
||||||
|
|
||||||
|
|
||||||
|
# point d'entrée de la commande `flask gen-api-map`
|
||||||
|
def gen_api_map(app, endpoint_start="api."):
|
||||||
|
"""
|
||||||
|
Fonction permettant de générer une carte SVG de l'API de ScoDoc
|
||||||
|
Elle récupère les routes de l'API et les transforme en un arbre de Token
|
||||||
|
puis génère un fichier SVG à partir de cet arbre
|
||||||
|
"""
|
||||||
|
|
||||||
|
print("DEBUG", app.view_functions["apiweb.user_info"].scodoc_permission)
|
||||||
|
|
||||||
|
api_map, doctable_lines = analyze_api_routes(app, endpoint_start)
|
||||||
|
|
||||||
# On génère le SVG à partir de l'arbre de Token
|
# On génère le SVG à partir de l'arbre de Token
|
||||||
generate_svg(api_map.to_svg_group(), "/tmp/api_map.svg")
|
generate_svg(api_map.to_svg_group(), "/tmp/api_map.svg")
|
||||||
@ -540,7 +555,8 @@ def gen_api_map(app, endpoint_start="api"):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# On génère le tableau à partir de doctable_lines
|
# On génère le tableau à partir de doctable_lines
|
||||||
_gen_table(sorted(doctable_lines.values(), key=lambda x: x["nom"]))
|
table = _gen_table(sorted(doctable_lines.values(), key=lambda x: x["nom"]))
|
||||||
|
_write_gen_table(table)
|
||||||
|
|
||||||
|
|
||||||
def _get_bbox(element, x_offset=0, y_offset=0):
|
def _get_bbox(element, x_offset=0, y_offset=0):
|
||||||
@ -646,7 +662,44 @@ def generate_svg(element, fname):
|
|||||||
tree.write(fname, encoding="utf-8", xml_declaration=True)
|
tree.write(fname, encoding="utf-8", xml_declaration=True)
|
||||||
|
|
||||||
|
|
||||||
def _get_doc_lines(keyword, doc) -> list[str]:
|
def _parse_doc_string(doc_string: str) -> dict[str, list[str]]:
|
||||||
|
"""Parse doc string and extract a dict:
|
||||||
|
{
|
||||||
|
"" : description_lines,
|
||||||
|
"keyword" : lines
|
||||||
|
}
|
||||||
|
|
||||||
|
In the docstring, each keyword is associated to a section like
|
||||||
|
|
||||||
|
KEYWORD
|
||||||
|
-------
|
||||||
|
...
|
||||||
|
(blank line)
|
||||||
|
|
||||||
|
All non blank lines not associated to a keyword go to description.
|
||||||
|
"""
|
||||||
|
doc_dict = {}
|
||||||
|
matches = re.finditer(
|
||||||
|
r"^\s*(?P<kw>[A-Z_\-]+)$\n^\s*-+\n(?P<txt>(^(?!\s*$).+$\n?)+)",
|
||||||
|
doc_string,
|
||||||
|
re.MULTILINE,
|
||||||
|
)
|
||||||
|
description = ""
|
||||||
|
i = 0
|
||||||
|
for match in matches:
|
||||||
|
start, end = match.span()
|
||||||
|
description += doc_string[i:start]
|
||||||
|
doc_dict[match.group("kw")] = [
|
||||||
|
x.strip() for x in match.group("txt").split("\n") if x.strip()
|
||||||
|
]
|
||||||
|
i = end
|
||||||
|
|
||||||
|
description += doc_string[i:]
|
||||||
|
doc_dict[""] = description.split("\n")
|
||||||
|
return doc_dict
|
||||||
|
|
||||||
|
|
||||||
|
def _get_doc_lines(keyword, doc_string: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Renvoie les lignes de la doc qui suivent le mot clé keyword
|
Renvoie les lignes de la doc qui suivent le mot clé keyword
|
||||||
Attention : s'arrête à la première ligne vide
|
Attention : s'arrête à la première ligne vide
|
||||||
@ -659,7 +712,7 @@ def _get_doc_lines(keyword, doc) -> list[str]:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
# Récupérer les lignes de la doc
|
# Récupérer les lignes de la doc
|
||||||
lines = [line.strip() for line in doc.split("\n")]
|
lines = [line.strip() for line in doc_string.split("\n")]
|
||||||
# On cherche la ligne "KEYWORD" et on vérifie que la ligne suivante est "-----"
|
# On cherche la ligne "KEYWORD" et on vérifie que la ligne suivante est "-----"
|
||||||
# Si ce n'est pas le cas, on renvoie un dictionnaire vide
|
# Si ce n'est pas le cas, on renvoie un dictionnaire vide
|
||||||
try:
|
try:
|
||||||
@ -682,7 +735,7 @@ def _get_doc_lines(keyword, doc) -> list[str]:
|
|||||||
return kw_lines
|
return kw_lines
|
||||||
|
|
||||||
|
|
||||||
def parse_doc_name(doc) -> str:
|
def parse_doc_name(doc_string: str) -> str:
|
||||||
"""
|
"""
|
||||||
renvoie le nom de la route à partir de la docstring
|
renvoie le nom de la route à partir de la docstring
|
||||||
|
|
||||||
@ -695,11 +748,11 @@ def parse_doc_name(doc) -> str:
|
|||||||
Il ne peut y avoir qu'une seule ligne suivant -----
|
Il ne peut y avoir qu'une seule ligne suivant -----
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name_lines: list[str] = _get_doc_lines("DOC_ANCHOR", doc)
|
name_lines: list[str] = _get_doc_lines("DOC_ANCHOR", doc_string)
|
||||||
return name_lines[0] if name_lines else None
|
return name_lines[0] if name_lines else None
|
||||||
|
|
||||||
|
|
||||||
def parse_query_doc(doc) -> dict[str, str]:
|
def parse_query_doc(doc_string: str) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
renvoie un dictionnaire {param: <type:nom_param>} (ex: {assiduite_id : <int:assiduite_id>})
|
renvoie un dictionnaire {param: <type:nom_param>} (ex: {assiduite_id : <int:assiduite_id>})
|
||||||
|
|
||||||
@ -714,7 +767,7 @@ def parse_query_doc(doc) -> dict[str, str]:
|
|||||||
Dès qu'une ligne ne respecte pas ce format (voir regex dans la fonction), on arrête de parser
|
Dès qu'une ligne ne respecte pas ce format (voir regex dans la fonction), on arrête de parser
|
||||||
Attention, la ligne ----- doit être collée contre QUERY et contre le premier paramètre
|
Attention, la ligne ----- doit être collée contre QUERY et contre le premier paramètre
|
||||||
"""
|
"""
|
||||||
query_lines: list[str] = _get_doc_lines("QUERY", doc)
|
query_lines: list[str] = _get_doc_lines("QUERY", doc_string)
|
||||||
|
|
||||||
query = {}
|
query = {}
|
||||||
regex = re.compile(r"^(\w+):(<.+>)$")
|
regex = re.compile(r"^(\w+):(<.+>)$")
|
||||||
@ -732,7 +785,7 @@ def parse_query_doc(doc) -> dict[str, str]:
|
|||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
def parse_doctable_doc(doc) -> dict[str, str]:
|
def parse_doctable_doc(doc_string: str) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Retourne un dictionnaire représentant les informations du tableau d'api
|
Retourne un dictionnaire représentant les informations du tableau d'api
|
||||||
à partir de la doc (DOC-TABLE)
|
à partir de la doc (DOC-TABLE)
|
||||||
@ -747,9 +800,7 @@ def parse_doctable_doc(doc) -> dict[str, str]:
|
|||||||
href: une-fonction
|
href: une-fonction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
doc_lines: list[str] = _get_doc_lines("DOC-TABLE", doc)
|
doc_lines: list[str] = _get_doc_lines("DOC-TABLE", doc_string)
|
||||||
|
|
||||||
# On crée un dictionnaire
|
|
||||||
table = {}
|
table = {}
|
||||||
|
|
||||||
# on parcourt les lignes de la doc
|
# on parcourt les lignes de la doc
|
||||||
@ -762,7 +813,9 @@ def parse_doctable_doc(doc) -> dict[str, str]:
|
|||||||
return table
|
return table
|
||||||
|
|
||||||
|
|
||||||
def _gen_table_line(nom, href, method, permission, doctable: dict):
|
def _gen_table_line(
|
||||||
|
nom="", href="", method="", permission="", doctable: dict = None, **kwargs
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Génère une ligne de tableau markdown
|
Génère une ligne de tableau markdown
|
||||||
|
|
||||||
@ -791,7 +844,7 @@ def _gen_table_head() -> str:
|
|||||||
return f"{headers}\n{line}\n"
|
return f"{headers}\n{line}\n"
|
||||||
|
|
||||||
|
|
||||||
def _gen_table(lines: list[dict], filename: str = "/tmp/api_table.md") -> str:
|
def _gen_table(lines: list[dict]) -> str:
|
||||||
"""
|
"""
|
||||||
Génère un tableau markdown à partir d'une liste de lignes
|
Génère un tableau markdown à partir d'une liste de lignes
|
||||||
|
|
||||||
@ -805,10 +858,13 @@ def _gen_table(lines: list[dict], filename: str = "/tmp/api_table.md") -> str:
|
|||||||
"""
|
"""
|
||||||
table = _gen_table_head()
|
table = _gen_table_head()
|
||||||
table += "\n".join([_gen_table_line(**line) for line in lines])
|
table += "\n".join([_gen_table_line(**line) for line in lines])
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
def _write_gen_table(table: str, filename: str = "/tmp/api_table.md"):
|
||||||
|
"""Ecriture du fichier md avec la table"""
|
||||||
with open(filename, "w", encoding="UTF-8") as f:
|
with open(filename, "w", encoding="UTF-8") as f:
|
||||||
f.write(table)
|
f.write(table)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"Le tableau a été généré avec succès. Vous pouvez le consulter à l'adresse suivante : {filename}"
|
f"Le tableau a été généré avec succès. Vous pouvez le consulter à l'adresse suivante : {filename}"
|
||||||
)
|
)
|
||||||
@ -854,3 +910,53 @@ if __name__ == "__main__":
|
|||||||
"href": hf,
|
"href": hf,
|
||||||
}
|
}
|
||||||
print(_gen_table([doc]))
|
print(_gen_table([doc]))
|
||||||
|
|
||||||
|
|
||||||
|
def doc_route(doctable: dict) -> str:
|
||||||
|
"""Generate markdown doc for a route"""
|
||||||
|
doc = f"""
|
||||||
|
#### **`{doctable['nom']}`**
|
||||||
|
|
||||||
|
"""
|
||||||
|
if doctable.get("routes"):
|
||||||
|
if len(doctable["routes"]) == 1:
|
||||||
|
doc += f"""* ** Route :** `{doctable["routes"][0]}`\n"""
|
||||||
|
else:
|
||||||
|
doc += "* ** Routes :**\n"
|
||||||
|
for route in doctable["routes"]:
|
||||||
|
doc += f""" * `{route}`\n"""
|
||||||
|
doc += f"""* **Méthode: {doctable['method']}**
|
||||||
|
* **Permission: `{doctable.get('permission', '')}`**
|
||||||
|
"""
|
||||||
|
if doctable.get("params"):
|
||||||
|
for param in doctable["params"]:
|
||||||
|
frags = param.split(":", maxsplit=1)
|
||||||
|
if len(frags) == 2:
|
||||||
|
name, descr = frags
|
||||||
|
else:
|
||||||
|
print(f"Warning: {doctable['nom']} : invalid PARAMS {param}")
|
||||||
|
name, descr = param, ""
|
||||||
|
doc += f""" * `{name}`: {descr}\n"""
|
||||||
|
if doctable.get("data"):
|
||||||
|
doc += f"""* **Data:** {doctable['data']}\n"""
|
||||||
|
if doctable.get("description"):
|
||||||
|
descr = "\n".join(s for s in doctable["description"])
|
||||||
|
doc += f"""* **Description:** {descr}\n"""
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
def gen_api_doc(app, endpoint_start="api."):
|
||||||
|
"commande gen-api-doc"
|
||||||
|
_, doctable_lines = analyze_api_routes(app, endpoint_start)
|
||||||
|
mddoc = "\n".join(
|
||||||
|
doc_route(doctable)
|
||||||
|
for doctable in sorted(doctable_lines.values(), key=lambda x: x["nom"])
|
||||||
|
)
|
||||||
|
|
||||||
|
fname = "/tmp/apidoc.md"
|
||||||
|
with open(fname, "w", encoding="utf-8") as f:
|
||||||
|
f.write(mddoc)
|
||||||
|
print(
|
||||||
|
"La documentation API a été générée avec succès. "
|
||||||
|
f"Vous pouvez la consulter à l'adresse suivante : {fname}"
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user