code: def recursive_apply(obj, fn, *args, **kwargs):
      """Recursively applies a function to an obj
  
      Parameters
      ----------
      obj : string, tuple, list, or dict
          Object (leaves must be strings, regardless of type)
      fn : function
          function to be applied to the leaves (strings)
  
      Returns
      -------
      string, tuple, list, or dict
          Object of the same type as obj, with fn applied to leaves
  
      """
      if type(obj) in [str, bytes]:
          return fn(obj, *args, **kwargs)  # obj.format(**(mapping))
      elif type(obj) == tuple:
          return tuple(recursive_apply(list(obj), fn, *args, **kwargs))
      elif type(obj) == list:
          return [recursive_apply(o, fn, *args, **kwargs) for o in obj]
      elif type(obj) == dict:
          return {
              k: recursive_apply(v, fn, *args, **kwargs)
              for k, v in obj.items()
          }
      else:
          return fn(obj, *args, **kwargs)
  
imports: import collections
  import itertools
  import string
  import numpy
  import re
  import copy
  import os
  import json
  import munch
  import pickle
  import csv
  from .viewer.template_editor import TemplateEditor
  from .multilingual import multilingual_params, get_language_code
label_desc: Use image node_id 2 for calling a global function with example usage: recursive_apply(obj, fn) and returns: fn, tuple, unknown, unknown, fn