def test_io_config_default(self): config_dict = { "name": "input1", "description": "some text", "type": types.BOOL, "isOptional": True, "value": True, } config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict) expected_repr = OrderedDict( (("name", "input1"), ("type", "bool"), ("value", True))) assert config.get_repr_from_value(None) == expected_repr assert config.get_repr() == expected_repr config_dict = { "name": "input1", "description": "some text", "type": types.FLOAT, "isOptional": True, "value": 3.4, } config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict) expected_repr = OrderedDict( (("name", "input1"), ("type", "float"), ("value", 3.4))) assert config.get_repr_from_value(None) == expected_repr assert config.get_repr() == expected_repr
def test_io_config_types(self): config_dict = { "name": "input1", "description": "some text", "type": types.INT } config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict) expected_repr = OrderedDict( (("name", "input1"), ("type", "int"), ("value", 3))) assert config.get_repr_from_value(3) == expected_repr assert config.get_repr() == OrderedDict( (("name", "input1"), ("type", "int"))) config_dict = { "name": "input1", "description": "some text", "type": types.S3 } config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict) expected_repr = OrderedDict( (("name", "input1"), ("type", types.S3), ("value", "s3://foo"))) assert config.get_repr_from_value("s3://foo") == expected_repr assert config.get_repr() == OrderedDict( (("name", "input1"), ("type", types.S3)))
def test_wrong_io_config_default(self): with self.assertRaises(ValidationError): V1IO.from_dict({ "name": "input1", "type": types.FLOAT, "value": "foo" }) with self.assertRaises(ValidationError): V1IO.from_dict({"name": "input1", "type": types.GCS, "value": 234})
def test_wrong_io_config_flag(self): with self.assertRaises(ValidationError): V1IO.from_dict({ "name": "input1", "type": types.S3, "isFlag": True }) with self.assertRaises(ValidationError): V1IO.from_dict({ "name": "input1", "type": types.FLOAT, "isFlag": True })
def test_value_non_typed_input(self): config_dict = {"name": "input1"} config = V1IO.from_dict(config_dict) assert config.validate_value("foo") == "foo" assert config.validate_value(1) == 1 assert config.validate_value(True) is True expected_repr = OrderedDict((("name", "input1"), ("value", "foo"))) assert config.get_repr_from_value("foo") == expected_repr assert config.get_repr() == OrderedDict(name="input1")
def test_io_config_default_and_required(self): config_dict = { "name": "input1", "description": "some text", "type": types.BOOL, "value": True, "isOptional": True, } config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict) config_dict = { "name": "input1", "description": "some text", "type": types.STR, "value": "foo", } with self.assertRaises(ValidationError): V1IO.from_dict(config_dict)
def test_value_typed_input(self): config_dict = {"name": "input1", "type": types.BOOL} config = V1IO.from_dict(config_dict) with self.assertRaises(ValidationError): config.validate_value("foo") with self.assertRaises(ValidationError): config.validate_value(1) with self.assertRaises(ValidationError): config.validate_value(None) assert config.validate_value(True) is True
def test_io_config_flag(self): config_dict = { "name": "input1", "description": "some text", "type": types.BOOL, "isFlag": True, } config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict) expected_repr = OrderedDict( (("name", "input1"), ("type", "bool"), ("value", False))) assert config.get_repr_from_value(False) == expected_repr
def test_io_config_required(self): config_dict = { "name": "input1", "description": "some text", "type": "float", "isOptional": False, } config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict) expected_repr = OrderedDict( (("name", "input1"), ("type", "float"), ("value", 1.1))) assert config.get_repr_from_value(1.1) == expected_repr assert config.get_repr() == OrderedDict( (("name", "input1"), ("type", "float")))
def set_contexts() -> List[V1IO]: context_params = [ p for p in param_specs if p not in processed_params ] contexts = [] for p in context_params: current_param = param_specs[p].param contexts.append( V1IO( name=p, value=current_param.value, is_optional=True, connection=current_param.connection, to_init=current_param.to_init, )) return contexts
def test_io_name_blacklist(self): config_dict = {"name": "params"} with self.assertRaises(ValidationError): V1IO.from_dict(config_dict) config_dict = {"name": "globals"} with self.assertRaises(ValidationError): V1IO.from_dict(config_dict) config_dict = {"name": "connections"} with self.assertRaises(ValidationError): V1IO.from_dict(config_dict)
def test_value_typed_input_with_default(self): config_dict = { "name": "input1", "type": types.INT, "value": 12, "isOptional": True, } config = V1IO.from_dict(config_dict) with self.assertRaises(ValidationError): config.validate_value("foo") assert config.validate_value(1) == 1 assert config.validate_value(0) == 0 assert config.validate_value(-1) == -1 assert config.validate_value(None) == 12 expected_repr = OrderedDict( (("name", "input1"), ("type", "int"), ("value", 12))) assert config.get_repr_from_value(None) == expected_repr assert config.get_repr() == expected_repr
def process_components(self, inputs=None, ignore_hub_validation: bool = False): """`ignore_hub_validation` is currently used for ignoring validation during tests with hub_ref. """ inputs = inputs or [] self._context["dag.name"] = V1IO(name="name", type=types.STR, value="", is_optional=True) self._context["dag.uuid"] = V1IO(name="uuid", type=types.STR, value="", is_optional=True) for _input in inputs: self._context["dag.inputs.{}".format(_input.name)] = _input if not self.operations: raise PolyaxonSchemaError( "Pipeline is not valid, it has no ops to validate components.") components = self.components or [] for component in components: component_name = component.name if component_name in self._components_by_names: raise PolyaxonSchemaError( "Pipeline has multiple components with the same name `{}`". format(component_name)) self._components_by_names[component_name] = component for op in self.operations: op_name = op.name if op.has_component_reference: outputs = op.component.outputs inputs = op.component.inputs elif op.has_dag_reference: component_ref_name = op.dag_ref if op_name in self._op_component_mapping: raise PolyaxonSchemaError( "Pipeline has multiple ops with the same name `{}`". format(op_name)) if component_ref_name not in self._components_by_names: raise PolyaxonSchemaError( "Pipeline op with name `{}` requires a component with name `{}`, " "which is not defined on this pipeline.".format( op_name, component_ref_name)) self._op_component_mapping[op_name] = component_ref_name outputs = self._components_by_names[component_ref_name].outputs inputs = self._components_by_names[component_ref_name].inputs elif op.has_hub_reference and ignore_hub_validation: continue else: raise PolyaxonSchemaError( "Pipeline op has no definition field `{}`".format(op_name)) if outputs: for output in outputs: self._context["ops.{}.outputs.{}".format( op_name, output.name)] = output if output.type == types.ARTIFACTS: self._context["ops.{}.artifacts.{}".format( op_name, output.name)] = output if inputs: for cinput in inputs: self._context["ops.{}.inputs.{}".format( op_name, cinput.name)] = cinput if cinput.type == types.ARTIFACTS: self._context["ops.{}.artifacts.{}".format( op_name, cinput.name)] = cinput for g_context in contexts_sections.GLOBALS_CONTEXTS: self._context["ops.{}.globals.{}".format( op_name, g_context)] = V1IO(name=g_context, type=types.STR, value="", is_optional=True) # We allow to resolve name, status, project, all outputs/inputs, iteration self._context["ops.{}.{}".format( op_name, contexts_sections.INPUTS)] = V1IO(name="inputs", type=types.DICT, value={}, is_optional=True) self._context["ops.{}.{}".format( op_name, contexts_sections.OUTPUTS)] = V1IO(name="outputs", type=types.DICT, value={}, is_optional=True) self._context["ops.{}.{}".format( op_name, contexts_sections.GLOBALS)] = V1IO(name="globals", type=types.STR, value="", is_optional=True) self._context["ops.{}.{}".format( op_name, contexts_sections.ARTIFACTS)] = V1IO(name="artifacts", type=types.STR, value="", is_optional=True) self._context["ops.{}.{}".format( op_name, contexts_sections.INPUTS_OUTPUTS)] = V1IO(name="io", type=types.STR, value={}, is_optional=True) for op in self.operations: if op.has_component_reference: component_ref = op.definition.name outputs = op.definition.outputs inputs = op.definition.inputs elif op.has_dag_reference: component_ref = op.definition.name outputs = self._components_by_names[component_ref].outputs inputs = self._components_by_names[component_ref].inputs elif op.has_hub_reference and ignore_hub_validation: continue else: raise PolyaxonSchemaError( "Pipeline op has no definition field `{}`".format(op.name)) ops_params.validate_params( params=op.params, inputs=inputs, outputs=outputs, context=self._context, matrix=op.matrix, joins=op.joins, is_template=False, check_runs=False, extra_info="<op {}>.<component {}>".format( op.name, component_ref), )
def process_components(self, inputs=None): from polyaxon.polyaxonfile.check import collect_references inputs = inputs or [] for _input in inputs: self._context["dag.inputs.{}".format(_input.name)] = _input if not self.operations: raise PolyaxonSchemaError( "Pipeline is not valid, it has no ops to validate components.") components = self.components or [] for component in components: component_name = component.name if component_name in self._components_by_names: raise PolyaxonSchemaError( "Pipeline has multiple components with the same name `{}`". format(component_name)) self._components_by_names[component_name] = component for op in self.operations: op_name = op.name if op.has_url_reference or op.has_path_reference: try: op = collect_references(op, self._path_context) except Exception as e: raise PolyaxonSchemaError( "Pipeline op with name `{}` requires a component with ref `{}`, " "the reference could not be resolved. Error: {}". format(op_name, op.hub_ref or op.url_ref or op.path_ref, e)) elif op.has_hub_reference: continue if op.has_component_reference: outputs = op.component.outputs inputs = op.component.inputs elif op.has_dag_reference: component_ref_name = op.dag_ref if op_name in self._op_component_mapping: raise PolyaxonSchemaError( "Pipeline has multiple ops with the same name `{}`". format(op_name)) if component_ref_name not in self._components_by_names: raise PolyaxonSchemaError( "Pipeline op with name `{}` requires a component with name `{}`, " "which is not defined on this pipeline.".format( op_name, component_ref_name)) self._op_component_mapping[op_name] = component_ref_name outputs = self._components_by_names[component_ref_name].outputs inputs = self._components_by_names[component_ref_name].inputs else: raise PolyaxonSchemaError( "Pipeline op has no template field `{}`".format(op_name)) if outputs: for output in outputs: self._context["ops.{}.outputs.{}".format( op_name, output.name)] = output if inputs: for cinput in inputs: self._context["ops.{}.inputs.{}".format( op_name, cinput.name)] = cinput # We allow to resolve name, status, project, all outputs/inputs, iteration self._context["ops.{}.inputs".format(op_name)] = V1IO( name="inputs", iotype=types.DICT, value={}, is_optional=True) self._context["ops.{}.outputs".format(op_name)] = V1IO( name="outputs", iotype=types.DICT, value={}, is_optional=True) self._context["ops.{}.status".format(op_name)] = V1IO( name="status", iotype=types.STR, value="", is_optional=True) self._context["ops.{}.name".format(op_name)] = V1IO( name="name", iotype=types.STR, value="", is_optional=True) self._context["ops.{}.uuid".format(op_name)] = V1IO( name="uuid", iotype=types.STR, value="", is_optional=True) self._context["ops.{}.project_name".format(op_name)] = V1IO( name="project_name", iotype=types.STR, value="", is_optional=True) self._context["ops.{}.project_uuid".format(op_name)] = V1IO( name="project_uuid", iotype=types.STR, value="", is_optional=True) self._context["ops.{}.iteration".format(op_name)] = V1IO( name="iteration", iotype=types.STR, value="", is_optional=True) for op in self.operations: if op.has_hub_reference: continue elif op.has_component_reference: component_ref = op.template.name outputs = op.template.outputs inputs = op.template.inputs elif op.has_dag_reference: component_ref = op.template.name outputs = self._components_by_names[component_ref].outputs inputs = self._components_by_names[component_ref].inputs else: raise PolyaxonSchemaError( "Pipeline op has no template field `{}`".format(op.name)) ops_params.validate_params( params=op.params, inputs=inputs, outputs=outputs, context=self._context, parallel=op.parallel, is_template=False, check_runs=False, extra_info="<op {}>.<component {}>".format( op.name, component_ref), )
def test_run_with_refs(self): # Get compiled_operation data run_config = V1CompiledOperation.read([ os.path.abspath("tests/fixtures/typing/run_with_refs.yml"), { "kind": "compiled_operation" }, ]) params = { "num_masks": { "value": 2 }, "model_path": { "ref": "runs.64332180bfce46eba80a65caf73c5396", "value": "outputs.doo", }, } validated_params = run_config.validate_params(params=params) param_specs_by_name = {p.name: p.param for p in validated_params} assert param_specs_by_name == { "num_masks": V1Param(value=2), "model_path": V1Param(ref="runs.64332180bfce46eba80a65caf73c5396", value="outputs.doo"), } ref_param = param_specs_by_name["model_path"] assert ref_param.to_dict() == params["model_path"] with self.assertRaises(ValidationError): run_config.apply_params(params=params) # Passing correct context run_config.apply_params( params=params, context={ "runs.64332180bfce46eba80a65caf73c5396.outputs.doo": V1IO( name="model_path", value="model_path", is_optional=True, iotype="path", ) }, ) # New params params = { "num_masks": { "value": 2 }, "model_path": { "ref": "ops.A", "value": "outputs.doo" }, } validated_params = run_config.validate_params(params=params) param_specs_by_name = {p.name: p.param for p in validated_params} assert param_specs_by_name == { "num_masks": V1Param(value=2), "model_path": V1Param(ref="ops.A", value="outputs.doo"), } ref_param = param_specs_by_name["model_path"] assert ref_param.to_dict() == params["model_path"] with self.assertRaises(ValidationError): run_config.apply_params(params=params) run_config.apply_params( params=params, context={ "ops.A.outputs.doo": V1IO( name="model_path", value="model_path", is_optional=True, iotype="path", ) }, )
def test_io_config_desc(self): # test desc config_dict = {"name": "input1", "description": "some text"} config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict)
def test_io_config_optionals(self): config_dict = {"name": "input1"} config = V1IO.from_dict(config_dict) assert_equal_dict(config.to_dict(), config_dict)
def test_wrong_io_config(self): # No name with self.assertRaises(ValidationError): V1IO.from_dict({})
def test_unsupported_io_config_type(self): with self.assertRaises(ValidationError): V1IO.from_dict({"name": "input1", "type": "something"})