code: def find_used_variables(fn: Callable) -> VarCollection:
      """Finds all Objax variables which are used by a given callable.
  
      Args:
          fn: input function or callable.
  
      Returns:
          Variable collection with all variables used by input function.
      """
      if not hasattr(fn, "__code__"):
          raise ValueError(
              "Can not determine variables used by a function. Function does not have __code__ attribute."
          )
  
      try:
          src = inspect.getsource(fn)
      except OSError:
          raise ValueError(
              "Can not determine variables used by a function. Code of the function can not be retrieved."
          )
  
      src = dedent_block(src)
  
      main_node = ast.parse(src)
      main_node = main_node.body[0]
  
      if fn.__closure__:
          closure_vars = {
              name: cell.cell_contents
              for name, cell in zip(
                  fn.__code__.co_freevars, fn.__closure__
              )
          }
      else:
          closure_vars = {}
      analyzer = AnalyzeUserVariablesNodeTransformer(
          closure_vars=closure_vars, global_vars=fn.__globals__
      )
      analyzer.visit(main_node)
  
      return analyzer.vc
  
file_path: objax/objax/util/tracing.py
imports: import inspect
  import ast
  import re
  import tokenize
  from io import StringIO
  from typing import Callable
  from objax.variable import BaseVar, VarCollection
  from objax.module import Module
label_desc: Use image node_id 5 for calling a global function with example usage: find_used_variables(fn) and returns: analyzer