diff options
| author | robot-piglet <[email protected]> | 2026-05-26 22:26:18 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2026-05-26 22:58:12 +0300 |
| commit | e7e308065735cdaf5dcb4348187dd43168e37d8e (patch) | |
| tree | 7ca0f751b640460e979d1f8b032447e5147d5c16 /contrib/python | |
| parent | 540c8c5d478736aed0a81bb7bf30da5aad866197 (diff) | |
Intermediate changes
commit_hash:4c139857684c7144eeea0ba5f8e53572276a86fc
Diffstat (limited to 'contrib/python')
4 files changed, 70 insertions, 3 deletions
diff --git a/contrib/python/hypothesis/py3/.dist-info/METADATA b/contrib/python/hypothesis/py3/.dist-info/METADATA index adb3b9f3fb3..4bb4b728a00 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.152.5 +Version: 6.152.6 Summary: The property-based testing library for Python 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/shrinker.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py index 15a4c1bad61..5b283bb7515 100644 --- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py +++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py @@ -9,9 +9,11 @@ # obtain one at https://mozilla.org/MPL/2.0/. import math +import unicodedata from collections import defaultdict from collections.abc import Callable, Iterator, Sequence from dataclasses import dataclass +from functools import lru_cache from typing import ( TYPE_CHECKING, Any, @@ -89,6 +91,34 @@ def sort_key(nodes: Sequence[ChoiceNode]) -> tuple[int, tuple[int, ...]]: ) +@lru_cache(maxsize=4096) +def _natural_simpler_chars(c, intervals): + """Return single-char replacements for ``c`` derived from natural text + transformations - case mapping (upper, lower, casefold) and unicode + decomposition (NFD, NFKD). We take each individual character of the + transformed form so that e.g. ``ß`` can shrink to ``s`` via casefold + even though the full case-folded form is two characters. + + Only candidates which are in ``intervals`` and which have a strictly + smaller index in shrink order than ``c`` are returned, sorted by that + shrink-order index. Callers must pass a single character that is itself + in ``intervals``. + """ + candidates: set[str] = set() + for form in ("NFKD", "NFD"): + candidates.update(unicodedata.normalize(form, c)) + for transformed in (c.upper(), c.lower(), c.casefold()): + candidates.update(transformed) + candidates.discard(c) + original_idx = intervals.index_from_char_in_shrink_order(c) + result = sorted( + (intervals.index_from_char_in_shrink_order(cand), cand) + for cand in candidates + if cand in intervals + ) + return [cand for idx, cand in result if idx < original_idx] + + @dataclass(slots=True, frozen=False) class ShrinkPass: function: Any @@ -321,6 +351,7 @@ class Shrinker: ShrinkPass(self.redistribute_numeric_pairs), ShrinkPass(self.lower_integers_together), ShrinkPass(self.lower_duplicated_characters), + ShrinkPass(self.normalize_unicode_chars), ] # Because the shrinker is also used to `pareto_optimise` in the target phase, @@ -1549,6 +1580,42 @@ class Shrinker: ), ) + def normalize_unicode_chars(self, chooser): + """For string nodes, try replacing characters with simpler equivalents + from natural text transformations: unicode decomposition (NFD, NFKD) + and case mapping. For example, an accented latin letter is reduced + to its base form, a ligature is reduced to its first base character, + a mathematical alphanumeric symbol is reduced to its plain ascii + counterpart, and a lowercase letter is replaced with its uppercase + form (which has a smaller shrink-order index in the default + alphabet). + + The codepoint shrinker is binary-search based, so it can get stuck on + a high codepoint whose simpler equivalents aren't reached by halving + / shifting / masking. This pass directly tries the natural simpler + forms one character at a time. + """ + node = chooser.choose( + self.nodes, + lambda n: n.type == "string" + and any( + _natural_simpler_chars(c, n.constraints["intervals"]) for c in n.value + ), + ) + intervals = node.constraints["intervals"] + i = chooser.choose( + range(len(node.value)), + lambda j: bool(_natural_simpler_chars(node.value[j], intervals)), + ) + for replacement in _natural_simpler_chars(node.value[i], intervals): + new_value = node.value[:i] + replacement + node.value[i + 1 :] + if self.consider_new_nodes( + self.nodes[: node.index] + + (node.copy(with_value=new_value),) + + self.nodes[node.index + 1 :] + ): + return + def minimize_nodes(self, nodes): choice_type = nodes[0].type value = nodes[0].value diff --git a/contrib/python/hypothesis/py3/hypothesis/version.py b/contrib/python/hypothesis/py3/hypothesis/version.py index bb420c28aea..5994b35ebfc 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, 152, 5) +__version_info__ = (6, 152, 6) __version__ = ".".join(map(str, __version_info__)) diff --git a/contrib/python/hypothesis/py3/ya.make b/contrib/python/hypothesis/py3/ya.make index 584f7300bd7..084316a1c7a 100644 --- a/contrib/python/hypothesis/py3/ya.make +++ b/contrib/python/hypothesis/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(6.152.5) +VERSION(6.152.6) LICENSE(MPL-2.0) |
