Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add examples to docstrings #109

Merged
merged 2 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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