docs: def validate(self, signature):
          '''Check if ofiles and ifiles match signatures recorded in md5file'''
          if not signature:
              return 'Empty signature'
          sig_files = self.input_files._targets + self.output_files._targets + \
              self.dependent_files._targets
          for x in sig_files:
              if not x.target_exists('any'):
                  return f'Missing target {x}'
          #
  
          files_checked = {x.target_name(): False for x in sig_files}
          res = {'input': [], 'output': [], 'depends': [], 'vars': {}}
          cur_type = 'input'
          # old signature
          if 'init_context' in signature:
              for key, value in signature['init_context'].items():
                  if key not in env.sos_dict:
                      return f'Variable {key} not in running environment'
                  try:
                      if env.sos_dict[key] != value:
                          return f'Context variable {key} value mismatch: {short_repr(value)} saved, {short_repr(env.sos_dict[key])} current'
                  except Exception as e:
                      env.logger.debug(
                          f"Variable {key} of type {type(value).__name__} cannot be compared: {e}"
                      )
          elif 'init_context_sig' in signature:
              for key, value in signature['init_context_sig'].items():
                  if key not in env.sos_dict:
                      return f'Variable {key} not in running environment'
                  try:
                      if objectMD5(env.sos_dict[key]) != value:
                          return f'ID of context variable {key} ({objectMD5(env.sos_dict[key])}) mismatch: {short_repr(env.sos_dict[key])} does not match id {value}'
                  except Exception as e:
                      env.logger.debug(f"Variable {key} cannot be compared: {e}")
  
          res['vars'].update(signature['end_context'])
          #
          for cur_type in ['input', 'output', 'depends']:
              for f, m in signature[cur_type].items():
                  try:
                      if '(' in f and ')' in f:
                          # this part is hard, because this can be a customized target.
                          target_type = f.split('(')[0]
                          target_class = None
                          if target_type in globals():
                              target_class = eval(target_type)
                          else:
                              # check registry
                              for entrypoint in pkg_resources.iter_entry_points(
                                      group='sos_targets'):
                                  if entrypoint.name.strip() == target_type:
                                      target_class = entrypoint.load()
                                      break
                          if target_class is None:
                              raise ValueError(
                                  f'Failed to identify target class {target_type}'
                              )
                          # parameter of class?
                          freal = eval(f, {target_type: target_class})
                      else:
                          freal = file_target(f)
                      if not freal.validate(m):
                          return f'Target {f} does not exist or does not match saved signature {m}'
                      res[cur_type].append(freal.target_name(
                      ) if isinstance(freal, file_target) else freal)
                      files_checked[freal.target_name()] = True
                  except Exception as e:
                      env.logger.debug(f'Wrong md5 in signature: {e}')
          #
          if not all(files_checked.values()):
              return f'No MD5 signature for {", ".join(x for x,y in files_checked.items() if not y)}'
          if 'input_obj' in signature:
              # for new style signature, the entire objects are kept
              res['input'] = signature['input_obj']
              res['depends'] = signature['depends_obj']
              res['output'] = signature['output_obj']
          return res