docstr: generating following rolling tasks for `task` until test_end
  
  Parameters
  ----------
  task : dict
      Qlib task format
  test_end : pd.Timestamp
      the latest rolling task includes `test_end`
  
  Returns
  -------
  List[dict]:
      the following tasks of `task`(`task` itself is excluded)
docstr_tok: ["generating","following","rolling","tasks","for","`","task","`","until","test_end","Parameters","--","--","--","--","--","task",":","dict","Qlib","task","format","test_end",":","pd.Timestamp","the","latest","rolling","task","includes","`","test_end","`","Returns","--","--","--","-","List","[","dict","]",":","the","following","tasks","of","`","task","`","(","`","task","`","itself","is","excluded",")"]
code: def gen_following_tasks(
      self, task: dict, test_end: pd.Timestamp
  ) -> List[dict]:
      """
      generating following rolling tasks for `task` until test_end
  
      Parameters
      ----------
      task : dict
          Qlib task format
      test_end : pd.Timestamp
          the latest rolling task includes `test_end`
  
      Returns
      -------
      List[dict]:
          the following tasks of `task`(`task` itself is excluded)
      """
      prev_seg = task["dataset"]["kwargs"]["segments"]
      while True:
          segments = {}
          try:
              for k, seg in prev_seg.items():
                  # decide how to shift
                  # expanding only for train data, the segments size of test data and valid data won't change
                  if k == self.train_key and self.rtype == self.ROLL_EX:
                      rtype = self.ta.SHIFT_EX
                  else:
                      rtype = self.ta.SHIFT_SD
                  # shift the segments data
                  segments[k] = self.ta.shift(
                      seg, step=self.step, rtype=rtype
                  )
              if segments[self.test_key][0] > test_end:
                  break
          except KeyError:
              # We reach the end of tasks
              # No more rolling
              break
  
          prev_seg = segments
          t = self.task_copy_func(
              task
          )  # deepcopy is necessary to avoid replace task inplace
          self._update_task_segs(t, segments)
          yield t
  
imports: import abc
  import copy
  import pandas
  from typing import Dict, List, Union, Callable
  from qlib.utils import transform_end_date
  from .utils import TimeAdjuster
label_desc: Use image node_id 3 for calling the RollingGen obj's underlying member method code with example usage: obj.gen_following_tasks(task, test_end) without return types