old_contents: from redbeaver.exceptions import InfiniteLoopError
  
  
  def calc(fn_name, eq):
      if not hasattr(calc, 'tree'):
          calc.tree = []
  
      if fn_name in calc.tree:
          raise InfiniteLoopError('Infinite loop on "%s" arg.\nCalc tree: %s' % (fn_name, calc.tree))
      else:
          calc.tree.append(fn_name)
  
      if fn_name in eq.eq_registry:
          params = {}
          for arg in eq.eq_registry[fn_name]['args']:
              if arg in eq.params:
                  params[arg] = eq.params.get(arg)
              else:
                  params[arg] = calc(arg, eq)
  
          res = eq.eq_registry[fn_name]['fn'](**params)
      else:
          raise Exception('Undefined fn: %s' % (fn_name,))
  
      return res
  
new_contents: from redbeaver.exceptions import InfiniteLoopError
  
  
  class Calc(object):
      u"""
      formula calculation
      """
  
      def __init__(self, formula):
          self.formula = formula
  
      def __call__(self, fn_name, iterate_param=None):
          self.__tree = []
          self.__iterate_params = [iterate_param] or iterate_param
  
          return self.__calc(fn_name)
  
      def __calc(self, fn_name):
          u"""
          calculation
          """
          if fn_name in self.__tree:
              raise InfiniteLoopError('Infinite loop on "%s" arg.\nCalc tree: %s' % (fn_name, self.__tree))
          else:
              self.__tree.append(fn_name)
  
          if fn_name in self.formula.get_fns():
              return self.__calc_fn(fn_name, *self.__calc_params(fn_name))
          else:
              raise Exception('Undefined fn: %s' % (fn_name,))
  
      def __calc_params(self, fn_name):
          u"""
          function params mapping
          """
          params = {}
          iterate_param = None
  
          for arg in self.formula.get_fn_by_name(fn_name)[self.formula.__ARGS_KEY__][1]:
              if arg in self.formula.get_params():
                  params[arg] = self.formula.get_param(arg)
              else:
                  params[arg] = self.__calc(arg)
  
              if arg in self.__iterate_params:
                  iterate_param = arg
                  self.__iterate_params.append(fn_name)
  
          return params, iterate_param
  
      def __calc_fn(self, fn_name, params, iterate_param):
          u"""
          function calculation
          """
          if iterate_param:
              try:
                  res = []
                  for arg in params[iterate_param]:
                      params[iterate_param] = arg
                      res.append(self.formula.get_fn_by_name(fn_name)[self.formula.__CALL_KEY__][1](**params))
              except TypeError:
                  raise TypeError('iterate_param_ %s=%s is not iterable' % (iterate_param, params[iterate_param]))
          else:
              res = self.formula.get_fn_by_name(fn_name)[self.formula.__CALL_KEY__][1](**params)
  
          self.formula({fn_name: res})
  
          return res
  
      def get_tree(self):
          return self.__tree
  
      def get_iterate_params(self):
          return self.__iterate_params
  
subject: make class Calc from fn calc