def extract_value_from_vertex(self, key_path: List[str], attributes: Dict[str, Any]) -> Any: for i, _ in enumerate(key_path): key = join_trimmed_strings(char_to_join=".", str_lst=key_path, num_to_trim=i) value = attributes.get(key, None) if value is not None: return value reversed_key_path = key_path[::-1] for i, _ in enumerate(reversed_key_path): key = join_trimmed_strings(char_to_join=".", str_lst=reversed_key_path, num_to_trim=i) value = attributes.get(key, None) if value is not None: return value if attributes.get(CustomAttributes.BLOCK_TYPE) in [ BlockType.VARIABLE, BlockType.TF_VARIABLE ]: var_type = attributes.get('type') default_val = attributes.get("default") if default_val is None: # this allows functions like merge(var.xyz, ...) to work even with no default value default_val = self.get_default_placeholder_value(var_type) value = None if isinstance(default_val, dict): value = self.extract_value_from_vertex(key_path, default_val) return default_val if not value else value if attributes.get(CustomAttributes.BLOCK_TYPE) == BlockType.OUTPUT: return attributes.get("value") return None
def update_attribute(self, attribute_key: str, attribute_value: Any, change_origin_id: Optional[int], previous_breadcrumbs: List[BreadcrumbMetadata], attribute_at_dest: Optional[str]) -> None: if self._should_add_previous_breadcrumbs(change_origin_id, previous_breadcrumbs, attribute_at_dest): previous_breadcrumbs.append( BreadcrumbMetadata(change_origin_id, attribute_at_dest)) attribute_key_parts = attribute_key.split(".") if len(attribute_key_parts) == 1: self.attributes[attribute_key] = attribute_value if self._should_set_changed_attributes(change_origin_id, attribute_at_dest): self.changed_attributes[attribute_key] = previous_breadcrumbs return for i in range(len(attribute_key_parts)): key = join_trimmed_strings(char_to_join=".", str_lst=attribute_key_parts, num_to_trim=i) if key.find(".") > -1: self.attributes[key] = attribute_value attribute_value = { attribute_key_parts[len(attribute_key_parts) - 1 - i]: attribute_value } if self._should_set_changed_attributes(change_origin_id, attribute_at_dest): self.changed_attributes[key] = previous_breadcrumbs
def update_attribute( self, attribute_key: str, attribute_value: Any, change_origin_id: Optional[int], previous_breadcrumbs: List[BreadcrumbMetadata], attribute_at_dest: Optional[str], transform_step: bool = False, ) -> None: if self._should_add_previous_breadcrumbs(change_origin_id, previous_breadcrumbs, attribute_at_dest): previous_breadcrumbs.append(BreadcrumbMetadata(change_origin_id, attribute_at_dest)) # update the numbered attributes, if the new value is a list if isinstance(attribute_value, list): for idx, value in enumerate(attribute_value): self.attributes[f"{attribute_key}.{idx}"] = value attribute_key_parts = attribute_key.split(".") if len(attribute_key_parts) == 1: self.attributes[attribute_key] = attribute_value if self._should_set_changed_attributes(change_origin_id, attribute_at_dest): self.changed_attributes[attribute_key] = previous_breadcrumbs return for i in range(len(attribute_key_parts)): key = join_trimmed_strings(char_to_join=".", str_lst=attribute_key_parts, num_to_trim=i) if key.find(".") > -1: self.attributes[key] = attribute_value end_key_part = attribute_key_parts[len(attribute_key_parts) - 1 - i] if transform_step and end_key_part in ("1", "2"): # if condition logic during the transform step breaks the values return attribute_value = {end_key_part: attribute_value} if self._should_set_changed_attributes(change_origin_id, attribute_at_dest): self.changed_attributes[key] = previous_breadcrumbs
def _build_edges(self) -> None: logging.info("Creating edges") self.get_module_vertices_mapping() aliases = self._get_aliases() for origin_node_index, vertex in enumerate(self.vertices): for attribute_key in vertex.attributes: if attribute_key in reserved_attribute_names or attribute_has_nested_attributes( attribute_key, vertex.attributes): continue referenced_vertices = get_referenced_vertices_in_value( value=vertex.attributes[attribute_key], aliases=aliases, resources_types=self.get_resources_types_in_graph(), ) for vertex_reference in referenced_vertices: # for certain blocks such as data and resource, the block name is composed from several parts. # the purpose of the loop is to avoid not finding the node if the name has several parts sub_values = [ remove_index_pattern_from_str(sub_value) for sub_value in vertex_reference.sub_parts ] for i, _ in enumerate(sub_values): reference_name = join_trimmed_strings( char_to_join=".", str_lst=sub_values, num_to_trim=i) if vertex.module_dependency: dest_node_index = self._find_vertex_index_relative_to_path( vertex_reference.block_type, reference_name, vertex.path, vertex.module_dependency, vertex.module_dependency_num) if dest_node_index == -1: dest_node_index = self._find_vertex_index_relative_to_path( vertex_reference.block_type, reference_name, vertex.path, vertex.path, vertex.module_dependency_num) else: dest_node_index = self._find_vertex_index_relative_to_path( vertex_reference.block_type, reference_name, vertex.path, vertex.module_dependency, vertex.module_dependency_num) if dest_node_index > -1 and origin_node_index > -1: if vertex_reference.block_type == BlockType.MODULE: try: self._connect_module( sub_values, attribute_key, self.vertices[dest_node_index], origin_node_index) except Exception as e: logging.warning( f"Module {self.vertices[dest_node_index]} does not have source attribute, skipping" ) logging.warning(e, stack_info=True) else: self._create_edge(origin_node_index, dest_node_index, attribute_key) break if vertex.block_type == BlockType.MODULE and vertex.attributes.get( 'source'): target_path = vertex.path if vertex.module_dependency != "": target_path = unify_dependency_path( [vertex.module_dependency, vertex.path]) dest_module_path = self._get_dest_module_path( curr_module_dir=self.get_dirname(vertex.path), dest_module_source=vertex.attributes["source"][0], dest_module_version=vertex.attributes.get( "version", ["latest"])[0]) target_variables = [ index for index in self.vertices_by_module_dependency.get(( target_path, self.module.module_address_map.get(( vertex.path, vertex.name))), {}).get(BlockType.VARIABLE, []) if self.get_dirname(self.vertices[index].path) == dest_module_path ] for attribute, value in vertex.attributes.items(): if attribute in MODULE_RESERVED_ATTRIBUTES: continue target_variable = next( (v for v in target_variables if self.vertices[v].name == attribute), None) if target_variable is not None: self._create_edge(target_variable, origin_node_index, "default") elif vertex.block_type == BlockType.TF_VARIABLE: # Assuming the tfvars file is in the same directory as the variables file (best practice) target_variables = [ index for index in self.vertices_block_name_map.get( BlockType.VARIABLE, {}).get(vertex.name, []) if self.get_dirname(self.vertices[index].path) == self.get_dirname(vertex.path) ] if len(target_variables) == 1: self._create_edge(target_variables[0], origin_node_index, "default")