Skip to content

Commit 0b2cfc0

Browse files
committed
merge fixed_dictionaries strategies
1 parent f62ec1e commit 0b2cfc0

File tree

3 files changed

+34
-41
lines changed

3 files changed

+34
-41
lines changed

hypothesis-python/RELEASE.rst

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
RELEASE_TYPE: patch
2+
3+
This patch improves the string representation of :func:`~hypothesis.strategies.fixed_dictionaries`.

hypothesis-python/src/hypothesis/strategies/_internal/collections.py

+27-37
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111
import copy
1212
from collections.abc import Iterable
13-
from typing import Any, overload
13+
from typing import Any, Optional, overload
1414

15+
from hypothesis import strategies as st
1516
from hypothesis.errors import InvalidArgument
1617
from hypothesis.internal.conjecture import utils as cu
1718
from hypothesis.internal.conjecture.engine import BUFFER_SIZE
@@ -24,7 +25,6 @@
2425
T4,
2526
T5,
2627
Ex,
27-
MappedStrategy,
2828
SearchStrategy,
2929
T,
3030
check_strategy,
@@ -306,50 +306,32 @@ def do_draw(self, data):
306306
return result
307307

308308

309-
class FixedKeysDictStrategy(MappedStrategy):
309+
class FixedDictStrategy(SearchStrategy):
310310
"""A strategy which produces dicts with a fixed set of keys, given a
311311
strategy for each of their equivalent values.
312312
313313
e.g. {'foo' : some_int_strategy} would generate dicts with the single
314314
key 'foo' mapping to some integer.
315315
"""
316316

317-
def __init__(self, strategy_dict):
318-
dict_type = type(strategy_dict)
319-
self.keys = tuple(strategy_dict.keys())
320-
super().__init__(
321-
strategy=TupleStrategy(strategy_dict[k] for k in self.keys),
322-
pack=lambda value: dict_type(zip(self.keys, value)),
317+
def __init__(
318+
self,
319+
mapping: dict[T, SearchStrategy[Ex]],
320+
*,
321+
optional: Optional[dict[T, SearchStrategy[Ex]]],
322+
):
323+
dict_type = type(mapping)
324+
keys = tuple(mapping.keys())
325+
self.fixed = st.tuples(*[mapping[k] for k in keys]).map(
326+
lambda value: dict_type(zip(keys, value))
323327
)
324-
325-
def calc_is_empty(self, recur):
326-
return recur(self.mapped_strategy)
327-
328-
def __repr__(self):
329-
return f"FixedKeysDictStrategy({self.keys!r}, {self.mapped_strategy!r})"
330-
331-
332-
class FixedAndOptionalKeysDictStrategy(SearchStrategy):
333-
"""A strategy which produces dicts with a fixed set of keys, given a
334-
strategy for each of their equivalent values.
335-
336-
e.g. {'foo' : some_int_strategy} would generate dicts with the single
337-
key 'foo' mapping to some integer.
338-
"""
339-
340-
def __init__(self, strategy_dict, optional):
341-
self.required = strategy_dict
342-
self.fixed = FixedKeysDictStrategy(strategy_dict)
343328
self.optional = optional
344329

345-
def calc_is_empty(self, recur):
346-
return recur(self.fixed)
347-
348-
def __repr__(self):
349-
return f"FixedAndOptionalKeysDictStrategy({self.required!r}, {self.optional!r})"
350-
351330
def do_draw(self, data):
352-
result = data.draw(self.fixed)
331+
value = data.draw(self.fixed)
332+
if self.optional is None:
333+
return value
334+
353335
remaining = [k for k, v in self.optional.items() if not v.is_empty]
354336
should_draw = cu.many(
355337
data, min_size=0, max_size=len(remaining), average_size=len(remaining) / 2
@@ -358,5 +340,13 @@ def do_draw(self, data):
358340
j = data.draw_integer(0, len(remaining) - 1)
359341
remaining[-1], remaining[j] = remaining[j], remaining[-1]
360342
key = remaining.pop()
361-
result[key] = data.draw(self.optional[key])
362-
return result
343+
value[key] = data.draw(self.optional[key])
344+
return value
345+
346+
def calc_is_empty(self, recur):
347+
return recur(self.fixed)
348+
349+
def __repr__(self):
350+
if self.optional is not None:
351+
return f"fixed_dictionaries({self.keys!r}, optional={self.optional!r})"
352+
return f"fixed_dictionaries({self.keys!r})"

hypothesis-python/src/hypothesis/strategies/_internal/core.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@
105105
)
106106
from hypothesis.strategies._internal import SearchStrategy, check_strategy
107107
from hypothesis.strategies._internal.collections import (
108-
FixedAndOptionalKeysDictStrategy,
109-
FixedKeysDictStrategy,
108+
FixedDictStrategy,
110109
ListStrategy,
111110
TupleStrategy,
112111
UniqueListStrategy,
@@ -510,6 +509,7 @@ def fixed_dictionaries(
510509
check_type(dict, mapping, "mapping")
511510
for k, v in mapping.items():
512511
check_strategy(v, f"mapping[{k!r}]")
512+
513513
if optional is not None:
514514
check_type(dict, optional, "optional")
515515
for k, v in optional.items():
@@ -524,8 +524,8 @@ def fixed_dictionaries(
524524
"The following keys were in both mapping and optional, "
525525
f"which is invalid: {set(mapping) & set(optional)!r}"
526526
)
527-
return FixedAndOptionalKeysDictStrategy(mapping, optional)
528-
return FixedKeysDictStrategy(mapping)
527+
528+
return FixedDictStrategy(mapping, optional=optional)
529529

530530

531531
@cacheable

0 commit comments

Comments
 (0)