Skip to content

Commit 949e349

Browse files
authored
docs: add common pitfalls section to deploying custom code (#228)
1 parent 2f01464 commit 949e349

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

docs/custom_code.qmd

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
In some cases, you may need to create and deploy custom code as part of your MLOps workflow using vetiver. This could be necessary when you need to:
44

5-
- deploy custom models in vetiver
6-
- deploy unsupported models in vetiver
7-
- include custom code in vetiver
8-
- deploy a vetiver model with a custom pipeline
5+
- deploy custom models in vetiver
6+
- deploy unsupported models in vetiver
7+
- include custom code in vetiver
8+
- deploy a vetiver model with a custom pipeline
99

10-
You may also have custom code in a known framework, such as a column transformer for a scikit-learn model.
10+
You may also have custom code in a known framework, such as a column transformer for a scikit-learn model.
1111

1212
In these cases, extra steps will be required to successfully create and deploy a `VetiverModel` object.
1313

@@ -17,12 +17,12 @@ Vetiver supports basic [scikit-learn](https://scikit-learn.org/), [torch](https:
1717

1818
To create a model handler, you should create a subclass of vetiver's `BaseHandler` class. This handler should include the following:
1919

20-
- `model_type`: A static method that declares the type of your model.
21-
- `handler_predict()`: A method that defines how predictions should be made for your model. This method is used at the /predict endpoint in the VetiverAPI.
20+
- `model_type`: A static method that declares the type of your model.
21+
- `handler_predict()`: A method that defines how predictions should be made for your model. This method is used at the /predict endpoint in the VetiverAPI.
2222

2323
Here's an example of a handler for a model of `newmodeltype` type. Once you have defined your handler, you can initialize it with your model and pass it to the `VetiverModel` class.
2424

25-
```python
25+
``` python
2626
from vetiver.handlers.base import BaseHandler
2727

2828
class CustomHandler(BaseHandler):
@@ -60,7 +60,7 @@ To deploy custom code, you need to include the necessary source code in your dep
6060

6161
If your `VetiverModel` includes custom source code, you need to include that code in your deployment files to build an API in another location. The example below shows a user-created `FeatureSelector`, which is part of a scikit-learn pipeline.
6262

63-
```{.python filename="model.py"}
63+
``` {.python filename="model.py"}
6464
from sklearn.base import BaseEstimator, TransformerMixin
6565
from sklearn.tree import DecisionTreeClassifier
6666
from sklearn.pipeline import Pipeline
@@ -94,18 +94,18 @@ board = pins.board_connect(allow_pickle_read=True)
9494
vetiver_pin_write(board, v)
9595
```
9696

97-
::: {.panel-tabset}
97+
::: panel-tabset
9898
## Docker
9999

100100
To generate files needed to start a Docker container, you can use the command `vetiver.prepare_docker`.
101101

102-
```{.python}
102+
``` python
103103
vetiver.prepare_docker(board, "selected_decision_tree")
104104
```
105105

106106
When you run this line, 3 files are generated: a Dockerfile, an `app.py` file, and a `vetiver_requirements.txt`. In the `app.py` file, you'll need to add an import statement that is formatted `from {name of file, excluding .py, that has custom element} import {name of custom element}`.
107107

108-
```{.python filename="app.py"}
108+
``` {.python filename="app.py"}
109109
from vetiver import VetiverModel
110110
import vetiver
111111
import pins
@@ -121,7 +121,7 @@ api = vetiver_api.app
121121

122122
Add a line to your Dockerfile to copy your source file(s) into your Docker container. The format will be `COPY path/to/your/filename.py /vetiver/app/filename.py`, where the destination is always in the `/vetiver/app/` directory.
123123

124-
```{.bash filename="Dockerfile"}
124+
``` {.bash filename="Dockerfile"}
125125
# # Generated by the vetiver package; edit with care
126126
# start with python base image
127127
FROM python:3.10
@@ -152,13 +152,13 @@ CMD ["uvicorn", "app.app:api", "--host", "0.0.0.0", "--port", "8080"]
152152

153153
To deploy custom code to Posit Connect, you'll first start with the command `vetiver.write_app`.
154154

155-
```{.python}
155+
``` python
156156
vetiver.write_app(board, 'selected_decision_tree')
157157
```
158158

159159
This will generate an `app.py` file, where you'll need to add an import statement that is formatted `from {name of file, excluding .py, that has custom element} import {name of custom element}`.
160160

161-
```{.python filename=="app.py"}
161+
``` {.python filename="=\"app.py\""}
162162
from vetiver import VetiverModel
163163
import vetiver
164164
import pins
@@ -174,7 +174,7 @@ api = vetiver_api.app
174174

175175
After editing the `app.py` file, you can deploy it to Posit Connect using the `rsconnect` package. Use the `rsconnect.api.actions.deploy_python_fastapi()` function to deploy the API, specifying the Connect server URL, API key, directory containing the `app.py` and `model.py` files, and the entry point of the API.
176176

177-
```{.python}
177+
``` python
178178
from rsconnect.api.actions import deploy_python_fastapi
179179
import rsconnect
180180

@@ -191,9 +191,15 @@ rsconnect.actions.deploy_python_fastapi(
191191
directory = "./", # path to the directory containing the app.py and model.py files
192192
entry_point = "app:api" # the API is the app.py file, in a variable named api
193193
)
194-
195194
```
196-
197195
:::
198196

197+
## Common Pitfalls
198+
199+
When deploying custom code, the most common error is something similar to `AttributeError: Can't get attribute 'ExampleModel' on <module '__main__' (built-in)>`. There are a few possible causes for this error:
200+
201+
1. The original `ExampleModel` may have been pinned from inside a Jupyter Notebook. Because pickling only saves a reference for how to read a class, not the source code, a custom model transformer pinned from a Jupyter Notebook cannot be imported and resolved later. To fix this, repin your model/transformer from inside a Python script.
202+
203+
2. You may not be uploading the custom code to be used later. When deploying, you'll want to add the files containing your custom code to the `extra_files` argument so that it can be imported, eg, `vetiver.deploy_rsconnect(connect_server, board, model_name, extra_files=['custom_model.py', 'requirements.txt'])` .
204+
199205
Please note that the above steps are a general guide, and you may need to adapt them to your specific use case and deployment environment. If you have any questions, please consider [opening an issue](https://github.com/rstudio/vetiver-python/issues/new).

0 commit comments

Comments
 (0)