hypothesis 6.135.7__py3-none-any.whl → 6.135.8__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.
- hypothesis/extra/_patching.py +49 -19
- hypothesis/version.py +1 -1
- {hypothesis-6.135.7.dist-info → hypothesis-6.135.8.dist-info}/METADATA +1 -1
- {hypothesis-6.135.7.dist-info → hypothesis-6.135.8.dist-info}/RECORD +8 -8
- {hypothesis-6.135.7.dist-info → hypothesis-6.135.8.dist-info}/WHEEL +0 -0
- {hypothesis-6.135.7.dist-info → hypothesis-6.135.8.dist-info}/entry_points.txt +0 -0
- {hypothesis-6.135.7.dist-info → hypothesis-6.135.8.dist-info}/licenses/LICENSE.txt +0 -0
- {hypothesis-6.135.7.dist-info → hypothesis-6.135.8.dist-info}/top_level.txt +0 -0
hypothesis/extra/_patching.py
CHANGED
@@ -26,9 +26,11 @@ import re
|
|
26
26
|
import sys
|
27
27
|
import types
|
28
28
|
from ast import literal_eval
|
29
|
+
from collections.abc import Sequence
|
29
30
|
from contextlib import suppress
|
30
31
|
from datetime import date, datetime, timedelta, timezone
|
31
32
|
from pathlib import Path
|
33
|
+
from typing import Any, Optional
|
32
34
|
|
33
35
|
import libcst as cst
|
34
36
|
from libcst import matchers as m
|
@@ -56,7 +58,7 @@ _space_only_re = re.compile("^ +$", re.MULTILINE)
|
|
56
58
|
_leading_space_re = re.compile("(^[ ]*)(?:[^ \n])", re.MULTILINE)
|
57
59
|
|
58
60
|
|
59
|
-
def dedent(text):
|
61
|
+
def dedent(text: str) -> tuple[str, str]:
|
60
62
|
# Simplified textwrap.dedent, for valid Python source code only
|
61
63
|
text = _space_only_re.sub("", text)
|
62
64
|
prefix = min(_leading_space_re.findall(text), key=len)
|
@@ -70,7 +72,14 @@ def indent(text: str, prefix: str) -> str:
|
|
70
72
|
class AddExamplesCodemod(VisitorBasedCodemodCommand):
|
71
73
|
DESCRIPTION = "Add explicit examples to failing tests."
|
72
74
|
|
73
|
-
def __init__(
|
75
|
+
def __init__(
|
76
|
+
self,
|
77
|
+
context: CodemodContext,
|
78
|
+
fn_examples: dict[str, list[tuple[cst.Call, str]]],
|
79
|
+
strip_via: tuple[str, ...] = (),
|
80
|
+
decorator: str = "example",
|
81
|
+
width: int = 88,
|
82
|
+
):
|
74
83
|
"""Add @example() decorator(s) for failing test(s).
|
75
84
|
|
76
85
|
`code` is the source code of the module where the test functions are defined.
|
@@ -79,9 +88,11 @@ class AddExamplesCodemod(VisitorBasedCodemodCommand):
|
|
79
88
|
assert fn_examples, "This codemod does nothing without fn_examples."
|
80
89
|
super().__init__(context)
|
81
90
|
|
82
|
-
self.decorator_func = cst.parse_expression(
|
91
|
+
self.decorator_func = cst.parse_expression(decorator)
|
83
92
|
self.line_length = width
|
84
|
-
value_in_strip_via = m.MatchIfTrue(
|
93
|
+
value_in_strip_via: Any = m.MatchIfTrue(
|
94
|
+
lambda x: literal_eval(x.value) in strip_via
|
95
|
+
)
|
85
96
|
self.strip_matching = m.Call(
|
86
97
|
m.Attribute(m.Call(), m.Name("via")),
|
87
98
|
[m.Arg(m.SimpleString() & value_in_strip_via)],
|
@@ -89,11 +100,17 @@ class AddExamplesCodemod(VisitorBasedCodemodCommand):
|
|
89
100
|
|
90
101
|
# Codemod the failing examples to Call nodes usable as decorators
|
91
102
|
self.fn_examples = {
|
92
|
-
k: tuple(
|
103
|
+
k: tuple(
|
104
|
+
d
|
105
|
+
for (node, via) in nodes
|
106
|
+
if (d := self.__call_node_to_example_dec(node, via))
|
107
|
+
)
|
93
108
|
for k, nodes in fn_examples.items()
|
94
109
|
}
|
95
110
|
|
96
|
-
def __call_node_to_example_dec(
|
111
|
+
def __call_node_to_example_dec(
|
112
|
+
self, node: cst.Call, via: str
|
113
|
+
) -> Optional[cst.Decorator]:
|
97
114
|
# If we have black installed, remove trailing comma, _unless_ there's a comment
|
98
115
|
node = node.with_changes(
|
99
116
|
func=self.decorator_func,
|
@@ -112,7 +129,7 @@ class AddExamplesCodemod(VisitorBasedCodemodCommand):
|
|
112
129
|
else node.args
|
113
130
|
),
|
114
131
|
)
|
115
|
-
via = cst.Call(
|
132
|
+
via: cst.BaseExpression = cst.Call(
|
116
133
|
func=cst.Attribute(node, cst.Name("via")),
|
117
134
|
args=[cst.Arg(cst.SimpleString(repr(via)))],
|
118
135
|
)
|
@@ -127,7 +144,9 @@ class AddExamplesCodemod(VisitorBasedCodemodCommand):
|
|
127
144
|
via = cst.parse_expression(pretty.strip())
|
128
145
|
return cst.Decorator(via)
|
129
146
|
|
130
|
-
def leave_FunctionDef(
|
147
|
+
def leave_FunctionDef(
|
148
|
+
self, _original_node: cst.FunctionDef, updated_node: cst.FunctionDef
|
149
|
+
) -> cst.FunctionDef:
|
131
150
|
return updated_node.with_changes(
|
132
151
|
# TODO: improve logic for where in the list to insert this decorator
|
133
152
|
decorators=tuple(
|
@@ -140,11 +159,16 @@ class AddExamplesCodemod(VisitorBasedCodemodCommand):
|
|
140
159
|
)
|
141
160
|
|
142
161
|
|
143
|
-
def get_patch_for(
|
162
|
+
def get_patch_for(
|
163
|
+
func: Any,
|
164
|
+
examples: Sequence[tuple[str, str]],
|
165
|
+
*,
|
166
|
+
strip_via: tuple[str, ...] = (),
|
167
|
+
) -> Optional[tuple[str, str, str]]:
|
144
168
|
# Skip this if we're unable to find the location or source of this function.
|
145
169
|
try:
|
146
170
|
module = sys.modules[func.__module__]
|
147
|
-
fname = Path(module.__file__).relative_to(Path.cwd())
|
171
|
+
fname = Path(module.__file__).relative_to(Path.cwd()) # type: ignore
|
148
172
|
before = inspect.getsource(func)
|
149
173
|
except Exception:
|
150
174
|
return None
|
@@ -160,10 +184,10 @@ def get_patch_for(func, failing_examples, *, strip_via=()):
|
|
160
184
|
|
161
185
|
# The printed examples might include object reprs which are invalid syntax,
|
162
186
|
# so we parse here and skip over those. If _none_ are valid, there's no patch.
|
163
|
-
call_nodes = []
|
164
|
-
for ex, via in set(
|
187
|
+
call_nodes: list[tuple[cst.Call, str]] = []
|
188
|
+
for ex, via in set(examples):
|
165
189
|
with suppress(Exception):
|
166
|
-
node = cst.parse_module(ex)
|
190
|
+
node: Any = cst.parse_module(ex)
|
167
191
|
the_call = node.body[0].body[0].value
|
168
192
|
assert isinstance(the_call, cst.Call), the_call
|
169
193
|
# Check for st.data(), which doesn't support explicit examples
|
@@ -194,14 +218,15 @@ def get_patch_for(func, failing_examples, *, strip_via=()):
|
|
194
218
|
with suppress(Exception):
|
195
219
|
wrapper = cst.metadata.MetadataWrapper(node)
|
196
220
|
kwarg_names = {
|
197
|
-
|
221
|
+
node.keyword # type: ignore
|
222
|
+
for node in m.findall(wrapper, m.Arg(keyword=m.Name()))
|
198
223
|
}
|
199
224
|
node = m.replace(
|
200
225
|
wrapper,
|
201
226
|
m.Name(value=m.MatchIfTrue(names.__contains__))
|
202
227
|
& m.MatchMetadata(ExpressionContextProvider, ExpressionContext.LOAD)
|
203
|
-
& m.MatchIfTrue(lambda n, k=kwarg_names: n not in k),
|
204
|
-
replacement=lambda node, _, ns=names: ns[node.value],
|
228
|
+
& m.MatchIfTrue(lambda n, k=kwarg_names: n not in k), # type: ignore
|
229
|
+
replacement=lambda node, _, ns=names: ns[node.value], # type: ignore
|
205
230
|
)
|
206
231
|
node = node.body[0].body[0].value
|
207
232
|
assert isinstance(node, cst.Call), node
|
@@ -229,18 +254,23 @@ def get_patch_for(func, failing_examples, *, strip_via=()):
|
|
229
254
|
CodemodContext(),
|
230
255
|
fn_examples={func.__name__: call_nodes},
|
231
256
|
strip_via=strip_via,
|
232
|
-
|
257
|
+
decorator=decorator_func,
|
233
258
|
width=88 - len(prefix), # to match Black's default formatting
|
234
259
|
).transform_module(node)
|
235
260
|
return (str(fname), before, indent(after.code, prefix=prefix))
|
236
261
|
|
237
262
|
|
238
|
-
def make_patch(
|
263
|
+
def make_patch(
|
264
|
+
triples: Sequence[tuple[str, str, str]],
|
265
|
+
*,
|
266
|
+
msg: str = "Hypothesis: add explicit examples",
|
267
|
+
when: Optional[datetime] = None,
|
268
|
+
) -> str:
|
239
269
|
"""Create a patch for (fname, before, after) triples."""
|
240
270
|
assert triples, "attempted to create empty patch"
|
241
271
|
when = when or datetime.now(tz=timezone.utc)
|
242
272
|
|
243
|
-
by_fname = {}
|
273
|
+
by_fname: dict[Path, list[tuple[str, str]]] = {}
|
244
274
|
for fname, before, after in triples:
|
245
275
|
by_fname.setdefault(Path(fname), []).append((before, after))
|
246
276
|
|
hypothesis/version.py
CHANGED
@@ -14,10 +14,10 @@ hypothesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
hypothesis/reporting.py,sha256=f-jhl1JfAi5_tG8dsUd2qDjGcPdvxEzfF6hXmpTFQ1g,1761
|
15
15
|
hypothesis/stateful.py,sha256=vQ8wDO7YW-8nGlBGLfR9ariwmRCS9jxJy-Ky3swXjDE,42861
|
16
16
|
hypothesis/statistics.py,sha256=kZ5mc0fAg7gnSO6EmDo82fyz8DYhIiJ_mHe7srxOeQ0,5438
|
17
|
-
hypothesis/version.py,sha256=
|
17
|
+
hypothesis/version.py,sha256=HDvRrINvs4J753R-FC-LQ2FqZQhRlgU7mrhH5euNkb0,498
|
18
18
|
hypothesis/extra/__init__.py,sha256=gx4ENVDkrzBxy5Lv3Iyfs3tvMGdWMbiHfi95B7t61CY,415
|
19
19
|
hypothesis/extra/_array_helpers.py,sha256=PLmFckBfQpzQ4Q3dFJQqMmrbm7Qdvqxf1t9LHDCuSp0,27627
|
20
|
-
hypothesis/extra/_patching.py,sha256=
|
20
|
+
hypothesis/extra/_patching.py,sha256=JztID3rv8Wnos7WMbZaLM3mlKnwt6ZlifyRfXSy4mLQ,11719
|
21
21
|
hypothesis/extra/array_api.py,sha256=bv_wisQS56wvwg-LiC26DxvzmPxcNLzlbzmltFWZ_Jo,42609
|
22
22
|
hypothesis/extra/cli.py,sha256=HOH_BGosyUvS4yNDsWF4Dfe672tEFGT4BBPBuZamm1s,12885
|
23
23
|
hypothesis/extra/codemods.py,sha256=i_iM5aSnrNjSZ_uNW40yShxXo7qaXuCrDHy8OznOa7o,11224
|
@@ -105,9 +105,9 @@ hypothesis/utils/terminal.py,sha256=IxGYDGaE4R3b_vMfz5buWbN18XH5qVP4IxqAgNAU5as,
|
|
105
105
|
hypothesis/vendor/__init__.py,sha256=gx4ENVDkrzBxy5Lv3Iyfs3tvMGdWMbiHfi95B7t61CY,415
|
106
106
|
hypothesis/vendor/pretty.py,sha256=WEZC-UV-QQgCjUf2Iz1WWaWnbgT7Hc3s-GWEVxq-Qz0,36114
|
107
107
|
hypothesis/vendor/tlds-alpha-by-domain.txt,sha256=W9hYvpu2BMmNgE-SfPp8-GTzEVjw0HJUviqlvHwpZu8,9588
|
108
|
-
hypothesis-6.135.
|
109
|
-
hypothesis-6.135.
|
110
|
-
hypothesis-6.135.
|
111
|
-
hypothesis-6.135.
|
112
|
-
hypothesis-6.135.
|
113
|
-
hypothesis-6.135.
|
108
|
+
hypothesis-6.135.8.dist-info/licenses/LICENSE.txt,sha256=rIkDe6xjVQZE3OjPMsZ2Xl-rncGhzpS4n4qAXzQaZ1A,17141
|
109
|
+
hypothesis-6.135.8.dist-info/METADATA,sha256=HdZyzvkWTMUPXGrbKESobO_OmKy9M5lwmiLlFD3JFIc,5637
|
110
|
+
hypothesis-6.135.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
111
|
+
hypothesis-6.135.8.dist-info/entry_points.txt,sha256=JDoUs9w1bYme7aG_eJ1cCtstRTWD71BzG8iRi-G2eHE,113
|
112
|
+
hypothesis-6.135.8.dist-info/top_level.txt,sha256=ReGreaueiJ4d1I2kEiig_CLeA0sD4QCQ4qk_8kH1oDc,81
|
113
|
+
hypothesis-6.135.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|