diff --git a/tests/test_dsl.py b/tests/test_dsl.py index b52e2c57..516aab9e 100644 --- a/tests/test_dsl.py +++ b/tests/test_dsl.py @@ -510,19 +510,20 @@ def test_example_template(): assert src_tpl == tosca_tpl2 tosca_tpl3 = _to_yaml(example_operation_on_template_python, False) wordpress_db = tosca_tpl3["topology_template"]["node_templates"]["wordpress_db"] - wordpress_db["artifacts"] = { + assert wordpress_db["artifacts"] == { "db_content": { "type": "tosca.artifacts.File", "file": "files/wordpress_db_content.txt", } } - wordpress_db["interfaces"] = { + assert wordpress_db["interfaces"] == { "Standard": { "type": "tosca.interfaces.node.lifecycle.Standard", "operations": { "create": { "implementation": {"primary": "db_create.sh"}, - "inputs": {"db_data": {"get_artifact": ["SELF", "db_content"]}}, + "inputs": {"db_data": {"get_artifact": ["SELF", "db_content"]} + }, } }, } diff --git a/tosca-package/tosca/_tosca.py b/tosca-package/tosca/_tosca.py index a1c3e850..0108fe16 100644 --- a/tosca-package/tosca/_tosca.py +++ b/tosca-package/tosca/_tosca.py @@ -2782,9 +2782,6 @@ def _get_instance_fields(self): elif not field and name[0] != "_" and is_data_field(value): # attribute is not part of class definition, try to deduce from the value's type field = _Tosca_Field.infer_field(self.__class__, name, value) - if field.tosca_field_type != ToscaFieldType.property: - # the value was a data value or unrecognized, nothing to convert - continue field.default = MISSING # this whole field was missing yield name, (field, value) elif isinstance(field, _Tosca_Field): @@ -3427,6 +3424,8 @@ def __getattr__(self, name): else: # this is only called when defining an operation on a type so reset query to be relative attr._path = [".", attr.field.as_ref_expr()] + elif isinstance(attr, ArtifactType): + return _ArtifactProxy(name) return attr def find_artifact(self, name_or_tpl): diff --git a/tosca-package/tosca/yaml2python.py b/tosca-package/tosca/yaml2python.py index cf039932..b480eba9 100644 --- a/tosca-package/tosca/yaml2python.py +++ b/tosca-package/tosca/yaml2python.py @@ -802,6 +802,8 @@ def _prop_decl( default_value: Any = MISSING if "default" in prop.schema.schema: default_value = prop.schema.schema["default"] + elif "value" in prop.schema.schema: # special case for topology outputs + default_value = prop.schema.schema["value"] elif not prop.required: default_value = None typename = self._prop_type(prop.schema) @@ -1271,7 +1273,7 @@ def get_configurator_decl(self, op: OperationDef) -> Tuple[str, Dict[str, Any]]: else None ) cmd = "" - if kw is None: + if kw is None or kw["primary"]: if isinstance(op.implementation, dict): artifact = op.implementation.get("primary") kw = op.implementation.copy() @@ -1281,11 +1283,12 @@ def get_configurator_decl(self, op: OperationDef) -> Tuple[str, Dict[str, Any]]: kw["inputs"] = op.inputs if isinstance(artifact, str): artifact, toscaname = self._get_name(artifact) - if hasattr(self, artifact): + tname = toscaname or artifact + if op.node_template and tname in op.node_template.artifacts: # add direct reference to allow static type checking - cmd = f"self.{artifact}.execute(" + cmd = f"self.{artifact}.execute" if not cmd and artifact: - cmd = f"self.find_artifact({self.value2python_repr(artifact)})" + cmd = f"self.find_artifact({self.value2python_repr(artifact)}).execute" else: cmd = kw["className"] module, sep, klass = cmd.rpartition(".") diff --git a/unfurl/yamlloader.py b/unfurl/yamlloader.py index 68724288..e4568b9c 100644 --- a/unfurl/yamlloader.py +++ b/unfurl/yamlloader.py @@ -349,14 +349,27 @@ def find_implementation(self, op: OperationDef) -> Optional[Dict[str, Any]]: from . import ( configurators, ) # need to import configurators to get short names # noqa: F401 + from .spec import NodeSpec inputs = op.inputs if op.inputs is not None else {} - if not op._source and self.manifest: - op._source = self.manifest.get_base_dir() + node = None + if self.manifest: + if not op._source: + op._source = self.manifest.get_base_dir() + if self.manifest.tosca and self.manifest.tosca.topology: + if op.node_template: + node_template = op.node_template + else: + ntype = op.ntype.type if op.ntype else "tosca:Root" + topology = self.manifest.tosca.topology.topology_template + nname = f"_{ntype}" + node_template = topology.add_template(nname, dict(type=ntype, imported="ignore")) + del topology.node_templates[nname] + node = NodeSpec(node_template, self.manifest.tosca.topology) return cast( Optional[Dict[str, Any]], _get_config_spec_args_from_implementation( - op, inputs, None, None, safe_mode=self.get_safe_mode() + op, inputs, node, None, safe_mode=self.get_safe_mode() ), )