Skip to content

spec

mlte/spec/spec.py

A collection of properties and their measurements.

Spec

Bases: Artifact

The Spec class integrates QACategory, measurements, and the results of measurement evaluation and validation.

Source code in mlte/spec/spec.py
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
class Spec(Artifact):
    """
    The Spec class integrates QACategory, measurements,
    and the results of measurement evaluation and validation.
    """

    def __init__(
        self,
        identifier: str = DEFAULT_SPEC_ID,
        qa_categories: Dict[QACategory, Dict[str, Condition]] = {},
    ):
        """
        Initialize a Spec instance.

        :param qa_categories: The collection of QACategory that compose the spec, with their conditions keyed by measurement id.
        """
        super().__init__(identifier, ArtifactType.SPEC)

        self.qa_categories = qa_categories
        """The collection of QACategory that compose the Spec."""

        if not _unique([p.name for p in self.qa_categories.keys()]):
            raise RuntimeError("All QACategory in Spec must be unique.")

    # -------------------------------------------------------------------------
    # Serialization.
    # -------------------------------------------------------------------------

    def to_model(self) -> ArtifactModel:
        """Convert a negotation card artifact to its corresponding model."""
        return ArtifactModel(
            header=self.build_artifact_header(),
            body=SpecModel(
                qa_categories=[
                    self._to_qa_category_model(qa_category)
                    for qa_category, _ in self.qa_categories.items()
                ],
            ),
        )

    @classmethod
    def from_model(cls, model: ArtifactModel) -> Spec:
        """Convert a negotiation card model to its corresponding artifact."""
        assert model.header.type == ArtifactType.SPEC, "Broken precondition."
        body = typing.cast(SpecModel, model.body)
        return Spec(
            identifier=model.header.identifier,
            qa_categories=Spec.to_qa_category_dict(body.qa_categories),
        )

    def _to_qa_category_model(self, qa_category: QACategory) -> QACategoryModel:
        """
        Generate a QACategory model. This just uses QACategory.to_model, but adds the list of conditions.

        :param qa_category: The QACategory of interest
        :return: The QACategory model
        """
        qa_category_model: QACategoryModel = qa_category.to_model()
        qa_category_model.conditions = {
            measurement_id: condition.to_model()
            for measurement_id, condition in self.qa_categories[
                qa_category
            ].items()
        }
        return qa_category_model

    @classmethod
    def to_qa_category_dict(
        cls,
        qa_category_models: List[QACategoryModel],
    ) -> Dict[QACategory, Dict[str, Condition]]:
        """Converts a list of QACategory models, into a dict of properties and conditions."""
        return {
            QACategory.from_model(qa_category_model): {
                measurement_id: Condition.from_model(condition_model)
                for measurement_id, condition_model in qa_category_model.conditions.items()
            }
            for qa_category_model in qa_category_models
        }

    @staticmethod
    def get_default_id() -> str:
        """Overriden"""
        return DEFAULT_SPEC_ID

    # -------------------------------------------------------------------------
    # Quality Attribute Category Manipulation
    # -------------------------------------------------------------------------

    def get_qa_category(self, qa_category_id: str) -> QACategory:
        """
        Returns a particular QACategory with the given id.

        :param qa_category_id: The QACategory itself, or its identifier
        :return: The QACategory object.
        """
        qa_categories = [
            category
            for category in self.qa_categories
            if category.name == qa_category_id
        ]
        if len(qa_categories) == 0:
            raise RuntimeError(
                f"QA category {qa_category_id} was not found in list."
            )
        if len(qa_categories) > 1:
            raise RuntimeError(
                f"Multiple properties with same id were found: {qa_category_id}"
            )
        return qa_categories[0]

    def has_qa_category(self, qa_category: Union[QACategory, str]) -> bool:
        """
        Determine if the spec contains a particular QACategory.

        :param qa_category: The QACategory itself, or its identifier
        :return: `True` if the spec has the QACategory, `False` otherwise
        """
        target_name = (
            qa_category if isinstance(qa_category, str) else qa_category.name
        )
        return any(
            qa_category.name == target_name
            for qa_category in self.qa_categories
        )

    # -------------------------------------------------------------------------
    # Equality Testing
    # -------------------------------------------------------------------------

    def __eq__(self, other: object) -> bool:
        """Compare Spec instances for equality."""
        if not isinstance(other, Spec):
            return False
        reference: Spec = other
        return self._equal(reference)

qa_categories = qa_categories instance-attribute

The collection of QACategory that compose the Spec.

__eq__(other)

Compare Spec instances for equality.

Source code in mlte/spec/spec.py
167
168
169
170
171
172
def __eq__(self, other: object) -> bool:
    """Compare Spec instances for equality."""
    if not isinstance(other, Spec):
        return False
    reference: Spec = other
    return self._equal(reference)

__init__(identifier=DEFAULT_SPEC_ID, qa_categories={})

Initialize a Spec instance.

Parameters:

Name Type Description Default
qa_categories Dict[QACategory, Dict[str, Condition]]

The collection of QACategory that compose the spec, with their conditions keyed by measurement id.

{}
Source code in mlte/spec/spec.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
def __init__(
    self,
    identifier: str = DEFAULT_SPEC_ID,
    qa_categories: Dict[QACategory, Dict[str, Condition]] = {},
):
    """
    Initialize a Spec instance.

    :param qa_categories: The collection of QACategory that compose the spec, with their conditions keyed by measurement id.
    """
    super().__init__(identifier, ArtifactType.SPEC)

    self.qa_categories = qa_categories
    """The collection of QACategory that compose the Spec."""

    if not _unique([p.name for p in self.qa_categories.keys()]):
        raise RuntimeError("All QACategory in Spec must be unique.")

from_model(model) classmethod

Convert a negotiation card model to its corresponding artifact.

Source code in mlte/spec/spec.py
77
78
79
80
81
82
83
84
85
@classmethod
def from_model(cls, model: ArtifactModel) -> Spec:
    """Convert a negotiation card model to its corresponding artifact."""
    assert model.header.type == ArtifactType.SPEC, "Broken precondition."
    body = typing.cast(SpecModel, model.body)
    return Spec(
        identifier=model.header.identifier,
        qa_categories=Spec.to_qa_category_dict(body.qa_categories),
    )

get_default_id() staticmethod

Overriden

Source code in mlte/spec/spec.py
117
118
119
120
@staticmethod
def get_default_id() -> str:
    """Overriden"""
    return DEFAULT_SPEC_ID

get_qa_category(qa_category_id)

Returns a particular QACategory with the given id.

Parameters:

Name Type Description Default
qa_category_id str

The QACategory itself, or its identifier

required

Returns:

Type Description
QACategory

The QACategory object.

Source code in mlte/spec/spec.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def get_qa_category(self, qa_category_id: str) -> QACategory:
    """
    Returns a particular QACategory with the given id.

    :param qa_category_id: The QACategory itself, or its identifier
    :return: The QACategory object.
    """
    qa_categories = [
        category
        for category in self.qa_categories
        if category.name == qa_category_id
    ]
    if len(qa_categories) == 0:
        raise RuntimeError(
            f"QA category {qa_category_id} was not found in list."
        )
    if len(qa_categories) > 1:
        raise RuntimeError(
            f"Multiple properties with same id were found: {qa_category_id}"
        )
    return qa_categories[0]

has_qa_category(qa_category)

Determine if the spec contains a particular QACategory.

Parameters:

Name Type Description Default
qa_category Union[QACategory, str]

The QACategory itself, or its identifier

required

Returns:

Type Description
bool

True if the spec has the QACategory, False otherwise

Source code in mlte/spec/spec.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def has_qa_category(self, qa_category: Union[QACategory, str]) -> bool:
    """
    Determine if the spec contains a particular QACategory.

    :param qa_category: The QACategory itself, or its identifier
    :return: `True` if the spec has the QACategory, `False` otherwise
    """
    target_name = (
        qa_category if isinstance(qa_category, str) else qa_category.name
    )
    return any(
        qa_category.name == target_name
        for qa_category in self.qa_categories
    )

to_model()

Convert a negotation card artifact to its corresponding model.

Source code in mlte/spec/spec.py
65
66
67
68
69
70
71
72
73
74
75
def to_model(self) -> ArtifactModel:
    """Convert a negotation card artifact to its corresponding model."""
    return ArtifactModel(
        header=self.build_artifact_header(),
        body=SpecModel(
            qa_categories=[
                self._to_qa_category_model(qa_category)
                for qa_category, _ in self.qa_categories.items()
            ],
        ),
    )

to_qa_category_dict(qa_category_models) classmethod

Converts a list of QACategory models, into a dict of properties and conditions.

Source code in mlte/spec/spec.py
103
104
105
106
107
108
109
110
111
112
113
114
115
@classmethod
def to_qa_category_dict(
    cls,
    qa_category_models: List[QACategoryModel],
) -> Dict[QACategory, Dict[str, Condition]]:
    """Converts a list of QACategory models, into a dict of properties and conditions."""
    return {
        QACategory.from_model(qa_category_model): {
            measurement_id: Condition.from_model(condition_model)
            for measurement_id, condition_model in qa_category_model.conditions.items()
        }
        for qa_category_model in qa_category_models
    }