docstr: Facade for pytest.mark.parametrize.
  
  Automatically derives argument names from the callable which in our
  case is always a method on a class with positional arguments.
  
  ids for parameter sets are derived using an optional template.
docstr_tok: ["Facade","for","pytest.mark.parametrize",".","Automatically","derives","argument","names","from","the","callable","which","in","our","case","is","always","a","method","on","a","class","with","positional","arguments",".","ids","for","parameter","sets","are","derived","using","an","optional","template","."]
code: def combinations(self, *arg_sets, **kw):
      """Facade for pytest.mark.parametrize.
  
      Automatically derives argument names from the callable which in our
      case is always a method on a class with positional arguments.
  
      ids for parameter sets are derived using an optional template.
  
      """
      from sqlalchemy.testing import exclusions
  
      if len(arg_sets) == 1 and hasattr(arg_sets[0], "__next__"):
          arg_sets = list(arg_sets[0])
  
      argnames = kw.pop("argnames", None)
  
      def _filter_exclusions(args):
          result = []
          gathered_exclusions = []
          for a in args:
              if isinstance(a, exclusions.compound):
                  gathered_exclusions.append(a)
              else:
                  result.append(a)
  
          return result, gathered_exclusions
  
      id_ = kw.pop("id_", None)
  
      tobuild_pytest_params = []
      has_exclusions = False
      if id_:
          _combination_id_fns = self._combination_id_fns
  
          # because itemgetter is not consistent for one argument vs.
          # multiple, make it multiple in all cases and use a slice
          # to omit the first argument
          _arg_getter = operator.itemgetter(
              0,
              *[
                  idx
                  for idx, char in enumerate(id_)
                  if char in ("n", "r", "s", "a")
              ],
          )
          fns = [
              (operator.itemgetter(idx), _combination_id_fns[char])
              for idx, char in enumerate(id_)
              if char in _combination_id_fns
          ]
  
          for arg in arg_sets:
              if not isinstance(arg, tuple):
                  arg = (arg,)
  
              fn_params, param_exclusions = _filter_exclusions(arg)
  
              parameters = _arg_getter(fn_params)[1:]
  
              if param_exclusions:
                  has_exclusions = True
  
              tobuild_pytest_params.append(
                  (
                      parameters,
                      param_exclusions,
                      "-".join(
                          comb_fn(getter(arg))
                          for getter, comb_fn in fns
                      ),
                  )
              )
  
      else:
          for arg in arg_sets:
              if not isinstance(arg, tuple):
                  arg = (arg,)
  
              fn_params, param_exclusions = _filter_exclusions(arg)
  
              if param_exclusions:
                  has_exclusions = True
  
              tobuild_pytest_params.append(
                  (fn_params, param_exclusions, None)
              )
  
      pytest_params = []
      for parameters, param_exclusions, id_ in tobuild_pytest_params:
          if has_exclusions:
              parameters += (param_exclusions,)
  
          param = pytest.param(*parameters, id=id_)
          pytest_params.append(param)
  
      def decorate(fn):
          if inspect.isclass(fn):
              if has_exclusions:
                  raise NotImplementedError(
                      "exclusions not supported for class level combinations"
                  )
              if "_sa_parametrize" not in fn.__dict__:
                  fn._sa_parametrize = []
              fn._sa_parametrize.append((argnames, pytest_params))
              return fn
          else:
              _fn_argnames = inspect.getfullargspec(fn).args[1:]
              if argnames is None:
                  _argnames = _fn_argnames
              else:
                  _argnames = re.split(r", *", argnames)
  
              if has_exclusions:
                  existing_exl = sum(
                      1
                      for n in _fn_argnames
                      if n.startswith("_exclusions")
                  )
                  current_exclusion_name = f"_exclusions_{existing_exl}"
                  _argnames += [current_exclusion_name]
  
                  @_pytest_fn_decorator
                  def check_exclusions(fn, *args, **kw):
                      _exclusions = args[-1]
                      if _exclusions:
                          exlu = exclusions.compound().add(*_exclusions)
                          fn = exlu(fn)
                      return fn(*args[:-1], **kw)
  
                  fn = check_exclusions(
                      fn,
                      add_positional_parameters=(
                          current_exclusion_name,
                      ),
                  )
  
              return pytest.mark.parametrize(_argnames, pytest_params)(
                  fn
              )
  
      return decorate
  
imports: from __future__ import annotations
  import argparse
  import collections
  from functools import update_wrapper
  import inspect
  import itertools
  import operator
  import os
  import re
  import sys
  from typing import TYPE_CHECKING
  import uuid
  import pytest
label_desc: Use image node_id 4 for calling the PytestFixtureFunctions obj's underlying member method code with example usage: obj.combinations() and returns: decorate, result,  gathered_exclusions, fn, pytest, fn