Esempio n. 1
0
 def parse_constraint(yaml_constraints):
     """ This method parses the yaml representation for semantic convention attributes
         creating a list of Constraint objects.
     """
     constraints = ()
     allowed_keys = ("include", "any_of")
     for constraint in yaml_constraints:
         validate_values(constraint, allowed_keys)
         if len(constraint.keys()) > 1:
             position = constraint.lc.data[list(constraint)[1]]
             msg = "Invalid entry in constraint array - multiple top-level keys in entry."
             raise ValidationError.from_yaml_pos(position, msg)
         if "include" in constraint:
             constraints += (Include(constraint.get("include")),)
         elif "any_of" in constraint:
             choice_sets = ()
             for constraint_list in constraint.get("any_of"):
                 inner_id_list = ()
                 if isinstance(constraint_list, CommentedSeq):
                     inner_id_list = tuple(
                         attr_constraint for attr_constraint in constraint_list
                     )
                 else:
                     inner_id_list += (constraint_list,)
                 choice_sets += (inner_id_list,)
             constraints += (AnyOf(choice_sets),)
     return constraints
Esempio n. 2
0
def test_validate_values__invalid(load_yaml, allowed, mandatory,
                                  expected_message):
    conventions = load_yaml("basic_example.yml")
    yaml = conventions["groups"][0]

    with pytest.raises(ValidationError) as err:
        validate_values(yaml, allowed, mandatory)

    assert err.value.message == expected_message
    def parse(attribute_type):
        """This method parses the yaml representation for semantic attribute types.
        If the type is an enumeration, it generated the EnumAttributeType object,
        otherwise it returns the basic type as string.
        """
        if isinstance(attribute_type, str):
            if AttributeType.is_simple_type(attribute_type):
                return attribute_type
            # Wrong type used - raise the exception and fill the missing data in the parent
            raise ValidationError(
                0, 0, "Invalid type: {} is not allowed".format(attribute_type)
            )
        allowed_keys = ["allow_custom_values", "members"]
        mandatory_keys = ["members"]
        validate_values(attribute_type, allowed_keys, mandatory_keys)
        custom_values = (
            bool(attribute_type.get("allow_custom_values"))
            if "allow_custom_values" in attribute_type
            else False
        )
        members = []
        if (
            not isinstance(attribute_type["members"], CommentedSeq)
            or len(attribute_type["members"]) < 1
        ):
            raise ValidationError.from_yaml_pos(
                attribute_type.lc.data["members"], "Enumeration without members!"
            )

        allowed_keys = ["id", "value", "brief", "note"]
        mandatory_keys = ["id", "value"]
        for member in attribute_type["members"]:
            validate_values(member, allowed_keys, mandatory_keys)
            if not EnumAttributeType.is_valid_enum_value(member["value"]):
                raise ValidationError.from_yaml_pos(
                    member.lc.data["value"][:2],
                    "Invalid value used in enum: <{}>".format(member["value"]),
                )
            validate_id(member["id"], member.lc.data["id"])
            members.append(
                EnumMember(
                    member_id=member["id"],
                    value=member["value"],
                    brief=member.get("brief", member["id"]).strip(),
                    note=member.get("note", "").strip(),
                )
            )
        enum_type = AttributeType.get_type(members[0].value)
        for myaml, m in zip(attribute_type["members"], members):
            if enum_type != AttributeType.get_type(m.value):
                raise ValidationError.from_yaml_pos(
                    myaml.lc.data["value"],
                    "Enumeration member does not have type {}!".format(enum_type),
                )
        return EnumAttributeType(custom_values, members, enum_type)
Esempio n. 4
0
 def parse(yaml_file):
     yaml = YAML().load(yaml_file)
     models = []
     available_keys = (
         "id",
         "brief",
         "note",
         "prefix",
         "extends",
         "span_kind",
         "attributes",
         "constraints",
     )
     mandatory_keys = ("id", "brief")
     for group in yaml["groups"]:
         validate_values(group, available_keys, mandatory_keys)
         validate_id(group["id"], group.lc.data["id"])
         span_kind = SpanKind.parse(group.get("span_kind"))
         if span_kind is None:
             position = group.lc.data["span_kind"]
             msg = "Invalid value for span_kind: {}".format(group.get("span_kind"))
             raise ValidationError.from_yaml_pos(position, msg)
         prefix = group.get("prefix", "")
         if prefix != "":
             validate_id(prefix, group.lc.data["prefix"])
         position = group.lc.data["id"]
         model = SemanticConvention(
             semconv_id=group["id"].strip(),
             brief=str(group["brief"]).strip(),
             note=group.get("note", "").strip(),
             prefix=prefix.strip(),
             extends=group.get("extends", "").strip(),
             span_kind=span_kind,
             attrs_by_name=SemanticAttribute.parse(prefix, group.get("attributes"))
             if "attributes" in group
             else {},
             constraints=SemanticConvention.parse_constraint(
                 group.get("constraints", ())
             ),
             _position=position,
         )
         models.append(model)
     return models
Esempio n. 5
0
    def parse(attribute_type):
        """ This method parses the yaml representation for semantic attribute types.
            If the type is an enumeration, it generated the EnumAttributeType object,
            otherwise it returns the basic type as string.
        """
        if isinstance(attribute_type, str):
            if AttributeType.is_simple_type(attribute_type):
                return attribute_type
            else:  # Wrong type used - rise the exception and fill the missing data in the parent
                raise ValidationError(
                    0, 0,
                    "Invalid type: {} is not allowed".format(attribute_type))
        else:
            allowed_keys = ["allow_custom_values", "members"]
            mandatory_keys = ["members"]
            validate_values(attribute_type, allowed_keys, mandatory_keys)
            custom_values = (bool(attribute_type.get("allow_custom_values"))
                             if "allow_custom_values" in attribute_type else
                             False)
            members = []
            if attribute_type["members"] is None or len(
                    attribute_type["members"]) < 1:
                # Missing members - rise the exception and fill the missing data in the parent
                raise ValidationError(0, 0, "Enumeration without values!")

            allowed_keys = ["id", "value", "brief", "note"]
            mandatory_keys = ["id", "value"]
            for member in attribute_type["members"]:
                validate_values(member, allowed_keys, mandatory_keys)
                members.append(
                    EnumMember(
                        member_id=member["id"],
                        value=member["value"],
                        brief=member.get("brief")
                        if "brief" in member else member["id"],
                        note=member.get("note") if "note" in member else "",
                    ))
            enum_type = AttributeType.get_type(members[0].value)
            for m in members:
                if enum_type != AttributeType.get_type(m.value):
                    raise ValidationError(0, 0,
                                          "Enumeration type inconsistent!")
            return EnumAttributeType(custom_values, members, enum_type)
    def parse(
        prefix, semconv_stability, yaml_attributes
    ) -> "Dict[str, SemanticAttribute]":
        """This method parses the yaml representation for semantic attributes
        creating the respective SemanticAttribute objects.
        """
        attributes = {}  # type: Dict[str, SemanticAttribute]
        allowed_keys = (
            "id",
            "type",
            "brief",
            "examples",
            "ref",
            "tag",
            "deprecated",
            "stability",
            "required",
            "sampling_relevant",
            "note",
        )
        if not yaml_attributes:
            return attributes

        for attribute in yaml_attributes:
            validate_values(attribute, allowed_keys)
            attr_id = attribute.get("id")
            ref = attribute.get("ref")
            position_data = attribute.lc.data
            position = position_data[next(iter(attribute))]
            if attr_id is None and ref is None:
                msg = "At least one of id or ref is required."
                raise ValidationError.from_yaml_pos(position, msg)
            if attr_id is not None:
                validate_id(attr_id, position_data["id"])
                attr_type, brief, examples = SemanticAttribute.parse_id(attribute)
                if prefix:
                    fqn = "{}.{}".format(prefix, attr_id)
                else:
                    fqn = attr_id
            else:
                # Ref
                attr_type = None
                if "type" in attribute:
                    msg = "Ref attribute '{}' must not declare a type".format(ref)
                    raise ValidationError.from_yaml_pos(position, msg)
                brief = attribute.get("brief")
                examples = attribute.get("examples")
                ref = ref.strip()
                fqn = ref

            required_value_map = {
                "always": Required.ALWAYS,
                "conditional": Required.CONDITIONAL,
                "": Required.NO,
            }
            required_msg = ""
            required_val = attribute.get("required", "")
            required: Optional[Required]
            if isinstance(required_val, CommentedMap):
                required = Required.CONDITIONAL
                required_msg = required_val.get("conditional", None)
                if required_msg is None:
                    position = position_data["required"]
                    msg = "Missing message for conditional required field!"
                    raise ValidationError.from_yaml_pos(position, msg)
            else:
                required = required_value_map.get(required_val)
                if required == Required.CONDITIONAL:
                    position = position_data["required"]
                    msg = "Missing message for conditional required field!"
                    raise ValidationError.from_yaml_pos(position, msg)
            if required is None:
                position = position_data["required"]
                msg = "Value '{}' for required field is not allowed".format(
                    required_val
                )
                raise ValidationError.from_yaml_pos(position, msg)
            tag = attribute.get("tag", "").strip()
            stability, deprecated = SemanticAttribute.parse_stability_deprecated(
                attribute.get("stability"), attribute.get("deprecated"), position_data
            )
            if (
                semconv_stability == StabilityLevel.DEPRECATED
                and stability is not StabilityLevel.DEPRECATED
            ):
                position = (
                    position_data["stability"]
                    if "stability" in position_data
                    else position_data["deprecated"]
                )
                msg = "Semantic convention stability set to deprecated but attribute '{}' is {}".format(
                    attr_id, stability
                )
                raise ValidationError.from_yaml_pos(position, msg)
            stability = stability or semconv_stability or StabilityLevel.STABLE
            sampling_relevant = (
                AttributeType.to_bool("sampling_relevant", attribute)
                if attribute.get("sampling_relevant")
                else False
            )
            note = attribute.get("note", "")
            fqn = fqn.strip()
            parsed_brief = TextWithLinks(brief.strip() if brief else "")
            parsed_note = TextWithLinks(note.strip())
            attr = SemanticAttribute(
                fqn=fqn,
                attr_id=attr_id,
                ref=ref,
                attr_type=attr_type,
                brief=parsed_brief,
                examples=examples,
                tag=tag,
                deprecated=deprecated,
                stability=stability,
                required=required,
                required_msg=str(required_msg).strip(),
                sampling_relevant=sampling_relevant,
                note=parsed_note,
                position=position,
            )
            if attr.fqn in attributes:
                position = position_data[list(attribute)[0]]
                msg = (
                    "Attribute id "
                    + fqn
                    + " is already present at line "
                    + str(attributes[fqn].position[0] + 1)
                )
                raise ValidationError.from_yaml_pos(position, msg)
            attributes[fqn] = attr
        return attributes
Esempio n. 7
0
def test_validate_values(load_yaml, allowed, mandatory):
    conventions = load_yaml("basic_example.yml")
    yaml = conventions["groups"][0]

    validate_values(yaml, allowed, mandatory)
Esempio n. 8
0
    def parse(prefix, yaml_attributes):
        """ This method parses the yaml representation for semantic attributes
            creating the respective SemanticAttribute objects.
        """
        attributes = {}
        allowed_keys = (
            "id",
            "type",
            "brief",
            "examples",
            "ref",
            "tag",
            "deprecated",
            "required",
            "sampling_relevant",
            "note",
        )
        for attribute in yaml_attributes:
            validate_values(attribute, allowed_keys)
            attr_id = attribute.get("id")
            ref = attribute.get("ref")
            position = attribute.lc.data[list(attribute)[0]]
            if attr_id is None and ref is None:
                msg = "At least one of id or ref is required."
                raise ValidationError.from_yaml_pos(position, msg)
            if attr_id is not None:
                validate_id(attr_id, attribute.lc.data["id"])
                attr_type, brief, examples = SemanticAttribute.parse_id(
                    attribute)
                fqn = "{}.{}".format(prefix, attr_id)
                attr_id = attr_id.strip()
            else:
                # Ref
                attr_type = None
                if "type" in attribute:
                    position = attribute.lc.data[list(attribute)[0]]
                    msg = "Ref attribute '{}' must not declare a type".format(
                        ref)
                    raise ValidationError.from_yaml_pos(position, msg)
                brief = attribute.get("brief")
                examples = attribute.get("examples")
                ref = ref.strip()
                fqn = ref

            required_value_map = {
                "always": Required.ALWAYS,
                "conditional": Required.CONDITIONAL,
                "": Required.NO,
            }
            required_msg = ""
            required_val = attribute.get("required", "")
            if isinstance(required_val, CommentedMap):
                required = Required.CONDITIONAL
                required_msg = required_val.get("conditional", None)
                if required_msg is None:
                    position = attribute.lc.data["required"]
                    msg = "Missing message for conditional required field!"
                    raise ValidationError.from_yaml_pos(position, msg)
            else:
                required = required_value_map.get(required_val)
                if required == Required.CONDITIONAL:
                    position = attribute.lc.data["required"]
                    msg = "Missing message for conditional required field!"
                    raise ValidationError.from_yaml_pos(position, msg)
            if required is None:
                position = attribute.lc.data["required"]
                msg = "Value '{}' for required field is not allowed".format(
                    required_val)
                raise ValidationError.from_yaml_pos(position, msg)
            tag = attribute.get("tag", "").strip()
            deprecated = attribute.get("deprecated")
            if deprecated is not None:
                if AttributeType.get_type(
                        deprecated) != "string" or deprecated == "":
                    position = attribute.lc.data["deprecated"]
                    msg = (
                        "Deprecated field expects a string that specify why the attribute is deprecated and/or what"
                        " to use instead! ")
                    raise ValidationError.from_yaml_pos(position, msg)
                deprecated = deprecated.strip()
            sampling_relevant = (AttributeType.to_bool("sampling_relevant",
                                                       attribute) if
                                 attribute.get("sampling_relevant") else False)
            note = attribute.get("note", "")
            fqn = fqn.strip()
            attr = SemanticAttribute(
                fqn=fqn,
                attr_id=attr_id,
                ref=ref,
                attr_type=attr_type,
                brief=brief.strip() if brief else "",
                examples=examples,
                tag=tag,
                deprecated=deprecated,
                required=required,
                required_msg=str(required_msg).strip(),
                sampling_relevant=sampling_relevant,
                note=note.strip(),
                position=position,
            )
            if attr.fqn in attributes:
                position = attribute.lc.data[list(attribute)[0]]
                msg = ("Attribute id " + fqn + " is already present at line " +
                       str(attributes.get(fqn).position[0] + 1))
                raise ValidationError.from_yaml_pos(position, msg)
            attributes[fqn] = attr
        return attributes