cocotb 2.0.0b1__cp313-cp313-win32.whl → 2.0.0rc2__cp313-cp313-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cocotb might be problematic. Click here for more details.
- cocotb/_ANSI.py +47 -54
- cocotb/__init__.py +12 -2
- cocotb/_base_triggers.py +11 -9
- cocotb/_bridge.py +8 -9
- cocotb/_extended_awaitables.py +1 -1
- cocotb/_gpi_triggers.py +4 -1
- cocotb/_init.py +17 -11
- cocotb/_py_compat.py +24 -10
- cocotb/_scheduler.py +25 -31
- cocotb/_test.py +6 -3
- cocotb/_test_factory.py +4 -1
- cocotb/_utils.py +1 -23
- cocotb/_version.py +1 -1
- cocotb/clock.py +98 -16
- cocotb/debug.py +24 -0
- cocotb/handle.py +62 -32
- cocotb/libs/cocotb.dll +0 -0
- cocotb/libs/cocotb.exp +0 -0
- cocotb/libs/cocotb.lib +0 -0
- cocotb/libs/cocotbfli_modelsim.dll +0 -0
- cocotb/libs/cocotbfli_modelsim.exp +0 -0
- cocotb/libs/cocotbfli_modelsim.lib +0 -0
- cocotb/libs/cocotbutils.dll +0 -0
- cocotb/libs/cocotbutils.exp +0 -0
- cocotb/libs/cocotbutils.lib +0 -0
- cocotb/libs/cocotbvhpi_aldec.dll +0 -0
- cocotb/libs/cocotbvhpi_aldec.exp +0 -0
- cocotb/libs/cocotbvhpi_aldec.lib +0 -0
- cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
- cocotb/libs/cocotbvpi_aldec.dll +0 -0
- cocotb/libs/cocotbvpi_aldec.exp +0 -0
- cocotb/libs/cocotbvpi_aldec.lib +0 -0
- cocotb/libs/cocotbvpi_ghdl.dll +0 -0
- cocotb/libs/cocotbvpi_ghdl.exp +0 -0
- cocotb/libs/cocotbvpi_ghdl.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.exp +0 -0
- cocotb/libs/cocotbvpi_icarus.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.vpl +0 -0
- cocotb/libs/cocotbvpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvpi_modelsim.lib +0 -0
- cocotb/libs/embed.dll +0 -0
- cocotb/libs/embed.exp +0 -0
- cocotb/libs/embed.lib +0 -0
- cocotb/libs/gpi.dll +0 -0
- cocotb/libs/gpi.exp +0 -0
- cocotb/libs/gpi.lib +0 -0
- cocotb/libs/gpilog.dll +0 -0
- cocotb/libs/gpilog.exp +0 -0
- cocotb/libs/gpilog.lib +0 -0
- cocotb/libs/pygpilog.dll +0 -0
- cocotb/libs/pygpilog.exp +0 -0
- cocotb/libs/pygpilog.lib +0 -0
- cocotb/logging.py +243 -117
- cocotb/regression.py +43 -35
- cocotb/share/def/aldec.exp +0 -0
- cocotb/share/def/aldec.lib +0 -0
- cocotb/share/def/ghdl.exp +0 -0
- cocotb/share/def/ghdl.lib +0 -0
- cocotb/share/def/icarus.exp +0 -0
- cocotb/share/def/icarus.lib +0 -0
- cocotb/share/def/modelsim.exp +0 -0
- cocotb/share/def/modelsim.lib +0 -0
- cocotb/share/include/cocotb_utils.h +3 -3
- cocotb/share/include/embed.h +2 -2
- cocotb/share/include/gpi.h +258 -109
- cocotb/share/include/py_gpi_logging.h +3 -3
- cocotb/share/lib/verilator/verilator.cpp +23 -15
- cocotb/simtime.py +230 -0
- cocotb/simulator.cp313-win32.exp +0 -0
- cocotb/simulator.cp313-win32.lib +0 -0
- cocotb/simulator.cp313-win32.pyd +0 -0
- cocotb/task.py +54 -11
- cocotb/types/__init__.py +4 -1
- cocotb/types/_array.py +33 -2
- cocotb/types/_indexing.py +17 -0
- cocotb/types/_logic.py +96 -59
- cocotb/types/_logic_array.py +56 -22
- cocotb/types/_range.py +12 -5
- cocotb/utils.py +9 -129
- {cocotb-2.0.0b1.dist-info → cocotb-2.0.0rc2.dist-info}/METADATA +1 -1
- cocotb-2.0.0rc2.dist-info/RECORD +146 -0
- {cocotb-2.0.0b1.dist-info → cocotb-2.0.0rc2.dist-info}/licenses/LICENSE +1 -0
- cocotb_tools/config.py +5 -5
- cocotb_tools/makefiles/Makefile.inc +3 -9
- cocotb_tools/makefiles/Makefile.sim +9 -1
- cocotb_tools/makefiles/simulators/Makefile.vcs +1 -1
- cocotb_tools/runner.py +94 -59
- pygpi/entry.py +5 -6
- cocotb-2.0.0b1.dist-info/RECORD +0 -143
- {cocotb-2.0.0b1.dist-info → cocotb-2.0.0rc2.dist-info}/WHEEL +0 -0
- {cocotb-2.0.0b1.dist-info → cocotb-2.0.0rc2.dist-info}/entry_points.txt +0 -0
- {cocotb-2.0.0b1.dist-info → cocotb-2.0.0rc2.dist-info}/top_level.txt +0 -0
cocotb/logging.py
CHANGED
|
@@ -10,74 +10,125 @@ Everything related to logging
|
|
|
10
10
|
|
|
11
11
|
import logging
|
|
12
12
|
import os
|
|
13
|
+
import re
|
|
13
14
|
import sys
|
|
15
|
+
import time
|
|
16
|
+
import warnings
|
|
14
17
|
from functools import wraps
|
|
15
18
|
from pathlib import Path
|
|
16
|
-
from typing import Union
|
|
19
|
+
from typing import Optional, Tuple, Union
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
import cocotb.simtime
|
|
22
|
+
from cocotb import simulator
|
|
23
|
+
from cocotb._ANSI import ANSI
|
|
19
24
|
from cocotb._deprecation import deprecated
|
|
20
|
-
from cocotb.
|
|
21
|
-
from cocotb.utils import
|
|
25
|
+
from cocotb.simtime import get_sim_time
|
|
26
|
+
from cocotb.utils import get_time_from_sim_steps
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
__all__ = (
|
|
29
|
+
"ANSI",
|
|
30
|
+
"SimLog",
|
|
31
|
+
"SimLogFormatter",
|
|
32
|
+
"SimTimeContextFilter",
|
|
33
|
+
"default_config",
|
|
34
|
+
"strip_ansi",
|
|
35
|
+
)
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
_LEVEL_CHARS = len("CRITICAL")
|
|
30
|
-
_RECORD_CHARS = 34
|
|
31
|
-
_FILENAME_CHARS = 20
|
|
32
|
-
_LINENO_CHARS = 4
|
|
33
|
-
_FUNCNAME_CHARS = 31
|
|
37
|
+
ANSI.__module__ = __name__
|
|
34
38
|
|
|
35
39
|
# Custom log level
|
|
36
40
|
logging.TRACE = 5 # type: ignore[attr-defined] # type checkers don't like adding module attributes after the fact
|
|
37
41
|
logging.addLevelName(5, "TRACE")
|
|
38
42
|
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
44
|
+
strip_ansi: bool = False
|
|
45
|
+
"""Whether the default formatter should strip ANSI (color) escape codes from log messages.
|
|
46
|
+
|
|
47
|
+
Defaults to ``True`` if ``stdout`` is not a TTY and ``False`` otherwise;
|
|
48
|
+
but can be overridden with the :envvar:`NO_COLOR` or :envvar:`COCOTB_ANSI_OUTPUT` environment variable.
|
|
49
|
+
"""
|
|
47
50
|
|
|
48
51
|
|
|
49
|
-
def default_config(
|
|
52
|
+
def default_config(
|
|
53
|
+
reduced_log_fmt: bool = True,
|
|
54
|
+
strip_ansi: Optional[bool] = None,
|
|
55
|
+
prefix_format: Optional[str] = None,
|
|
56
|
+
) -> None:
|
|
50
57
|
"""Apply the default cocotb log formatting to the root logger.
|
|
51
58
|
|
|
52
|
-
This hooks up the logger to write to stdout, using
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
:attr:`~logging.LogRecord.created_sim_time` is available to the formatter.
|
|
59
|
+
This hooks up the logger to write to stdout, using :class:`SimLogFormatter` for formatting.
|
|
60
|
+
It also adds a :class:`SimTimeContextFilter` filter so that the
|
|
61
|
+
:attr:`~logging.LogRecord.created_sim_time` attribute on :class:`~logging.LogRecord`
|
|
62
|
+
is available to the formatter.
|
|
57
63
|
|
|
58
64
|
If desired, this logging configuration can be overwritten by calling
|
|
59
|
-
``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards),
|
|
60
|
-
manually resetting the root logger instance.
|
|
65
|
+
``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards),
|
|
66
|
+
or by manually resetting the root logger instance.
|
|
61
67
|
An example of this can be found in the section on :ref:`rotating-logger`.
|
|
62
68
|
|
|
69
|
+
Args:
|
|
70
|
+
reduced_log_fmt:
|
|
71
|
+
If ``True``, use a reduced log format that does not include the
|
|
72
|
+
filename, line number, and function name in the log prefix.
|
|
73
|
+
|
|
74
|
+
.. versionadded:: 2.0
|
|
75
|
+
|
|
76
|
+
strip_ansi:
|
|
77
|
+
If ``True``, strip ANSI (color) escape codes in log messages.
|
|
78
|
+
If ``False``, do not strip ANSI escape codes in log messages.
|
|
79
|
+
If ``None``, use the value of :data:`strip_ansi`.
|
|
80
|
+
|
|
81
|
+
.. versionadded:: 2.0
|
|
82
|
+
|
|
83
|
+
prefix_format:
|
|
84
|
+
An f-string to build a prefix for each log message.
|
|
85
|
+
|
|
86
|
+
.. versionadded:: 2.0
|
|
87
|
+
|
|
63
88
|
.. versionadded:: 1.4
|
|
64
89
|
|
|
65
90
|
.. versionchanged:: 2.0
|
|
66
|
-
|
|
91
|
+
Now captures warnings and outputs them through the logging system using
|
|
92
|
+
:func:`logging.captureWarnings`.
|
|
67
93
|
"""
|
|
94
|
+
logging.basicConfig()
|
|
95
|
+
|
|
68
96
|
hdlr = logging.StreamHandler(sys.stdout)
|
|
69
97
|
hdlr.addFilter(SimTimeContextFilter())
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
98
|
+
hdlr.setFormatter(
|
|
99
|
+
SimLogFormatter(
|
|
100
|
+
reduced_log_fmt=reduced_log_fmt,
|
|
101
|
+
strip_ansi=strip_ansi,
|
|
102
|
+
prefix_format=prefix_format,
|
|
103
|
+
)
|
|
104
|
+
)
|
|
76
105
|
logging.getLogger().handlers = [hdlr] # overwrite default handlers
|
|
77
106
|
|
|
107
|
+
logging.getLogger("cocotb").setLevel(logging.INFO)
|
|
108
|
+
logging.getLogger("gpi").setLevel(logging.INFO)
|
|
78
109
|
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
logging.captureWarnings(True)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _init() -> None:
|
|
114
|
+
"""cocotb-specific logging setup.
|
|
115
|
+
|
|
116
|
+
- Decides whether ANSI escape code stripping is desired by checking
|
|
117
|
+
:envvar:`NO_COLOR` and :envvar:`COCOTB_ANSI_OUTPUT`.
|
|
118
|
+
- Initializes the GPI logger and sets up the GPI logging optimization.
|
|
119
|
+
- Sets the log level of the ``"cocotb"`` and ``"gpi"`` loggers based on
|
|
120
|
+
:envvar:`COCOTB_LOG_LEVEL` and :envvar:`GPI_LOG_LEVEL`, respectively.
|
|
121
|
+
"""
|
|
122
|
+
global strip_ansi
|
|
123
|
+
strip_ansi = not sys.stdout.isatty() # default to color for TTYs
|
|
124
|
+
if os.getenv("NO_COLOR", ""):
|
|
125
|
+
strip_ansi = True
|
|
126
|
+
ansi_output = os.getenv("COCOTB_ANSI_OUTPUT")
|
|
127
|
+
if ansi_output is not None:
|
|
128
|
+
strip_ansi = not int(ansi_output)
|
|
129
|
+
in_gui = os.getenv("GUI")
|
|
130
|
+
if in_gui is not None:
|
|
131
|
+
strip_ansi = bool(int(in_gui))
|
|
81
132
|
|
|
82
133
|
# Monkeypatch "gpi" logger with function that also sets a PyGPI-local logger level
|
|
83
134
|
# as an optimization.
|
|
@@ -95,8 +146,11 @@ def _init(_: object) -> None:
|
|
|
95
146
|
simulator.initialize_logger(_log_from_c, logging.getLogger)
|
|
96
147
|
|
|
97
148
|
# Set "cocotb" and "gpi" logger based on environment variables
|
|
98
|
-
def set_level(logger_name: str, envvar: str
|
|
99
|
-
log_level = os.environ.get(envvar
|
|
149
|
+
def set_level(logger_name: str, envvar: str) -> None:
|
|
150
|
+
log_level = os.environ.get(envvar)
|
|
151
|
+
if log_level is None:
|
|
152
|
+
return
|
|
153
|
+
|
|
100
154
|
log_level = log_level.upper()
|
|
101
155
|
|
|
102
156
|
logger = logging.getLogger(logger_name)
|
|
@@ -113,18 +167,24 @@ def _init(_: object) -> None:
|
|
|
113
167
|
f"levels: {valid_levels}"
|
|
114
168
|
) from None
|
|
115
169
|
|
|
116
|
-
set_level("gpi", "GPI_LOG_LEVEL"
|
|
117
|
-
set_level("cocotb", "COCOTB_LOG_LEVEL"
|
|
170
|
+
set_level("gpi", "GPI_LOG_LEVEL")
|
|
171
|
+
set_level("cocotb", "COCOTB_LOG_LEVEL")
|
|
118
172
|
|
|
119
173
|
|
|
120
|
-
def
|
|
121
|
-
"""
|
|
122
|
-
|
|
174
|
+
def _configure(_: object) -> None:
|
|
175
|
+
"""Configure basic logging."""
|
|
176
|
+
reduced_log_fmt = True
|
|
177
|
+
try:
|
|
178
|
+
reduced_log_fmt = bool(int(os.environ.get("COCOTB_REDUCED_LOG_FMT", "1")))
|
|
179
|
+
except ValueError:
|
|
180
|
+
pass
|
|
181
|
+
prefix_format = os.environ.get("COCOTB_LOG_PREFIX", None)
|
|
182
|
+
default_config(reduced_log_fmt=reduced_log_fmt, prefix_format=prefix_format)
|
|
123
183
|
|
|
124
184
|
|
|
125
185
|
@deprecated('Use `logging.getLogger(f"{name}.0x{ident:x}")` instead')
|
|
126
186
|
def SimLog(name: str, ident: Union[int, None] = None) -> logging.Logger:
|
|
127
|
-
"""Like logging.getLogger
|
|
187
|
+
"""Like :func:`logging.getLogger`, but append a numeric identifier to the name.
|
|
128
188
|
|
|
129
189
|
Args:
|
|
130
190
|
name: Logger name.
|
|
@@ -146,18 +206,12 @@ class SimTimeContextFilter(logging.Filter):
|
|
|
146
206
|
"""
|
|
147
207
|
A filter to inject simulator times into the log records.
|
|
148
208
|
|
|
149
|
-
This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual
|
|
150
|
-
|
|
151
|
-
This adds the :attr:`~logging.LogRecord.created_sim_time` attribute.
|
|
209
|
+
This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual>`
|
|
210
|
+
which adds the :attr:`~logging.LogRecord.created_sim_time` attribute.
|
|
152
211
|
|
|
153
212
|
.. versionadded:: 1.4
|
|
154
213
|
"""
|
|
155
214
|
|
|
156
|
-
# needed to make our docs render well
|
|
157
|
-
def __init__(self) -> None:
|
|
158
|
-
""""""
|
|
159
|
-
super().__init__()
|
|
160
|
-
|
|
161
215
|
def filter(self, record: logging.LogRecord) -> bool:
|
|
162
216
|
try:
|
|
163
217
|
record.created_sim_time = get_sim_time()
|
|
@@ -174,13 +228,65 @@ class SimLogFormatter(logging.Formatter):
|
|
|
174
228
|
This will only add simulator timestamps if the handler object this
|
|
175
229
|
formatter is attached to has a :class:`SimTimeContextFilter` filter
|
|
176
230
|
attached, which cocotb ensures by default.
|
|
231
|
+
|
|
232
|
+
See :func:`.default_config` for a description of the arguments.
|
|
177
233
|
"""
|
|
178
234
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
235
|
+
loglevel2colour = {
|
|
236
|
+
logging.TRACE: "", # type: ignore[attr-defined] # type checkers don't like adding module attributes after the fact
|
|
237
|
+
logging.DEBUG: "",
|
|
238
|
+
logging.INFO: "",
|
|
239
|
+
logging.WARNING: ANSI.YELLOW_FG,
|
|
240
|
+
logging.ERROR: ANSI.RED_FG,
|
|
241
|
+
logging.CRITICAL: ANSI.RED_BG + ANSI.BLACK_FG,
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
prefix_func_globals = {
|
|
245
|
+
"time": time,
|
|
246
|
+
"simtime": cocotb.simtime,
|
|
247
|
+
"ANSI": ANSI,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
def __init__(
|
|
251
|
+
self,
|
|
252
|
+
*,
|
|
253
|
+
reduced_log_fmt: bool = True,
|
|
254
|
+
strip_ansi: Union[bool, None] = None,
|
|
255
|
+
prefix_format: Optional[str] = None,
|
|
256
|
+
) -> None:
|
|
257
|
+
self._reduced_log_fmt = reduced_log_fmt
|
|
258
|
+
self._strip_ansi = strip_ansi
|
|
259
|
+
self._prefix_func = (
|
|
260
|
+
eval(
|
|
261
|
+
f"lambda record: f'''{prefix_format}'''",
|
|
262
|
+
type(self).prefix_func_globals,
|
|
263
|
+
)
|
|
264
|
+
if prefix_format is not None
|
|
265
|
+
else None
|
|
266
|
+
)
|
|
267
|
+
self._ansi_escape_pattern = re.compile(
|
|
268
|
+
r"""
|
|
269
|
+
(?: # either 7-bit C1, two bytes, ESC Fe (omitting CSI)
|
|
270
|
+
\x1B
|
|
271
|
+
[@-Z\\-_]
|
|
272
|
+
| # or a single 8-bit byte Fe (omitting CSI)
|
|
273
|
+
[\x80-\x9A\x9C-\x9F]
|
|
274
|
+
| # or CSI + control codes
|
|
275
|
+
(?: # 7-bit CSI, ESC [
|
|
276
|
+
\x1B\[
|
|
277
|
+
| # 8-bit CSI, 9B
|
|
278
|
+
\x9B
|
|
279
|
+
)
|
|
280
|
+
[0-?]* # Parameter bytes
|
|
281
|
+
[ -/]* # Intermediate bytes
|
|
282
|
+
[@-~] # Final byte
|
|
283
|
+
)
|
|
284
|
+
""",
|
|
285
|
+
re.VERBOSE,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
def strip_ansi(self) -> bool:
|
|
289
|
+
return strip_ansi if self._strip_ansi is None else self._strip_ansi
|
|
184
290
|
|
|
185
291
|
# Justify and truncate
|
|
186
292
|
@staticmethod
|
|
@@ -195,88 +301,108 @@ class SimLogFormatter(logging.Formatter):
|
|
|
195
301
|
return ".." + string[(chars - 2) * -1 :]
|
|
196
302
|
return string.rjust(chars)
|
|
197
303
|
|
|
198
|
-
def
|
|
199
|
-
self, level: str, record: logging.LogRecord, msg: str, coloured: bool = False
|
|
200
|
-
) -> str:
|
|
304
|
+
def formatPrefix(self, record: logging.LogRecord) -> Tuple[str, int]:
|
|
201
305
|
sim_time = getattr(record, "created_sim_time", None)
|
|
202
306
|
if sim_time is None:
|
|
203
307
|
sim_time_str = " -.--ns"
|
|
204
308
|
else:
|
|
205
309
|
time_ns = get_time_from_sim_steps(sim_time, "ns")
|
|
206
310
|
sim_time_str = f"{time_ns:6.2f}ns"
|
|
207
|
-
prefix = (
|
|
208
|
-
sim_time_str.rjust(11)
|
|
209
|
-
+ " "
|
|
210
|
-
+ level
|
|
211
|
-
+ " "
|
|
212
|
-
+ self.ljust(record.name, _RECORD_CHARS)
|
|
213
|
-
+ " "
|
|
214
|
-
)
|
|
215
|
-
if not _suppress:
|
|
216
|
-
prefix += (
|
|
217
|
-
self.rjust(Path(record.filename).name, _FILENAME_CHARS)
|
|
218
|
-
+ ":"
|
|
219
|
-
+ self.ljust(str(record.lineno), _LINENO_CHARS)
|
|
220
|
-
+ " in "
|
|
221
|
-
+ self.ljust(str(record.funcName), _FUNCNAME_CHARS)
|
|
222
|
-
+ " "
|
|
223
|
-
)
|
|
224
311
|
|
|
225
|
-
|
|
312
|
+
if self.strip_ansi():
|
|
313
|
+
highlight_start = ""
|
|
314
|
+
highlight_end = ""
|
|
315
|
+
else:
|
|
316
|
+
highlight_start = self.loglevel2colour.get(record.levelno, "")
|
|
317
|
+
highlight_end = ANSI.DEFAULT
|
|
318
|
+
|
|
319
|
+
if self._prefix_func is not None:
|
|
320
|
+
prefix = self._prefix_func(record)
|
|
321
|
+
stripped_prefix = self._ansi_escape_pattern.sub("", prefix)
|
|
322
|
+
prefix_len = len(stripped_prefix)
|
|
323
|
+
return prefix, prefix_len
|
|
324
|
+
else:
|
|
325
|
+
prefix = f"{sim_time_str:>11} {highlight_start}{record.levelname:<8}{highlight_end} {self.ljust(record.name, 34)} "
|
|
326
|
+
if not self._reduced_log_fmt:
|
|
327
|
+
prefix = f"{prefix}{self.rjust(Path(record.filename).name, 20)}:{record.lineno:<4} in {self.ljust(str(record.funcName), 31)} "
|
|
328
|
+
|
|
329
|
+
prefix_len = len(prefix) - len(highlight_start) - len(highlight_end)
|
|
330
|
+
return prefix, prefix_len
|
|
331
|
+
|
|
332
|
+
def formatMessage(self, record: logging.LogRecord) -> str:
|
|
333
|
+
msg = record.getMessage()
|
|
334
|
+
|
|
335
|
+
if self.strip_ansi():
|
|
336
|
+
highlight_start = ""
|
|
337
|
+
highlight_end = ""
|
|
338
|
+
msg = self._ansi_escape_pattern.sub("", msg)
|
|
339
|
+
else:
|
|
340
|
+
highlight_start = self.loglevel2colour.get(record.levelno, "")
|
|
341
|
+
highlight_end = ANSI.DEFAULT
|
|
342
|
+
|
|
343
|
+
msg = f"{highlight_start}{msg}{highlight_end}"
|
|
344
|
+
|
|
345
|
+
return msg
|
|
346
|
+
|
|
347
|
+
def formatExcInfo(self, record: logging.LogRecord) -> str:
|
|
348
|
+
msg = ""
|
|
349
|
+
|
|
350
|
+
# these lines are copied and updated from the built-in logger
|
|
226
351
|
if record.exc_info:
|
|
227
352
|
# Cache the traceback text to avoid converting it multiple times
|
|
228
353
|
# (it's constant anyway)
|
|
229
354
|
if not record.exc_text:
|
|
230
355
|
record.exc_text = self.formatException(record.exc_info)
|
|
231
356
|
if record.exc_text:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
357
|
+
msg += record.exc_text
|
|
358
|
+
if record.stack_info:
|
|
359
|
+
if not msg.endswith("\n"):
|
|
360
|
+
msg += "\n"
|
|
361
|
+
msg += self.formatStack(record.stack_info)
|
|
235
362
|
|
|
236
|
-
|
|
237
|
-
if coloured:
|
|
238
|
-
prefix_len -= len(level) - _LEVEL_CHARS
|
|
239
|
-
pad = "\n" + " " * (prefix_len)
|
|
240
|
-
return prefix + pad.join(msg.split("\n"))
|
|
363
|
+
return msg
|
|
241
364
|
|
|
242
365
|
def format(self, record: logging.LogRecord) -> str:
|
|
243
|
-
|
|
366
|
+
prefix, prefix_len = self.formatPrefix(record)
|
|
367
|
+
msg = self.formatMessage(record)
|
|
368
|
+
exc_info = self.formatExcInfo(record)
|
|
244
369
|
|
|
245
|
-
|
|
246
|
-
|
|
370
|
+
lines = msg.splitlines()
|
|
371
|
+
lines.extend(exc_info.splitlines())
|
|
247
372
|
|
|
248
|
-
|
|
373
|
+
# add prefix to first line of message
|
|
374
|
+
lines[0] = prefix + lines[0]
|
|
249
375
|
|
|
376
|
+
# add padding to each line of message
|
|
377
|
+
pad = "\n" + " " * prefix_len
|
|
378
|
+
return pad.join(lines)
|
|
250
379
|
|
|
251
|
-
class SimColourLogFormatter(SimLogFormatter):
|
|
252
|
-
"""Log formatter to provide consistent log message handling."""
|
|
253
380
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
logging.DEBUG: "%s",
|
|
257
|
-
logging.INFO: "%s",
|
|
258
|
-
logging.WARNING: _ANSI.COLOR_WARNING + "%s" + _ANSI.COLOR_DEFAULT,
|
|
259
|
-
logging.ERROR: _ANSI.COLOR_ERROR + "%s" + _ANSI.COLOR_DEFAULT,
|
|
260
|
-
logging.CRITICAL: _ANSI.COLOR_CRITICAL + "%s" + _ANSI.COLOR_DEFAULT,
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
def format(self, record: logging.LogRecord) -> str:
|
|
264
|
-
"""Prettify the log output by annotating with simulation time."""
|
|
381
|
+
class SimColourLogFormatter(SimLogFormatter):
|
|
382
|
+
"""Log formatter similar to :class:`SimLogFormatter`, but with colored output by default.
|
|
265
383
|
|
|
266
|
-
|
|
384
|
+
.. deprecated:: 2.0
|
|
385
|
+
Use :class:`!SimLogFormatter` with ``strip_ansi=False`` instead.
|
|
386
|
+
"""
|
|
267
387
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
388
|
+
def __init__(
|
|
389
|
+
self,
|
|
390
|
+
*,
|
|
391
|
+
reduced_log_fmt: bool = True,
|
|
392
|
+
strip_ansi: Union[bool, None] = False,
|
|
393
|
+
prefix_format: Optional[str] = None,
|
|
394
|
+
) -> None:
|
|
395
|
+
warnings.warn(
|
|
396
|
+
"SimColourLogFormatter is deprecated and will be removed in a future release. "
|
|
397
|
+
"Use SimLogFormatter with `strip_ansi=False` instead.",
|
|
398
|
+
DeprecationWarning,
|
|
399
|
+
stacklevel=2,
|
|
400
|
+
)
|
|
401
|
+
super().__init__(
|
|
402
|
+
reduced_log_fmt=reduced_log_fmt,
|
|
403
|
+
strip_ansi=strip_ansi,
|
|
404
|
+
prefix_format=prefix_format,
|
|
274
405
|
)
|
|
275
|
-
level = SimColourLogFormatter.loglevel2colour.get(
|
|
276
|
-
record.levelno, "%s"
|
|
277
|
-
) % record.levelname.ljust(_LEVEL_CHARS)
|
|
278
|
-
|
|
279
|
-
return self._format(level, record, msg, coloured=True)
|
|
280
406
|
|
|
281
407
|
|
|
282
408
|
def _log_from_c(
|
cocotb/regression.py
CHANGED
|
@@ -18,6 +18,7 @@ import warnings
|
|
|
18
18
|
from enum import auto
|
|
19
19
|
from importlib import import_module
|
|
20
20
|
from typing import (
|
|
21
|
+
TYPE_CHECKING,
|
|
21
22
|
Callable,
|
|
22
23
|
Coroutine,
|
|
23
24
|
List,
|
|
@@ -27,10 +28,10 @@ from typing import (
|
|
|
27
28
|
import cocotb
|
|
28
29
|
import cocotb._gpi_triggers
|
|
29
30
|
import cocotb.handle
|
|
30
|
-
from cocotb import
|
|
31
|
-
from cocotb
|
|
31
|
+
from cocotb import logging as cocotb_logging
|
|
32
|
+
from cocotb import simulator
|
|
32
33
|
from cocotb._decorators import Parameterized, Test
|
|
33
|
-
from cocotb._extended_awaitables import
|
|
34
|
+
from cocotb._extended_awaitables import with_timeout
|
|
34
35
|
from cocotb._gpi_triggers import GPITrigger, Timer
|
|
35
36
|
from cocotb._outcomes import Error, Outcome
|
|
36
37
|
from cocotb._test import RunningTest
|
|
@@ -40,11 +41,14 @@ from cocotb._utils import (
|
|
|
40
41
|
DocEnum,
|
|
41
42
|
remove_traceback_frames,
|
|
42
43
|
safe_divide,
|
|
43
|
-
want_color_output,
|
|
44
44
|
)
|
|
45
45
|
from cocotb._xunit_reporter import XUnitReporter
|
|
46
|
+
from cocotb.logging import ANSI
|
|
47
|
+
from cocotb.simtime import get_sim_time
|
|
46
48
|
from cocotb.task import Task
|
|
47
|
-
|
|
49
|
+
|
|
50
|
+
if TYPE_CHECKING:
|
|
51
|
+
from cocotb._base_triggers import Trigger
|
|
48
52
|
|
|
49
53
|
__all__ = (
|
|
50
54
|
"Parameterized",
|
|
@@ -62,7 +66,12 @@ TestFactory.__module__ = __name__
|
|
|
62
66
|
|
|
63
67
|
|
|
64
68
|
class SimFailure(BaseException):
|
|
65
|
-
"""A Test failure due to simulator failure.
|
|
69
|
+
"""A Test failure due to simulator failure.
|
|
70
|
+
|
|
71
|
+
.. caution::
|
|
72
|
+
Not to be raised or caught within a test.
|
|
73
|
+
Only used for marking expected failure with ``expect_error`` in :func:`cocotb.test`.
|
|
74
|
+
"""
|
|
66
75
|
|
|
67
76
|
|
|
68
77
|
_logger = logging.getLogger(__name__)
|
|
@@ -128,6 +137,11 @@ class RegressionManager:
|
|
|
128
137
|
:attr:`skipped`, and :attr:`failures` hold placeholder values.
|
|
129
138
|
"""
|
|
130
139
|
|
|
140
|
+
COLOR_TEST = ANSI.BLUE_FG
|
|
141
|
+
COLOR_PASSED = ANSI.GREEN_FG
|
|
142
|
+
COLOR_SKIPPED = ANSI.YELLOW_FG
|
|
143
|
+
COLOR_FAILED = ANSI.RED_FG
|
|
144
|
+
|
|
131
145
|
_timer1 = Timer(1)
|
|
132
146
|
|
|
133
147
|
def __init__(self) -> None:
|
|
@@ -365,13 +379,7 @@ class RegressionManager:
|
|
|
365
379
|
|
|
366
380
|
@functools.wraps(f)
|
|
367
381
|
async def func(*args: object, **kwargs: object) -> None:
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
try:
|
|
371
|
-
await with_timeout(running_co, timeout, self._test.timeout_unit)
|
|
372
|
-
except SimTimeoutError:
|
|
373
|
-
running_co.cancel()
|
|
374
|
-
raise
|
|
382
|
+
await with_timeout(f(*args, **kwargs), timeout, self._test.timeout_unit)
|
|
375
383
|
else:
|
|
376
384
|
func = self._test.func
|
|
377
385
|
|
|
@@ -539,8 +547,8 @@ class RegressionManager:
|
|
|
539
547
|
|
|
540
548
|
def _log_test_start(self) -> None:
|
|
541
549
|
"""Called by :meth:`_execute` to log that a test is starting."""
|
|
542
|
-
hilight_start =
|
|
543
|
-
hilight_end =
|
|
550
|
+
hilight_start = "" if cocotb_logging.strip_ansi else self.COLOR_TEST
|
|
551
|
+
hilight_end = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT
|
|
544
552
|
self.log.info(
|
|
545
553
|
"%srunning%s %s (%d/%d)%s",
|
|
546
554
|
hilight_start,
|
|
@@ -573,8 +581,8 @@ class RegressionManager:
|
|
|
573
581
|
"""Called by :meth:`_execute` when a test is skipped."""
|
|
574
582
|
|
|
575
583
|
# log test results
|
|
576
|
-
hilight_start =
|
|
577
|
-
hilight_end =
|
|
584
|
+
hilight_start = "" if cocotb_logging.strip_ansi else self.COLOR_SKIPPED
|
|
585
|
+
hilight_end = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT
|
|
578
586
|
self.log.info(
|
|
579
587
|
"%sskipping%s %s (%d/%d)%s",
|
|
580
588
|
hilight_start,
|
|
@@ -616,8 +624,8 @@ class RegressionManager:
|
|
|
616
624
|
"""Called by :meth:`_execute` when a test initialization fails."""
|
|
617
625
|
|
|
618
626
|
# log test results
|
|
619
|
-
hilight_start =
|
|
620
|
-
hilight_end =
|
|
627
|
+
hilight_start = "" if cocotb_logging.strip_ansi else self.COLOR_FAILED
|
|
628
|
+
hilight_end = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT
|
|
621
629
|
self.log.exception(
|
|
622
630
|
"%sFailed to initialize%s %s! (%d/%d)%s",
|
|
623
631
|
hilight_start,
|
|
@@ -662,8 +670,8 @@ class RegressionManager:
|
|
|
662
670
|
result: Union[Exception, None],
|
|
663
671
|
msg: Union[str, None],
|
|
664
672
|
) -> None:
|
|
665
|
-
start_hilight =
|
|
666
|
-
stop_hilight =
|
|
673
|
+
start_hilight = "" if cocotb_logging.strip_ansi else self.COLOR_PASSED
|
|
674
|
+
stop_hilight = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT
|
|
667
675
|
if msg is None:
|
|
668
676
|
rest = ""
|
|
669
677
|
else:
|
|
@@ -715,8 +723,8 @@ class RegressionManager:
|
|
|
715
723
|
result: Union[BaseException, None],
|
|
716
724
|
msg: Union[str, None],
|
|
717
725
|
) -> None:
|
|
718
|
-
start_hilight =
|
|
719
|
-
stop_hilight =
|
|
726
|
+
start_hilight = "" if cocotb_logging.strip_ansi else self.COLOR_FAILED
|
|
727
|
+
stop_hilight = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT
|
|
720
728
|
if msg is None:
|
|
721
729
|
rest = ""
|
|
722
730
|
else:
|
|
@@ -821,28 +829,28 @@ class RegressionManager:
|
|
|
821
829
|
summary += LINE_SEP
|
|
822
830
|
|
|
823
831
|
test_line = "** {a:<{a_len}} {start}{b:^{b_len}}{end} {c:>{c_len}.2f} {d:>{d_len}.2f} {e:>{e_len}} **\n"
|
|
832
|
+
hilite: str
|
|
833
|
+
lolite: str
|
|
824
834
|
for result in self._test_results:
|
|
825
|
-
hilite = ""
|
|
826
|
-
lolite = ""
|
|
827
|
-
|
|
828
835
|
if result.passed is None:
|
|
829
836
|
ratio = "-.--"
|
|
830
837
|
pass_fail_str = "SKIP"
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
lolite = _ANSI.COLOR_DEFAULT
|
|
838
|
+
hilite = self.COLOR_SKIPPED
|
|
839
|
+
lolite = ANSI.DEFAULT
|
|
834
840
|
elif result.passed:
|
|
835
841
|
ratio = format(result.ratio, "0.2f")
|
|
836
842
|
pass_fail_str = "PASS"
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
lolite = _ANSI.COLOR_DEFAULT
|
|
843
|
+
hilite = self.COLOR_PASSED
|
|
844
|
+
lolite = ANSI.DEFAULT
|
|
840
845
|
else:
|
|
841
846
|
ratio = format(result.ratio, "0.2f")
|
|
842
847
|
pass_fail_str = "FAIL"
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
848
|
+
hilite = self.COLOR_FAILED
|
|
849
|
+
lolite = ANSI.DEFAULT
|
|
850
|
+
|
|
851
|
+
if cocotb_logging.strip_ansi:
|
|
852
|
+
hilite = ""
|
|
853
|
+
lolite = ""
|
|
846
854
|
|
|
847
855
|
test_dict = {
|
|
848
856
|
"a": result.test_fullname,
|
cocotb/share/def/aldec.exp
CHANGED
|
Binary file
|
cocotb/share/def/aldec.lib
CHANGED
|
Binary file
|
cocotb/share/def/ghdl.exp
CHANGED
|
Binary file
|
cocotb/share/def/ghdl.lib
CHANGED
|
Binary file
|
cocotb/share/def/icarus.exp
CHANGED
|
Binary file
|
cocotb/share/def/icarus.lib
CHANGED
|
Binary file
|
cocotb/share/def/modelsim.exp
CHANGED
|
Binary file
|
cocotb/share/def/modelsim.lib
CHANGED
|
Binary file
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
#define xstr(a) str(a)
|
|
20
20
|
#define str(a) #a
|
|
21
21
|
|
|
22
|
-
extern "C" COCOTBUTILS_EXPORT void*
|
|
23
|
-
extern "C" COCOTBUTILS_EXPORT void*
|
|
24
|
-
const char*
|
|
22
|
+
extern "C" COCOTBUTILS_EXPORT void *utils_dyn_open(const char *lib_name);
|
|
23
|
+
extern "C" COCOTBUTILS_EXPORT void *utils_dyn_sym(void *handle,
|
|
24
|
+
const char *sym_name);
|
|
25
25
|
extern "C" COCOTBUTILS_EXPORT int is_python_context;
|
|
26
26
|
|
|
27
27
|
// to_python and to_simulator are implemented as macros instead of functions so
|