rstudio / rstudio/vetiver-python
bug: `predict()` sends request body as raw string, breaks with `pydantic>=2`
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 71
- Forks
- 20
- PR merge metrics
- No merged PRs in 30d
Description
Describe the bug
The predict() function in vetiver/server.py sends DataFrame data using requests.post(endpoint, data=...), which transmits the JSON as a raw byte string without setting Content-Type: application/json.
On the server side, the /predict endpoint declares its input as List[Model], relying on FastAPI + Pydantic to parse the body. Pydantic v1 was lenient enough to coerce the raw bytes into the expected type, but pydantic v2 strictly rejects it with a 422:
"Input should be a valid list".
data= sends the body as raw bytes. It should use json= (or set the content type to application/json) so that FastAPI correctly parses the body before handing it to pydantic for validation.
pydantic: 2.12.5
vetiver: 0.2.6
To Reproduce
import vetiver
from fastapi.testclient import TestClient
X, y = vetiver.mock.get_mock_data()
model = vetiver.mock.get_mock_model().fit(X, y)
v = vetiver.VetiverModel(model=model, model_name="model", prototype_data=X)
app = vetiver.VetiverAPI(v).app
client = TestClient(app)
response = vetiver.predict(
"http://testserver/predict", X, test_client=client
)
Traceback (most recent call last):
File "vetiver/server.py", line 379, in predict
response.raise_for_status()
File "httpx/_models.py", line 829, in raise_for_status
raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '422 Unprocessable Entity' for url 'http://testserver/predict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "demo.py", line 11, in <module>
response = vetiver.predict(
"http://testserver/predict", X, test_client=client
)
File "vetiver/server.py", line 382, in predict
raise TypeError(re.sub(r"\n", ": ", response.text))
TypeError: 1 validation error:: {'type': 'list_type', 'loc': ('body',), 'msg': 'Input should be a valid list', 'input':
b'[{"B":54,"C":48,"D":68},...]'}: : File "vetiver/server.py", line 238, in custom_endpoint: POST /predict
Expected behavior
vetiver.predict() should return a DataFrame of predictions. With pydantic<2 installed, it does
Additional context
Add any other context about the problem here.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in vetiver/server.py at predict() and inspect how the request body is sent to the /predict endpoint. Reproduce the failure with the provided FastAPI TestClient example under pydantic 2, then verify that predict() returns a DataFrame of predictions without a 422 response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- fastapi, python
- Domain
- api
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 62/100