def yaml_seq_node(): # A yaml.SequenceNode representing a sequence of mappings tag1 = 'tag:yaml.org,2002:map' item1_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item_id') item1_value1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item1') item1_key2_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'price') item1_value2_node = yaml.ScalarNode('tag:yaml.org,2002:float', '100.0') value1 = [(item1_key1_node, item1_value1_node), (item1_key2_node, item1_value2_node)] item1 = yaml.MappingNode(tag1, value1) tag2 = 'tag:yaml.org,2002:map' item2_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item_id') item2_value1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item2') item2_key2_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'price') item2_value2_node = yaml.ScalarNode('tag:yaml.org,2002:float', '200.0') item2_key3_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'on_sale') item2_value3_node = yaml.ScalarNode('tag:yaml.org,2002:bool', 'True') value2 = [(item2_key1_node, item2_value1_node), (item2_key2_node, item2_value2_node), (item2_key3_node, item2_value3_node)] item2 = yaml.MappingNode(tag2, value2) return yaml.SequenceNode('tag:yaml.org,2002:seq', [item1, item2])
def yaml_map_node(): # A yaml.MappingNode representing a mapping of mappings tag1 = 'tag:yaml.org,2002:map' item1_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'price') item1_value1_node = yaml.ScalarNode('tag:yaml.org,2002:float', '100.0') value1 = [(item1_key1_node, item1_value1_node)] item1 = yaml.MappingNode(tag1, value1) key1 = yaml.ScalarNode('tag:yaml.org,2002:str', 'item1') tag2 = 'tag:yaml.org,2002:map' item2_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'price') item2_value1_node = yaml.ScalarNode('tag:yaml.org,2002:float', '200.0') value2 = [(item2_key1_node, item2_value1_node)] item2 = yaml.MappingNode(tag2, value2) key2 = yaml.ScalarNode('tag:yaml.org,2002:str', 'item2') item3 = yaml.ScalarNode('tag:yaml.org,2002:float', '150.0') key3 = yaml.ScalarNode('tag:yaml.org,2002:str', 'item3') outer_map_value = [(key1, item1), (key2, item2), (key3, item3)] outer_tag = 'tag:yaml.org,2002:map' outer_map = yaml.MappingNode(outer_tag, outer_map_value) return outer_map
def __call__(self, dumper: 'Dumper', data: Any) -> yaml.Node: """Represents the class as a ScalarNode. Args: dumper: The dumper to use. data: The user-defined object to dump. Returns: A yaml.Node representing the object. """ # make a ScalarNode of type str with name of value logger.info('Representing {} of class {}'.format( data, self.class_.__name__)) # convert to a yaml.ScalarNode start_mark = yaml.error.StreamMark('Generated node', 0, 0, 0) end_mark = start_mark represented = yaml.ScalarNode('tag:yaml.org,2002:str', data.name, start_mark, end_mark) # type: yaml.Node # sweeten snode = Node(represented) if hasattr(self.class_, '_yatiml_sweeten'): self.class_._yatiml_sweeten(snode) represented = snode.yaml_node logger.debug('End representing {}'.format(data)) return represented
def class_node_dup_key(): # A Node wrapping a yaml.SequenceNode representing a sequence of # mappings with a duplicate key. tag1 = 'tag:yaml.org,2002:map' item1_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item_id') item1_value1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item') value1 = [(item1_key1_node, item1_value1_node)] item1 = yaml.MappingNode(tag1, value1) tag2 = 'tag:yaml.org,2002:map' item2_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item_id') item2_value1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item') value2 = [(item2_key1_node, item2_value1_node)] item2 = yaml.MappingNode(tag2, value2) seq_node = yaml.SequenceNode('tag:yaml.org,2002:seq', [item1, item2]) list1_key_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'dup_list') value = [(list1_key_node, seq_node)] map_node = yaml.MappingNode('tag:yaml.org,2002:map', value) return yatiml.Node(map_node)
def test_set_attribute(class_node: yatiml.Node) -> None: assert class_node.get_attribute('attr1').get_value() == 42 class_node.set_attribute('attr1', 43) attr1 = class_node.get_attribute('attr1') assert attr1.yaml_node.tag == 'tag:yaml.org,2002:int' assert attr1.yaml_node.value == '43' assert attr1.yaml_node.start_mark is not None assert attr1.yaml_node.end_mark is not None class_node.set_attribute('attr1', 'test') attr1 = class_node.get_attribute('attr1') assert attr1.yaml_node.tag == 'tag:yaml.org,2002:str' assert attr1.yaml_node.value == 'test' assert attr1.yaml_node.start_mark is not None assert attr1.yaml_node.end_mark is not None class_node.set_attribute('attr1', 3.14) attr1 = class_node.get_attribute('attr1') assert attr1.yaml_node.tag == 'tag:yaml.org,2002:float' assert attr1.yaml_node.value == '3.14' assert attr1.yaml_node.start_mark is not None assert attr1.yaml_node.end_mark is not None class_node.set_attribute('attr1', True) attr1 = class_node.get_attribute('attr1') assert attr1.yaml_node.tag == 'tag:yaml.org,2002:bool' assert attr1.yaml_node.value == 'true' assert attr1.yaml_node.start_mark is not None assert attr1.yaml_node.end_mark is not None class_node.set_attribute('attr1', None) attr1 = class_node.get_attribute('attr1') assert attr1.yaml_node.tag == 'tag:yaml.org,2002:null' assert attr1.yaml_node.value == '' assert attr1.yaml_node.start_mark is not None assert attr1.yaml_node.end_mark is not None assert not class_node.has_attribute('attr2') class_node.set_attribute('attr2', 'testing') attr2 = class_node.get_attribute('attr2') assert attr2.yaml_node.value == 'testing' assert attr2.yaml_node.start_mark is not None assert attr2.yaml_node.end_mark is not None node = yaml.ScalarNode('tag:yaml.org,2002:str', 'testnode') class_node.set_attribute('attr3', node) assert class_node.get_attribute('attr3').yaml_node == node with pytest.raises(TypeError): class_node.set_attribute('attr4', class_node) # type: ignore
def yaml_node(yaml_seq_node, yaml_map_node): tag = 'tag:yaml.org,2002:map' attr1_key_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'attr1') attr1_value_node = yaml.ScalarNode('tag:yaml.org,2002:int', '42') null_attr_key_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'null_attr') null_attr_value_node = yaml.ScalarNode('tag:yaml.org,2002:null', '') list1_key_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'list1') dict1_key_node = yaml.ScalarNode('tag:yaml.org,2002:map', 'dict1') dashed_key_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'dashed-attr') dashed_value_node = yaml.ScalarNode('tag:yaml.org,2002:int', '13') undered_key_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'undered_attr') undered_value_node = yaml.ScalarNode('tag:yaml.org,2002:float', '13.0') value = [(attr1_key_node, attr1_value_node), (null_attr_key_node, null_attr_value_node), (list1_key_node, yaml_seq_node), (dict1_key_node, yaml_map_node), (dashed_key_node, dashed_value_node), (undered_key_node, undered_value_node)] return yaml.MappingNode(tag, value)
def set_attribute(self, attribute: str, value: Union[ScalarType, yaml.Node]) -> None: """Sets the attribute to the given value. Use only if :meth:`is_mapping` returns ``True``. If the attribute does not exist, this adds a new attribute, if it does, it will be overwritten. If value is a ``str``, ``int``, ``float``, ``bool`` or ``None``, the attribute will be set to this value. If you want to set the value to a list or dict containing other values, build a yaml.Node and pass it here. Args: attribute: Name of the attribute whose value to change. value: The value to set. """ start_mark = StreamMark('generated node', 0, 0, 0) end_mark = StreamMark('generated node', 0, 0, 0) if isinstance(value, str): value_node = yaml.ScalarNode('tag:yaml.org,2002:str', value, start_mark, end_mark) # type: yaml.Node elif isinstance(value, bool): value_str = 'true' if value else 'false' value_node = yaml.ScalarNode('tag:yaml.org,2002:bool', value_str, start_mark, end_mark) elif isinstance(value, int): value_node = yaml.ScalarNode('tag:yaml.org,2002:int', str(value), start_mark, end_mark) elif isinstance(value, float): value_node = yaml.ScalarNode('tag:yaml.org,2002:float', str(value), start_mark, end_mark) elif value is None: value_node = yaml.ScalarNode('tag:yaml.org,2002:null', '', start_mark, end_mark) elif isinstance(value, yaml.Node): value_node = value else: raise TypeError('Invalid kind of value passed to set_attribute()') attr_index = self.__attr_index(attribute) if attr_index is not None: key_node = self.yaml_node.value[attr_index][0] self.yaml_node.value[attr_index] = key_node, value_node else: key_node = yaml.ScalarNode('tag:yaml.org,2002:str', attribute, start_mark, end_mark) self.yaml_node.value.append((key_node, value_node)) if isinstance(self.yaml_node, yaml.MappingNode): self.yaml_node.flow_style = False
def yatiml_savorize(cls, node: yatiml.Node) -> None: text = str(node.get_value()) parts = text.split('.') node.make_mapping() # We need to make a yaml.SequenceNode by hand here, since # set_attribute doesn't take lists as an argument. start_mark = yaml.error.StreamMark('generated node', 0, 0, 0) end_mark = yaml.error.StreamMark('generated node', 0, 0, 0) item_nodes = list() for part in parts[:-1]: item_nodes.append( yaml.ScalarNode('tag:yaml.org,2002:str', part, start_mark, end_mark)) ynode = yaml.SequenceNode('tag:yaml.org,2002:seq', item_nodes, start_mark, end_mark) node.set_attribute('namespaces', ynode) node.set_attribute('name', parts[-1])
def _yatiml_sweeten(cls, node: yatiml.Node) -> None: script_node = node.get_attribute('script') if script_node.is_scalar(str): text = cast(str, script_node.get_value()) if '\n' in text: # make a sequence of lines lines = text.split('\n') start_mark = node.yaml_node.start_mark end_mark = node.yaml_node.end_mark lines_nodes = [ yaml.ScalarNode( 'tag:yaml.org,2002:str', line, start_mark, end_mark) for line in lines] seq_node = yaml.SequenceNode( 'tag:yaml.org,2002:seq', lines_nodes, start_mark, end_mark) node.set_attribute('script', seq_node)
def set_value(self, value: ScalarType) -> None: """Sets the value of the node to a scalar value. After this, is_scalar(type(value)) will return true. Args: value: The value to set this node to, a str, int, float, \ bool, or None. """ if isinstance(value, bool): value_str = 'true' if value else 'false' else: value_str = str(value) start_mark = self.yaml_node.start_mark end_mark = self.yaml_node.end_mark # If we're of a class type, then we want to keep that tag so that the # correct Constructor is called. If we're a built-in type, set the tag # to the appropriate YAML tag. tag = self.yaml_node.tag if tag.startswith('tag:yaml.org,2002:'): tag = scalar_type_to_tag[type(value)] new_node = yaml.ScalarNode(tag, value_str, start_mark, end_mark) self.yaml_node = new_node
def map_attribute_to_index(self, attribute: str, key_attribute: str, value_attribute: Optional[str] = None) -> None: """Converts a mapping attribute to an index . It is often convenient to represent a collection of objects by a dict mapping a name of each object to that object (let's call that an *index*). If each object knows its own name, then the name is stored twice, which is not nice to have to type and keep synchronised in YAML. In YAML, such an index is a mapping of mappings, where the key of the outer mapping matches the value of one of the items in the corresponding inner mapping. This function enables a short-hand notation for the above, where the name of the object is mentioned only in the key of the mapping and not again in the values, and, if ``value_attribute`` is specified, converting any entries with a scalar value (rather than a mapping) to a mapping with ''value_attribute'' as the key and the original value as the value. An example probably helps. Let's say we have a class ``Employee`` and a ``Company`` which has employees: .. code-block:: python class Employee: def __init__( self, name: str, role: str, hours: int = 40 ) -> None: ... class Company: def __init__( self, employees: Dict[str, Employee] ) -> None: ... my_company = Company({ 'Mary': Employee('Mary', 'Director'), 'Vishnu': Employee('Vishnu', 'Sales'), 'Susan': Employee('Susan', 'Engineering')}) By default, to load this from YAML, you have to write: .. code-block:: yaml employees: Mary: name: Mary role: Director Vishnu: name: Vishnu role: Sales Susan: name: Susan role: Engineering If you call ``node.map_attribute_to_index('employees', 'name')`` in ``Company._yatiml_savorize()``, then the following will also work: .. code-block:: yaml employees: Mary: role: Director Vishnu: role: Sales Susan: role: Engineering And if you call ``node.map_attribute_to_index('employees', 'name', 'role')`` then you can also write: .. code-block:: yaml employees: Mary: Director Vishnu: Sales Susan: Engineering If the attribute does not exist, or is not a mapping of mappings, this function will silently do nothing. See :meth:`index_attribute_to_map` for the reverse. With thanks to the makers of the Common Workflow Language for the idea. Args: attribute: Name of the attribute whose value to modify. key_attribute: Name of the attribute in each item to add, with the value of the key. value_attribute: Name of the attribute in each item to use for the value in the new mapping, if only a key and value have been given. """ if not self.has_attribute(attribute): return attr_node = self.get_attribute(attribute) if not attr_node.is_mapping(): return new_value = list() for key_node, value_node in attr_node.yaml_node.value: if not isinstance(value_node, yaml.MappingNode): if value_attribute is not None: new_key = yaml.ScalarNode('tag:yaml.org,2002:str', value_attribute, value_node.start_mark, value_node.end_mark) new_mapping = yaml.MappingNode('tag:yaml.org,2002:map', [(new_key, value_node)], value_node.start_mark, value_node.end_mark) else: new_mapping = value_node if isinstance(new_mapping, yaml.MappingNode): key_key = yaml.ScalarNode('tag:yaml.org,2002:str', key_attribute, key_node.start_mark, key_node.end_mark) new_mapping.value.append((key_key, copy(key_node))) new_value.append((key_node, new_mapping)) attr_node.yaml_node.value = new_value
def unknown_scalar_node(): ynode = yaml.ScalarNode('tag:yaml.org,2002:int', '23') return yatiml.UnknownNode(Recognizer({}), ynode)
def scalar_node(): ynode = yaml.ScalarNode('tag:yaml.org,2002:int', '42') return yatiml.Node(ynode)
def get_single_node(self): return yaml.ScalarNode(tag='tag:yaml.org,2002:str', value=self.stream.read())
def unknown_scalar_node(recognizer: Recognizer) -> yatiml.UnknownNode: ynode = yaml.ScalarNode('tag:yaml.org,2002:int', '23') return yatiml.UnknownNode(recognizer, ynode)
def yaml_index_node() -> yaml.Node: # A yaml.MappingNode representing a mapping of mappings indexed # by item id tag1 = 'tag:yaml.org,2002:map' item1_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item_id') item1_value1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item1') item1_key2_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'price') item1_value2_node = yaml.ScalarNode('tag:yaml.org,2002:float', '100.0') value1 = [(item1_key1_node, item1_value1_node), (item1_key2_node, item1_value2_node)] item1 = yaml.MappingNode(tag1, value1) key1 = yaml.ScalarNode('tag:yaml.org,2002:str', 'item1') tag2 = 'tag:yaml.org,2002:map' item2_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item_id') item2_value1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item2') item2_key2_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'price') item2_value2_node = yaml.ScalarNode('tag:yaml.org,2002:float', '200.0') value2 = [(item2_key1_node, item2_value1_node), (item2_key2_node, item2_value2_node)] item2 = yaml.MappingNode(tag2, value2) key2 = yaml.ScalarNode('tag:yaml.org,2002:str', 'item2') tag3 = 'tag:yaml.org,2002:map' item3_key1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item_id') item3_value1_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'item3') item3_key2_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'price') item3_value2_node = yaml.ScalarNode('tag:yaml.org,2002:float', '150.0') item3_key3_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'on_sale') item3_value3_node = yaml.ScalarNode('tag:yaml.org,2002:bool', 'true') value3 = [(item3_key1_node, item3_value1_node), (item3_key2_node, item3_value2_node), (item3_key3_node, item3_value3_node)] item3 = yaml.MappingNode(tag3, value3) key3 = yaml.ScalarNode('tag:yaml.org,2002:str', 'item3') outer_map_value = [(key1, item1), (key2, item2), (key3, item3)] outer_tag = 'tag:yaml.org,2002:map' outer_map = yaml.MappingNode(outer_tag, outer_map_value) return outer_map