code: def _base_step_decorator(decotype, *args, **kwargs):
      """
      Decorator prototype for all step decorators. This function gets specialized
      and imported for all decorators types by _import_plugin_decorators().
      """
      if args:
          # No keyword arguments specified for the decorator, e.g. @foobar.
          # The first argument is the function to be decorated.
          func = args[0]
          if not hasattr(func, "is_step"):
              raise BadStepDecoratorException(decotype.name, func)
  
          # if `allow_multiple` is not `True` then only one decorator type is allowed per step
          if (
              decotype.name in [deco.name for deco in func.decorators]
              and not decotype.allow_multiple
          ):
              raise DuplicateStepDecoratorException(decotype.name, func)
          else:
              func.decorators.append(
                  decotype(attributes=kwargs, statically_defined=True)
              )
  
          return func
      else:
          # Keyword arguments specified, e.g. @foobar(a=1, b=2).
          # Return a decorator function that will get the actual
          # function to be decorated as the first argument.
          def wrap(f):
              return _base_step_decorator(decotype, f, **kwargs)
  
          return wrap
  
imports: from functools import partial
  import json
  import re
  import os
  import sys
  from .flowspec import FlowSpec
  from .exception import MetaflowInternalError, MetaflowException, InvalidDecoratorAttribute
  from metaflow._vendor import click
label_desc: Use image node_id 4 for calling a global function with example usage: _base_step_decorator(decotype) and returns: func, wrap, _base_step_decorator