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
