code: def normalize(
      base_name,
      test_function,
      *,
      required_successes=100,
      allowed_to_update=False,
      max_dfas=10,
      random=None,
  ):
      """Attempt to ensure that this test function successfully normalizes - i.e.
      whenever it declares a test case to be interesting, we are able
      to shrink that to the same interesting test case (which logically should
      be the shortlex minimal interesting test case, though we may not be able
      to detect if it is).
  
      Will run until we have seen ``required_successes`` many interesting test
      cases in a row normalize to the same value.
  
      If ``allowed_to_update`` is True, whenever we fail to normalize we will
      learn a new DFA-based shrink pass that allows us to make progress. Any
      learned DFAs will be written back into the learned DFA file at the end
      of this function. If ``allowed_to_update`` is False, this will raise an
      error as soon as it encounters a failure to normalize.
  
      Additionally, if more than ``max_dfas` DFAs are required to normalize
      this test function, this function will raise an error - it's essentially
      designed for small patches that other shrink passes don't cover, and
      if it's learning too many patches then you need a better shrink pass
      than this can provide.
      """
      # Need import inside the function to avoid circular imports
      from hypothesis.internal.conjecture.engine import (
          BUFFER_SIZE,
          ConjectureRunner,
      )
  
      runner = ConjectureRunner(
          test_function,
          settings=settings(
              database=None, suppress_health_check=list(HealthCheck)
          ),
          ignore_limits=True,
          random=random,
      )
  
      seen = set()
  
      dfas_added = 0
  
      found_interesting = False
      consecutive_successes = 0
      failures_to_find_interesting = 0
      while consecutive_successes < required_successes:
          attempt = runner.cached_test_function(b"", extend=BUFFER_SIZE)
          if attempt.status < Status.INTERESTING:
              failures_to_find_interesting += 1
              assert (
                  found_interesting
                  or failures_to_find_interesting <= 1000
              ), "Test function seems to have no interesting test cases"
              continue
  
          found_interesting = True
  
          target = attempt.interesting_origin
  
          def shrinking_predicate(d):
              return (
                  d.status == Status.INTERESTING
                  and d.interesting_origin == target
              )
  
          if target not in seen:
              seen.add(target)
              runner.shrink(attempt, shrinking_predicate)
              continue
  
          previous = fully_shrink(
              runner,
              runner.interesting_examples[target],
              shrinking_predicate,
          )
          current = fully_shrink(runner, attempt, shrinking_predicate)
  
          if current.buffer == previous.buffer:
              consecutive_successes += 1
              continue
  
          consecutive_successes = 0
  
          if not allowed_to_update:
              raise FailedToNormalise(
                  f"Shrinker failed to normalize {previous.buffer!r} to "
                  f"{current.buffer!r} and we are not allowed to learn new DFAs."
              )
  
          if dfas_added >= max_dfas:
              raise FailedToNormalise(
                  f"Test function is too hard to learn: Added {dfas_added} "
                  "DFAs and still not done."
              )
  
          dfas_added += 1
  
          new_dfa = learn_a_new_dfa(
              runner,
              previous.buffer,
              current.buffer,
              shrinking_predicate,
          )
  
          name = (
              base_name
              + "-"
              + hashlib.sha256(repr(new_dfa).encode()).hexdigest()[:10]
          )
  
          # If there is a name collision this DFA should already be being
          # used for shrinking, so we should have already been able to shrink
          # v further.
          assert name not in SHRINKING_DFAS
          SHRINKING_DFAS[name] = new_dfa
  
      if dfas_added > 0:
          # We've learned one or more DFAs in the course of normalising, so now
          # we update the file to record those for posterity.
          update_learned_dfas()
  
file_path: catboost/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/dfas.py
imports: import hashlib
  import math
  from itertools import islice
  from pathlib import Path
  from hypothesis import HealthCheck, settings
  from hypothesis.errors import HypothesisException
  from hypothesis.internal.conjecture.data import ConjectureResult, Status
  from hypothesis.internal.conjecture.dfa.lstar import LStar
  from hypothesis.internal.conjecture.shrinking.learned_dfas import SHRINKING_DFAS, __file__
label_desc: Use image node_id 4 for calling a global function with example usage: normalize(base_name, test_function) and returns: unknown