Skip to content

Commit db0bde8

Browse files
committed
Resolve Iterable type arg
1 parent 2b470fc commit db0bde8

File tree

6 files changed

+36
-27
lines changed

6 files changed

+36
-27
lines changed

hypothesis-python/RELEASE.rst

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
RELEASE_TYPE: patch
2+
3+
This patch fixes :func:`~hypothesis.strategies.from_type` with
4+
:class:`Iterable[T] <python:typing.Iterable>` (:issue:`2645`).

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,10 @@ def _networks(bits):
365365

366366
_global_type_lookup.update(
367367
{
368-
typing.ByteString: st.binary() | st.binary().map(bytearray),
369-
# Reversible is somehow a subclass of Hashable, so we tuplize it.
370-
# See also the discussion at https://bugs.python.org/issue39046
371-
typing.Reversible: st.lists(st.integers()).map(tuple),
368+
# Note: while ByteString notionally also represents the bytearray and
369+
# memoryview types, it is a subclass of Hashable and those types are not.
370+
# We therefore only generate the bytes type.
371+
typing.ByteString: st.binary(),
372372
# TODO: SupportsAbs and SupportsRound should be covariant, ie have functions.
373373
typing.SupportsAbs: st.one_of(
374374
st.booleans(),

hypothesis-python/tests/cover/test_lookup.py

+24-19
Original file line numberDiff line numberDiff line change
@@ -90,25 +90,30 @@ def test_typing_Type_Union(ex):
9090
assert ex in (str, list)
9191

9292

93+
class Elem:
94+
pass
95+
96+
9397
@pytest.mark.parametrize(
9498
"typ,coll_type,instance_of",
9599
[
96-
(typing.Set[int], set, int),
97-
(typing.FrozenSet[int], frozenset, int),
98-
(typing.Dict[int, int], dict, int),
99-
(typing.DefaultDict[int, int], collections.defaultdict, int),
100-
(typing.KeysView[int], type({}.keys()), int),
101-
(typing.ValuesView[int], type({}.values()), int),
102-
(typing.List[int], list, int),
103-
(typing.Tuple[int], tuple, int),
104-
(typing.Tuple[int, ...], tuple, int),
105-
(typing.Iterator[int], typing.Iterator, int),
106-
(typing.Sequence[int], typing.Sequence, int),
107-
(typing.Iterable[int], typing.Iterable, int),
108-
(typing.Mapping[int, None], typing.Mapping, int),
109-
(typing.Container[int], typing.Container, int),
110-
(typing.NamedTuple("A_NamedTuple", (("elem", int),)), tuple, int),
100+
(typing.Set[Elem], set, Elem),
101+
(typing.FrozenSet[Elem], frozenset, Elem),
102+
(typing.Dict[Elem, Elem], dict, Elem),
103+
(typing.DefaultDict[Elem, Elem], collections.defaultdict, Elem),
104+
(typing.KeysView[Elem], type({}.keys()), Elem),
105+
(typing.ValuesView[Elem], type({}.values()), Elem),
106+
(typing.List[Elem], list, Elem),
107+
(typing.Tuple[Elem], tuple, Elem),
108+
(typing.Tuple[Elem, ...], tuple, Elem),
109+
(typing.Iterator[Elem], typing.Iterator, Elem),
110+
(typing.Sequence[Elem], typing.Sequence, Elem),
111+
(typing.Iterable[Elem], typing.Iterable, Elem),
112+
(typing.Mapping[Elem, None], typing.Mapping, Elem),
113+
(typing.Container[Elem], typing.Container, Elem),
114+
(typing.NamedTuple("A_NamedTuple", (("elem", Elem),)), tuple, Elem),
111115
],
116+
ids=repr,
112117
)
113118
@given(data=st.data())
114119
def test_specialised_collection_types(data, typ, coll_type, instance_of):
@@ -119,17 +124,17 @@ def test_specialised_collection_types(data, typ, coll_type, instance_of):
119124
assume(instances) # non-empty collections without calling len(iterator)
120125

121126

122-
@given(from_type(typing.DefaultDict[int, int]).filter(len))
127+
@given(from_type(typing.DefaultDict[Elem, Elem]).filter(len))
123128
def test_defaultdict_values_type(ex):
124-
assert all(isinstance(elem, int) for elem in ex.values())
129+
assert all(isinstance(elem, Elem) for elem in ex.values())
125130

126131

127-
@given(from_type(typing.ItemsView[int, int]).filter(len))
132+
@given(from_type(typing.ItemsView[Elem, Elem]).filter(len))
128133
def test_ItemsView(ex):
129134
# See https://github.com/python/typing/issues/177
130135
assert isinstance(ex, type({}.items()))
131136
assert all(isinstance(elem, tuple) and len(elem) == 2 for elem in ex)
132-
assert all(all(isinstance(e, int) for e in elem) for elem in ex)
137+
assert all(all(isinstance(e, Elem) for e in elem) for elem in ex)
133138

134139

135140
def test_Optional_minimises_to_None():

hypothesis-python/tests/ghostwriter/recorded/timsort_idempotent.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import test_expected_output
55
from hypothesis import given, strategies as st
66

77

8-
@given(seq=st.one_of(st.binary(), st.binary().map(bytearray), st.lists(st.integers())))
8+
@given(seq=st.one_of(st.binary(), st.lists(st.integers())))
99
def test_idempotent_timsort(seq):
1010
result = test_expected_output.timsort(seq=seq)
1111
repeat = test_expected_output.timsort(seq=result)

hypothesis-python/tests/ghostwriter/test_ghostwriter.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import unittest.mock
2222
from decimal import Decimal
2323
from types import ModuleType
24-
from typing import Any, List, Sequence, Set
24+
from typing import Any, List, Sequence, Set, Union
2525

2626
import pytest
2727

@@ -117,7 +117,7 @@ def non_resolvable_arg(x: NotResolvable):
117117

118118

119119
def test_flattens_one_of_repr():
120-
strat = from_type(Sequence[int])
120+
strat = from_type(Union[int, Sequence[int]])
121121
assert repr(strat).count("one_of(") > 1
122122
assert ghostwriter._valid_syntax_repr(strat).count("one_of(") == 1
123123

tooling/src/hypothesistooling/__main__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ def run_tox(task, version):
376376

377377

378378
# Via https://github.com/pyenv/pyenv/tree/master/plugins/python-build/share/python-build
379-
PY36 = "3.6.9"
379+
PY36 = "3.6.12"
380380
PY37 = "3.7.9"
381381
PY38 = "3.8.6"
382382
PY39 = "3.9.0"

0 commit comments

Comments
 (0)