Source code for pyEDAA.OutputFilter

# ==================================================================================================================== #
#               _____ ____    _        _      ___        _               _   _____ _ _ _                               #
#   _ __  _   _| ____|  _ \  / \      / \    / _ \ _   _| |_ _ __  _   _| |_|  ___(_) | |_ ___ _ __                    #
#  | '_ \| | | |  _| | | | |/ _ \    / _ \  | | | | | | | __| '_ \| | | | __| |_  | | | __/ _ \ '__|                   #
#  | |_) | |_| | |___| |_| / ___ \  / ___ \ | |_| | |_| | |_| |_) | |_| | |_|  _| | | | ||  __/ |                      #
#  | .__/ \__, |_____|____/_/   \_\/_/   \_(_)___/ \__,_|\__| .__/ \__,_|\__|_|   |_|_|\__\___|_|                      #
#  |_|    |___/                                             |_|                                                        #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2017-2026 Patrick Lehmann - Boetzingen, Germany                                                            #
# Copyright 2014-2016 Technische Universitaet Dresden - Germany, Chair of VLSI-Design, Diagnostics and Architecture    #
#                                                                                                                      #
# 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                                                                                  #
# ==================================================================================================================== #
#
"""An abstraction layer of EDA tool output filters."""
__author__ =    "Patrick Lehmann"
__email__ =     "Paebbels@gmail.com"
__copyright__ = "2014-2026, Patrick Lehmann"
__license__ =   "Apache License, Version 2.0"
__version__ =   "0.11.0"
__keywords__ =  ["cli", "abstraction layer", "eda", "filter", "classification"]

from datetime              import datetime
from enum                  import Flag
from typing                import Any, Generator, Callable, Tuple, Union, Optional as Nullable, Generic, TypeVar

from pyTooling.Common      import getFullyQualifiedName
from pyTooling.Decorators  import export, readonly
from pyTooling.Exceptions  import ExceptionBase
from pyTooling.MetaClasses import ExtendedType


[docs] @export class OutputFilterException(ExceptionBase): """Base-class for all pyEDAA.OutputFilter specific exceptions."""
LineClassification = TypeVar("LineClassification", bound=Flag) LineProcessingAction = TypeVar("LineProcessingAction", bound=Flag)
[docs] @export class Line(Generic[LineClassification, LineProcessingAction], metaclass=ExtendedType, slots=True): """ This class represents any line in a log file. A line has a line number (:attr:`_lineNumber`), a message (:attr:`__message`) and a message kind (:attr:`__kind`). In addition, all line objects in a log file form a doubly linked list. """ _lineNumber: int _timestamp: Nullable[datetime] _document: "Document" _kind: LineClassification _action: LineProcessingAction _message: str _previousLine: Nullable["Line"] _nextLine: Nullable["Line"]
[docs] def __init__( self, lineNumber: int, kind: LineClassification, action: LineProcessingAction, message: str, previousLine: Nullable["Line"] = None ) -> None: self._lineNumber = lineNumber self._kind = kind self._action = action self._message = message self._previousLine = previousLine self._nextLine = None if previousLine is not None: previousLine._nextLine = self if not isinstance(message, str): pass
@readonly def LineNumber(self) -> int: return self._lineNumber @readonly def Kind(self) -> LineClassification: return self._kind @readonly def Action(self) -> LineProcessingAction: return self._action @readonly def Message(self) -> str: return self._message @property def PreviousLine(self) -> Nullable["Line"]: return self._previousLine @PreviousLine.setter def PreviousLine(self, line: "Line") -> None: self._previousLine = line if line is not None: line._nextLine = self @readonly def NextLine(self) -> Nullable["Line"]: return self._nextLine def StartsWith(self, prefix: Union[str, Tuple[str, ...]]): return self._message.startswith(prefix) def Partition(self, separator: str) -> Tuple[str, str, str]: return self._message.partition(separator)
[docs] def GetIterator( self, stopPredicate: Nullable[Callable[["Line"], bool]] = None, *, reverse: bool = False, inclusive: bool = True, maxLines: Nullable[int] = None, ) -> Generator["Line", None, None]: """ Iterate consecutive lines starting from next line towards the end of the log. If the order is reversed, iterate starting at the previous line towards the beginning of the log. The iteration ends either at the bounds of the log, by specifying a stop predicate or a maximum number of lines to return. When stopped this line is usually included in the iteration, but can be excluded. :param stopPredicate: Optional, a callable receiving a :class:`Line` and returning ``True`` when iteration should stop at that line. :param reverse: Optional, reverse the iteration from previous line to the beginning of the log. :param inclusive: Optional, when ``True`` the line where ``stopPredicate`` or ``maxLines`` triggers, is included in the iteration, otherwise it's excluded. :param maxLines: Optional, maximum number of lines to yield. :returns: A generator yielding :class:`Line` in the requested direction, stopping at the log boundary, the predicate match, or the line limit — whichever comes first. :raises TypeError: When ``stopPredicate`` is not callable. :raises ValueError: When ``maxLines`` is not a positive integer. """ if stopPredicate is not None and not callable(stopPredicate): ex = TypeError("Parameter 'stopPredicate' is not a callable.") ex.add_note(f"Got type '{getFullyQualifiedName(stopPredicate)}'.") raise ex if not isinstance(reverse, bool): ex = TypeError("Parameter 'reverse' is not a boolean.") ex.add_note(f"Got type '{getFullyQualifiedName(reverse)}'.") raise ex if not isinstance(inclusive, bool): ex = TypeError("Parameter 'inclusive' is not a boolean.") ex.add_note(f"Got type '{getFullyQualifiedName(inclusive)}'.") raise ex if maxLines is not None: if not isinstance(maxLines, int): ex = TypeError("Parameter 'maxLines' is not a integer.") ex.add_note(f"Got type '{getFullyQualifiedName(maxLines)}'.") raise ex elif maxLines <= 0: ex = ValueError("Parameter 'maxLines' must be a positive integer.") ex.add_note(f"Got {maxLines!r}.") raise ex current = self._previousLine if reverse else self._nextLine if maxLines is None: if stopPredicate is None: if reverse: while current is not None: yield current current = current._previousLine else: while current is not None: yield current current = current._nextLine else: if reverse: while current is not None: if stopPredicate(current): if inclusive: yield current return yield current current = current._previousLine else: while current is not None: if stopPredicate(current): if inclusive: yield current return yield current current = current._nextLine elif stopPredicate is None: remaining = maxLines if reverse: while current is not None and remaining > 0: yield current current = current._previousLine remaining -= 1 else: while current is not None and remaining > 0: yield current current = current._nextLine remaining -= 1 else: remaining = maxLines if reverse: while current is not None and remaining > 0: if stopPredicate(current): if inclusive: yield current return yield current current = current._previousLine remaining -= 1 else: while current is not None and remaining > 0: if stopPredicate(current): if inclusive: yield current return yield current current = current._nextLine remaining -= 1
def __getitem__(self, item: slice) -> str: return self._message[item]
[docs] def __eq__(self, other: Any): return self._message == other
[docs] def __ne__(self, other: Any): return self._message != other
[docs] def __str__(self) -> str: return self._message
[docs] def __repr__(self) -> str: return f"{self._lineNumber}: {self._message}"
[docs] @export class InfoMessage(metaclass=ExtendedType, mixin=True): pass
[docs] @export class WarningMessage(metaclass=ExtendedType, mixin=True): pass
[docs] @export class CriticalWarningMessage(metaclass=ExtendedType, mixin=True): pass
[docs] @export class ErrorMessage(metaclass=ExtendedType, mixin=True): pass