Hello community, here is the log from the commit of package python-hypothesis for openSUSE:Factory checked in at 2017-12-08 21:47:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-hypothesis (Old) and /work/SRC/openSUSE:Factory/.python-hypothesis.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-hypothesis" Fri Dec 8 21:47:50 2017 rev:13 rq:554735 version:3.40.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-hypothesis/python-hypothesis.changes 2017-11-30 12:38:20.629292841 +0100 +++ /work/SRC/openSUSE:Factory/.python-hypothesis.new/python-hypothesis.changes 2017-12-08 21:47:53.341776459 +0100 @@ -1,0 +2,57 @@ +Wed Dec 6 02:52:35 UTC 2017 - a...@gmx.de + +- update to version 3.40.1: + +3.40.1 - 2017-12-04 + * This release makes two changes: + + It makes the calculation of some of the metadata that Hypothesis + uses for shrinking occur lazily. This should speed up + performance of test case generation a bit because it no longer + calculates information it doesn’t need. + + It improves the shrinker for certain classes of nested + examples. e.g. when shrinking lists of lists, the shrinker is + now able to concatenate two adjacent lists together into a + single list. As a result of this change, shrinking may get + somewhat slower when the minimal example found is large. + +- changes from version 3.40.0: + * This release improves how various ways of seeding Hypothesis + interact with the example database: + + Using the example database with seed() is now deprecated. You + should set database=None if you are doing that. This will only + warn if you actually load examples from the database while using + @seed. + + The derandomize will behave the same way as @seed. + + Using --hypothesis-seed will disable use of the database. + + If a test used examples from the database, it will not suggest + using a seed to reproduce it, because that won’t work. + +- changes from version 3.39.0: + * This release adds a new health check that checks if the smallest + “natural” possible example of your test case is very large - this + will tend to cause Hypothesis to generate bad examples and be + quite slow. + +- changes from version 3.38.9: + * This is a documentation release to improve the documentation of + shrinking behaviour for Hypothesis’s strategies. + +- changes from version 3.38.8: + * This release improves the performance of characters() when using + blacklist_characters and from_regex() when using negative + character classes. + +- changes from version 3.38.7: + * This is a patch release for from_regex(), which had a bug in + handling of the re.VERBOSE flag (issue #992). Flags are now + handled correctly when parsing regex. + +------------------------------------------------------------------- +Tue Nov 28 19:04:24 UTC 2017 - a...@gmx.de + +- update to version 3.38.6: + * This patch changes a few byte-string literals from double to + single quotes, thanks to an update in unify. There are no + user-visible changes. + +------------------------------------------------------------------- Old: ---- hypothesis-3.38.5.tar.gz New: ---- hypothesis-3.40.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-hypothesis.spec ++++++ --- /var/tmp/diff_new_pack.OnGafi/_old 2017-12-08 21:47:54.421730003 +0100 +++ /var/tmp/diff_new_pack.OnGafi/_new 2017-12-08 21:47:54.425729832 +0100 @@ -24,7 +24,7 @@ %endif %bcond_with test Name: python-hypothesis -Version: 3.38.5 +Version: 3.40.1 Release: 0 Summary: A library for property based testing License: MPL-2.0 ++++++ hypothesis-3.38.5.tar.gz -> hypothesis-3.40.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/PKG-INFO new/hypothesis-3.40.1/PKG-INFO --- old/hypothesis-3.38.5/PKG-INFO 2017-11-23 20:40:32.000000000 +0100 +++ new/hypothesis-3.40.1/PKG-INFO 2017-12-04 10:02:53.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: hypothesis -Version: 3.38.5 +Version: 3.40.1 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.38.5/src/hypothesis/_settings.py new/hypothesis-3.40.1/src/hypothesis/_settings.py --- old/hypothesis-3.38.5/src/hypothesis/_settings.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/_settings.py 2017-12-04 10:02:20.000000000 +0100 @@ -517,6 +517,9 @@ hung_test = 6 """Checks if your tests have been running for a very long time.""" + large_base_example = 7 + """Checks if the natural example to shrink towards is very large.""" + @unique class Statistics(IntEnum): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/core.py new/hypothesis-3.40.1/src/hypothesis/core.py --- old/hypothesis-3.38.5/src/hypothesis/core.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/core.py 2017-12-04 10:02:20.000000000 +0100 @@ -388,7 +388,9 @@ class StateForActualGivenExecution(object): - def __init__(self, test_runner, search_strategy, test, settings, random): + def __init__( + self, test_runner, search_strategy, test, settings, random, had_seed + ): self.test_runner = test_runner self.search_strategy = search_strategy self.settings = settings @@ -400,12 +402,15 @@ self.__warned_deadline = False self.__existing_collector = None self.__test_runtime = None + self.__had_seed = had_seed self.test = test self.coverage_data = CoverageData() self.files_to_propagate = set() + self.used_examples_from_database = False + if settings.use_coverage and not IN_COVERAGE_TESTS: # pragma: no cover if Collector._collectors: self.hijack_collector(Collector._collectors[-1]) @@ -625,7 +630,10 @@ def run(self): # Tell pytest to omit the body of this function from tracebacks __tracebackhide__ = True - database_key = str_to_bytes(fully_qualified_name(self.test)) + if global_force_seed is None: + database_key = str_to_bytes(fully_qualified_name(self.test)) + else: + database_key = None self.start_time = time.time() global in_given runner = ConjectureRunner( @@ -647,6 +655,25 @@ sys.settrace(original_trace) note_engine_for_statistics(runner) run_time = time.time() - self.start_time + + self.used_examples_from_database = runner.used_examples_from_database + + if runner.used_examples_from_database: + if self.settings.derandomize: + note_deprecation( + 'In future derandomize will imply database=None, but your ' + 'test is currently using examples from the database. To ' + 'get the future behaviour, update your settings to ' + 'include database=None.' + ) + if self.__had_seed: + note_deprecation( + 'In future use of @seed will imply database=None in your ' + 'settings, but your test is currently using examples from ' + 'the database. To get the future behaviour, update your ' + 'settings for this test to include database=None.' + ) + timed_out = runner.exit_reason == ExitReason.timeout if runner.last_data is None: return @@ -827,12 +854,17 @@ try: state = StateForActualGivenExecution( - test_runner, search_strategy, test, settings, random) + test_runner, search_strategy, test, settings, random, + had_seed=wrapped_test._hypothesis_internal_use_seed + ) state.run() except BaseException: generated_seed = \ wrapped_test._hypothesis_internal_use_generated_seed - if generated_seed is not None: + if ( + generated_seed is not None and + not state.used_examples_from_database + ): if running_under_pytest: report(( 'You can add @seed(%(seed)d) to this test or run ' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/errors.py new/hypothesis-3.40.1/src/hypothesis/errors.py --- old/hypothesis-3.38.5/src/hypothesis/errors.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/errors.py 2017-12-04 10:02:20.000000000 +0100 @@ -174,6 +174,10 @@ """Raised when a test fails a preliminary healthcheck that occurs before execution.""" + def __init__(self, message, check): + super(FailedHealthCheck, self).__init__(message) + self.health_check = check + class HypothesisDeprecationWarning(HypothesisException, DeprecationWarning): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/internal/charmap.py new/hypothesis-3.40.1/src/hypothesis/internal/charmap.py --- old/hypothesis-3.38.5/src/hypothesis/internal/charmap.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/internal/charmap.py 2017-12-04 10:02:20.000000000 +0100 @@ -141,6 +141,82 @@ return tuple(result) +def _subtract_intervals(x, y): + """Set difference for lists of intervals. That is, returns a list of + intervals that bounds all values bounded by x that are not also bounded by + y. x and y are expected to be in sorted order. + + For example _subtract_intervals([(1, 10)], [(2, 3), (9, 15)]) would + return [(1, 1), (4, 8)], removing the values 2, 3, 9 and 10 from the + interval. + + """ + if not y: + return tuple(x) + x = list(map(list, x)) + i = 0 + j = 0 + result = [] + while i < len(x) and j < len(y): + # Iterate in parallel over x and y. j stays pointing at the smallest + # interval in the left hand side that could still overlap with some + # element of x at index >= i. + # Similarly, i is not incremented until we know that it does not + # overlap with any element of y at index >= j. + + xl, xr = x[i] + assert xl <= xr + yl, yr = y[j] + assert yl <= yr + + if yr < xl: + # The interval at y[j] is strictly to the left of the interval at + # x[i], so will not overlap with it or any later interval of x. + j += 1 + elif yl > xr: + # The interval at y[j] is strictly to the right of the interval at + # x[i], so all of x[i] goes into the result as no further intervals + # in y will intersect it. + result.append(x[i]) + i += 1 + elif yl <= xl: + if yr >= xr: + # x[i] is contained entirely in y[j], so we just skip over it + # without adding it to the result. + i += 1 + else: + # The beginning of x[i] is contained in y[j], so we update the + # left endpoint of x[i] to remove this, and increment j as we + # now have moved past it. Note that this is not added to the + # result as is, as more intervals from y may intersect it so it + # may need updating further. + x[i][0] = yr + 1 + j += 1 + else: + # yl > xl, so the left hand part of x[i] is not contained in y[j], + # so there are some values we should add to the result. + result.append((xl, yl - 1)) + + if yr + 1 <= xr: + # If y[j] finishes before x[i] does, there may be some values + # in x[i] left that should go in the result (or they may be + # removed by a later interval in y), so we update x[i] to + # reflect that and increment j because it no longer overlaps + # with any remaining element of x. + x[i][0] = yr + 1 + j += 1 + else: + # Every element of x[i] other than the initial part we have + # already added is contained in y[j], so we move to the next + # interval. + i += 1 + # Any remaining intervals in x do not overlap with any of y, as if they did + # we would not have incremented j to the end, so can be added to the result + # as they are. + result.extend(x[i:]) + return tuple(map(tuple, result)) + + def _intervals(s): """Return a tuple of intervals, covering the codepoints of characters in `s`. @@ -212,7 +288,8 @@ exclude_categories=(), include_categories=None, min_codepoint=None, max_codepoint=None, - include_characters='' + include_characters='', + exclude_characters='', ): """Return a tuple of intervals covering the codepoints for all characters that meet the critera (min_codepoint <= codepoint(c) <= max_codepoint and @@ -236,7 +313,11 @@ max_codepoint = sys.maxunicode catkey = _category_key(exclude_categories, include_categories) character_intervals = _intervals(include_characters or '') - qkey = (catkey, min_codepoint, max_codepoint, character_intervals) + exclude_intervals = _intervals(exclude_characters or '') + qkey = ( + catkey, min_codepoint, max_codepoint, + character_intervals, exclude_intervals + ) try: return limited_category_index_cache[qkey] except KeyError: @@ -250,5 +331,6 @@ )) result = tuple(result) result = _union_intervals(result, character_intervals) + result = _subtract_intervals(result, exclude_intervals) limited_category_index_cache[qkey] = result return result diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/internal/conjecture/data.py new/hypothesis-3.40.1/src/hypothesis/internal/conjecture/data.py --- old/hypothesis-3.38.5/src/hypothesis/internal/conjecture/data.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/internal/conjecture/data.py 2017-12-04 10:02:20.000000000 +0100 @@ -64,7 +64,6 @@ self.status = Status.VALID self.frozen = False self.intervals_by_level = [] - self.intervals = [] self.interval_stack = [] global global_test_counter self.testcounter = global_test_counter @@ -76,6 +75,7 @@ self.interesting_origin = None self.tags = set() self.draw_times = [] + self.__intervals = None def __assert_not_frozen(self, name): if self.frozen: @@ -157,12 +157,30 @@ if k != self.index: t = (k, self.index) self.intervals_by_level[self.level].append(t) - if not self.intervals or self.intervals[-1] != t: - self.intervals.append(t) def note_event(self, event): self.events.add(event) + @property + def intervals(self): + assert self.frozen + if self.__intervals is None: + intervals = set(self.blocks) + for l in self.intervals_by_level: + intervals.update(l) + for i in hrange(len(l) - 1): + if l[i][1] == l[i + 1][0]: + intervals.add((l[i][0], l[i + 1][1])) + for i in hrange(len(self.blocks) - 1): + intervals.add((self.blocks[i][0], self.blocks[i + 1][1])) + # Intervals are sorted as longest first, then by interval start. + self.__intervals = tuple(sorted( + set(intervals), + key=lambda se: (se[0] - se[1], se[0]) + )) + del self.intervals_by_level + return self.__intervals + def freeze(self): if self.frozen: assert isinstance(self.buffer, hbytes) @@ -170,15 +188,6 @@ self.frozen = True self.finish_time = benchmark_time() - # Intervals are sorted as longest first, then by interval start. - for l in self.intervals_by_level: - for i in hrange(len(l) - 1): - if l[i][1] == l[i + 1][0]: - self.intervals.append((l[i][0], l[i + 1][1])) - self.intervals = sorted( - set(self.intervals), - key=lambda se: (se[0] - se[1], se[0]) - ) self.buffer = hbytes(self.buffer) self.events = frozenset(self.events) del self._draw_bytes @@ -227,7 +236,6 @@ assert len(result) == n assert self.index == initial self.buffer.extend(result) - self.intervals.append((initial, self.index)) def draw_bytes(self, n): self.__assert_not_frozen('draw_bytes') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/internal/conjecture/engine.py new/hypothesis-3.40.1/src/hypothesis/internal/conjecture/engine.py --- old/hypothesis-3.38.5/src/hypothesis/internal/conjecture/engine.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/internal/conjecture/engine.py 2017-12-04 10:02:20.000000000 +0100 @@ -136,6 +136,8 @@ self.health_check_state = None + self.used_examples_from_database = False + def __tree_is_exhausted(self): return 0 in self.dead @@ -368,11 +370,11 @@ @property def secondary_key(self): - return b'.'.join((self.database_key, b"secondary")) + return b'.'.join((self.database_key, b'secondary')) @property def covering_key(self): - return b'.'.join((self.database_key, b"coverage")) + return b'.'.join((self.database_key, b'coverage')) def note_details(self, data): if data.status == Status.INTERESTING: @@ -629,9 +631,12 @@ node_index = node[data.buffer[i]] assert node_index not in self.dead node = self.tree[node_index] - except KeyError: - data.__hit_novelty = True - return result + except KeyError: # pragma: no cover + assert False, ( + 'This should be impossible. If you see this error, please ' + 'report it as a bug (ideally with a reproducible test ' + 'case).' + ) for i, b in enumerate(result): assert isinstance(b, int) @@ -728,6 +733,8 @@ extra.sort(key=sort_key) corpus.extend(extra) + self.used_examples_from_database = len(corpus) > 0 + for existing in corpus: self.last_data = ConjectureData.for_buffer(existing) try: @@ -747,11 +754,27 @@ if Phase.generate not in self.settings.phases: return - zero_data = ConjectureData( - max_length=self.settings.buffer_size, - draw_bytes=lambda data, n: self.__rewrite_for_novelty( - data, hbytes(n))) - self.test_function(zero_data) + zero_data = self.cached_test_function( + hbytes(self.settings.buffer_size)) + if zero_data.status == Status.OVERRUN or ( + zero_data.status == Status.VALID and + len(zero_data.buffer) * 2 > self.settings.buffer_size + ): + fail_health_check( + self.settings, + 'The smallest natural example for your test is extremely ' + 'large. This makes it difficult for Hypothesis to generate ' + 'good examples, especially when trying to reduce failing ones ' + 'at the end. Consider reducing the size of your data if it is ' + 'of a fixed size. You could also fix this by improving how ' + 'your data shrinks (see https://hypothesis.readthedocs.io/en/' + 'latest/data.html#shrinking for details), or by introducing ' + 'default values inside your strategy. e.g. could you replace ' + 'some arguments with their defaults by using ' + 'one_of(none(), some_complex_strategy)?', + HealthCheck.large_base_example + ) + if self.settings.perform_health_check: self.health_check_state = HealthCheckState() @@ -885,22 +908,29 @@ self.shrunk_examples.add(target) self.exit_with(ExitReason.finished) - def try_buffer_with_rewriting_from(self, initial_attempt, v): - initial_data = None + def cached_test_function(self, buffer): node_index = 0 - for c in initial_attempt: + for i in hrange(self.settings.buffer_size): + try: + c = self.forced[node_index] + except KeyError: + if i < len(buffer): + c = buffer[i] + else: + c = 0 try: node_index = self.tree[node_index][c] except KeyError: break node = self.tree[node_index] if isinstance(node, ConjectureData): - initial_data = node - break + return node + result = ConjectureData.for_buffer(buffer) + self.test_function(result) + return result - if initial_data is None: - initial_data = ConjectureData.for_buffer(initial_attempt) - self.test_function(initial_data) + def try_buffer_with_rewriting_from(self, initial_attempt, v): + initial_data = self.cached_test_function(initial_attempt) if initial_data.status == Status.INTERESTING: return initial_data is self.last_data diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/internal/healthcheck.py new/hypothesis-3.40.1/src/hypothesis/internal/healthcheck.py --- old/hypothesis-3.38.5/src/hypothesis/internal/healthcheck.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/internal/healthcheck.py 2017-12-04 10:02:20.000000000 +0100 @@ -35,4 +35,4 @@ 'If you want to disable just this health check, add %s ' 'to the suppress_health_check settings for this test.' ) % (label,) - raise FailedHealthCheck(message) + raise FailedHealthCheck(message, label) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/searchstrategy/regex.py new/hypothesis-3.40.1/src/hypothesis/searchstrategy/regex.py --- old/hypothesis-3.38.5/src/hypothesis/searchstrategy/regex.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/searchstrategy/regex.py 2017-12-04 10:02:20.000000000 +0100 @@ -232,11 +232,11 @@ def base_regex_strategy(regex, parsed=None): if parsed is None: - parsed = sre_parse.parse(regex.pattern) + parsed = sre_parse.parse(regex.pattern, flags=regex.flags) return clear_cache_after_draw(_strategy( parsed, Context(flags=regex.flags), - regex.pattern + isinstance(regex.pattern, text_type) )) @@ -246,7 +246,7 @@ is_unicode = isinstance(regex.pattern, text_type) - parsed = sre_parse.parse(regex.pattern) + parsed = sre_parse.parse(regex.pattern, flags=regex.flags) if not parsed: if is_unicode: @@ -294,7 +294,7 @@ return maybe_pad(regex, base, left_pad, right_pad) -def _strategy(codes, context, pattern): +def _strategy(codes, context, is_unicode): """Convert SRE regex parse tree to strategy that generates strings matching that regex represented by that parse tree. @@ -323,9 +323,9 @@ """ def recurse(codes): - return _strategy(codes, context, pattern) + return _strategy(codes, context, is_unicode) - if isinstance(pattern, text_type): + if is_unicode: empty = u'' to_char = hunichr else: @@ -387,7 +387,7 @@ if context.flags & re.IGNORECASE and \ re.match(c, c.swapcase(), re.IGNORECASE) is not None: blacklist |= set(c.swapcase()) - if isinstance(pattern, text_type): + if is_unicode: return st.characters(blacklist_characters=blacklist) else: return binary_char.filter(lambda c: c not in blacklist) @@ -395,7 +395,7 @@ elif code == sre.IN: # Regex '[abc0-9]' (set of characters) negate = value[0][0] == sre.NEGATE - if isinstance(pattern, text_type): + if is_unicode: builder = CharactersBuilder(negate, context.flags) else: builder = BytesBuilder(negate, context.flags) @@ -425,7 +425,7 @@ elif code == sre.ANY: # Regex '.' (any char) - if isinstance(pattern, text_type): + if is_unicode: if context.flags & re.DOTALL: return st.characters() return st.characters(blacklist_characters=u'\n') @@ -447,7 +447,7 @@ # This feature is available only in specific Python versions context.flags = (context.flags | value[1]) & ~value[2] - strat = _strategy(value[-1], context, pattern) + strat = _strategy(value[-1], context, is_unicode) context.flags = old_flags diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/searchstrategy/strings.py new/hypothesis-3.40.1/src/hypothesis/searchstrategy/strings.py --- old/hypothesis-3.38.5/src/hypothesis/searchstrategy/strings.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/searchstrategy/strings.py 2017-12-04 10:02:20.000000000 +0100 @@ -45,6 +45,7 @@ min_codepoint=min_codepoint, max_codepoint=max_codepoint, include_characters=whitelist_characters, + exclude_characters=blacklist_characters, ) if not intervals: raise InvalidArgument( @@ -55,28 +56,14 @@ self.whitelist_characters = set(whitelist_characters) else: self.whitelist_characters = set() - if blacklist_characters: - self.blacklist_characters = set( - b for b in blacklist_characters if ord(b) in self.intervals - ) - if (len(self.whitelist_characters) == 0 and - len(self.blacklist_characters) == len(self.intervals)): - raise InvalidArgument( - 'No valid characters in set' - ) - else: - self.blacklist_characters = set() self.zero_point = self.intervals.index_above(ord('0')) def do_draw(self, data): - while True: - i = integer_range( - data, 0, len(self.intervals) - 1, - center=self.zero_point, - ) - c = hunichr(self.intervals[i]) - if c not in self.blacklist_characters: - return c + i = integer_range( + data, 0, len(self.intervals) - 1, + center=self.zero_point, + ) + return hunichr(self.intervals[i]) class StringStrategy(MappedSearchStrategy): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/strategies.py new/hypothesis-3.40.1/src/hypothesis/strategies.py --- old/hypothesis-3.38.5/src/hypothesis/strategies.py 2017-11-23 20:40:05.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/strategies.py 2017-12-04 10:02:20.000000000 +0100 @@ -167,7 +167,11 @@ @cacheable def nothing(): """This strategy never successfully draws a value and will always reject on - an attempt to draw.""" + an attempt to draw. + + Examples from this strategy do not shrink (because there are none). + + """ return NOTHING @@ -180,6 +184,8 @@ :func:`builds(callable) <hypothesis.strategies.builds>` instead of ``just(callable())`` to get a fresh value each time. + Examples from this strategy do not shrink (because there is only one). + """ from hypothesis.searchstrategy.misc import JustStrategy @@ -188,7 +194,12 @@ @defines_strategy def none(): - """Return a strategy which only generates None.""" + """Return a strategy which only generates None. + + Examples from this strategy do not shrink (because there is only + one). + + """ return just(None) @@ -200,6 +211,17 @@ strategy arguments. In which case one_of(x) and one_of(\*x) are equivalent. + Examples from this strategy will generally shrink to ones that come from + strategies earlier in the list, then shrink according to behaviour of the + strategy that produced them. In order to get good shrinking behaviour, + try to put simpler strategies first. e.g. ``one_of(none(), text())`` is + better than ``one_of(text(), none())``. + + This is especially important when using recursive strategies. e.g. + ``x = st.deferred(lambda: st.none() | st.tuples(x, x))`` will shrink well, + but ``x = st.deferred(lambda: st.tuples(x, x) | st.none())`` will shrink + very badly indeed. + """ if len(args) == 1 and not isinstance(args[0], SearchStrategy): try: @@ -219,6 +241,9 @@ If min_value is not None then all values will be >= min_value. If max_value is not None then all values will be <= max_value + Examples from this strategy will shrink towards being positive (e.g. 1000 + is considered simpler than -1) and then towards zero. + """ check_valid_bound(min_value, 'min_value') @@ -264,7 +289,12 @@ @cacheable @defines_strategy def booleans(): - """Returns a strategy which generates instances of bool.""" + """Returns a strategy which generates instances of bool. + + Examples from this strategy will shrink towards False (i.e. + shrinking will try to replace True with False where possible). + + """ from hypothesis.searchstrategy.misc import BoolStrategy return BoolStrategy() @@ -286,6 +316,11 @@ Where not explicitly ruled out by the bounds, all of infinity, -infinity and NaN are possible values generated by this strategy. + Examples from this strategy have a complicated and hard to explain + shrinking behaviour, but it tries to improve "human readability". Finite + numbers will be preferred to infinity and infinity will be preferred to + NaN. + """ if allow_nan is None: @@ -381,7 +416,12 @@ @cacheable @defines_strategy_with_reusable_values def complex_numbers(): - """Returns a strategy that generates complex numbers.""" + """Returns a strategy that generates complex numbers. + + Examples from this strategy shrink by shrinking their component real + and imaginary parts. + + """ from hypothesis.searchstrategy.numbers import ComplexStrategy return ComplexStrategy( tuples(floats(), floats()) @@ -397,6 +437,8 @@ e.g. tuples(integers(), integers()) would generate a tuple of length two with both values an integer. + Examples from this strategy shrink by shrinking their component parts. + """ for arg in args: check_strategy(arg) @@ -416,6 +458,11 @@ :class:`~python:enum.Enum` objects. :class:`~python:enum.Flag` objects may also generate any combination of their members. + Examples from this strategy shrink by replacing them with values earlier in + the list. So e.g. sampled_from((10, 1)) will shrink by trying to replace + 1 values with 10, and sampled_from((1, 10)) will shrink by trying to + replace 10 values with 1. + """ from hypothesis.searchstrategy.misc import SampledFromStrategy from hypothesis.internal.conjecture.utils import check_sample @@ -459,6 +506,9 @@ when given a value drawn from elements. The resulting list will satisfy the condition that for i != j, unique_by(result[i]) != unique_by(result[j]). + Examples from this strategy shrink by trying to remove elements from the + list, and by shrinking each individual element of the list. + """ check_valid_sizes(min_size, average_size, max_size) if elements is None or (max_size is not None and max_size <= 0): @@ -527,6 +577,9 @@ are hashable until running the test, so you can define a strategy for sets of an unhashable type but it will fail at test time. + Examples from this strategy shrink by trying to remove elements from the + set, and by shrinking each individual element of the set. + """ return lists( elements=elements, min_size=min_size, average_size=average_size, @@ -587,6 +640,9 @@ instance of OrderedDict the keys will also be in the same order, otherwise the order is arbitrary. + Examples from this strategy shrink by shrinking each individual value in + the generated dictionary. + """ from hypothesis.searchstrategy.collections import FixedKeysDictStrategy check_type(dict, mapping, 'mapping') @@ -606,6 +662,9 @@ The size parameters have the same interpretation as for lists. + Examples from this strategy shrink by trying to remove keys from the + generated dictionary, and by shrinking each generated key and value. + """ check_valid_sizes(min_size, average_size, max_size) if max_size == 0: @@ -628,6 +687,8 @@ The result is iterable (the iterator will never terminate) and indexable. + Examples from this strategy shrink by trying to shrink each value drawn. + .. deprecated:: 3.15.0 Use :func:`data() <hypothesis.strategies.data>` instead. @@ -672,6 +733,8 @@ will be not be produced. Any overlap between ``whitelist_characters`` and ``blacklist_characters`` will raise an exception. + Examples from this strategy shrink towards smaller codepoints. + """ if ( min_codepoint is not None and max_codepoint is not None and @@ -732,6 +795,9 @@ min_size, max_size and average_size have the usual interpretations. + Examples from this strategy shrink towards shorter strings, and with the + characters in the text shrinking as per the alphabet strategy. + """ from hypothesis.searchstrategy.strings import StringStrategy if alphabet is None: @@ -779,6 +845,9 @@ string, while ``"."`` will return any string, and ``r"\\A.$"`` will return a single character optionally followed by a ``"\\n"``. + Examples from this strategy shrink towards shorter strings and lower + character values. + """ from hypothesis.searchstrategy.regex import regex_strategy return regex_strategy(regex) @@ -794,6 +863,9 @@ min_size, average_size and max_size have the usual interpretations. + Examples from this strategy shrink towards smaller strings and lower byte + values. + """ from hypothesis.searchstrategy.strings import BinaryStringStrategy, \ FixedSizeBytes @@ -812,7 +884,11 @@ @defines_strategy def randoms(): """Generates instances of Random (actually a Hypothesis specific - RandomWithSeed class which displays what it was initially seeded with)""" + RandomWithSeed class which displays what it was initially seeded with) + + Examples from this strategy shrink to seeds closer to zero. + + """ from hypothesis.searchstrategy.misc import RandomStrategy return RandomStrategy(integers()) @@ -839,6 +915,8 @@ a random number generator you should use the randoms() strategy which will give you one. + Examples from these strategy shrink to seeds closer to zero. + """ from hypothesis.control import cleanup import random @@ -870,6 +948,9 @@ value :const:`hypothesis.infer` as a keyword argument to builds, instead of a strategy for that argument to ``target``. + Examples from this strategy shrink by shrinking the argument values to + the target. + """ if infer in args: # Avoid an implementation nightmare juggling tuples and worse things @@ -1037,6 +1118,9 @@ values is no greater than max_denominator. Note that max_denominator must be None or a positive integer. + Examples from this strategy shrink towards smaller denominators, then + closer to zero. + """ min_value = try_convert(Fraction, min_value, 'min_value') max_value = try_convert(Fraction, max_value, 'max_value') @@ -1140,6 +1224,9 @@ If ``places`` is not None, all finite values drawn from the strategy will have that number of digits after the decimal place. + Examples from this strategy do not have a well defined shrink order but + try to maximize human readability when shrinking. + """ # Convert min_value and max_value to Decimal values, and validate args check_valid_integer(places) @@ -1232,6 +1319,10 @@ So e.g. ``False``, ``[True]``, ``[False, []]``, and ``[[[[True]]]]`` are all valid values to be drawn from that strategy. + Examples from this strategy shrink by trying to reduce the amount of + recursion and by shrinking according to the shrinking behaviour of base + and the result of extend. + """ from hypothesis.searchstrategy.recursive import RecursiveStrategy @@ -1241,7 +1332,12 @@ @defines_strategy def permutations(values): """Return a strategy which returns permutations of the collection - ``values``.""" + ``values``. + + Examples from this strategy shrink by trying to become closer to the + original order of values. + + """ from hypothesis.internal.conjecture.utils import integer_range values = list(values) @@ -1297,6 +1393,8 @@ :py:func:`sampled_from`. Ensure that simple values such as None or UTC are at the beginning of the list for proper minimisation. + Examples from this strategy shrink towards midnight on January 1st 2000. + """ # Why must bounds be naive? In principle, we could also write a strategy # that took aware bounds, but the API and validation is much harder. @@ -1335,7 +1433,11 @@ min_value=dt.date.min, max_value=dt.date.max, min_date=None, max_date=None, ): - """A strategy for dates between ``min_date`` and ``max_date``.""" + """A strategy for dates between ``min_date`` and ``max_date``. + + Examples from this strategy shrink towards January 1st 2000. + + """ from hypothesis.searchstrategy.datetime import DateStrategy check_type(dt.date, min_value, 'min_value') @@ -1359,6 +1461,9 @@ The ``timezones`` argument is handled as for :py:func:`datetimes`. + Examples from this strategy shrink towards midnight, with the timezone + component shrinking as for the strategy that provided it. + """ check_type(dt.time, min_value, 'min_value') check_type(dt.time, max_value, 'max_value') @@ -1382,7 +1487,11 @@ min_value=dt.timedelta.min, max_value=dt.timedelta.max, min_delta=None, max_delta=None ): - """A strategy for timedeltas between ``min_value`` and ``max_value``.""" + """A strategy for timedeltas between ``min_value`` and ``max_value``. + + Examples from this strategy shrink towards zero. + + """ from hypothesis.searchstrategy.datetime import TimedeltaStrategy check_type(dt.timedelta, min_value, 'min_value') @@ -1402,6 +1511,9 @@ :ref:`the full documentation for more details <composite-strategies>` about how to use this function. + Examples from this strategy shrink by shrinking the output of each draw + call. + """ from hypothesis.internal.reflection import define_function_signature @@ -1456,6 +1568,8 @@ >>> x = shared(s, key="hi") >>> y = shared(s, key="hi") + Examples from this strategy shrink as per their base strategy. + """ from hypothesis.searchstrategy.shared import SharedStrategy return SharedStrategy(base, key) @@ -1472,6 +1586,9 @@ Use :func:`data() <hypothesis.strategies.data>` with :func:`sampled_from() <hypothesis.strategies.sampled_from>` instead. + Examples from this strategy shrink by making each choice function return + an earlier value in the sequence passed to it. + """ from hypothesis.control import note, current_build_context from hypothesis.internal.conjecture.utils import choice, check_sample @@ -1524,6 +1641,8 @@ All returned values from this will be unique, so e.g. if you do ``lists(uuids())`` the resulting list will never contain duplicates. + Examples from this strategy don't have any meaningful shrink order. + """ from uuid import UUID if version not in (None, 1, 2, 3, 4, 5): @@ -1545,6 +1664,8 @@ If there is no current test runner and a default is provided, return that default. If no default is provided, raises InvalidArgument. + Examples from this strategy do not shrink (because there is only one). + """ class RunnerStrategy(SearchStrategy): @@ -1575,6 +1696,9 @@ See :ref:`the rest of the documentation <interactive-draw>` for more complete information. + Examples from this strategy do not shrink (because there is only one), + but the result of calls to each draw() call shrink as they normally would. + """ from hypothesis.control import note @@ -1684,6 +1808,9 @@ >>> b.example() (False, True) + Examples from this strategy shrink as they normally would from the strategy + returned by the definition. + """ from hypothesis.searchstrategy.deferred import DeferredStrategy return DeferredStrategy(definition) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis/version.py new/hypothesis-3.40.1/src/hypothesis/version.py --- old/hypothesis-3.38.5/src/hypothesis/version.py 2017-11-23 20:40:32.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis/version.py 2017-12-04 10:02:53.000000000 +0100 @@ -17,5 +17,5 @@ from __future__ import division, print_function, absolute_import -__version_info__ = (3, 38, 5) +__version_info__ = (3, 40, 1) __version__ = '.'.join(map(str, __version_info__)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-3.38.5/src/hypothesis.egg-info/PKG-INFO new/hypothesis-3.40.1/src/hypothesis.egg-info/PKG-INFO --- old/hypothesis-3.38.5/src/hypothesis.egg-info/PKG-INFO 2017-11-23 20:40:32.000000000 +0100 +++ new/hypothesis-3.40.1/src/hypothesis.egg-info/PKG-INFO 2017-12-04 10:02:53.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: hypothesis -Version: 3.38.5 +Version: 3.40.1 Summary: A library for property based testing Home-page: https://github.com/HypothesisWorks/hypothesis-python Author: David R. MacIver