[Python-modules-commits] [python-hypothesis] 10/12: Import python-hypothesis_2.0.0.orig.tar.gz

Tristan Seligmann mithrandi at moszumanska.debian.org
Sat Jan 23 02:52:25 UTC 2016


This is an automated email from the git hooks/post-receive script.

mithrandi pushed a commit to branch master
in repository python-hypothesis.

commit eb7b1f82e4146b3477e35b9791b21bcfdffa2067
Author: Tristan Seligmann <mithrandi at debian.org>
Date:   Sat Jan 23 04:34:38 2016 +0200

    Import python-hypothesis_2.0.0.orig.tar.gz
---
 .coveragerc                                        |   2 +-
 .travis.yml                                        |   7 +-
 Makefile                                           |  15 +-
 README.rst                                         |  11 +-
 docs/changes.rst                                   |  99 ++++
 docs/data.rst                                      |  17 -
 docs/details.rst                                   |  51 +-
 docs/settings.rst                                  |  24 +-
 examples/__init__.py                               |  15 -
 examples/bintree.py                                | 619 ---------------------
 scripts/retry.sh                                   |  13 +
 tests/conftest.py => scripts/unicodechecker.py     |  46 +-
 src/hypothesis/__init__.py                         |  10 +-
 src/hypothesis/{settings.py => _settings.py}       | 298 +++++-----
 src/hypothesis/configuration.py                    |  52 ++
 src/hypothesis/control.py                          |   4 +-
 src/hypothesis/core.py                             | 424 +++++++-------
 src/hypothesis/errors.py                           |  17 +-
 src/hypothesis/executors/executors.py              |  10 +-
 src/hypothesis/extra/datetime.py                   |  23 -
 src/hypothesis/extra/django/fixtures.py            |   2 +-
 src/hypothesis/extra/pytestplugin.py               |   4 +-
 src/hypothesis/internal/charstree.py               |   2 +-
 src/hypothesis/internal/compat.py                  |  47 +-
 src/hypothesis/internal/debug.py                   |  12 +-
 src/hypothesis/{utils => internal}/extmethod.py    |   0
 src/hypothesis/internal/reflection.py              | 166 +++---
 src/hypothesis/internal/strategymethod.py          | 214 -------
 src/hypothesis/internal/tracker.py                 |   6 +-
 src/hypothesis/internal/typechecking.py            |  69 ---
 src/hypothesis/reporting.py                        |  10 +-
 src/hypothesis/searchstrategy/__init__.py          |   5 -
 src/hypothesis/searchstrategy/basic.py             | 311 -----------
 src/hypothesis/searchstrategy/collections.py       |  51 +-
 src/hypothesis/searchstrategy/deferred.py          |  25 +-
 src/hypothesis/searchstrategy/flatmapped.py        |   7 +-
 src/hypothesis/searchstrategy/misc.py              |   2 +-
 src/hypothesis/searchstrategy/narytree.py          | 166 ------
 src/hypothesis/searchstrategy/numbers.py           |  79 +--
 src/hypothesis/searchstrategy/recursive.py         |  16 +-
 src/hypothesis/searchstrategy/reprwrapper.py       |   3 +
 src/hypothesis/searchstrategy/strategies.py        |  71 +--
 src/hypothesis/searchstrategy/streams.py           |   5 +-
 src/hypothesis/searchstrategy/strings.py           |   8 +-
 src/hypothesis/specifiers.py                       |  90 ---
 src/hypothesis/stateful.py                         |  16 +-
 src/hypothesis/strategies.py                       | 266 +++++----
 src/hypothesis/strategytests.py                    |  94 ++--
 src/hypothesis/types.py                            |   3 +-
 src/hypothesis/utils/dynamicvariables.py           |   4 +-
 src/hypothesis/utils/idkey.py                      |  53 --
 src/hypothesis/utils/show.py                       | 190 -------
 src/hypothesis/version.py                          |   4 +-
 tests/common/__init__.py                           |  32 +-
 tests/common/basic.py                              |  48 --
 tests/conftest.py                                  |  23 +-
 tests/cover/test_bad_repr.py                       |  55 +-
 tests/cover/test_basic_strategy.py                 | 217 --------
 tests/cover/test_caching.py                        |  55 ++
 tests/cover/test_choices.py                        |   4 +-
 tests/cover/test_collective_minimization.py        |   9 +-
 tests/cover/test_converter.py                      |   3 -
 tests/cover/test_core.py                           |  19 +-
 tests/cover/test_database.py                       |  26 +-
 tests/cover/test_database_backend.py               |  10 +-
 tests/cover/test_deprecated_api.py                 | 299 ----------
 tests/cover/test_deprecation.py                    | 101 ----
 tests/cover/test_direct_strategies.py              |  33 +-
 tests/cover/test_draw_example.py                   |   5 +-
 tests/cover/test_eval_as_source.py                 |   6 +-
 tests/cover/test_exhaustion.py                     |   5 +-
 tests/cover/test_explicit_examples.py              |   5 +-
 tests/cover/test_extmethod.py                      |   2 +-
 tests/cover/test_filestorage.py                    |   2 +-
 tests/cover/test_find.py                           |  11 +-
 tests/cover/test_flakiness.py                      | 146 +++++
 tests/cover/test_flatmap.py                        |  39 +-
 tests/cover/test_float_nastiness.py                |  13 +-
 tests/cover/test_given_error_conditions.py         |   8 +-
 tests/cover/test_health_checks.py                  |  51 +-
 tests/cover/test_idkey.py                          |  42 --
 tests/cover/test_imports.py                        |   2 +-
 tests/cover/test_manual_given_invocation.py        |  80 ---
 tests/cover/test_minimal.py                        |   5 +-
 tests/cover/test_morpher.py                        |  11 +-
 tests/cover/test_nary_tree.py                      |  77 ---
 tests/cover/test_nice_string.py                    | 200 -------
 tests/cover/test_randomization.py                  |  19 +-
 tests/cover/test_recursive.py                      |  18 +-
 tests/cover/test_reflection.py                     | 244 ++++----
 tests/cover/test_reporting.py                      |  19 +-
 tests/cover/test_sampled_from.py                   |   5 +-
 tests/cover/test_searchstrategy.py                 |   3 +-
 tests/cover/test_sets.py                           |   7 +-
 tests/cover/test_settings.py                       | 116 ++--
 tests/cover/test_setup_teardown.py                 |  12 +-
 ...est_descriptors.py => test_shrinking_limits.py} |  20 +-
 tests/cover/test_simple_collections.py             |   7 +-
 tests/cover/test_simple_strings.py                 |   5 +-
 tests/cover/test_stateful.py                       |  23 +-
 tests/cover/test_streams.py                        |   3 +-
 tests/cover/test_testdecorators.py                 | 180 ++----
 tests/cover/test_timeout.py                        |   5 +-
 tests/cover/test_validation.py                     |  51 +-
 tests/cover/test_verbosity.py                      |  31 +-
 tests/cover/test_via_the_database.py               |  21 +-
 tests/cover/test_weird_settings.py                 |   5 +-
 tests/datetime/test_datetime.py                    |  24 +-
 tests/datetime/test_times.py                       |   4 +-
 tests/fakefactory/test_fake_factory.py             |   6 -
 tests/nocover/test_debug.py                        |   5 +-
 tests/nocover/test_descriptortests.py              | 359 ++++++------
 tests/nocover/test_example_quality.py              |  10 +-
 tests/nocover/test_floating.py                     |  55 +-
 tests/nocover/test_git_merge.py                    |   3 +
 tests/nocover/test_pretty_repr.py                  |   7 +-
 tests/nocover/test_strategy_state.py               |  31 +-
 tests/numpy/test_gen_data.py                       |   4 +-
 tests/pytest/test_capture.py                       |  10 +-
 tests/pytest/test_profiles.py                      |   8 +-
 tox.ini                                            |  11 +
 121 files changed, 2074 insertions(+), 4659 deletions(-)

diff --git a/.coveragerc b/.coveragerc
index 1d09c62..0c4a163 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -4,7 +4,7 @@ include =
     .tox/*/lib/*/site-packages/hypothesis/*.py
     .tox/*/lib/*/site-packages/hypothesis/**/*.py
 omit =
-    **/settings.py
+    **/_settings.py
     **/pytestplugin.py
     **/strategytests.py
     **/internal/debug.py
diff --git a/.travis.yml b/.travis.yml
index c8321cf..cae5ffe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,11 +25,10 @@ env:
         - TASK=lint
         - TASK=check-format
         - TASK=check-coverage
+        - TASK=check-unicode
         - TASK=check-pypy
-        - TASK=check-py26
         - TASK=check-py35
         - TASK=check-py27
-        - TASK=check-py33
         - TASK=check-py34
         - TASK=check-nose
         - TASK=check-pytest27
@@ -39,8 +38,6 @@ env:
         - TASK=check-pytest26
         - TASK=check-django17
         - TASK=check-django18
-        - TASK=check-examples2
-        - TASK=check-examples3
 
 script:
     - make $TASK
@@ -48,6 +45,8 @@ script:
 matrix:
     exclude:
         - os: osx
+          env: TASK=check-unicode
+        - os: osx
           env: TASK=check-fakefactory052
         - os: osx
           env: TASK=check-fakefactory053
diff --git a/Makefile b/Makefile
index 7ace141..18d32b5 100644
--- a/Makefile
+++ b/Makefile
@@ -34,22 +34,22 @@ export PATH:=$(BUILD_RUNTIMES)/snakepit:$(TOOLS):$(PATH)
 export LC_ALL=C.UTF-8
 
 $(PY26):
-	scripts/install.sh 2.6
+	scripts/retry.sh scripts/install.sh 2.6
 
 $(PY27):
-	scripts/install.sh 2.7
+	scripts/retry.sh scripts/install.sh 2.7
 
 $(PY33):
-	scripts/install.sh 3.3
+	scripts/retry.sh scripts/install.sh 3.3
 
 $(PY34):
-	scripts/install.sh 3.4
+	scripts/retry.sh scripts/install.sh 3.4
 
 $(PY35):
-	scripts/install.sh 3.5
+	scripts/retry.sh scripts/install.sh 3.5
 
 $(PYPY):
-	scripts/install.sh pypy
+	scripts/retry.sh scripts/install.sh pypy
 
 $(TOOL_VIRTUALENV): $(PY34)
 	$(PY34) -m virtualenv $(TOOL_VIRTUALENV)
@@ -131,6 +131,9 @@ check-examples3: $(TOX) $(PY35)
 check-coverage: $(TOX) $(PY35)
 	$(TOX) -e coverage
 
+check-unicode: $(TOX) $(PY27)
+	$(TOX) -e unicode
+
 check-noformat: check-coverage check-py26 check-py27 check-py33 check-py34 check-py35 check-pypy check-django check-pytest
 
 check: check-format check-noformat
diff --git a/README.rst b/README.rst
index 3853c8f..6ba75b2 100644
--- a/README.rst
+++ b/README.rst
@@ -11,10 +11,13 @@ Hypothesis is both extremely practical and also advances the state of the art of
 unit testing by some way. It's easy to use, stable, and extremely powerful. If
 you're not using Hypothesis to test your project then you're missing out.
 
-Hypothesis works with most widely used versions of Python. It supports implementations
-compatible with 2.6, 2.7 and 3.3+, and is known to work on CPython and PyPy (but not
-PyPy3 until they support a 3.3 compatible version of the language). It does *not* currently
-work on Jython or on Python 3.0 through 3.2.
+Hypothesis works with most widely used versions of Python. It officially supports
+CPython 2.7, 3.4 and 3.5, as well as PyPy. CPython 2.6 and 3.3 are supported on a
+"best effort" basis - they probably work, and bugs in them may be fixed, but they're
+not regularly tested and are likely to work less well.
+
+Jython, IronPython and PyPy3 are known not to work and there are currently no plans
+to support them.
 
 -----------------
 Links of interest
diff --git a/docs/changes.rst b/docs/changes.rst
index 91a3fd7..2f4c98e 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -21,6 +21,105 @@ Hypothesis APIs come in three flavours:
 You should generally assume that an API is internal unless you have specific
 information to the contrary.
 
+------------------
+2.0.0 - 2016-01-10
+------------------
+
+Codename: A new beginning
+
+This release cleans up all of the legacy that accrued in the course of
+Hypothesis 1.0. These are mostly things that were emitting deprecation warnings
+in 1.19.0, but there were a few additional changes.
+
+In particular:
+
+* non-strategy values will no longer be converted to strategies when used in
+  given or find.
+* FailedHealthCheck is now an error and not a warning.
+* Handling of non-ascii reprs in user types have been simplified by using raw
+  strings in more places in Python 2.
+* given no longer allows mixing positional and keyword arguments.
+* given no longer works with functions with defaults.
+* given no longer turns provided arguments into defaults - they will not appear
+  in the argspec at all.
+* the basic() strategy no longer exists.
+* the n_ary_tree strategy no longer exists.
+* the average_list_length setting no longer exists.
+* @rule can no longer be applied to the same method twice.
+
+This also includes two non-deprecation changes:
+
+* given's keyword arguments no longer have to be the rightmost arguments and
+  can appear anywhere in the method signature.
+* The max_shrinks setting would sometimes not have been respected.
+
+
+-------------------
+1.19.0 - 2016-01-09
+-------------------
+
+Codename: IT COMES
+
+This release heralds the beginning of a new and terrible age of Hypothesis 2.0.
+
+It's primary purpose is some final deprecations prior to said release. The goal
+is that if your code emits no warnings under this release then it will probably run
+unchanged under Hypothesis 2.0 (there are some caveats to this: 2.0 will drop
+support for some Python versions, and if you're using internal APIs then as usual
+that may break without warning).
+
+It does have two new features:
+
+* New @seed() decorator which allows you to manually seed a test. This may be
+  harmlessly combined with and overrides the derandomize setting.
+* settings objects may now be used as a decorator to fix those settings to a
+  particular @given test.
+
+API changes (old usage still works but is deprecated):
+
+* Settings has been renamed to settings (lower casing) in order to make the
+  decorator usage more natural.
+* Functions for the storage directory that were in hypothesis.settings are now
+  in a new hypothesis.configuration module.
+
+Additional deprecations:
+
+* the average_list_length setting has been deprecated in favour of being
+  explicit.
+* the basic() strategy has been deprecated as it is impossible to support
+  it under a Conjecture based model, which will hopefully be implemented at
+  some point in the 2.x series.
+* the n_ary_tree strategy (which was never actually part of the public API)
+  has been deprecated.
+* Passing settings or random as keyword arguments to given is deprecated (use
+  the new functionality instead)
+
+
+Bug fixes:
+
+* No longer emit PendingDeprecationWarning for __iter__ and StopIteration in
+  streaming() values.
+* When running in health check mode with non strict, don't print quite so
+  many errors for an exception in reify.
+* When an assumption made in a test or a filter is flaky, tests will now
+  raise Flaky instead of UnsatisfiedAssumption.
+
+
+-----------------------------------------------------------------------
+`1.18.1 <https://hypothesis.readthedocs.org/en/1.18.0/>`_ - 2015-12-22
+-----------------------------------------------------------------------
+
+Two behind the scenes changes:
+
+* Hypothesis will no longer write generated code to the file system. This
+  will improve performance on some systems (e.g. if you're using
+  `PythonAnywhere <https://www.pythonanywhere.com/>`_ which is running your
+  code from NFS) and prevent some annoying interactions with auto-restarting
+  systems.
+* Hypothesis will cache the creation of some strategies. This can significantly
+  improve performance for code that uses flatmap or composite and thus has to
+  instantiate strategies a lot.
+
 -----------------------------------------------------------------------
 `1.18.0 <https://hypothesis.readthedocs.org/en/1.18.0/>`_ - 2015-12-21
 -----------------------------------------------------------------------
diff --git a/docs/data.rst b/docs/data.rst
index d30879f..ca67e20 100644
--- a/docs/data.rst
+++ b/docs/data.rst
@@ -472,20 +472,3 @@ use BasicStrategy. These caveats should be read in the light of the fact that
 the full Hypothesis SearchStrategy interface is really very powerful, and the
 ones using BasicStrategy are merely a bit better than the normal quickcheck
 interface.
-
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Using the SearchStrategy API directly
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you're really super enthused about this search strategies thing and you want
-to learn all the gory details of how it works under the hood, you can use the
-full blown raw SearchStrategy interface to experience the full power of
-Hypothesis.
-
-This is only semi-public API, meaning that it may break between minor versions
-but will not break in patch versions, but it should be considered relatively
-stable and most minor versions won't break it.
-
-.. autoclass:: SearchStrategy
-  :members:
diff --git a/docs/details.rst b/docs/details.rst
index e84d74f..8315cbb 100644
--- a/docs/details.rst
+++ b/docs/details.rst
@@ -253,12 +253,16 @@ For example all of the following are valid uses:
   def c(x, y):
     pass
 
+  @given(x=integers())
+  def d(x, y):
+    pass
+
   @given(x=integers(), y=integers())
-  def d(x, **kwargs):
+  def e(x, **kwargs):
     pass
 
   @given(x=integers(), y=integers())
-  def e(x, *args, **kwargs):
+  def f(x, *args, **kwargs):
     pass
 
 
@@ -272,46 +276,37 @@ The following are not:
 .. code:: python
 
   @given(integers(), integers(), integers())
-  def f(x, y):
+  def g(x, y):
       pass
 
   @given(integers())
-  def g(x, *args):
+  def h(x, *args):
       pass
 
-  @given(x=integers())
-  def h(x, y):
+  @given(integers(), x=integers())
+  def i(x, y):
       pass
 
   @given()
-  def i(x, y):
+  def j(x, y):
       pass
 
 
 The rules for determining what are valid uses of given are as follows:
 
-1. Arguments passed as keyword arguments must cover the right hand side
-   of the argument list. That is, if you provide an argument as a keyword
-   you must also provide everything to the right of it.
-2. Positional arguments fill up from the right, starting from the first
-   argument not covered by a keyword argument. (Note: Mixing keyword and
-   positional arguments is supported but deprecated as its semantics are
-   highly confusing and difficult to support. You'll get a warning if you
-   do).
-3. If the function has variable keywords, additional arguments will be
-   added corresponding to any keyword arguments passed. These will be to
-   the right of the normal argument list in an arbitrary order.
-4. If the function has varargs, positional arguments to :func:`@given <hypothesis.core.given>` are not
-   supported. Keyword arguments may be passed, however.
-
-If you don't have kwargs then the function returned by :func:`@given <hypothesis.core.given>` will have
-the same argspec (i.e. same arguments, keyword arguments, etc) as the
-original but with different defaults.
-
-The reason for the "filling up from the right" behaviour is so that
-using :func:`@given <hypothesis.core.given>` with instance methods works: self will be passed to the
-function as normal and not be parametrized over.
+1. You may pass any keyword argument to given.
+2. Positional arguments to given are equivalent to the rightmost named
+   arguments for the test function.
+3. positional arguments may not be used if the underlying test function has
+   varargs or arbitrary keywords.
+4. Functions tested with given may not have any defaults.
+
+The reason for the "rightmost named arguments" behaviour is so that
+using :func:`@given <hypothesis.core.given>` with instance methods works: self
+will be passed to the function as normal and not be parametrized over.
 
+The function returned by given has all the arguments that the original test did
+, minus the ones that are being filled in by given.
 
 -------------------------
 Custom function execution
diff --git a/docs/settings.rst b/docs/settings.rst
index f94bd0e..0042a55 100644
--- a/docs/settings.rst
+++ b/docs/settings.rst
@@ -5,28 +5,44 @@ Settings
 Hypothesis tries to have good defaults for its behaviour, but sometimes that's
 not enough and you need to tweak it.
 
-The mechanism for doing this is the :class:`~hypothesis.Settings` object. You can pass this to a
+The mechanism for doing this is the :class:`~hypothesis.Settings` object.
+You can set up a @given based test to use this using a Settings decorator:
+
 :func:`@given <hypothesis.core.given>` invocation as follows:
 
 .. code:: python
 
     from hypothesis import given, Settings
 
-    @given(integers(), settings=Settings(max_examples=500))
+    @given(integers())
+    @Settings(max_examples=500)
     def test_this_thoroughly(x):
         pass
 
 This uses a :class:`~hypothesis.Settings` object which causes the test to receive a much larger
 set of examples than normal.
 
+This may be applied either before or after the given and the results are
+the same. The following is exactly equivalent:
+
+
+.. code:: python
+
+    from hypothesis import given, Settings
+
+    @Settings(max_examples=500)
+    @given(integers())
+    def test_this_thoroughly(x):
+        pass
+
 ------------------
 Available settings
 ------------------
 
 .. module:: hypothesis
-.. autoclass:: Settings
+.. autoclass:: settings
     :members: max_examples, max_iterations, min_satisfying_examples,
-        max_shrinks, timeout, strict, database_file, stateful_step_count, average_list_length,
+        max_shrinks, timeout, strict, database_file, stateful_step_count, 
         database
 
 .. _verbose-output:
diff --git a/examples/__init__.py b/examples/__init__.py
deleted file mode 100644
index 2778a19..0000000
--- a/examples/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# coding=utf-8
-#
-# This file is part of Hypothesis (https://github.com/DRMacIver/hypothesis)
-#
-# Most of this work is copyright (C) 2013-2015 David R. MacIver
-# (david at drmaciver.com), but it contains contributions by others. See
-# https://github.com/DRMacIver/hypothesis/blob/master/CONTRIBUTING.rst for a
-# full list of people who may hold copyright, and consult the git log if you
-# need to determine who owns an individual contribution.
-#
-# This Source Code Form is subject to the terms of the Mozilla Public License,
-# v. 2.0. If a copy of the MPL was not distributed with this file, You can
-# obtain one at http://mozilla.org/MPL/2.0/.
-#
-# END HEADER
diff --git a/examples/bintree.py b/examples/bintree.py
deleted file mode 100644
index 534102a..0000000
--- a/examples/bintree.py
+++ /dev/null
@@ -1,619 +0,0 @@
-# coding=utf-8
-#
-# This file is part of Hypothesis (https://github.com/DRMacIver/hypothesis)
-#
-# Most of this work is copyright (C) 2013-2015 David R. MacIver
-# (david at drmaciver.com), but it contains contributions by others. See
-# https://github.com/DRMacIver/hypothesis/blob/master/CONTRIBUTING.rst for a
-# full list of people who may hold copyright, and consult the git log if you
-# need to determine who owns an individual contribution.
-#
-# This Source Code Form is subject to the terms of the Mozilla Public License,
-# v. 2.0. If a copy of the MPL was not distributed with this file, You can
-# obtain one at http://mozilla.org/MPL/2.0/.
-#
-# END HEADER
-
-"""This is a tutorial for building a strategy from scratch rather than using
-the strategy combinators.
-
-Note that the API described herein is "semi-public". This means it will not
-break between patch releases but may break between minor versions. However
-it should be pretty stable and usually it shouldn't break between minor
-versions either, or will only do so in a fairly easy to fix way.
-
-We're going to build a strategy for a binary tree with labelled leaves. That
-is, every element of our data type is either a Leaf with a single value as a
-label, or a Split which has a left and a right element that are themselves
-binary trees.
-
-Note: This file contains both tests and implementation, mostly for ease of
-following. Normally you would of course separate these into their own files.
-
-To run these tests, install pytest (ideally in a virtualenv) and from the root
-of a hypothesis checkout run
-
-PYTHONPATH=src python -m pytest examples/bintree.py
-
-"""
-
-from __future__ import division, print_function, absolute_import, \
-    unicode_literals
-
-import math
-from collections import namedtuple
-
-from hypothesis import find
-from hypothesis.strategies import just, lists, integers
-from hypothesis.strategytests import strategy_test_suite
-from hypothesis.searchstrategy import SearchStrategy
-from hypothesis.searchstrategy.strategies import check_length, \
-    check_data_type
-
-
-class BinaryTree(object):
-    pass
-
-
-class Leaf(BinaryTree):
-
-    def __init__(self, label):
-        self.label = label
-
-    def __repr__(self):
-        return 'Leaf(%r)' % (self.label,)
-
-    def __eq__(self, other):
-        return isinstance(other, Leaf) and self.label == other.label
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-
-class Split(BinaryTree):
-
-    def __init__(self, left, right):
-        self.left = left
-        self.right = right
-
-    def __repr__(self):
-        return 'Split(%r, %r)' % (self.left, self.right)
-
-    def __eq__(self, other):
-        return (
-            isinstance(other, Split) and
-            self.left == other.left and
-            self.right == other.right
-        )
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-
-class BinaryTreeStrategy(SearchStrategy):
-
-    """An implementation of a strategy for generating BinaryTree instances.
-
-    All methods specific to this implementation are prefixed with _, all
-    others are implementing the SearchStrategy interface.
-
-    """
-
-    def __init__(self, leaf_strategy):
-        """In order to create a strategy for binary trees, we need a strategy
-        for creating labels for its leaves.
-
-        Everything else we can handle ourselves.
-
-        """
-        super(BinaryTreeStrategy, self).__init__()
-        self.leaf_strategy = leaf_strategy
-
-    Parameter = namedtuple(
-        'Parameter',
-        ('size_control', 'split_location', 'leaf_parameter'),
-    )
-
-    def draw_parameter(self, random):
-        """A parameter controls the "shape" of the data. Data generation
-        proceeds by first drawing a parameter and then drawing a template given
-        that parameter.
-
-        This has two main benefits: Firstly, it lets us produce more
-        interesting data, because the results are typically less uniform and
-        more likely to trigger edge cases, and secondly it gives us a tool for
-        shaping the exploration of the search space.
-
-        Parameters can be any value at all. In this case we've defined a custom
-        namedtuple to hold our data.
-
-        """
-
-        # Our parameter has three important details:
-        return self.Parameter(
-            # size_control will be used to determine how many leaves we
-            # generate. We will use a geometric distribution, so the expected
-            # number of leaves is 1 / size_control. As a result we set a lower
-            # bound of 0.01 to prevent us from generating dangerously large
-            # trees.
-            size_control=max(0.01, random.random()),
-
-            # split location will determine how balanced the tree is. The idea
-            # will be that when splitting n nodes into a tree, we put roughly
-            # split_location * n in the left hand side. Thus, if split_location
-            # is around 0.5 the tree will be roughly balanced, but if it's near
-            # 0 or 1 the tree will be very unbalanced.
-            # Because python is bad at recursion and tends to have very short
-            # stacks, we force this not to go too far to the edges so as to
-            # keep the depth under control.
-            split_location=0.2 + 0.8 * random.random(),
-
-            # We need a parameter to control the shape of our leaf distribution
-            # too. We use whatever the parameter normally associated with the
-            # leaf strategy is. Note this is completely opaque to us: We can't
-            # do anything with it except feed it back into the leaf strategy
-            # later.
-            leaf_parameter=self.leaf_strategy.draw_parameter(random)
-        )
-
-    def draw_template(self, random, parameter_value):
-        """We now produce a template, which is a value that we will later turn
-        into a binary tree.
-
-        There are a number of reasons for the distinction which we won't
-        go into here, but think of a template as an easier to work with
-        intermediate representation of the final value. In particular
-        templates are always hashable and comparable for equality, even
-        if the finished product is not.
-
-        """
-
-        # Our templates will be tuples of 1 or 3 elements. A tuple of 1 element
-        # is a leaf and will contain a leaf template, a tuple of 3 elements is
-        # a split and will contain two BinaryTree templates followed by an int
-        # which caches the number of leaf nodes in the tree. The reason for the
-        # latter will become clear later.
-
-        # Rather than attempt to do this recursively, we build a list of leaves
-        # of a fixed size and then split that up into a tree. This allows us
-        # much more control over the size of the finished product than we would
-        # otherwise have.
-
-        # This is 1 + a geometric distribution with parameter size_control.
-        # It's 1 + because we don't allow our trees to be empty so we need at
-        # least one element.
-        n_leaf_labels = 1 + int(
-            math.log(random.random()) /
-            math.log1p(-parameter_value.size_control)
-        )
-
-        leaf_templates = tuple(
-            self.leaf_strategy.draw_template(
-                random, parameter_value.leaf_parameter)
-            for _ in range(n_leaf_labels)
-        )
-
-        # We now need to need to figure out how to distribute the leaves.
-        # We do this recursively, so farm off to another method.
-        return self._split_leaf_list(
-            leaf_templates, random, parameter_value.split_location
-        )
-
-    def _split_leaf_list(self, leaves, random, split_location):
-        # Calling this on an empty list is a logical error.
-        assert leaves
-
-        if len(leaves) == 1:
-            # If we have only one leaf then this is already the template for
-            # a single node and we're done.
-            return tuple(leaves)
-        if len(leaves) == 2:
-            # If we only have two, this can only be produced as a single split
-            # with a leaf on either side.
-            return (
-                (leaves[0],), (leaves[1],), 2
-            )
-        # We now need to split the remaining leaves into two piles, one for the
-        # left branch and one for the right. We first ensure that each pile is
-        # non-empty and then distribute the remainder according to the
-        # split_location parameter.
-
-        left = [leaves[0]]
-        right = [leaves[1]]
-        for leaf in leaves[2:]:
-            if random.random() <= split_location:
-                left.append(leaf)
-            else:
-                right.append(leaf)
-
-        left_template = self._split_leaf_list(left, random, split_location)
-        right_template = self._split_leaf_list(right, random, split_location)
-
-        # We now have two nice little piles of nodes to put on the left and
-        # the right side of this split, and we must split those too.
-        return self._make_split(
-            left_template, right_template,
-        )
-
-    def _template_size(self, template):
-        """Get the number of leaf nodes below a template."""
-        if len(template) == 1:
-            return 1
-        else:
-            return template[-1]
-
-    def _make_split(self, left, right):
-        """Smart constructor for a split template which handles getting the
-        size right automatically."""
-        return (
-            left, right,
-            self._template_size(left) + self._template_size(right)
-        )
-
-    def reify(self, template):
-        """Reify is the point at which we take our templates and turn them into
-        the values we actually want.
-
-        Our templates here quite closely map to the desired end type, so
-        all we have to do is make sure to reify the leaves and then
-        assemble the templates into the appropriate BinaryTree subtype.
-
-        """
-        assert len(template) in (1, 3)
-        if len(template) == 1:
-            return Leaf(self.leaf_strategy.reify(template[0]))
-        else:
-            return Split(
-                self.reify(template[0]), self.reify(template[1])
-            )
-
-    # At this point we can generate trees, and they will participate in the
-    # adaptive assume nicely, but we can't save them to the database and they
-    # won't simplify. This will tend to mean that our examples are very
-    # complicated.
-    # e.g. the following is from a find(BinaryTreeStrategy(strategy(())),
-    # lambda x: True):
-    # Split(Split(Leaf(()), Leaf(())), Leaf(()))
-
-    # So we now need to define rules for simplifying.
-
-    def simplifiers(self, random, template):
-        """simplifiers are functions which take a pair (random, template) and
-        return a generator over simpler versions of that template.
-
-        Rather than each strategy having a single simplifier, strategies
-        have many. This allows us to focus on only using simplifiers
-        that work well for a particular problem, rather than continually
-        trying ones that will never work.
-
-        """
-        # The purpose of the template argument is that it lets us skip
-        # simplifiers we know will be useless for this particular template.
-        # All simplifiers *must* work for every template, but "work" just means
-        # doesn't error. It doesn't matter if they don't do anything useful.
-        if len(template) == 3:
-            # We first try passing to subtrees because this has the potential
-            # to make the template a lot smaller, which we want to prioritise.
-            # In general you want to leave small changes to later because it
-            # is a lot faster to throw away as much of the template as possible
-            # rather than performing lots of small shrinks.
-            yield self._simplify_to_subtrees
-
-            # Note that we try deleting leaves before we try simplifying them.
-            # This is because it's likely to be a lot cheaper this way round,
-            # as if we can delete a leaf we never have to try simplifying it.
-            yield self._delete_leaves
-            for i in range(self._template_size(template)):
-                yield self._leaf_simplifier(i)
-        else:
-            assert len(template) == 1
-            for s in self.leaf_strategy.simplifiers(random, template[0]):
-                yield self._convert_leaf_simplifier(s)
-
-    def _simplify_to_subtrees(self, random, template):
-        """If this template corresponds to a Split, yield the templates for
-        each subtree in a random order. Otherwise do nothing.
-
-        This would be useful for e.g. tests that only care about the presence
-        or absence of a particular leaf label in order to fail, and would allow
-        us to simply extract that leaf.
-
-        The randomness is not essential, but empirically it seems to work
-        better to make random choices when one is presented to you because it
-        makes you more robust against hitting pathological edge cases from
-        certain structures.
-
-        """
-        if len(template) == 3:
-            start = random.randint(0, 1)
-            yield template[start]
-            yield template[1 - start]
-
-    def _convert_leaf_simplifier(self, simplifier):
-        """This takes a single simplifier for leaf labels and turns it into a
-        simplifier for trees that will only do something if the tree is a
-        leaf."""
-
-        def accept(random, template):
-            if len(template) != 1:
-                return
-
-            for label in simplifier(random, template[0]):
-                yield (label,)
-        accept.__name__ = str(
-            '_convert_leaf_simplifier(%s)' % (simplifier.__name__,)
-        )
-        return accept
-
-    def _delete_leaf_at(self, index, template):
-        """If this tree is a split with at least index leaves, return a
-        template that is the same as this template with that leaf deleted,
-        otherwise return the template unchanged."""
-        assert index >= 0
-        if len(template) != 3:
-            return template
-        if index >= self._template_size(template):
-            return template
-        left_size = self._template_size(template[0])
-        right_size = self._template_size(template[1])
-
-        if index < left_size:
-            if left_size == 1:
-                return template[1]
-            else:
-                return self._make_split(
-                    self._delete_leaf_at(index, template[0]),
-                    template[1]
-                )
-        else:
-            if right_size == 1:
-                return template[0]
-            else:
-                return self._make_split(
-                    template[0],
-                    self._delete_leaf_at(index - left_size, template[1])
-                )
-
-    def _delete_leaves(self, random, template):
-        """Simplifier that tries to delete individual leaves one at a time."""
-        if len(template) == 1:
-            return
-        for i in range(self._template_size(template)):
-            yield self._delete_leaf_at(i, template)
-
-    def _simplify_leaf_at(self, index, random, template):
-        """Simplifier that applies a full simplify to each leaf. Note that
-        unlike the behaviour when our top level template is a leaf we use
-        full_simplify. This is to prevent a combinatorial explosion: If we
-        were to use all the individual simplifiers of the leaves we would
-        potentially have a very large number of simplifiers to consider.
-
-        All full_simplify does is run each simplifier (albeit in a slightly
-        randomized order), so we still get the same amount of simplification.
-        This does prevent certain optimisations in how simplify normally works.
-        It's a trade-off - you have to strike a balance between number of
-        simplifiers and quality of simplification. Usually the only way to
-        find the right balance is trial and error.
-        """
-        assert index >= 0
-        if index >= self._template_size(template):
-            return
-        if len(template) == 1:
-            for simpler in self.leaf_strategy.full_simplify(
-                random, template[0]
-            ):
-                yield (simpler,)
-        else:
-            assert len(template) == 3
-            left = self._template_size(template[0])
-            if index < left:
-                for simpler in self._simplify_leaf_at(
-                    index, random, template[0]
-                ):
-                    yield self._make_split(simpler, template[1])
-            else:
-                for simpler in self._simplify_leaf_at(
-                    index - left, random, template[1]
-                ):
-                    yield self._make_split(template[0], simpler)
-
-    def _leaf_simplifier(self, index):
-        def accept(random, template):
-            for result in self._simplify_leaf_at(index, random, template):
-                yield result
-        accept.__name__ = str(
-            'leaf_simplifier(%d)' % (index,)
-        )
-        return accept
-
-    def strictly_simpler(self, x, y):
-        """This returns True in if x should be regarded as strictly simpler
-        than y. This is a heuristic that is mainly used in collection
-        simplification.
-
-        - it allows us to e.g. simplify long lists by replacing more complex
-        elements of the list with simpler ones and seeing if test still fails.
-
-        It is not strictly necessary to implement this, but it will improve
-        quality and performance when testing lists of values, so it's a good
-        idea.
-
-        """
-        # We always consider leaves simpler than splits
-        if len(x) < len(y):
-            return True
-        if len(x) > len(y):
-            return False
-        assert len(x) == len(y)
-        if len(x) == 1:
-            # For leaves we delegate to the leaf strategy
-            return self.leaf_strategy.strictly_simpler(x[0], y[0])
-        assert len(x) == 3
-
-        # We now compare number of leaf nodes. A template with fewer nodes is
-        # always strictly simpler. We do this to preserve the required
-        # invariant that a simplifier cannot produce something such that the
-        # original would be consider strictly simpler: Without this step,
... 10680 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-hypothesis.git



More information about the Python-modules-commits mailing list