wallaroo.model_config
1from typing import TYPE_CHECKING, List, cast 2 3from .object import * 4 5if TYPE_CHECKING: 6 # Imports that happen below in methods to fix circular import dependency 7 # issues need to also be specified here to satisfy mypy type checking. 8 from .client import Client 9 from .model import Model 10 11import gql # type: ignore 12import yaml 13 14 15class ModelConfig(Object): 16 """Wraps a backend ModelConfig object.""" 17 18 def __init__( 19 self, client: Optional["Client"], data: Dict[str, Any], standalone=False 20 ) -> None: 21 self.client = client 22 super().__init__( 23 gql_client=client._gql_client if client is not None else None, 24 data=data, 25 standalone=standalone, 26 ) 27 28 @staticmethod 29 def as_standalone( 30 model: "Model", 31 filter_threshold: Optional[float] = None, 32 runtime: Optional[str] = None, 33 tensor_fields: Optional[List[str]] = None, 34 ) -> "ModelConfig": 35 """Creates a ModelConfig intended for use in generating standalone configurations""" 36 constructor_dict = { 37 "id": -1, 38 "model": model, 39 "filter_threshold": filter_threshold, 40 "runtime": runtime, 41 "tensor_fields": tensor_fields, 42 } 43 return ModelConfig(None, data=constructor_dict, standalone=True) 44 45 @property 46 def inputs(self): 47 return self.model().inputs 48 49 @property 50 def outputs(self): 51 return self.model().outputs 52 53 def to_yaml(self): 54 """Generates a yaml file for standalone engines""" 55 extra = { 56 "model_id": self.model().name(), 57 "model_version": self.model().version(), 58 } 59 return self._yaml(extra) 60 61 def to_k8s_yaml(self): 62 # XXX - the deployment manager currently stitches this together 63 extra = { 64 "name": self.model().name(), 65 "version": self.model().version(), 66 "sha": self.model().sha(), 67 } 68 return self._yaml(extra) 69 70 def _yaml(self, yaml_dict): 71 if self.filter_threshold(): 72 yaml_dict["filter_threshold"] = self.filter_threshold() 73 if self.runtime(): 74 yaml_dict["runtime"] = self.runtime() 75 if self.tensor_fields(): 76 yaml_dict["tensor_fields"] = self.tensor_fields() 77 if type(self._input_schema) == str: 78 yaml_dict["input_schema"] = self._input_schema 79 if type(self._output_schema) == str: 80 yaml_dict["output_schema"] = self._output_schema 81 return yaml.dump(yaml_dict) 82 83 def _fill(self, data: Dict[str, Any]) -> None: 84 """Fills an object given a response dictionary from the GraphQL API. 85 86 Only the primary key member must be present; other members will be 87 filled in via rehydration if their corresponding member function is 88 called. 89 """ 90 from .model import Model # Avoids circular imports 91 92 for required_attribute in ["id"]: 93 if required_attribute not in data: 94 raise RequiredAttributeMissing( 95 self.__class__.__name__, required_attribute 96 ) 97 # Required 98 self._id = data["id"] 99 100 # Optional 101 self._filter_threshold = value_if_present(data, "filter_threshold") 102 self._model = ( 103 ( 104 data["model"] 105 if isinstance(data["model"], Model) 106 else Model( 107 client=self.client, 108 data=data["model"], 109 standalone=self._standalone, 110 ) 111 ) 112 if "model" in data 113 else DehydratedValue() 114 ) 115 self._runtime = value_if_present(data, "runtime") 116 self._tensor_fields = value_if_present(data, "tensor_fields") 117 self._input_schema = value_if_present(data, "input_schema") 118 self._output_schema = value_if_present(data, "output_schema") 119 120 def _fetch_attributes(self) -> Dict[str, Any]: 121 """Fetches all member data from the GraphQL API.""" 122 assert self.client is not None 123 return self.client._gql_client.execute( 124 gql.gql( 125 """ 126 query ModelConfigById($model_config_id: bigint!) { 127 model_config_by_pk(id: $model_config_id) { 128 id 129 filter_threshold 130 model { 131 id 132 } 133 runtime 134 tensor_fields 135 } 136 } 137 """ 138 ), 139 variable_values={ 140 "model_config_id": self._id, 141 }, 142 )["model_config_by_pk"] 143 144 def id(self) -> int: 145 return self._id 146 147 @rehydrate("_filter_threshold") 148 def filter_threshold(self) -> float: 149 return cast(float, self._filter_threshold) 150 151 @rehydrate("_model") 152 def model(self) -> "Model": 153 from .model import Model # Avoids circular imports 154 155 return cast(Model, self._model) 156 157 @rehydrate("_runtime") 158 def runtime(self) -> str: 159 return cast(str, self._runtime) 160 161 @rehydrate("_tensor_fields") 162 def tensor_fields(self) -> List[str]: 163 return cast(List[str], self._tensor_fields)
16class ModelConfig(Object): 17 """Wraps a backend ModelConfig object.""" 18 19 def __init__( 20 self, client: Optional["Client"], data: Dict[str, Any], standalone=False 21 ) -> None: 22 self.client = client 23 super().__init__( 24 gql_client=client._gql_client if client is not None else None, 25 data=data, 26 standalone=standalone, 27 ) 28 29 @staticmethod 30 def as_standalone( 31 model: "Model", 32 filter_threshold: Optional[float] = None, 33 runtime: Optional[str] = None, 34 tensor_fields: Optional[List[str]] = None, 35 ) -> "ModelConfig": 36 """Creates a ModelConfig intended for use in generating standalone configurations""" 37 constructor_dict = { 38 "id": -1, 39 "model": model, 40 "filter_threshold": filter_threshold, 41 "runtime": runtime, 42 "tensor_fields": tensor_fields, 43 } 44 return ModelConfig(None, data=constructor_dict, standalone=True) 45 46 @property 47 def inputs(self): 48 return self.model().inputs 49 50 @property 51 def outputs(self): 52 return self.model().outputs 53 54 def to_yaml(self): 55 """Generates a yaml file for standalone engines""" 56 extra = { 57 "model_id": self.model().name(), 58 "model_version": self.model().version(), 59 } 60 return self._yaml(extra) 61 62 def to_k8s_yaml(self): 63 # XXX - the deployment manager currently stitches this together 64 extra = { 65 "name": self.model().name(), 66 "version": self.model().version(), 67 "sha": self.model().sha(), 68 } 69 return self._yaml(extra) 70 71 def _yaml(self, yaml_dict): 72 if self.filter_threshold(): 73 yaml_dict["filter_threshold"] = self.filter_threshold() 74 if self.runtime(): 75 yaml_dict["runtime"] = self.runtime() 76 if self.tensor_fields(): 77 yaml_dict["tensor_fields"] = self.tensor_fields() 78 if type(self._input_schema) == str: 79 yaml_dict["input_schema"] = self._input_schema 80 if type(self._output_schema) == str: 81 yaml_dict["output_schema"] = self._output_schema 82 return yaml.dump(yaml_dict) 83 84 def _fill(self, data: Dict[str, Any]) -> None: 85 """Fills an object given a response dictionary from the GraphQL API. 86 87 Only the primary key member must be present; other members will be 88 filled in via rehydration if their corresponding member function is 89 called. 90 """ 91 from .model import Model # Avoids circular imports 92 93 for required_attribute in ["id"]: 94 if required_attribute not in data: 95 raise RequiredAttributeMissing( 96 self.__class__.__name__, required_attribute 97 ) 98 # Required 99 self._id = data["id"] 100 101 # Optional 102 self._filter_threshold = value_if_present(data, "filter_threshold") 103 self._model = ( 104 ( 105 data["model"] 106 if isinstance(data["model"], Model) 107 else Model( 108 client=self.client, 109 data=data["model"], 110 standalone=self._standalone, 111 ) 112 ) 113 if "model" in data 114 else DehydratedValue() 115 ) 116 self._runtime = value_if_present(data, "runtime") 117 self._tensor_fields = value_if_present(data, "tensor_fields") 118 self._input_schema = value_if_present(data, "input_schema") 119 self._output_schema = value_if_present(data, "output_schema") 120 121 def _fetch_attributes(self) -> Dict[str, Any]: 122 """Fetches all member data from the GraphQL API.""" 123 assert self.client is not None 124 return self.client._gql_client.execute( 125 gql.gql( 126 """ 127 query ModelConfigById($model_config_id: bigint!) { 128 model_config_by_pk(id: $model_config_id) { 129 id 130 filter_threshold 131 model { 132 id 133 } 134 runtime 135 tensor_fields 136 } 137 } 138 """ 139 ), 140 variable_values={ 141 "model_config_id": self._id, 142 }, 143 )["model_config_by_pk"] 144 145 def id(self) -> int: 146 return self._id 147 148 @rehydrate("_filter_threshold") 149 def filter_threshold(self) -> float: 150 return cast(float, self._filter_threshold) 151 152 @rehydrate("_model") 153 def model(self) -> "Model": 154 from .model import Model # Avoids circular imports 155 156 return cast(Model, self._model) 157 158 @rehydrate("_runtime") 159 def runtime(self) -> str: 160 return cast(str, self._runtime) 161 162 @rehydrate("_tensor_fields") 163 def tensor_fields(self) -> List[str]: 164 return cast(List[str], self._tensor_fields)
Wraps a backend ModelConfig object.
ModelConfig( client: Optional[wallaroo.client.Client], data: Dict[str, Any], standalone=False)
19 def __init__( 20 self, client: Optional["Client"], data: Dict[str, Any], standalone=False 21 ) -> None: 22 self.client = client 23 super().__init__( 24 gql_client=client._gql_client if client is not None else None, 25 data=data, 26 standalone=standalone, 27 )
Base constructor.
Each object requires:
- a GraphQL client - in order to fill its missing members dynamically
- an initial data blob - typically from unserialized JSON, contains at
- least the data for required members (typically the object's primary key) and optionally other data members.
@staticmethod
def
as_standalone( model: wallaroo.model.Model, filter_threshold: Optional[float] = None, runtime: Optional[str] = None, tensor_fields: Optional[List[str]] = None) -> wallaroo.model_config.ModelConfig:
29 @staticmethod 30 def as_standalone( 31 model: "Model", 32 filter_threshold: Optional[float] = None, 33 runtime: Optional[str] = None, 34 tensor_fields: Optional[List[str]] = None, 35 ) -> "ModelConfig": 36 """Creates a ModelConfig intended for use in generating standalone configurations""" 37 constructor_dict = { 38 "id": -1, 39 "model": model, 40 "filter_threshold": filter_threshold, 41 "runtime": runtime, 42 "tensor_fields": tensor_fields, 43 } 44 return ModelConfig(None, data=constructor_dict, standalone=True)
Creates a ModelConfig intended for use in generating standalone configurations
def
to_yaml(self):
54 def to_yaml(self): 55 """Generates a yaml file for standalone engines""" 56 extra = { 57 "model_id": self.model().name(), 58 "model_version": self.model().version(), 59 } 60 return self._yaml(extra)
Generates a yaml file for standalone engines
def
filter_threshold(*args, **kwargs):
41 def wrapper(*args, **kwargs): 42 obj = args[0] 43 if not getattr(obj, "_standalone", None): 44 present = getattr(obj, attr) != DehydratedValue() 45 # Uncomment to debug while testing 46 # print( 47 # "rehydrate: {} -> {}".format( 48 # attr, "present" if present else "not present" 49 # ) 50 # ) 51 if not present: 52 obj._rehydrate() 53 result = fn(*args, **kwargs) 54 return result
def
model(*args, **kwargs):
41 def wrapper(*args, **kwargs): 42 obj = args[0] 43 if not getattr(obj, "_standalone", None): 44 present = getattr(obj, attr) != DehydratedValue() 45 # Uncomment to debug while testing 46 # print( 47 # "rehydrate: {} -> {}".format( 48 # attr, "present" if present else "not present" 49 # ) 50 # ) 51 if not present: 52 obj._rehydrate() 53 result = fn(*args, **kwargs) 54 return result
def
runtime(*args, **kwargs):
41 def wrapper(*args, **kwargs): 42 obj = args[0] 43 if not getattr(obj, "_standalone", None): 44 present = getattr(obj, attr) != DehydratedValue() 45 # Uncomment to debug while testing 46 # print( 47 # "rehydrate: {} -> {}".format( 48 # attr, "present" if present else "not present" 49 # ) 50 # ) 51 if not present: 52 obj._rehydrate() 53 result = fn(*args, **kwargs) 54 return result
def
tensor_fields(*args, **kwargs):
41 def wrapper(*args, **kwargs): 42 obj = args[0] 43 if not getattr(obj, "_standalone", None): 44 present = getattr(obj, attr) != DehydratedValue() 45 # Uncomment to debug while testing 46 # print( 47 # "rehydrate: {} -> {}".format( 48 # attr, "present" if present else "not present" 49 # ) 50 # ) 51 if not present: 52 obj._rehydrate() 53 result = fn(*args, **kwargs) 54 return result