docs: def decorators(self):
          """Get all the decorators of all the option methods in the class
  
          http://stackoverflow.com/questions/5910703/ specifically, I used this
          answer http://stackoverflow.com/a/9580006
          """
          res = collections.defaultdict(list)
          mmap = {}
  
          def get_val(na, default=None):
              ret = None
              if isinstance(na, ast.Num):
                  repr_n = repr(na.n)
                  val = na.n
                  vtype = float if '.' in repr_n else int
                  ret = vtype(val)
  
              elif isinstance(na, ast.Str):
                  ret = str(na.s)
  
              elif isinstance(na, ast.Name):
                  # http://stackoverflow.com/questions/12700893/
                  ret = getattr(builtins, na.id, None)
                  if not ret:
                      ret = na.id
                      if ret == 'True':
                          ret = True
                      elif ret == 'False':
                          ret = False
  
              elif isinstance(na, ast.Dict):
                  if na.keys:
                      ret = {get_val(na_[0]): get_val(na_[1]) for na_ in zip(na.keys, na.values)}
                  else:
                      ret = {}
  
              elif isinstance(na, (ast.List, ast.Tuple)):
                  if na.elts:
                      ret = [get_val(na_) for na_ in na.elts]
                  else:
                      ret = []
  
                  if isinstance(na, ast.Tuple):
                      ret = tuple(ret)
  
              else:
                  ret = default
  
              return ret
  
          def is_super(childnode, parentnode):
              """returns true if child node has a super() call to parent node"""
              ret = False
              for n in childnode.body:
                  if not isinstance(n, ast.Expr): continue
  
                  try:
                      func = n.value.func
                      func_name = func.attr
                      if func_name == parentnode.name:
                          ret = isinstance(func.value, ast.Call)
                          break
  
                  except AttributeError as e:
                      ret = False
  
              return ret
  
          def visit_FunctionDef(node):
              """ https://docs.python.org/2/library/ast.html#ast.NodeVisitor.visit """
  
              add_decs = True
              if node.name in res:
                  add_decs = is_super(mmap[node.name], node)
  
              mmap[node.name] = node
  
              if add_decs:
                  for n in node.decorator_list:
                      d = {}
                      name = ''
                      args = []
                      kwargs = {}
                      if isinstance(n, ast.Call):
                          name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id
                          for an in n.args:
                              args.append(get_val(an))
  
                          for an in n.keywords:
                              kwargs[an.arg] = get_val(an.value)
  
                      else:
                          name = n.attr if isinstance(n, ast.Attribute) else n.id
  
                      d = {
                          "name": name,
                          "args": args,
                          "kwargs": kwargs
                      }
                      m = self.module
                      decor = getattr(m, name, None)
                      if decor:
                          d["decorator"] = decor
  
                      #res[node.name].append((name, args, kwargs))
                      res[node.name].append(self.decorator_class(**d))
  
          node_iter = ast.NodeVisitor()
          node_iter.visit_FunctionDef = visit_FunctionDef
          for target_cls in inspect.getmro(self.controller_class):
              if target_cls == Controller: break
              node_iter.visit(ast.parse(inspect.getsource(target_cls)))
  
          return res