We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Internal error for unique lists
```python
from hypothesis import given, strategies as st

@given(st.lists(st.sampled_from([0, 0.0]), unique=True, min_size=1))
def t(x): pass

t()
```

triggers an assertion via `conjecture.utils.integer_range(data, lower=0, upper=-1)`

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `hypothesis-python/src/hypothesis/searchstrategy/collections.py`
Content:
```
1 # coding=utf-8
2 #
3 # This file is part of Hypothesis, which may be found at
4 # https://github.com/HypothesisWorks/hypothesis/
5 #
6 # Most of this work is copyright (C) 2013-2019 David R. MacIver
7 # (david@drmaciver.com), but it contains contributions by others. See
8 # CONTRIBUTING.rst for a full list of people who may hold copyright, and
9 # consult the git log if you need to determine who owns an individual
10 # contribution.
11 #
12 # This Source Code Form is subject to the terms of the Mozilla Public License,
13 # v. 2.0. If a copy of the MPL was not distributed with this file, You can
14 # obtain one at https://mozilla.org/MPL/2.0/.
15 #
16 # END HEADER
17 
18 from __future__ import absolute_import, division, print_function
19 
20 from collections import OrderedDict
21 
22 import hypothesis.internal.conjecture.utils as cu
23 from hypothesis.errors import InvalidArgument
24 from hypothesis.internal.conjecture.junkdrawer import LazySequenceCopy
25 from hypothesis.internal.conjecture.utils import combine_labels
26 from hypothesis.searchstrategy.strategies import (
27     MappedSearchStrategy,
28     SearchStrategy,
29     filter_not_satisfied,
30 )
31 
32 
33 class TupleStrategy(SearchStrategy):
34     """A strategy responsible for fixed length tuples based on heterogenous
35     strategies for each of their elements."""
36 
37     def __init__(self, strategies):
38         SearchStrategy.__init__(self)
39         self.element_strategies = tuple(strategies)
40 
41     def do_validate(self):
42         for s in self.element_strategies:
43             s.validate()
44 
45     def calc_label(self):
46         return combine_labels(
47             self.class_label, *[s.label for s in self.element_strategies]
48         )
49 
50     def __repr__(self):
51         if len(self.element_strategies) == 1:
52             tuple_string = "%s," % (repr(self.element_strategies[0]),)
53         else:
54             tuple_string = ", ".join(map(repr, self.element_strategies))
55         return "TupleStrategy((%s))" % (tuple_string,)
56 
57     def calc_has_reusable_values(self, recur):
58         return all(recur(e) for e in self.element_strategies)
59 
60     def do_draw(self, data):
61         return tuple(data.draw(e) for e in self.element_strategies)
62 
63     def calc_is_empty(self, recur):
64         return any(recur(e) for e in self.element_strategies)
65 
66 
67 class ListStrategy(SearchStrategy):
68     """A strategy for lists which takes a strategy for its elements and the
69     allowed lengths, and generates lists with the correct size and contents."""
70 
71     def __init__(self, elements, min_size=0, max_size=float("inf")):
72         SearchStrategy.__init__(self)
73         self.min_size = min_size or 0
74         self.max_size = max_size if max_size is not None else float("inf")
75         assert 0 <= self.min_size <= self.max_size
76         self.average_size = min(
77             max(self.min_size * 2, self.min_size + 5),
78             0.5 * (self.min_size + self.max_size),
79         )
80         self.element_strategy = elements
81 
82     def calc_label(self):
83         return combine_labels(self.class_label, self.element_strategy.label)
84 
85     def do_validate(self):
86         self.element_strategy.validate()
87         if self.is_empty:
88             raise InvalidArgument(
89                 (
90                     "Cannot create non-empty lists with elements drawn from "
91                     "strategy %r because it has no values."
92                 )
93                 % (self.element_strategy,)
94             )
95         if self.element_strategy.is_empty and 0 < self.max_size < float("inf"):
96             raise InvalidArgument(
97                 "Cannot create a collection of max_size=%r, because no "
98                 "elements can be drawn from the element strategy %r"
99                 % (self.max_size, self.element_strategy)
100             )
101 
102     def calc_is_empty(self, recur):
103         if self.min_size == 0:
104             return False
105         else:
106             return recur(self.element_strategy)
107 
108     def do_draw(self, data):
109         if self.element_strategy.is_empty:
110             assert self.min_size == 0
111             return []
112 
113         elements = cu.many(
114             data,
115             min_size=self.min_size,
116             max_size=self.max_size,
117             average_size=self.average_size,
118         )
119         result = []
120         while elements.more():
121             result.append(data.draw(self.element_strategy))
122         return result
123 
124     def __repr__(self):
125         return "%s(%r, min_size=%r, max_size=%r)" % (
126             self.__class__.__name__,
127             self.element_strategy,
128             self.min_size,
129             self.max_size,
130         )
131 
132 
133 class UniqueListStrategy(ListStrategy):
134     def __init__(self, elements, min_size, max_size, keys):
135         super(UniqueListStrategy, self).__init__(elements, min_size, max_size)
136         self.keys = keys
137 
138     def do_draw(self, data):
139         if self.element_strategy.is_empty:
140             assert self.min_size == 0
141             return []
142 
143         elements = cu.many(
144             data,
145             min_size=self.min_size,
146             max_size=self.max_size,
147             average_size=self.average_size,
148         )
149         seen_sets = tuple(set() for _ in self.keys)
150         result = []
151 
152         # We construct a filtered strategy here rather than using a check-and-reject
153         # approach because some strategies have special logic for generation under a
154         # filter, and FilteredStrategy can consolidate multiple filters.
155         filtered = self.element_strategy.filter(
156             lambda val: all(
157                 key(val) not in seen for (key, seen) in zip(self.keys, seen_sets)
158             )
159         )
160         while elements.more():
161             value = filtered.filtered_strategy.do_filtered_draw(
162                 data=data, filter_strategy=filtered
163             )
164             if value is filter_not_satisfied:
165                 elements.reject()
166             else:
167                 for key, seen in zip(self.keys, seen_sets):
168                     seen.add(key(value))
169                 result.append(value)
170         assert self.max_size >= len(result) >= self.min_size
171         return result
172 
173 
174 class UniqueSampledListStrategy(ListStrategy):
175     def __init__(self, elements, min_size, max_size, keys):
176         super(UniqueSampledListStrategy, self).__init__(elements, min_size, max_size)
177         self.keys = keys
178 
179     def do_draw(self, data):
180         should_draw = cu.many(
181             data,
182             min_size=self.min_size,
183             max_size=self.max_size,
184             average_size=self.average_size,
185         )
186         seen_sets = tuple(set() for _ in self.keys)
187         result = []
188 
189         remaining = LazySequenceCopy(self.element_strategy.elements)
190 
191         while should_draw.more():
192             i = len(remaining) - 1
193             j = cu.integer_range(data, 0, i)
194             if j != i:
195                 remaining[i], remaining[j] = remaining[j], remaining[i]
196             value = remaining.pop()
197 
198             if all(key(value) not in seen for (key, seen) in zip(self.keys, seen_sets)):
199                 for key, seen in zip(self.keys, seen_sets):
200                     seen.add(key(value))
201                 result.append(value)
202             else:
203                 should_draw.reject()
204         assert self.max_size >= len(result) >= self.min_size
205         return result
206 
207 
208 class FixedKeysDictStrategy(MappedSearchStrategy):
209     """A strategy which produces dicts with a fixed set of keys, given a
210     strategy for each of their equivalent values.
211 
212     e.g. {'foo' : some_int_strategy} would generate dicts with the single
213     key 'foo' mapping to some integer.
214     """
215 
216     def __init__(self, strategy_dict):
217         self.dict_type = type(strategy_dict)
218 
219         if isinstance(strategy_dict, OrderedDict):
220             self.keys = tuple(strategy_dict.keys())
221         else:
222             try:
223                 self.keys = tuple(sorted(strategy_dict.keys()))
224             except TypeError:
225                 self.keys = tuple(sorted(strategy_dict.keys(), key=repr))
226         super(FixedKeysDictStrategy, self).__init__(
227             strategy=TupleStrategy(strategy_dict[k] for k in self.keys)
228         )
229 
230     def calc_is_empty(self, recur):
231         return recur(self.mapped_strategy)
232 
233     def __repr__(self):
234         return "FixedKeysDictStrategy(%r, %r)" % (self.keys, self.mapped_strategy)
235 
236     def pack(self, value):
237         return self.dict_type(zip(self.keys, value))
238 
239 
240 class FixedAndOptionalKeysDictStrategy(SearchStrategy):
241     """A strategy which produces dicts with a fixed set of keys, given a
242     strategy for each of their equivalent values.
243 
244     e.g. {'foo' : some_int_strategy} would generate dicts with the single
245     key 'foo' mapping to some integer.
246     """
247 
248     def __init__(self, strategy_dict, optional):
249         self.required = strategy_dict
250         self.fixed = FixedKeysDictStrategy(strategy_dict)
251         self.optional = optional
252 
253         if isinstance(self.optional, OrderedDict):
254             self.optional_keys = tuple(self.optional.keys())
255         else:
256             try:
257                 self.optional_keys = tuple(sorted(self.optional.keys()))
258             except TypeError:
259                 self.optional_keys = tuple(sorted(self.optional.keys(), key=repr))
260 
261     def calc_is_empty(self, recur):
262         return recur(self.fixed)
263 
264     def __repr__(self):
265         return "FixedAndOptionalKeysDictStrategy(%r, %r)" % (
266             self.required,
267             self.optional,
268         )
269 
270     def do_draw(self, data):
271         result = data.draw(self.fixed)
272         remaining = [k for k in self.optional_keys if not self.optional[k].is_empty]
273         should_draw = cu.many(
274             data, min_size=0, max_size=len(remaining), average_size=len(remaining) / 2
275         )
276         while should_draw.more():
277             j = cu.integer_range(data, 0, len(remaining) - 1)
278             remaining[-1], remaining[j] = remaining[j], remaining[-1]
279             key = remaining.pop()
280             result[key] = data.draw(self.optional[key])
281         return result
282
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/hypothesis-python/src/hypothesis/searchstrategy/collections.py b/hypothesis-python/src/hypothesis/searchstrategy/collections.py
--- a/hypothesis-python/src/hypothesis/searchstrategy/collections.py
+++ b/hypothesis-python/src/hypothesis/searchstrategy/collections.py
@@ -188,7 +188,7 @@
 
         remaining = LazySequenceCopy(self.element_strategy.elements)
 
-        while should_draw.more():
+        while remaining and should_draw.more():
             i = len(remaining) - 1
             j = cu.integer_range(data, 0, i)
             if j != i:

{"golden_diff": "diff --git a/hypothesis-python/src/hypothesis/searchstrategy/collections.py b/hypothesis-python/src/hypothesis/searchstrategy/collections.py\n--- a/hypothesis-python/src/hypothesis/searchstrategy/collections.py\n+++ b/hypothesis-python/src/hypothesis/searchstrategy/collections.py\n@@ -188,7 +188,7 @@\n \n         remaining = LazySequenceCopy(self.element_strategy.elements)\n \n-        while should_draw.more():\n+        while remaining and should_draw.more():\n             i = len(remaining) - 1\n             j = cu.integer_range(data, 0, i)\n             if j != i:\n", "issue": "Internal error for unique lists\n```python\r\nfrom hypothesis import given, strategies as st\r\n\r\n@given(st.lists(st.sampled_from([0, 0.0]), unique=True, min_size=1))\r\ndef t(x): pass\r\n\r\nt()\r\n```\r\n\r\ntriggers an assertion via `conjecture.utils.integer_range(data, lower=0, upper=-1)`\n", "before_files": [{"content": "# coding=utf-8\n#\n# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Most of this work is copyright (C) 2013-2019 David R. MacIver\n# (david@drmaciver.com), but it contains contributions by others. See\n# CONTRIBUTING.rst for a full list of people who may hold copyright, and\n# consult the git log if you need to determine who owns an individual\n# contribution.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n#\n# END HEADER\n\nfrom __future__ import absolute_import, division, print_function\n\nfrom collections import OrderedDict\n\nimport hypothesis.internal.conjecture.utils as cu\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture.junkdrawer import LazySequenceCopy\nfrom hypothesis.internal.conjecture.utils import combine_labels\nfrom hypothesis.searchstrategy.strategies import (\n    MappedSearchStrategy,\n    SearchStrategy,\n    filter_not_satisfied,\n)\n\n\nclass TupleStrategy(SearchStrategy):\n    \"\"\"A strategy responsible for fixed length tuples based on heterogenous\n    strategies for each of their elements.\"\"\"\n\n    def __init__(self, strategies):\n        SearchStrategy.__init__(self)\n        self.element_strategies = tuple(strategies)\n\n    def do_validate(self):\n        for s in self.element_strategies:\n            s.validate()\n\n    def calc_label(self):\n        return combine_labels(\n            self.class_label, *[s.label for s in self.element_strategies]\n        )\n\n    def __repr__(self):\n        if len(self.element_strategies) == 1:\n            tuple_string = \"%s,\" % (repr(self.element_strategies[0]),)\n        else:\n            tuple_string = \", \".join(map(repr, self.element_strategies))\n        return \"TupleStrategy((%s))\" % (tuple_string,)\n\n    def calc_has_reusable_values(self, recur):\n        return all(recur(e) for e in self.element_strategies)\n\n    def do_draw(self, data):\n        return tuple(data.draw(e) for e in self.element_strategies)\n\n    def calc_is_empty(self, recur):\n        return any(recur(e) for e in self.element_strategies)\n\n\nclass ListStrategy(SearchStrategy):\n    \"\"\"A strategy for lists which takes a strategy for its elements and the\n    allowed lengths, and generates lists with the correct size and contents.\"\"\"\n\n    def __init__(self, elements, min_size=0, max_size=float(\"inf\")):\n        SearchStrategy.__init__(self)\n        self.min_size = min_size or 0\n        self.max_size = max_size if max_size is not None else float(\"inf\")\n        assert 0 <= self.min_size <= self.max_size\n        self.average_size = min(\n            max(self.min_size * 2, self.min_size + 5),\n            0.5 * (self.min_size + self.max_size),\n        )\n        self.element_strategy = elements\n\n    def calc_label(self):\n        return combine_labels(self.class_label, self.element_strategy.label)\n\n    def do_validate(self):\n        self.element_strategy.validate()\n        if self.is_empty:\n            raise InvalidArgument(\n                (\n                    \"Cannot create non-empty lists with elements drawn from \"\n                    \"strategy %r because it has no values.\"\n                )\n                % (self.element_strategy,)\n            )\n        if self.element_strategy.is_empty and 0 < self.max_size < float(\"inf\"):\n            raise InvalidArgument(\n                \"Cannot create a collection of max_size=%r, because no \"\n                \"elements can be drawn from the element strategy %r\"\n                % (self.max_size, self.element_strategy)\n            )\n\n    def calc_is_empty(self, recur):\n        if self.min_size == 0:\n            return False\n        else:\n            return recur(self.element_strategy)\n\n    def do_draw(self, data):\n        if self.element_strategy.is_empty:\n            assert self.min_size == 0\n            return []\n\n        elements = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        result = []\n        while elements.more():\n            result.append(data.draw(self.element_strategy))\n        return result\n\n    def __repr__(self):\n        return \"%s(%r, min_size=%r, max_size=%r)\" % (\n            self.__class__.__name__,\n            self.element_strategy,\n            self.min_size,\n            self.max_size,\n        )\n\n\nclass UniqueListStrategy(ListStrategy):\n    def __init__(self, elements, min_size, max_size, keys):\n        super(UniqueListStrategy, self).__init__(elements, min_size, max_size)\n        self.keys = keys\n\n    def do_draw(self, data):\n        if self.element_strategy.is_empty:\n            assert self.min_size == 0\n            return []\n\n        elements = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        seen_sets = tuple(set() for _ in self.keys)\n        result = []\n\n        # We construct a filtered strategy here rather than using a check-and-reject\n        # approach because some strategies have special logic for generation under a\n        # filter, and FilteredStrategy can consolidate multiple filters.\n        filtered = self.element_strategy.filter(\n            lambda val: all(\n                key(val) not in seen for (key, seen) in zip(self.keys, seen_sets)\n            )\n        )\n        while elements.more():\n            value = filtered.filtered_strategy.do_filtered_draw(\n                data=data, filter_strategy=filtered\n            )\n            if value is filter_not_satisfied:\n                elements.reject()\n            else:\n                for key, seen in zip(self.keys, seen_sets):\n                    seen.add(key(value))\n                result.append(value)\n        assert self.max_size >= len(result) >= self.min_size\n        return result\n\n\nclass UniqueSampledListStrategy(ListStrategy):\n    def __init__(self, elements, min_size, max_size, keys):\n        super(UniqueSampledListStrategy, self).__init__(elements, min_size, max_size)\n        self.keys = keys\n\n    def do_draw(self, data):\n        should_draw = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        seen_sets = tuple(set() for _ in self.keys)\n        result = []\n\n        remaining = LazySequenceCopy(self.element_strategy.elements)\n\n        while should_draw.more():\n            i = len(remaining) - 1\n            j = cu.integer_range(data, 0, i)\n            if j != i:\n                remaining[i], remaining[j] = remaining[j], remaining[i]\n            value = remaining.pop()\n\n            if all(key(value) not in seen for (key, seen) in zip(self.keys, seen_sets)):\n                for key, seen in zip(self.keys, seen_sets):\n                    seen.add(key(value))\n                result.append(value)\n            else:\n                should_draw.reject()\n        assert self.max_size >= len(result) >= self.min_size\n        return result\n\n\nclass FixedKeysDictStrategy(MappedSearchStrategy):\n    \"\"\"A strategy which produces dicts with a fixed set of keys, given a\n    strategy for each of their equivalent values.\n\n    e.g. {'foo' : some_int_strategy} would generate dicts with the single\n    key 'foo' mapping to some integer.\n    \"\"\"\n\n    def __init__(self, strategy_dict):\n        self.dict_type = type(strategy_dict)\n\n        if isinstance(strategy_dict, OrderedDict):\n            self.keys = tuple(strategy_dict.keys())\n        else:\n            try:\n                self.keys = tuple(sorted(strategy_dict.keys()))\n            except TypeError:\n                self.keys = tuple(sorted(strategy_dict.keys(), key=repr))\n        super(FixedKeysDictStrategy, self).__init__(\n            strategy=TupleStrategy(strategy_dict[k] for k in self.keys)\n        )\n\n    def calc_is_empty(self, recur):\n        return recur(self.mapped_strategy)\n\n    def __repr__(self):\n        return \"FixedKeysDictStrategy(%r, %r)\" % (self.keys, self.mapped_strategy)\n\n    def pack(self, value):\n        return self.dict_type(zip(self.keys, value))\n\n\nclass FixedAndOptionalKeysDictStrategy(SearchStrategy):\n    \"\"\"A strategy which produces dicts with a fixed set of keys, given a\n    strategy for each of their equivalent values.\n\n    e.g. {'foo' : some_int_strategy} would generate dicts with the single\n    key 'foo' mapping to some integer.\n    \"\"\"\n\n    def __init__(self, strategy_dict, optional):\n        self.required = strategy_dict\n        self.fixed = FixedKeysDictStrategy(strategy_dict)\n        self.optional = optional\n\n        if isinstance(self.optional, OrderedDict):\n            self.optional_keys = tuple(self.optional.keys())\n        else:\n            try:\n                self.optional_keys = tuple(sorted(self.optional.keys()))\n            except TypeError:\n                self.optional_keys = tuple(sorted(self.optional.keys(), key=repr))\n\n    def calc_is_empty(self, recur):\n        return recur(self.fixed)\n\n    def __repr__(self):\n        return \"FixedAndOptionalKeysDictStrategy(%r, %r)\" % (\n            self.required,\n            self.optional,\n        )\n\n    def do_draw(self, data):\n        result = data.draw(self.fixed)\n        remaining = [k for k in self.optional_keys if not self.optional[k].is_empty]\n        should_draw = cu.many(\n            data, min_size=0, max_size=len(remaining), average_size=len(remaining) / 2\n        )\n        while should_draw.more():\n            j = cu.integer_range(data, 0, len(remaining) - 1)\n            remaining[-1], remaining[j] = remaining[j], remaining[-1]\n            key = remaining.pop()\n            result[key] = data.draw(self.optional[key])\n        return result\n", "path": "hypothesis-python/src/hypothesis/searchstrategy/collections.py"}], "after_files": [{"content": "# coding=utf-8\n#\n# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Most of this work is copyright (C) 2013-2019 David R. MacIver\n# (david@drmaciver.com), but it contains contributions by others. See\n# CONTRIBUTING.rst for a full list of people who may hold copyright, and\n# consult the git log if you need to determine who owns an individual\n# contribution.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n#\n# END HEADER\n\nfrom __future__ import absolute_import, division, print_function\n\nfrom collections import OrderedDict\n\nimport hypothesis.internal.conjecture.utils as cu\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture.junkdrawer import LazySequenceCopy\nfrom hypothesis.internal.conjecture.utils import combine_labels\nfrom hypothesis.searchstrategy.strategies import (\n    MappedSearchStrategy,\n    SearchStrategy,\n    filter_not_satisfied,\n)\n\n\nclass TupleStrategy(SearchStrategy):\n    \"\"\"A strategy responsible for fixed length tuples based on heterogenous\n    strategies for each of their elements.\"\"\"\n\n    def __init__(self, strategies):\n        SearchStrategy.__init__(self)\n        self.element_strategies = tuple(strategies)\n\n    def do_validate(self):\n        for s in self.element_strategies:\n            s.validate()\n\n    def calc_label(self):\n        return combine_labels(\n            self.class_label, *[s.label for s in self.element_strategies]\n        )\n\n    def __repr__(self):\n        if len(self.element_strategies) == 1:\n            tuple_string = \"%s,\" % (repr(self.element_strategies[0]),)\n        else:\n            tuple_string = \", \".join(map(repr, self.element_strategies))\n        return \"TupleStrategy((%s))\" % (tuple_string,)\n\n    def calc_has_reusable_values(self, recur):\n        return all(recur(e) for e in self.element_strategies)\n\n    def do_draw(self, data):\n        return tuple(data.draw(e) for e in self.element_strategies)\n\n    def calc_is_empty(self, recur):\n        return any(recur(e) for e in self.element_strategies)\n\n\nclass ListStrategy(SearchStrategy):\n    \"\"\"A strategy for lists which takes a strategy for its elements and the\n    allowed lengths, and generates lists with the correct size and contents.\"\"\"\n\n    def __init__(self, elements, min_size=0, max_size=float(\"inf\")):\n        SearchStrategy.__init__(self)\n        self.min_size = min_size or 0\n        self.max_size = max_size if max_size is not None else float(\"inf\")\n        assert 0 <= self.min_size <= self.max_size\n        self.average_size = min(\n            max(self.min_size * 2, self.min_size + 5),\n            0.5 * (self.min_size + self.max_size),\n        )\n        self.element_strategy = elements\n\n    def calc_label(self):\n        return combine_labels(self.class_label, self.element_strategy.label)\n\n    def do_validate(self):\n        self.element_strategy.validate()\n        if self.is_empty:\n            raise InvalidArgument(\n                (\n                    \"Cannot create non-empty lists with elements drawn from \"\n                    \"strategy %r because it has no values.\"\n                )\n                % (self.element_strategy,)\n            )\n        if self.element_strategy.is_empty and 0 < self.max_size < float(\"inf\"):\n            raise InvalidArgument(\n                \"Cannot create a collection of max_size=%r, because no \"\n                \"elements can be drawn from the element strategy %r\"\n                % (self.max_size, self.element_strategy)\n            )\n\n    def calc_is_empty(self, recur):\n        if self.min_size == 0:\n            return False\n        else:\n            return recur(self.element_strategy)\n\n    def do_draw(self, data):\n        if self.element_strategy.is_empty:\n            assert self.min_size == 0\n            return []\n\n        elements = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        result = []\n        while elements.more():\n            result.append(data.draw(self.element_strategy))\n        return result\n\n    def __repr__(self):\n        return \"%s(%r, min_size=%r, max_size=%r)\" % (\n            self.__class__.__name__,\n            self.element_strategy,\n            self.min_size,\n            self.max_size,\n        )\n\n\nclass UniqueListStrategy(ListStrategy):\n    def __init__(self, elements, min_size, max_size, keys):\n        super(UniqueListStrategy, self).__init__(elements, min_size, max_size)\n        self.keys = keys\n\n    def do_draw(self, data):\n        if self.element_strategy.is_empty:\n            assert self.min_size == 0\n            return []\n\n        elements = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        seen_sets = tuple(set() for _ in self.keys)\n        result = []\n\n        # We construct a filtered strategy here rather than using a check-and-reject\n        # approach because some strategies have special logic for generation under a\n        # filter, and FilteredStrategy can consolidate multiple filters.\n        filtered = self.element_strategy.filter(\n            lambda val: all(\n                key(val) not in seen for (key, seen) in zip(self.keys, seen_sets)\n            )\n        )\n        while elements.more():\n            value = filtered.filtered_strategy.do_filtered_draw(\n                data=data, filter_strategy=filtered\n            )\n            if value is filter_not_satisfied:\n                elements.reject()\n            else:\n                for key, seen in zip(self.keys, seen_sets):\n                    seen.add(key(value))\n                result.append(value)\n        assert self.max_size >= len(result) >= self.min_size\n        return result\n\n\nclass UniqueSampledListStrategy(ListStrategy):\n    def __init__(self, elements, min_size, max_size, keys):\n        super(UniqueSampledListStrategy, self).__init__(elements, min_size, max_size)\n        self.keys = keys\n\n    def do_draw(self, data):\n        should_draw = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        seen_sets = tuple(set() for _ in self.keys)\n        result = []\n\n        remaining = LazySequenceCopy(self.element_strategy.elements)\n\n        while remaining and should_draw.more():\n            i = len(remaining) - 1\n            j = cu.integer_range(data, 0, i)\n            if j != i:\n                remaining[i], remaining[j] = remaining[j], remaining[i]\n            value = remaining.pop()\n\n            if all(key(value) not in seen for (key, seen) in zip(self.keys, seen_sets)):\n                for key, seen in zip(self.keys, seen_sets):\n                    seen.add(key(value))\n                result.append(value)\n            else:\n                should_draw.reject()\n        assert self.max_size >= len(result) >= self.min_size\n        return result\n\n\nclass FixedKeysDictStrategy(MappedSearchStrategy):\n    \"\"\"A strategy which produces dicts with a fixed set of keys, given a\n    strategy for each of their equivalent values.\n\n    e.g. {'foo' : some_int_strategy} would generate dicts with the single\n    key 'foo' mapping to some integer.\n    \"\"\"\n\n    def __init__(self, strategy_dict):\n        self.dict_type = type(strategy_dict)\n\n        if isinstance(strategy_dict, OrderedDict):\n            self.keys = tuple(strategy_dict.keys())\n        else:\n            try:\n                self.keys = tuple(sorted(strategy_dict.keys()))\n            except TypeError:\n                self.keys = tuple(sorted(strategy_dict.keys(), key=repr))\n        super(FixedKeysDictStrategy, self).__init__(\n            strategy=TupleStrategy(strategy_dict[k] for k in self.keys)\n        )\n\n    def calc_is_empty(self, recur):\n        return recur(self.mapped_strategy)\n\n    def __repr__(self):\n        return \"FixedKeysDictStrategy(%r, %r)\" % (self.keys, self.mapped_strategy)\n\n    def pack(self, value):\n        return self.dict_type(zip(self.keys, value))\n\n\nclass FixedAndOptionalKeysDictStrategy(SearchStrategy):\n    \"\"\"A strategy which produces dicts with a fixed set of keys, given a\n    strategy for each of their equivalent values.\n\n    e.g. {'foo' : some_int_strategy} would generate dicts with the single\n    key 'foo' mapping to some integer.\n    \"\"\"\n\n    def __init__(self, strategy_dict, optional):\n        self.required = strategy_dict\n        self.fixed = FixedKeysDictStrategy(strategy_dict)\n        self.optional = optional\n\n        if isinstance(self.optional, OrderedDict):\n            self.optional_keys = tuple(self.optional.keys())\n        else:\n            try:\n                self.optional_keys = tuple(sorted(self.optional.keys()))\n            except TypeError:\n                self.optional_keys = tuple(sorted(self.optional.keys(), key=repr))\n\n    def calc_is_empty(self, recur):\n        return recur(self.fixed)\n\n    def __repr__(self):\n        return \"FixedAndOptionalKeysDictStrategy(%r, %r)\" % (\n            self.required,\n            self.optional,\n        )\n\n    def do_draw(self, data):\n        result = data.draw(self.fixed)\n        remaining = [k for k in self.optional_keys if not self.optional[k].is_empty]\n        should_draw = cu.many(\n            data, min_size=0, max_size=len(remaining), average_size=len(remaining) / 2\n        )\n        while should_draw.more():\n            j = cu.integer_range(data, 0, len(remaining) - 1)\n            remaining[-1], remaining[j] = remaining[j], remaining[-1]\n            key = remaining.pop()\n            result[key] = data.draw(self.optional[key])\n        return result\n", "path": "hypothesis-python/src/hypothesis/searchstrategy/collections.py"}]}