code: def assign_step_methods(
      model: Model,
      step: Optional[Union[Step, Sequence[Step]]] = None,
      methods: Optional[Sequence[Type[BlockedStep]]] = None,
      step_kwargs: Optional[Dict[str, Any]] = None,
  ) -> Union[Step, List[Step]]:
      """Assign model variables to appropriate step methods.
  
      Passing a specified model will auto-assign its constituent stochastic
      variables to step methods based on the characteristics of the variables.
      This function is intended to be called automatically from ``sample()``, but
      may be called manually. Each step method passed should have a
      ``competence()`` method that returns an ordinal competence value
      corresponding to the variable passed to it. This value quantifies the
      appropriateness of the step method for sampling the variable.
  
      Parameters
      ----------
      model : Model object
          A fully-specified model object.
      step : step function or iterable of step functions, optional
          One or more step functions that have been assigned to some subset of
          the model's parameters. Defaults to ``None`` (no assigned variables).
      methods : iterable of step method classes, optional
          The set of step methods from which the function may choose. Defaults
          to the main step methods provided by PyMC.
      step_kwargs : dict, optional
          Parameters for the samplers. Keys are the lower case names of
          the step method, values a dict of arguments.
  
      Returns
      -------
      methods : list
          List of step methods associated with the model's variables.
      """
      steps: List[Step] = []
      assigned_vars: Set[Variable] = set()
  
      if step is not None:
          if isinstance(step, (BlockedStep, CompoundStep)):
              steps.append(step)
          else:
              steps.extend(step)
          for step in steps:
              for var in step.vars:
                  if var not in model.value_vars:
                      raise ValueError(
                          f"{var} assigned to {step} sampler is not a value variable in the model. "
                          "You can use `util.get_value_vars_from_user_vars` to parse user provided variables."
                      )
              assigned_vars = assigned_vars.union(set(step.vars))
  
      # Use competence classmethods to select step methods for remaining
      # variables
      methods_list: List[Type[BlockedStep]] = list(
          methods or pm.STEP_METHODS
      )
      selected_steps: Dict[Type[BlockedStep], List] = {}
      model_logp = model.logp()
  
      for var in model.value_vars:
          if var not in assigned_vars:
              # determine if a gradient can be computed
              has_gradient = getattr(var, "dtype") not in discrete_types
              if has_gradient:
                  try:
                      tg.grad(model_logp, var)  # type: ignore
                  except (NotImplementedError, tg.NullTypeGradError):
                      has_gradient = False
  
              # select the best method
              rv_var = model.values_to_rvs[var]
              selected = max(
                  methods_list,
                  key=lambda method, var=rv_var, has_gradient=has_gradient: method._competence(  # type: ignore
                      var, has_gradient
                  ),
              )
              selected_steps.setdefault(selected, []).append(var)
  
      return instantiate_steppers(
          model, steps, selected_steps, step_kwargs
      )
  
imports: import logging
  import pickle
  import sys
  import time
  import warnings
  from typing import Any, Dict, Iterator, List, Literal, Mapping, Optional, Sequence, Set, Tuple, Type, Union, overload
  import numpy
  import pytensor.gradient
  from arviz import InferenceData, dict_to_dataset
  from arviz.data.base import make_attrs
  from fastprogress.fastprogress import progress_bar
  from pytensor.graph.basic import Variable
  from typing_extensions import Protocol, TypeAlias
  import pymc
  from pymc.backends import RunType, TraceOrBackend, init_traces
  from pymc.backends.arviz import coords_and_dims_for_inferencedata, find_constants, find_observations
  from pymc.backends.base import IBaseTrace, MultiTrace, _choose_chains
  from pymc.blocking import DictToArrayBijection
  from pymc.exceptions import SamplingError
  from pymc.initial_point import PointType, StartDict, make_initial_point_fns_per_chain
  from pymc.model import Model, modelcontext
  from pymc.sampling.parallel import Draw, _cpu_count
  from pymc.sampling.population import _sample_population
  from pymc.stats.convergence import log_warning_stats, log_warnings, run_convergence_checks
  from pymc.step_methods import NUTS, CompoundStep
  from pymc.step_methods.arraystep import BlockedStep, PopulationArrayStepShared
  from pymc.step_methods.hmc import quadpotential
  from pymc.util import RandomSeed, RandomState, _get_seeds_per_chain, drop_warning_stat, get_untransformed_name, is_transformed_name
  from pymc.vartypes import discrete_types
label_desc: Use image node_id 2 for calling a global function with example usage: assign_step_methods(model, step, methods, step_kwargs) and returns: instantiate_steppers