def test_from_hook(self): config_dict = { "connection": "test-connection", "trigger": "succeeded", "hubRef": "foo", "conditions": "foo > bar", "params": {"param1": {"value": "foo"}, "param2": {"value": "bar"}}, "presets": ["pre1", "pre2"], } hook = V1Hook.from_dict(config_dict) op = V1Operation.from_hook(hook, None, None, None) assert op.run_patch["connections"] == [hook.connection] assert op.hub_ref == hook.hub_ref assert op.params == hook.params assert op.presets == hook.presets op = V1Operation.from_hook(hook, {"in1": "v1"}, {"out1": "v1"}, {"c1": "v1"}) assert op.run_patch["connections"] == [hook.connection] assert op.hub_ref == hook.hub_ref assert op.params == { **hook.params, "inputs": V1Param(value={"in1": "v1"}, context_only=True), "outputs": V1Param(value={"out1": "v1"}, context_only=True), "condition": V1Param(value={"c1": "v1"}, context_only=True), } assert op.presets == hook.presets
def get_tuner( name: str, container: V1Container, matrix: V1Matrix, search: V1ParamSearch, iteration: int, bracket_iteration: int = None, ) -> V1Operation: params = { "matrix": V1Param(value=matrix.to_dict()), "search": V1Param(value=search.to_dict()), "iteration": V1Param(value=iteration), } inputs = [ V1IO(name="matrix", iotype=types.DICT, is_list=False, is_optional=True), V1IO(name="search", iotype=types.DICT, is_list=False, is_optional=True), V1IO(name="iteration", iotype=types.INT, is_list=False, is_optional=True), ] if bracket_iteration is not None: params["bracket_iteration"] = V1Param(value=bracket_iteration) inputs.append( V1IO( name="bracket_iteration", iotype=types.INT, is_list=False, is_optional=True, )) return V1Operation( params=params, component=V1Component( name=name, plugins=V1Plugins( auth=True, collect_logs=True, collect_artifacts=True, collect_resources=False, sync_statuses=False, ), inputs=inputs, outputs=[ V1IO( name="suggestions", iotype=types.DICT, is_list=True, is_optional=False, ), ], run=V1Tuner(container=container, ), ), )
def get_tuner( name: str, container: V1Container, matrix: V1Matrix, configs: List[Dict], metrics: List[float], iteration: int, ) -> V1Operation: return V1Operation( params={ "configs": V1Param(value=configs), "metrics": V1Param(value=metrics), "matrix": V1Param(value=matrix), "iteration": V1Param(value=iteration), }, termination=V1Termination(max_retries=3), component=V1Component( name=name, plugins=V1Plugins( auth=True, collect_logs=False, collect_artifacts=False, collect_resources=False, sync_statuses=True, ), inputs=[ V1IO(name="configs", iotype=types.DICT, is_list=True, is_optional=False), V1IO(name="metrics", iotype=types.FLOAT, is_list=True, is_optional=False), V1IO(name="iteration", iotype=types.INT, is_list=True, is_optional=True), ], outputs=[ V1IO( name="suggestions", iotype=types.DICT, is_list=True, is_optional=False, ), ], run=V1Tuner(container=container, ), ), )
def get_ops_from_suggestions( content: str, compiled_operation: V1CompiledOperation, suggestions: List[Dict], ) -> List[V1Operation]: def has_param(k: str): if not compiled_operation.matrix: return None return not compiled_operation.matrix.has_param(k) op_content = V1Operation.read(content) for suggestion in suggestions: params = { k: V1Param(value=Parser.parse_expression(v, {}), context_only=has_param(k)) for (k, v) in suggestion.items() } op_spec = copy.deepcopy(op_content) op_spec.matrix = None op_spec.conditions = None op_spec.schedule = None op_spec.events = None op_spec.dependencies = None op_spec.trigger = None op_spec.skip_on_upstream_skip = None op_spec.cache = compiled_operation.cache op_spec.queue = compiled_operation.queue op_spec.params = params op_spec.component.inputs = compiled_operation.inputs op_spec.component.outputs = compiled_operation.outputs op_spec.component.contexts = compiled_operation.contexts yield op_spec
def get_ops_from_suggestions( content: str, compiled_operation: V1CompiledOperation, suggestions: List[Dict], ) -> List[V1Operation]: ops = [] for suggestion in suggestions: params = { k: V1Param(value=Parser.parse_expression(v, {})) for (k, v) in suggestion.items() } op_spec = V1Operation.read(content) op_spec.matrix = None op_spec.conditions = None op_spec.schedule = None op_spec.events = None op_spec.dependencies = None op_spec.trigger = None op_spec.skip_on_upstream_skip = None op_spec.cache = compiled_operation.cache op_spec.queue = compiled_operation.queue op_spec.params = params op_spec.component.inputs = compiled_operation.inputs op_spec.component.outputs = compiled_operation.outputs op_spec.component.contexts = compiled_operation.contexts ops.append(op_spec) return ops
def dict_to_param_spec(contexts: Dict = None): contexts = contexts or {} return { k: ParamSpec( name=k, param=V1Param(value=v), iotype=types.ANY, is_flag=False, is_list=None, ) for k, v in contexts.items() }
def _update_params_with_contexts( params: Dict[str, ParamSpec], contexts: Dict = None) -> Dict[str, ParamSpec]: contexts = contexts or {} contexts = { k: ParamSpec( name=k, param=V1Param(value=v), iotype=types.ANY, is_flag=False, ) for k, v in contexts.items() } params.update(contexts) return params
def get_ops_from_suggestions( content: str, compiled_operation: V1CompiledOperation, suggestions: List[Dict] ) -> List[V1Operation]: ops = [] for suggestion in suggestions: params = { k: V1Param(value=Parser.parse_expression(v, {})) for (k, v) in suggestion.items() } op_spec = V1Operation.read(content) op_spec.matrix = None # remove matrix op_spec.params = params op_spec.component.inputs = compiled_operation.inputs op_spec.component.outputs = compiled_operation.outputs ops.append(op_spec) return ops
def get_notifier_operation( connection: str, backend: str, owner: str, project: str, run_uuid: str, run_name: str, condition: Union[str, Dict], ) -> V1Operation: return V1Operation( params={ "backend": V1Param(value=backend), "owner": V1Param(value=owner), "project": V1Param(value=project), "uuid": V1Param(value=run_uuid), "name": V1Param(value=run_name), "condition": V1Param(value=condition), }, termination=V1Termination(max_retries=3), component=V1Component( name="notifier", plugins=V1Plugins( auth=False, collect_logs=False, collect_artifacts=False, collect_resources=False, auto_resume=False, sync_statuses=False, external_host=True, ), inputs=[ V1IO(name="backend", type=types.STR, is_optional=False), V1IO(name="owner", type=types.STR, is_optional=False), V1IO(name="project", type=types.STR, is_optional=False), V1IO(name="uuid", type=types.STR, is_optional=False), V1IO(name="name", type=types.STR, is_optional=True), V1IO(name="condition", type=types.DICT, is_optional=True), V1IO(name="connection", type=types.STR, is_optional=True), ], run=V1NotifierJob( connections=[connection], container=get_default_notification_container(), ), ), )
def get_notifier_operation( connection: str, kind: str, owner: str, project: str, run_uuid: str, run_name: str, condition: str, ) -> V1Operation: return V1Operation( params={ "kind": V1Param(value=kind), "owner": V1Param(value=owner), "project": V1Param(value=project), "run_uuid": V1Param(value=run_uuid), "run_name": V1Param(value=run_name), "condition": V1Param(value=condition), }, termination=V1Termination(max_retries=3), component=V1Component( name="slack-notification", plugins=V1Plugins( auth=False, collect_logs=False, collect_artifacts=False, collect_resources=False, sync_statuses=False, ), inputs=[ V1IO(name="kind", iotype=types.STR, is_optional=False), V1IO(name="owner", iotype=types.STR, is_optional=False), V1IO(name="project", iotype=types.STR, is_optional=False), V1IO(name="run_uuid", iotype=types.STR, is_optional=False), V1IO(name="run_name", iotype=types.STR, is_optional=True), V1IO(name="condition", iotype=types.STR, is_optional=True), V1IO(name="connection", iotype=types.STR, is_optional=True), ], run=V1Notifier( connections=[connection], container=get_default_notification_container(), ), ), )
def test_apply_context_passes_with_required_inputs_and_params(self): content = { "version": 1.1, "kind": "component", "inputs": [ { "name": "lr", "type": types.FLOAT }, { "name": "num_steps", "type": types.INT }, ], "run": { "kind": V1RunKind.JOB, "container": { "name": "polyaxon-main", "image": "test/test:latest", "command": "train", }, }, } component_config = V1Component.read(content) assert component_config.to_dict() == content content = { "version": 1.1, "kind": "compiled_operation", "inputs": [ { "name": "lr", "type": types.FLOAT }, { "name": "num_steps", "type": types.INT }, ], "run": { "kind": V1RunKind.JOB, "container": { "name": "polyaxon-main", "image": "test/test:latest", "command": "train", }, }, } run_config = V1CompiledOperation.read(content) # no params with self.assertRaises(ValidationError): CompiledOperationSpecification.apply_operation_contexts(run_config) params = { "lr": V1Param(value=0.1), "num_steps": V1Param.from_dict({"value": 100}), } assert run_config.inputs[0].value is None assert run_config.inputs[1].value is None validated_params = run_config.validate_params(params=params) run_config.apply_params(params=params) assert {k: v.to_dict() for k, v in params.items() } == {p.name: p.param.to_dict() for p in validated_params} assert run_config.inputs[0].value == 0.1 assert run_config.inputs[1].value == 100 run_config = CompiledOperationSpecification.apply_operation_contexts( run_config) updated_content = { "version": 1.1, "kind": "compiled_operation", "inputs": [ { "name": "lr", "type": types.FLOAT, "isOptional": True, "value": 0.1 }, { "name": "num_steps", "type": types.INT, "isOptional": True, "value": 100, }, ], "run": { "kind": V1RunKind.JOB, "container": { "name": "polyaxon-main", "image": "test/test:latest", "command": "train", }, }, } assert run_config.to_dict() == updated_content updated_content["run"]["container"]["resources"] = { "requests": { "gpu": 1, "tpu": 1 }, "limits": { "gpu": 1, "tpu": 1 }, } run_config = V1CompiledOperation.read(updated_content) assert (run_config.run.container.resources == updated_content["run"] ["container"]["resources"])