cot-assert 0.1.0__py2.py3-none-any.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.
- cot_assert/__init__.py +22 -0
- cot_assert/_entry.py +29 -0
- cot_assert/_error.py +155 -0
- cot_assert/_hook.py +224 -0
- cot_assert/_llexc.py +75 -0
- cot_assert/_render.py +311 -0
- cot_assert/_rewrite.py +495 -0
- cot_assert/_rpy.py +32 -0
- cot_assert/_runtime.py +12 -0
- cot_assert/_unparse.py +180 -0
- cot_assert/_values.py +30 -0
- cot_assert/pytest_plugin.py +140 -0
- cot_assert-0.1.0.dist-info/METADATA +69 -0
- cot_assert-0.1.0.dist-info/RECORD +17 -0
- cot_assert-0.1.0.dist-info/WHEEL +5 -0
- cot_assert-0.1.0.dist-info/entry_points.txt +2 -0
- cot_assert-0.1.0.dist-info/licenses/LICENSE +373 -0
cot_assert/_unparse.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""Expression source text for labels, identical on Python 2.7 and 3.x.
|
|
2
|
+
|
|
3
|
+
``ast.unparse`` does not exist on 2.7 and its output drifts between 3.x
|
|
4
|
+
releases; labels end up in prebuilt RPython constants and in test
|
|
5
|
+
expectations, so they come from here on every version.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import absolute_import, division, print_function
|
|
9
|
+
|
|
10
|
+
_BINOP = {
|
|
11
|
+
"Add": ("+", 11),
|
|
12
|
+
"Sub": ("-", 11),
|
|
13
|
+
"Mult": ("*", 12),
|
|
14
|
+
"MatMult": ("@", 12),
|
|
15
|
+
"Div": ("/", 12),
|
|
16
|
+
"FloorDiv": ("//", 12),
|
|
17
|
+
"Mod": ("%", 12),
|
|
18
|
+
"Pow": ("**", 14),
|
|
19
|
+
"LShift": ("<<", 10),
|
|
20
|
+
"RShift": (">>", 10),
|
|
21
|
+
"BitOr": ("|", 7),
|
|
22
|
+
"BitXor": ("^", 8),
|
|
23
|
+
"BitAnd": ("&", 9),
|
|
24
|
+
}
|
|
25
|
+
_UNARY = {"Not": ("not ", 4), "Invert": ("~", 13), "USub": ("-", 13), "UAdd": ("+", 13)}
|
|
26
|
+
_CMP = {
|
|
27
|
+
"Eq": "==",
|
|
28
|
+
"NotEq": "!=",
|
|
29
|
+
"Lt": "<",
|
|
30
|
+
"LtE": "<=",
|
|
31
|
+
"Gt": ">",
|
|
32
|
+
"GtE": ">=",
|
|
33
|
+
"Is": "is",
|
|
34
|
+
"IsNot": "is not",
|
|
35
|
+
"In": "in",
|
|
36
|
+
"NotIn": "not in",
|
|
37
|
+
}
|
|
38
|
+
_BOOL = {"And": ("and", 3), "Or": ("or", 2)}
|
|
39
|
+
_ATOM = 16
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def cmpop(op):
|
|
43
|
+
return _CMP[type(op).__name__]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def binop(op):
|
|
47
|
+
return _BINOP[type(op).__name__][0]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def unaryop(op):
|
|
51
|
+
return _UNARY[type(op).__name__][0]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def unparse(node):
|
|
55
|
+
return _unparse(node)[0]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _wrap(node, minimum):
|
|
59
|
+
text, prec = _unparse(node)
|
|
60
|
+
if prec < minimum:
|
|
61
|
+
return "(" + text + ")"
|
|
62
|
+
return text
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _unparse(node):
|
|
66
|
+
kind = type(node).__name__
|
|
67
|
+
if kind == "Name":
|
|
68
|
+
return node.id, _ATOM
|
|
69
|
+
if kind in ("Constant", "NameConstant"):
|
|
70
|
+
if node.value is Ellipsis:
|
|
71
|
+
return "...", _ATOM
|
|
72
|
+
return repr(node.value), _ATOM
|
|
73
|
+
if kind == "Num":
|
|
74
|
+
return repr(node.n), _ATOM
|
|
75
|
+
if kind in ("Str", "Bytes"):
|
|
76
|
+
return repr(node.s), _ATOM
|
|
77
|
+
if kind == "Attribute":
|
|
78
|
+
return _wrap(node.value, _ATOM) + "." + node.attr, _ATOM
|
|
79
|
+
if kind == "Call":
|
|
80
|
+
return _wrap(node.func, _ATOM) + "(" + ", ".join(_call_args(node)) + ")", _ATOM
|
|
81
|
+
if kind == "Subscript":
|
|
82
|
+
return _wrap(node.value, _ATOM) + "[" + _slice(node.slice) + "]", _ATOM
|
|
83
|
+
if kind == "BinOp":
|
|
84
|
+
op, prec = _BINOP[type(node.op).__name__]
|
|
85
|
+
# ** is right associative, everything else left
|
|
86
|
+
if op == "**":
|
|
87
|
+
left, right = _wrap(node.left, prec + 1), _wrap(node.right, prec)
|
|
88
|
+
else:
|
|
89
|
+
left, right = _wrap(node.left, prec), _wrap(node.right, prec + 1)
|
|
90
|
+
return left + " " + op + " " + right, prec
|
|
91
|
+
if kind == "UnaryOp":
|
|
92
|
+
op, prec = _UNARY[type(node.op).__name__]
|
|
93
|
+
return op + _wrap(node.operand, prec), prec
|
|
94
|
+
if kind == "Compare":
|
|
95
|
+
parts = [_wrap(node.left, 6)]
|
|
96
|
+
for op, comparator in zip(node.ops, node.comparators):
|
|
97
|
+
parts.append(cmpop(op))
|
|
98
|
+
parts.append(_wrap(comparator, 6))
|
|
99
|
+
return " ".join(parts), 5
|
|
100
|
+
if kind == "BoolOp":
|
|
101
|
+
op, prec = _BOOL[type(node.op).__name__]
|
|
102
|
+
return (" " + op + " ").join(_wrap(v, prec + 1) for v in node.values), prec
|
|
103
|
+
if kind == "IfExp":
|
|
104
|
+
return (
|
|
105
|
+
_wrap(node.body, 2)
|
|
106
|
+
+ " if "
|
|
107
|
+
+ _wrap(node.test, 2)
|
|
108
|
+
+ " else "
|
|
109
|
+
+ _wrap(node.orelse, 1)
|
|
110
|
+
), 1
|
|
111
|
+
if kind == "Lambda":
|
|
112
|
+
return "lambda: ...", 0
|
|
113
|
+
if kind == "Tuple":
|
|
114
|
+
items = [unparse(e) for e in node.elts]
|
|
115
|
+
if len(items) == 1:
|
|
116
|
+
return "(" + items[0] + ",)", _ATOM
|
|
117
|
+
return "(" + ", ".join(items) + ")", _ATOM
|
|
118
|
+
if kind == "List":
|
|
119
|
+
return "[" + ", ".join(unparse(e) for e in node.elts) + "]", _ATOM
|
|
120
|
+
if kind == "Set":
|
|
121
|
+
return "{" + ", ".join(unparse(e) for e in node.elts) + "}", _ATOM
|
|
122
|
+
if kind == "Dict":
|
|
123
|
+
items = []
|
|
124
|
+
for k, v in zip(node.keys, node.values):
|
|
125
|
+
if k is None:
|
|
126
|
+
items.append("**" + _wrap(v, _ATOM))
|
|
127
|
+
else:
|
|
128
|
+
items.append(unparse(k) + ": " + unparse(v))
|
|
129
|
+
return "{" + ", ".join(items) + "}", _ATOM
|
|
130
|
+
if kind == "Starred":
|
|
131
|
+
return "*" + _wrap(node.value, _ATOM), _ATOM
|
|
132
|
+
if kind == "Repr":
|
|
133
|
+
return "`" + unparse(node.value) + "`", _ATOM
|
|
134
|
+
if kind in ("ListComp", "SetComp", "GeneratorExp", "DictComp"):
|
|
135
|
+
return {"ListComp": "[...]", "SetComp": "{...}", "DictComp": "{...}"}.get(
|
|
136
|
+
kind, "(...)"
|
|
137
|
+
), _ATOM
|
|
138
|
+
if kind == "NamedExpr":
|
|
139
|
+
return unparse(node.target) + " := " + _wrap(node.value, 1), 0
|
|
140
|
+
return "<%s>" % kind, _ATOM
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _call_args(node):
|
|
144
|
+
args = [unparse(a) for a in node.args]
|
|
145
|
+
starargs = getattr(node, "starargs", None)
|
|
146
|
+
if starargs is not None:
|
|
147
|
+
args.append("*" + unparse(starargs))
|
|
148
|
+
for kw in node.keywords:
|
|
149
|
+
if kw.arg is None:
|
|
150
|
+
args.append("**" + unparse(kw.value))
|
|
151
|
+
else:
|
|
152
|
+
args.append(kw.arg + "=" + unparse(kw.value))
|
|
153
|
+
kwargs = getattr(node, "kwargs", None)
|
|
154
|
+
if kwargs is not None:
|
|
155
|
+
args.append("**" + unparse(kwargs))
|
|
156
|
+
return args
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _slice(node):
|
|
160
|
+
kind = type(node).__name__
|
|
161
|
+
if kind == "Index":
|
|
162
|
+
return _slice(node.value)
|
|
163
|
+
if kind == "Slice":
|
|
164
|
+
text = ""
|
|
165
|
+
if node.lower is not None:
|
|
166
|
+
text += unparse(node.lower)
|
|
167
|
+
text += ":"
|
|
168
|
+
if node.upper is not None:
|
|
169
|
+
text += unparse(node.upper)
|
|
170
|
+
if node.step is not None:
|
|
171
|
+
text += ":" + unparse(node.step)
|
|
172
|
+
return text
|
|
173
|
+
if kind == "ExtSlice":
|
|
174
|
+
return ", ".join(_slice(d) for d in node.dims)
|
|
175
|
+
if kind == "Tuple" and node.elts:
|
|
176
|
+
return ", ".join(_slice(e) for e in node.elts)
|
|
177
|
+
return unparse(node)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
__all__ = ["binop", "cmpop", "unaryop", "unparse"]
|
cot_assert/_values.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Capturing values at the point an assert fails."""
|
|
2
|
+
|
|
3
|
+
from __future__ import absolute_import, division, print_function
|
|
4
|
+
|
|
5
|
+
from ._rpy import float_repr, specialize, we_are_translated
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@specialize.argtype(0)
|
|
9
|
+
def value(obj):
|
|
10
|
+
"""Host: the object itself. Translated: its RPython-level repr."""
|
|
11
|
+
if we_are_translated():
|
|
12
|
+
return rpy_repr(obj)
|
|
13
|
+
return obj
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@specialize.argtype(0)
|
|
17
|
+
def rpy_repr(obj):
|
|
18
|
+
if obj is None:
|
|
19
|
+
return "None"
|
|
20
|
+
if isinstance(obj, bool):
|
|
21
|
+
if obj:
|
|
22
|
+
return "True"
|
|
23
|
+
return "False"
|
|
24
|
+
if isinstance(obj, int):
|
|
25
|
+
return str(obj)
|
|
26
|
+
if isinstance(obj, float):
|
|
27
|
+
return float_repr(obj)
|
|
28
|
+
if isinstance(obj, str):
|
|
29
|
+
return "'" + obj + "'"
|
|
30
|
+
return "<object>"
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""pytest plugin: cot_assert in place of pytest's assertion rewriter.
|
|
2
|
+
|
|
3
|
+
Off unless enabled with ``--cot-assert`` or ``cot_assert = true`` in the ini
|
|
4
|
+
file. pytest keeps choosing which files to rewrite (test files, conftests,
|
|
5
|
+
``register_assert_rewrite``) and keeps caching them; only the rewriting
|
|
6
|
+
itself is swapped, and the cache name changes so neither rewriter picks up
|
|
7
|
+
the other's bytecode. Works with pytest 4.6 (Python 2.7) and current pytest.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import absolute_import, division, print_function
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from . import _hook, _render
|
|
15
|
+
from ._error import AnnotatedAssertion
|
|
16
|
+
from ._rewrite import rewrite_asserts
|
|
17
|
+
|
|
18
|
+
FINALIZE_MODES = ("message", "notes")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def pytest_addoption(parser):
|
|
22
|
+
group = parser.getgroup("cot_assert")
|
|
23
|
+
group.addoption(
|
|
24
|
+
"--cot-assert",
|
|
25
|
+
action="store_true",
|
|
26
|
+
default=None,
|
|
27
|
+
help="rewrite asserts with cot_assert instead of pytest's rewriter",
|
|
28
|
+
)
|
|
29
|
+
parser.addini(
|
|
30
|
+
"cot_assert",
|
|
31
|
+
type="bool",
|
|
32
|
+
default=False,
|
|
33
|
+
help="rewrite asserts with cot_assert instead of pytest's rewriter",
|
|
34
|
+
)
|
|
35
|
+
parser.addini(
|
|
36
|
+
"cot_assert_finalize",
|
|
37
|
+
default="message",
|
|
38
|
+
help="where a failed assert's explanation goes: message or notes",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _enabled(config):
|
|
43
|
+
# during pytest_load_initial_conftests only the early parse has run
|
|
44
|
+
option = getattr(config.known_args_namespace, "cot_assert", None)
|
|
45
|
+
if option is not None:
|
|
46
|
+
return option
|
|
47
|
+
return config.getini("cot_assert")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@pytest.hookimpl(tryfirst=True)
|
|
51
|
+
def pytest_load_initial_conftests(early_config, parser, args):
|
|
52
|
+
# before pytest imports (and rewrites) the first conftest
|
|
53
|
+
if not _enabled(early_config):
|
|
54
|
+
return
|
|
55
|
+
mode = early_config.getini("cot_assert_finalize")
|
|
56
|
+
if mode not in FINALIZE_MODES:
|
|
57
|
+
raise pytest.UsageError(
|
|
58
|
+
"cot_assert_finalize must be one of %s, not %r"
|
|
59
|
+
% (", ".join(FINALIZE_MODES), mode)
|
|
60
|
+
)
|
|
61
|
+
patch = _PytestPatch(mode)
|
|
62
|
+
patch.apply()
|
|
63
|
+
early_config.pluginmanager.register(patch, "cot_assert_active")
|
|
64
|
+
early_config.add_cleanup(patch.undo)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class _PytestPatch(object):
|
|
68
|
+
def __init__(self, finalize_mode):
|
|
69
|
+
self.finalize_mode = finalize_mode
|
|
70
|
+
self.saved = []
|
|
71
|
+
|
|
72
|
+
def apply(self):
|
|
73
|
+
from _pytest.assertion import rewrite as pytest_rewrite
|
|
74
|
+
|
|
75
|
+
self._set(pytest_rewrite, "rewrite_asserts", _pytest_rewrite_asserts)
|
|
76
|
+
self._set(
|
|
77
|
+
pytest_rewrite,
|
|
78
|
+
"PYC_TAIL",
|
|
79
|
+
pytest_rewrite.PYC_TAIL.replace(
|
|
80
|
+
pytest_rewrite.PYC_EXT, "-" + _hook.CACHE_TAG + pytest_rewrite.PYC_EXT
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
self.previous_formatter = _render.set_formatter(PytestFormatter())
|
|
84
|
+
|
|
85
|
+
def _set(self, obj, name, value):
|
|
86
|
+
self.saved.append((obj, name, getattr(obj, name)))
|
|
87
|
+
setattr(obj, name, value)
|
|
88
|
+
|
|
89
|
+
def undo(self):
|
|
90
|
+
while self.saved:
|
|
91
|
+
obj, name, value = self.saved.pop()
|
|
92
|
+
setattr(obj, name, value)
|
|
93
|
+
_render.set_formatter(self.previous_formatter)
|
|
94
|
+
|
|
95
|
+
@pytest.hookimpl(hookwrapper=True)
|
|
96
|
+
def pytest_runtest_makereport(self, item, call):
|
|
97
|
+
# render while pytest's comparison hook and config are still set,
|
|
98
|
+
# before the report turns the exception into text
|
|
99
|
+
excinfo = call.excinfo
|
|
100
|
+
if excinfo is not None and isinstance(excinfo.value, AnnotatedAssertion):
|
|
101
|
+
excinfo.value.finalize(self.finalize_mode)
|
|
102
|
+
yield
|
|
103
|
+
|
|
104
|
+
def pytest_report_header(self, config):
|
|
105
|
+
return "cot_assert: rewriting asserts (finalize into %s)" % (
|
|
106
|
+
self.finalize_mode,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _pytest_rewrite_asserts(mod, *args, **kwargs):
|
|
111
|
+
# pytest 4.6: (mod, module_path, config); current: (mod, source, path, config)
|
|
112
|
+
rewrite_asserts(mod)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class PytestFormatter(_render.Formatter):
|
|
116
|
+
"""Formatting through pytest's own helpers, as its rewriter does."""
|
|
117
|
+
|
|
118
|
+
def saferepr(self, obj):
|
|
119
|
+
from _pytest.assertion.rewrite import _saferepr
|
|
120
|
+
|
|
121
|
+
return _saferepr(obj)
|
|
122
|
+
|
|
123
|
+
def format_assertmsg(self, obj):
|
|
124
|
+
from _pytest.assertion.rewrite import _format_assertmsg
|
|
125
|
+
|
|
126
|
+
# pytest doubles % for the %-formatting its template goes through;
|
|
127
|
+
# nothing formats this text again
|
|
128
|
+
return _format_assertmsg(obj).replace("%%", "%")
|
|
129
|
+
|
|
130
|
+
def format_explanation(self, explanation):
|
|
131
|
+
from _pytest.assertion.util import format_explanation
|
|
132
|
+
|
|
133
|
+
return format_explanation(explanation)
|
|
134
|
+
|
|
135
|
+
def reprcompare(self, op, left, right):
|
|
136
|
+
from _pytest.assertion import util
|
|
137
|
+
|
|
138
|
+
if util._reprcompare is None:
|
|
139
|
+
return None
|
|
140
|
+
return util._reprcompare(op, left, right)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: cot-assert
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: assertion rewriting with a structured AssertionError, for Python 2.7, 3.x and RPython
|
|
5
|
+
Author-email: Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>
|
|
6
|
+
License-Expression: MPL-2.0
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: assert,pytest,rpython
|
|
9
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
10
|
+
Classifier: Framework :: Pytest
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 2
|
|
13
|
+
Classifier: Programming Language :: Python :: 2.7
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Software Development :: Testing
|
|
22
|
+
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,!=3.8.*,>=2.7
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# cot-assert
|
|
26
|
+
|
|
27
|
+
Assertion rewriting that raises a structured `AnnotatedAssertion`, for Python
|
|
28
|
+
2.7, Python 3.9+ and RPython. Intended as a drop-in replacement for pytest's
|
|
29
|
+
assertion rewriting on current pytest and on pytest 4.6.
|
|
30
|
+
|
|
31
|
+
Pre-alpha.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
pip install cot-assert
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
One universal wheel serves Python 2.7 (pip 20 and later, CPython or PyPy)
|
|
38
|
+
and Python 3.9 and later. It has no dependencies.
|
|
39
|
+
|
|
40
|
+
## With pytest
|
|
41
|
+
|
|
42
|
+
Installing the package registers a pytest plugin that stays off until
|
|
43
|
+
enabled:
|
|
44
|
+
|
|
45
|
+
```ini
|
|
46
|
+
[pytest]
|
|
47
|
+
cot_assert = true
|
|
48
|
+
# where a failed assert's explanation goes: message (default) or notes
|
|
49
|
+
cot_assert_finalize = message
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
or `pytest --cot-assert`. On Python 2.7, where it runs from source, load it
|
|
53
|
+
with `-p cot_assert.pytest_plugin`.
|
|
54
|
+
|
|
55
|
+
pytest still decides which modules are rewritten (test files, conftests,
|
|
56
|
+
`pytest.register_assert_rewrite`) and caches them under a separate name;
|
|
57
|
+
cot_assert does the rewriting, and failures render through pytest's own
|
|
58
|
+
comparison hooks. Failures show as `AnnotatedAssertion` instead of
|
|
59
|
+
`AssertionError`. `--assert=plain` turns rewriting off for both.
|
|
60
|
+
|
|
61
|
+
## Without pytest
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import cot_assert
|
|
65
|
+
|
|
66
|
+
cot_assert.install(["mypackage", "test_*"])
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
rewrites modules imported afterwards whose name matches.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
cot_assert/__init__.py,sha256=cEb8TqnJ1XTtAFuAAxnDq7fpFX7MZ_cr16q0Sudbrik,582
|
|
2
|
+
cot_assert/_entry.py,sha256=x-a-3vo6uRDgK27X7EcPIKNyvt50viHuG1HNeE2G6xE,983
|
|
3
|
+
cot_assert/_error.py,sha256=L_Y52SFTPjWvwxPnIUZI-dKyD1725XPBWZ5M0YwDOkc,5425
|
|
4
|
+
cot_assert/_hook.py,sha256=JVA6A7_bHMQpQ_zUJoQyzmcXD6aota-9rmsc-1GJToc,7332
|
|
5
|
+
cot_assert/_llexc.py,sha256=VftW_Ktg-tXs5qXoR2SA04RVfGilRsQEwsbHqKRphFI,2582
|
|
6
|
+
cot_assert/_render.py,sha256=8C1wUUVlj9XRber8zxDIN3T1BivhQVr4WGZxnRIitks,9682
|
|
7
|
+
cot_assert/_rewrite.py,sha256=g1n0kWm6sbXJXldwp5jYi0YzypILBLBwDbst_NAQq6s,17613
|
|
8
|
+
cot_assert/_rpy.py,sha256=NC3d5VMqUgrg-nJTdPPPIPPaZquKPRUmcd8wWWB1VN8,957
|
|
9
|
+
cot_assert/_runtime.py,sha256=3_BimWc_RfkVZCwIUGTOc2ndfQawkUcWEFpUbekhE-o,334
|
|
10
|
+
cot_assert/_unparse.py,sha256=Yq1oGl07BQ3HcleCpx_920PU6vPoZP183iPUe29Dmgo,5541
|
|
11
|
+
cot_assert/_values.py,sha256=IMmaZUoE_ioyuFZQU_H4qo55QgAGGL2l1A_fU9ovzu8,742
|
|
12
|
+
cot_assert/pytest_plugin.py,sha256=v4xGIxgkjUHgR7SYIXlwHGGo9PJnx0WAeRrf8syutLM,4637
|
|
13
|
+
cot_assert-0.1.0.dist-info/METADATA,sha256=SSLQsZ0ZnZXoTZRn131SRuoo5A2M2kbRSw6dfw221CI,2312
|
|
14
|
+
cot_assert-0.1.0.dist-info/WHEEL,sha256=DnXx7cBEyVTTMvhePCuz2Now68IkDfyaQ4wNff8GnEk,105
|
|
15
|
+
cot_assert-0.1.0.dist-info/entry_points.txt,sha256=cyZBmXtGq7G82iJQy0Mhmqrq3gui0OkDetFeObZrXaM,49
|
|
16
|
+
cot_assert-0.1.0.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
17
|
+
cot_assert-0.1.0.dist-info/RECORD,,
|