Skip to content

Commit

Permalink
WIP improving API documentation #24
Browse files Browse the repository at this point in the history
  • Loading branch information
juliecoust committed Oct 13, 2021
1 parent 7a14c59 commit 7ad37e5
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 33 deletions.
42 changes: 28 additions & 14 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1879,7 +1879,7 @@
"projects"
],
"summary":"Set Project Predict Settings",
"description":"**Update the project's prediction settings**, return **NULL upon success.**\n\nUnlike during full project update above, which needs high permissions, this entry point is accessible\nto project annotators, as it mirrors the prediction privileges.",
"description":"**Update the project's prediction settings**, return **NULL upon success.**\n\n🔒 Unlike during full project update above, which needs high permissions, this entry point is accessible\nto **project annotators**, as it mirrors the prediction privileges.",
"operationId":"set_project_predict_settings_projects__project_id__prediction_settings_put",
"parameters":[
{
Expand All @@ -1895,12 +1895,12 @@
"in":"path"
},
{
"description":"The new prediction settings",
"description":"The new prediction settings.",
"required":true,
"schema":{
"title":"Settings",
"type":"string",
"description":"The new prediction settings"
"description":"The new prediction settings."
},
"example":"seltaxo=84963,59996,56545 baseproject=2562,2571",
"name":"settings",
Expand Down Expand Up @@ -2503,24 +2503,24 @@
"in":"path"
},
{
"description":"\n\nSpecify the needed object (and ancilliary entities) fields.\n \nIt follows the naming convention 'prefix.field' : Prefix is either 'obj' for main object, 'fre' for free fields, 'img' for the visible image.\n\nThe column obj.imgcount contains the total count of images for the object.\n\nUse a comma to separate fields. \n ",
"description":"\n\nSpecify the needed object (and ancilliary entities) fields.\n \nIt follows the naming convention 'prefix.field' : Prefix is either 'obj' for main object, 'fre' for free fields, 'img' for the visible image.\n\nThe column obj.imgcount contains the total count of images for the object.\n\nUse a comma to separate fields. \n\n💡 More help :\n\nYou can get the field labels by parsing the classiffieldlist returned by a call to https://ecotaxa.obs-vlfr.fr/api/docs#/projects/project_query_projects__project_id__get.\n\n**Note that the following fields must be prefixed with the header \"obj.\"** (for example → obj.orig_id):\n\nacquisid classif_auto_id, classif_auto_score, classif_auto_when, classif_crossvalidation_id, classif_qual, classif_qual,\nclassif_id, classif_qual, classif_who, classif_when, complement_info, depth_max, depth_min,\nlatitude, longitude, objdate, object_link, objid, objtime, orig_id, random_value, similarity, sunpos.\n\n**Note that the following fields must be prefixed with the header \"img.\"** (for example → img.file_name):\n\nfile_name, height, imgid, imgrank, file_name, orig, objid, file_name thumb_file_name, thumb_height, thumb_width, width.\n\n**Note that the following fields must be prefixed with the header \"txo.\"** (for example → txo.display_name):\n\ncreation_datetime, creator_email, display_name, id, id_instance, id_source, lastupdate_datetime,\nname, nbrobj, nbrobjcum, parent_id, rename_to source_desc, source_url, taxostatus, taxotype.\n\n**All other fields must be prefixed by the header \"fre.\"** (for example → fre.circ.).\n ",
"required":false,
"schema":{
"title":"Fields",
"type":"string",
"description":"\n\nSpecify the needed object (and ancilliary entities) fields.\n \nIt follows the naming convention 'prefix.field' : Prefix is either 'obj' for main object, 'fre' for free fields, 'img' for the visible image.\n\nThe column obj.imgcount contains the total count of images for the object.\n\nUse a comma to separate fields. \n "
"description":"\n\nSpecify the needed object (and ancilliary entities) fields.\n \nIt follows the naming convention 'prefix.field' : Prefix is either 'obj' for main object, 'fre' for free fields, 'img' for the visible image.\n\nThe column obj.imgcount contains the total count of images for the object.\n\nUse a comma to separate fields. \n\n💡 More help :\n\nYou can get the field labels by parsing the classiffieldlist returned by a call to https://ecotaxa.obs-vlfr.fr/api/docs#/projects/project_query_projects__project_id__get.\n\n**Note that the following fields must be prefixed with the header \"obj.\"** (for example → obj.orig_id):\n\nacquisid classif_auto_id, classif_auto_score, classif_auto_when, classif_crossvalidation_id, classif_qual, classif_qual,\nclassif_id, classif_qual, classif_who, classif_when, complement_info, depth_max, depth_min,\nlatitude, longitude, objdate, object_link, objid, objtime, orig_id, random_value, similarity, sunpos.\n\n**Note that the following fields must be prefixed with the header \"img.\"** (for example → img.file_name):\n\nfile_name, height, imgid, imgrank, file_name, orig, objid, file_name thumb_file_name, thumb_height, thumb_width, width.\n\n**Note that the following fields must be prefixed with the header \"txo.\"** (for example → txo.display_name):\n\ncreation_datetime, creator_email, display_name, id, id_instance, id_source, lastupdate_datetime,\nname, nbrobj, nbrobjcum, parent_id, rename_to source_desc, source_url, taxostatus, taxotype.\n\n**All other fields must be prefixed by the header \"fre.\"** (for example → fre.circ.).\n "
},
"example":"obj.longitude,fre.feret",
"name":"fields",
"in":"query"
},
{
"description":"order_field will order the result using given field. If prefixed with \"-\" then it will be reversed.",
"description":"Order the result using given field. If prefixed with \"-\" then it will be reversed.",
"required":false,
"schema":{
"title":"Order field",
"type":"string",
"description":"order_field will order the result using given field. If prefixed with \"-\" then it will be reversed."
"description":"Order the result using given field. If prefixed with \"-\" then it will be reversed."
},
"example":"obj.longitude",
"name":"order_field",
Expand Down Expand Up @@ -3582,7 +3582,7 @@
"Taxonomy Tree"
],
"summary":"Reclassif Project Stats",
"description":"Dig into reclassification logs and **return the associations source → target for previous reclassifications.**",
"description":"Dig into reclassification logs and **return the associations (source → target) for previous reclassifications.**",
"operationId":"reclassif_project_stats_taxa_reclassification_history__project_id__get",
"parameters":[
{
Expand All @@ -3603,7 +3603,13 @@
"description":"Successful Response",
"content":{
"application/json":{
"schema":{}
"schema":{
"title":"Response Reclassif Project Stats Taxa Reclassification History Project Id Get",
"type":"array",
"items":{
"type":"object"
}
}
}
}
},
Expand Down Expand Up @@ -4221,7 +4227,7 @@
"content":{
"application/json":{
"schema":{
"title":"#TODO JCE Reply Model",
"title":"Reply job question",
"type":"object",
"default":{}
}
Expand Down Expand Up @@ -5649,7 +5655,7 @@
"title":"Source path",
"type":"string",
"description":"Source path on server, to zip or plain directory. \n \n The path can be returned by a file upload (absolute), \n \n otherwise it's relative to shared file area root.",
"example":""
"example":"/import_test.zip"
},
"taxo_mappings":{
"title":"Taxo mappings",
Expand All @@ -5666,12 +5672,14 @@
"skip_loaded_files":{
"title":"Skip loaded files",
"type":"boolean",
"description":"If true skip loaded files, else don't.",
"default":false,
"example":false
},
"skip_existing_objects":{
"title":"Skip existing objects",
"type":"boolean",
"description":"If true skip existing objects, else don't.",
"default":false,
"example":false
},
Expand Down Expand Up @@ -5706,7 +5714,9 @@
},
"description":"Errors from analysis.",
"default":[],
"example":[]
"example":[
"new TSV file(s) are not compliant"
]
}
},
"description":"Import response. "
Expand Down Expand Up @@ -7146,7 +7156,7 @@
"title":"Source path",
"type":"string",
"description":"Source path on server, to zip or plain directory.",
"example":""
"example":"/import_test"
},
"values":{
"title":"Constant values, per field, to write for all images. If a field has no value don't include it.",
Expand Down Expand Up @@ -7202,7 +7212,11 @@
"type":"string"
},
"description":"Validation errors, dry_run or not.",
"example":[]
"example":[
"'abcde' is not a valid value for SimpleImportFields.latitude",
"'456.5' is not a valid value for SimpleImportFields.longitude",
"'very very low' is not a valid value for SimpleImportFields.depthmin"
]
}
},
"description":"Simple Import, response. "
Expand Down
18 changes: 8 additions & 10 deletions py/API_models/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,19 @@

from helpers.pydantic import BaseModel, Field

#TODO JCE - description
class ImportReq(BaseModel):
""" Import request, from UI choices. """
source_path: str = Field(title="Source path", description="Source path on server, to zip or plain directory."
" \n \n The path can be returned by a file upload (absolute),"
" \n \n otherwise it's relative to shared file area root.", example="")
" \n \n otherwise it's relative to shared file area root.", example="/import_test.zip")
taxo_mappings: Dict[str, str] = Field(title="Taxo mappings", description="Optional taxonomy mapping, the key specifies the taxonomy ID found in file and the value specifies the final taxonomy ID to write.", default={}, example={23444 : 76543})
skip_loaded_files: bool = Field(default=False, title ="Skip loaded files", description="", example=False)
skip_existing_objects: bool = Field(default=False, title ="Skip existing objects", description="", example=False)
skip_loaded_files: bool = Field(default=False, title ="Skip loaded files", description="If true skip loaded files, else don't.", example=False)
skip_existing_objects: bool = Field(default=False, title ="Skip existing objects", description="If true skip existing objects, else don't.", example=False)
update_mode: str = Field(title="Update mode", description="Update data ('Yes'), including classification ('Cla').", default="", example="Yes")

class Config:
schema_extra = {"title": "Import request Model"}

#TODO JCE - example
class ImportRsp(BaseModel):
""" Import response. """
job_id: int = Field(title="Job Id", description="The job which was created for the run.", example=1)
Expand All @@ -38,7 +36,7 @@ class ImportRsp(BaseModel):
# default={})
# warnings: List[str] = Field(title="Warnings from analysis",
# default=[])
errors: List[str] = Field(title="Errors", description="Errors from analysis.", default=[], example=[])
errors: List[str] = Field(title="Errors", description="Errors from analysis.", default=[], example=["new TSV file(s) are not compliant"])
# rowcount: int = Field(title="Number of TSV rows, just counted during validation, or loaded", default=0)


Expand Down Expand Up @@ -73,10 +71,9 @@ class SimpleImportFields(str, Enum):
userlb = "userlb"
status = "status"

#TODO JCE - example
class SimpleImportReq(BaseModel):
""" Simple Import request. """
source_path: str = Field(title="Source path", description="Source path on server, to zip or plain directory.", example="")
source_path: str = Field(title="Source path", description="Source path on server, to zip or plain directory.", example="/import_test")
values: Dict[SimpleImportFields, str] = Field(
title="Constant values, per field, to write for all images. If a field has no value don't include it.",
description=":" + ", ".join(SimpleImportFields), example={SimpleImportFields.latitude: 43.69, SimpleImportFields.longitude : 7.30})
Expand All @@ -88,8 +85,9 @@ class SimpleImportReq(BaseModel):
class Config:
schema_extra = {"title": "Simple import request Model"}

#TODO JCE - example
class SimpleImportRsp(BaseModel):
""" Simple Import, response. """
job_id: int = Field(title="Job Id", description="The job which was created for the run. 0 if called with dry_run option.", example=1)
errors: List[str] = Field(title="Errors", description="Validation errors, dry_run or not.", example=[])
errors: List[str] = Field(title="Errors", description="Validation errors, dry_run or not.", example=["'abcde' is not a valid value for SimpleImportFields.latitude",
"'456.5' is not a valid value for SimpleImportFields.longitude",
"'very very low' is not a valid value for SimpleImportFields.depthmin"])
40 changes: 31 additions & 9 deletions py/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from fastapi import FastAPI, Request, Response, status, Depends, HTTPException, UploadFile, File, Query, Form, Body, \
Path
from fastapi import responses
from fastapi.logger import logger as fastapi_logger
from fastapi.responses import StreamingResponse, FileResponse
from fastapi.templating import Jinja2Templates
Expand Down Expand Up @@ -888,16 +889,16 @@ def update_project(project: ProjectModel,
}
}
})
def set_project_predict_settings(settings: str = Query(..., description="The new prediction settings",
def set_project_predict_settings(settings: str = Query(..., description="The new prediction settings.",
example="seltaxo=84963,59996,56545 baseproject=2562,2571"),
project_id: int = Path(..., description="Internal, numeric id of the project.",
example=4223),
current_user: int = Depends(get_current_user)):
"""
**Update the project's prediction settings**, return **NULL upon success.**
Unlike during full project update above, which needs high permissions, this entry point is accessible
to project annotators, as it mirrors the prediction privileges.
🔒 Unlike during full project update above, which needs high permissions, this entry point is accessible
to **project annotators**, as it mirrors the prediction privileges.
"""
with ProjectsService() as sce:
with RightsThrower():
Expand Down Expand Up @@ -1152,10 +1153,31 @@ def get_object_set(project_id: int = Path(..., description="Internal, numeric id
The column obj.imgcount contains the total count of images for the object.
Use a comma to separate fields.
Use a comma to separate fields.
💡 More help :
You can get the field labels by parsing the classiffieldlist returned by a call to https://ecotaxa.obs-vlfr.fr/api/docs#/projects/project_query_projects__project_id__get.
**Note that the following fields must be prefixed with the header "obj."** (for example → obj.orig_id):
acquisid classif_auto_id, classif_auto_score, classif_auto_when, classif_crossvalidation_id, classif_qual, classif_qual,
classif_id, classif_qual, classif_who, classif_when, complement_info, depth_max, depth_min,
latitude, longitude, objdate, object_link, objid, objtime, orig_id, random_value, similarity, sunpos.
**Note that the following fields must be prefixed with the header "img."** (for example → img.file_name):
file_name, height, imgid, imgrank, file_name, orig, objid, file_name thumb_file_name, thumb_height, thumb_width, width.
**Note that the following fields must be prefixed with the header "txo."** (for example → txo.display_name):
creation_datetime, creator_email, display_name, id, id_instance, id_source, lastupdate_datetime,
name, nbrobj, nbrobjcum, parent_id, rename_to source_desc, source_url, taxostatus, taxotype.
**All other fields must be prefixed by the header "fre."** (for example → fre.circ.).
''', default=None, example="obj.longitude,fre.feret"),
order_field: Optional[str] = Query(title="Order field",
description='order_field will order the result using given field. If prefixed with "-" then it will be reversed.',
description='Order the result using given field. If prefixed with "-" then it will be reversed.',
default=None, example="obj.longitude"),
# TODO: order_field should be a user-visible field name, not nXXX, in case of free field
window_start: Optional[int] = Query(default=None, title="Window start",
Expand Down Expand Up @@ -1591,14 +1613,14 @@ async def reclassif_stats(taxa_ids: str = Query(..., title="Taxa ids",
ret = sce.most_used_non_advised(current_user, num_taxa_ids)
return ret


@app.get("/taxa/reclassification_history/{project_id}", tags=['Taxonomy Tree'])
#TODO JCE
@app.get("/taxa/reclassification_history/{project_id}", tags=['Taxonomy Tree'], response_model=List[Dict])
async def reclassif_project_stats(
project_id: int = Path(..., description="Internal, numeric id of the project.", example=1),
current_user: Optional[int] = Depends(get_optional_current_user)) \
-> List[TaxonBO]:
"""
Dig into reclassification logs and **return the associations source → target for previous reclassifications.**
Dig into reclassification logs and **return the associations (source → target) for previous reclassifications.**
"""
with TaxonomyService() as sce:
with RightsThrower():
Expand Down Expand Up @@ -1930,7 +1952,7 @@ def get_job(job_id: int = Path(..., description="Internal, the unique numeric id
})
def reply_job_question(
job_id: int = Path(..., description="Internal, the unique numeric id of this job.", example=47445),
reply: Dict[str, Any] = Body(default={}, title="#TODO JCE Reply Model"),
reply: Dict[str, Any] = Body(default={}, title="Reply job question"),
current_user: int = Depends(get_current_user)) -> None:
"""
**Send answers to last question.** The job resumes after it receives the reply.
Expand Down

0 comments on commit 7ad37e5

Please sign in to comment.