docs: def __package_app(tasks_pkg, dist_dir, custom_main=None, extra_data=None):
      """
      Packages the `tasks_pkg` (as zip) to `dist_dir`. Also copies the 'main' python file to
      `dist_dir`, to be submitted to spark. Same for `extra_data`.
  
      Parameters
      ----------
      tasks_pkg (str): Path to the python package containing tasks
      dist_dir (str): Path to the directory where the packaged code should be stored
      custom_main (str): Path to a custom 'main' python file.
      extra_data (List[str]): List containing paths to files/directories that should also be packaged
          and submitted to spark
      """
      logging.info('Packaging application')
  
      # Package tasks
      tasks_dir_splits = os.path.split(os.path.realpath(tasks_pkg))
      shutil.make_archive(os.path.join(dist_dir, 'tasks'),
                          'zip',
                          tasks_dir_splits[0],
                          tasks_dir_splits[1])
  
      # Package main.py
      if custom_main is None:
          from . import _main
          main_path = _main.__file__
          if main_path[-3:] == 'pyc':
              main_path = main_path[:-1]
          shutil.copy(os.path.realpath(main_path),
                      os.path.join(dist_dir, 'main.py'))
      else:
          shutil.copy(os.path.realpath(custom_main),
                      os.path.join(dist_dir, 'main.py'))
  
      # Package _framework
      shutil.make_archive(os.path.join(dist_dir, '_framework'),
                          'zip',
                          os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..'),
                          './sparklanes/')
  
      # Package extra data
      if extra_data:
          for dat in extra_data:
              real_path = os.path.realpath(dat)
              target = os.path.join(dist_dir, os.path.split(real_path)[1])
              if os.path.isfile(real_path):
                  shutil.copy(real_path, target)
              elif os.path.isdir(real_path):
                  shutil.copytree(real_path, target)
              else:
                  raise IOError('File `%s` not found at `%s`.' % (dat, real_path))