code: def get_numeric_predicate_bounds(
      predicate: Predicate,
  ) -> ConstructivePredicate:
      """Shared logic for understanding numeric bounds.
  
      We then specialise this in the other functions below, to ensure that e.g.
      all the values are representable in the types that we're planning to generate
      so that the strategy validation doesn't complain.
      """
      unchanged = ConstructivePredicate.unchanged(predicate)
      if (
          isinstance(predicate, partial)
          and len(predicate.args) == 1
          and not predicate.keywords
      ):
          arg = predicate.args[0]
          if (
              (isinstance(arg, Decimal) and Decimal.is_snan(arg))
              or not isinstance(arg, (int, float, Fraction, Decimal))
              or math.isnan(arg)
          ):
              return unchanged
          options = {
              # We're talking about op(arg, x) - the reverse of our usual intuition!
              operator.lt: {
                  "min_value": arg,
                  "exclude_min": True,
              },  # lambda x: arg < x
              operator.le: {"min_value": arg},  # lambda x: arg <= x
              operator.eq: {
                  "min_value": arg,
                  "max_value": arg,
              },  # lambda x: arg == x
              operator.ge: {"max_value": arg},  # lambda x: arg >= x
              operator.gt: {
                  "max_value": arg,
                  "exclude_max": True,
              },  # lambda x: arg > x
          }
          if predicate.func in options:
              return ConstructivePredicate(
                  options[predicate.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
      # parsing it to an abstract syntax tree; if this fails for any reason we bail out
      # and fall back to standard rejection sampling (a running theme).
      try:
          if predicate.__name__ == "<lambda>":
              source = extract_lambda_source(predicate)
          else:
              source = inspect.getsource(predicate)
          tree: ast.AST = ast.parse(source)
      except Exception:
          return unchanged
  
      # Dig down to the relevant subtree - our tree is probably a Module containing
      # either a FunctionDef, or an Expr which in turn contains a lambda definition.
      while isinstance(tree, ast.Module) and len(tree.body) == 1:
          tree = tree.body[0]
      while isinstance(tree, ast.Expr):
          tree = tree.value
  
      if isinstance(tree, ast.Lambda) and len(tree.args.args) == 1:
          return numeric_bounds_from_ast(
              tree.body, tree.args.args[0].arg, unchanged
          )
      elif (
          isinstance(tree, ast.FunctionDef) and len(tree.args.args) == 1
      ):
          if len(tree.body) != 1 or not isinstance(
              tree.body[0], ast.Return
          ):
              # If the body of the function is anything but `return <expr>`,
              # i.e. as simple as a lambda, we can't process it (yet).
              return unchanged
          argname = tree.args.args[0].arg
          body = tree.body[0].value
          assert isinstance(body, ast.AST)
          return numeric_bounds_from_ast(body, argname, unchanged)
      return unchanged
  
imports: import ast
  import inspect
  import math
  import operator
  from decimal import Decimal
  from fractions import Fraction
  from functools import partial
  from typing import Any, Callable, Collection, Dict, NamedTuple, Optional, TypeVar
  from hypothesis.internal.compat import ceil, floor
  from hypothesis.internal.floats import next_down, next_up
  from hypothesis.internal.reflection import extract_lambda_source
label_desc: Use image node_id 5 for calling a global function with example usage: get_numeric_predicate_bounds(predicate) and returns: unchanged, numeric_bounds_from_ast, unchanged, ConstructivePredicate, unchanged, numeric_bounds_from_ast, unchanged