cocotb 1.9.2__cp312-cp312-win_amd64.whl → 2.0.0b1__cp312-cp312-win_amd64.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 → _ANSI.py} +5 -25
- cocotb/__init__.py +76 -332
- cocotb/_base_triggers.py +513 -0
- cocotb/_bridge.py +187 -0
- cocotb/_decorators.py +515 -0
- cocotb/_deprecation.py +3 -3
- cocotb/_exceptions.py +7 -0
- cocotb/_extended_awaitables.py +419 -0
- cocotb/_gpi_triggers.py +382 -0
- cocotb/_init.py +295 -0
- cocotb/_outcomes.py +54 -0
- cocotb/_profiling.py +46 -0
- cocotb/_py_compat.py +100 -29
- cocotb/_scheduler.py +454 -0
- cocotb/_test.py +245 -0
- cocotb/_test_factory.py +309 -0
- cocotb/_test_functions.py +42 -0
- cocotb/_typing.py +7 -0
- cocotb/_utils.py +296 -0
- cocotb/_version.py +3 -7
- cocotb/_xunit_reporter.py +66 -0
- cocotb/clock.py +271 -108
- cocotb/handle.py +1342 -795
- 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/{log.py → logging.py} +105 -110
- cocotb/queue.py +103 -57
- cocotb/regression.py +667 -712
- cocotb/result.py +17 -188
- 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.def +1 -0
- cocotb/share/def/modelsim.exp +0 -0
- cocotb/share/def/modelsim.lib +0 -0
- cocotb/share/include/cocotb_utils.h +6 -29
- cocotb/share/include/embed.h +5 -28
- cocotb/share/include/gpi.h +137 -92
- cocotb/share/include/gpi_logging.h +221 -142
- cocotb/share/include/py_gpi_logging.h +7 -4
- cocotb/share/include/vpi_user_ext.h +4 -26
- cocotb/share/lib/verilator/verilator.cpp +59 -54
- cocotb/simulator.cp312-win_amd64.exp +0 -0
- cocotb/simulator.cp312-win_amd64.lib +0 -0
- cocotb/simulator.cp312-win_amd64.pyd +0 -0
- cocotb/simulator.pyi +107 -0
- cocotb/task.py +434 -212
- cocotb/triggers.py +55 -1092
- cocotb/types/__init__.py +25 -47
- cocotb/types/_abstract_array.py +151 -0
- cocotb/types/_array.py +264 -0
- cocotb/types/_logic.py +296 -0
- cocotb/types/_logic_array.py +834 -0
- cocotb/types/{range.py → _range.py} +36 -44
- cocotb/types/_resolve.py +76 -0
- cocotb/utils.py +119 -587
- cocotb-2.0.0b1.dist-info/METADATA +60 -0
- cocotb-2.0.0b1.dist-info/RECORD +143 -0
- {cocotb-1.9.2.dist-info → cocotb-2.0.0b1.dist-info}/WHEEL +1 -1
- cocotb-2.0.0b1.dist-info/entry_points.txt +2 -0
- {cocotb-1.9.2.dist-info → cocotb-2.0.0b1.dist-info}/top_level.txt +1 -0
- cocotb_tools/__init__.py +0 -0
- cocotb_tools/_coverage.py +33 -0
- cocotb_tools/_vendor/__init__.py +3 -0
- cocotb_tools/check_results.py +65 -0
- cocotb_tools/combine_results.py +152 -0
- cocotb_tools/config.py +241 -0
- {cocotb → cocotb_tools}/ipython_support.py +29 -22
- cocotb_tools/makefiles/Makefile.deprecations +27 -0
- {cocotb/share → cocotb_tools}/makefiles/Makefile.inc +82 -54
- {cocotb/share → cocotb_tools}/makefiles/Makefile.sim +8 -33
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.activehdl +9 -16
- cocotb_tools/makefiles/simulators/Makefile.cvc +61 -0
- cocotb_tools/makefiles/simulators/Makefile.dsim +39 -0
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.ghdl +13 -42
- cocotb_tools/makefiles/simulators/Makefile.icarus +80 -0
- cocotb_tools/makefiles/simulators/Makefile.ius +93 -0
- cocotb_tools/makefiles/simulators/Makefile.modelsim +9 -0
- cocotb_tools/makefiles/simulators/Makefile.nvc +60 -0
- cocotb_tools/makefiles/simulators/Makefile.questa +29 -0
- cocotb/share/makefiles/simulators/Makefile.questa → cocotb_tools/makefiles/simulators/Makefile.questa-compat +26 -54
- cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun +149 -0
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.riviera +17 -56
- cocotb_tools/makefiles/simulators/Makefile.vcs +65 -0
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.verilator +15 -22
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.xcelium +20 -52
- cocotb_tools/py.typed +0 -0
- {cocotb → cocotb_tools}/runner.py +794 -361
- cocotb/_sim_versions.py → cocotb_tools/sim_versions.py +16 -21
- pygpi/entry.py +34 -17
- pygpi/py.typed +0 -0
- cocotb/binary.py +0 -858
- cocotb/config.py +0 -289
- cocotb/decorators.py +0 -332
- cocotb/memdebug.py +0 -35
- cocotb/outcomes.py +0 -56
- cocotb/scheduler.py +0 -1099
- cocotb/share/makefiles/Makefile.deprecations +0 -12
- cocotb/share/makefiles/simulators/Makefile.cvc +0 -94
- cocotb/share/makefiles/simulators/Makefile.icarus +0 -111
- cocotb/share/makefiles/simulators/Makefile.ius +0 -125
- cocotb/share/makefiles/simulators/Makefile.modelsim +0 -32
- cocotb/share/makefiles/simulators/Makefile.nvc +0 -64
- cocotb/share/makefiles/simulators/Makefile.vcs +0 -98
- cocotb/types/array.py +0 -309
- cocotb/types/logic.py +0 -292
- cocotb/types/logic_array.py +0 -298
- cocotb/wavedrom.py +0 -199
- cocotb/xunit_reporter.py +0 -80
- cocotb-1.9.2.dist-info/METADATA +0 -168
- cocotb-1.9.2.dist-info/RECORD +0 -121
- cocotb-1.9.2.dist-info/entry_points.txt +0 -2
- /cocotb/{_vendor/__init__.py → py.typed} +0 -0
- {cocotb-1.9.2.dist-info → cocotb-2.0.0b1.dist-info/licenses}/LICENSE +0 -0
- {cocotb → cocotb_tools}/_vendor/distutils_version.py +0 -0
cocotb/utils.py
CHANGED
|
@@ -1,49 +1,30 @@
|
|
|
1
|
+
# Copyright cocotb contributors
|
|
1
2
|
# Copyright (c) 2013 Potential Ventures Ltd
|
|
2
3
|
# Copyright (c) 2013 SolarFlare Communications Inc
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# notice, this list of conditions and the following disclaimer.
|
|
9
|
-
# * Redistributions in binary form must reproduce the above copyright
|
|
10
|
-
# notice, this list of conditions and the following disclaimer in the
|
|
11
|
-
# documentation and/or other materials provided with the distribution.
|
|
12
|
-
# * Neither the name of Potential Ventures Ltd,
|
|
13
|
-
# SolarFlare Communications Inc nor the
|
|
14
|
-
# names of its contributors may be used to endorse or promote products
|
|
15
|
-
# derived from this software without specific prior written permission.
|
|
16
|
-
#
|
|
17
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
18
|
-
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
-
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
-
# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY
|
|
21
|
-
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
-
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
26
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
-
|
|
28
|
-
"""Collection of handy functions."""
|
|
29
|
-
import ctypes
|
|
30
|
-
import functools
|
|
31
|
-
import inspect
|
|
32
|
-
import math
|
|
33
|
-
import os
|
|
34
|
-
import sys
|
|
35
|
-
import traceback
|
|
4
|
+
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
5
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
6
|
+
|
|
7
|
+
"""Utility functions for dealing with simulation time."""
|
|
8
|
+
|
|
36
9
|
import warnings
|
|
37
|
-
import weakref
|
|
38
10
|
from decimal import Decimal
|
|
39
|
-
from
|
|
40
|
-
from
|
|
11
|
+
from fractions import Fraction
|
|
12
|
+
from functools import lru_cache
|
|
13
|
+
from math import ceil, floor
|
|
14
|
+
from typing import Union, overload
|
|
41
15
|
|
|
42
|
-
import cocotb.ANSI as ANSI
|
|
43
16
|
from cocotb import simulator
|
|
17
|
+
from cocotb._py_compat import Literal, TypeAlias
|
|
18
|
+
from cocotb._typing import RoundMode, TimeUnit
|
|
44
19
|
|
|
20
|
+
__all__ = (
|
|
21
|
+
"get_sim_steps",
|
|
22
|
+
"get_sim_time",
|
|
23
|
+
"get_time_from_sim_steps",
|
|
24
|
+
)
|
|
45
25
|
|
|
46
|
-
|
|
26
|
+
|
|
27
|
+
def _get_simulator_precision() -> int:
|
|
47
28
|
# cache and replace this function
|
|
48
29
|
precision = simulator.get_precision()
|
|
49
30
|
global _get_simulator_precision
|
|
@@ -51,51 +32,58 @@ def _get_simulator_precision():
|
|
|
51
32
|
return _get_simulator_precision()
|
|
52
33
|
|
|
53
34
|
|
|
54
|
-
def get_python_integer_types():
|
|
55
|
-
warnings.warn(
|
|
56
|
-
"This is an internal cocotb function, use six.integer_types instead",
|
|
57
|
-
DeprecationWarning,
|
|
58
|
-
stacklevel=2,
|
|
59
|
-
)
|
|
60
|
-
return (int,)
|
|
61
|
-
|
|
62
|
-
|
|
63
35
|
# Simulator helper functions
|
|
64
|
-
def get_sim_time(
|
|
65
|
-
"""
|
|
36
|
+
def get_sim_time(unit: TimeUnit = "step", *, units: None = None) -> float:
|
|
37
|
+
"""Retrieve the simulation time from the simulator.
|
|
66
38
|
|
|
67
39
|
Args:
|
|
68
|
-
|
|
40
|
+
unit: String specifying the unit of the result
|
|
69
41
|
(one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).
|
|
70
42
|
``'step'`` will return the raw simulation time.
|
|
71
43
|
|
|
72
|
-
..
|
|
73
|
-
|
|
44
|
+
.. versionchanged:: 2.0
|
|
45
|
+
Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead.
|
|
74
46
|
|
|
75
|
-
|
|
76
|
-
|
|
47
|
+
.. versionchanged:: 2.0
|
|
48
|
+
Renamed from ``units``.
|
|
77
49
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"""
|
|
81
|
-
timeh, timel = simulator.get_sim_time()
|
|
50
|
+
Raises:
|
|
51
|
+
ValueError: If *unit* is not a valid unit.
|
|
82
52
|
|
|
83
|
-
|
|
53
|
+
Returns:
|
|
54
|
+
The simulation time in the specified unit.
|
|
84
55
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
56
|
+
.. versionchanged:: 1.6
|
|
57
|
+
Support ``'step'`` as the the *unit* argument to mean "simulator time step".
|
|
58
|
+
"""
|
|
59
|
+
if units is not None:
|
|
88
60
|
warnings.warn(
|
|
89
|
-
'
|
|
61
|
+
"The 'units' argument has been renamed to 'unit'.",
|
|
90
62
|
DeprecationWarning,
|
|
91
63
|
stacklevel=2,
|
|
92
64
|
)
|
|
65
|
+
unit = units
|
|
66
|
+
timeh, timel = simulator.get_sim_time()
|
|
67
|
+
steps = timeh << 32 | timel
|
|
68
|
+
return get_time_from_sim_steps(steps, unit) if unit != "step" else steps
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@overload
|
|
72
|
+
def _ldexp10(frac: float, exp: int) -> float: ...
|
|
93
73
|
|
|
94
|
-
return result
|
|
95
74
|
|
|
75
|
+
@overload
|
|
76
|
+
def _ldexp10(frac: Fraction, exp: int) -> Fraction: ...
|
|
96
77
|
|
|
97
|
-
|
|
98
|
-
|
|
78
|
+
|
|
79
|
+
@overload
|
|
80
|
+
def _ldexp10(frac: Decimal, exp: int) -> Decimal: ...
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _ldexp10(
|
|
84
|
+
frac: Union[float, Fraction, Decimal], exp: int
|
|
85
|
+
) -> Union[float, Fraction, Decimal]:
|
|
86
|
+
"""Like :func:`math.ldexp`, but base 10."""
|
|
99
87
|
# using * or / separately prevents rounding errors if `frac` is a
|
|
100
88
|
# high-precision type
|
|
101
89
|
if exp > 0:
|
|
@@ -104,23 +92,49 @@ def _ldexp10(frac, exp):
|
|
|
104
92
|
return frac / (10**-exp)
|
|
105
93
|
|
|
106
94
|
|
|
107
|
-
def get_time_from_sim_steps(
|
|
108
|
-
|
|
95
|
+
def get_time_from_sim_steps(
|
|
96
|
+
steps: int,
|
|
97
|
+
unit: Union[TimeUnit, None] = None,
|
|
98
|
+
*,
|
|
99
|
+
units: None = None,
|
|
100
|
+
) -> float:
|
|
101
|
+
"""Calculate simulation time in the specified *unit* from the *steps* based
|
|
109
102
|
on the simulator precision.
|
|
110
103
|
|
|
111
104
|
Args:
|
|
112
105
|
steps: Number of simulation steps.
|
|
113
|
-
|
|
106
|
+
unit: String specifying the unit of the result
|
|
114
107
|
(one of ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).
|
|
115
108
|
|
|
109
|
+
.. versionchanged:: 2.0
|
|
110
|
+
Renamed from ``units``.
|
|
111
|
+
|
|
112
|
+
Raises:
|
|
113
|
+
ValueError: If *unit* is not a valid unit.
|
|
114
|
+
|
|
116
115
|
Returns:
|
|
117
|
-
The simulation time in the specified
|
|
116
|
+
The simulation time in the specified unit.
|
|
118
117
|
"""
|
|
119
|
-
|
|
118
|
+
if units is not None:
|
|
119
|
+
warnings.warn(
|
|
120
|
+
"The 'units' argument has been renamed to 'unit'.",
|
|
121
|
+
DeprecationWarning,
|
|
122
|
+
stacklevel=2,
|
|
123
|
+
)
|
|
124
|
+
unit = units
|
|
125
|
+
if unit is None:
|
|
126
|
+
raise TypeError("Missing required argument 'unit'")
|
|
127
|
+
if unit == "step":
|
|
128
|
+
return steps
|
|
129
|
+
return _ldexp10(steps, _get_simulator_precision() - _get_log_time_scale(unit))
|
|
120
130
|
|
|
121
131
|
|
|
122
132
|
def get_sim_steps(
|
|
123
|
-
time: Union[
|
|
133
|
+
time: Union[float, Fraction, Decimal],
|
|
134
|
+
unit: TimeUnit = "step",
|
|
135
|
+
*,
|
|
136
|
+
round_mode: RoundMode = "error",
|
|
137
|
+
units: None = None,
|
|
124
138
|
) -> int:
|
|
125
139
|
"""Calculates the number of simulation time steps for a given amount of *time*.
|
|
126
140
|
|
|
@@ -132,9 +146,13 @@ def get_sim_steps(
|
|
|
132
146
|
|
|
133
147
|
Args:
|
|
134
148
|
time: The value to convert to simulation time steps.
|
|
135
|
-
|
|
149
|
+
unit: String specifying the unit of the result
|
|
136
150
|
(one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).
|
|
137
151
|
``'step'`` means *time* is already in simulation time steps.
|
|
152
|
+
|
|
153
|
+
.. versionchanged:: 2.0
|
|
154
|
+
Renamed from ``units``.
|
|
155
|
+
|
|
138
156
|
round_mode: String specifying how to handle time values that sit between time steps
|
|
139
157
|
(one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``).
|
|
140
158
|
|
|
@@ -146,553 +164,67 @@ def get_sim_steps(
|
|
|
146
164
|
time steps when *round_mode* is ``"error"``.
|
|
147
165
|
|
|
148
166
|
.. versionchanged:: 1.5
|
|
149
|
-
Support ``'step'`` as the *
|
|
167
|
+
Support ``'step'`` as the *unit* argument to mean "simulator time step".
|
|
150
168
|
|
|
151
169
|
.. versionchanged:: 1.6
|
|
152
170
|
Support rounding modes.
|
|
153
171
|
"""
|
|
154
|
-
if units not
|
|
155
|
-
result = _ldexp10(time, _get_log_time_scale(units) - _get_simulator_precision())
|
|
156
|
-
else:
|
|
157
|
-
result = time
|
|
158
|
-
if units is None:
|
|
172
|
+
if units is not None:
|
|
159
173
|
warnings.warn(
|
|
160
|
-
'
|
|
174
|
+
"The 'units' argument has been renamed to 'unit'.",
|
|
161
175
|
DeprecationWarning,
|
|
162
176
|
stacklevel=2,
|
|
163
177
|
)
|
|
164
|
-
|
|
178
|
+
unit = units
|
|
179
|
+
result: Union[float, Fraction, Decimal]
|
|
180
|
+
if unit != "step":
|
|
181
|
+
result = _ldexp10(time, _get_log_time_scale(unit) - _get_simulator_precision())
|
|
182
|
+
else:
|
|
183
|
+
result = time
|
|
165
184
|
|
|
166
185
|
if round_mode == "error":
|
|
167
|
-
result_rounded =
|
|
186
|
+
result_rounded = floor(result)
|
|
168
187
|
if result_rounded != result:
|
|
169
188
|
precision = _get_simulator_precision()
|
|
170
189
|
raise ValueError(
|
|
171
|
-
f"Unable to accurately represent {time}({
|
|
190
|
+
f"Unable to accurately represent {time}({unit}) with the simulator precision of 1e{precision}"
|
|
172
191
|
)
|
|
173
192
|
elif round_mode == "ceil":
|
|
174
|
-
result_rounded =
|
|
193
|
+
result_rounded = ceil(result)
|
|
175
194
|
elif round_mode == "round":
|
|
176
195
|
result_rounded = round(result)
|
|
177
196
|
elif round_mode == "floor":
|
|
178
|
-
result_rounded =
|
|
197
|
+
result_rounded = floor(result)
|
|
179
198
|
else:
|
|
180
199
|
raise ValueError(f"Invalid round_mode specifier: {round_mode}")
|
|
181
200
|
|
|
182
201
|
return result_rounded
|
|
183
202
|
|
|
184
203
|
|
|
185
|
-
|
|
186
|
-
"""Retrieves the ``log10()`` of the scale factor for a given time unit.
|
|
187
|
-
|
|
188
|
-
Args:
|
|
189
|
-
units (str): String specifying the units
|
|
190
|
-
(one of ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).
|
|
191
|
-
|
|
192
|
-
Returns:
|
|
193
|
-
The ``log10()`` of the scale factor for the time unit.
|
|
194
|
-
"""
|
|
195
|
-
scale = {"fs": -15, "ps": -12, "ns": -9, "us": -6, "ms": -3, "sec": 0}
|
|
196
|
-
|
|
197
|
-
units_lwr = units.lower()
|
|
198
|
-
if units_lwr not in scale:
|
|
199
|
-
raise ValueError(f"Invalid unit ({units}) provided")
|
|
200
|
-
else:
|
|
201
|
-
return scale[units_lwr]
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
# Ctypes helper functions
|
|
204
|
+
TimeUnitWithoutSteps: TypeAlias = Literal["fs", "ps", "ns", "us", "ms", "sec"]
|
|
205
205
|
|
|
206
206
|
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
@lru_cache(maxsize=None)
|
|
208
|
+
def _get_log_time_scale(unit: TimeUnitWithoutSteps) -> int:
|
|
209
|
+
"""Retrieves the ``log10()`` of the scale factor for a given time unit.
|
|
209
210
|
|
|
210
211
|
Args:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
Returns:
|
|
214
|
-
New Python string containing the bytes from memory holding *ctypes_obj*.
|
|
215
|
-
|
|
216
|
-
.. deprecated:: 1.5
|
|
217
|
-
This function is deprecated, use ``bytes(ctypes_obj)`` instead.
|
|
218
|
-
"""
|
|
219
|
-
warnings.warn(
|
|
220
|
-
"This function is deprecated and will be removed, use ``bytes(ctypes_obj)`` instead.",
|
|
221
|
-
DeprecationWarning,
|
|
222
|
-
stacklevel=2,
|
|
223
|
-
)
|
|
224
|
-
return ctypes.string_at(ctypes.addressof(ctypes_obj), ctypes.sizeof(ctypes_obj))
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
def unpack(ctypes_obj, string, bytes=None):
|
|
228
|
-
"""Unpack a Python string into a :mod:`ctypes` structure.
|
|
229
|
-
|
|
230
|
-
If the length of *string* is not the correct size for the memory
|
|
231
|
-
footprint of the :mod:`ctypes` structure then the *bytes* keyword argument
|
|
232
|
-
must be used.
|
|
212
|
+
unit: String specifying the unit
|
|
213
|
+
(one of ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).
|
|
233
214
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
string (str): String to copy over the *ctypes_obj* memory space.
|
|
237
|
-
bytes (int, optional): Number of bytes to copy.
|
|
238
|
-
Defaults to ``None``, meaning the length of *string* is used.
|
|
215
|
+
.. versionchanged:: 2.0
|
|
216
|
+
Renamed from ``units``.
|
|
239
217
|
|
|
240
218
|
Raises:
|
|
241
|
-
:
|
|
242
|
-
are not equal.
|
|
243
|
-
:exc:`MemoryError`: If *bytes* is longer than size of *ctypes_obj*.
|
|
244
|
-
|
|
245
|
-
.. deprecated:: 1.5
|
|
246
|
-
Converting bytes to a ctypes object should be done with :meth:`~ctypes._CData.from_buffer_copy`.
|
|
247
|
-
If you need to assign bytes into an *existing* ctypes object, use ``memoryview(ctypes_obj).cast('B')[:bytes] = string``,
|
|
248
|
-
see :class:`memoryview` for details.
|
|
249
|
-
"""
|
|
250
|
-
warnings.warn(
|
|
251
|
-
"This function is being removed, use ``memoryview(ctypes_obj).cast('B')[:bytes] = string`` instead.",
|
|
252
|
-
DeprecationWarning,
|
|
253
|
-
stacklevel=2,
|
|
254
|
-
)
|
|
255
|
-
if bytes is None:
|
|
256
|
-
if len(string) != ctypes.sizeof(ctypes_obj):
|
|
257
|
-
raise ValueError(
|
|
258
|
-
"Attempt to unpack a string of size %d into a \
|
|
259
|
-
struct of size %d"
|
|
260
|
-
% (len(string), ctypes.sizeof(ctypes_obj))
|
|
261
|
-
)
|
|
262
|
-
bytes = len(string)
|
|
263
|
-
|
|
264
|
-
if bytes > ctypes.sizeof(ctypes_obj):
|
|
265
|
-
raise MemoryError(
|
|
266
|
-
"Attempt to unpack %d bytes over an object \
|
|
267
|
-
of size %d"
|
|
268
|
-
% (bytes, ctypes.sizeof(ctypes_obj))
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
ctypes.memmove(ctypes.addressof(ctypes_obj), string, bytes)
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
# A note on the use of latin1 in the deprecations below:
|
|
275
|
-
# Latin1 is the only encoding `e` that satisfies
|
|
276
|
-
# `all(chr(x).encode(e) == bytes([x]) for x in range(255))`
|
|
277
|
-
# Our use of `ord` and `chr` throughout other bits of code make this the most
|
|
278
|
-
# compatible choice of encoding. Under this convention, old code can be upgraded
|
|
279
|
-
# by changing "binary" strings from `"\x12\x34"` to `b"\x12\x34"`.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
def _sane(x: bytes) -> str:
|
|
283
|
-
r = ""
|
|
284
|
-
for j in x:
|
|
285
|
-
if (j < 32) or (j >= 127):
|
|
286
|
-
r += "."
|
|
287
|
-
else:
|
|
288
|
-
r += chr(j)
|
|
289
|
-
return r
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
def hexdump(x: bytes) -> str:
|
|
293
|
-
"""Hexdump a buffer.
|
|
294
|
-
|
|
295
|
-
Args:
|
|
296
|
-
x: Object that supports conversion to :class:`bytes`.
|
|
219
|
+
ValueError: If *unit* is not a valid unit.
|
|
297
220
|
|
|
298
221
|
Returns:
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
.. deprecated:: 1.4
|
|
302
|
-
Passing a :class:`str` to this function is deprecated, as it
|
|
303
|
-
is not an appropriate type for binary data. Doing so anyway
|
|
304
|
-
will encode the string to ``latin1``.
|
|
305
|
-
|
|
306
|
-
.. deprecated:: 1.6.0
|
|
307
|
-
The function will be removed in the next major version.
|
|
308
|
-
Use :func:`scapy.utils.hexdump` instead.
|
|
309
|
-
|
|
310
|
-
Example:
|
|
311
|
-
>>> print(hexdump(b'this somewhat long string'))
|
|
312
|
-
0000 74 68 69 73 20 73 6F 6D 65 77 68 61 74 20 6C 6F this somewhat lo
|
|
313
|
-
0010 6E 67 20 73 74 72 69 6E 67 ng string
|
|
314
|
-
<BLANKLINE>
|
|
315
|
-
"""
|
|
316
|
-
# adapted from scapy.utils.hexdump
|
|
317
|
-
warnings.warn(
|
|
318
|
-
"cocotb.utils.hexdump is deprecated. Use scapy.utils.hexdump instead.",
|
|
319
|
-
DeprecationWarning,
|
|
320
|
-
stacklevel=2,
|
|
321
|
-
)
|
|
322
|
-
rs = ""
|
|
323
|
-
if isinstance(x, str):
|
|
324
|
-
warnings.warn(
|
|
325
|
-
"Passing a string to hexdump is deprecated, pass bytes instead",
|
|
326
|
-
DeprecationWarning,
|
|
327
|
-
stacklevel=2,
|
|
328
|
-
)
|
|
329
|
-
x = x.encode("latin1")
|
|
330
|
-
x = b"%b" % x
|
|
331
|
-
l = len(x)
|
|
332
|
-
i = 0
|
|
333
|
-
while i < l:
|
|
334
|
-
rs += "%04x " % i
|
|
335
|
-
for j in range(16):
|
|
336
|
-
if i + j < l:
|
|
337
|
-
rs += "%02X " % x[i + j]
|
|
338
|
-
else:
|
|
339
|
-
rs += " "
|
|
340
|
-
if j % 16 == 7:
|
|
341
|
-
rs += ""
|
|
342
|
-
rs += " "
|
|
343
|
-
rs += _sane(x[i : i + 16]) + "\n"
|
|
344
|
-
i += 16
|
|
345
|
-
return rs
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
def hexdiffs(x: bytes, y: bytes) -> str:
|
|
349
|
-
r"""Return a diff string showing differences between two binary strings.
|
|
350
|
-
|
|
351
|
-
Args:
|
|
352
|
-
x: Object that supports conversion to :class:`bytes`.
|
|
353
|
-
y: Object that supports conversion to :class:`bytes`.
|
|
354
|
-
|
|
355
|
-
.. deprecated:: 1.4
|
|
356
|
-
Passing :class:`str`\ s to this function is deprecated, as it
|
|
357
|
-
is not an appropriate type for binary data. Doing so anyway
|
|
358
|
-
will encode the string to ``latin1``.
|
|
359
|
-
|
|
360
|
-
.. deprecated:: 1.6.0
|
|
361
|
-
The function will be removed in the next major version.
|
|
362
|
-
Use :func:`scapy.utils.hexdiff` instead.
|
|
363
|
-
|
|
364
|
-
Example:
|
|
365
|
-
>>> print(hexdiffs(b'a', b'b'))
|
|
366
|
-
0000 61 a
|
|
367
|
-
0000 62 b
|
|
368
|
-
<BLANKLINE>
|
|
369
|
-
>>> print(hexdiffs(b'this short thing', b'this also short'))
|
|
370
|
-
0000 746869732073686F 7274207468696E67 this short thing
|
|
371
|
-
0000 7468697320616C73 6F 2073686F7274 this also short
|
|
372
|
-
<BLANKLINE>
|
|
373
|
-
"""
|
|
374
|
-
# adapted from scapy.utils.hexdiff
|
|
375
|
-
warnings.warn(
|
|
376
|
-
"cocotb.utils.hexdiffs is deprecated. Use scapy.utils.hexdiff instead.",
|
|
377
|
-
DeprecationWarning,
|
|
378
|
-
stacklevel=2,
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
def highlight(string: str, colour=ANSI.COLOR_HILITE_HEXDIFF_DEFAULT) -> str:
|
|
382
|
-
"""Highlight with ANSI colors if possible/requested and not running in GUI."""
|
|
383
|
-
|
|
384
|
-
if want_color_output():
|
|
385
|
-
return colour + string + ANSI.COLOR_DEFAULT
|
|
386
|
-
else:
|
|
387
|
-
return string
|
|
388
|
-
|
|
389
|
-
x_is_str = isinstance(x, str)
|
|
390
|
-
y_is_str = isinstance(y, str)
|
|
391
|
-
if x_is_str or y_is_str:
|
|
392
|
-
warnings.warn(
|
|
393
|
-
"Passing strings to hexdiffs is deprecated, pass bytes instead",
|
|
394
|
-
DeprecationWarning,
|
|
395
|
-
stacklevel=2,
|
|
396
|
-
)
|
|
397
|
-
if x_is_str:
|
|
398
|
-
x = x.encode("latin1")
|
|
399
|
-
if y_is_str:
|
|
400
|
-
y = y.encode("latin1")
|
|
401
|
-
|
|
402
|
-
rs = ""
|
|
403
|
-
|
|
404
|
-
x = (b"%b" % x)[::-1]
|
|
405
|
-
y = (b"%b" % y)[::-1]
|
|
406
|
-
SUBST = 1
|
|
407
|
-
INSERT = 1
|
|
408
|
-
d = {}
|
|
409
|
-
d[-1, -1] = 0, (-1, -1)
|
|
410
|
-
for j in range(len(y)):
|
|
411
|
-
d[-1, j] = d[-1, j - 1][0] + INSERT, (-1, j - 1)
|
|
412
|
-
for i in range(len(x)):
|
|
413
|
-
d[i, -1] = d[i - 1, -1][0] + INSERT, (i - 1, -1)
|
|
414
|
-
|
|
415
|
-
for j in range(len(y)):
|
|
416
|
-
for i in range(len(x)):
|
|
417
|
-
d[i, j] = min(
|
|
418
|
-
(d[i - 1, j - 1][0] + SUBST * (x[i] != y[j]), (i - 1, j - 1)),
|
|
419
|
-
(d[i - 1, j][0] + INSERT, (i - 1, j)),
|
|
420
|
-
(d[i, j - 1][0] + INSERT, (i, j - 1)),
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
backtrackx = []
|
|
424
|
-
backtracky = []
|
|
425
|
-
i = len(x) - 1
|
|
426
|
-
j = len(y) - 1
|
|
427
|
-
while not (i == j == -1):
|
|
428
|
-
i2, j2 = d[i, j][1]
|
|
429
|
-
backtrackx.append(x[i2 + 1 : i + 1])
|
|
430
|
-
backtracky.append(y[j2 + 1 : j + 1])
|
|
431
|
-
i, j = i2, j2
|
|
432
|
-
|
|
433
|
-
x = y = i = 0
|
|
434
|
-
colorize = {0: lambda x: x, -1: lambda x: x, 1: lambda x: x} # noqa # noqa # noqa
|
|
435
|
-
|
|
436
|
-
dox = 1
|
|
437
|
-
doy = 0
|
|
438
|
-
l = len(backtrackx)
|
|
439
|
-
while i < l:
|
|
440
|
-
linex = backtrackx[i : i + 16]
|
|
441
|
-
liney = backtracky[i : i + 16]
|
|
442
|
-
xx = sum(len(k) for k in linex)
|
|
443
|
-
yy = sum(len(k) for k in liney)
|
|
444
|
-
if dox and not xx:
|
|
445
|
-
dox = 0
|
|
446
|
-
doy = 1
|
|
447
|
-
if dox and linex == liney:
|
|
448
|
-
doy = 1
|
|
449
|
-
|
|
450
|
-
if dox:
|
|
451
|
-
xd = y
|
|
452
|
-
j = 0
|
|
453
|
-
while not linex[j]:
|
|
454
|
-
j += 1
|
|
455
|
-
xd -= 1
|
|
456
|
-
if dox != doy:
|
|
457
|
-
rs += highlight("%04x" % xd) + " "
|
|
458
|
-
else:
|
|
459
|
-
rs += highlight("%04x" % xd, colour=ANSI.COLOR_HILITE_HEXDIFF_1) + " "
|
|
460
|
-
x += xx
|
|
461
|
-
line = linex
|
|
462
|
-
else:
|
|
463
|
-
rs += " "
|
|
464
|
-
if doy:
|
|
465
|
-
yd = y
|
|
466
|
-
j = 0
|
|
467
|
-
while not liney[j]:
|
|
468
|
-
j += 1
|
|
469
|
-
yd -= 1
|
|
470
|
-
if doy - dox != 0:
|
|
471
|
-
rs += " " + highlight("%04x" % yd)
|
|
472
|
-
else:
|
|
473
|
-
rs += highlight("%04x" % yd, colour=ANSI.COLOR_HILITE_HEXDIFF_1)
|
|
474
|
-
y += yy
|
|
475
|
-
line = liney
|
|
476
|
-
else:
|
|
477
|
-
rs += " "
|
|
478
|
-
|
|
479
|
-
rs += " "
|
|
480
|
-
|
|
481
|
-
cl = ""
|
|
482
|
-
for j in range(16):
|
|
483
|
-
if i + j < l:
|
|
484
|
-
if line[j]:
|
|
485
|
-
(char_j,) = line[j]
|
|
486
|
-
if linex[j] != liney[j]:
|
|
487
|
-
rs += highlight(
|
|
488
|
-
"%02X" % char_j, colour=ANSI.COLOR_HILITE_HEXDIFF_2
|
|
489
|
-
)
|
|
490
|
-
else:
|
|
491
|
-
rs += "%02X" % char_j
|
|
492
|
-
if linex[j] == liney[j]:
|
|
493
|
-
cl += highlight(
|
|
494
|
-
_sane(line[j]), colour=ANSI.COLOR_HILITE_HEXDIFF_3
|
|
495
|
-
)
|
|
496
|
-
else:
|
|
497
|
-
cl += highlight(
|
|
498
|
-
_sane(line[j]), colour=ANSI.COLOR_HILITE_HEXDIFF_4
|
|
499
|
-
)
|
|
500
|
-
else:
|
|
501
|
-
rs += " "
|
|
502
|
-
cl += " "
|
|
503
|
-
else:
|
|
504
|
-
rs += " "
|
|
505
|
-
if j == 7:
|
|
506
|
-
rs += " "
|
|
507
|
-
|
|
508
|
-
rs += " " + cl + "\n"
|
|
509
|
-
|
|
510
|
-
if doy or not yy:
|
|
511
|
-
doy = 0
|
|
512
|
-
dox = 1
|
|
513
|
-
i += 16
|
|
514
|
-
else:
|
|
515
|
-
if yy:
|
|
516
|
-
dox = 0
|
|
517
|
-
doy = 1
|
|
518
|
-
else:
|
|
519
|
-
i += 16
|
|
520
|
-
return rs
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
class ParametrizedSingleton(type):
|
|
524
|
-
"""A metaclass that allows class construction to reuse an existing instance.
|
|
525
|
-
|
|
526
|
-
We use this so that :class:`RisingEdge(sig) <cocotb.triggers.RisingEdge>` and :class:`Join(coroutine) <cocotb.triggers.Join>` always return
|
|
527
|
-
the same instance, rather than creating new copies.
|
|
528
|
-
"""
|
|
529
|
-
|
|
530
|
-
def __init__(cls, *args, **kwargs):
|
|
531
|
-
# Attach a lookup table to this class.
|
|
532
|
-
# Weak such that if the instance is no longer referenced, it can be
|
|
533
|
-
# collected.
|
|
534
|
-
cls.__instances = weakref.WeakValueDictionary()
|
|
535
|
-
|
|
536
|
-
def __singleton_key__(cls, *args, **kwargs):
|
|
537
|
-
"""Convert the construction arguments into a normalized representation that
|
|
538
|
-
uniquely identifies this singleton.
|
|
539
|
-
"""
|
|
540
|
-
# Could default to something like this, but it would be slow
|
|
541
|
-
# return tuple(inspect.Signature(cls).bind(*args, **kwargs).arguments.items())
|
|
542
|
-
raise NotImplementedError
|
|
543
|
-
|
|
544
|
-
def __call__(cls, *args, **kwargs):
|
|
545
|
-
key = cls.__singleton_key__(*args, **kwargs)
|
|
546
|
-
try:
|
|
547
|
-
return cls.__instances[key]
|
|
548
|
-
except KeyError:
|
|
549
|
-
# construct the object as normal
|
|
550
|
-
self = super().__call__(*args, **kwargs)
|
|
551
|
-
cls.__instances[key] = self
|
|
552
|
-
return self
|
|
553
|
-
|
|
554
|
-
@property
|
|
555
|
-
def __signature__(cls):
|
|
556
|
-
return inspect.signature(cls.__singleton_key__)
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
def reject_remaining_kwargs(name, kwargs):
|
|
560
|
-
"""
|
|
561
|
-
Helper function to emulate Python 3 keyword-only arguments.
|
|
562
|
-
|
|
563
|
-
Use as::
|
|
564
|
-
|
|
565
|
-
def func(x1, **kwargs):
|
|
566
|
-
a = kwargs.pop('a', 1)
|
|
567
|
-
b = kwargs.pop('b', 2)
|
|
568
|
-
reject_remaining_kwargs('func', kwargs)
|
|
569
|
-
...
|
|
570
|
-
|
|
571
|
-
To emulate the Python 3 syntax::
|
|
572
|
-
|
|
573
|
-
def func(x1, *, a=1, b=2):
|
|
574
|
-
...
|
|
575
|
-
|
|
576
|
-
.. deprecated:: 1.4
|
|
577
|
-
Since the minimum supported Python version is now 3.5, this function
|
|
578
|
-
is not needed.
|
|
579
|
-
"""
|
|
580
|
-
warnings.warn(
|
|
581
|
-
"reject_remaining_kwargs is deprecated and will be removed, use "
|
|
582
|
-
"Python 3 keyword-only arguments directly.",
|
|
583
|
-
DeprecationWarning,
|
|
584
|
-
stacklevel=2,
|
|
585
|
-
)
|
|
586
|
-
if kwargs:
|
|
587
|
-
# match the error message to what Python 3 produces
|
|
588
|
-
bad_arg = next(iter(kwargs))
|
|
589
|
-
raise TypeError(f"{name}() got an unexpected keyword argument {bad_arg!r}")
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
class lazy_property:
|
|
593
|
-
"""
|
|
594
|
-
A property that is executed the first time, then cached forever.
|
|
595
|
-
|
|
596
|
-
It does this by replacing itself on the instance, which works because
|
|
597
|
-
unlike `@property` it does not define __set__.
|
|
598
|
-
|
|
599
|
-
This should be used for expensive members of objects that are not always
|
|
600
|
-
used.
|
|
601
|
-
"""
|
|
602
|
-
|
|
603
|
-
def __init__(self, fget):
|
|
604
|
-
self.fget = fget
|
|
605
|
-
|
|
606
|
-
# copy the getter function's docstring and other attributes
|
|
607
|
-
functools.update_wrapper(self, fget)
|
|
608
|
-
|
|
609
|
-
def __get__(self, obj, cls):
|
|
610
|
-
if obj is None:
|
|
611
|
-
return self
|
|
612
|
-
|
|
613
|
-
value = self.fget(obj)
|
|
614
|
-
setattr(obj, self.fget.__qualname__, value)
|
|
615
|
-
return value
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
def want_color_output():
|
|
619
|
-
"""Return ``True`` if colored output is possible/requested and not running in GUI.
|
|
620
|
-
|
|
621
|
-
Colored output can be explicitly requested by setting :envvar:`COCOTB_ANSI_OUTPUT` to ``1``.
|
|
622
|
-
"""
|
|
623
|
-
want_color = sys.stdout.isatty() # default to color for TTYs
|
|
624
|
-
if os.getenv("NO_COLOR") is not None:
|
|
625
|
-
want_color = False
|
|
626
|
-
if os.getenv("COCOTB_ANSI_OUTPUT", default="0") == "1":
|
|
627
|
-
want_color = True
|
|
628
|
-
if os.getenv("GUI", default="0") == "1":
|
|
629
|
-
want_color = False
|
|
630
|
-
return want_color
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
def remove_traceback_frames(tb_or_exc, frame_names):
|
|
222
|
+
The ``log10()`` of the scale factor for the time unit.
|
|
634
223
|
"""
|
|
635
|
-
|
|
224
|
+
scale = {"fs": -15, "ps": -12, "ns": -9, "us": -6, "ms": -3, "sec": 0}
|
|
636
225
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
a copy of the exception with a new shorter traceback. If a tuple
|
|
641
|
-
from `sys.exc_info` is passed, returns the same tuple with the
|
|
642
|
-
traceback shortened
|
|
643
|
-
frame_names (List[str]):
|
|
644
|
-
Names of the frames to strip, which must be present.
|
|
645
|
-
"""
|
|
646
|
-
# self-invoking overloads
|
|
647
|
-
if isinstance(tb_or_exc, BaseException):
|
|
648
|
-
exc = tb_or_exc
|
|
649
|
-
return exc.with_traceback(
|
|
650
|
-
remove_traceback_frames(exc.__traceback__, frame_names)
|
|
651
|
-
)
|
|
652
|
-
elif isinstance(tb_or_exc, tuple):
|
|
653
|
-
exc_type, exc_value, exc_tb = tb_or_exc
|
|
654
|
-
exc_tb = remove_traceback_frames(exc_tb, frame_names)
|
|
655
|
-
return exc_type, exc_value, exc_tb
|
|
656
|
-
# base case
|
|
226
|
+
unit_lwr = unit.lower()
|
|
227
|
+
if unit_lwr not in scale:
|
|
228
|
+
raise ValueError(f"Invalid unit ({unit}) provided")
|
|
657
229
|
else:
|
|
658
|
-
|
|
659
|
-
for frame_name in frame_names:
|
|
660
|
-
assert tb.tb_frame.f_code.co_name == frame_name
|
|
661
|
-
tb = tb.tb_next
|
|
662
|
-
return tb
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
def walk_coro_stack(coro):
|
|
666
|
-
"""Walk down the coroutine stack, starting at *coro*.
|
|
667
|
-
|
|
668
|
-
Supports coroutines and generators.
|
|
669
|
-
"""
|
|
670
|
-
while coro is not None:
|
|
671
|
-
try:
|
|
672
|
-
f = getattr(coro, "cr_frame")
|
|
673
|
-
coro = coro.cr_await
|
|
674
|
-
except AttributeError:
|
|
675
|
-
try:
|
|
676
|
-
f = getattr(coro, "gi_frame")
|
|
677
|
-
coro = coro.gi_yieldfrom
|
|
678
|
-
except AttributeError:
|
|
679
|
-
f = None
|
|
680
|
-
coro = None
|
|
681
|
-
if f is not None:
|
|
682
|
-
yield (f, f.f_lineno)
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
def extract_coro_stack(coro, limit=None):
|
|
686
|
-
"""Create a list of pre-processed entries from the coroutine stack.
|
|
687
|
-
|
|
688
|
-
This is based on :func:`traceback.extract_tb`.
|
|
689
|
-
|
|
690
|
-
If *limit* is omitted or ``None``, all entries are extracted.
|
|
691
|
-
The list is a :class:`traceback.StackSummary` object, and
|
|
692
|
-
each entry in the list is a :class:`traceback.FrameSummary` object
|
|
693
|
-
containing attributes ``filename``, ``lineno``, ``name``, and ``line``
|
|
694
|
-
representing the information that is usually printed for a stack
|
|
695
|
-
trace. The line is a string with leading and trailing
|
|
696
|
-
whitespace stripped; if the source is not available it is ``None``.
|
|
697
|
-
"""
|
|
698
|
-
return traceback.StackSummary.extract(walk_coro_stack(coro), limit=limit)
|
|
230
|
+
return scale[unit_lwr]
|