Skip to content

Commit

Permalink
wip: POC of three metadata sources
Browse files Browse the repository at this point in the history
  • Loading branch information
RafalSkolasinski committed Apr 8, 2020
1 parent e60cae5 commit 12fdac5
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 31 deletions.
12 changes: 3 additions & 9 deletions python/seldon_core/metadata.py
@@ -1,13 +1,11 @@
import os
import json
import logging


logger = logging.getLogger(__name__)

NONIMPLEMENTED_MSG = "NOT_IMPLEMENTED"

ENV_MODEL_METADATA = "MODEL_METADATA"
ENV_MODEL_IMAGE = "PREDICTIVE_UNIT_IMAGE"
image = os.environ.get(ENV_MODEL_IMAGE, f"{NONIMPLEMENTED_MSG}:{NONIMPLEMENTED_MSG}")
image_name, image_version = image.split(":")
Expand Down Expand Up @@ -46,8 +44,10 @@ def __init__(
logger.debug(f"Successfully validated ModelMetadata: {self}")

def validate(self):
if self.versions is None:
self.versions = []
if not isinstance(self.versions, (list, tuple)):
self.versions = [self.versions]
logger.error("ModelMetadata versions must be a list or tuple.")
self.versions = [str(x) for x in self.versions]

@staticmethod
Expand Down Expand Up @@ -110,9 +110,3 @@ def from_json(data):
inputs=inputs,
outputs=outputs,
)

@staticmethod
def from_env():
data = json.loads(os.environ.get(ENV_MODEL_METADATA, "{}"))
logger.debug(f"Reading metadata from environment: {data}")
return ModelMetadata.from_json(data)
48 changes: 29 additions & 19 deletions python/seldon_core/seldon_methods.py
@@ -1,3 +1,6 @@
import os
import yaml
import json
import logging
from seldon_core.utils import (
extract_request_parts,
Expand Down Expand Up @@ -507,9 +510,9 @@ def health_status(
)


def metadata(user_model: Any) -> Dict:
def init_metadata(user_model: Any) -> Dict:
"""
Call the user model to get the model metadata
Call the user model to get the model init_metadata
Parameters
----------
Expand All @@ -519,25 +522,32 @@ def metadata(user_model: Any) -> Dict:
-------
Model Metadata
"""
if hasattr(user_model, "metadata"):
# meta1: load metadata defined in the user_model instance
if hasattr(user_model, "init_metadata"):
try:
# Returned metadata can be dict or ModelMetadata
metadata = user_model.metadata()
if isinstance(metadata, dict):
metadata = ModelMetadata.from_json(metadata)
elif not isinstance(metadata, ModelMetadata):
raise SeldonMicroserviceException(
"user_model.metadata did not return ModelMetadata or dict instance",
status_code=500,
reason="MICROSERVICE_BAD_MODEL_METADATA",
)
# After validating that we got a correct output and in case of dict creating
# ModelMetadata instance we can return json.
return metadata.json()
meta1 = user_model.init_metadata()
except SeldonNotImplementedError:
meta1 = {}
pass
else:
meta1 = {}

# meta2: load metadata from yaml file
file_path = os.environ.get("MODEL_METADATA_FILE", "metadata.yaml")
try:
with open(file_path, "r") as f:
meta2 = yaml.load(f.read())
except FileNotFoundError:
meta2 = {}
except yaml.YAMLError:
logger.error(
f"metadata file {file_path} present but does not contain valid yaml"
)
meta2 = {}

# meta3: load metadata from environmental variable
meta3 = json.loads(os.environ.get("MODEL_METADATA", "{}"))

# If there is no "metadata" method in "user_model" or "SeldonNotImplementedError"
# is raised we fallback to read from environmental variable
metadata = ModelMetadata.from_env()
# Cast to ModelMetadata and back in order to validate
metadata = ModelMetadata.from_json({**meta1, **meta2, **meta3})
return metadata.json()
3 changes: 3 additions & 0 deletions python/seldon_core/user_model.py
Expand Up @@ -119,6 +119,9 @@ def health_status_raw(self) -> prediction_pb2.SeldonMessage:
def metadata(self) -> Dict:
raise SeldonNotImplementedError("metadata is not implemented")

def init_metadata(self) -> Dict:
raise SeldonNotImplementedError("init_metadata is not implemented")


def client_custom_tags(user_model: SeldonComponent) -> Dict:
"""
Expand Down
7 changes: 4 additions & 3 deletions python/seldon_core/wrapper.py
Expand Up @@ -25,6 +25,8 @@ def get_rest_microservice(user_model, seldon_metrics):

_set_flask_app_configs(app)

metadata_data = seldon_core.seldon_methods.init_metadata(user_model)

if hasattr(user_model, "model_error_handler"):
logger.info("Registering the custom error handler...")
app.register_blueprint(user_model.model_error_handler)
Expand Down Expand Up @@ -127,9 +129,8 @@ def HealthStatus():
@app.route("/metadata", methods=["GET"])
def Metadata():
logger.debug("REST Metadata Request")
response = seldon_core.seldon_methods.metadata(user_model)
logger.debug("REST Metadata Response: %s", response)
return jsonify(response)
logger.debug("REST Metadata Response: %s", metadata_data)
return jsonify(metadata_data)

return app

Expand Down

0 comments on commit 12fdac5

Please sign in to comment.