'This computes access to a block\'s group_access rules in the context of its position
within the courseware structure, in the form of a lazily-computed attribute.
Each block\'s group_access rule is merged recursively with its parent\'s, guaranteeing
that any rule in a parent block will be enforced on descendants, even if a descendant
also defined its own access rules.  The return value is always a dict, with the same
structure as that of the group_access field.
When merging access rules results in a case where all groups are denied access in a
user partition (which effectively denies access to that block for all students),
the special value False will be returned for that user partition key.'

@lazy
def merged_group_access(self):

    parent = self.get_parent()
    if (not parent):
        return (self.group_access or {})
    merged_access = parent.merged_group_access.copy()
    if (self.group_access is not None):
        for (partition_id, group_ids) in self.group_access.items():
            if group_ids:
                if (partition_id in merged_access):
                    if (merged_access[partition_id] is False):
                        continue
                    merged_access[partition_id] = (list(set(merged_access[partition_id]).intersection(group_ids)) or False)
                else:
                    merged_access[partition_id] = group_ids
    return merged_access
