code: def recursive_format(obj, mapping, ignore_missing=False):
      """Formats all strings within an object, using mapping
  
      Parameters
      ----------
      obj : string, tuple, list, or dict
          Object (leaves must be strings, regardless of type)
      mapping : dict
          format dictionary, maps keys to values
      ignore_missing : bool
          If True, will not throw exception if a string contains a tag not
          present in mapping, and will keep the tag instead.
  
      Returns
      -------
      string, tuple, list, or dict
          Object of the same type as obj, with strings formatted (tags replaced
          by their value)
  
      """
  
      def formatfn(x, mapping):
          fmt = SafeFormatter()
          formatz = (
              lambda x, m: x.format(**m)
              if not ignore_missing
              else fmt.format(x, **m)
          )
          options = re.compile(r"{([^}]+):([^}]+)}")
  
          def mysub(match):
              options, thing = match.group(1, 2)
              ret = ""
              if "a" in options:
                  if ignore_missing and thing not in mapping:
                      return match.group()
                  else:
                      word = formatz("{%s}" % thing, mapping)
                      ret += "%s " % add_article(word).split()[0]
              ret += "{%s}" % thing
              return ret
  
          x = options.sub(mysub, x)
          return formatz(x, mapping)
  
      return recursive_apply(obj, formatfn, mapping)
  
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 1 for calling a global function with example usage: recursive_format(obj, mapping, ignore_missing) and returns: recursive_apply, formatz, ret, match