Factory method to create a tree traverser depending on the input
        source and target data combination.

        :param source_data: Source data.
        :param target_target: Target data.
        :param str relation_operation: Relation operation. On of the constants
          defined in :class:`everest.constants.RELATION_OPERATIONS`.
        :param accessor: Accessor for looking up target nodes for update
          operations.
        :param bool manage_back_references: If set, backreferences will
          automatically be updated in the target data.

def make_traverser(cls, source_data, target_data, relation_operation,
                       accessor=None, manage_back_references=True):
        """
        Factory method to create a tree traverser depending on the input
        source and target data combination.

        :param source_data: Source data.
        :param target_target: Target data.
        :param str relation_operation: Relation operation. On of the constants
          defined in :class:`everest.constants.RELATION_OPERATIONS`.
        :param accessor: Accessor for looking up target nodes for update
          operations.
        :param bool manage_back_references: If set, backreferences will
          automatically be updated in the target data.
        """
        reg = get_current_registry()
        prx_fac = reg.getUtility(IDataTraversalProxyFactory)
        if relation_operation == RELATION_OPERATIONS.ADD \
           or relation_operation == RELATION_OPERATIONS.UPDATE:
            if relation_operation == RELATION_OPERATIONS.ADD \
               and not target_data is None:
                raise ValueError('Must not provide target data with '
                                 'relation operation ADD.')
            source_proxy = prx_fac.make_proxy(source_data,
                                              None,
                                              RELATIONSHIP_DIRECTIONS.NONE,
                                              relation_operation)
            source_is_sequence = \
                source_proxy.proxy_for == RESOURCE_KINDS.COLLECTION
            if not source_is_sequence:
                source_id = source_proxy.get_id()
        else:
            source_proxy = None
            source_is_sequence = False
        if relation_operation == RELATION_OPERATIONS.REMOVE \
           or relation_operation == RELATION_OPERATIONS.UPDATE:
            rel_dir = RELATIONSHIP_DIRECTIONS.BIDIRECTIONAL
            if not manage_back_references:
                rel_dir &= ~RELATIONSHIP_DIRECTIONS.REVERSE
            if relation_operation == RELATION_OPERATIONS.REMOVE:
                if not source_data is None:
                    raise ValueError('Must not provide source data with '
                                     'relation operation REMOVE.')
                target_proxy = prx_fac.make_proxy(target_data,
                                                  accessor,
                                                  rel_dir,
                                                  relation_operation)
            else: # UPDATE
                if accessor is None:
                    raise ValueError('Need to provide an accessor when '
                                     'performing UPDATE operations.')
                if not target_data is None:
                    target_root = target_data
                elif not source_is_sequence:
                    # Look up the (single) target to update.
                    target_root = accessor.get_by_id(source_id)
                    if target_root is None:
                        raise ValueError('Entity with ID %s to update not '
                                         'found.' % source_id)
                else:
                    # Look up collection of targets to update.
                    target_root = []
                    for src_prx in source_proxy:
                        tgt_ent_id = src_prx.get_id()
                        if tgt_ent_id is None:
                            continue
                        tgt_ent = accessor.get_by_id(tgt_ent_id)
                        if tgt_ent is None:
                            continue
                        target_root.append(tgt_ent)
                target_proxy = prx_fac.make_proxy(target_root,
                                                  accessor,
                                                  rel_dir,
                                                  relation_operation)
            target_is_sequence = \
                    target_proxy.proxy_for == RESOURCE_KINDS.COLLECTION
        else:
            target_proxy = None
            target_is_sequence = False
        if not source_proxy is None and not target_proxy is None:
            # Check for source/target consistency.
            if not ((source_is_sequence and target_is_sequence) or
                    (not source_is_sequence and not target_is_sequence)):
                raise ValueError('When both source and target root nodes are '
                                 'given, they can either both be sequences '
                                 'or both not be sequences.')
        return cls(source_proxy, target_proxy)