diff --git a/hypothesis-python/RELEASE.rst b/hypothesis-python/RELEASE.rst new file mode 100644 index 0000000000..4a4b6531b9 --- /dev/null +++ b/hypothesis-python/RELEASE.rst @@ -0,0 +1,3 @@ +RELEASE_TYPE: patch + +This patch does some minor internal cleanup; there is no user-visible change. diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/collections.py b/hypothesis-python/src/hypothesis/strategies/_internal/collections.py index 9b6bc16008..b1c613a394 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/collections.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/collections.py @@ -167,11 +167,7 @@ def do_draw(self, data): return result -class UniqueSampledListStrategy(ListStrategy): - def __init__(self, elements, min_size, max_size, keys): - super().__init__(elements, min_size, max_size) - self.keys = keys - +class UniqueSampledListStrategy(UniqueListStrategy): def do_draw(self, data): should_draw = cu.many( data, diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/core.py b/hypothesis-python/src/hypothesis/strategies/_internal/core.py index a70772b18e..20daebd74d 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/core.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/core.py @@ -1799,9 +1799,8 @@ def timedeltas( class CompositeStrategy(SearchStrategy): - def __init__(self, definition, label, args, kwargs): + def __init__(self, definition, args, kwargs): self.definition = definition - self.__label = label self.args = args self.kwargs = kwargs @@ -1809,7 +1808,7 @@ def do_draw(self, data): return self.definition(data.draw, *self.args, **self.kwargs) def calc_label(self): - return self.__label + return calc_label_from_cls(self.definition) @cacheable @@ -1841,12 +1840,10 @@ def composite(f: Callable[..., Ex]) -> Callable[..., SearchStrategy[Ex]]: } new_argspec = argspec._replace(args=argspec.args[1:], annotations=annots) - label = calc_label_from_cls(f) - @defines_strategy @define_function_signature(f.__name__, f.__doc__, new_argspec) def accept(*args, **kwargs): - return CompositeStrategy(f, label, args, kwargs) + return CompositeStrategy(f, args, kwargs) accept.__module__ = f.__module__ return accept diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py b/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py index 2c1811d372..4cb1e64981 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py @@ -547,21 +547,31 @@ def calc_is_cacheable(self, recur): @property def element_strategies(self): if self.__element_strategies is None: + # While strategies are hashable, they use object.__hash__ and are + # therefore distinguished only by identity. + # + # In principle we could "just" define a __hash__ method + # (and __eq__, but that's easy in terms of type() and hash()) + # to make this more powerful, but this is harder than it sounds: + # + # 1. Strategies are often distinguished by non-hashable attributes, + # or by attributes that have the same hash value ("^.+" / b"^.+"). + # 2. LazyStrategy: can't reify the wrapped strategy without breaking + # laziness, so there's a hash each for the lazy and the nonlazy. + # + # Having made several attempts, the minor benefits of making strategies + # hashable are simply not worth the engineering effort it would take. + # See also issues #2291 and #2327. + seen = {self} strategies = [] for arg in self.original_strategies: check_strategy(arg) if not arg.is_empty: - strategies.extend([s for s in arg.branches if not s.is_empty]) - pruned = [] - seen = set() - for s in strategies: - if s is self: - continue - if s in seen: - continue - seen.add(s) - pruned.append(s) - self.__element_strategies = pruned + for s in arg.branches: + if s not in seen and not s.is_empty: + seen.add(s) + strategies.append(s) + self.__element_strategies = strategies return self.__element_strategies def calc_label(self): diff --git a/requirements/coverage.txt b/requirements/coverage.txt index a1a48741bd..bc7b20b596 100644 --- a/requirements/coverage.txt +++ b/requirements/coverage.txt @@ -4,10 +4,10 @@ # # pip-compile --output-file=requirements/coverage.txt requirements/coverage.in # -coverage==5.0.2 +coverage==5.0.3 lark-parser==0.7.8 numpy==1.18.1 pandas==0.25.3 python-dateutil==2.8.1 # via pandas pytz==2019.3 -six==1.13.0 # via python-dateutil +six==1.14.0 # via python-dateutil diff --git a/requirements/test.in b/requirements/test.in index 08c3da8317..4af0ccbf8d 100644 --- a/requirements/test.in +++ b/requirements/test.in @@ -3,3 +3,4 @@ sortedcontainers pexpect pytest pytest-xdist +zipp < 2 # dropped support for 3.5; required via pytest via importlib-metadata diff --git a/requirements/test.txt b/requirements/test.txt index 40abb3f540..46a7f07a7f 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -8,10 +8,10 @@ apipkg==1.5 # via execnet atomicwrites==1.3.0 # via pytest attrs==19.3.0 execnet==1.7.1 # via pytest-xdist -importlib-metadata==1.3.0 # via pluggy, pytest -more-itertools==8.0.2 # via pytest, zipp +importlib-metadata==1.4.0 # via pluggy, pytest +more-itertools==8.1.0 # via pytest, zipp packaging==20.0 # via pytest -pexpect==4.7.0 +pexpect==4.8.0 pluggy==0.13.1 # via pytest ptyprocess==0.6.0 # via pexpect py==1.8.1 # via pytest @@ -19,7 +19,7 @@ pyparsing==2.4.6 # via packaging pytest-forked==1.1.3 # via pytest-xdist pytest-xdist==1.31.0 pytest==5.3.2 -six==1.13.0 # via packaging, pytest-xdist +six==1.14.0 # via packaging, pytest-xdist sortedcontainers==2.1.0 wcwidth==0.1.8 # via pytest -zipp==0.6.0 # via importlib-metadata +zipp==1.0.0 diff --git a/requirements/tools.txt b/requirements/tools.txt index b4eca404e7..de95154452 100644 --- a/requirements/tools.txt +++ b/requirements/tools.txt @@ -14,23 +14,23 @@ babel==2.8.0 # via sphinx backcall==0.1.0 # via ipython bandit==1.6.2 # via flake8-bandit black==19.10b0 -blacken-docs==1.4.0 +blacken-docs==1.5.0 bleach==3.1.0 # via readme-renderer certifi==2019.11.28 # via requests chardet==3.0.4 # via requests click==7.0 # via black, pip-tools, pyupio, safety -coverage==5.0.2 +coverage==5.0.3 decorator==4.4.1 # via ipython, traitlets deprecated==1.2.7 # via pygithub django==3.0.2 -docutils==0.15.2 # via readme-renderer, restructuredtext-lint, sphinx +docutils==0.16 # via readme-renderer, restructuredtext-lint, sphinx dparse==0.4.1 # via pyupio, safety dpcontracts==0.6.0 entrypoints==0.3 # via flake8 filelock==3.0.12 # via tox flake8-bandit==2.1.2 flake8-bugbear==20.1.2 -flake8-comprehensions==3.1.4 +flake8-comprehensions==3.2.2 flake8-docstrings==1.5.0 flake8-polyfill==1.0.2 # via flake8-bandit flake8==3.7.9 @@ -38,17 +38,17 @@ gitdb2==2.0.6 # via gitpython gitpython==3.0.5 # via bandit idna==2.8 # via requests imagesize==1.2.0 # via sphinx -importlib-metadata==1.3.0 # via flake8-comprehensions, keyring, pluggy, pytest, tox, twine +importlib-metadata==1.4.0 # via flake8-comprehensions, keyring, pluggy, pytest, tox, twine ipython-genutils==0.2.0 # via traitlets ipython==7.11.1 isort==4.3.21 jedi==0.15.2 # via ipython jinja2==2.10.3 # via pyupio, sphinx -keyring==21.0.0 # via twine +keyring==21.1.0 # via twine lark-parser==0.7.8 markupsafe==1.1.1 # via jinja2 mccabe==0.6.1 # via flake8 -more-itertools==8.0.2 # via pytest, zipp +more-itertools==8.1.0 # via pytest, zipp mypy-extensions==0.4.3 # via mypy mypy==0.761 numpy==1.18.1 @@ -57,13 +57,13 @@ parso==0.5.2 # via jedi pathspec==0.7.0 # via black pbr==5.4.4 # via stevedore pickleshare==0.7.5 # via ipython -pip-tools==4.3.0 +pip-tools==4.4.0 pkginfo==1.5.0.1 # via twine pluggy==0.13.1 # via pytest, tox prompt-toolkit==3.0.2 # via ipython py==1.8.1 # via pytest, tox pycodestyle==2.5.0 # via flake8, flake8-bandit -pydocstyle==5.0.1 # via flake8-docstrings +pydocstyle==5.0.2 # via flake8-docstrings pyflakes==2.1.1 # via autoflake, flake8 pygithub==1.45 # via pyupio pygments==2.5.2 # via ipython, readme-renderer, sphinx @@ -73,17 +73,17 @@ pytest==5.3.2 python-dateutil==2.8.1 python-gitlab==1.15.0 # via pyupio pytz==2019.3 # via babel, django -pyupgrade==1.25.2 +pyupgrade==1.26.1 pyupio==1.0.2 pywin32-ctypes==0.2.0 # via keyring pyyaml==5.3 # via bandit, dparse, pyupio readme-renderer==24.0 # via twine -regex==2019.12.20 # via black +regex==2020.1.8 # via black requests-toolbelt==0.9.1 # via twine requests==2.22.0 restructuredtext-lint==1.3.0 safety==1.8.5 # via pyupio -six==1.13.0 # via bandit, bleach, dparse, packaging, pip-tools, pygithub, python-dateutil, python-gitlab, pyupio, readme-renderer, stevedore, tox, traitlets +six==1.14.0 # via bandit, bleach, dparse, packaging, pip-tools, pygithub, python-dateutil, python-gitlab, pyupio, readme-renderer, stevedore, tox, traitlets smmap2==2.0.5 # via gitdb2 snowballstemmer==2.0.0 # via pydocstyle, sphinx sortedcontainers==2.1.0 @@ -103,14 +103,14 @@ tox==3.14.3 tqdm==4.41.1 # via pyupio, twine traitlets==4.3.3 # via ipython twine==3.1.1 -typed-ast==1.4.0 # via black, mypy +typed-ast==1.4.1 # via black, mypy typing-extensions==3.7.4.1 # via mypy -urllib3==1.25.7 # via requests +urllib3==1.25.8 # via requests virtualenv==16.7.9 # via tox wcwidth==0.1.8 # via prompt-toolkit, pytest webencodings==0.5.1 # via bleach wrapt==1.11.2 # via deprecated -zipp==0.6.0 # via importlib-metadata +zipp==2.0.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: -# setuptools==44.0.0 # via ipython, safety, sphinx, twine +# setuptools