def _require_homogeneous_roots(self, accept_predicate, reject_predicate):
    """Ensures that there is no ambiguity in the context according to the given predicates.

    If any targets in the context satisfy the accept_predicate, and no targets satisfy the
    reject_predicate, returns the accepted targets.

    If no targets satisfy the accept_predicate, returns None.

    Otherwise throws TaskError.
    """
    if len(self.context.target_roots) == 0:
      raise self.NoActivationsError('No target specified.')

    def resolve(targets):
      # Recursively resolve target aliases.
      for t in targets:
        if type(t) == Target:
          for r in resolve(t.dependencies):
            yield r
        else:
          yield t

    expanded_roots = list(resolve(self.context.target_roots))

    accepted = list(filter(accept_predicate, expanded_roots))
    rejected = list(filter(reject_predicate, expanded_roots))
    if len(accepted) == 0:
      # no targets were accepted, regardless of rejects
      return None
    elif len(rejected) == 0:
      # we have at least one accepted target, and no rejected targets
      return accepted
    else:
      # both accepted and rejected targets
      # TODO: once https://github.com/pantsbuild/pants/issues/425 lands, we should add
      # language-specific flags that would resolve the ambiguity here
      def render_target(target):
        return '{} (a {})'.format(target.address.reference(), target.type_alias)
      raise self.IncompatibleActivationsError('Mutually incompatible targets specified: {} vs {} '
                                              '(and {} others)'
                                              .format(render_target(accepted[0]),
                                                      render_target(rejected[0]),
                                                      len(accepted) + len(rejected) - 2))
dataset/ETHPy150Open pantsbuild/pants/src/python/pants/task/mutex_task_mixin.py/MutexTaskMixin._require_homogeneous_roots/original