Skip to content

Commit

Permalink
Merge pull request #109 from rstudio/docs-update
Browse files Browse the repository at this point in the history
add examples to docstrings
  • Loading branch information
isabelizimm authored Sep 19, 2022
2 parents c3e1feb + a34fcb4 commit 90cc570
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 20 deletions.
5 changes: 3 additions & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ Monitor

Model Handlers
==================

.. autosummary::
:toctree: reference/
:caption: Monitor
:caption: Model Handlers

~BaseHandler
~handlers.BaseHandler
~SKLearnHandler
~TorchHandler
~StatsmodelsHandler
Expand Down
10 changes: 10 additions & 0 deletions vetiver/pin_read_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True):
VetiverModel to be written to board
versioned: bool
Whether or not the pin should be versioned
Example
-------
>>> import vetiver
>>> from pins import board_temp
>>> model_board = board_temp(versioned = True, allow_pickle_read = True)
>>> X, y = vetiver.get_mock_data()
>>> model = vetiver.get_mock_model().fit(X, y)
>>> v = vetiver.VetiverModel(model = model, model_name = "my_model", ptype_data = X)
>>> vetiver.vetiver_pin_write(model_board, v)
"""
if not board.allow_pickle_read:
raise NotImplementedError # must be pickle-able
Expand Down
22 changes: 21 additions & 1 deletion vetiver/rsconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def deploy_rsconnect(
Parameters
----------
connect_server:
connect_server: rsconnect.api.RSConnectServer
RSConnect Server
board:
Pins board
Expand All @@ -52,6 +52,26 @@ def deploy_rsconnect(
Callback to use to write the log to
image: str
Docker image to be specified for off-host execution
Example
-------
>>> import vetiver
>>> import pins
>>> import rsconnect
>>> board = pins.board_temp(allow_pickle_read=True)
>>> connect_server = rsconnect.api.RSConnectServer(
... url = url,
... api_key = api_key) # doctest: +SKIP
>>> X, y = vetiver.get_mock_data()
>>> model = vetiver.get_mock_model().fit(X, y)
>>> v = vetiver.VetiverModel(model = model,
... model_name = "my_model",
... ptype_data = X)
>>> vetiver.deploy_rsconnect(
... connect_server = connect_server,
... board = board,
... pin_name = "my_model"
... ) # doctest: +SKIP
"""
if not title:
title = pin_name + "_vetiver"
Expand Down
51 changes: 42 additions & 9 deletions vetiver/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,22 @@
class VetiverAPI:
"""Create model aware API
Attributes
Parameters
----------
model : VetiverModel
Model to be deployed in API
check_ptype : bool
Determine if data prototype should be enforced
app_factory :
Type of API to be deployed
app :
API that is deployed
Example
-------
>>> import vetiver
>>> X, y = vetiver.get_mock_data()
>>> model = vetiver.get_mock_model().fit(X, y)
>>> v = vetiver.VetiverModel(model = model, model_name = "my_model", ptype_data = X)
>>> v_api = vetiver.VetiverAPI(model = v, check_ptype = True)
"""

app = None
Expand Down Expand Up @@ -133,7 +139,7 @@ async def rapidoc():
def vetiver_post(
self, endpoint_fx: Callable, endpoint_name: str = "custom_endpoint"
):
"""Create new POST endpoint
"""Create new POST endpoint that is aware of model input data
Parameters
----------
Expand All @@ -142,25 +148,31 @@ def vetiver_post(
endpoint_name : str
Name of endpoint
Returns
Example
-------
dict
Key: endpoint_name Value: Output of endpoint_fx, in list format
>>> import vetiver
>>> X, y = vetiver.get_mock_data()
>>> model = vetiver.get_mock_model().fit(X, y)
>>> v = vetiver.VetiverModel(model = model, model_name = "model", ptype_data = X)
>>> v_api = vetiver.VetiverAPI(model = v, check_ptype = True)
>>> def sum_values(x):
... return x.sum()
>>> v_api.vetiver_post(sum_values, "sums")
"""
if self.check_ptype is True:

@self.app.post("/" + endpoint_name)
async def custom_endpoint(input_data: self.model.ptype):
y = _prepare_data(input_data)
new = endpoint_fx(pd.Series(y))
new = endpoint_fx(pd.DataFrame(y))
return {endpoint_name: new.tolist()}

else:

@self.app.post("/" + endpoint_name)
async def custom_endpoint(input_data: Request):
y = await input_data.json()
new = endpoint_fx(pd.Series(y))
new = endpoint_fx(pd.DataFrame(y))

return {endpoint_name: new.tolist()}

Expand All @@ -174,6 +186,15 @@ def run(self, port: int = 8000, host: str = "127.0.0.1", **kw):
An integer that indicates the server port that should be listened on.
host : str
A valid IPv4 or IPv6 address, which the application will listen on.
Example
-------
>>> import vetiver
>>> X, y = vetiver.get_mock_data()
>>> model = vetiver.get_mock_model().fit(X, y)
>>> v = vetiver.VetiverModel(model = model, model_name = "model", ptype_data = X)
>>> v_api = vetiver.VetiverAPI(model = v, check_ptype = True)
>>> v_api.run() # doctest: +SKIP
"""
_jupyter_nb()
uvicorn.run(self.app, port=port, host=host, **kw)
Expand Down Expand Up @@ -209,6 +230,13 @@ def predict(endpoint, data: Union[dict, pd.DataFrame, pd.Series], **kw):
-------
dict
Endpoint_name and list of endpoint_fx output
Example
-------
>>> import vetiver
>>> X, y = vetiver.get_mock_data()
>>> endpoint = vetiver.vetiver_endpoint(url='http://127.0.0.1:8000/predict')
>>> vetiver.predict(endpoint, X) # doctest: +SKIP
"""
if isinstance(endpoint, testclient.TestClient):
requester = endpoint
Expand Down Expand Up @@ -273,5 +301,10 @@ def vetiver_endpoint(url="http://127.0.0.1:8000/predict"):
-------
url : str
URI path to endpoint
Example
-------
>>> import vetiver
>>> endpoint = vetiver.vetiver_endpoint(url='http://127.0.0.1:8000/predict')
"""
return url
4 changes: 2 additions & 2 deletions vetiver/tests/test_add_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_endpoint_adds_ptype():
data = {"B": 0, "C": 0, "D": 0}
response = client.post("/sum", json=data)
assert response.status_code == 200, response.text
assert response.json() == {"sum": 0}, response.json()
assert response.json() == {"sum": [0]}, response.json()


def test_endpoint_adds_no_ptype():
Expand All @@ -40,4 +40,4 @@ def test_endpoint_adds_no_ptype():
data = [0, 0, 0]
response = client.post("/sum", json=data)
assert response.status_code == 200, response.text
assert response.json() == {"sum": 0}, response.json()
assert response.json() == {"sum": [0]}, response.json()
10 changes: 9 additions & 1 deletion vetiver/vetiver_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class VetiverModel:
----------
model :
A trained model, such as an sklearn or torch model
name : string
model_name : string
Model name or ID
ptype_data : pd.DataFrame, np.array
Sample of data model should expect when it is being served
Expand All @@ -49,6 +49,14 @@ class VetiverModel:
VetiverModel can also take an initialized custom VetiverHandler
as a model, for advanced use cases or non-supported model types.
Example
-------
>>> from vetiver import mock, VetiverModel
>>> X, y = mock.get_mock_data()
>>> model = mock.get_mock_model().fit(X, y)
>>> v = VetiverModel(model = model, model_name = "my_model", ptype_data = X)
>>> v.description
"Scikit-learn <class 'sklearn.dummy.DummyRegressor'> model"
"""

def __init__(
Expand Down
20 changes: 18 additions & 2 deletions vetiver/write_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def write_docker(
):
"""Writes a Dockerfile to run VetiverAPI in a container
Args
----
Parameters
----------
app_file: str
File containing VetiverAPI to be deployed into container
path: str
Expand All @@ -41,6 +41,22 @@ def write_docker(
Host address to run VetiverAPI from Dockerfile
port: str
Port to run VetiverAPI from Dockerfile
Example
-------
>>> import vetiver
>>> import tempfile
>>> import pins
>>> tmp = tempfile.TemporaryDirectory()
>>> board = pins.board_temp(allow_pickle_read=True)
>>> X, y = vetiver.get_mock_data()
>>> model = vetiver.get_mock_model().fit(X, y)
>>> v = vetiver.VetiverModel(model = model, model_name = "my_model", ptype_data = X)
>>> vetiver.vetiver_pin_write(board, v)
>>> vetiver.write_app(board,
... "my_model",
... file = tmp.name + "/app.py") # need file for model
>>> vetiver.write_docker(app_file = "app.py", path = tmp.name)
"""
py_version = str(sys.version_info.major) + "." + str(sys.version_info.minor)

Expand Down
21 changes: 18 additions & 3 deletions vetiver/write_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,31 @@ def write_app(
):
"""Write VetiverAPI app to a file
Args
----
board : pinse.BaseBoard
Parameters
----------
board :
API to be written
pin_name : string
Name of pin containing VetiverModel
version :
Pins version of VetiverModel
file :
Name of file
Example
-------
>>> import vetiver
>>> import tempfile
>>> import pins
>>> tmp = tempfile.TemporaryDirectory()
>>> board = pins.board_temp(allow_pickle_read=True)
>>> X, y = vetiver.get_mock_data()
>>> model = vetiver.get_mock_model().fit(X, y)
>>> v = vetiver.VetiverModel(model = model, model_name = "my_model", ptype_data = X)
>>> vetiver.vetiver_pin_write(board, v)
>>> vetiver.write_app(board,
... "my_model",
... file = tmp.name + "/app.py")
"""

if board.versioned:
Expand Down

0 comments on commit 90cc570

Please sign in to comment.