Hello community,

here is the log from the commit of package python-hypothesis for 
openSUSE:Factory checked in at 2017-10-18 10:44:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-hypothesis (Old)
 and      /work/SRC/openSUSE:Factory/.python-hypothesis.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-hypothesis"

Wed Oct 18 10:44:28 2017 rev:8 rq:534391 version:3.33.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-hypothesis/python-hypothesis.changes      
2017-10-10 11:38:16.535878153 +0200
+++ /work/SRC/openSUSE:Factory/.python-hypothesis.new/python-hypothesis.changes 
2017-10-18 10:44:30.021727644 +0200
@@ -1,0 +2,78 @@
+Tue Oct 17 01:47:00 UTC 2017 - [email protected]
+
+- update to version 3.33.0:
+  * This release supports strategy inference for more field types in
+    Django models() - you can now omit an argument for Date, Time,
+    Duration, Slug, IP Address, and UUID fields. (issue #642)
+  * Strategy generation for fields with grouped choices now selects
+    choices from each group, instead of selecting from the group
+    names.
+
+-------------------------------------------------------------------
+Sun Oct 15 22:19:10 UTC 2017 - [email protected]
+
+- specfile:
+  * removed sed for src/hypothesis/tools/mergedbs.py, not in tar-ball anymore
+
+- update to version 3.32.2:
+  * This patch removes the mergedb tool, introduced in Hypothesis
+    1.7.1 on an experimental basis. It has never actually worked, and
+    the new Hypothesis example database is designed to make such a
+    tool unnecessary.
+
+- changes from version 3.32.1:
+  * This patch has two improvements for strategies based on
+    enumerations.
+  * from_type() now handles enumerations correctly, delegating to
+    sampled_from(). Previously it noted that Enum.__init__ has no
+    required arguments and therefore delegated to builds(), which
+    would subsequently fail.
+  * When sampling from an enum.Flag, we also generate combinations of
+    members. Eg for Flag('Permissions', 'READ, WRITE, EXECUTE') we can
+    now generate, Permissions.READ, Permissions.READ|WRITE, and so on.
+
+-------------------------------------------------------------------
+Mon Oct  9 04:06:23 UTC 2017 - [email protected]
+
+- update to version 3.32.0:
+  * This changes the default value of use_coverage=True to True when
+    running on pypy (it was already True on CPython).
+
+    It was previously set to False because we expected it to be too
+    slow, but recent benchmarking shows that actually performance of
+    the feature on pypy is fairly acceptable - sometimes it’s slower
+    than on CPython, sometimes it’s faster, but it’s generally within
+    a factor of two either way.
+
+- changes from version 3.31.6:
+  * This patch improves the quality of strategies inferred from Numpy
+    dtypes:
+    + Integer dtypes generated examples with the upper half of their
+      (non-sign) bits set to zero. The inferred strategies can now
+      produce any representable integer.
+    + Fixed-width unicode- and byte-string dtypes now cap the internal
+      example length, which should improve example and shrink quality.
+    + Numpy arrays can only store fixed-size strings internally, and
+      allow shorter strings by right-padding them with null
+      bytes. Inferred string strategies no longer generate such
+      values, as they can never be retrieved from an array. This
+      improves shrinking performance by skipping useless values.
+    + This has already been useful in Hypothesis - we found an
+      overflow bug in our Pandas support, and as a result indexes()
+      and range_indexes() now check that min_size and max_size are at
+      least zero.
+
+- changes from version 3.31.5:
+  * This release fixes a performance problem in tests where
+    + use_coverage is set to True.
+    + Tests experience a slow-down proportionate to the amount of code
+      they cover. This is still the case, but the factor is now low
+      enough that it should be unnoticeable. Previously it was large
+      and became much larger in 3.28.4.
+
+- changes from version 3.31.4:
+  * from_type() failed with a very confusing error if passed a
+    NewType() (issue #901). These psudeo-types are now unwrapped
+    correctly, and strategy inference works as expected.
+
+-------------------------------------------------------------------

Old:
----
  hypothesis-3.31.3.tar.gz

New:
----
  hypothesis-3.33.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-hypothesis.spec ++++++
--- /var/tmp/diff_new_pack.35c8Bn/_old  2017-10-18 10:44:31.021680665 +0200
+++ /var/tmp/diff_new_pack.35c8Bn/_new  2017-10-18 10:44:31.025680477 +0200
@@ -24,7 +24,7 @@
 %endif
 %bcond_with test
 Name:           python-hypothesis
-Version:        3.31.3
+Version:        3.33.0
 Release:        0
 Summary:        A library for property based testing
 License:        MPL-2.0
@@ -68,8 +68,6 @@
 
 %prep
 %setup -q -n hypothesis-%{version}
-# remove shebang
-sed -e '1d' -i src/hypothesis/tools/mergedbs.py
 
 %build
 %python_build

++++++ hypothesis-3.31.3.tar.gz -> hypothesis-3.33.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/PKG-INFO 
new/hypothesis-3.33.0/PKG-INFO
--- old/hypothesis-3.31.3/PKG-INFO      2017-10-06 19:17:35.000000000 +0200
+++ new/hypothesis-3.33.0/PKG-INFO      2017-10-16 09:13:49.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: hypothesis
-Version: 3.31.3
+Version: 3.33.0
 Summary: A library for property based testing
 Home-page: https://github.com/HypothesisWorks/hypothesis-python
 Author: David R. MacIver
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/_settings.py 
new/hypothesis-3.33.0/src/hypothesis/_settings.py
--- old/hypothesis-3.31.3/src/hypothesis/_settings.py   2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/_settings.py   2017-10-16 
09:12:42.000000000 +0200
@@ -34,7 +34,6 @@
 
 from hypothesis.errors import InvalidArgument, HypothesisDeprecationWarning
 from hypothesis.configuration import hypothesis_home_dir
-from hypothesis.internal.compat import PYPY
 from hypothesis.utils.conventions import UniqueIdentifier, not_set
 from hypothesis.utils.dynamicvariables import DynamicVariable
 
@@ -649,15 +648,15 @@
 
 settings.define_setting(
     'use_coverage',
-    default=not PYPY,
-    show_default=False,
+    default=True,
     description="""
 Whether to use coverage information to improve Hypothesis's ability to find
-bugs. You should generally leave this turned on unless your code performs
-poorly when run under coverage.
+bugs.
 
-Note: This is turned on by default except on pypy, where coverage performance
-is sufficiently poor as to make this unusable.
+You should generally leave this turned on unless your code performs
+poorly when run under coverage. If you turn it off, please file a bug report
+or add a comment to an existing one about the problem that prompted you to do
+so.
 """
 )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/core.py 
new/hypothesis-3.33.0/src/hypothesis/core.py
--- old/hypothesis-3.31.3/src/hypothesis/core.py        2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/core.py        2017-10-16 
09:12:42.000000000 +0200
@@ -551,11 +551,26 @@
     )
 
 
[email protected](slots=True, frozen=True)
 class Arc(object):
-    filename = attr.ib()
-    source = attr.ib()
-    target = attr.ib()
+    __slots__ = ('filename', 'source', 'target')
+
+    def __init__(self, filename, source, target):
+        self.filename = filename
+        self.source = source
+        self.target = target
+
+
+ARC_CACHE = {}
+
+
+def arc(filename, source, target):
+    try:
+        return ARC_CACHE[filename][source][target]
+    except KeyError:
+        result = Arc(filename, source, target)
+        ARC_CACHE.setdefault(
+            filename, {}).setdefault(source, {})[target] = result
+        return result
 
 
 in_given = False
@@ -720,7 +735,7 @@
                         if is_hypothesis_file(filename):
                             continue
                         data.tags.update(
-                            Arc(filename, source, target)
+                            arc(filename, source, target)
                             for source, target in covdata.arcs(filename)
                         )
             if result is not None and self.settings.perform_health_check:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-3.31.3/src/hypothesis/extra/django/models.py 
new/hypothesis-3.33.0/src/hypothesis/extra/django/models.py
--- old/hypothesis-3.31.3/src/hypothesis/extra/django/models.py 2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/extra/django/models.py 2017-10-16 
09:12:42.000000000 +0200
@@ -19,6 +19,7 @@
 
 import string
 from decimal import Decimal
+from datetime import timedelta
 
 import django.db.models as dm
 from django.db import IntegrityError
@@ -26,32 +27,18 @@
 from django.core.exceptions import ValidationError
 
 import hypothesis.strategies as st
+from hypothesis import reject
 from hypothesis.errors import InvalidArgument
 from hypothesis.extra.pytz import timezones
+from hypothesis.provisional import emails, ip4_addr_strings, \
+    ip6_addr_strings
 from hypothesis.utils.conventions import UniqueIdentifier
-from hypothesis.searchstrategy.strategies import SearchStrategy
 
 
-class ModelNotSupported(Exception):
-    pass
-
-
-def referenced_models(model, seen=None):
-    if seen is None:
-        seen = set()
-    for f in model._meta.concrete_fields:
-        if isinstance(f, dm.ForeignKey):
-            t = f.rel.to
-            if t not in seen:
-                seen.add(t)
-                referenced_models(t, seen)
-    return seen
-
-
-def get_datetime_strat():
+def get_tz_strat():
     if getattr(django_settings, 'USE_TZ', False):
-        return st.datetimes(timezones=timezones())
-    return st.datetimes()
+        return timezones()
+    return st.none()
 
 
 __default_field_mappings = None
@@ -61,6 +48,8 @@
     global __default_field_mappings
 
     if __default_field_mappings is None:
+        # Sized fields are handled in _get_strategy_for_field()
+        # URL fields are not yet handled
         __default_field_mappings = {
             dm.SmallIntegerField: st.integers(-32768, 32767),
             dm.IntegerField: st.integers(-2147483648, 2147483647),
@@ -70,10 +59,26 @@
             dm.PositiveSmallIntegerField: st.integers(0, 32767),
             dm.BinaryField: st.binary(),
             dm.BooleanField: st.booleans(),
-            dm.DateTimeField: get_datetime_strat(),
+            dm.DateField: st.dates(),
+            dm.DateTimeField: st.datetimes(timezones=get_tz_strat()),
+            dm.DurationField: st.timedeltas(),
+            dm.EmailField: emails(),
             dm.FloatField: st.floats(),
             dm.NullBooleanField: st.one_of(st.none(), st.booleans()),
+            dm.TimeField: st.times(timezones=get_tz_strat()),
+            dm.UUIDField: st.uuids(),
         }
+
+        # SQLite does not support timezone-aware times, or timedeltas that
+        # don't fit in six bytes of microseconds, so we override those
+        db = getattr(django_settings, 'DATABASES', {}).get('default', {})
+        if db.get('ENGINE', '').endswith('.sqlite3'):  # pragma: no branch
+            sqlite_delta = timedelta(microseconds=2 ** 47 - 1)
+            __default_field_mappings.update({
+                dm.TimeField: st.times(),
+                dm.DurationField: st.timedeltas(-sqlite_delta, sqlite_delta),
+            })
+
     return __default_field_mappings
 
 
@@ -84,10 +89,6 @@
 default_value = UniqueIdentifier(u'default_value')
 
 
-class UnmappedFieldError(Exception):
-    pass
-
-
 def validator_to_filter(f):
     """Converts the field run_validators method to something suitable for use
     in filter."""
@@ -102,61 +103,34 @@
     return validate
 
 
-safe_letters = string.ascii_letters + string.digits + '_-'
-
-domains = st.builds(
-    lambda x, y: '.'.join(x + [y]),
-    st.lists(st.text(safe_letters, min_size=1), min_size=1), st.sampled_from([
-        'com', 'net', 'org', 'biz', 'info',
-    ])
-)
-
-
-email_domains = st.one_of(
-    domains,
-    st.sampled_from(['gmail.com', 'yahoo.com', 'hotmail.com'])
-)
-
-base_emails = st.text(safe_letters, min_size=1)
-
-emails_with_plus = st.builds(
-    lambda x, y: '%s+%s' % (x, y), base_emails, base_emails
-)
-
-emails = st.builds(
-    lambda x, y: '%s@%s' % (x, y),
-    st.one_of(base_emails, emails_with_plus), email_domains
-)
-
-
 def _get_strategy_for_field(f):
-    if isinstance(f, dm.AutoField):
-        return default_value
-    elif f.choices:
-        choices = [value for (value, name) in f.choices]
+    if f.choices:
+        choices = []
+        for value, name_or_optgroup in f.choices:
+            if isinstance(name_or_optgroup, (list, tuple)):
+                choices.extend(key for key, _ in name_or_optgroup)
+            else:
+                choices.append(value)
         if isinstance(f, (dm.CharField, dm.TextField)) and f.blank:
-            choices.append(u'')
+            choices.insert(0, u'')
         strategy = st.sampled_from(choices)
-    elif isinstance(f, dm.EmailField):
-        return emails
+    elif type(f) == dm.SlugField:
+        strategy = st.text(alphabet=string.ascii_letters + string.digits,
+                           min_size=(None if f.blank else 1),
+                           max_size=f.max_length)
+    elif type(f) == dm.GenericIPAddressField:
+        lookup = {'both': ip4_addr_strings() | ip6_addr_strings(),
+                  'ipv4': ip4_addr_strings(), 'ipv6': ip6_addr_strings()}
+        strategy = lookup[f.protocol.lower()]
     elif type(f) in (dm.TextField, dm.CharField):
         strategy = st.text(min_size=(None if f.blank else 1),
                            max_size=f.max_length)
     elif type(f) == dm.DecimalField:
-        m = 10 ** f.max_digits - 1
-        div = 10 ** f.decimal_places
-        q = Decimal('1.' + ('0' * f.decimal_places))
-        strategy = (
-            st.integers(min_value=-m, max_value=m)
-            .map(lambda n: (Decimal(n) / div).quantize(q)))
+        bound = Decimal(10 ** f.max_digits - 1) / (10 ** f.decimal_places)
+        strategy = st.decimals(min_value=-bound, max_value=bound,
+                               places=f.decimal_places)
     else:
-        try:
-            strategy = field_mappings()[type(f)]
-        except KeyError:
-            if f.null:
-                return None
-            else:
-                raise UnmappedFieldError(f)
+        strategy = field_mappings().get(type(f), st.nothing())
     if f.validators:
         strategy = strategy.filter(validator_to_filter(f))
     if f.null:
@@ -165,45 +139,25 @@
 
 
 def models(model, **extra):
-    result = {}
-    mandatory = set()
+    """Return a strategy for instances of a model."""
+    result = {k: v for k, v in extra.items() if v is not default_value}
+    missed = []
     for f in model._meta.concrete_fields:
-        try:
-            strategy = _get_strategy_for_field(f)
-        except UnmappedFieldError:
-            mandatory.add(f.name)
-            continue
-        if strategy is not None:
-            result[f.name] = strategy
-    missed = {x for x in mandatory if x not in extra}
+        if not (f.name in extra or isinstance(f, dm.AutoField)):
+            result[f.name] = _get_strategy_for_field(f)
+            if result[f.name].is_empty:
+                missed.append(f.name)
     if missed:
-        raise InvalidArgument((
-            u'Missing arguments for mandatory field%s %s for model %s' % (
-                u's' if len(missed) > 1 else u'',
-                u', '.join(missed),
-                model.__name__,
-            )))
-    result.update(extra)
-    # Remove default_values so we don't try to generate anything for those.
-    result = {k: v for k, v in result.items() if v is not default_value}
-    return ModelStrategy(model, result)
-
-
-class ModelStrategy(SearchStrategy):
-
-    def __init__(self, model, mappings):
-        super(ModelStrategy, self).__init__()
-        self.model = model
-        self.arg_strategy = st.fixed_dictionaries(mappings)
+        raise InvalidArgument(
+            u'Missing arguments for mandatory field%s %s for model %s'
+            % (u's' if missed else u'', u', '.join(missed), model.__name__))
+    return _models_impl(st.builds(model.objects.get_or_create, **result))
 
-    def __repr__(self):
-        return u'ModelStrategy(%s)' % (self.model.__name__,)
 
-    def do_draw(self, data):
-        try:
-            result, _ = self.model.objects.get_or_create(
-                **self.arg_strategy.do_draw(data)
-            )
-            return result
-        except IntegrityError:
-            data.mark_invalid()
[email protected]
+def _models_impl(draw, strat):
+    """Handle the nasty part of drawing a value for models()"""
+    try:
+        return draw(strat)[0]
+    except IntegrityError:
+        reject()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/extra/numpy.py 
new/hypothesis-3.33.0/src/hypothesis/extra/numpy.py
--- old/hypothesis-3.31.3/src/hypothesis/extra/numpy.py 2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/extra/numpy.py 2017-10-16 
09:12:42.000000000 +0200
@@ -53,15 +53,20 @@
     elif dtype.kind == u'c':
         result = st.complex_numbers()
     elif dtype.kind in (u'S', u'a'):
-        result = st.binary()
+        # Numpy strings are null-terminated; only allow round-trippable values.
+        # `itemsize == 0` means 'fixed length determined at array creation'
+        result = st.binary(max_size=dtype.itemsize or None
+                           ).filter(lambda b: b[-1:] != b'\0')
     elif dtype.kind == u'u':
-        result = st.integers(
-            min_value=0, max_value=1 << (4 * dtype.itemsize) - 1)
+        result = st.integers(min_value=0,
+                             max_value=2 ** (8 * dtype.itemsize) - 1)
     elif dtype.kind == u'i':
-        min_integer = -1 << (4 * dtype.itemsize - 1)
-        result = st.integers(min_value=min_integer, max_value=-min_integer - 1)
+        overflow = 2 ** (8 * dtype.itemsize - 1)
+        result = st.integers(min_value=-overflow, max_value=overflow - 1)
     elif dtype.kind == u'U':
-        result = st.text()
+        # Encoded in UTF-32 (four bytes/codepoint) and null-terminated
+        result = st.text(max_size=(dtype.itemsize or 0) // 4 or None
+                         ).filter(lambda b: b[-1:] != u'\0')
     elif dtype.kind in (u'm', u'M'):
         if '[' in dtype.str:
             res = st.just(dtype.str.split('[')[-1][:-1])
@@ -86,7 +91,7 @@
         floor, small, name=name
     )
     check_argument(
-        small <= large, u'min_{name}={} is larger than max_name={}',
+        small <= large, u'min_{name}={} is larger than max_{name}={}',
         small, large, name=name
     )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-3.31.3/src/hypothesis/extra/pandas/impl.py 
new/hypothesis-3.33.0/src/hypothesis/extra/pandas/impl.py
--- old/hypothesis-3.31.3/src/hypothesis/extra/pandas/impl.py   2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/extra/pandas/impl.py   2017-10-16 
09:12:42.000000000 +0200
@@ -156,9 +156,11 @@
       it will default to some suitable value based on min_size.
 
     """
-    st.check_valid_interval(min_size, max_size, 'min_size', 'max_size')
+    st.check_valid_size(min_size, 'min_size')
+    st.check_valid_size(max_size, 'max_size')
     if max_size is None:
-        max_size = min_size + DEFAULT_MAX_SIZE
+        max_size = min([min_size + DEFAULT_MAX_SIZE, 2 ** 63 - 1])
+    st.check_valid_interval(min_size, max_size, 'min_size', 'max_size')
     return st.integers(min_size, max_size).map(pandas.RangeIndex)
 
 
@@ -187,6 +189,8 @@
       should be distinct.
 
     """
+    st.check_valid_size(min_size, 'min_size')
+    st.check_valid_size(max_size, 'max_size')
     st.check_valid_interval(min_size, max_size, 'min_size', 'max_size')
     st.check_type(bool, unique, 'unique')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-3.31.3/src/hypothesis/internal/conjecture/engine.py 
new/hypothesis-3.33.0/src/hypothesis/internal/conjecture/engine.py
--- old/hypothesis-3.31.3/src/hypothesis/internal/conjecture/engine.py  
2017-10-06 19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/internal/conjecture/engine.py  
2017-10-16 09:12:42.000000000 +0200
@@ -24,8 +24,6 @@
 from weakref import WeakKeyDictionary
 from collections import defaultdict
 
-import attr
-
 from hypothesis import settings as Settings
 from hypothesis import Phase
 from hypothesis.reporting import debug_report
@@ -138,10 +136,7 @@
 
         self.debug_data(data)
 
-        tags = frozenset(
-            self.tag_intern_table.setdefault(t, t)
-            for t in data.tags
-        )
+        tags = frozenset(data.tags)
         data.tags = self.tag_intern_table.setdefault(tags, tags)
 
         if data.status == Status.VALID:
@@ -1135,9 +1130,23 @@
         return random.choice(self.__values)
 
 
[email protected](slots=True, hash=True, cmp=True)
 class Negated(object):
-    tag = attr.ib()
+    __slots__ = ('tag',)
+
+    def __init__(self, tag):
+        self.tag = tag
+
+
+NEGATED_CACHE = {}
+
+
+def negated(tag):
+    try:
+        return NEGATED_CACHE[tag]
+    except KeyError:
+        result = Negated(tag)
+        NEGATED_CACHE[tag] = result
+        return result
 
 
 universal = UniqueIdentifier('universal')
@@ -1232,7 +1241,7 @@
 
         for t in new_tags:
             self.non_universal_tags.add(t)
-            self.examples_by_tags[Negated(t)] = list(
+            self.examples_by_tags[negated(t)] = list(
                 self.examples_by_tags[universal]
             )
 
@@ -1254,7 +1263,7 @@
             yield t
         for t in self.non_universal_tags:
             if t not in data.tags:
-                yield Negated(t)
+                yield negated(t)
 
     def rescore(self, tag):
         new_score = (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/provisional.py 
new/hypothesis-3.33.0/src/hypothesis/provisional.py
--- old/hypothesis-3.31.3/src/hypothesis/provisional.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/hypothesis-3.33.0/src/hypothesis/provisional.py 2017-10-16 
09:12:42.000000000 +0200
@@ -0,0 +1,84 @@
+# coding=utf-8
+#
+# This file is part of Hypothesis, which may be found at
+# https://github.com/HypothesisWorks/hypothesis-python
+#
+# Most of this work is copyright (C) 2013-2017 David R. MacIver
+# ([email protected]), but it contains contributions by others. See
+# 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 module contains various provisional APIs and strategies.
+
+It is intended for internal use, to ease code reuse, and is not stable.
+Point releases may move or break the contents at any time!
+
+Internet strategies should conform to https://tools.ietf.org/html/rfc3696 or
+the authoritative definitions it links to.  If not, report the bug!
+
+"""
+
+from __future__ import division, print_function, absolute_import
+
+import string
+
+import hypothesis.strategies as st
+
+
[email protected]_strategy_with_reusable_values
+def domains():
+    """A strategy for :rfc:`1035` fully qualified domain names."""
+    atoms = st.text(string.ascii_letters + '0123456789-',
+                    min_size=1, max_size=63
+                    ).filter(lambda s: '-' not in s[0] + s[-1])
+    return st.builds(
+        lambda x, y: '.'.join(x + [y]),
+        st.lists(atoms, min_size=1),
+        # TODO: be more devious about top-level domains
+        st.sampled_from(['com', 'net', 'org', 'biz', 'info'])
+    ).filter(lambda url: len(url) <= 255)
+
+
[email protected]_strategy_with_reusable_values
+def emails():
+    """A strategy for email addresses.
+
+    See https://github.com/HypothesisWorks/hypothesis-python/issues/162
+    for work on a permanent replacement.
+
+    """
+    local_chars = string.ascii_letters + string.digits + "!#$%&'*+-/=^_`{|}~"
+    local_part = st.text(local_chars, min_size=1, max_size=64)
+    # TODO: include dot-atoms, quoted strings, escaped chars, etc in local part
+    return st.builds('{}@{}'.format, local_part, domains()).filter(
+        lambda addr: len(addr) <= 255)
+
+
[email protected]_strategy_with_reusable_values
+def ip4_addr_strings():
+    """A strategy for IPv4 address strings.
+
+    This consists of four strings representing integers [0..255],
+    without zero-padding, joined by dots.
+
+    """
+    return st.builds('{}.{}.{}.{}'.format, *(4 * [st.integers(0, 255)]))
+
+
[email protected]_strategy_with_reusable_values
+def ip6_addr_strings():
+    """A strategy for IPv6 address strings.
+
+    This consists of sixteen quads of hex digits (0000 .. FFFF), joined
+    by colons.  Values do not currently have zero-segments collapsed.
+
+    """
+    part = st.integers(0, 2**16 - 1).map(u'{:04x}'.format)
+    return st.tuples(*[part] * 8).map(lambda a: u':'.join(a).upper())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/strategies.py 
new/hypothesis-3.33.0/src/hypothesis/strategies.py
--- old/hypothesis-3.31.3/src/hypothesis/strategies.py  2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/strategies.py  2017-10-16 
09:12:42.000000000 +0200
@@ -17,13 +17,15 @@
 
 from __future__ import division, print_function, absolute_import
 
+import enum
 import math
 import datetime as dt
 import operator
 from decimal import Context, Decimal
-from inspect import isclass
+from inspect import isclass, isfunction
 from numbers import Rational
 from fractions import Fraction
+from functools import reduce
 
 from hypothesis.errors import InvalidArgument, ResolutionFailed
 from hypothesis.control import assume
@@ -401,23 +403,30 @@
 
 @defines_strategy
 def sampled_from(elements):
-    """Returns a strategy which generates any value present in the iterable
-    elements.
+    """Returns a strategy which generates any value present in ``elements``.
 
-    Note that as with just, values will not be copied and thus you
-    should be careful of using mutable data.
+    Note that as with :func:`~hypotheses.strategies.just`, values will not be
+    copied and thus you should be careful of using mutable data.
 
-    """
+    ``sampled_from`` supports ordered collections, as well as
+    :class:`~python:enum.Enum` objects.  :class:`~python:enum.Flag` objects
+    may also generate any combination of their members.
 
-    from hypothesis.searchstrategy.misc import SampledFromStrategy, \
-        JustStrategy
+    """
+    from hypothesis.searchstrategy.misc import SampledFromStrategy
     from hypothesis.internal.conjecture.utils import check_sample
-    elements = check_sample(elements)
-    if not elements:
+    values = check_sample(elements)
+    if not values:
         return nothing()
-    if len(elements) == 1:
-        return JustStrategy(elements[0])
-    return SampledFromStrategy(elements)
+    if len(values) == 1:
+        return just(values[0])
+    if hasattr(enum, 'Flag') and isclass(elements) and \
+            issubclass(elements, enum.Flag):
+        # Combinations of enum.Flag members are also members.  We generate
+        # these dynamically, because static allocation takes O(2^n) memory.
+        return sets(sampled_from(values), min_size=1).map(
+            lambda s: reduce(operator.or_, s))
+    return SampledFromStrategy(values)
 
 
 @cacheable
@@ -927,11 +936,18 @@
     """
     from hypothesis.searchstrategy import types
     if not isinstance(thing, type):
-        # Under Python 3.6, Unions are not instances of `type` - but we still
-        # want to resolve them!  This __origin__ check only passes if thing is
-        # a Union with parameters; if it doesn't we can't resolve it anyway.
         try:
+            # At runtime, `typing.NewType` returns an identity function rather
+            # than an actual type, but we can check that for a possible match
+            # and then read the magic attribute to unwrap it.
             import typing
+            if all([
+                hasattr(thing, '__supertype__'), hasattr(typing, 'NewType'),
+                isfunction(thing), getattr(thing, '__module__', 0) == 'typing'
+            ]):
+                return from_type(thing.__supertype__)
+            # Under Python 3.6, Unions are not instances of `type` - but we
+            # still want to resolve them!
             if getattr(thing, '__origin__', None) is typing.Union:
                 args = sorted(thing.__args__, key=types.type_sorting_key)
                 return one_of([from_type(t) for t in args])
@@ -987,6 +1003,9 @@
             and hasattr(thing, '_field_types'):
         kwargs = {k: from_type(thing._field_types[k]) for k in thing._fields}
         return builds(thing, **kwargs)
+    if issubclass(thing, enum.Enum):
+        assert len(thing), repr(thing) + ' has no members to sample'
+        return sampled_from(thing)
     # If the constructor has an annotation for every required argument,
     # we can (and do) use builds() without supplying additional arguments.
     required = required_args(thing)
@@ -1681,7 +1700,7 @@
                 name, value, type(value).__name__, typ.__name__
             )
         )
-    except ValueError:
+    except (OverflowError, ValueError):
         raise InvalidArgument(
             'Cannot convert %s=%r to type %s' % (
                 name, value, typ.__name__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/tools/__init__.py 
new/hypothesis-3.33.0/src/hypothesis/tools/__init__.py
--- old/hypothesis-3.31.3/src/hypothesis/tools/__init__.py      2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/tools/__init__.py      1970-01-01 
01:00:00.000000000 +0100
@@ -1,16 +0,0 @@
-# coding=utf-8
-#
-# This file is part of Hypothesis, which may be found at
-# https://github.com/HypothesisWorks/hypothesis-python
-#
-# Most of this work is copyright (C) 2013-2017 David R. MacIver
-# ([email protected]), but it contains contributions by others. See
-# 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/tools/mergedbs.py 
new/hypothesis-3.33.0/src/hypothesis/tools/mergedbs.py
--- old/hypothesis-3.31.3/src/hypothesis/tools/mergedbs.py      2017-10-06 
19:16:46.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/tools/mergedbs.py      1970-01-01 
01:00:00.000000000 +0100
@@ -1,146 +0,0 @@
-#!/usr/bin/env python
-
-# coding=utf-8
-#
-# This file is part of Hypothesis, which may be found at
-# https://github.com/HypothesisWorks/hypothesis-python
-#
-# Most of this work is copyright (C) 2013-2017 David R. MacIver
-# ([email protected]), but it contains contributions by others. See
-# 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 git merge driver for merging two Hypothesis database files. It
-allows you to check in your Hypothesis database into your git repo and have
-merging examples work correctly.
-
-You can either install Hypothesis and invoke this as a module, or just copy
-this file somewhere convenient and run it directly (it has no dependencies on
-the rest of Hypothesis).
-
-You can then set this up by following the instructions in
-http://git-scm.com/docs/gitattributes to use this as the merge driver for
-wherever you have put your hypothesis database (it is in
-.hypothesis/examples.db by default). For example, the following should work
-with a default configuration:
-
-In .gitattributes add:
-
-.hypothesis/examples.db merge=hypothesisdb
-
-And in .git/config add:
-
-[merge "hypothesisdb"]
-    name = Hypothesis database files
-    driver = python -m hypothesis.tools.mergedbs %O %A %B
-
-"""
-
-
-from __future__ import division, print_function, absolute_import
-
-import sys
-import sqlite3
-
-import attr
-
-
-def get_rows(cursor):
-    cursor.execute("""
-        select key, value
-        from hypothesis_data_mapping
-    """)
-    for r in cursor:
-        yield tuple(r)
-
-
[email protected]()
-class Report(object):
-    inserts = attr.ib()
-    deletes = attr.ib()
-
-
-def merge_paths(ancestor, current, other):
-    ancestor = sqlite3.connect(ancestor)
-    current = sqlite3.connect(current)
-    other = sqlite3.connect(other)
-    result = merge_dbs(ancestor, current, other)
-    ancestor.close()
-    current.close()
-    other.close()
-    return result
-
-
-def contains(db, key, value):
-    cursor = db.cursor()
-    cursor.execute("""
-        select 1 from hypothesis_data_mapping
-        where key = ? and value = ?
-    """, (key, value))
-    result = bool(list(cursor))
-    cursor.close()
-    return result
-
-
-def merge_dbs(ancestor, current, other):
-    other_cursor = other.cursor()
-    other_cursor.execute("""
-        select key, value
-        from hypothesis_data_mapping
-    """)
-    current_cursor = current.cursor()
-    inserts = 0
-    for r in other_cursor:
-        if not contains(ancestor, *r):
-            try:
-                current_cursor.execute("""
-                    insert into hypothesis_data_mapping(key, value)
-                    values(?, ?)
-                """, tuple(r))
-                inserts += 1
-            except sqlite3.IntegrityError:
-                pass
-            current.commit()
-    deletes = 0
-    ancestor_cursor = ancestor.cursor()
-    ancestor_cursor.execute("""
-        select key, value
-        from hypothesis_data_mapping
-    """)
-    for r in ancestor_cursor:
-        if not contains(other, *r) and contains(current, *r):
-            try:
-                current_cursor.execute("""
-                    delete from hypothesis_data_mapping
-                    where key = ? and value = ?
-                """, tuple(r))
-                deletes += 1
-                current.commit()
-            except sqlite3.IntegrityError:
-                pass
-
-    return Report(inserts, deletes)
-
-
-def main():
-    _, _, current, other = sys.argv
-    result = merge_dbs(destination=current, source=other)
-    print(u'%d new entries and %d deletions from merge' % (
-        result.inserts, result.deletions))
-
-    print(
-        u'The SQLite Hypothesis database format has been deprecated and will '
-        u'go away in a future version of Hypothesis. Please switch to the '
-        u'directory based format, which handles merging correctly '
-        u'automatically.', file=sys.stderr)
-
-
-if __name__ == u'__main__':
-    main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis/version.py 
new/hypothesis-3.33.0/src/hypothesis/version.py
--- old/hypothesis-3.31.3/src/hypothesis/version.py     2017-10-06 
19:17:35.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis/version.py     2017-10-16 
09:13:48.000000000 +0200
@@ -17,5 +17,5 @@
 
 from __future__ import division, print_function, absolute_import
 
-__version_info__ = (3, 31, 3)
+__version_info__ = (3, 33, 0)
 __version__ = '.'.join(map(str, __version_info__))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-3.31.3/src/hypothesis.egg-info/PKG-INFO 
new/hypothesis-3.33.0/src/hypothesis.egg-info/PKG-INFO
--- old/hypothesis-3.31.3/src/hypothesis.egg-info/PKG-INFO      2017-10-06 
19:17:35.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis.egg-info/PKG-INFO      2017-10-16 
09:13:48.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: hypothesis
-Version: 3.31.3
+Version: 3.33.0
 Summary: A library for property based testing
 Home-page: https://github.com/HypothesisWorks/hypothesis-python
 Author: David R. MacIver
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-3.31.3/src/hypothesis.egg-info/SOURCES.txt 
new/hypothesis-3.33.0/src/hypothesis.egg-info/SOURCES.txt
--- old/hypothesis-3.31.3/src/hypothesis.egg-info/SOURCES.txt   2017-10-06 
19:17:35.000000000 +0200
+++ new/hypothesis-3.33.0/src/hypothesis.egg-info/SOURCES.txt   2017-10-16 
09:13:48.000000000 +0200
@@ -8,6 +8,7 @@
 src/hypothesis/database.py
 src/hypothesis/errors.py
 src/hypothesis/executors.py
+src/hypothesis/provisional.py
 src/hypothesis/reporting.py
 src/hypothesis/stateful.py
 src/hypothesis/statistics.py
@@ -65,8 +66,6 @@
 src/hypothesis/searchstrategy/streams.py
 src/hypothesis/searchstrategy/strings.py
 src/hypothesis/searchstrategy/types.py
-src/hypothesis/tools/__init__.py
-src/hypothesis/tools/mergedbs.py
 src/hypothesis/utils/__init__.py
 src/hypothesis/utils/conventions.py
 src/hypothesis/utils/dynamicvariables.py


Reply via email to