2022-08-14 11:36:24 +02:00
#!/usr/bin/env python3
# -*- mode: python -*-
# -*- coding: utf-8 -*-
""" Construction des fichiers exemples pour la documentation.
Usage :
cd / opt / scodoc / tests / api
2022-08-21 09:17:45 +02:00
python make_samples . py [ entry_names ]
2022-08-14 11:36:24 +02:00
2022-08-21 09:17:45 +02:00
si entry_names est spécifié , la génération est restreints aux exemples cités . expl : ` python make_samples departements departement - formsemestres `
2022-08-14 11:36:24 +02:00
doit être exécutée immédiatement apres une initialisation de la base pour test API ! ( car dépendant des identifiants générés lors de la création des objets )
cd / opt / scodoc / tests / api
tools / create_database . sh - - drop SCODOC_TEST_API & & flask db upgrade & & flask sco - db - init - - erase & & flask init - test - database
Créer éventuellement un fichier ` . env ` dans / opt / scodoc / tests / api
avec la config du client API :
` ` `
SCODOC_URL = " http://localhost:5000/ "
` ` `
Cet utilitaire prend en donnée le fichier de nom ` samples . csv ` contenant la description des exemples ( séparés par une tabulation ( \t ) , une ligne par exemple )
* Le nom de l ' exemple donne le nom du fichier généré (nom_exemple => nom_exemple.json.md). plusieurs lignes peuvent partager le même nom. dans ce cas le fichier contiendra chacun des exemples
* l ' url utilisée
* la permission nécessaire ( par défaut ScoView )
* la méthode GET , POST à utiliser ( si commence par #, la ligne est ignorée)
* les arguments éventuel ( en cas de POST ) : une chaîne de caractère selon json
Implémentation :
Le code complète une structure de données ( Samples ) qui est un dictionnaire de set ( indicé par le nom des exemple .
Chacun des éléments du set est un exemple ( Sample )
Quand la structure est complète , on génére tous les fichiers textes
- nom de l exemple
- un ou plusieurs exemples avec pour chaucn
- l url utilisée
- les arguments éventuels
- le résultat
Le tout mis en forme au format markdown et rangé dans le répertoire DATA_DIR ( / tmp / samples ) qui est créé ou écrasé si déjà existant
TODO : ajouter un argument au script permettant de ne générer qu ' un seul fichier (exemple: `python make_samples.py nom_exemple`)
"""
import os
import shutil
2022-08-21 09:17:45 +02:00
import sys
import re
2022-08-14 11:36:24 +02:00
from collections import defaultdict
from pprint import pprint as pp
from pprint import pformat as pf
import urllib3
import json
from setup_test_api import (
API_PASSWORD ,
API_URL ,
API_USER ,
APIError ,
CHECK_CERTIFICATE ,
get_auth_headers ,
GET ,
POST_JSON ,
SCODOC_URL ,
)
DATA_DIR = " /tmp/samples/ "
class Sample :
def __init__ ( self , url , method = " GET " , permission = " ScoView " , content = None ) :
self . content = content
self . permission = permission
self . url = url
self . method = method
self . result = None
2022-08-21 09:17:45 +02:00
self . output = " json "
2022-08-14 11:36:24 +02:00
if permission == " ScoView " :
HEADERS = get_auth_headers ( " test " , " test " )
elif permission == " ScoSuperAdmin " :
HEADERS = get_auth_headers ( " admin_api " , " admin_api " )
elif permission == " ScoUsersAdmin " :
HEADERS = get_auth_headers ( " admin_api " , " admin_api " )
else :
raise Exception ( f " Bad permission : { permission } " )
if self . method == " GET " :
self . result = GET ( self . url , HEADERS )
elif self . method == " POST " :
if self . content == " " :
self . result = POST_JSON ( self . url , headers = HEADERS )
else :
HEADERS [ " Content-Type " ] = " application/json ; charset=utf-8 "
self . result = POST_JSON ( self . url , json . loads ( self . content ) , HEADERS )
elif self . method [ 0 ] != " # " :
2022-10-31 10:12:04 +01:00
error = f ' Bad method : " { self . method } " '
raise Exception ( error )
2022-08-14 11:36:24 +02:00
self . shorten ( )
file = open ( f " sample_TEST.json.md " , " tw " )
self . dump ( file )
file . close ( )
2022-08-21 09:17:45 +02:00
def _shorten (
self , item
) : # abrege les longues listes (limite à 2 éléments et affiche "... etc. à la place"
2022-08-14 11:36:24 +02:00
if isinstance ( item , list ) :
2022-08-21 09:17:45 +02:00
return [ self . _shorten ( child ) for child in item [ : 2 ] ] + [ " ... etc. " ]
2022-08-14 11:36:24 +02:00
return item
def shorten ( self ) :
self . result = self . _shorten ( self . result )
def pp ( self ) :
print ( f " ------ url: { self . url } " )
print ( f " method: { self . method } " )
print ( f " content: { self . content } " )
print ( f " permission: { self . permission } " )
pp ( self . result , indent = 4 )
def dump ( self , file ) :
2022-11-01 11:19:28 +01:00
self . url = self . url . replace ( " ?date_courante=2022-07-20 " , " " )
2022-10-31 10:12:04 +01:00
2022-08-14 11:36:24 +02:00
file . write ( f " #### { self . method } { self . url } \n " )
if len ( self . content ) > 0 :
file . write ( f " > `Content-Type: application/json` \n " )
file . write ( f " > \n " )
file . write ( f " > ` { self . content } ` \n \n " )
file . write ( " ```json \n " )
2022-08-21 09:17:45 +02:00
content = json . dumps ( self . result , indent = 4 , sort_keys = True )
content = content . replace ( " ... etc. " , " ... " )
# regexp for date like: "2022-08-14T10:01:44.043869+02:00"
regexp = re . compile (
r ' " (-?(?:[1-9][0-9]*)?[0-9] {4} )-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])( \ .[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])? " '
)
content = regexp . sub ( ' " 2022-08-20T12:00:00.000000+02:00 " ' , content )
file . write ( content )
2022-08-14 11:36:24 +02:00
file . write ( " \n ``` \n \n " )
class Samples :
2022-08-21 09:17:45 +02:00
def __init__ ( self , entry_names ) :
""" Entry_names: la liste des entrées à reconstruire.
si None , la totalité des lignes de samples . csv est prise en compte
"""
2022-08-14 11:36:24 +02:00
self . entries = defaultdict ( lambda : set ( ) )
2022-08-21 09:17:45 +02:00
self . entry_names = entry_names
2022-08-14 11:36:24 +02:00
def add_sample ( self , entry , url , method = " GET " , permission = " ScoView " , content = None ) :
2022-08-21 09:17:45 +02:00
if self . entry_names is None or entry in self . entry_names :
if method [ 0 ] == " # " :
detail = " **ignored** "
elif content == " " :
detail = " "
else :
detail = f " : { content } "
print ( f " { entry : 50 } { method : 5 } { url : 50 } { detail } " )
sample = Sample ( url , method , permission , content )
self . entries [ entry ] . add ( sample )
2022-08-14 11:36:24 +02:00
def pp ( self ) :
for entry , samples in self . entries . items ( ) :
print ( f " === { entry } " )
for sample in samples :
sample . pp ( )
def dump ( self ) :
for entry , samples in self . entries . items ( ) :
file = open ( f " { DATA_DIR } sample_ { entry } .json.md " , " tw " )
file . write ( f " ### { entry } \n \n " )
2022-08-21 09:17:45 +02:00
for sample in sorted (
samples , key = lambda s : s . url
) : # sorted de façon à rendre le fichier résultat déterministe (i.e. indépendant de l ordre d arrivée des résultats)
2022-08-14 11:36:24 +02:00
sample . dump ( file )
file . close ( )
def make_samples ( ) :
2022-08-21 09:17:45 +02:00
if len ( sys . argv ) == 1 :
entry_names = None
else :
entry_names = sys . argv [ 1 : ]
2022-08-14 11:36:24 +02:00
if os . path . exists ( DATA_DIR ) :
if not os . path . isdir ( DATA_DIR ) :
raise f " { DATA_DIR } existe déjà et n ' est pas un répertoire "
else :
# DATA_DIR existe déjà - effacer et recréer
shutil . rmtree ( DATA_DIR )
os . mkdir ( DATA_DIR )
else :
os . mkdir ( " /tmp/samples " )
2022-08-21 09:17:45 +02:00
samples = Samples ( entry_names )
samples_file = os . path . dirname ( __file__ ) + " /samples.csv "
with open ( samples_file ) as f :
2022-08-14 11:36:24 +02:00
L = [ x [ : - 1 ] . split ( " \t " ) for x in f ]
for line in L [ 1 : ] :
entry_name = line [ 0 ]
url = line [ 1 ]
permission = line [ 2 ] if line [ 2 ] != " " else " ScoView "
method = line [ 3 ] if line [ 3 ] != " " else " GET "
2022-10-31 10:12:04 +01:00
content = line [ 4 ] if len ( line ) > 4 else " "
2022-08-14 11:36:24 +02:00
samples . add_sample ( entry_name , url , method , permission , content )
samples . dump ( )
return samples
if not CHECK_CERTIFICATE :
urllib3 . disable_warnings ( )
make_samples ( )