From e725ddbb4c146e5cf5226b2e34c2e821074e2d16 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Fri, 4 Nov 2022 16:49:50 -0400 Subject: [PATCH 01/20] rework metadata --- vetiver/handlers/base.py | 1 + vetiver/handlers/sklearn.py | 9 ++--- vetiver/handlers/statsmodels.py | 7 ++-- vetiver/handlers/torch.py | 7 ++-- vetiver/handlers/xgboost.py | 7 ++-- vetiver/pin_read_write.py | 7 ++-- vetiver/tests/test_build_vetiver_model.py | 18 +++++++++- vetiver/vetiver_model.py | 42 +++++++++++++---------- 8 files changed, 64 insertions(+), 34 deletions(-) diff --git a/vetiver/handlers/base.py b/vetiver/handlers/base.py index 2ceda71d..91cad106 100644 --- a/vetiver/handlers/base.py +++ b/vetiver/handlers/base.py @@ -83,6 +83,7 @@ def describe(self): return desc def create_meta( + self, user: list = None, version: str = None, url: str = None, diff --git a/vetiver/handlers/sklearn.py b/vetiver/handlers/sklearn.py index d1449872..94c7a9ce 100644 --- a/vetiver/handlers/sklearn.py +++ b/vetiver/handlers/sklearn.py @@ -1,7 +1,6 @@ import pandas as pd import sklearn -from ..meta import _model_meta from .base import BaseHandler @@ -22,14 +21,16 @@ def describe(self): return desc def create_meta( - user: list = None, + self, + user: dict = None, version: str = None, url: str = None, required_pkgs: list = [], ): """Create metadata for sklearn model""" - required_pkgs = required_pkgs + ["scikit-learn"] - meta = _model_meta(user, version, url, required_pkgs) + if "scikit-learn" not in required_pkgs: + required_pkgs = required_pkgs + ["scikit-learn"] + meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/handlers/statsmodels.py b/vetiver/handlers/statsmodels.py index 8675485e..b7ac4cfb 100644 --- a/vetiver/handlers/statsmodels.py +++ b/vetiver/handlers/statsmodels.py @@ -1,6 +1,5 @@ import pandas as pd -from ..meta import _model_meta from .base import BaseHandler sm_exists = True @@ -27,14 +26,16 @@ def describe(self): return desc def create_meta( + self, user: list = None, version: str = None, url: str = None, required_pkgs: list = [], ): """Create metadata for statsmodel""" - required_pkgs = required_pkgs + ["statsmodels"] - meta = _model_meta(user, version, url, required_pkgs) + if "statsmodels" not in required_pkgs: + required_pkgs = required_pkgs + ["statsmodels"] + meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/handlers/torch.py b/vetiver/handlers/torch.py index 788fb601..44365ec4 100644 --- a/vetiver/handlers/torch.py +++ b/vetiver/handlers/torch.py @@ -1,6 +1,5 @@ import numpy as np -from ..meta import _model_meta from .base import BaseHandler torch_exists = True @@ -27,14 +26,16 @@ def describe(self): return desc def create_meta( + self, user: list = None, version: str = None, url: str = None, required_pkgs: list = [], ): """Create metadata for torch model""" - required_pkgs = required_pkgs + ["torch"] - meta = _model_meta(user, version, url, required_pkgs) + if "torch" not in required_pkgs: + required_pkgs = required_pkgs + ["torch"] + meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/handlers/xgboost.py b/vetiver/handlers/xgboost.py index f719c9a1..e79d0aee 100644 --- a/vetiver/handlers/xgboost.py +++ b/vetiver/handlers/xgboost.py @@ -1,6 +1,5 @@ import pandas as pd -from ..meta import _model_meta from .base import BaseHandler xgb_exists = True @@ -27,14 +26,16 @@ def describe(self): return desc def create_meta( + self, user: list = None, version: str = None, url: str = None, required_pkgs: list = [], ): """Create metadata for xgboost""" - required_pkgs = required_pkgs + ["xgboost"] - meta = _model_meta(user, version, url, required_pkgs) + if "xgboost" not in required_pkgs: + required_pkgs = required_pkgs + ["xgboost"] + meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/pin_read_write.py b/vetiver/pin_read_write.py index 7532da48..53ae4a99 100644 --- a/vetiver/pin_read_write.py +++ b/vetiver/pin_read_write.py @@ -61,8 +61,11 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): type="joblib", description=model.description, metadata={ - "required_pkgs": model.metadata.get("required_pkgs"), - "prototype": None if model.prototype is None else model.prototype().json(), + "user": model.metadata.get("user"), + "vetiver_meta": { + "required_pkgs": model.metadata.get("required_pkgs"), + "prototype": None if model.prototype is None else model.prototype().json(), + }, }, versioned=versioned, ) diff --git a/vetiver/tests/test_build_vetiver_model.py b/vetiver/tests/test_build_vetiver_model.py index 2d8df52c..3672d296 100644 --- a/vetiver/tests/test_build_vetiver_model.py +++ b/vetiver/tests/test_build_vetiver_model.py @@ -71,14 +71,21 @@ def test_vetiver_model_basemodel_prototype(): m = MockPrototype(B=4, C=0, D=0) vt4 = vt.VetiverModel( model=model, +<<<<<<< HEAD prototype_data=m, model_name="model", versioned=None, +======= + ptype_data=None, + model_name="iris", + versioned=False, +>>>>>>> 7edbe59 (rework metadata) description=None, - metadata=None, + metadata={"test": 123}, ) assert vt4.model == model +<<<<<<< HEAD assert vt4.prototype is m @@ -109,6 +116,15 @@ def test_vetiver_model_use_ptype(): assert vt5.model == model assert isinstance(vt5.prototype.construct(), pydantic.BaseModel) assert list(vt5.prototype.__fields__.values())[0].type_ == int +======= + assert vt4.ptype is None + assert vt4.metadata == { + "user": {"test": 123}, + "version": None, + "url": None, + "required_pkgs": ["scikit-learn"], + } +>>>>>>> 7edbe59 (rework metadata) def test_vetiver_model_from_pin(): diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index 843f607b..d5a868ee 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -1,7 +1,6 @@ import json from warnings import warn from vetiver.handlers.base import create_handler -from .meta import _model_meta class NoModelAvailableError(Exception): @@ -91,36 +90,43 @@ def __init__( self.model_name = model_name self.description = description if description else translator.describe() self.versioned = versioned - self.metadata = ( - metadata - if metadata - else translator.create_meta(metadata, required_pkgs=["vetiver"]) - ) self.handler_predict = translator.handler_predict + if metadata: + user = metadata.get("user") if "user" in metadata else metadata + version = metadata.get("version") if "version" in metadata else None + url = metadata.get("url") if "url" in metadata else None + required_pkgs = ( + metadata.get("required_pkgs") + if "required_pkgs" in metadata and metadata.get("required_pkgs") + else [] + ) + else: + user, version, url, required_pkgs = None, None, None, [] + + self.metadata = translator.create_meta(user, version, url, required_pkgs) + @classmethod def from_pin(cls, board, name: str, version: str = None): model = board.pin_read(name, version) meta = board.pin_meta(name, version) - if meta.user.get("ptype"): - get_prototype = meta.user.get("ptype") - elif meta.user.get("prototype"): - get_prototype = meta.user.get("prototype") - else: - get_prototype = None + if "vetiver_meta" in meta.user: + ptype = meta.user.get("vetiver_meta").get("prototype") + required_pkgs = meta.user.get("vetiver_meta").get("required_pkgs") + meta.user.pop("vetiver_meta") return cls( model=model, model_name=name, description=meta.description, - metadata=_model_meta( - user=meta.user, - version=meta.version.version, - url=meta.local.get("url"), # None all the time, besides Connect - required_pkgs=meta.user.get("required_pkgs"), - ), + metadata={ + "user": meta.user.get("user"), + "version": meta.version.version, + "url": meta.user.get("url"), # None all the time, besides Connect, + "required_pkgs": required_pkgs, + }, prototype_data=json.loads(get_prototype) if get_prototype else None, versioned=True, ) From f767e80f922c391d807006958a09a1fbcbcb5d0c Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Thu, 17 Nov 2022 17:35:52 -0500 Subject: [PATCH 02/20] add versions for required pkgs --- vetiver/handlers/sklearn.py | 6 +++-- vetiver/handlers/statsmodels.py | 4 ++-- vetiver/handlers/torch.py | 4 ++-- vetiver/handlers/xgboost.py | 4 ++-- vetiver/tests/test_build_vetiver_model.py | 27 +++++++++-------------- vetiver/tests/test_sklearn.py | 14 ++++++++++++ vetiver/vetiver_model.py | 3 +++ 7 files changed, 38 insertions(+), 24 deletions(-) diff --git a/vetiver/handlers/sklearn.py b/vetiver/handlers/sklearn.py index 94c7a9ce..5d39fb08 100644 --- a/vetiver/handlers/sklearn.py +++ b/vetiver/handlers/sklearn.py @@ -28,8 +28,10 @@ def create_meta( required_pkgs: list = [], ): """Create metadata for sklearn model""" - if "scikit-learn" not in required_pkgs: - required_pkgs = required_pkgs + ["scikit-learn"] + + if not list(filter(lambda x: "scikit-learn" in x, required_pkgs)): + required_pkgs = required_pkgs + [f"scikit-learn=={sklearn.__version__}"] + meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/handlers/statsmodels.py b/vetiver/handlers/statsmodels.py index b7ac4cfb..e9a8add2 100644 --- a/vetiver/handlers/statsmodels.py +++ b/vetiver/handlers/statsmodels.py @@ -33,8 +33,8 @@ def create_meta( required_pkgs: list = [], ): """Create metadata for statsmodel""" - if "statsmodels" not in required_pkgs: - required_pkgs = required_pkgs + ["statsmodels"] + if not list(filter(lambda x: "statsmodels" in x, required_pkgs)): + required_pkgs = required_pkgs + [f"statsmodels=={statsmodels.__version__}"] meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/handlers/torch.py b/vetiver/handlers/torch.py index 44365ec4..dcfb037e 100644 --- a/vetiver/handlers/torch.py +++ b/vetiver/handlers/torch.py @@ -33,8 +33,8 @@ def create_meta( required_pkgs: list = [], ): """Create metadata for torch model""" - if "torch" not in required_pkgs: - required_pkgs = required_pkgs + ["torch"] + if not list(filter(lambda x: "torch" in x, required_pkgs)): + required_pkgs = required_pkgs + [f"torch=={torch.__version__}"] meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/handlers/xgboost.py b/vetiver/handlers/xgboost.py index e79d0aee..8006c608 100644 --- a/vetiver/handlers/xgboost.py +++ b/vetiver/handlers/xgboost.py @@ -33,8 +33,8 @@ def create_meta( required_pkgs: list = [], ): """Create metadata for xgboost""" - if "xgboost" not in required_pkgs: - required_pkgs = required_pkgs + ["xgboost"] + if not list(filter(lambda x: "xgboost" in x, required_pkgs)): + required_pkgs = required_pkgs + [f"xgboost=={xgboost.__version__}"] meta = super().create_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/tests/test_build_vetiver_model.py b/vetiver/tests/test_build_vetiver_model.py index 3672d296..ff058051 100644 --- a/vetiver/tests/test_build_vetiver_model.py +++ b/vetiver/tests/test_build_vetiver_model.py @@ -71,21 +71,13 @@ def test_vetiver_model_basemodel_prototype(): m = MockPrototype(B=4, C=0, D=0) vt4 = vt.VetiverModel( model=model, -<<<<<<< HEAD prototype_data=m, model_name="model", - versioned=None, -======= - ptype_data=None, - model_name="iris", versioned=False, ->>>>>>> 7edbe59 (rework metadata) - description=None, - metadata={"test": 123}, + description=None ) assert vt4.model == model -<<<<<<< HEAD assert vt4.prototype is m @@ -106,25 +98,23 @@ def test_vetiver_model_no_prototype(): def test_vetiver_model_use_ptype(): vt5 = vt.VetiverModel( model=model, - ptype_data=X_df, + prototype_data=None, model_name="model", versioned=None, description=None, - metadata=None, + metadata={"test": 123}, ) assert vt5.model == model assert isinstance(vt5.prototype.construct(), pydantic.BaseModel) assert list(vt5.prototype.__fields__.values())[0].type_ == int -======= - assert vt4.ptype is None + assert vt4.prototype is None assert vt4.metadata == { "user": {"test": 123}, "version": None, "url": None, - "required_pkgs": ["scikit-learn"], + "required_pkgs": [f"scikit-learn=={sklearn.__version__}"], } ->>>>>>> 7edbe59 (rework metadata) def test_vetiver_model_from_pin(): @@ -135,12 +125,17 @@ def test_vetiver_model_from_pin(): model_name="model", versioned=None, description=None, - metadata=None, + metadata={"test": 123}, ) + board = pins.board_temp(allow_pickle_read=True) vt.vetiver_pin_write(board=board, model=v) v2 = vt.VetiverModel.from_pin(board, "model") + assert isinstance(v2, vt.VetiverModel) assert isinstance(v2.model, sklearn.base.BaseEstimator) assert isinstance(v2.prototype.construct(), pydantic.BaseModel) + assert v2.metadata.get("user") == {"test": 123} + assert v2.metadata.get("version") is not None + board.pin_delete("model") diff --git a/vetiver/tests/test_sklearn.py b/vetiver/tests/test_sklearn.py index 29fe9fdf..b2ed10d6 100644 --- a/vetiver/tests/test_sklearn.py +++ b/vetiver/tests/test_sklearn.py @@ -2,6 +2,7 @@ from fastapi.testclient import TestClient import numpy as np import pytest +import sklearn def _start_application(save_prototype: bool = True): @@ -20,6 +21,19 @@ def _start_application(save_prototype: bool = True): return app +def test_build_sklearn(): + X, y = mock.get_mock_data() + model = mock.get_mock_model().fit(X, y) + v = VetiverModel( + model=model, + ptype_data=X, + model_name="my_model", + description="A regression model for testing purposes", + ) + + assert v.metadata.get("required_pkgs") == [f"scikit-learn=={sklearn.__version__}"] + + def test_predict_endpoint_ptype(): np.random.seed(500) client = TestClient(_start_application().app) diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index d5a868ee..47677383 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -116,6 +116,9 @@ def from_pin(cls, board, name: str, version: str = None): ptype = meta.user.get("vetiver_meta").get("prototype") required_pkgs = meta.user.get("vetiver_meta").get("required_pkgs") meta.user.pop("vetiver_meta") + else: + ptype = meta.user.get("ptype") if meta.user.get("ptype") else None + required_pkgs = meta.user.get("required_pkgs") return cls( model=model, From adfe1aa680825a9fed4759a7547f118628b35b42 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Thu, 17 Nov 2022 17:45:50 -0500 Subject: [PATCH 03/20] testing for all frameworks --- vetiver/tests/test_pytorch.py | 1 + vetiver/tests/test_xgboost.py | 1 + vetiver/vetiver_model.py | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/vetiver/tests/test_pytorch.py b/vetiver/tests/test_pytorch.py index e57c4676..8e1aa15d 100644 --- a/vetiver/tests/test_pytorch.py +++ b/vetiver/tests/test_pytorch.py @@ -53,6 +53,7 @@ def test_vetiver_build(): ) assert vt2.model == torch_model + assert vt2.metadata.get("required_pkgs") == [f"torch=={torch.__version__}"] def test_torch_predict_ptype(): diff --git a/vetiver/tests/test_xgboost.py b/vetiver/tests/test_xgboost.py index c708237a..9450e124 100644 --- a/vetiver/tests/test_xgboost.py +++ b/vetiver/tests/test_xgboost.py @@ -50,6 +50,7 @@ def test_vetiver_build(vetiver_client): response = vetiver.predict(endpoint=vetiver_client, data=data) + assert build_xgb.metadata.get("required_pkgs") == [f"xgboost=={xgb.__version__}"] assert response.iloc[0, 0] == 21.064373016357422 assert len(response) == 1 diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index 47677383..9e4a75e1 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -127,7 +127,7 @@ def from_pin(cls, board, name: str, version: str = None): metadata={ "user": meta.user.get("user"), "version": meta.version.version, - "url": meta.user.get("url"), # None all the time, besides Connect, + "url": meta.local.get("url"), # None all the time, besides Connect, "required_pkgs": required_pkgs, }, prototype_data=json.loads(get_prototype) if get_prototype else None, From 2713011f9f7bfb68c12a1f0826de7f92d02fe9ae Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Fri, 18 Nov 2022 13:28:39 -0500 Subject: [PATCH 04/20] moving all metadata to base handler --- docs/source/advancedusage/custom_handler.md | 2 ++ vetiver/handlers/base.py | 6 +++++- vetiver/handlers/sklearn.py | 20 +++----------------- vetiver/handlers/statsmodels.py | 20 ++------------------ vetiver/handlers/torch.py | 21 ++------------------- vetiver/handlers/xgboost.py | 21 ++------------------- vetiver/tests/test_custom_handler.py | 6 ++++-- vetiver/vetiver_model.py | 4 +--- 8 files changed, 21 insertions(+), 79 deletions(-) diff --git a/docs/source/advancedusage/custom_handler.md b/docs/source/advancedusage/custom_handler.md index 333bda48..2389a804 100644 --- a/docs/source/advancedusage/custom_handler.md +++ b/docs/source/advancedusage/custom_handler.md @@ -12,6 +12,8 @@ class CustomHandler(BaseHandler): super().__init__(model, ptype_data) model_type = staticmethod(lambda: newmodeltype) + pkg = statsmodels # modeling package + pip_name = "py-custommodel" # pkg name on pip, used for tracking pkg versions def handler_predict(self, input_data, check_ptype: bool): """ diff --git a/vetiver/handlers/base.py b/vetiver/handlers/base.py index 91cad106..6d1c5f18 100644 --- a/vetiver/handlers/base.py +++ b/vetiver/handlers/base.py @@ -79,7 +79,8 @@ def __init__(self, model, prototype_data): def describe(self): """Create description for model""" - desc = f"{self.model.__class__} model" + obj_name = type(self.model).__qualname__ + desc = f"A {self.pip_name} {obj_name} model" return desc def create_meta( @@ -90,6 +91,9 @@ def create_meta( required_pkgs: list = [], ): """Create metadata for a model""" + if not list(filter(lambda x: self.pip_name in x, required_pkgs)): + required_pkgs = required_pkgs + [f"{self.pip_name}=={self.pkg.__version__}"] + meta = _model_meta(user, version, url, required_pkgs) return meta diff --git a/vetiver/handlers/sklearn.py b/vetiver/handlers/sklearn.py index 5d39fb08..7066e3b7 100644 --- a/vetiver/handlers/sklearn.py +++ b/vetiver/handlers/sklearn.py @@ -14,29 +14,15 @@ class SKLearnHandler(BaseHandler): """ model_class = staticmethod(lambda: sklearn.base.BaseEstimator) + pip_name = "scikit-learn" + pkg = sklearn def describe(self): """Create description for sklearn model""" desc = f"Scikit-learn {self.model.__class__} model" return desc - def create_meta( - self, - user: dict = None, - version: str = None, - url: str = None, - required_pkgs: list = [], - ): - """Create metadata for sklearn model""" - - if not list(filter(lambda x: "scikit-learn" in x, required_pkgs)): - required_pkgs = required_pkgs + [f"scikit-learn=={sklearn.__version__}"] - - meta = super().create_meta(user, version, url, required_pkgs) - - return meta - - def handler_predict(self, input_data, check_prototype): + def handler_predict(self, input_data, check_ptype): """Generates method for /predict endpoint in VetiverAPI The `handler_predict` function executes at each API call. Use this diff --git a/vetiver/handlers/statsmodels.py b/vetiver/handlers/statsmodels.py index e9a8add2..41df51bc 100644 --- a/vetiver/handlers/statsmodels.py +++ b/vetiver/handlers/statsmodels.py @@ -20,24 +20,8 @@ class StatsmodelsHandler(BaseHandler): model_class = staticmethod(lambda: statsmodels.base.wrapper.ResultsWrapper) - def describe(self): - """Create description for statsmodels model""" - desc = f"Statsmodels {self.model.__class__} model." - return desc - - def create_meta( - self, - user: list = None, - version: str = None, - url: str = None, - required_pkgs: list = [], - ): - """Create metadata for statsmodel""" - if not list(filter(lambda x: "statsmodels" in x, required_pkgs)): - required_pkgs = required_pkgs + [f"statsmodels=={statsmodels.__version__}"] - meta = super().create_meta(user, version, url, required_pkgs) - - return meta + pkg = statsmodels + pip_name = "statsmodels" def handler_predict(self, input_data, check_prototype): """Generates method for /predict endpoint in VetiverAPI diff --git a/vetiver/handlers/torch.py b/vetiver/handlers/torch.py index dcfb037e..289133c4 100644 --- a/vetiver/handlers/torch.py +++ b/vetiver/handlers/torch.py @@ -19,25 +19,8 @@ class TorchHandler(BaseHandler): """ model_class = staticmethod(lambda: torch.nn.Module) - - def describe(self): - """Create description for torch model""" - desc = f"Pytorch model of type {type(self.model)}" - return desc - - def create_meta( - self, - user: list = None, - version: str = None, - url: str = None, - required_pkgs: list = [], - ): - """Create metadata for torch model""" - if not list(filter(lambda x: "torch" in x, required_pkgs)): - required_pkgs = required_pkgs + [f"torch=={torch.__version__}"] - meta = super().create_meta(user, version, url, required_pkgs) - - return meta + pkg = torch + pip_name = "torch" def handler_predict(self, input_data, check_prototype): """Generates method for /predict endpoint in VetiverAPI diff --git a/vetiver/handlers/xgboost.py b/vetiver/handlers/xgboost.py index 8006c608..c471a465 100644 --- a/vetiver/handlers/xgboost.py +++ b/vetiver/handlers/xgboost.py @@ -19,25 +19,8 @@ class XGBoostHandler(BaseHandler): """ model_class = staticmethod(lambda: xgboost.Booster) - - def describe(self): - """Create description for xgboost model""" - desc = f"XGBoost {self.model.__class__} model." - return desc - - def create_meta( - self, - user: list = None, - version: str = None, - url: str = None, - required_pkgs: list = [], - ): - """Create metadata for xgboost""" - if not list(filter(lambda x: "xgboost" in x, required_pkgs)): - required_pkgs = required_pkgs + [f"xgboost=={xgboost.__version__}"] - meta = super().create_meta(user, version, url, required_pkgs) - - return meta + pkg = xgboost + pip_name = "xgboost" def handler_predict(self, input_data, check_prototype): """Generates method for /predict endpoint in VetiverAPI diff --git a/vetiver/tests/test_custom_handler.py b/vetiver/tests/test_custom_handler.py index 873c21d0..531560a4 100644 --- a/vetiver/tests/test_custom_handler.py +++ b/vetiver/tests/test_custom_handler.py @@ -10,6 +10,8 @@ def __init__(self, model, prototype_data): super().__init__(model, prototype_data) model_type = staticmethod(lambda: sklearn.dummy.DummyRegressor) + pkg = pd # random non modeling package chosen for init purposes + pip_name = "random_pkg" def handler_predict(self, input_data, check_ptype): if check_ptype is True: @@ -35,10 +37,10 @@ def test_custom_vetiver_model(): prototype_data=X, model_name="my_model", versioned=None, - description="A regression model for testing purposes", ) - assert v.description == "A regression model for testing purposes" + assert v.description == "A random_pkg DummyRegressor model" + assert v.metadata.get("required_pkgs") == [f"random_pkg=={pd.__version__}"] assert isinstance(v.model, sklearn.dummy.DummyRegressor) assert isinstance(v.prototype.construct(), pydantic.BaseModel) diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index 9e4a75e1..d1d70010 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -97,9 +97,7 @@ def __init__( version = metadata.get("version") if "version" in metadata else None url = metadata.get("url") if "url" in metadata else None required_pkgs = ( - metadata.get("required_pkgs") - if "required_pkgs" in metadata and metadata.get("required_pkgs") - else [] + metadata.get("required_pkgs") if "required_pkgs" in metadata else [] ) else: user, version, url, required_pkgs = None, None, None, [] From 636b4073d5d61a0d89ebe4dae5b585a322e333e7 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Fri, 18 Nov 2022 13:50:50 -0500 Subject: [PATCH 05/20] avoid torch import --- vetiver/handlers/torch.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vetiver/handlers/torch.py b/vetiver/handlers/torch.py index 289133c4..d5995f90 100644 --- a/vetiver/handlers/torch.py +++ b/vetiver/handlers/torch.py @@ -19,7 +19,8 @@ class TorchHandler(BaseHandler): """ model_class = staticmethod(lambda: torch.nn.Module) - pkg = torch + if torch_exists: + pkg = torch pip_name = "torch" def handler_predict(self, input_data, check_prototype): From 18752d1ae6de2c870add190fed84e81278e1ce4c Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Fri, 18 Nov 2022 14:03:49 -0500 Subject: [PATCH 06/20] avoid dependency errors --- vetiver/handlers/statsmodels.py | 6 +++--- vetiver/handlers/torch.py | 2 +- vetiver/handlers/xgboost.py | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/vetiver/handlers/statsmodels.py b/vetiver/handlers/statsmodels.py index 41df51bc..6edb4d0b 100644 --- a/vetiver/handlers/statsmodels.py +++ b/vetiver/handlers/statsmodels.py @@ -19,9 +19,9 @@ class StatsmodelsHandler(BaseHandler): """ model_class = staticmethod(lambda: statsmodels.base.wrapper.ResultsWrapper) - - pkg = statsmodels - pip_name = "statsmodels" + if sm_exists: + pkg = statsmodels + pip_name = "statsmodels" def handler_predict(self, input_data, check_prototype): """Generates method for /predict endpoint in VetiverAPI diff --git a/vetiver/handlers/torch.py b/vetiver/handlers/torch.py index d5995f90..fe968643 100644 --- a/vetiver/handlers/torch.py +++ b/vetiver/handlers/torch.py @@ -21,7 +21,7 @@ class TorchHandler(BaseHandler): model_class = staticmethod(lambda: torch.nn.Module) if torch_exists: pkg = torch - pip_name = "torch" + pip_name = "torch" def handler_predict(self, input_data, check_prototype): """Generates method for /predict endpoint in VetiverAPI diff --git a/vetiver/handlers/xgboost.py b/vetiver/handlers/xgboost.py index c471a465..ee058832 100644 --- a/vetiver/handlers/xgboost.py +++ b/vetiver/handlers/xgboost.py @@ -19,8 +19,9 @@ class XGBoostHandler(BaseHandler): """ model_class = staticmethod(lambda: xgboost.Booster) - pkg = xgboost - pip_name = "xgboost" + if xgb_exists: + pkg = xgboost + pip_name = "xgboost" def handler_predict(self, input_data, check_prototype): """Generates method for /predict endpoint in VetiverAPI From 90f26749b74ae117c6d51dcc10da0fbd9ab7ec7e Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 29 Nov 2022 14:49:28 -0500 Subject: [PATCH 07/20] changes from review --- docs/source/advancedusage/custom_handler.md | 4 ++-- vetiver/vetiver_model.py | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/source/advancedusage/custom_handler.md b/docs/source/advancedusage/custom_handler.md index 2389a804..62e28172 100644 --- a/docs/source/advancedusage/custom_handler.md +++ b/docs/source/advancedusage/custom_handler.md @@ -12,8 +12,8 @@ class CustomHandler(BaseHandler): super().__init__(model, ptype_data) model_type = staticmethod(lambda: newmodeltype) - pkg = statsmodels # modeling package - pip_name = "py-custommodel" # pkg name on pip, used for tracking pkg versions + pkg = sklearn # modeling package + pip_name = "scikit-learn" # pkg name on pip, used for tracking pkg versions def handler_predict(self, input_data, check_ptype: bool): """ diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index d1d70010..052f1736 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -93,12 +93,10 @@ def __init__( self.handler_predict = translator.handler_predict if metadata: - user = metadata.get("user") if "user" in metadata else metadata - version = metadata.get("version") if "version" in metadata else None - url = metadata.get("url") if "url" in metadata else None - required_pkgs = ( - metadata.get("required_pkgs") if "required_pkgs" in metadata else [] - ) + user = metadata.get("user", metadata) + version = metadata.get("version", None) + url = metadata.get("url", None) + required_pkgs = metadata.get("required_pkgs", []) else: user, version, url, required_pkgs = None, None, None, [] From 279a6c31ec7edc38d624e9bd210c1badfd0ac04b Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Mon, 5 Dec 2022 09:45:13 -0500 Subject: [PATCH 08/20] consolidate meta parsing --- vetiver/handlers/base.py | 17 ++++++++++------- vetiver/tests/test_xgboost.py | 1 - vetiver/vetiver_model.py | 13 ++----------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/vetiver/handlers/base.py b/vetiver/handlers/base.py index 6d1c5f18..b980fedd 100644 --- a/vetiver/handlers/base.py +++ b/vetiver/handlers/base.py @@ -83,14 +83,17 @@ def describe(self): desc = f"A {self.pip_name} {obj_name} model" return desc - def create_meta( - self, - user: list = None, - version: str = None, - url: str = None, - required_pkgs: list = [], - ): + def create_meta(self, metadata): """Create metadata for a model""" + + if metadata: + user = metadata.get("user", metadata) + version = metadata.get("version", None) + url = metadata.get("url", None) + required_pkgs = metadata.get("required_pkgs", []) + else: + user, version, url, required_pkgs = None, None, None, [] + if not list(filter(lambda x: self.pip_name in x, required_pkgs)): required_pkgs = required_pkgs + [f"{self.pip_name}=={self.pkg.__version__}"] diff --git a/vetiver/tests/test_xgboost.py b/vetiver/tests/test_xgboost.py index 9450e124..c708237a 100644 --- a/vetiver/tests/test_xgboost.py +++ b/vetiver/tests/test_xgboost.py @@ -50,7 +50,6 @@ def test_vetiver_build(vetiver_client): response = vetiver.predict(endpoint=vetiver_client, data=data) - assert build_xgb.metadata.get("required_pkgs") == [f"xgboost=={xgb.__version__}"] assert response.iloc[0, 0] == 21.064373016357422 assert len(response) == 1 diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index 052f1736..06ce7b7d 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -91,16 +91,7 @@ def __init__( self.description = description if description else translator.describe() self.versioned = versioned self.handler_predict = translator.handler_predict - - if metadata: - user = metadata.get("user", metadata) - version = metadata.get("version", None) - url = metadata.get("url", None) - required_pkgs = metadata.get("required_pkgs", []) - else: - user, version, url, required_pkgs = None, None, None, [] - - self.metadata = translator.create_meta(user, version, url, required_pkgs) + self.metadata = translator.create_meta(metadata) @classmethod def from_pin(cls, board, name: str, version: str = None): @@ -113,7 +104,7 @@ def from_pin(cls, board, name: str, version: str = None): required_pkgs = meta.user.get("vetiver_meta").get("required_pkgs") meta.user.pop("vetiver_meta") else: - ptype = meta.user.get("ptype") if meta.user.get("ptype") else None + ptype = meta.user.get("ptype", None) required_pkgs = meta.user.get("required_pkgs") return cls( From 72bdd85fb3ac57481c71e1984db826caec6c5eb4 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 6 Dec 2022 15:04:27 -0500 Subject: [PATCH 09/20] use dataclass rather than dict --- vetiver/handlers/base.py | 17 +------- vetiver/meta.py | 48 ++++++++++++----------- vetiver/pin_read_write.py | 6 +-- vetiver/server.py | 18 +++++++-- vetiver/tests/test_build_vetiver_model.py | 19 +++++++++ vetiver/tests/test_custom_handler.py | 2 +- vetiver/tests/test_sklearn.py | 2 +- vetiver/tests/test_xgboost.py | 10 +++++ 8 files changed, 76 insertions(+), 46 deletions(-) diff --git a/vetiver/handlers/base.py b/vetiver/handlers/base.py index b980fedd..bfd563f2 100644 --- a/vetiver/handlers/base.py +++ b/vetiver/handlers/base.py @@ -3,7 +3,7 @@ from contextlib import suppress from ..prototype import vetiver_create_prototype -from ..meta import _model_meta +from ..meta import VetiverMeta class InvalidModelError(Exception): @@ -86,20 +86,7 @@ def describe(self): def create_meta(self, metadata): """Create metadata for a model""" - if metadata: - user = metadata.get("user", metadata) - version = metadata.get("version", None) - url = metadata.get("url", None) - required_pkgs = metadata.get("required_pkgs", []) - else: - user, version, url, required_pkgs = None, None, None, [] - - if not list(filter(lambda x: self.pip_name in x, required_pkgs)): - required_pkgs = required_pkgs + [f"{self.pip_name}=={self.pkg.__version__}"] - - meta = _model_meta(user, version, url, required_pkgs) - - return meta + return VetiverMeta.from_dict(metadata, self.pip_name, self.pkg) def construct_prototype(self): """Create data prototype for a model diff --git a/vetiver/meta.py b/vetiver/meta.py index bfcdb6d7..6cd123bd 100644 --- a/vetiver/meta.py +++ b/vetiver/meta.py @@ -1,23 +1,27 @@ -def _model_meta( - user: dict = None, version: str = None, url: str = None, required_pkgs: list = None -): - """Populate relevant metadata for VetiverModel +from dataclasses import dataclass - Args - ---- - user: dict - Extra user-defined information - version: str - Model version, generally populated from pins - url: str - Discoverable URL for API - required_pkgs: list - Packages necessary to make predictions - """ - meta = { - "user": user, - "version": version, - "url": url, - "required_pkgs": required_pkgs, - } - return meta + +@dataclass +class VetiverMeta: + """Metadata in a VetiverModel""" + + user: "dict | None" = None + version: "str | None" = None + url: "str | None" = None + required_pkgs: "list | None" = None + + @classmethod + def from_dict(cls, metadata, pip_name, pkg) -> "VetiverMeta": + + if metadata: + user = metadata.get("user", metadata) + version = metadata.get("version", None) + url = metadata.get("url", None) + required_pkgs = metadata.get("required_pkgs", []) + else: + user, version, url, required_pkgs = None, None, None, [] + + if not list(filter(lambda x: pip_name in x, required_pkgs)): + required_pkgs = required_pkgs + [f"{pip_name}=={pkg.__version__}"] + + return cls(user, version, url, required_pkgs) diff --git a/vetiver/pin_read_write.py b/vetiver/pin_read_write.py index 53ae4a99..e0f9658e 100644 --- a/vetiver/pin_read_write.py +++ b/vetiver/pin_read_write.py @@ -66,9 +66,9 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): "required_pkgs": model.metadata.get("required_pkgs"), "prototype": None if model.prototype is None else model.prototype().json(), }, - }, - versioned=versioned, - ) + versioned=versioned, + ) + # metadata is VetiverMeta def vetiver_pin_read(board, name: str, version: str = None) -> VetiverModel: diff --git a/vetiver/server.py b/vetiver/server.py index e621d404..a8e307a6 100644 --- a/vetiver/server.py +++ b/vetiver/server.py @@ -82,11 +82,21 @@ def docs_redirect(): return RedirectResponse(redirect) - if self.model.metadata.get("url") is not None: + # metadata is a dict + try: + if self.model.metadata.get("url") is not None: - @app.get("/pin-url") - def pin_url(): - return repr(self.model.metadata.get("url")) + @app.get("/pin-url") + def pin_url(): + return repr(self.model.get("url")) + + # metadata is type VetiverMeta + except AttributeError: + if self.model.metadata.url is not None: + + @app.get("/pin-url") + def pin_url(): + return repr(self.model.metadata.url) @app.get("/ping", include_in_schema=True) async def ping(): diff --git a/vetiver/tests/test_build_vetiver_model.py b/vetiver/tests/test_build_vetiver_model.py index ff058051..dae6ca00 100644 --- a/vetiver/tests/test_build_vetiver_model.py +++ b/vetiver/tests/test_build_vetiver_model.py @@ -1,6 +1,7 @@ import sklearn import vetiver as vt +from vetiver.meta import VetiverMeta from vetiver.mock import get_mock_data, get_mock_model import pandas as pd @@ -105,6 +106,7 @@ def test_vetiver_model_use_ptype(): metadata={"test": 123}, ) +<<<<<<< HEAD assert vt5.model == model assert isinstance(vt5.prototype.construct(), pydantic.BaseModel) assert list(vt5.prototype.__fields__.values())[0].type_ == int @@ -115,6 +117,16 @@ def test_vetiver_model_use_ptype(): "url": None, "required_pkgs": [f"scikit-learn=={sklearn.__version__}"], } +======= + assert vt4.model == model + assert vt4.ptype is None + assert vt4.metadata == VetiverMeta( + user={"test": 123}, + version=None, + url=None, + required_pkgs=[f"scikit-learn=={sklearn.__version__}"], + ) +>>>>>>> 38a4b80 (use dataclass rather than dict) def test_vetiver_model_from_pin(): @@ -134,8 +146,15 @@ def test_vetiver_model_from_pin(): assert isinstance(v2, vt.VetiverModel) assert isinstance(v2.model, sklearn.base.BaseEstimator) +<<<<<<< HEAD assert isinstance(v2.prototype.construct(), pydantic.BaseModel) assert v2.metadata.get("user") == {"test": 123} assert v2.metadata.get("version") is not None +======= + assert isinstance(v2.ptype.construct(), pydantic.BaseModel) + assert v2.metadata.user == {"test": 123} + assert v2.metadata.version is not None + assert v2.metadata.required_pkgs == [f"scikit-learn=={sklearn.__version__}"] +>>>>>>> 38a4b80 (use dataclass rather than dict) board.pin_delete("model") diff --git a/vetiver/tests/test_custom_handler.py b/vetiver/tests/test_custom_handler.py index 531560a4..821711d7 100644 --- a/vetiver/tests/test_custom_handler.py +++ b/vetiver/tests/test_custom_handler.py @@ -40,7 +40,7 @@ def test_custom_vetiver_model(): ) assert v.description == "A random_pkg DummyRegressor model" - assert v.metadata.get("required_pkgs") == [f"random_pkg=={pd.__version__}"] + assert v.metadata.required_pkgs == [f"random_pkg=={pd.__version__}"] assert isinstance(v.model, sklearn.dummy.DummyRegressor) assert isinstance(v.prototype.construct(), pydantic.BaseModel) diff --git a/vetiver/tests/test_sklearn.py b/vetiver/tests/test_sklearn.py index b2ed10d6..cc77868e 100644 --- a/vetiver/tests/test_sklearn.py +++ b/vetiver/tests/test_sklearn.py @@ -31,7 +31,7 @@ def test_build_sklearn(): description="A regression model for testing purposes", ) - assert v.metadata.get("required_pkgs") == [f"scikit-learn=={sklearn.__version__}"] + assert v.metadata.required_pkgs == [f"scikit-learn=={sklearn.__version__}"] def test_predict_endpoint_ptype(): diff --git a/vetiver/tests/test_xgboost.py b/vetiver/tests/test_xgboost.py index c708237a..e42bd384 100644 --- a/vetiver/tests/test_xgboost.py +++ b/vetiver/tests/test_xgboost.py @@ -44,6 +44,16 @@ def vetiver_client_check_ptype_false(xgb_model): # With check_prototype=True return client +<<<<<<< HEAD +======= + +def test_model(xgb_model): + v = xgb_model + + assert v.metadata.required_pkgs == [f"xgboost=={xgb.__version__}"] + assert v.metadata.user is None + +>>>>>>> 38a4b80 (use dataclass rather than dict) def test_vetiver_build(vetiver_client): data = mtcars.head(1).drop(columns="mpg") From 38ac3e2750aabce764de71913f4dcadeba405023 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 6 Dec 2022 19:02:36 -0500 Subject: [PATCH 10/20] update pytorch test --- vetiver/tests/test_pytorch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vetiver/tests/test_pytorch.py b/vetiver/tests/test_pytorch.py index 8e1aa15d..bcfa2e8e 100644 --- a/vetiver/tests/test_pytorch.py +++ b/vetiver/tests/test_pytorch.py @@ -53,7 +53,7 @@ def test_vetiver_build(): ) assert vt2.model == torch_model - assert vt2.metadata.get("required_pkgs") == [f"torch=={torch.__version__}"] + assert vt2.metadata.required_pkgs == [f"torch=={torch.__version__}"] def test_torch_predict_ptype(): From 7a37a3d16b758c5eb60c8e082a7560b968f27a66 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 6 Dec 2022 19:08:55 -0500 Subject: [PATCH 11/20] handle required_pkgs in load_pkgs --- vetiver/attach_pkgs.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/vetiver/attach_pkgs.py b/vetiver/attach_pkgs.py index bf845b2a..401df75c 100644 --- a/vetiver/attach_pkgs.py +++ b/vetiver/attach_pkgs.py @@ -1,6 +1,7 @@ import tempfile import os -from vetiver import VetiverModel +from .vetiver_model import VetiverModel +from vetiver import __version__ as version def load_pkgs(model: VetiverModel = None, packages: list = None, path=""): @@ -16,11 +17,17 @@ def load_pkgs(model: VetiverModel = None, packages: list = None, path=""): Where to save output file """ - required_pkgs = ["vetiver"] + required_pkgs = [f"vetiver=={version}"] if packages: required_pkgs = list(set(required_pkgs + packages)) - if model.metadata.get("required_pkgs"): - required_pkgs = list(set(required_pkgs + model.metadata.get("required_pkgs"))) + try: + if model.metadata.get("required_pkgs"): + required_pkgs = list( + set(required_pkgs + model.metadata.get("required_pkgs")) + ) + except AttributeError: + if model.metadata.required_pkgs: + required_pkgs = list(set(required_pkgs + model.metadata.required_pkgs)) tmp = tempfile.NamedTemporaryFile(suffix=".in", delete=False) tmp.close() From 371428bd088c430692283a10fa5bf76b49097e57 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 6 Dec 2022 19:17:30 -0500 Subject: [PATCH 12/20] removing version from vetiver in attach_pkgs --- vetiver/attach_pkgs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vetiver/attach_pkgs.py b/vetiver/attach_pkgs.py index 401df75c..42a133ba 100644 --- a/vetiver/attach_pkgs.py +++ b/vetiver/attach_pkgs.py @@ -1,7 +1,6 @@ import tempfile import os from .vetiver_model import VetiverModel -from vetiver import __version__ as version def load_pkgs(model: VetiverModel = None, packages: list = None, path=""): @@ -17,7 +16,7 @@ def load_pkgs(model: VetiverModel = None, packages: list = None, path=""): Where to save output file """ - required_pkgs = [f"vetiver=={version}"] + required_pkgs = ["vetiver"] if packages: required_pkgs = list(set(required_pkgs + packages)) try: From 29ac30a6f53cab864479148aa0582a34afacf80f Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Mon, 12 Dec 2022 18:49:09 -0500 Subject: [PATCH 13/20] coerce VetiverMeta rather than try/except --- vetiver/attach_pkgs.py | 15 +++++++-------- vetiver/meta.py | 29 +++++++++++++++++------------ vetiver/pin_read_write.py | 18 ++++++++++++++++++ vetiver/server.py | 20 +++++++------------- vetiver/tests/test_xgboost.py | 2 +- 5 files changed, 50 insertions(+), 34 deletions(-) diff --git a/vetiver/attach_pkgs.py b/vetiver/attach_pkgs.py index 42a133ba..14341d52 100644 --- a/vetiver/attach_pkgs.py +++ b/vetiver/attach_pkgs.py @@ -1,6 +1,7 @@ import tempfile import os from .vetiver_model import VetiverModel +from .meta import VetiverMeta def load_pkgs(model: VetiverModel = None, packages: list = None, path=""): @@ -19,14 +20,12 @@ def load_pkgs(model: VetiverModel = None, packages: list = None, path=""): required_pkgs = ["vetiver"] if packages: required_pkgs = list(set(required_pkgs + packages)) - try: - if model.metadata.get("required_pkgs"): - required_pkgs = list( - set(required_pkgs + model.metadata.get("required_pkgs")) - ) - except AttributeError: - if model.metadata.required_pkgs: - required_pkgs = list(set(required_pkgs + model.metadata.required_pkgs)) + + if isinstance(model.metadata, dict): + model.metadata = VetiverMeta.from_dict(model.metadata) + + if model.metadata.required_pkgs: + required_pkgs = list(set(required_pkgs + model.metadata.required_pkgs)) tmp = tempfile.NamedTemporaryFile(suffix=".in", delete=False) tmp.close() diff --git a/vetiver/meta.py b/vetiver/meta.py index 6cd123bd..2fd75912 100644 --- a/vetiver/meta.py +++ b/vetiver/meta.py @@ -1,25 +1,30 @@ -from dataclasses import dataclass +from dataclasses import dataclass, asdict, field +from typing import Mapping @dataclass class VetiverMeta: """Metadata in a VetiverModel""" - user: "dict | None" = None + user: "dict | None" = field(default_factory=dict) version: "str | None" = None url: "str | None" = None - required_pkgs: "list | None" = None + required_pkgs: "list | None" = field(default_factory=list) + + def to_dict(self) -> Mapping: + data = asdict(self) + + return data @classmethod - def from_dict(cls, metadata, pip_name, pkg) -> "VetiverMeta": - - if metadata: - user = metadata.get("user", metadata) - version = metadata.get("version", None) - url = metadata.get("url", None) - required_pkgs = metadata.get("required_pkgs", []) - else: - user, version, url, required_pkgs = None, None, None, [] + def from_dict(cls, metadata, pip_name=None, pkg=None) -> "VetiverMeta": + + metadata = {} if metadata is None else metadata + + user = metadata.get("user", metadata) + version = metadata.get("version", None) + url = metadata.get("url", None) + required_pkgs = metadata.get("required_pkgs", []) if not list(filter(lambda x: pip_name in x, required_pkgs)): required_pkgs = required_pkgs + [f"{pip_name}=={pkg.__version__}"] diff --git a/vetiver/pin_read_write.py b/vetiver/pin_read_write.py index e0f9658e..8c76f6c9 100644 --- a/vetiver/pin_read_write.py +++ b/vetiver/pin_read_write.py @@ -1,4 +1,5 @@ from .vetiver_model import VetiverModel +from .meta import VetiverMeta from .utils import inform import warnings import logging @@ -50,10 +51,16 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): "reporting. \n Use the vetiver `.qmd` Quarto template as a place to start, \n " "with vetiver.model_card()", ) +<<<<<<< HEAD # convert older model's ptype to prototype if hasattr(model, "ptype"): model.prototype = model.ptype +======= + # metadata is dict + if isinstance(model.metadata, dict): + model.metadata = VetiverMeta.from_dict(model.metadata) +>>>>>>> bfe7205 (coerce VetiverMeta rather than try/except) board.pin_write( model.model, @@ -61,6 +68,7 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): type="joblib", description=model.description, metadata={ +<<<<<<< HEAD "user": model.metadata.get("user"), "vetiver_meta": { "required_pkgs": model.metadata.get("required_pkgs"), @@ -69,6 +77,16 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): versioned=versioned, ) # metadata is VetiverMeta +======= + "user": model.metadata.user, + "vetiver_meta": { + "required_pkgs": model.metadata.required_pkgs, + "ptype": None if model.ptype is None else model.ptype().json(), + }, + }, + versioned=versioned, + ) +>>>>>>> bfe7205 (coerce VetiverMeta rather than try/except) def vetiver_pin_read(board, name: str, version: str = None) -> VetiverModel: diff --git a/vetiver/server.py b/vetiver/server.py index a8e307a6..9d148916 100644 --- a/vetiver/server.py +++ b/vetiver/server.py @@ -12,6 +12,7 @@ from .utils import _jupyter_nb from .vetiver_model import VetiverModel +from .meta import VetiverMeta class VetiverAPI: @@ -82,21 +83,14 @@ def docs_redirect(): return RedirectResponse(redirect) - # metadata is a dict - try: - if self.model.metadata.get("url") is not None: + if isinstance(self.model.metadata, dict): + self.model.metadata = VetiverMeta.from_dict(self.model.metadata) - @app.get("/pin-url") - def pin_url(): - return repr(self.model.get("url")) + if self.model.metadata.url is not None: - # metadata is type VetiverMeta - except AttributeError: - if self.model.metadata.url is not None: - - @app.get("/pin-url") - def pin_url(): - return repr(self.model.metadata.url) + @app.get("/pin-url") + def pin_url(): + return repr(self.model.metadata.url) @app.get("/ping", include_in_schema=True) async def ping(): diff --git a/vetiver/tests/test_xgboost.py b/vetiver/tests/test_xgboost.py index e42bd384..436410af 100644 --- a/vetiver/tests/test_xgboost.py +++ b/vetiver/tests/test_xgboost.py @@ -51,7 +51,7 @@ def test_model(xgb_model): v = xgb_model assert v.metadata.required_pkgs == [f"xgboost=={xgb.__version__}"] - assert v.metadata.user is None + assert not v.metadata.user >>>>>>> 38a4b80 (use dataclass rather than dict) From 517a42ce44d6acf387296044e0a273817a4cf586 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Mon, 12 Dec 2022 19:51:28 -0500 Subject: [PATCH 14/20] remove version pinning from model pkgs --- vetiver/handlers/base.py | 12 +++++++--- vetiver/handlers/sklearn.py | 6 ----- vetiver/handlers/statsmodels.py | 1 - vetiver/handlers/torch.py | 1 - vetiver/handlers/xgboost.py | 1 - vetiver/meta.py | 7 +++--- vetiver/tests/test_build_vetiver_model.py | 29 ++++------------------- vetiver/tests/test_custom_handler.py | 6 ++--- vetiver/tests/test_pytorch.py | 2 +- vetiver/tests/test_sklearn.py | 3 +-- vetiver/tests/test_xgboost.py | 2 +- vetiver/vetiver_model.py | 2 +- 12 files changed, 24 insertions(+), 48 deletions(-) diff --git a/vetiver/handlers/base.py b/vetiver/handlers/base.py index bfd563f2..82772977 100644 --- a/vetiver/handlers/base.py +++ b/vetiver/handlers/base.py @@ -43,7 +43,7 @@ def create_handler(model, prototype_data): >>> model = vetiver.mock.get_mock_model() >>> handler = vetiver.create_handler(model, X) >>> handler.describe() - "Scikit-learn model" + 'A scikit-learn DummyRegressor model' """ raise InvalidModelError( @@ -79,14 +79,20 @@ def __init__(self, model, prototype_data): def describe(self): """Create description for model""" + + pip_name = self.pip_name if hasattr(self, "pip_name") else "" obj_name = type(self.model).__qualname__ - desc = f"A {self.pip_name} {obj_name} model" + + desc = f"A {pip_name} {obj_name} model" + return desc def create_meta(self, metadata): """Create metadata for a model""" - return VetiverMeta.from_dict(metadata, self.pip_name, self.pkg) + pip_name = self.pip_name if hasattr(self, "pip_name") else None + + return VetiverMeta.from_dict(metadata, pip_name) def construct_prototype(self): """Create data prototype for a model diff --git a/vetiver/handlers/sklearn.py b/vetiver/handlers/sklearn.py index 7066e3b7..27c7d847 100644 --- a/vetiver/handlers/sklearn.py +++ b/vetiver/handlers/sklearn.py @@ -15,12 +15,6 @@ class SKLearnHandler(BaseHandler): model_class = staticmethod(lambda: sklearn.base.BaseEstimator) pip_name = "scikit-learn" - pkg = sklearn - - def describe(self): - """Create description for sklearn model""" - desc = f"Scikit-learn {self.model.__class__} model" - return desc def handler_predict(self, input_data, check_ptype): """Generates method for /predict endpoint in VetiverAPI diff --git a/vetiver/handlers/statsmodels.py b/vetiver/handlers/statsmodels.py index 6edb4d0b..6888338b 100644 --- a/vetiver/handlers/statsmodels.py +++ b/vetiver/handlers/statsmodels.py @@ -20,7 +20,6 @@ class StatsmodelsHandler(BaseHandler): model_class = staticmethod(lambda: statsmodels.base.wrapper.ResultsWrapper) if sm_exists: - pkg = statsmodels pip_name = "statsmodels" def handler_predict(self, input_data, check_prototype): diff --git a/vetiver/handlers/torch.py b/vetiver/handlers/torch.py index fe968643..13b37888 100644 --- a/vetiver/handlers/torch.py +++ b/vetiver/handlers/torch.py @@ -20,7 +20,6 @@ class TorchHandler(BaseHandler): model_class = staticmethod(lambda: torch.nn.Module) if torch_exists: - pkg = torch pip_name = "torch" def handler_predict(self, input_data, check_prototype): diff --git a/vetiver/handlers/xgboost.py b/vetiver/handlers/xgboost.py index ee058832..f8c5b2e3 100644 --- a/vetiver/handlers/xgboost.py +++ b/vetiver/handlers/xgboost.py @@ -20,7 +20,6 @@ class XGBoostHandler(BaseHandler): model_class = staticmethod(lambda: xgboost.Booster) if xgb_exists: - pkg = xgboost pip_name = "xgboost" def handler_predict(self, input_data, check_prototype): diff --git a/vetiver/meta.py b/vetiver/meta.py index 2fd75912..c6e052c1 100644 --- a/vetiver/meta.py +++ b/vetiver/meta.py @@ -17,7 +17,7 @@ def to_dict(self) -> Mapping: return data @classmethod - def from_dict(cls, metadata, pip_name=None, pkg=None) -> "VetiverMeta": + def from_dict(cls, metadata, pip_name) -> "VetiverMeta": metadata = {} if metadata is None else metadata @@ -26,7 +26,8 @@ def from_dict(cls, metadata, pip_name=None, pkg=None) -> "VetiverMeta": url = metadata.get("url", None) required_pkgs = metadata.get("required_pkgs", []) - if not list(filter(lambda x: pip_name in x, required_pkgs)): - required_pkgs = required_pkgs + [f"{pip_name}=={pkg.__version__}"] + if pip_name: + if not list(filter(lambda x: pip_name in x, required_pkgs)): + required_pkgs = required_pkgs + [f"{pip_name}"] return cls(user, version, url, required_pkgs) diff --git a/vetiver/tests/test_build_vetiver_model.py b/vetiver/tests/test_build_vetiver_model.py index dae6ca00..22954db9 100644 --- a/vetiver/tests/test_build_vetiver_model.py +++ b/vetiver/tests/test_build_vetiver_model.py @@ -106,27 +106,14 @@ def test_vetiver_model_use_ptype(): metadata={"test": 123}, ) -<<<<<<< HEAD assert vt5.model == model - assert isinstance(vt5.prototype.construct(), pydantic.BaseModel) - assert list(vt5.prototype.__fields__.values())[0].type_ == int - assert vt4.prototype is None - assert vt4.metadata == { - "user": {"test": 123}, - "version": None, - "url": None, - "required_pkgs": [f"scikit-learn=={sklearn.__version__}"], - } -======= - assert vt4.model == model - assert vt4.ptype is None - assert vt4.metadata == VetiverMeta( + assert vt5.ptype is None + assert vt5.metadata == VetiverMeta( user={"test": 123}, version=None, url=None, - required_pkgs=[f"scikit-learn=={sklearn.__version__}"], + required_pkgs=["scikit-learn"], ) ->>>>>>> 38a4b80 (use dataclass rather than dict) def test_vetiver_model_from_pin(): @@ -146,15 +133,9 @@ def test_vetiver_model_from_pin(): assert isinstance(v2, vt.VetiverModel) assert isinstance(v2.model, sklearn.base.BaseEstimator) -<<<<<<< HEAD assert isinstance(v2.prototype.construct(), pydantic.BaseModel) assert v2.metadata.get("user") == {"test": 123} assert v2.metadata.get("version") is not None -======= - assert isinstance(v2.ptype.construct(), pydantic.BaseModel) - assert v2.metadata.user == {"test": 123} - assert v2.metadata.version is not None - assert v2.metadata.required_pkgs == [f"scikit-learn=={sklearn.__version__}"] ->>>>>>> 38a4b80 (use dataclass rather than dict) - + assert v2.metadata.required_pkgs == ["scikit-learn"] + board.pin_delete("model") diff --git a/vetiver/tests/test_custom_handler.py b/vetiver/tests/test_custom_handler.py index 821711d7..f08ac551 100644 --- a/vetiver/tests/test_custom_handler.py +++ b/vetiver/tests/test_custom_handler.py @@ -10,8 +10,6 @@ def __init__(self, model, prototype_data): super().__init__(model, prototype_data) model_type = staticmethod(lambda: sklearn.dummy.DummyRegressor) - pkg = pd # random non modeling package chosen for init purposes - pip_name = "random_pkg" def handler_predict(self, input_data, check_ptype): if check_ptype is True: @@ -39,8 +37,8 @@ def test_custom_vetiver_model(): versioned=None, ) - assert v.description == "A random_pkg DummyRegressor model" - assert v.metadata.required_pkgs == [f"random_pkg=={pd.__version__}"] + assert v.description == "A DummyRegressor model" + assert not v.metadata.required_pkgs assert isinstance(v.model, sklearn.dummy.DummyRegressor) assert isinstance(v.prototype.construct(), pydantic.BaseModel) diff --git a/vetiver/tests/test_pytorch.py b/vetiver/tests/test_pytorch.py index bcfa2e8e..11c7ab4f 100644 --- a/vetiver/tests/test_pytorch.py +++ b/vetiver/tests/test_pytorch.py @@ -53,7 +53,7 @@ def test_vetiver_build(): ) assert vt2.model == torch_model - assert vt2.metadata.required_pkgs == [f"torch=={torch.__version__}"] + assert vt2.metadata.required_pkgs == ["torch"] def test_torch_predict_ptype(): diff --git a/vetiver/tests/test_sklearn.py b/vetiver/tests/test_sklearn.py index cc77868e..0d03c026 100644 --- a/vetiver/tests/test_sklearn.py +++ b/vetiver/tests/test_sklearn.py @@ -2,7 +2,6 @@ from fastapi.testclient import TestClient import numpy as np import pytest -import sklearn def _start_application(save_prototype: bool = True): @@ -31,7 +30,7 @@ def test_build_sklearn(): description="A regression model for testing purposes", ) - assert v.metadata.required_pkgs == [f"scikit-learn=={sklearn.__version__}"] + assert v.metadata.required_pkgs == ["scikit-learn"] def test_predict_endpoint_ptype(): diff --git a/vetiver/tests/test_xgboost.py b/vetiver/tests/test_xgboost.py index 436410af..e8c9bf52 100644 --- a/vetiver/tests/test_xgboost.py +++ b/vetiver/tests/test_xgboost.py @@ -50,7 +50,7 @@ def vetiver_client_check_ptype_false(xgb_model): # With check_prototype=True def test_model(xgb_model): v = xgb_model - assert v.metadata.required_pkgs == [f"xgboost=={xgb.__version__}"] + assert v.metadata.required_pkgs == ["xgboost"] assert not v.metadata.user >>>>>>> 38a4b80 (use dataclass rather than dict) diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index 06ce7b7d..9e093235 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -61,7 +61,7 @@ class VetiverModel: >>> model = mock.get_mock_model().fit(X, y) >>> v = VetiverModel(model = model, model_name = "my_model", prototype_data = X) >>> v.description - "Scikit-learn model" + 'A scikit-learn DummyRegressor model' """ def __init__( From 1a3a796f82877dd7dcbb2cefe44978f2aa771c9c Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 13 Dec 2022 09:47:51 -0500 Subject: [PATCH 15/20] update tests --- script/setup-docker/docker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/setup-docker/docker.py b/script/setup-docker/docker.py index 50ba36ae..57fd5eb5 100644 --- a/script/setup-docker/docker.py +++ b/script/setup-docker/docker.py @@ -9,7 +9,7 @@ board = pins.board_folder("pinsboard", allow_pickle_read=True) -v = vetiver.VetiverModel(model, "mymodel", ptype_data=X) +v = vetiver.VetiverModel(model, "mymodel", prototype_data=X) vetiver.vetiver_pin_write(board, v) From f49cb355da72b464ecc07ce63d0da4bec658ad80 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 13 Dec 2022 13:20:13 -0500 Subject: [PATCH 16/20] install into docker from branch --- script/setup-docker/docker.py | 12 +++++++++++- vetiver/meta.py | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/script/setup-docker/docker.py b/script/setup-docker/docker.py index 57fd5eb5..55a99c61 100644 --- a/script/setup-docker/docker.py +++ b/script/setup-docker/docker.py @@ -9,8 +9,18 @@ board = pins.board_folder("pinsboard", allow_pickle_read=True) -v = vetiver.VetiverModel(model, "mymodel", prototype_data=X) +v = vetiver.VetiverModel(model, "mymodel", ptype_data=X) vetiver.vetiver_pin_write(board, v) +<<<<<<< HEAD vetiver.prepare_docker(board, "mymodel") +======= +vetiver.load_pkgs( + v, + packages=["git+https://github.com/rstudio/vetiver-python@metadata"], + path="vetiver_", +) +vetiver.write_app(board, "mymodel") +vetiver.write_docker() +>>>>>>> 875faf2 (install into docker from branch) diff --git a/vetiver/meta.py b/vetiver/meta.py index c6e052c1..d2a10f93 100644 --- a/vetiver/meta.py +++ b/vetiver/meta.py @@ -17,7 +17,7 @@ def to_dict(self) -> Mapping: return data @classmethod - def from_dict(cls, metadata, pip_name) -> "VetiverMeta": + def from_dict(cls, metadata, pip_name=None) -> "VetiverMeta": metadata = {} if metadata is None else metadata From da0e9adaca82c49c8532c6f05ea06a4c878d41a6 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 13 Dec 2022 13:41:44 -0500 Subject: [PATCH 17/20] always install latest vetiver in docker --- .github/workflows/tests.yml | 8 ++++++++ script/setup-docker/docker.py | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4d8febf2..4f1adb8a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -78,12 +78,20 @@ jobs: python-version: 3.8 - name: Install dependencies run: | +<<<<<<< HEAD +======= + python -m pip install --upgrade pip +>>>>>>> aa70c3e (always install latest vetiver in docker) python -m pip install ".[dev]" python -m pip install --upgrade git+https://github.com/rstudio/vetiver-python@${{ github.sha }} - name: run Docker run: | python script/setup-docker/docker.py +<<<<<<< HEAD pip freeze > vetiver_requirements.txt +======= + pip freeze > requirements.txt +>>>>>>> aa70c3e (always install latest vetiver in docker) docker build -t mock . docker run -d -v $PWD/pinsboard:/vetiver/pinsboard -p 8080:8080 mock sleep 5 diff --git a/script/setup-docker/docker.py b/script/setup-docker/docker.py index 55a99c61..3009baad 100644 --- a/script/setup-docker/docker.py +++ b/script/setup-docker/docker.py @@ -13,6 +13,7 @@ vetiver.vetiver_pin_write(board, v) <<<<<<< HEAD +<<<<<<< HEAD vetiver.prepare_docker(board, "mymodel") ======= @@ -21,6 +22,9 @@ packages=["git+https://github.com/rstudio/vetiver-python@metadata"], path="vetiver_", ) +======= +vetiver.load_pkgs(v, path="vetiver_") +>>>>>>> aa70c3e (always install latest vetiver in docker) vetiver.write_app(board, "mymodel") vetiver.write_docker() >>>>>>> 875faf2 (install into docker from branch) From 982251eb43221d6800849848f86e9dae4f197e75 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Tue, 13 Dec 2022 13:45:48 -0500 Subject: [PATCH 18/20] refactoring docker test again --- .github/workflows/tests.yml | 4 ++++ script/setup-docker/docker.py | 15 +-------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4f1adb8a..d8950adc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -87,11 +87,15 @@ jobs: - name: run Docker run: | python script/setup-docker/docker.py +<<<<<<< HEAD <<<<<<< HEAD pip freeze > vetiver_requirements.txt ======= pip freeze > requirements.txt >>>>>>> aa70c3e (always install latest vetiver in docker) +======= + pip freeze > vetiver_requirements.txt +>>>>>>> 3edaa19 (refactoring docker test again) docker build -t mock . docker run -d -v $PWD/pinsboard:/vetiver/pinsboard -p 8080:8080 mock sleep 5 diff --git a/script/setup-docker/docker.py b/script/setup-docker/docker.py index 3009baad..b0738d38 100644 --- a/script/setup-docker/docker.py +++ b/script/setup-docker/docker.py @@ -12,19 +12,6 @@ v = vetiver.VetiverModel(model, "mymodel", ptype_data=X) vetiver.vetiver_pin_write(board, v) -<<<<<<< HEAD -<<<<<<< HEAD + vetiver.prepare_docker(board, "mymodel") -======= -vetiver.load_pkgs( - v, - packages=["git+https://github.com/rstudio/vetiver-python@metadata"], - path="vetiver_", -) -======= -vetiver.load_pkgs(v, path="vetiver_") ->>>>>>> aa70c3e (always install latest vetiver in docker) -vetiver.write_app(board, "mymodel") -vetiver.write_docker() ->>>>>>> 875faf2 (install into docker from branch) From 748624ec342209964efb2710c8470529ddc1c1e6 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Mon, 19 Dec 2022 12:06:39 -0600 Subject: [PATCH 19/20] merge conflicts --- .github/workflows/tests.yml | 11 ----------- vetiver/pin_read_write.py | 16 +--------------- vetiver/tests/test_xgboost.py | 3 --- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d8950adc..fd2525b6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -78,24 +78,13 @@ jobs: python-version: 3.8 - name: Install dependencies run: | -<<<<<<< HEAD -======= python -m pip install --upgrade pip ->>>>>>> aa70c3e (always install latest vetiver in docker) python -m pip install ".[dev]" python -m pip install --upgrade git+https://github.com/rstudio/vetiver-python@${{ github.sha }} - name: run Docker run: | python script/setup-docker/docker.py -<<<<<<< HEAD -<<<<<<< HEAD pip freeze > vetiver_requirements.txt -======= - pip freeze > requirements.txt ->>>>>>> aa70c3e (always install latest vetiver in docker) -======= - pip freeze > vetiver_requirements.txt ->>>>>>> 3edaa19 (refactoring docker test again) docker build -t mock . docker run -d -v $PWD/pinsboard:/vetiver/pinsboard -p 8080:8080 mock sleep 5 diff --git a/vetiver/pin_read_write.py b/vetiver/pin_read_write.py index 8c76f6c9..8f89b08b 100644 --- a/vetiver/pin_read_write.py +++ b/vetiver/pin_read_write.py @@ -51,16 +51,13 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): "reporting. \n Use the vetiver `.qmd` Quarto template as a place to start, \n " "with vetiver.model_card()", ) -<<<<<<< HEAD # convert older model's ptype to prototype if hasattr(model, "ptype"): model.prototype = model.ptype -======= # metadata is dict if isinstance(model.metadata, dict): model.metadata = VetiverMeta.from_dict(model.metadata) ->>>>>>> bfe7205 (coerce VetiverMeta rather than try/except) board.pin_write( model.model, @@ -68,25 +65,14 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): type="joblib", description=model.description, metadata={ -<<<<<<< HEAD - "user": model.metadata.get("user"), - "vetiver_meta": { - "required_pkgs": model.metadata.get("required_pkgs"), - "prototype": None if model.prototype is None else model.prototype().json(), - }, - versioned=versioned, - ) - # metadata is VetiverMeta -======= "user": model.metadata.user, "vetiver_meta": { "required_pkgs": model.metadata.required_pkgs, - "ptype": None if model.ptype is None else model.ptype().json(), + "ptype": None if model.prototype is None else model.prototype().json(), }, }, versioned=versioned, ) ->>>>>>> bfe7205 (coerce VetiverMeta rather than try/except) def vetiver_pin_read(board, name: str, version: str = None) -> VetiverModel: diff --git a/vetiver/tests/test_xgboost.py b/vetiver/tests/test_xgboost.py index e8c9bf52..425898ab 100644 --- a/vetiver/tests/test_xgboost.py +++ b/vetiver/tests/test_xgboost.py @@ -44,8 +44,6 @@ def vetiver_client_check_ptype_false(xgb_model): # With check_prototype=True return client -<<<<<<< HEAD -======= def test_model(xgb_model): v = xgb_model @@ -53,7 +51,6 @@ def test_model(xgb_model): assert v.metadata.required_pkgs == ["xgboost"] assert not v.metadata.user ->>>>>>> 38a4b80 (use dataclass rather than dict) def test_vetiver_build(vetiver_client): data = mtcars.head(1).drop(columns="mpg") From 2c83fa49f2a9db3a19a2e5156938afa1f4d033d2 Mon Sep 17 00:00:00 2001 From: isabelizimm Date: Mon, 19 Dec 2022 15:52:12 -0600 Subject: [PATCH 20/20] refactor metadata w prototypes --- docs/source/advancedusage/custom_handler.md | 1 - script/setup-docker/docker.py | 1 - vetiver/handlers/sklearn.py | 2 +- vetiver/pin_read_write.py | 3 ++- vetiver/tests/test_build_vetiver_model.py | 10 +++++----- vetiver/vetiver_model.py | 13 ++++++++++--- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/source/advancedusage/custom_handler.md b/docs/source/advancedusage/custom_handler.md index 62e28172..9009f403 100644 --- a/docs/source/advancedusage/custom_handler.md +++ b/docs/source/advancedusage/custom_handler.md @@ -12,7 +12,6 @@ class CustomHandler(BaseHandler): super().__init__(model, ptype_data) model_type = staticmethod(lambda: newmodeltype) - pkg = sklearn # modeling package pip_name = "scikit-learn" # pkg name on pip, used for tracking pkg versions def handler_predict(self, input_data, check_ptype: bool): diff --git a/script/setup-docker/docker.py b/script/setup-docker/docker.py index b0738d38..50ba36ae 100644 --- a/script/setup-docker/docker.py +++ b/script/setup-docker/docker.py @@ -13,5 +13,4 @@ vetiver.vetiver_pin_write(board, v) - vetiver.prepare_docker(board, "mymodel") diff --git a/vetiver/handlers/sklearn.py b/vetiver/handlers/sklearn.py index 27c7d847..774f2b3b 100644 --- a/vetiver/handlers/sklearn.py +++ b/vetiver/handlers/sklearn.py @@ -16,7 +16,7 @@ class SKLearnHandler(BaseHandler): model_class = staticmethod(lambda: sklearn.base.BaseEstimator) pip_name = "scikit-learn" - def handler_predict(self, input_data, check_ptype): + def handler_predict(self, input_data, check_prototype): """Generates method for /predict endpoint in VetiverAPI The `handler_predict` function executes at each API call. Use this diff --git a/vetiver/pin_read_write.py b/vetiver/pin_read_write.py index 8f89b08b..42c8c216 100644 --- a/vetiver/pin_read_write.py +++ b/vetiver/pin_read_write.py @@ -55,6 +55,7 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): # convert older model's ptype to prototype if hasattr(model, "ptype"): model.prototype = model.ptype + delattr(model, "ptype") # metadata is dict if isinstance(model.metadata, dict): model.metadata = VetiverMeta.from_dict(model.metadata) @@ -68,7 +69,7 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True): "user": model.metadata.user, "vetiver_meta": { "required_pkgs": model.metadata.required_pkgs, - "ptype": None if model.prototype is None else model.prototype().json(), + "prototype": None if not model.prototype else model.prototype().json(), }, }, versioned=versioned, diff --git a/vetiver/tests/test_build_vetiver_model.py b/vetiver/tests/test_build_vetiver_model.py index 22954db9..2832ea0c 100644 --- a/vetiver/tests/test_build_vetiver_model.py +++ b/vetiver/tests/test_build_vetiver_model.py @@ -75,7 +75,7 @@ def test_vetiver_model_basemodel_prototype(): prototype_data=m, model_name="model", versioned=False, - description=None + description=None, ) assert vt4.model == model @@ -107,7 +107,7 @@ def test_vetiver_model_use_ptype(): ) assert vt5.model == model - assert vt5.ptype is None + assert vt5.prototype is None assert vt5.metadata == VetiverMeta( user={"test": 123}, version=None, @@ -134,8 +134,8 @@ def test_vetiver_model_from_pin(): assert isinstance(v2, vt.VetiverModel) assert isinstance(v2.model, sklearn.base.BaseEstimator) assert isinstance(v2.prototype.construct(), pydantic.BaseModel) - assert v2.metadata.get("user") == {"test": 123} - assert v2.metadata.get("version") is not None + assert v2.metadata.user == {"test": 123} + assert v2.metadata.version is not None assert v2.metadata.required_pkgs == ["scikit-learn"] - + board.pin_delete("model") diff --git a/vetiver/vetiver_model.py b/vetiver/vetiver_model.py index 9e093235..f01e7a3f 100644 --- a/vetiver/vetiver_model.py +++ b/vetiver/vetiver_model.py @@ -100,11 +100,18 @@ def from_pin(cls, board, name: str, version: str = None): meta = board.pin_meta(name, version) if "vetiver_meta" in meta.user: - ptype = meta.user.get("vetiver_meta").get("prototype") - required_pkgs = meta.user.get("vetiver_meta").get("required_pkgs") + get_prototype = meta.user.get("vetiver_meta").get("prototype", None) + required_pkgs = meta.user.get("vetiver_meta").get("required_pkgs", None) meta.user.pop("vetiver_meta") else: - ptype = meta.user.get("ptype", None) + # ptype = meta.user.get("ptype", None) + + get_prototype = meta.user.get("ptype") + # elif meta.user.get("prototype"): + # get_prototype = meta.user.get("prototype") + # else: + # get_prototype = None + required_pkgs = meta.user.get("required_pkgs") return cls(