Source code for skidl.skidlbaseobj

# -*- coding: utf-8 -*-

# The MIT License (MIT) - Copyright (c) 2016-2021 Dave Vandenbout.

"""
Base object for Circuit, Interface, Package, Part, Net, Bus, Pin objects.
"""

from __future__ import (  # isort:skip
    absolute_import,
    division,
    print_function,
    unicode_literals,
)

import inspect
from builtins import object, range, str, super
from collections import namedtuple
from copy import deepcopy

from future import standard_library

from .alias import Alias
from .note import Note

standard_library.install_aliases()

OK, WARNING, ERROR = list(range(3))


[docs]class SkidlBaseObject(object): # These are fallback lists so every object will have them to reference. erc_list = list() erc_assertion_list = list() def __init__(self): self.fields = {} def __getattr__(self, key): try: # Don't use super()!! It leads to long run times on Python 2.7. return self.__getattribute__("fields")[key] except KeyError: raise AttributeError def __setattr__(self, key, value): if key == "fields" or key not in self.fields: super().__setattr__(key, value) else: self.fields[key] = value @property def aliases(self): try: return self._aliases except AttributeError: return Alias([]) # No aliases, so just return an empty list. @aliases.setter def aliases(self, name_or_list): if not name_or_list: return self._aliases = Alias(name_or_list) @aliases.deleter def aliases(self): try: del self._aliases except AttributeError: pass @property def notes(self): try: return self._notes except AttributeError: return Note([]) # No notes, so just return empty list. @notes.setter def notes(self, text_or_notes): if not text_or_notes: return self._notes = Note(text_or_notes) @notes.deleter def notes(self): try: del self._notes except AttributeError: pass
[docs] def copy(self): cpy = SkidlBaseObject() cpy.fields = deepcopy(self.fields) try: cpy.aliases = deepcopy(self.aliases) except AttributeError: pass try: cpy.notes = deepcopy(self.notes) except AttributeError: pass return cpy
[docs] def ERC(self, *args, **kwargs): """Run ERC on this object.""" # Run ERC functions. self._exec_erc_functions(*args, **kwargs) # Run ERC assertions. self._eval_erc_assertions()
[docs] def add_erc_function(self, func): """Add an ERC function to a class or class instance.""" self.erc_list.append(func)
[docs] def add_erc_assertion(self, assertion, fail_msg="FAILED", severity=ERROR): """Add an ERC assertion to a class or class instance.""" # Tuple for storing assertion code object with its global & local dicts. EvalTuple = namedtuple( "EvalTuple", "stmnt fail_msg severity filename lineno function globals locals", ) assertion_frame, filename, lineno, function, _, _ = inspect.stack()[1] self.erc_assertion_list.append( EvalTuple( assertion, fail_msg, severity, filename, lineno, function, assertion_frame.f_globals, assertion_frame.f_locals, ) )
def _eval_erc_assertions(self): """ Evaluate assertions for this object. """ from .logger import active_logger def erc_report(evtpl): log_msg = "{evtpl.stmnt} {evtpl.fail_msg} in {evtpl.filename}:{evtpl.lineno}:{evtpl.function}.".format( evtpl=evtpl ) if evtpl.severity == ERROR: active_logger.error(log_msg) elif evtpl.severity == WARNING: active_logger.warning(log_msg) for evtpl in self.erc_assertion_list: if eval(evtpl.stmnt, evtpl.globals, evtpl.locals) == False: erc_report(evtpl) def _exec_erc_functions(self, *args, **kwargs): """ Execute ERC functions on a class instance. Args: args, kwargs: Arbitary argument lists to pass to the functions that are executed. (All functions get the same arguments.) """ # Execute any instance functions for this particular instance. for f in self.erc_list: f(self, *args, **kwargs)