Skip to content

Commit cdcce18

Browse files
ignacioalvarolopez
authored andcommitted
Improve documentation
1 parent cf1a706 commit cdcce18

File tree

3 files changed

+141
-77
lines changed

3 files changed

+141
-77
lines changed

deepaas/model/v2/base.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class in order to expose the model functionality, but the entrypoint that
2828
is configured should expose the same API.
2929
"""
3030

31-
# FIXME(aloga): document this
3231
schema = None
3332
"""Must contain a valid schema for the model's predictions or None.
3433
@@ -47,7 +46,7 @@ class in order to expose the model functionality, but the entrypoint that
4746
"predictions": "<model response as string>"
4847
}
4948
50-
As previosly stated, there are two ways of defining an schema here. If our
49+
As previously stated, there are two ways of defining an schema here. If our
5150
response have the following form::
5251
5352
{
@@ -67,7 +66,7 @@ class in order to expose the model functionality, but the entrypoint that
6766
We should define or schema as schema as follows:
6867
6968
70-
- Using a schema dictionary. This is the most straightforwad way. In order
69+
- Using a schema dictionary. This is the most straightforward way. In order
7170
to do so, you must use the ``marshmallow`` Python module, as follows::
7271
7372
from marshmallow import fields
@@ -113,14 +112,14 @@ def get_metadata(self):
113112
114113
The metadata that is expected should follow the schema that is shown
115114
below. This basically means that you should return a dictionary with
116-
the folling aspect::
115+
the following aspect::
117116
118117
{
119-
'author': 'Author name',
120-
'description': 'Model description',
121-
'license': 'Model's license',
122-
'url': 'URL for the model (e.g. GitHub repository)',
123-
'version': 'Model version',
118+
"author": "Author name",
119+
"description": "Model description",
120+
"license": "Model's license",
121+
"url": "URL for the model (e.g. GitHub repository)",
122+
"version": "Model version",
124123
}
125124
126125
The only fields that are mandatory are 'description' and 'name'.
@@ -172,8 +171,9 @@ def predict(self, **kwargs):
172171
def get_predict_args(self):
173172
"""Return the arguments that are needed to perform a prediction.
174173
175-
This function should return a dictionary of ``webargs`` fields. For
176-
example::
174+
This function should return a dictionary of ``webargs`` fields (check
175+
`here <https://marshmallow.readthedocs.io/en/latest/api_reference.html#module-marshmallow.fields>`_
176+
for a full reference of the available options). For example::
177177
178178
from webargs import fields
179179
@@ -182,14 +182,15 @@ def get_predict_args(self):
182182
def get_predict_args():
183183
return {
184184
"arg1": fields.Str(
185-
required=False,
186-
default="foo",
187-
description="Argument one"
185+
required=False, # force the user to define the value
186+
missing="foo", # default value to use
187+
enum=["choice1", "choice2"], # list of choices
188+
description="Argument one" # help string
188189
),
189190
}
190191
191192
:return dict: A dictionary of ``webargs`` fields containing the
192-
applicationr required arguments.
193+
application required arguments.
193194
"""
194195
raise NotImplementedError()
195196

@@ -210,8 +211,9 @@ def train(self, **kwargs):
210211
def get_train_args(self):
211212
"""Return the arguments that are needed to train the application.
212213
213-
This function should return a dictionary of ``webargs`` fields. For
214-
example::
214+
This function should return a dictionary of ``webargs`` fields (check
215+
`here <https://marshmallow.readthedocs.io/en/latest/api_reference.html#module-marshmallow.fields>`_
216+
for a full reference of the available options). For example::
215217
216218
from webargs import fields
217219
@@ -220,9 +222,10 @@ def get_train_args(self):
220222
def get_train_args():
221223
return {
222224
"arg1": fields.Str(
223-
required=False,
224-
default="foo",
225-
description="Argument one"
225+
required=False, # force the user to define the value
226+
missing="foo", # default value to use
227+
enum=["choice1", "choice2"], # list of choices
228+
description="Argument one" # help string
226229
),
227230
}
228231

doc/source/install/upgrade.rst

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,67 +6,69 @@ Upgrade notes
66
Upgrading to version 1.0.0
77
--------------------------
88

9-
The release ``1.0.0`` of the DEEPaaS API implementes several backwards
9+
The release ``1.0.0`` of the DEEPaaS API implements several backwards
1010
incompatible changes when compared with the previous releases in the ``0.X.X``
1111
series. Before upgrading your code and deploying into production, read the
1212
following, as changes are needed in your model. Please go through the following
1313
checklist in order.
1414

15-
* Migrate new namespace entry point .
15+
* **Migrate new namespace entry point.**
1616

1717
Previous code relied on a top-level entry point named ``deepaas.model``,
1818
where we searched for the required functions or methods to be invoked for
1919
each API action.
2020

2121
Now the namespace has changed to ``deepaas.v2.model``.
2222

23-
Therefore, assumming that your code for V1 of the API was under the
23+
Therefore, assuming that your code for V1 of the API was under the
2424
``my_model.api`` and you defined your the entry point as follows:
2525

26-
.. code-block:: ini
26+
.. code-block:: ini
2727
28-
[entry_points]
28+
[entry_points]
2929
30-
deepaas.model =
31-
my_model = my_model.api
30+
deepaas.model =
31+
my_model = my_model.api
3232
33-
You should migrate to the following:
33+
You should migrate to the following:
3434

35-
.. code-block:: ini
35+
.. code-block:: ini
3636
3737
[entry_points]
3838
3939
deepaas.v2.model =
4040
my_model = my_model.api
4141
42-
.. note::
43-
If you do not change the namespace, we will try to load the old
44-
entrypoint. However, this is deprecated and you should upgrade as soon as
45-
possible.
42+
.. note::
43+
If you do not change the namespace, we will try to load the old
44+
entrypoint. However, this is deprecated and you should upgrade as soon as
45+
possible.
4646

47-
* Migrate from returning dictionaries to use an argument parser to define
48-
train and predict arguments.
47+
* **Migrate from returning dictionaries to use an argument parser to define
48+
train and predict arguments.**
4949

50-
Previous code relied on returing arbitrary dictionaries that were used to
50+
Previous code relied on returning arbitrary dictionaries that were used to
5151
generate the arguments for each of the API endpoints. This is not anymore
52-
supported and you should return a ``webargs`` field dictioary. This is still
53-
done by defining the ``get_predict_args`` and ``fet_train_args`` functions.
52+
supported and you should return a ``webargs`` field dictionary (check
53+
`here <https://marshmallow.readthedocs.io/en/latest/api_reference.html#module-marshmallow.fields>`_
54+
for a full reference of the available options). This is still
55+
done by defining the ``get_predict_args`` and ``get_train_args`` functions.
5456
These functions must receive no arguments and they should return a dictionary
5557
as follows::
5658

57-
from webargs import fields
58-
59-
(...)
59+
from webargs import fields
6060

61-
def get_predict_args():
62-
return {
63-
"arg1": fields.Str(
64-
required=False,
65-
default="foo",
66-
description="Argument one"
67-
),
68-
}
61+
(...)
6962

63+
def get_predict_args():
64+
return {
65+
"arg1": fields.Str(
66+
required=False, # force the user to define the value
67+
missing="foo", # default value to use
68+
enum=["choice1", "choice2"], # list of choices
69+
description="Argument one" # help string
70+
),
71+
}
7072

7173
.. note::
7274
If you do still follow the old way of returning the arguments we will try
@@ -75,34 +77,83 @@ checklist in order.
7577
soon as possible. All the arguments will be converted to Strings,
7678
therefore you will loose any type checking, etc.
7779

78-
* Explictly define your input arguments. The previous version of the API
80+
* **Explicitly define your input arguments.**
81+
82+
The previous version of the API
7983
defined two arguments for inference: ``data`` and ``urls``. This is not
80-
anymore true, and you must define your own input arguments as follows::
84+
anymore true, and you must define your own input arguments.
85+
To replicate the response of v1 you have to define::
8186

8287
from webargs import fields
8388

8489
(...)
8590

8691
def get_predict_args():
8792
return {
88-
"data": fields.Field(
89-
required=True,
90-
type="file",
91-
location="form",
92-
),
93-
}
94-
95-
Then, you will get your input data in the ``data`` keyword argument in your
93+
'files': fields.Field(
94+
required=False,
95+
missing=None,
96+
type="file",
97+
data_key="data",
98+
location="form",
99+
description="Select the image you want to classify."),
100+
101+
'urls': fields.Url(
102+
required=False,
103+
missing=None,
104+
description="Select an URL of the image you want to classify.")
105+
}
106+
107+
Then, you will get your input data in the ``data`` and ``urls`` keyword arguments in your
96108
application.
97109

98-
* Define your responses for the prediction. Now, unless you explicitly define
99-
your application response schema, whatever you return will be converted into
100-
a string and wrapped in the following response::
110+
.. note::
111+
For the moment, in contrast with v1, only one url field at the same time is enabled,
112+
although multi-url (along with multi-files) support is coming soon.
113+
114+
* **Define your responses for the prediction.**
115+
116+
Now, unless you explicitly define your application response schema,
117+
whatever you return will be converted into a string and wrapped in the following response::
101118

102119
{
103120
"status": "OK",
104121
"predictions": "<model response as string>"
105122
}
106123

107-
* Arguments and now passed as unpacked keyword arguments, not anymore as a
108-
dictionary.
124+
* **Change in the ``predict`` function name.**
125+
126+
The ``predict_url`` and ``predict_data`` functions have been merged into a single ``predict``
127+
function. In addition, arguments are now passed as unpacked keyword arguments, not anymore as a
128+
dictionary. So if you want to upgrade to v2 with minimal code changes, you just have to add
129+
the following function to your .py file::
130+
131+
def predict(**args):
132+
133+
if (not any([args['urls'], args['files']]) or
134+
all([args['urls'], args['files']])):
135+
raise Exception("You must provide either 'url' or 'data' in the payload")
136+
137+
if args['files']:
138+
args['files'] = [args['files']] # patch until list is available
139+
return predict_data(args)
140+
elif args['urls']:
141+
args['urls'] = [args['urls']] # patch until list is available
142+
return predict_url(args)
143+
144+
* **Changes in the data response**
145+
146+
The return object in ``args['files']`` is no longer a ``werkzeug.FileStorage`` but an
147+
``aiohttp.web_request.FileField``.
148+
149+
The main difference is that now you should read the bytes using ``f.file.read()``
150+
instead of ``f.read()``. Additional changes might be needed if you were also
151+
using file information like content-type.
152+
153+
* **Catch error function**
154+
155+
The ``catch_error`` decorator around function is no longer needed.
156+
157+
* **API url**
158+
159+
Now the API functions are accessed under http://api_url/docs (eg. http://0.0.0.0:5000/docs)

0 commit comments

Comments
 (0)