docs: def getclosurevars(func):
      """
      Get the mapping of free variables to their current values.
  
      Returns a named tuple of dicts mapping the current nonlocal, global
      and builtin references as seen by the body of the function. A final
      set of unbound names that could not be resolved is also provided.
  
      Note:
          Modified function from the Python 3.5 inspect standard library module
  
          Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
          2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation; All Rights
          Reserved"
  
          See also py-cloud-compute-cannon/NOTICES.
      """
      if inspect.ismethod(func):
          func = func.__func__
  
      elif not inspect.isroutine(func):
          raise TypeError("'{!r}' is not a Python function".format(func))
  
      # AMVMOD: deal with python 2 builtins that don't define these
      code = getattr(func, '__code__', None)
      closure = getattr(func, '__closure__', None)
      co_names = getattr(code, 'co_names', ())
      glb = getattr(func, '__globals__', {})
  
      # Nonlocal references are named in co_freevars and resolved
      # by looking them up in __closure__ by positional index
      if closure is None:
          nonlocal_vars = {}
      else:
          nonlocal_vars = {var: cell.cell_contents
                           for var, cell in zip(code.co_freevars, func.__closure__)}
  
      # Global and builtin references are named in co_names and resolved
      # by looking them up in __globals__ or __builtins__
      global_ns = glb
      builtin_ns = global_ns.get("__builtins__", builtins.__dict__)
      if inspect.ismodule(builtin_ns):
          builtin_ns = builtin_ns.__dict__
      global_vars = {}
      builtin_vars = {}
      unbound_names = set()
      for name in co_names:
          if name in ("None", "True", "False"):
              # Because these used to be builtins instead of keywords, they
              # may still show up as name references. We ignore them.
              continue
          try:
              global_vars[name] = global_ns[name]
          except KeyError:
              try:
                  builtin_vars[name] = builtin_ns[name]
              except KeyError:
                  unbound_names.add(name)
  
      return {'nonlocal': nonlocal_vars,
              'global': global_vars,
              'builtin': builtin_vars,
              'unbound': unbound_names}