Skip to content

Commit

Permalink
Feature / Extra validation in the model runtime (#270)
Browse files Browse the repository at this point in the history
* Perform default value encoding for model parameters as part of the static API in define_parameter

* Extra validation capabilities in api guard

* Move type validation logic into a new module

* Make RuntimeHookImpl use validation module directly

* Remove remaining references to ApiGuard

* Rename static API hook

* Update tests after renaming static API hook

* Change return type of define_attributes in model API

* Add staticAttributes to model definition, for attributes defined in code

* Use a single scan_model method and return staticAttributes on model_def

* Make ImportModelFunc and ImportAttrsFunc use the new scan_model semantics

* Fix unit test after update

* Move model validation into the validation module

* Fix scan_model in dev mode translator

* Quick validation of identifiers in scanned model definitions

* Use \A \Z style to match start/end of string in runtime validators

* Fixes in data round trip test model
  • Loading branch information
martin-traverse committed Jan 10, 2023
1 parent a516d5f commit dd9d5d9
Show file tree
Hide file tree
Showing 21 changed files with 625 additions and 454 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,9 @@ message ModelDefinition {
map<string, ModelParameter> parameters = 7;
map<string, ModelInputSchema> inputs = 8;
map<string, ModelOutputSchema> outputs = 9;

/**
* Static attributes defined in model code
*/
map<string, Value> staticAttributes = 12;
}
12 changes: 6 additions & 6 deletions tracdap-runtime/python/src/tracdap/rt/_exec/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
import tracdap.rt.api as _api
import tracdap.rt.metadata as _meta
import tracdap.rt.exceptions as _ex
import tracdap.rt._impl.api_hook as _api_hook # noqa
import tracdap.rt._impl.type_system as _types # noqa
import tracdap.rt._impl.data as _data # noqa
import tracdap.rt._impl.util as _util # noqa
import tracdap.rt._impl.validation as _val # noqa


class TracContextImpl(_api.TracContext):
Expand Down Expand Up @@ -78,7 +78,7 @@ def __init__(self,

def get_parameter(self, parameter_name: str) -> tp.Any:

_api_hook.ApiGuard.validate_signature(self.get_parameter, parameter_name)
_val.validate_signature(self.get_parameter, parameter_name)

self.__val.check_param_not_null(parameter_name)
self.__val.check_param_valid_identifier(parameter_name)
Expand All @@ -90,7 +90,7 @@ def get_parameter(self, parameter_name: str) -> tp.Any:

def get_schema(self, dataset_name: str) -> _meta.SchemaDefinition:

_api_hook.ApiGuard.validate_signature(self.get_schema, dataset_name)
_val.validate_signature(self.get_schema, dataset_name)

self.__val.check_dataset_name_not_null(dataset_name)
self.__val.check_dataset_valid_identifier(dataset_name)
Expand All @@ -109,7 +109,7 @@ def get_schema(self, dataset_name: str) -> _meta.SchemaDefinition:

def get_pandas_table(self, dataset_name: str, use_temporal_objects: tp.Optional[bool] = None) -> pd.DataFrame:

_api_hook.ApiGuard.validate_signature(self.get_pandas_table, dataset_name, use_temporal_objects)
_val.validate_signature(self.get_pandas_table, dataset_name, use_temporal_objects)

part_key = _data.DataPartKey.for_root()

Expand All @@ -136,7 +136,7 @@ def get_pandas_table(self, dataset_name: str, use_temporal_objects: tp.Optional[

def put_pandas_table(self, dataset_name: str, dataset: pd.DataFrame):

_api_hook.ApiGuard.validate_signature(self.put_pandas_table, dataset_name, dataset)
_val.validate_signature(self.put_pandas_table, dataset_name, dataset)

part_key = _data.DataPartKey.for_root()

Expand Down Expand Up @@ -165,7 +165,7 @@ def put_pandas_table(self, dataset_name: str, dataset: pd.DataFrame):

def log(self) -> logging.Logger:

_api_hook.ApiGuard.validate_signature(self.log)
_val.validate_signature(self.log)

return self.__model_log

Expand Down
11 changes: 1 addition & 10 deletions tracdap-runtime/python/src/tracdap/rt/_exec/dev_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,16 +297,7 @@ def _generate_model_for_entry_point(
outputs={})

model_class = model_loader.load_model_class("DEV_MODE_TRANSLATION", skeleton_modeL_def)
model_scan = model_loader.scan_model(model_class)

model_def = _meta.ModelDefinition( # noqa
language="python",
repository="trac_integrated",
entryPoint=model_entry_point,

parameters=model_scan.parameters,
inputs=model_scan.inputs,
outputs=model_scan.outputs)
model_def = model_loader.scan_model(skeleton_modeL_def, model_class)

model_object = _meta.ObjectDefinition(
objectType=_meta.ObjectType.MODEL,
Expand Down
29 changes: 17 additions & 12 deletions tracdap-runtime/python/src/tracdap/rt/_exec/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from __future__ import annotations

import copy
import datetime
import abc
import random
Expand Down Expand Up @@ -502,31 +501,37 @@ def __init__(self, node: ImportModelNode, models: _models.ModelLoader):

def _execute(self, ctx: NodeContext) -> meta.ObjectDefinition:

stub_model_def = _model_def_for_import(self.node.import_details)
model_stub = _model_def_for_import(self.node.import_details)

model_class = self._models.load_model_class(self.node.model_scope, stub_model_def)
model_scan = self._models.scan_model(model_class)

model_def = copy.copy(stub_model_def)
model_def.parameters = model_scan.parameters
model_def.inputs = model_scan.inputs
model_def.outputs = model_scan.outputs
model_class = self._models.load_model_class(self.node.model_scope, model_stub)
model_def = self._models.scan_model(model_stub, model_class)

return meta.ObjectDefinition(meta.ObjectType.MODEL, model=model_def)


class ImportAttrsFunc(NodeFunction[_config.TagUpdateList]):

# TODO: Remove this function, now staticAttributes are kept on model def

def __init__(self, node: ImportAttrsNode, models: _models.ModelLoader):
self.node = node
self._models = models

def _execute(self, ctx: NodeContext) -> _config.TagUpdateList:

stub_model_def = _model_def_for_import(self.node.import_details)
model_stub = _model_def_for_import(self.node.import_details)
model_class = self._models.load_model_class(self.node.model_scope, model_stub)
model_def = self._models.scan_model(model_stub, model_class)

updates = []

for attr_name, attr_value in model_def.staticAttributes.items():

updates.append(meta.TagUpdate(
attrName=attr_name, value=attr_value,
operation=meta.TagOperation.CREATE_OR_REPLACE_ATTR))

model_class = self._models.load_model_class(self.node.model_scope, stub_model_def)
return self._models.scan_model_attrs(model_class)
return cfg.TagUpdateList(updates)


class RunModelFunc(NodeFunction[Bundle[_data.DataView]]):
Expand Down
2 changes: 2 additions & 0 deletions tracdap-runtime/python/src/tracdap/rt/_exec/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ class ImportModelNode(Node[meta.ObjectDefinition]):
@_node_type
class ImportAttrsNode(Node[cfg.TagUpdateList]):

# TODO: Remove this node, now staticAttributes are kept on model def

model_scope: str
import_details: meta.ImportModelJob

Expand Down
4 changes: 2 additions & 2 deletions tracdap-runtime/python/src/tracdap/rt/_exec/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import tracdap.rt._impl.util as util # noqa
import tracdap.rt._impl.models as _models # noqa
import tracdap.rt._impl.storage as _storage # noqa
import tracdap.rt._impl.api_hook as _hook # noqa
import tracdap.rt._impl.static_api as _static_api # noqa


@dc.dataclass
Expand Down Expand Up @@ -121,7 +121,7 @@ def pre_start(self):

# Plugins will be loaded here, before config

_hook.RuntimeHookImpl.register_impl()
_static_api.StaticApiImpl.register_impl()

# Load sys and job config (or use embedded)

Expand Down
Loading

0 comments on commit dd9d5d9

Please sign in to comment.