From 6d0e199affcc070c1fe760fa91eb5cb5fde9d982 Mon Sep 17 00:00:00 2001 From: Isabel Zimmerman <54685329+isabelizimm@users.noreply.github.com> Date: Mon, 25 Mar 2024 18:29:57 -0400 Subject: [PATCH] refactor tests (#209) * refactor tests * parameterize ptype tests --- vetiver/data/__init__.py | 32 ++--- vetiver/server.py | 7 +- vetiver/tests/__init__.py | 0 vetiver/tests/conftest.py | 30 +++++ vetiver/tests/test_add_endpoint.py | 73 +++-------- vetiver/tests/test_build_api.py | 30 ----- vetiver/tests/test_build_vetiver_model.py | 140 +++++++++------------- vetiver/tests/test_no_handler.py | 16 --- vetiver/tests/test_pin_write.py | 8 +- vetiver/tests/test_pytorch.py | 49 +++----- vetiver/tests/test_sklearn.py | 54 ++------- vetiver/tests/test_spacy.py | 41 ++----- vetiver/tests/test_statsmodels.py | 38 ++---- vetiver/tests/test_xgboost.py | 47 +++----- 14 files changed, 186 insertions(+), 379 deletions(-) create mode 100644 vetiver/tests/__init__.py create mode 100644 vetiver/tests/conftest.py delete mode 100644 vetiver/tests/test_build_api.py delete mode 100644 vetiver/tests/test_no_handler.py diff --git a/vetiver/data/__init__.py b/vetiver/data/__init__.py index 7177ee52..6e4bfd32 100644 --- a/vetiver/data/__init__.py +++ b/vetiver/data/__init__.py @@ -1,22 +1,24 @@ -from importlib_resources import files as _files - -sources = { - "mtcars": _files("vetiver") / "data/mtcars.csv", - "chicago": _files("vetiver") / "data/chicago.csv", - "sacramento": _files("vetiver") / "data/sacramento.csv", -} +__all__ = [ + "mtcars", + "chicago", + "sacramento", +] def __dir__(): - return list(sources) + return __all__ -def __getattr__(k): +def _load_data_csv(name): import pandas as pd + import pkg_resources + + fname = pkg_resources.resource_filename("vetiver.data", f"{name}.csv") + return pd.read_csv(fname) + + +def __getattr__(name): + if name not in __all__: + raise AttributeError(f"No dataset named: {name}") - f_path = sources.get("mtcars") - if k == "chicago": - f_path = sources.get("chicago") - elif k == "sacramento": - f_path = sources.get("sacramento") - return pd.read_csv(f_path) + return _load_data_csv(name) diff --git a/vetiver/server.py b/vetiver/server.py index c5069f0a..950d3672 100644 --- a/vetiver/server.py +++ b/vetiver/server.py @@ -5,7 +5,7 @@ import uvicorn import logging import pandas as pd -from fastapi import FastAPI, Request, testclient +from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError from fastapi.openapi.utils import get_openapi from fastapi.responses import HTMLResponse, RedirectResponse, PlainTextResponse @@ -321,9 +321,8 @@ def predict(endpoint, data: Union[dict, pd.DataFrame, pd.Series], **kw) -> pd.Da >>> 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 - endpoint = requester.app.root_path + if "test_client" in kw: + requester = kw.pop("test_client") else: requester = requests diff --git a/vetiver/tests/__init__.py b/vetiver/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vetiver/tests/conftest.py b/vetiver/tests/conftest.py new file mode 100644 index 00000000..713e5ed1 --- /dev/null +++ b/vetiver/tests/conftest.py @@ -0,0 +1,30 @@ +import pytest +from vetiver import VetiverModel, VetiverAPI +from vetiver.helpers import api_data_to_frame +from starlette.testclient import TestClient + + +def sum_values(x): + return x.sum().to_list() + + +def sum_values_no_prototype(x): + return api_data_to_frame(x).sum().to_list() + + +@pytest.fixture +def client(model: VetiverModel) -> TestClient: + app = VetiverAPI(model, check_prototype=True) + app.vetiver_post(sum_values, "sum") + client = TestClient(app.app) + + return client + + +@pytest.fixture +def client_no_prototype(model: VetiverModel) -> TestClient: + app = VetiverAPI(model, check_prototype=False) + app.vetiver_post(sum_values_no_prototype, "sum") + client = TestClient(app.app) + + return client diff --git a/vetiver/tests/test_add_endpoint.py b/vetiver/tests/test_add_endpoint.py index 645cc2e2..5a5f1a21 100644 --- a/vetiver/tests/test_add_endpoint.py +++ b/vetiver/tests/test_add_endpoint.py @@ -1,75 +1,32 @@ import pytest - -import numpy as np import pandas as pd -from fastapi.testclient import TestClient - -from vetiver import mock, VetiverModel, VetiverAPI -from vetiver.helpers import api_data_to_frame -import vetiver +from vetiver import mock, VetiverModel -@pytest.fixture -def vetiver_model(): - np.random.seed(500) +@pytest.fixture() +def model(): X, y = mock.get_mock_data() - model = mock.get_mock_model().fit(X, y) - v = VetiverModel( - model=model, - prototype_data=X, - model_name="my_model", - versioned=None, - description="A regression model for testing purposes", - ) - - return v - - -def sum_values(x): - return x.sum().to_list() - - -def sum_values_no_prototype(x): - return api_data_to_frame(x).sum().to_list() - + model = mock.get_mock_model() -@pytest.fixture -def vetiver_client(vetiver_model): # With check_prototype=True - - app = VetiverAPI(vetiver_model, check_prototype=True) - app.vetiver_post(sum_values, "sum") - - app.app.root_path = "/sum" - client = TestClient(app.app) - - return client + return VetiverModel(model.fit(X, y), "model", prototype_data=X) @pytest.fixture -def vetiver_client_check_ptype_false(vetiver_model): # With check_prototype=False - - app = VetiverAPI(vetiver_model, check_prototype=False) - app.vetiver_post(sum_values_no_prototype, "sum") +def data() -> pd.DataFrame: + return pd.DataFrame({"B": [1, 1, 1], "C": [2, 2, 2], "D": [3, 3, 3]}) - app.app.root_path = "/sum" - client = TestClient(app.app) - return client - - -def test_endpoint_adds_ptype(vetiver_client): - - data = pd.DataFrame({"B": [1, 1, 1], "C": [2, 2, 2], "D": [3, 3, 3]}) - response = vetiver.predict(endpoint=vetiver_client, data=data) +def test_endpoint_adds(client, data): + response = client.post("/sum/", data=data.to_json(orient="records")) - assert isinstance(response, pd.DataFrame) - assert response.to_json() == '{"sum":{"0":3,"1":6,"2":9}}', response.to_json() + assert response.status_code == 200 + assert response.json() == {"sum": [3, 6, 9]} -def test_endpoint_adds_no_ptype(vetiver_client_check_ptype_false): +def test_endpoint_adds_no_prototype(client_no_prototype, data): data = pd.DataFrame({"B": [1, 1, 1], "C": [2, 2, 2], "D": [3, 3, 3]}) - response = vetiver.predict(endpoint=vetiver_client_check_ptype_false, data=data) + response = client_no_prototype.post("/sum/", data=data.to_json(orient="records")) - assert isinstance(response, pd.DataFrame) - assert response.to_json() == '{"sum":{"0":3,"1":6,"2":9}}', response.to_json() + assert response.status_code == 200 + assert response.json() == {"sum": [3, 6, 9]} diff --git a/vetiver/tests/test_build_api.py b/vetiver/tests/test_build_api.py deleted file mode 100644 index fd18a2de..00000000 --- a/vetiver/tests/test_build_api.py +++ /dev/null @@ -1,30 +0,0 @@ -from vetiver import mock, VetiverModel, VetiverAPI -from fastapi import FastAPI - - -def _build_v(): - X, y = mock.get_mock_data() - model = mock.get_mock_model().fit(X, y) - v = VetiverModel( - model=model, - prototype_data=X, - model_name="my_model", - versioned=None, - description="A regression model for testing purposes", - ) - - return v - - -def test_is_fastapi(): - - v = _build_v() - app = VetiverAPI(v) - assert isinstance(app.app, FastAPI) - - -def test_is_v_model(): - - v = _build_v() - app = VetiverAPI(v) - assert isinstance(app.model, VetiverModel) diff --git a/vetiver/tests/test_build_vetiver_model.py b/vetiver/tests/test_build_vetiver_model.py index e87a64d8..080a77e6 100644 --- a/vetiver/tests/test_build_vetiver_model.py +++ b/vetiver/tests/test_build_vetiver_model.py @@ -1,9 +1,16 @@ import sklearn import sys - -import vetiver as vt -from vetiver.meta import VetiverMeta -from vetiver.mock import get_mock_data, get_mock_model +import pytest + +import vetiver +from vetiver import ( + VetiverModel, + mock, + InvalidModelError, + get_mock_data, + get_mock_model, + vetiver_pin_write, +) import pandas as pd import pydantic @@ -18,6 +25,7 @@ model = get_mock_model().fit(X_df, y) +# --- test prototypes --- class MockPrototype(pydantic.BaseModel): B: int C: int @@ -25,7 +33,7 @@ class MockPrototype(pydantic.BaseModel): def test_vetiver_model_array_prototype(): - vt1 = vt.VetiverModel( + v = VetiverModel( model=model, prototype_data=X_array, model_name="model", @@ -34,99 +42,49 @@ def test_vetiver_model_array_prototype(): metadata=None, ) - assert vt1.model == model - assert issubclass(vt1.prototype, vt.Prototype) + assert v.model == model + assert issubclass(v.prototype, vetiver.Prototype) # change to model_construct for pydantic v3 - assert isinstance(vt1.prototype.construct(), pydantic.BaseModel) - assert vt1.prototype.construct().__dict__ == {"0": 96, "1": 11, "2": 33} + assert isinstance(v.prototype.construct(), pydantic.BaseModel) + assert v.prototype.construct().__dict__ == {"0": 96, "1": 11, "2": 33} -def test_vetiver_model_df_prototype(): - vt2 = vt.VetiverModel( +@pytest.mark.parametrize("prototype_data", [{"B": 96, "C": 0, "D": 0}, X_df]) +def test_vetiver_model_dict_like_prototype(prototype_data): + v = VetiverModel( model=model, - prototype_data=X_df, + prototype_data=prototype_data, model_name="model", versioned=None, description=None, metadata=None, ) - assert vt2.model == model + assert v.model == model # change to model_construct for pydantic v3 - assert isinstance(vt2.prototype.construct(), pydantic.BaseModel) - assert vt2.prototype.construct().B == 96 + assert isinstance(v.prototype.construct(), pydantic.BaseModel) + assert v.prototype.construct().B == 96 -def test_vetiver_model_dict_prototype(): - dict_data = {"B": 0, "C": 0, "D": 0} - vt3 = vt.VetiverModel( +@pytest.mark.parametrize("prototype_data", [MockPrototype(B=4, C=0, D=0), None]) +def test_vetiver_model_prototypes(prototype_data): + v = VetiverModel( model=model, - prototype_data=dict_data, + prototype_data=prototype_data, model_name="model", versioned=None, description=None, metadata=None, ) - assert vt3.model == model - # change to model_construct for pydantic v3 - assert isinstance(vt3.prototype.construct(), pydantic.BaseModel) - assert vt3.prototype.construct().B == 0 - - -def test_vetiver_model_basemodel_prototype(): - - m = MockPrototype(B=4, C=0, D=0) - vt4 = vt.VetiverModel( - model=model, - prototype_data=m, - model_name="model", - versioned=False, - description=None, - ) - - assert vt4.model == model - assert vt4.prototype is m - - -def test_vetiver_model_no_prototype(): - vt4 = vt.VetiverModel( - model=model, - prototype_data=None, - model_name="model", - versioned=None, - description=None, - metadata=None, - ) - - assert vt4.model == model - assert vt4.prototype is None - - -def test_vetiver_model_use_ptype(): - vt5 = vt.VetiverModel( - model=model, - prototype_data=None, - model_name="model", - versioned=None, - description=None, - metadata={"test": 123}, - ) - - assert vt5.model == model - assert vt5.prototype is None - assert vt5.metadata == VetiverMeta( - user={"test": 123}, - version=None, - url=None, - required_pkgs=["scikit-learn"], - python_version=tuple(sys.version_info), - ) + assert v.model == model + assert v.prototype is prototype_data +# --- test from pins --- def test_vetiver_model_from_pin(): - v = vt.VetiverModel( + v = VetiverModel( model=model, prototype_data=X_df, model_name="model", @@ -136,10 +94,10 @@ def test_vetiver_model_from_pin(): ) board = pins.board_temp(allow_pickle_read=True) - vt.vetiver_pin_write(board=board, model=v) - v2 = vt.VetiverModel.from_pin(board, "model") + vetiver_pin_write(board=board, model=v) + v2 = VetiverModel.from_pin(board, "model") - assert isinstance(v2, vt.VetiverModel) + assert isinstance(v2, VetiverModel) assert isinstance(v2.model, sklearn.base.BaseEstimator) # change to model_construct for pydantic v3 assert isinstance(v2.prototype.construct(), pydantic.BaseModel) @@ -162,7 +120,7 @@ def test_vetiver_model_from_pin_user_metadata(): } loaded_pkgs = custom_meta["required_pkgs"] + ["scikit-learn"] - v = vt.VetiverModel( + v = VetiverModel( model=model, prototype_data=X_df, model_name="model", @@ -172,10 +130,10 @@ def test_vetiver_model_from_pin_user_metadata(): ) board = pins.board_temp(allow_pickle_read=True) - vt.vetiver_pin_write(board=board, model=v) - v2 = vt.VetiverModel.from_pin(board, "model") + vetiver_pin_write(board=board, model=v) + v2 = VetiverModel.from_pin(board, "model") - assert isinstance(v2, vt.VetiverModel) + assert isinstance(v2, VetiverModel) assert isinstance(v2.model, sklearn.base.BaseEstimator) # change to model_construct for pydantic v3 assert isinstance(v2.prototype.construct(), pydantic.BaseModel) @@ -196,7 +154,7 @@ def test_vetiver_model_from_pin_no_version(): "python_version": None, } - v = vt.VetiverModel( + v = VetiverModel( model=model, prototype_data=X_df, model_name="model", @@ -204,10 +162,24 @@ def test_vetiver_model_from_pin_no_version(): ) board = pins.board_temp(allow_pickle_read=True) - vt.vetiver_pin_write(board=board, model=v) - v2 = vt.VetiverModel.from_pin(board, "model") + vetiver_pin_write(board=board, model=v) + v2 = VetiverModel.from_pin(board, "model") assert v2.metadata.required_pkgs == ["scikit-learn"] assert v2.metadata.python_version is None board.pin_delete("model") + + +# --- test handlers +def test_no_model_handler_found(): + X, y = mock.get_mock_data() + + with pytest.raises(InvalidModelError): + VetiverModel( + model=y, + prototype_data=X, + model_name="my_model", + versioned=None, + description="A regression model for testing purposes", + ) diff --git a/vetiver/tests/test_no_handler.py b/vetiver/tests/test_no_handler.py deleted file mode 100644 index bb01352c..00000000 --- a/vetiver/tests/test_no_handler.py +++ /dev/null @@ -1,16 +0,0 @@ -import pytest -from vetiver import VetiverModel, mock -from vetiver import InvalidModelError - - -def test_not_implemented_error(): - X, y = mock.get_mock_data() - - with pytest.raises(InvalidModelError): - VetiverModel( - model=y, - prototype_data=X, - model_name="my_model", - versioned=None, - description="A regression model for testing purposes", - ) diff --git a/vetiver/tests/test_pin_write.py b/vetiver/tests/test_pin_write.py index 8e309dc8..8deb94ae 100644 --- a/vetiver/tests/test_pin_write.py +++ b/vetiver/tests/test_pin_write.py @@ -1,14 +1,12 @@ import pytest -from vetiver.mock import get_mock_data, get_mock_model -from vetiver.pin_read_write import vetiver_pin_write -from vetiver.vetiver_model import VetiverModel +from vetiver import mock, vetiver_pin_write, VetiverModel import sklearn import pins # Load data, model -X_df, y = get_mock_data() -model = get_mock_model().fit(X_df, y) +X_df, y = mock.get_mock_data() +model = mock.get_mock_model().fit(X_df, y) def test_board_pin_write_error(): diff --git a/vetiver/tests/test_pytorch.py b/vetiver/tests/test_pytorch.py index c940fdf8..73a86fd4 100644 --- a/vetiver/tests/test_pytorch.py +++ b/vetiver/tests/test_pytorch.py @@ -44,11 +44,10 @@ def build_torch(): @pytest.fixture -def torch_vetiver(build_torch): +def model(build_torch): x_train, torch_model = build_torch - - vt2 = VetiverModel( + return VetiverModel( model=torch_model, prototype_data=x_train, model_name="torch", @@ -57,75 +56,57 @@ def torch_vetiver(build_torch): metadata=None, ) - assert vt2.model == torch_model - assert vt2.metadata.required_pkgs == ["torch"] - - return vt2 - - -@pytest.fixture -def vetiver_client_prototype(torch_vetiver): - app = vetiver.VetiverAPI(torch_vetiver, check_prototype=True) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client - - -@pytest.fixture -def vetiver_client_no_prototype(torch_vetiver): - app = vetiver.VetiverAPI(torch_vetiver, check_prototype=False) - app.app.root_path = "/predict" - client = TestClient(app.app) - return client +def test_required_pkgs(model): + assert isinstance(model.model, torch.nn.Linear) + assert model.metadata.required_pkgs == ["torch"] -def test_torch_predict_ptype(vetiver_client_prototype): +def test_torch_predict_ptype(client: TestClient): torch.manual_seed(3) data = [{"0": 3.3}] - response = predict(endpoint=vetiver_client_prototype, data=data) + response = predict(endpoint="/predict/", data=data, test_client=client) assert len(response) == 1, len(response) assert isinstance(response, pd.DataFrame) assert response.iloc[0, 0] == [-4.060722351074219], response.iloc[0, 0] -def test_torch_predict_ptype_batch(vetiver_client_prototype): +def test_torch_predict_ptype_batch(client: TestClient): data = [{"0": 3.3}, {"0": 3.3}] - response = predict(endpoint=vetiver_client_prototype, data=data) + response = predict(endpoint="/predict/", data=data, test_client=client) assert len(response) == 2, len(response) assert isinstance(response, pd.DataFrame) assert response.iloc[0, 0] == [-4.060722351074219], response.iloc[0, 0] -def test_torch_predict_ptype_error(vetiver_client_prototype): +def test_torch_predict_ptype_error(client: TestClient): data = {"0": "bad"} with pytest.raises(TypeError): - predict(endpoint=vetiver_client_prototype, data=data) + predict(endpoint="/predict/", data=data, test_client=client) -def test_torch_predict_no_ptype_batch(vetiver_client_no_prototype): +def test_torch_predict_no_ptype_batch(client_no_prototype: TestClient): torch.manual_seed(3) data = [[3.3], [3.3]] - response = predict(endpoint=vetiver_client_no_prototype, data=data) + response = predict(endpoint="/predict/", data=data, test_client=client_no_prototype) assert len(response) == 2, len(response) assert isinstance(response, pd.DataFrame) assert response.iloc[0, 0] == [-4.060722351074219], response.iloc[0, 0] -def test_torch_predict_no_ptype(vetiver_client_no_prototype): +def test_torch_predict_no_ptype(client_no_prototype: TestClient): torch.manual_seed(3) data = [[3.3]] - response = predict(endpoint=vetiver_client_no_prototype, data=data) + response = predict(endpoint="/predict/", data=data, test_client=client_no_prototype) assert len(response) == 1, len(response) assert isinstance(response, pd.DataFrame) diff --git a/vetiver/tests/test_sklearn.py b/vetiver/tests/test_sklearn.py index caad53a9..d4b016ce 100644 --- a/vetiver/tests/test_sklearn.py +++ b/vetiver/tests/test_sklearn.py @@ -1,11 +1,8 @@ import pytest - import numpy as np import pandas as pd from requests.exceptions import HTTPError -from fastapi.testclient import TestClient - -from vetiver import mock, VetiverModel, VetiverAPI +from vetiver import mock, VetiverModel from vetiver.server import predict np.random.seed(500) @@ -13,7 +10,7 @@ @pytest.fixture -def vetiver_model(): +def model() -> VetiverModel: np.random.seed(500) model = mock.get_mock_model().fit(X, y) v = VetiverModel( @@ -27,44 +24,23 @@ def vetiver_model(): return v -@pytest.fixture -def vetiver_client(vetiver_model): # With check_ptype=True - app = VetiverAPI(vetiver_model, check_prototype=True) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client - - -@pytest.fixture -def vetiver_client_check_ptype_false(vetiver_model): # With check_ptype=False - app = VetiverAPI(vetiver_model, check_prototype=False) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client - - @pytest.mark.parametrize( - "data,length", - [({"B": 0, "C": 0, "D": 0}, 1), (pd.Series(data=[0, 0, 0]), 1), (X, 100)], + "data,expected_length", + [([{"B": 0, "C": 0, "D": 0}], 1), (pd.Series(data=[0, 0, 0]), 1), (X, 100)], ) -def test_predict_sklearn_ptype(data, length, vetiver_client): - - response = predict(endpoint=vetiver_client, data=data) - +def test_predict_sklearn_ptype(data, expected_length, client): + response = predict(endpoint="/predict/", data=data, test_client=client) assert isinstance(response, pd.DataFrame), response assert response.iloc[0, 0] == 44.47 - assert len(response) == length + assert len(response) == expected_length @pytest.mark.parametrize( "data,length", [({"B": 0, "C": 0, "D": 0}, 1), (pd.Series(data=[0, 0, 0]), 1), (X, 100)], ) -def test_predict_sklearn_no_ptype(data, length, vetiver_client_check_ptype_false): - X, y = mock.get_mock_data() - response = predict(endpoint=vetiver_client_check_ptype_false, data=data) +def test_predict_sklearn_no_ptype(data, length, client_no_prototype): + response = predict(endpoint="/predict/", data=data, test_client=client_no_prototype) assert isinstance(response, pd.DataFrame), response assert response.iloc[0, 0] == 44.47 @@ -72,7 +48,7 @@ def test_predict_sklearn_no_ptype(data, length, vetiver_client_check_ptype_false @pytest.mark.parametrize("data", [(0), 0, 0.0, "0"]) -def test_predict_sklearn_type_error(data, vetiver_client): +def test_predict_sklearn_type_error(data, client): msg = str( "[{'type': 'list_type', 'loc': ('body',), 'msg': 'Input should be a valid list', \ @@ -80,14 +56,10 @@ def test_predict_sklearn_type_error(data, vetiver_client): ) with pytest.raises(TypeError, match=msg): - predict(endpoint=vetiver_client, data=data) + predict(endpoint="/predict/", data=data, test_client=client) -def test_predict_server_error(vetiver_model): - X, y = mock.get_mock_data() - app = VetiverAPI(vetiver_model, check_prototype=True) - app.app.root_path = "/i_do_not_exists" - client = TestClient(app.app) +def test_predict_server_error(client): with pytest.raises(HTTPError): - predict(endpoint=client, data=X) + predict(endpoint="/i_do_not_exists/", data=X, test_client=client) diff --git a/vetiver/tests/test_spacy.py b/vetiver/tests/test_spacy.py index 53926d29..c28e92fc 100644 --- a/vetiver/tests/test_spacy.py +++ b/vetiver/tests/test_spacy.py @@ -32,35 +32,10 @@ def spacy_model(): return nlp -@pytest.fixture() -def vetiver_client_with_prototype(spacy_model): # With check_prototype=True - df = pd.DataFrame({"new_column": ["one", "two", "three"]}) - v = vetiver.VetiverModel(spacy_model, "animals", prototype_data=df) - app = vetiver.VetiverAPI(v, check_prototype=True) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client - - -@pytest.fixture(scope="function") -def vetiver_client_with_prototype_series(spacy_model): # With check_prototype=True - df = pd.Series({"new_column": ["one", "two", "three"]}) - v = vetiver.VetiverModel(spacy_model, "animals", prototype_data=df) - app = vetiver.VetiverAPI(v, check_prototype=True) - app.app.root_path = "/predict" - client = TestClient(app.app) - return client - - @pytest.fixture -def vetiver_client_no_prototype(spacy_model): # With check_prototype=False - v = vetiver.VetiverModel(spacy_model, "animals") - app = vetiver.VetiverAPI(v, check_prototype=False) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client +def model(spacy_model) -> TestClient: + df = pd.DataFrame({"new_column": ["one", "two", "three"]}) + return vetiver.VetiverModel(spacy_model, "animals", prototype_data=df) @pytest.mark.parametrize("data", ["a", 1, [1, 2, 3]]) @@ -88,10 +63,10 @@ def test_good_prototype_shape(data, spacy_model): assert v.prototype.construct().dict() == {"col": "1"} -def test_vetiver_predict_with_prototype(vetiver_client_with_prototype): +def test_vetiver_predict_with_prototype(client: TestClient): df = pd.DataFrame({"new_column": ["turtles", "i have a dog"]}) - response = vetiver.predict(endpoint=vetiver_client_with_prototype, data=df) + response = vetiver.predict(endpoint="/predict/", data=df, test_client=client) assert isinstance(response, pd.DataFrame), response assert response.to_dict() == { @@ -115,10 +90,12 @@ def test_vetiver_predict_with_prototype(vetiver_client_with_prototype): } -def test_vetiver_predict_no_prototype(vetiver_client_no_prototype): +def test_vetiver_predict_no_prototype(client_no_prototype: TestClient): df = pd.DataFrame({"uhhh": ["turtles", "i have a dog"]}) - response = vetiver.predict(endpoint=vetiver_client_no_prototype, data=df) + response = vetiver.predict( + endpoint="/predict/", data=df, test_client=client_no_prototype + ) assert isinstance(response, pd.DataFrame), response assert response.to_dict() == { diff --git a/vetiver/tests/test_statsmodels.py b/vetiver/tests/test_statsmodels.py index e666c05c..0cfec079 100644 --- a/vetiver/tests/test_statsmodels.py +++ b/vetiver/tests/test_statsmodels.py @@ -14,7 +14,7 @@ @pytest.fixture -def sm_model(): +def model(): X, y = vetiver.get_mock_data() glm = sm.GLM(y, X).fit() @@ -23,55 +23,39 @@ def sm_model(): return v -@pytest.fixture -def vetiver_client(sm_model): # With check_prototype=True - app = vetiver.VetiverAPI(sm_model, check_prototype=True) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client - - -@pytest.fixture -def vetiver_client_check_ptype_false(sm_model): # With check_prototype=True - app = vetiver.VetiverAPI(sm_model, check_prototype=False) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client - - -def test_vetiver_build(vetiver_client): +def test_vetiver_build(client): data = [{"B": 0, "C": 0, "D": 0}] - response = vetiver.predict(endpoint=vetiver_client, data=data) + response = vetiver.predict(endpoint="/predict/", data=data, test_client=client) assert response.iloc[0, 0] == 0.0 assert len(response) == 1 -def test_batch(vetiver_client): +def test_batch(client): data = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list("ABCD")) - response = vetiver.predict(endpoint=vetiver_client, data=data) + response = vetiver.predict(endpoint="/predict/", data=data, test_client=client) assert len(response) == 100 -def test_no_ptype(vetiver_client_check_ptype_false): +def test_no_ptype(client_no_prototype): data = [0, 0, 0] - response = vetiver.predict(endpoint=vetiver_client_check_ptype_false, data=data) + response = vetiver.predict( + endpoint="/predict/", data=data, test_client=client_no_prototype + ) assert response.iloc[0, 0] == 0.0 assert len(response) == 1 -def test_serialize(sm_model): +def test_serialize(model): import pins board = pins.board_temp(allow_pickle_read=True) - vetiver.vetiver_pin_write(board=board, model=sm_model) + vetiver.vetiver_pin_write(board=board, model=model) assert isinstance( board.pin_read("glm"), statsmodels.genmod.generalized_linear_model.GLMResultsWrapper, diff --git a/vetiver/tests/test_xgboost.py b/vetiver/tests/test_xgboost.py index 5a00621a..7a24c08b 100644 --- a/vetiver/tests/test_xgboost.py +++ b/vetiver/tests/test_xgboost.py @@ -14,7 +14,7 @@ @pytest.fixture -def xgb_model(): +def model(): # read in data dtrain = xgb.DMatrix(mtcars.drop(columns="mpg"), label=mtcars["mpg"]) # specify parameters via map @@ -30,63 +30,44 @@ def xgb_model(): return vetiver.VetiverModel(fit, "xgb", mtcars.drop(columns="mpg")) -@pytest.fixture -def vetiver_client(xgb_model): # With check_prototype=True - app = vetiver.VetiverAPI(xgb_model, check_prototype=True) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client - - -@pytest.fixture -def vetiver_client_check_ptype_false(xgb_model): # With check_prototype=True - app = vetiver.VetiverAPI(xgb_model, check_prototype=False) - app.app.root_path = "/predict" - client = TestClient(app.app) - - return client +def test_required_pkgs(model): + assert model.metadata.required_pkgs == ["xgboost"] + assert not model.metadata.user -def test_model(xgb_model): - v = xgb_model - - assert v.metadata.required_pkgs == ["xgboost"] - assert not v.metadata.user - - -def test_vetiver_build(vetiver_client): +def test_vetiver_build(client): data = mtcars.head(1).drop(columns="mpg") - response = vetiver.predict(endpoint=vetiver_client, data=data) + response = vetiver.predict(endpoint="/predict/", data=data, test_client=client) assert response.iloc[0, 0] == PREDICT_VALUE assert len(response) == 1 -def test_batch(vetiver_client): +def test_batch(client): data = mtcars.head(3).drop(columns="mpg") - response = vetiver.predict(endpoint=vetiver_client, data=data) + response = vetiver.predict(endpoint="/predict/", data=data, test_client=client) assert response.iloc[0, 0] == PREDICT_VALUE assert len(response) == 3 -def test_no_ptype(vetiver_client_check_ptype_false): +def test_no_ptype(client_no_prototype): data = mtcars.head(1).drop(columns="mpg") - response = vetiver.predict(endpoint=vetiver_client_check_ptype_false, data=data) - + response = vetiver.predict( + endpoint="/predict/", data=data, test_client=client_no_prototype + ) assert response.iloc[0, 0] == PREDICT_VALUE assert len(response) == 1 -def test_serialize(xgb_model): +def test_serialize(model): import pins board = pins.board_temp(allow_pickle_read=True) - vetiver.vetiver_pin_write(board=board, model=xgb_model) + vetiver.vetiver_pin_write(board=board, model=model) assert isinstance( board.pin_read("xgb"), xgb.Booster,