diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-12 09:19:01 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-12 09:56:20 +0300 |
commit | 965ccc1b60627c70d0cedc79d0a738dc6bcd03a5 (patch) | |
tree | 2ef73c31348105b0bd00977d490323b7869b25aa | |
parent | 1823321f2d789b9ae9ff875a4861d998c6071ed9 (diff) | |
download | ydb-965ccc1b60627c70d0cedc79d0a738dc6bcd03a5.tar.gz |
Intermediate changes
15 files changed, 86 insertions, 112 deletions
diff --git a/contrib/python/hypothesis/py3/.dist-info/METADATA b/contrib/python/hypothesis/py3/.dist-info/METADATA index b6eca63e8f..2a7e253367 100644 --- a/contrib/python/hypothesis/py3/.dist-info/METADATA +++ b/contrib/python/hypothesis/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: hypothesis -Version: 6.90.0 +Version: 6.91.0 Summary: A library for property-based testing Home-page: https://hypothesis.works Author: David R. MacIver and Zac Hatfield-Dodds @@ -26,6 +26,7 @@ Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Education :: Testing diff --git a/contrib/python/hypothesis/py3/hypothesis/control.py b/contrib/python/hypothesis/py3/hypothesis/control.py index eb1768c565..c49dba2954 100644 --- a/contrib/python/hypothesis/py3/hypothesis/control.py +++ b/contrib/python/hypothesis/py3/hypothesis/control.py @@ -11,6 +11,7 @@ import math from collections import defaultdict from typing import NoReturn, Union +from weakref import WeakKeyDictionary from hypothesis import Verbosity, settings from hypothesis._settings import note_deprecation @@ -168,18 +169,38 @@ def note(value: str) -> None: report(value) -def event(value: str) -> None: - """Record an event that occurred this test. Statistics on number of test +def event(value: str, payload: Union[str, int, float] = "") -> None: + """Record an event that occurred during this test. Statistics on the number of test runs with each event will be reported at the end if you run Hypothesis in statistics reporting mode. - Events should be strings or convertible to them. + Event values should be strings or convertible to them. If an optional + payload is given, it will be included in the string for :ref:`statistics`. """ context = _current_build_context.value if context is None: raise InvalidArgument("Cannot make record events outside of a test") - context.data.note_event(value) + payload = _event_to_string(payload, (str, int, float)) + context.data.events[_event_to_string(value)] = payload + + +_events_to_strings: WeakKeyDictionary = WeakKeyDictionary() + + +def _event_to_string(event, allowed_types=str): + if isinstance(event, allowed_types): + return event + try: + return _events_to_strings[event] + except (KeyError, TypeError): + pass + result = str(event) + try: + _events_to_strings[event] = result + except TypeError: + pass + return result def target(observation: Union[int, float], *, label: str = "") -> Union[int, float]: diff --git a/contrib/python/hypothesis/py3/hypothesis/core.py b/contrib/python/hypothesis/py3/hypothesis/core.py index 1c4cf9e144..b2298418c8 100644 --- a/contrib/python/hypothesis/py3/hypothesis/core.py +++ b/contrib/python/hypothesis/py3/hypothesis/core.py @@ -80,10 +80,10 @@ from hypothesis.internal.conjecture.junkdrawer import ensure_free_stackframes from hypothesis.internal.conjecture.shrinker import sort_key from hypothesis.internal.entropy import deterministic_PRNG from hypothesis.internal.escalation import ( + InterestingOrigin, current_pytest_item, escalate_hypothesis_internal_error, format_exception, - get_interesting_origin, get_trimmed_traceback, ) from hypothesis.internal.healthcheck import fail_health_check @@ -970,7 +970,7 @@ class StateForActualGivenExecution: self.failed_normally = True - interesting_origin = get_interesting_origin(e) + interesting_origin = InterestingOrigin.from_exception(e) if trace: # pragma: no cover # Trace collection is explicitly disabled under coverage. self.explain_traces[interesting_origin].add(trace) @@ -1037,7 +1037,9 @@ class StateForActualGivenExecution: info = falsifying_example.extra_information fragments = [] - ran_example = ConjectureData.for_buffer(falsifying_example.buffer) + ran_example = runner.new_conjecture_data_for_buffer( + falsifying_example.buffer + ) ran_example.slice_comments = falsifying_example.slice_comments assert info.__expected_exception is not None try: diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py index 7eb5fbe080..2f086bf04f 100644 --- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py +++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py @@ -20,7 +20,6 @@ from typing import ( Callable, Dict, FrozenSet, - Hashable, Iterable, Iterator, List, @@ -1367,7 +1366,7 @@ class ConjectureData: self.testcounter = global_test_counter global_test_counter += 1 self.start_time = time.perf_counter() - self.events: "Union[Set[Hashable], FrozenSet[Hashable]]" = set() + self.events: Dict[str, Union[str, int, float]] = {} self.forced_indices: "Set[int]" = set() self.interesting_origin: Optional[InterestingOrigin] = None self.draw_times: "List[float]" = [] @@ -1615,10 +1614,6 @@ class ConjectureData: self.observer.kill_branch() - def note_event(self, event: Hashable) -> None: - assert isinstance(self.events, set) - self.events.add(event) - @property def examples(self) -> Examples: assert self.frozen @@ -1643,7 +1638,6 @@ class ConjectureData: self.frozen = True self.buffer = bytes(self.buffer) - self.events = frozenset(self.events) self.observer.conclude_test(self.status, self.interesting_origin) def draw_bits(self, n: int, *, forced: Optional[int] = None) -> int: @@ -1729,7 +1723,7 @@ class ConjectureData: def mark_invalid(self, why: Optional[str] = None) -> NoReturn: if why is not None: - self.note_event(why) + self.events["invalid because"] = why self.conclude_test(Status.INVALID) def mark_overrun(self) -> NoReturn: diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py index 6944e127de..c5d33480e2 100644 --- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py +++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py @@ -15,7 +15,6 @@ from contextlib import contextmanager from datetime import timedelta from enum import Enum from random import Random, getrandbits -from weakref import WeakKeyDictionary import attr @@ -101,8 +100,6 @@ class ConjectureRunner: self.statistics = {} self.stats_per_test_case = [] - self.events_to_strings = WeakKeyDictionary() - self.interesting_examples = {} # We use call_count because there may be few possible valid_examples. self.first_bug_found_at = None @@ -209,7 +206,9 @@ class ConjectureRunner: "status": data.status.name.lower(), "runtime": data.finish_time - data.start_time, "drawtime": math.fsum(data.draw_times), - "events": sorted({self.event_to_string(e) for e in data.events}), + "events": sorted( + k if v == "" else f"{k}: {v}" for k, v in data.events.items() + ), } self.stats_per_test_case.append(call_stats) self.__data_cache[data.buffer] = data.as_result() @@ -1055,20 +1054,6 @@ class ConjectureRunner: self.__data_cache[buffer] = result return result - def event_to_string(self, event): - if isinstance(event, str): - return event - try: - return self.events_to_strings[event] - except (KeyError, TypeError): - pass - result = str(event) - try: - self.events_to_strings[event] = result - except TypeError: - pass - return result - def passing_buffers(self, prefix=b""): """Return a collection of bytestrings which cause the test to pass. diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/escalation.py b/contrib/python/hypothesis/py3/hypothesis/internal/escalation.py index 605ea52e97..9261d2aefc 100644 --- a/contrib/python/hypothesis/py3/hypothesis/internal/escalation.py +++ b/contrib/python/hypothesis/py3/hypothesis/internal/escalation.py @@ -11,10 +11,11 @@ import contextlib import os import sys +import textwrap import traceback from inspect import getframeinfo from pathlib import Path -from typing import Dict +from typing import Dict, NamedTuple, Optional, Type import hypothesis from hypothesis.errors import ( @@ -105,32 +106,46 @@ def get_trimmed_traceback(exception=None): return tb -def get_interesting_origin(exception): +class InterestingOrigin(NamedTuple): # The `interesting_origin` is how Hypothesis distinguishes between multiple # failures, for reporting and also to replay from the example database (even # if report_multiple_bugs=False). We traditionally use the exception type and # location, but have extracted this logic in order to see through `except ...:` # blocks and understand the __cause__ (`raise x from y`) or __context__ that # first raised an exception as well as PEP-654 exception groups. - tb = get_trimmed_traceback(exception) - if tb is None: + exc_type: Type[BaseException] + filename: Optional[str] + lineno: Optional[int] + context: "InterestingOrigin | tuple[()]" + group_elems: "tuple[InterestingOrigin, ...]" + + def __str__(self) -> str: + ctx = "" + if self.context: + ctx = textwrap.indent(f"\ncontext: {self.context}", prefix=" ") + group = "" + if self.group_elems: + chunks = "\n ".join(str(x) for x in self.group_elems) + group = textwrap.indent(f"\nchild exceptions:\n {chunks}", prefix=" ") + return f"{self.exc_type.__name__} at {self.filename}:{self.lineno}{ctx}{group}" + + @classmethod + def from_exception(cls, exception: BaseException, /) -> "InterestingOrigin": filename, lineno = None, None - else: - filename, lineno, *_ = traceback.extract_tb(tb)[-1] - return ( - type(exception), - filename, - lineno, - # Note that if __cause__ is set it is always equal to __context__, explicitly - # to support introspection when debugging, so we can use that unconditionally. - get_interesting_origin(exception.__context__) if exception.__context__ else (), - # We distinguish exception groups by the inner exceptions, as for __context__ - tuple( - map(get_interesting_origin, exception.exceptions) + if tb := get_trimmed_traceback(exception): + filename, lineno, *_ = traceback.extract_tb(tb)[-1] + return cls( + type(exception), + filename, + lineno, + # Note that if __cause__ is set it is always equal to __context__, explicitly + # to support introspection when debugging, so we can use that unconditionally. + cls.from_exception(exception.__context__) if exception.__context__ else (), + # We distinguish exception groups by the inner exceptions, as for __context__ + tuple(map(cls.from_exception, exception.exceptions)) if isinstance(exception, BaseExceptionGroup) - else [] - ), - ) + else (), + ) current_pytest_item = DynamicVariable(None) diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/lazyformat.py b/contrib/python/hypothesis/py3/hypothesis/internal/lazyformat.py deleted file mode 100644 index 9a728c6380..0000000000 --- a/contrib/python/hypothesis/py3/hypothesis/internal/lazyformat.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis/ -# -# Copyright the Hypothesis Authors. -# Individual contributors are listed in AUTHORS.rst and the git log. -# -# 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 https://mozilla.org/MPL/2.0/. - - -class lazyformat: - """A format string that isn't evaluated until it's needed.""" - - def __init__(self, format_string, *args): - self.__format_string = format_string - self.__args = args - - def __str__(self): - return self.__format_string % self.__args - - def __eq__(self, other): - return ( - isinstance(other, lazyformat) - and self.__format_string == other.__format_string - and self.__args == other.__args - ) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return hash(self.__format_string) diff --git a/contrib/python/hypothesis/py3/hypothesis/stateful.py b/contrib/python/hypothesis/py3/hypothesis/stateful.py index e70c805815..39ce653981 100644 --- a/contrib/python/hypothesis/py3/hypothesis/stateful.py +++ b/contrib/python/hypothesis/py3/hypothesis/stateful.py @@ -402,7 +402,7 @@ class RuleBasedStateMachine(metaclass=StateMachineMeta): settings = Settings(deadline=None, suppress_health_check=list(HealthCheck)) def runTest(self): - run_state_machine_as_test(cls) + run_state_machine_as_test(cls, settings=self.settings) runTest.is_hypothesis_test = True diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/datetime.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/datetime.py index abf77c5026..f2c33fa8c5 100644 --- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/datetime.py +++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/datetime.py @@ -163,8 +163,10 @@ class DatetimeStrategy(SearchStrategy): try: return replace_tzinfo(dt.datetime(**result), timezone=tz) except (ValueError, OverflowError): - msg = "Failed to draw a datetime between %r and %r with timezone from %r." - data.mark_invalid(msg % (self.min_value, self.max_value, self.tz_strat)) + data.mark_invalid( + f"Failed to draw a datetime between {self.min_value!r} and " + f"{self.max_value!r} with timezone from {self.tz_strat!r}." + ) @defines_strategy(force_reusable_values=True) diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/recursive.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/recursive.py index 7709b45460..cf7add9538 100644 --- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/recursive.py +++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/recursive.py @@ -12,7 +12,6 @@ import threading from contextlib import contextmanager from hypothesis.errors import InvalidArgument -from hypothesis.internal.lazyformat import lazyformat from hypothesis.internal.reflection import get_pretty_function_description from hypothesis.internal.validation import check_type from hypothesis.strategies._internal.strategies import ( @@ -112,13 +111,7 @@ class RecursiveStrategy(SearchStrategy): with self.limited_base.capped(self.max_leaves): return data.draw(self.strategy) except LimitReached: - # Workaround for possible coverage bug - this branch is definitely - # covered but for some reason is showing up as not covered. - if count == 0: # pragma: no branch - data.note_event( - lazyformat( - "Draw for %r exceeded max_leaves and had to be retried", - self, - ) - ) + if count == 0: + msg = f"Draw for {self!r} exceeded max_leaves and had to be retried" + data.events[msg] = "" count += 1 diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/strategies.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/strategies.py index 6b68a1d353..caf8d1ba9a 100644 --- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/strategies.py +++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/strategies.py @@ -43,7 +43,6 @@ from hypothesis.internal.conjecture.utils import ( combine_labels, ) from hypothesis.internal.coverage import check_function -from hypothesis.internal.lazyformat import lazyformat from hypothesis.internal.reflection import ( get_pretty_function_description, is_identity_function, @@ -550,7 +549,7 @@ class SampledFromStrategy(SearchStrategy): if element is not filter_not_satisfied: return element if not known_bad_indices: - FilteredStrategy.note_retried(self, data) + data.events[f"Retried draw from {self!r} to satisfy filter"] = "" known_bad_indices.add(i) # If we've tried all the possible elements, give up now. @@ -940,9 +939,6 @@ class FilteredStrategy(SearchStrategy[Ex]): data.mark_invalid(f"Aborted test because unable to satisfy {self!r}") raise NotImplementedError("Unreachable, for Mypy") - def note_retried(self, data): - data.note_event(lazyformat("Retried draw from %r to satisfy filter", self)) - def do_filtered_draw(self, data): for i in range(3): start_index = data.index @@ -954,7 +950,7 @@ class FilteredStrategy(SearchStrategy[Ex]): else: data.stop_example(discard=True) if i == 0: - self.note_retried(data) + data.events[f"Retried draw from {self!r} to satisfy filter"] = "" # This is to guard against the case where we consume no data. # As long as we consume data, we'll eventually pass or raise. # But if we don't this could be an infinite loop. diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py index d979081415..aba2e457a0 100644 --- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py +++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py @@ -275,7 +275,7 @@ def is_annotated_type(thing): def get_constraints_filter_map(): - if at := sys.modules.get("annotated_types"): # pragma: no branch + if at := sys.modules.get("annotated_types"): return { # Due to the order of operator.gt/ge/lt/le arguments, order is inversed: at.Gt: lambda constraint: partial(operator.lt, constraint.gt), @@ -290,7 +290,7 @@ def get_constraints_filter_map(): def _get_constraints(args: Tuple[Any, ...]) -> Iterator["at.BaseMetadata"]: - if at := sys.modules.get("annotated_types"): # pragma: no branch + if at := sys.modules.get("annotated_types"): for arg in args: if isinstance(arg, at.BaseMetadata): yield arg diff --git a/contrib/python/hypothesis/py3/hypothesis/vendor/tlds-alpha-by-domain.txt b/contrib/python/hypothesis/py3/hypothesis/vendor/tlds-alpha-by-domain.txt index 5402c8d9cb..98deba4045 100644 --- a/contrib/python/hypothesis/py3/hypothesis/vendor/tlds-alpha-by-domain.txt +++ b/contrib/python/hypothesis/py3/hypothesis/vendor/tlds-alpha-by-domain.txt @@ -1,4 +1,4 @@ -# Version 2023111800, Last Updated Sat Nov 18 07:07:01 2023 UTC +# Version 2023112500, Last Updated Sat Nov 25 07:07:01 2023 UTC AAA AARP ABB @@ -1234,7 +1234,6 @@ VIVO VLAANDEREN VN VODKA -VOLKSWAGEN VOLVO VOTE VOTING diff --git a/contrib/python/hypothesis/py3/hypothesis/version.py b/contrib/python/hypothesis/py3/hypothesis/version.py index 158c609209..9b0a5e2eb1 100644 --- a/contrib/python/hypothesis/py3/hypothesis/version.py +++ b/contrib/python/hypothesis/py3/hypothesis/version.py @@ -8,5 +8,5 @@ # v. 2.0. If a copy of the MPL was not distributed with this file, You can # obtain one at https://mozilla.org/MPL/2.0/. -__version_info__ = (6, 90, 0) +__version_info__ = (6, 91, 0) __version__ = ".".join(map(str, __version_info__)) diff --git a/contrib/python/hypothesis/py3/ya.make b/contrib/python/hypothesis/py3/ya.make index b9abaef8bd..100509362e 100644 --- a/contrib/python/hypothesis/py3/ya.make +++ b/contrib/python/hypothesis/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(6.90.0) +VERSION(6.91.0) LICENSE(MPL-2.0) @@ -82,7 +82,6 @@ PY_SRCS( hypothesis/internal/floats.py hypothesis/internal/healthcheck.py hypothesis/internal/intervalsets.py - hypothesis/internal/lazyformat.py hypothesis/internal/reflection.py hypothesis/internal/scrutineer.py hypothesis/internal/validation.py |