def _init_test(self, test: Test) -> Optional[RunningTask]: """Initialize a test. Record outcome if the initialization fails. Record skip if the test is skipped. Save the initialized test if it successfully initializes. """ if test.skip: hilight_start = ANSI.COLOR_TEST if want_color_output() else '' hilight_end = ANSI.COLOR_DEFAULT if want_color_output() else '' # Want this to stand out a little bit self.log.info("{}Skipping test {}/{}:{} {}".format( hilight_start, self.count, self.ntests, hilight_end, test.__qualname__)) self._record_result(test, None, 0, 0) return None test_init_outcome = cocotb.outcomes.capture(test, self._dut) if isinstance(test_init_outcome, cocotb.outcomes.Error): self.log.error("Failed to initialize test %s" % test.__qualname__, exc_info=test_init_outcome.error) self._record_result(test, test_init_outcome, 0, 0) return None test = test_init_outcome.get() return test
def _log_test_failed(self, test: Test, result: Optional[Exception] = None, msg: Optional[str] = None) -> None: start_hilight = ANSI.COLOR_FAILED if want_color_output() else "" stop_hilight = ANSI.COLOR_DEFAULT if want_color_output() else "" if msg is None: rest = "" else: rest = f": {msg}" self.log.info(f"{test} {start_hilight}failed{stop_hilight}{rest}", exc_info=result)
def _log_test_summary(self): TEST_FIELD = 'TEST' RESULT_FIELD = 'PASS/FAIL' SIM_FIELD = 'SIM TIME(NS)' REAL_FIELD = 'REAL TIME(S)' RATIO_FIELD = 'RATIO(NS/S)' TEST_FIELD_LEN = max( len(TEST_FIELD), len(max([x['test'] for x in self.test_results], key=len))) RESULT_FIELD_LEN = len(RESULT_FIELD) SIM_FIELD_LEN = len(SIM_FIELD) REAL_FIELD_LEN = len(REAL_FIELD) RATIO_FIELD_LEN = len(RATIO_FIELD) LINE_LEN = 3 + TEST_FIELD_LEN + 2 + RESULT_FIELD_LEN + 2 + SIM_FIELD_LEN + 2 + REAL_FIELD_LEN + 2 + RATIO_FIELD_LEN + 3 LINE_SEP = "*" * LINE_LEN + "\n" summary = "" summary += LINE_SEP summary += "** {a:<{a_len}} {b:^{b_len}} {c:>{c_len}} {d:>{d_len}} {e:>{e_len}} **\n".format( a=TEST_FIELD, a_len=TEST_FIELD_LEN, b=RESULT_FIELD, b_len=RESULT_FIELD_LEN, c=SIM_FIELD, c_len=SIM_FIELD_LEN, d=REAL_FIELD, d_len=REAL_FIELD_LEN, e=RATIO_FIELD, e_len=RATIO_FIELD_LEN) summary += LINE_SEP for result in self.test_results: hilite = '' if result['pass'] is None: pass_fail_str = "N/A" elif result['pass']: pass_fail_str = "PASS" else: pass_fail_str = "FAIL" if want_color_output(): hilite = ANSI.COLOR_HILITE_SUMMARY summary += "{start}** {a:<{a_len}} {b:^{b_len}} {c:>{c_len}.2f} {d:>{d_len}.2f} {e:>{e_len}.2f} **\n".format( a=result['test'], a_len=TEST_FIELD_LEN, b=pass_fail_str, b_len=RESULT_FIELD_LEN, c=result['sim'], c_len=SIM_FIELD_LEN - 1, d=result['real'], d_len=REAL_FIELD_LEN - 1, e=result['ratio'], e_len=RATIO_FIELD_LEN - 1, start=hilite) summary += LINE_SEP self.log.info(summary)
def _log_test_passed(self, test: Test, result: Optional[Exception] = None, msg: Optional[str] = None) -> None: start_hilight = ANSI.COLOR_PASSED if want_color_output() else "" stop_hilight = ANSI.COLOR_DEFAULT if want_color_output() else "" if msg is None: rest = "" else: rest = f": {msg}" if result is None: result_was = "" else: result_was = f" (result was {type(result).__qualname__})" self.log.info( f"{test} {start_hilight}passed{stop_hilight}{rest}{result_was}")
def colour(self): warnings.warn( "the .colour attribute may be removed in future, use the " "equivalent `cocotb.utils.want_color_output()` instead", DeprecationWarning, stacklevel=2) return want_color_output()
def default_config(): """Apply the default cocotb log formatting to the root logger. This hooks up the logger to write to stdout, using either :class:`SimColourLogFormatter` or :class:`SimLogFormatter` depending on whether colored output is requested. It also adds a :class:`SimTimeContextFilter` filter so that :attr:`~logging.LogRecord.created_sim_time` is available to the formatter. The logging level for cocotb logs is set based on the :envvar:`COCOTB_LOG_LEVEL` environment variable, which defaults to ``INFO``. If desired, this logging configuration can be overwritten by calling ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by manually resetting the root logger instance. An example of this can be found in the section on :ref:`rotating-logger`. .. versionadded:: 1.4 """ # construct an appropriate handler hdlr = logging.StreamHandler(sys.stdout) hdlr.addFilter(SimTimeContextFilter()) if want_color_output(): hdlr.setFormatter(SimColourLogFormatter()) else: hdlr.setFormatter(SimLogFormatter()) logging.setLoggerClass(SimBaseLog) # For backwards compatibility logging.basicConfig() logging.getLogger().handlers = [hdlr] # overwrite default handlers # apply level settings for cocotb log = logging.getLogger("cocotb") try: # All log levels are upper case, convert the user input for convenience. level = os.environ["COCOTB_LOG_LEVEL"].upper() except KeyError: level = _COCOTB_LOG_LEVEL_DEFAULT try: log.setLevel(level) except ValueError: valid_levels = ("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE") raise ValueError( "Invalid log level %r passed through the " "COCOTB_LOG_LEVEL environment variable. Valid log " "levels: %s" % (level, ", ".join(valid_levels)) ) # Notify GPI of log level, which it uses as an optimization to avoid # calling into Python. from cocotb import simulator simulator.log_level(log.getEffectiveLevel())
def _init_test(self, test: Test) -> Optional[RunningTask]: """Initialize a test. Record outcome if the initialization fails. Record skip if the test is skipped. Save the initialized test if it successfully initializes. """ if test.skip: hilight_start = ANSI.COLOR_SKIPPED if want_color_output() else "" hilight_end = ANSI.COLOR_DEFAULT if want_color_output() else "" # Want this to stand out a little bit self.log.info("{start}skipping{end} {name} ({i}/{total})".format( start=hilight_start, i=self.count, total=self.ntests, end=hilight_end, name=test.__qualname__, )) self._record_result(test, None, 0, 0) return None test_init_outcome = cocotb.outcomes.capture(test, self._dut) if isinstance(test_init_outcome, cocotb.outcomes.Error): self.log.error( "Failed to initialize test %s" % test.__qualname__, exc_info=test_init_outcome.error, ) self._record_result(test, test_init_outcome, 0, 0) return None running_test = test_init_outcome.get() # seed random number generator based on test module, name, and RANDOM_SEED hasher = hashlib.sha1() hasher.update(test.__qualname__.encode()) hasher.update(test.__module__.encode()) seed = cocotb.RANDOM_SEED + int(hasher.hexdigest(), 16) random.seed(seed) return running_test
def __init__(self, name): super(SimBaseLog, self).__init__(name) # customizations of the defaults hdlr = logging.StreamHandler(sys.stdout) if want_color_output(): hdlr.setFormatter(SimColourLogFormatter()) else: hdlr.setFormatter(SimLogFormatter()) self.propagate = False self.addHandler(hdlr)
def _start_test(self) -> None: start = '' end = '' if want_color_output(): start = ANSI.COLOR_TEST end = ANSI.COLOR_DEFAULT # Want this to stand out a little bit self.log.info( "%sRunning test %d/%d:%s %s" % (start, self.count, self.ntests, end, self._test.__qualname__)) self._test_start_time = time.time() self._test_start_sim_time = get_sim_time('ns') cocotb.scheduler._add_test(self._test_task)
def execute(self): self._running_test = cocotb.regression_manager.next_test() if self._running_test: start = '' end = '' if want_color_output(): start = ANSI.COLOR_TEST end = ANSI.COLOR_DEFAULT # Want this to stand out a little bit self.log.info("%sRunning test %d/%d:%s %s" % (start, self.count, self.ntests, end, self._running_test.funcname)) cocotb.scheduler.add_test(self._running_test) self.count += 1 else: self.tear_down()
def default_config(): """ Apply the default cocotb log formatting to the root logger. This hooks up the logger to write to stdout, using either :class:`SimColourLogFormatter` or :class:`SimLogFormatter` depending on whether colored output is requested. It also adds a :class:`SimTimeContextFilter` filter so that :attr:`~logging.LogRecord.created_sim_time` is available to the formatter. The logging level for cocotb logs is set based on the :envvar:`COCOTB_LOG_LEVEL` environment variable, which defaults to ``INFO``. If desired, this logging configuration can be overwritten by calling ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by manually resetting the root logger instance. An example of this can be found in the section on :ref:`rotating-logger`. .. versionadded:: 1.4 """ # construct an appropriate handler hdlr = logging.StreamHandler(sys.stdout) hdlr.addFilter(SimTimeContextFilter()) if want_color_output(): hdlr.setFormatter(SimColourLogFormatter()) else: hdlr.setFormatter(SimLogFormatter()) logging.setLoggerClass(SimBaseLog) # For backwards compatibility logging.basicConfig() logging.getLogger().handlers = [hdlr] # overwrite default handlers # apply level settings for cocotb log = logging.getLogger('cocotb') level = os.getenv("COCOTB_LOG_LEVEL", "INFO") try: _default_log = getattr(logging, level) except AttributeError: log.error("Unable to set logging level to %r" % level) _default_log = logging.INFO log.setLevel(_default_log) # Notify GPI of log level, which it uses as an optimization to avoid # calling into Python. from cocotb import simulator simulator.log_level(_default_log)
def _start_test(self) -> None: start = '' end = '' if want_color_output(): start = ANSI.COLOR_TEST end = ANSI.COLOR_DEFAULT # Want this to stand out a little bit self.log.info("{start}running{end} {name} ({i}/{total})".format( start=start, i=self.count, total=self.ntests, end=end, name=self._test.__qualname__, )) self._test_start_time = time.time() self._test_start_sim_time = get_sim_time('ns') cocotb.scheduler._add_test(self._test_task)
def _start_test(self) -> None: # Want this to stand out a little bit start = "" end = "" if want_color_output(): start = ANSI.COLOR_TEST end = ANSI.COLOR_DEFAULT self.log.info( "{start}running{end} {name} ({i}/{total}){description}".format( start=start, i=self.count, total=self.ntests, end=end, name=self._test.__qualname__, description=_trim(self._test.__doc__), )) self._test_start_time = time.time() self._test_start_sim_time = get_sim_time("ns") cocotb.scheduler._add_test(self._test_task)
def _log_test_summary(self) -> None: real_time = time.time() - self.start_time sim_time_ns = get_sim_time("ns") ratio_time = self._safe_divide(sim_time_ns, real_time) if len(self.test_results) == 0: return TEST_FIELD = "TEST" RESULT_FIELD = "STATUS" SIM_FIELD = "SIM TIME (ns)" REAL_FIELD = "REAL TIME (s)" RATIO_FIELD = "RATIO (ns/s)" TOTAL_NAME = f"TESTS={self.ntests} PASS={self.passed} FAIL={self.failures} SKIP={self.skipped}" TEST_FIELD_LEN = max( len(TEST_FIELD), len(TOTAL_NAME), len(max([x["test"] for x in self.test_results], key=len)), ) RESULT_FIELD_LEN = len(RESULT_FIELD) SIM_FIELD_LEN = len(SIM_FIELD) REAL_FIELD_LEN = len(REAL_FIELD) RATIO_FIELD_LEN = len(RATIO_FIELD) header_dict = dict( a=TEST_FIELD, b=RESULT_FIELD, c=SIM_FIELD, d=REAL_FIELD, e=RATIO_FIELD, a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN, d_len=REAL_FIELD_LEN, e_len=RATIO_FIELD_LEN, ) LINE_LEN = (3 + TEST_FIELD_LEN + 2 + RESULT_FIELD_LEN + 2 + SIM_FIELD_LEN + 2 + REAL_FIELD_LEN + 2 + RATIO_FIELD_LEN + 3) LINE_SEP = "*" * LINE_LEN + "\n" summary = "" summary += LINE_SEP summary += "** {a:<{a_len}} {b:^{b_len}} {c:>{c_len}} {d:>{d_len}} {e:>{e_len}} **\n".format( **header_dict) summary += LINE_SEP test_line = "** {a:<{a_len}} {start}{b:^{b_len}}{end} {c:>{c_len}.2f} {d:>{d_len}.2f} {e:>{e_len}} **\n" for result in self.test_results: hilite = "" lolite = "" if result["pass"] is None: ratio = "-.--" pass_fail_str = "SKIP" if want_color_output(): hilite = ANSI.COLOR_SKIPPED lolite = ANSI.COLOR_DEFAULT elif result["pass"]: ratio = format(result["ratio"], "0.2f") pass_fail_str = "PASS" if want_color_output(): hilite = ANSI.COLOR_PASSED lolite = ANSI.COLOR_DEFAULT else: ratio = format(result["ratio"], "0.2f") pass_fail_str = "FAIL" if want_color_output(): hilite = ANSI.COLOR_FAILED lolite = ANSI.COLOR_DEFAULT test_dict = dict( a=result["test"], b=pass_fail_str, c=result["sim"], d=result["real"], e=ratio, a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN - 1, d_len=REAL_FIELD_LEN - 1, e_len=RATIO_FIELD_LEN - 1, start=hilite, end=lolite, ) summary += test_line.format(**test_dict) summary += LINE_SEP summary += test_line.format( a=TOTAL_NAME, b="", c=sim_time_ns, d=real_time, e=format(ratio_time, "0.2f"), a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN - 1, d_len=REAL_FIELD_LEN - 1, e_len=RATIO_FIELD_LEN - 1, start="", end="", ) summary += LINE_SEP self.log.info(summary)
def _log_test_summary(self) -> None: if self.failures: self.log.error("Failed %d out of %d tests (%d skipped)" % (self.failures, self.count, self.skipped)) else: self.log.info("Passed %d tests (%d skipped)" % (self.count, self.skipped)) if len(self.test_results) == 0: return TEST_FIELD = 'TEST' RESULT_FIELD = 'PASS/FAIL' SIM_FIELD = 'SIM TIME(NS)' REAL_FIELD = 'REAL TIME(S)' RATIO_FIELD = 'RATIO(NS/S)' TEST_FIELD_LEN = max( len(TEST_FIELD), len(max([x['test'] for x in self.test_results], key=len))) RESULT_FIELD_LEN = len(RESULT_FIELD) SIM_FIELD_LEN = len(SIM_FIELD) REAL_FIELD_LEN = len(REAL_FIELD) RATIO_FIELD_LEN = len(RATIO_FIELD) header_dict = dict(a=TEST_FIELD, b=RESULT_FIELD, c=SIM_FIELD, d=REAL_FIELD, e=RATIO_FIELD, a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN, d_len=REAL_FIELD_LEN, e_len=RATIO_FIELD_LEN) LINE_LEN = 3 + TEST_FIELD_LEN + 2 + RESULT_FIELD_LEN + 2 + SIM_FIELD_LEN + 2 + \ REAL_FIELD_LEN + 2 + RATIO_FIELD_LEN + 3 LINE_SEP = "*" * LINE_LEN + "\n" summary = "" summary += LINE_SEP summary += "** {a:<{a_len}} {b:^{b_len}} {c:>{c_len}} {d:>{d_len}} {e:>{e_len}} **\n".format( **header_dict) summary += LINE_SEP test_line = "{start}** {a:<{a_len}} {b:^{b_len}} {c:>{c_len}.2f} {d:>{d_len}.2f} {e:>{e_len}.2f} **\n" for result in self.test_results: hilite = '' if result['pass'] is None: pass_fail_str = "N/A" elif result['pass']: pass_fail_str = "PASS" else: pass_fail_str = "FAIL" if want_color_output(): hilite = ANSI.COLOR_HILITE_SUMMARY test_dict = dict(a=result['test'], b=pass_fail_str, c=result['sim'], d=result['real'], e=result['ratio'], a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN - 1, d_len=REAL_FIELD_LEN - 1, e_len=RATIO_FIELD_LEN - 1, start=hilite) summary += test_line.format(**test_dict) summary += LINE_SEP self.log.info(summary)
import logging import sys import re from explainusb.descriptors import descriptor_data # Use cocotb logging if available. Use the built in logging module otherwise. # The color routines check if stdout is a tty. SAME_COLOR = '' DIFF_COLOR = '' try: from cocotb.log import SimLog from cocotb.utils import want_color_output import cocotb.ANSI as ANSI logger = SimLog("cocotb.usb.explain") #logger.setLevel(logging.DEBUG) if want_color_output(): SAME_COLOR = ANSI.COLOR_INFO DIFF_COLOR = ANSI.COLOR_ERROR except ImportError: logger = logging # Create a pretty printer object to display descriptors as structures. # Leave list unsorted if the option is available. if sys.version_info >= (3, 8): pp = pprint.PrettyPrinter(sort_dicts=False) else: pp = pprint.PrettyPrinter() # Use UTF empty set symbol for non-existant field in packet comparisons as long # as environment is not limited to 8-bit characters. import locale