def run(template_fd, resource_fds, output_fd, local_tags, format="yaml"): assemblies = {} for fd in resource_fds: try: record_assemblies(fd, assemblies, local_tags) except YAMLError as e: log.error("While processing resource document %s:", getattr(fd, "filename", "<input>")) log.error("%s", str(e)) return 1 try: docs = transclude_template(template_fd, assemblies, local_tags) except YAMLError as e: log.error("While processing template document %s:", getattr(template_fd, "filename", "<input>")) log.error("%s", str(e)) return 1 if format == "json": if len(docs) > 1: log.warning("Multiple documents are not supported with JSON " "output; only the first document will be written.") constructor = SafeConstructor() pyobjs = constructor.construct_document(docs[0]) json_dump(pyobjs, output_fd) else: yaml_serialize_all(docs, stream=output_fd, Dumper=SafeDumper) return 0
def python_type(self, ast_node): if type(ast_node) is ScalarNode: return type(SafeConstructor().construct_object(ast_node)) if type(ast_node) is SequenceNode: return list if type(ast_node) is MappingNode: return dict raise RuntimeError('Unable to map ast_node type ({0})'.format( type(ast_node)))
def validate(self, ast_node, parent_key=None): ast_node_type = self.python_type(ast_node) if self._type is str: wrong_type = type(ast_node) is not ScalarNode ast_node.tag = 'tag:yaml.org,2002:str' # enforce string type. else: wrong_type = ast_node_type is not self._type if wrong_type: if (self.python_type(ast_node) is type(None)): msg = 'Expected a type {0} but got nothing'.format( self.pretty_type(self._type)) else: msg = 'Expected a type {0} but got {1} type {2}'.format( self.pretty_type(self._type), 'a' if bool(ast_node.value) else 'an empty', self.pretty_type(self.python_type(ast_node))) self.raise_error(msg, ast_node) if len(self._checks) > 0: if ast_node_type is dict: value = parent_key else: value = SafeConstructor().construct_object(ast_node) for desc, check in self._checks: if not check(value): self.raise_error('Invalid {0} "{1}"'.format(desc, value), ast_node) if self._allowed is not None: value = SafeConstructor().construct_object(ast_node) (desc, allowed_set) = self._allowed if value not in allowed_set: self.raise_error('Unrecognized {0} "{1}"'.format(desc, value), ast_node) if self._subnode is None: return if self.python_type(ast_node) is dict: required_nodes = set(k for k, v in self._subnode.items() if not v.optional) for subnode_key, ast_subnode in ast_node.value: subnode_key = subnode_key.value if '*' in self._subnode: self._subnode['*'].validate(ast_subnode, parent_key=subnode_key) if '*' in required_nodes: required_nodes.remove('*') elif subnode_key in self._subnode: # ignore everything else self._subnode[subnode_key].validate(ast_subnode, parent_key=subnode_key) if subnode_key in required_nodes: required_nodes.remove(subnode_key) if len(required_nodes): if '*' in required_nodes: msg = '{0} cannot be empty'.format(parent_key) else: msg = 'Missing mandatory {0}: "{1}"'.format( 'entry' if len(required_nodes) == 1 else 'entries', ', '.join(required_nodes)) self.raise_error(msg, ast_node)