summaryrefslogtreecommitdiffstats
path: root/contrib/python/hypothesis
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-11-17 15:36:50 +0300
committerrobot-piglet <[email protected]>2025-11-17 16:16:43 +0300
commit587164cd7213f9ff3d1feaad777b7804dc6c342f (patch)
tree500e13a84fba80a8cc47767045ffd71d89ee8c63 /contrib/python/hypothesis
parentbe8dd0630b1dee6c76c7c7566cf6903eac0cbb9b (diff)
Intermediate changes
commit_hash:31e1caa5b7ddaf9cddf874715cad6425dc610f22
Diffstat (limited to 'contrib/python/hypothesis')
-rw-r--r--contrib/python/hypothesis/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py4
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/filtering.py30
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py46
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/version.py2
-rw-r--r--contrib/python/hypothesis/py3/ya.make2
6 files changed, 68 insertions, 18 deletions
diff --git a/contrib/python/hypothesis/py3/.dist-info/METADATA b/contrib/python/hypothesis/py3/.dist-info/METADATA
index dd1a0d3f396..fa535de452c 100644
--- a/contrib/python/hypothesis/py3/.dist-info/METADATA
+++ b/contrib/python/hypothesis/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: hypothesis
-Version: 6.143.0
+Version: 6.144.0
Summary: A library for property-based testing
Author-email: "David R. MacIver and Zac Hatfield-Dodds" <[email protected]>
License-Expression: MPL-2.0
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py
index 1a20c61220f..a363cdd047a 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/engine.py
@@ -317,6 +317,7 @@ class ConjectureRunner:
# We use call_count because there may be few possible valid_examples.
self.first_bug_found_at: int | None = None
self.last_bug_found_at: int | None = None
+ self.first_bug_found_time: float = math.inf
self.shrunk_examples: set[InterestingOrigin] = set()
self.health_check_state: HealthCheckState | None = None
@@ -660,6 +661,7 @@ class ConjectureRunner:
self.last_bug_found_at = self.call_count
if self.first_bug_found_at is None:
self.first_bug_found_at = self.call_count
+ self.first_bug_found_time = time.monotonic()
else:
if sort_key(data.nodes) < sort_key(existing.nodes):
self.shrinks += 1
@@ -1073,9 +1075,11 @@ class ConjectureRunner:
return True
# Users who disable shrinking probably want to exit as fast as possible.
# If we've found a bug and won't report more than one, stop looking.
+ # If we first saw a bug more than 10 seconds ago, stop looking.
elif (
Phase.shrink not in self.settings.phases
or not self.settings.report_multiple_bugs
+ or time.monotonic() - self.first_bug_found_time > 10
):
return False
assert isinstance(self.first_bug_found_at, int)
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py b/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py
index c92d7be83a6..155e67e74a9 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py
@@ -37,6 +37,12 @@ from hypothesis.internal.floats import next_down, next_up
from hypothesis.internal.lambda_sources import lambda_description
from hypothesis.internal.reflection import get_pretty_function_description
+try:
+ # new in 3.14
+ from functools import Placeholder # type: ignore
+except ImportError:
+ Placeholder = object()
+
Ex = TypeVar("Ex")
Predicate = Callable[[Ex], bool]
@@ -221,10 +227,26 @@ def get_numeric_predicate_bounds(predicate: Predicate) -> ConstructivePredicate:
unchanged = ConstructivePredicate.unchanged(predicate)
if (
isinstance(predicate, partial)
- and len(predicate.args) == 1
and not predicate.keywords
+ and (
+ len(predicate.args) == 1
+ or (predicate.args[0] is Placeholder and len(predicate.args) == 2)
+ )
):
- arg = predicate.args[0]
+ if len(predicate.args) == 1:
+ arg = predicate.args[0]
+ func = predicate.func
+ else: # pragma: no cover # Python 3.14+ only
+ assert predicate.args[0] is Placeholder
+ arg = predicate.args[1]
+ func = { # reverses the table below; eq is unchanged
+ operator.lt: operator.gt,
+ operator.le: operator.ge,
+ operator.ge: operator.le,
+ operator.gt: operator.lt,
+ }.get(predicate.func, predicate.func)
+ assert func not in (min_len, max_len) # sanity-check; these are private
+
if (
(isinstance(arg, Decimal) and Decimal.is_snan(arg))
or not isinstance(arg, (int, float, Fraction, Decimal))
@@ -242,8 +264,8 @@ def get_numeric_predicate_bounds(predicate: Predicate) -> ConstructivePredicate:
min_len: {"min_value": arg, "len": True},
max_len: {"max_value": arg, "len": True},
}
- if predicate.func in options:
- return ConstructivePredicate(options[predicate.func], None)
+ if func in options:
+ return ConstructivePredicate(options[func], None)
# This section is a little complicated, but stepping through with comments should
# help to clarify it. We start by finding the source code for our predicate and
diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py
index 62bd40e13a4..187be5c78f1 100644
--- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py
+++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py
@@ -1424,11 +1424,13 @@ def _from_type(thing: type[Ex]) -> SearchStrategy[Ex]:
# Taken from `Lib/typing.py` and modified:
def _get_typeddict_qualifiers(key, annotation_type):
qualifiers = []
+ annotations = []
while True:
annotation_origin = types.extended_get_origin(annotation_type)
if annotation_origin is Annotated:
if annotation_args := get_args(annotation_type):
annotation_type = annotation_args[0]
+ annotations.extend(annotation_args[1:])
else:
break
elif annotation_origin in types.RequiredTypes:
@@ -1442,6 +1444,8 @@ def _from_type(thing: type[Ex]) -> SearchStrategy[Ex]:
annotation_type = _get_annotation_arg(key, annotation_type)
else:
break
+ if annotations:
+ annotation_type = Annotated[(annotation_type, *annotations)]
return set(qualifiers), annotation_type
# The __optional_keys__ attribute may or may not be present, but if there's no
@@ -1693,24 +1697,44 @@ def fractions(
def _as_finite_decimal(
- value: Real | str | None, name: str, allow_infinity: bool | None
+ value: Real | str | None, name: str, allow_infinity: bool | None, places: int | None
) -> Decimal | None:
"""Convert decimal bounds to decimals, carefully."""
assert name in ("min_value", "max_value")
if value is None:
return None
+ old = value
+ if isinstance(value, Fraction):
+ value = Context(prec=places).divide(value.numerator, value.denominator)
+ if old != value:
+ raise InvalidArgument(
+ f"{old!r} cannot be exactly represented as a decimal with {places=}"
+ )
if not isinstance(value, Decimal):
with localcontext(Context()): # ensure that default traps are enabled
value = try_convert(Decimal, value, name)
assert isinstance(value, Decimal)
+ if value.is_nan():
+ raise InvalidArgument(f"Invalid {name}={value!r}")
+
+ # If you are reading this conditional, I am so sorry. I did my best.
+ finitude_old = value if isinstance(old, str) else old
+ if math.isfinite(finitude_old) != math.isfinite(value) or (
+ value.is_finite() and Fraction(str(old)) != Fraction(str(value))
+ ):
+ note_deprecation(
+ f"{old!r} cannot be exactly represented as a decimal with {places=}",
+ since="2025-11-02",
+ has_codemod=False,
+ stacklevel=1,
+ )
+
if value.is_finite():
return value
- if value.is_infinite() and (value < 0 if "min" in name else value > 0):
- if allow_infinity or allow_infinity is None:
- return None
- raise InvalidArgument(f"{allow_infinity=}, but {name}={value!r}")
- # This could be infinity, quiet NaN, or signalling NaN
- raise InvalidArgument(f"Invalid {name}={value!r}")
+ assert value.is_infinite()
+ if (value < 0 if "min" in name else value > 0) and allow_infinity is not False:
+ return None
+ raise InvalidArgument(f"{allow_infinity=}, but {name}={value!r}")
@cacheable
@@ -1747,8 +1771,8 @@ def decimals(
check_valid_integer(places, "places")
if places is not None and places < 0:
raise InvalidArgument(f"{places=} may not be negative")
- min_value = _as_finite_decimal(min_value, "min_value", allow_infinity)
- max_value = _as_finite_decimal(max_value, "max_value", allow_infinity)
+ min_value = _as_finite_decimal(min_value, "min_value", allow_infinity, places)
+ max_value = _as_finite_decimal(max_value, "max_value", allow_infinity, places)
check_valid_interval(min_value, max_value, "min_value", "max_value")
if allow_infinity and (None not in (min_value, max_value)):
raise InvalidArgument("Cannot allow infinity between finite bounds")
@@ -1793,12 +1817,12 @@ def decimals(
strat = fractions(min_value, max_value).map(fraction_to_decimal)
# Compose with sampled_from for infinities and NaNs as appropriate
special: list[Decimal] = []
- if allow_nan or (allow_nan is None and (None in (min_value, max_value))):
- special.extend(map(Decimal, ("NaN", "-NaN", "sNaN", "-sNaN")))
if allow_infinity or (allow_infinity is None and max_value is None):
special.append(Decimal("Infinity"))
if allow_infinity or (allow_infinity is None and min_value is None):
special.append(Decimal("-Infinity"))
+ if allow_nan or (allow_nan is None and (None in (min_value, max_value))):
+ special.extend(map(Decimal, ("NaN", "-NaN", "sNaN", "-sNaN")))
return strat | (sampled_from(special) if special else nothing())
diff --git a/contrib/python/hypothesis/py3/hypothesis/version.py b/contrib/python/hypothesis/py3/hypothesis/version.py
index c18a9cfb689..f9daf2ead6b 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, 143, 0)
+__version_info__ = (6, 144, 0)
__version__ = ".".join(map(str, __version_info__))
diff --git a/contrib/python/hypothesis/py3/ya.make b/contrib/python/hypothesis/py3/ya.make
index ed19ada6367..c392b732384 100644
--- a/contrib/python/hypothesis/py3/ya.make
+++ b/contrib/python/hypothesis/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(6.143.0)
+VERSION(6.144.0)
LICENSE(MPL-2.0)