Source code for pyEDAA.Reports.CodeCoverage.UCIS.ToggleBits

# ==================================================================================================================== #
#              _____ ____    _        _      ____                       _                                              #
#  _ __  _   _| ____|  _ \  / \      / \    |  _ \ ___ _ __   ___  _ __| |_ ___                                        #
# | '_ \| | | |  _| | | | |/ _ \    / _ \   | |_) / _ \ '_ \ / _ \| '__| __/ __|                                       #
# | |_) | |_| | |___| |_| / ___ \  / ___ \ _|  _ <  __/ |_) | (_) | |  | |_\__ \                                       #
# | .__/ \__, |_____|____/_/   \_\/_/   \_(_)_| \_\___| .__/ \___/|_|   \__|___/                                       #
# |_|    |___/                                        |_|                                                              #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2026-2026 Electronic Design Automation Abstraction (EDA²)                                                  #
#                                                                                                                      #
# Licensed under the Apache License, Version 2.0 (the "License");                                                      #
# you may not use this file except in compliance with the License.                                                     #
# You may obtain a copy of the License at                                                                              #
#                                                                                                                      #
#   http://www.apache.org/licenses/LICENSE-2.0                                                                         #
#                                                                                                                      #
# Unless required by applicable law or agreed to in writing, software                                                  #
# distributed under the License is distributed on an "AS IS" BASIS,                                                    #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                             #
# See the License for the specific language governing permissions and                                                  #
# limitations under the License.                                                                                       #
#                                                                                                                      #
# SPDX-License-Identifier: Apache-2.0                                                                                  #
# ==================================================================================================================== #
#
"""
The bits of the toggle coverage of the UCIS XML interchange format: a signal's ``<toggleBit>`` elements and their
transitions.
"""
from __future__                                 import annotations

from typing                                     import TYPE_CHECKING, Iterable, Optional as Nullable, Self

from lxml.etree                                 import _Element
from pyTooling.Common                           import getFullyQualifiedName
from pyTooling.Decorators                       import export, readonly
from pyTooling.MetaClasses                      import ExtendedType

from pyEDAA.Reports.CodeCoverage.UCIS.Bins      import Bin
from pyEDAA.Reports.CodeCoverage.UCIS.Elements  import Base, ObjectAttributesMixin, UserAttribute

if TYPE_CHECKING:
	from pyEDAA.Reports.CodeCoverage.UCIS.Toggles import ToggleObject


# A class with a property named like a class - ``Bin`` - can't name that class in the annotation of a field: the class
# body's namespace, where annotations are evaluated, binds the name to the property.
_Bin = Bin


[docs] @export class ToggleBit(Base, ObjectAttributesMixin): """ A ``<toggleBit>`` of a toggle object: a bit of the signal, its indices and its transitions. """ _parent: Nullable[ToggleObject] #: The toggle object the bit belongs to. _name: str #: Name of the bit, e.g. ``ff1[2]``. _key: str #: UCIS key of the bit. _indices: list[int] #: The indices of the bit, one per dimension. _toggles: list[Toggle] #: The transitions of the bit.
[docs] def __init__( self, name: str, key: str, indices: Nullable[Iterable[int]] = None, alias: Nullable[str] = None, excluded: bool = False, excludedReason: Nullable[str] = None, weight: int = 1, userAttributes: Nullable[Iterable[UserAttribute]] = None, *, parent: Nullable[ToggleObject] = None ) -> None: """ Initialize the toggle bit, and append it to the bits of its toggle object. Its transitions are added by creating them with this bit as their parent. :param name: Name of the bit, e.g. ``ff1[2]``. :param key: UCIS key of the bit. :param indices: Optional, the indices of the bit, one per dimension. Default: ``None``. :param alias: Optional, an alias of the bit's name. Default: ``None``. :param excluded: Optional, whether the bit is excluded from the coverage. Default: ``False``. :param excludedReason: Optional, why the bit is excluded. Default: ``None``. :param weight: Optional, weight of the bit in computing the coverage. Default: ``1``. :param userAttributes: Optional, the user-defined attributes. Default: ``None``. :param parent: Optional, the toggle object the bit belongs to. Default: ``None``. :raises ValueError: If parameter ``name`` is ``None``. :raises TypeError: If parameter ``name`` isn't of type :class:`str`. :raises ValueError: If parameter ``key`` is ``None``. :raises TypeError: If parameter ``key`` isn't of type :class:`str`. :raises TypeError: If parameter ``indices`` isn't iterable. :raises TypeError: If parameter ``indices`` contains an element not of type :class:`int`. :raises ValueError: If parameter ``indices`` contains a negative index. :raises TypeError: If parameter ``alias`` isn't of type :class:`str`. :raises ValueError: If parameter ``excluded`` is ``None``. :raises TypeError: If parameter ``excluded`` isn't of type :class:`bool`. :raises TypeError: If parameter ``excludedReason`` isn't of type :class:`str`. :raises ValueError: If parameter ``weight`` is ``None``. :raises TypeError: If parameter ``weight`` isn't of type :class:`int`. :raises ValueError: If parameter ``weight`` is negative. :raises TypeError: If parameter ``userAttributes`` isn't iterable. :raises TypeError: If parameter ``userAttributes`` contains an element not of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Elements.UserAttribute`. :raises TypeError: If parameter ``parent`` isn't of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Toggles.ToggleObject`. """ from pyEDAA.Reports.CodeCoverage.UCIS.Toggles import ToggleObject super().__init__(userAttributes) ObjectAttributesMixin.__init__(self, alias, excluded, excludedReason, weight) for parameterName, value in ( ("name", name), ("key", key) ): if value is None: raise ValueError(f"Parameter '{parameterName}' is None.") elif not isinstance(value, str): ex = TypeError(f"Parameter '{parameterName}' is not of type 'str'.") ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") raise ex if parent is not None and not isinstance(parent, ToggleObject): ex = TypeError("Parameter 'parent' is not of type 'ToggleObject'.") ex.add_note(f"Got type '{getFullyQualifiedName(parent)}'.") raise ex self._parent = parent self._name = name self._key = key self._indices = indexList = [] self._toggles = [] if indices is not None: if not isinstance(indices, Iterable): ex = TypeError("Parameter 'indices' is not iterable.") ex.add_note(f"Got type '{getFullyQualifiedName(indices)}'.") raise ex for index in indices: if not isinstance(index, int) or isinstance(index, bool): ex = TypeError("Parameter 'indices' contains an element not of type 'int'.") ex.add_note(f"Got type '{getFullyQualifiedName(index)}'.") raise ex elif index < 0: ex = ValueError("Parameter 'indices' contains a negative index.") ex.add_note(f"Got value '{index}'.") raise ex indexList.append(index) if parent is not None: parent._bits.append(self)
[docs] @classmethod def Parse(cls, element: _Element, *, parent: Nullable[ToggleObject] = None) -> Self: """ Parse a toggle bit and its transitions from its ``<toggleBit>`` element. :param element: The ``<toggleBit>`` element. :param parent: Optional, the toggle object the bit belongs to. Default: ``None``. :returns: The toggle bit. :raises CodeCoverageError: If a user-defined attribute's value isn't of the type the attribute states. """ toggleBit = cls( element.attrib["name"], element.attrib["key"], [int(indexElement.text) for indexElement in element.iterfind("{*}index")], element.attrib.get("alias"), cls._ParseBoolean(element.attrib.get("excluded", "false")), element.attrib.get("excludedReason"), int(element.attrib.get("weight", "1")), cls._ParseUserAttributes(element), parent=parent ) for toggleElement in element.iterfind("{*}toggle"): Toggle.Parse(toggleElement, parent=toggleBit) return toggleBit
@readonly def Parent(self) -> Nullable[ToggleObject]: """ Read-only property to access the toggle object the bit belongs to (:attr:`_parent`). :returns: The toggle object; ``None``, if the bit belongs to none. """ return self._parent @readonly def Name(self) -> str: """ Read-only property to access the name of the bit (:attr:`_name`). :returns: The name, e.g. ``ff1[2]``. """ return self._name @readonly def Key(self) -> str: """ Read-only property to access the UCIS key of the bit (:attr:`_key`). :returns: The key, as stated. """ return self._key @readonly def Indices(self) -> list[int]: """ Read-only property to access the indices of the bit (:attr:`_indices`). :returns: The indices, one per dimension; empty, if the report states none. """ return self._indices @readonly def Toggles(self) -> list[Toggle]: """ Read-only property to access the transitions of the bit (:attr:`_toggles`). :returns: The transitions, in the order the report lists them. """ return self._toggles
[docs] @export class Toggle(metaclass=ExtendedType, slots=True): """ A ``<toggle>`` of a toggle bit: a transition from one value to another, and its bin - how often it happened. """ _parent: Nullable[ToggleBit] #: The toggle bit the transition belongs to. _from: str #: The value before the transition, e.g. ``0``. _to: str #: The value after the transition, e.g. ``1``. _bin: _Bin #: How often the transition happened.
[docs] def __init__(self, fromValue: str, toValue: str, coverBin: Bin, *, parent: Nullable[ToggleBit] = None) -> None: """ Initialize the transition, become its bin's parent, and append it to the transitions of its toggle bit. :param fromValue: The value before the transition, e.g. ``0``. :param toValue: The value after the transition, e.g. ``1``. :param coverBin: How often the transition happened. :param parent: Optional, the toggle bit the transition belongs to. Default: ``None``. :raises ValueError: If parameter ``fromValue`` is ``None``. :raises TypeError: If parameter ``fromValue`` isn't of type :class:`str`. :raises ValueError: If parameter ``toValue`` is ``None``. :raises TypeError: If parameter ``toValue`` isn't of type :class:`str`. :raises ValueError: If parameter ``coverBin`` is ``None``. :raises TypeError: If parameter ``coverBin`` isn't of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Bins.Bin`. :raises TypeError: If parameter ``parent`` isn't of type :class:`ToggleBit`. """ for parameterName, value in ( ("fromValue", fromValue), ("toValue", toValue) ): if value is None: raise ValueError(f"Parameter '{parameterName}' is None.") elif not isinstance(value, str): ex = TypeError(f"Parameter '{parameterName}' is not of type 'str'.") ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") raise ex if coverBin is None: raise ValueError("Parameter 'coverBin' is None.") elif not isinstance(coverBin, Bin): ex = TypeError("Parameter 'coverBin' is not of type 'Bin'.") ex.add_note(f"Got type '{getFullyQualifiedName(coverBin)}'.") raise ex if parent is not None and not isinstance(parent, ToggleBit): ex = TypeError("Parameter 'parent' is not of type 'ToggleBit'.") ex.add_note(f"Got type '{getFullyQualifiedName(parent)}'.") raise ex self._parent = parent self._from = fromValue self._to = toValue self._bin = coverBin coverBin._parent = self if parent is not None: parent._toggles.append(self)
[docs] @classmethod def Parse(cls, element: _Element, *, parent: Nullable[ToggleBit] = None) -> Self: """ Parse a transition and its bin from its ``<toggle>`` element. :param element: The ``<toggle>`` element. :param parent: Optional, the toggle bit the transition belongs to. Default: ``None``. :returns: The transition. :raises CodeCoverageError: If a user-defined attribute's value isn't of the type the attribute states. """ return cls(element.attrib["from"], element.attrib["to"], Bin.Parse(element.find("{*}bin")), parent=parent)
@readonly def Parent(self) -> Nullable[ToggleBit]: """ Read-only property to access the toggle bit the transition belongs to (:attr:`_parent`). :returns: The toggle bit; ``None``, if the transition belongs to none. """ return self._parent @readonly def From(self) -> str: """ Read-only property to access the value before the transition (:attr:`_from`). :returns: The value, as stated, e.g. ``0``. """ return self._from @readonly def To(self) -> str: """ Read-only property to access the value after the transition (:attr:`_to`). :returns: The value, as stated, e.g. ``1``. """ return self._to @readonly def Bin(self) -> Bin: """ Read-only property to access the transition's bin (:attr:`_bin`). :returns: The bin, stating how often the transition happened. """ return self._bin