Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Negative indices slices #2511

Merged
merged 4 commits into from
Jul 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ their individual contributions.
* `Ryan Turner <https://github.com/rdturnermtl>`_ ([email protected])
* `Sam Bishop (TechDragon) <https://github.com/techdragon>`_ ([email protected])
* `Sam Hames <https://www.github.com/SamHames>`_
* `Sangarshanan <https://www.github.com/sangarshanan>`_ ([email protected])
* `Sanyam Khurana <https://github.com/CuriousLearner>`_
* `Saul Shanabrook <https://www.github.com/saulshanabrook>`_ ([email protected])
* `Stuart Cook <https://www.github.com/Zalathar>`_
Expand Down
7 changes: 7 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
RELEASE_TYPE: minor

The :func:`~hypothesis.strategies.slices` strategy can now generate slices for empty sequences,
slices with negative start and stop indices (from the end of the sequence),
and ``step=None`` in place of ``step=1``.

Thanks to Sangarshanan for implementing this feature at the EuroPython sprints!
2 changes: 1 addition & 1 deletion hypothesis-python/src/hypothesis/internal/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def check_valid_size(value, name):

Otherwise raises InvalidArgument.
"""
if value is None and name != "min_size":
if value is None and name not in ("min_size", "size"):
return
check_type(int, value, name)
if value < 0:
Expand Down
14 changes: 10 additions & 4 deletions hypothesis-python/src/hypothesis/strategies/_internal/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2173,15 +2173,16 @@ def functions(
def slices(draw: Any, size: int) -> slice:
"""Generates slices that will select indices up to the supplied size

Generated slices will have start and stop indices that range from 0 to size - 1
Generated slices will have start and stop indices that range from -size to size - 1
and will step in the appropriate direction. Slices should only produce an empty selection
if the start and end are the same.

Examples from this strategy shrink toward 0 and smaller values
"""
check_valid_integer(size, "size")
if size is None or size < 1:
raise InvalidArgument("size=%r must be at least one" % size)
check_valid_size(size, "size")
if size == 0:
step = draw(none() | integers().filter(bool))
return slice(None, None, step)

min_start = min_stop = 0
max_start = max_stop = size
Expand All @@ -2205,4 +2206,9 @@ def slices(draw: Any, size: int) -> slice:
if (stop or 0) < (start or 0):
step *= -1

if draw(booleans()) and start is not None:
start -= size
if draw(booleans()) and stop is not None:
stop -= size

return slice(start, stop, step)
1 change: 0 additions & 1 deletion hypothesis-python/tests/cover/test_direct_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ def fn_ktest(*fnkwargs):
(ds.characters, {"max_codepoint": "1"}),
(ds.characters, {"whitelist_categories": []}),
(ds.characters, {"whitelist_categories": ["Nd"], "blacklist_categories": ["Nd"]}),
(ds.slices, {"size": 0}),
(ds.slices, {"size": None}),
(ds.slices, {"size": "chips"}),
(ds.slices, {"size": -1}),
Expand Down
16 changes: 12 additions & 4 deletions hypothesis-python/tests/cover/test_slices.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@
@use_several_sizes
def test_stop_stays_within_bounds(size):
assert_all_examples(
st.slices(size), lambda x: x.stop is None or (x.stop >= 0 and x.stop <= size)
st.slices(size),
lambda x: x.stop is None or (x.stop >= -size and x.stop <= size),
)


@use_several_sizes
def test_start_stay_within_bounds(size):
assert_all_examples(
st.slices(size), lambda x: x.start is None or (x.start >= 0 and x.start <= size)
st.slices(size),
lambda x: x.start is None or (x.start >= -size and x.start <= size),
)


Expand All @@ -45,9 +47,9 @@ def test_step_stays_within_bounds(size):
st.slices(size),
lambda x: (
x.indices(size)[0] + x.indices(size)[2] <= size
and x.indices(size)[0] + x.indices(size)[2] >= -1
and x.indices(size)[0] + x.indices(size)[2] >= -size
)
or x.start == x.stop,
or x.start % size == x.stop % size,
)


Expand Down Expand Up @@ -98,3 +100,9 @@ def test_start_will_equal_0(size):
@settings(deadline=None)
def test_start_will_equal_stop(size):
find_any(st.slices(size), lambda x: x.start == x.stop)


def test_size_is_equal_0():
assert_all_examples(
st.slices(0), lambda x: x.step != 0 and x.start is None and x.stop is None
)