docs: def unarchive(self, experiments=None, archive=None, complete=False,
                    project_data=False, replace_project_config=False, root=None,
                    projectname=None, fmt=None, force=False, **kwargs):
          """
          Extract archived experiments
  
          Parameters
          ----------
          experiments: list of str
              The experiments to extract. If None the current experiment is used
          archive: str
              The path to an archive to extract the experiments from. If None,
              we assume that the path to the archive has been stored in the
              configuration when using the :meth:`archive` command
          complete: bool
              If True, archives are extracted completely, not only the experiment
              (implies ``project_data = True``)
          project_data: bool
              If True, the data for the project is extracted as well
          replace_project_config: bool
              If True and the project does already exist in the configuration, it
              is updated with what is stored in the archive
          root: str
              An alternative root directory to use. Otherwise the experiment will
              be exctracted to
  
              1. the root directory specified in the configuration files
                 (if the project exists in it) and `replace_project_config` is
                 False
              2. the root directory as stored in the archive
          projectname: str
              The projectname to use. If None, use the one specified in the
              archive
          fmt: { 'gztar' | 'bztar' | 'tar' | 'zip' }
              The format of the archive. If None, it is inferred
          force: bool
              If True, force to overwrite the configuration of all experiments
              from what is stored in `archive`. Otherwise, the configuration of
              the experiments in `archive` are only used if missing in the
              current configuration
          """
          def extract_file(path):
              if atype == 'zip':
                  return file_obj.open(path)
              else:
                  return file_obj.extractfile(path)
  
          self.app_main(**kwargs)
  
          logger = self.logger
  
          project_config = None
  
          all_exps = self.config.experiments
          all_projects = self.config.projects
          # ---- set archive
          # if archive is None, check for the archives listed in `experiments`
          # and raise an error if one has not been archived yet or if they belong
          # to different files
          if archive is None:
              # ---- set experiments
              # if experiments is None, use the current experiment. If complete
              # is True, this will be replaced below
              if experiments is None:
                  experiments = [self.experiment]
              archives = list(filter(utils.isstring,
                                     map(self.is_archived, experiments)))
              if len(archives) > 1:
                  raise ValueError(
                      'The given experiments belong to multiple archives %s!' % (
                          ', '.join(archives)))
              archive = next(iter(archives))
          elif not complete and experiments is None:
              experiments = [self.experiment]
  
          logger.info('Unarchiving from %s', archive)
  
          # --- infer compression type
          ext_map, fmt_map = self._archive_extensions()
          if fmt is None:
              try:
                  fmt = next(fmt for ext, fmt in ext_map.items()
                             if archive.endswith(ext))
              except StopIteration:
                  raise IOError(
                      "Could not infer archive format of {}! Please specify it "
                      "manually using the `fmt` parameter!".format(archive))
  
          # if no root directory is specified but a projectname, we take the root
          # directory from the configuration if, and only if, the configuration
          # should not be replaced
          if (root is None and projectname is not None and
                  not replace_project_config):
              all_projects.get(projectname, {}).get('root')
  
          # ---- open the archive
          modes = {'bztar': 'r:bz2', 'gztar': 'r:gz', 'tar': 'r', 'zip': 'r'}
          atype = 'zip' if fmt == 'zip' else 'tar'
          if atype == 'tar':
              from tarfile import open as open_file
          else:
              from zipfile import ZipFile as open_file
          file_obj = open_file(archive, modes[fmt])
  
          # ---- if root is None, get it from the archive
          if root is None:
              fp = extract_file(osp.join('.project', '.project.yml'))
              try:
                  project_config = ordered_yaml_load(fp)
                  # use the projectname in archive only, if nothing is specified
                  # here
                  projectname = projectname or project_config['name']
              except:
                  raise
              finally:
                  fp.close()
              # if the projectname is existent in our configuration and already
              # specified, use this one
              if (projectname in self.config.projects and
                      not replace_project_config):
                  root = self.config.projects[projectname].get('root')
              else:
                  root = project_config.get('root')
          # if we still don't have it, because it was not specified in the
          # archive or the configuration, raise an error
          if root is None:
              raise ValueError("Could not find a root directory path for the "
                               "project. Please specify manually!")
  
          logger.info('Root directory for the project: %s', root)
  
          t = str(dt.datetime.now())  # time at the beginning of extraction
  
          config_files = []
  
          def fname_filter(m):
              fname = get_fname(m)
              if (dir_contains('.project', fname) and
                      not osp.basename(fname).startswith('.')):
                  config_files.append(fname)
              return (
                  complete or fname in config_files or
                  (project_data and not dir_contains('experiments', fname)) or
                  any(dir_contains(d, fname) for d in dirs))
  
          if not complete:
              dirs = [osp.join('experiments', exp) for exp in experiments]
              dirs.append(osp.join('.project', '.project.yml'))
          dir_contains = partial(utils.dir_contains, exists=False)
          if atype == 'zip':
              def get_fname(m):
                  return m
              members = list(filter(fname_filter, file_obj.namelist()))
          else:
              def get_fname(m):
                  return m.name
              members = list(filter(fname_filter, file_obj.getmembers()))
          logger.debug('Extracting %s files from archive to %s',
                       len(members), root)
          file_obj.extractall(root, members=members)
  
          # if the project_config yet not has been red, read it now
          if not project_config:
              with open(osp.join(root, '.project', '.project.yml')) as fp:
                  project_config = ordered_yaml_load(fp)
              if projectname:
                  project_config['name'] = projectname
              else:
                  projectname = project_config['name']
          if projectname not in all_projects or replace_project_config:
              all_projects[projectname] = project_config
          else:
              all_projects[projectname]['root'] = root
  
          # get all experiment names in the archive
          arc_exps = [osp.splitext(osp.basename(f))[0] for f in config_files]
          if complete:
              experiments = arc_exps
          else:
              for exp in filter(lambda exp: exp not in arc_exps, experiments[:]):
                  logger.warn('Experiment %s was not found in archive!', exp)
                  experiments.remove(exp)
          for exp in experiments:
              if force or exp not in self.config.experiments or self.is_archived(
                      exp):
                  with open(osp.join(root, '.project', exp + '.yml')) as fexp:
                      exp_config = ordered_yaml_load(fexp)
                  logger.debug('Update configuration for %s', exp)
                  all_exps[exp] = self.fix_paths(exp_config)
              else:
                  exp_config = all_exps[exp]
              exp_config['project'] = projectname
              exp_config['timestamps']['unarchive'] = t
  
          logger.debug('Done.')