'Copies each xblock in subtree_list and those blocks descendants excluding blacklist
from source_course to destination_course.
To delete a block in the destination_course, copy its parent and blacklist the other
sibs to keep them from being copies. You can also just call delete_item on the destination.
Ensures that each subtree occurs in the same place in destination as it does in source. If any
of the source\'s subtree parents are missing from destination, it raises ItemNotFound([parent_ids]).
To determine the same relative order vis-a-vis published siblings,
publishing may involve changing the order of previously published siblings. For example,
if publishing `[c, d]` and source parent has children `[a, b, c, d, e]` and destination parent
currently has children `[e, b]`, there\'s no obviously correct resulting order; thus, publish will
reorder destination to `[b, c, d, e]` to make it conform with the source.
:param source_course: a CourseLocator (can be a version or course w/ branch)
:param destination_course: a CourseLocator which must be an existing course but branch doesn\'t have
to exist yet. (The course must exist b/c Locator doesn\'t have everything necessary to create it).
Note, if the branch doesn\'t exist, then the source_course structure\'s root must be in subtree_list;
otherwise, the publish will violate the parents must exist rule.
:param subtree_list: a list of usage keys whose subtrees to publish.
:param blacklist: a list of usage keys to not change in the destination: i.e., don\'t add
if not there, don\'t update if there.
Raises:
ItemNotFoundError: if it cannot find the course. if the request is to publish a
subtree but the ancestors up to and including the course root are not published.'

def copy(self, user_id, source_course, destination_course, subtree_list=None, blacklist=None):

    with self.bulk_operations(source_course):
        source_structure = self._lookup_course(source_course).structure
    with self.bulk_operations(destination_course):
        index_entry = self.get_course_index(destination_course)
        if (index_entry is None):
            raise ItemNotFoundError(destination_course)
        if (destination_course.branch not in index_entry['versions']):
            root_block_key = source_structure['root']
            if (not any(((root_block_key == BlockKey.from_usage_key(subtree)) for subtree in subtree_list))):
                raise ItemNotFoundError(u'Must    publish    course    root    {}'.format(root_block_key))
            root_source = source_structure['blocks'][root_block_key]
            destination_structure = self._new_structure(user_id, root_block_key, definition_id=root_source.definition)
        else:
            destination_structure = self._lookup_course(destination_course).structure
            destination_structure = self.version_structure(destination_course, destination_structure, user_id)
        if (blacklist != EXCLUDE_ALL):
            blacklist = [BlockKey.from_usage_key(shunned) for shunned in (blacklist or [])]
        orphans = set()
        destination_blocks = destination_structure['blocks']
        for subtree_root in subtree_list:
            if (BlockKey.from_usage_key(subtree_root) != source_structure['root']):
                parents = self._get_parents_from_structure(BlockKey.from_usage_key(subtree_root), source_structure)
                parent_found = False
                for parent in parents:
                    if (parent in destination_blocks):
                        parent_found = True
                        orphans.update(self._sync_children(source_structure['blocks'][parent], destination_blocks[parent], BlockKey.from_usage_key(subtree_root)))
                if (len(parents) and (not parent_found)):
                    raise ItemNotFoundError(parents)
            orphans.update(self._copy_subdag(user_id, destination_structure['_id'], BlockKey.from_usage_key(subtree_root), source_structure['blocks'], destination_blocks, blacklist))
        for orphan in orphans:
            self._delete_if_true_orphan(orphan, destination_structure)
        self.update_structure(destination_course, destination_structure)
        self._update_head(destination_course, index_entry, destination_course.branch, destination_structure['_id'])
