Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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])
Ejemplo n.º 3
0
    def represent_odict(self, mapping, flow_style=None):  # pragma: no cover
        """https://gist.github.com/miracle2k/3184458

        Make PyYAML output an OrderedDict.

        It will do so fine if you use yaml.dump(), but that generates ugly, non-standard YAML code.

        To use yaml.safe_dump(), you need the following.
        """
        tag = YAML_MAP_TAG
        value = []
        node = yaml.MappingNode(tag, value, flow_style=flow_style)
        if self.alias_key is not None:
            self.represented_objects[self.alias_key] = node
        best_style = True
        if hasattr(mapping, "items"):
            mapping = mapping.items()
        for item_key, item_value in mapping:
            node_key = self.represent_data(item_key)
            node_value = self.represent_data(item_value)
            if not (isinstance(node_key, yaml.ScalarNode)
                    and not node_key.style):
                best_style = False
            if not (isinstance(node_value, yaml.ScalarNode)
                    and not node_value.style):
                best_style = False
            value.append((node_key, node_value))
        if flow_style is None:
            if self.default_flow_style is not None:
                node.flow_style = self.default_flow_style
            else:
                node.flow_style = best_style
        return node
Ejemplo n.º 4
0
def yaml_node(yaml_seq_node: yaml.Node, yaml_map_node: yaml.Node,
              yaml_index_node: yaml.Node) -> yaml.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')

    index1_key_node = yaml.ScalarNode('tag:yaml.org,2002:str', 'index1')

    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),
             (index1_key_node, yaml_index_node),
             (dashed_key_node, dashed_value_node),
             (undered_key_node, undered_value_node)]
    return yaml.MappingNode(tag, value)
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
    def make_mapping(self) -> None:
        """Replaces the node with a new, empty mapping.

        Note that this will work on the Node object that is passed to \
        a yatiml_savorize() or yatiml_sweeten() function, but not on \
        any of its attributes or items. If you need to set an attribute \
        to a complex value, build a yaml.Node representing it and use \
        set_attribute with that.
        """
        start_mark = StreamMark('generated node', 0, 0, 0)
        end_mark = StreamMark('generated node', 0, 0, 0)
        self.yaml_node = yaml.MappingNode('tag:yaml.org,2002:map', list(),
                                          start_mark, end_mark)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
    def seq_attribute_to_map(self,
                             attribute: str,
                             key_attribute: str,
                             value_attribute: Optional[str] = None,
                             strict: Optional[bool] = True) -> None:
        """Converts a sequence attribute to a map.

        This function takes an attribute of this Node that is \
        a sequence of mappings and turns it into a mapping of mappings. \
        It assumes that each of the mappings in the original sequence \
        has an attribute containing a unique value, which it will use \
        as a key for the new outer mapping.

        An example probably helps. If you have a Node representing \
        this piece of YAML::

            items:
            - item_id: item1
              description: Basic widget
              price: 100.0
            - item_id: item2
              description: Premium quality widget
              price: 200.0

        and call seq_attribute_to_map('items', 'item_id'), then the \
        Node will be modified to represent this::

            items:
              item1:
                description: Basic widget
                price: 100.0
              item2:
                description: Premium quality widget
                price: 200.0

        which is often more intuitive for people to read and write.

        If the attribute does not exist, or is not a sequence of \
        mappings, this function will silently do nothing. If the keys \
        are not unique and strict is False, it will also do nothing. If \
        the keys are not unique and strict is True, it will raise an \
        error.

        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 use \
                    as a key for the new mapping.
            strict: Whether to give an error if the intended keys are \
                    not unique.

        Raises:
            SeasoningError: If the keys are not unique and strict is \
                    True.
        """
        if not self.has_attribute(attribute):
            return

        attr_node = self.get_attribute(attribute)
        if not attr_node.is_sequence():
            return

        start_mark = attr_node.yaml_node.start_mark
        end_mark = attr_node.yaml_node.end_mark

        # check that all list items are mappings and that the keys are unique
        # strings
        seen_keys = set()  # type: Set[str]
        for item in attr_node.seq_items():
            key_attr_node = item.get_attribute(key_attribute)
            if not key_attr_node.is_scalar(str):
                raise SeasoningError(
                    ('Attribute names must be strings in'
                     'YAtiML, {} is not a string.').format(key_attr_node))
            if key_attr_node.get_value() in seen_keys:
                if strict:
                    raise SeasoningError(
                        ('Found a duplicate key {}: {} when'
                         ' converting from sequence to mapping'.format(
                             key_attribute, key_attr_node.get_value())))
                return
            seen_keys.add(key_attr_node.get_value())  # type: ignore

        # construct mapping
        mapping_values = list()
        for item in attr_node.seq_items():
            # we've already checked that it's a SequenceNode above
            key_node = item.get_attribute(key_attribute).yaml_node
            item.remove_attribute(key_attribute)
            if value_attribute is not None:
                value_node = item.get_attribute(value_attribute).yaml_node
                if len(item.yaml_node.value) == 1:
                    # no other attributes, use short form
                    mapping_values.append((key_node, value_node))
                else:
                    mapping_values.append((key_node, item.yaml_node))
            else:
                mapping_values.append((key_node, item.yaml_node))

        # create mapping node
        mapping = yaml.MappingNode('tag:yaml.org,2002:map', mapping_values,
                                   start_mark, end_mark)
        self.set_attribute(attribute, mapping)
Ejemplo n.º 9
0
    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