[docs]class Relationship(object):
    """Class to represent an relationship between entities
    See Also:
        :class:`.EntitySet`, :class:`.Entity`, :class:`.Variable`
    """
[docs]    def __init__(self, parent_variable, child_variable):
        """ Create a relationship
        Args:
            parent_variable (:class:`.Discrete`): Instance of variable
                in parent entity.  Must be a Discrete Variable
            child_variable (:class:`.Discrete`): Instance of variable in
                child entity.  Must be a Discrete Variable
        """
        self.entityset = child_variable.entityset
        self._parent_entity_id = parent_variable.entity.id
        self._child_entity_id = child_variable.entity.id
        self._parent_variable_id = parent_variable.id
        self._child_variable_id = child_variable.id
        if (parent_variable.entity.index is not None and
                parent_variable.id != parent_variable.entity.index):
            raise AttributeError("Parent variable '%s' is not the index of entity %s" % (parent_variable, parent_variable.entity)) 
    @classmethod
    def from_dictionary(cls, arguments, es):
        parent_entity = es[arguments['parent_entity_id']]
        child_entity = es[arguments['child_entity_id']]
        parent_variable = parent_entity[arguments['parent_variable_id']]
        child_variable = child_entity[arguments['child_variable_id']]
        return cls(parent_variable, child_variable)
    def __repr__(self):
        ret = u"<Relationship: %s.%s -> %s.%s>" % \
            
(self._child_entity_id, self._child_variable_id,
             self._parent_entity_id, self._parent_variable_id)
        return ret
    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return False
        return self._parent_entity_id == other._parent_entity_id and \
            
self._child_entity_id == other._child_entity_id and \
            
self._parent_variable_id == other._parent_variable_id and \
            
self._child_variable_id == other._child_variable_id
    def __hash__(self):
        return hash((self._parent_entity_id,
                     self._child_entity_id,
                     self._parent_variable_id,
                     self._child_variable_id))
    @property
    def parent_entity(self):
        """Parent entity object"""
        return self.entityset[self._parent_entity_id]
    @property
    def child_entity(self):
        """Child entity object"""
        return self.entityset[self._child_entity_id]
    @property
    def parent_variable(self):
        """Instance of variable in parent entity"""
        return self.parent_entity[self._parent_variable_id]
    @property
    def child_variable(self):
        """Instance of variable in child entity"""
        return self.child_entity[self._child_variable_id]
    @property
    def parent_name(self):
        """The name of the parent, relative to the child."""
        if self._is_unique():
            return self._parent_entity_id
        else:
            return '%s[%s]' % (self._parent_entity_id, self._child_variable_id)
    @property
    def child_name(self):
        """The name of the child, relative to the parent."""
        if self._is_unique():
            return self._child_entity_id
        else:
            return '%s[%s]' % (self._child_entity_id, self._child_variable_id)
    def to_dictionary(self):
        return {
            'parent_entity_id': self._parent_entity_id,
            'child_entity_id': self._child_entity_id,
            'parent_variable_id': self._parent_variable_id,
            'child_variable_id': self._child_variable_id,
        }
    def _is_unique(self):
        """Is there any other relationship with same parent and child entities?"""
        es = self.child_entity.entityset
        relationships = es.get_forward_relationships(self._child_entity_id)
        n = len([r for r in relationships
                 if r._parent_entity_id == self._parent_entity_id])
        assert n > 0, 'This relationship is missing from the entityset'
        return n == 1 
class RelationshipPath(object):
    def __init__(self, relationships_with_direction):
        self._relationships_with_direction = relationships_with_direction
    @property
    def name(self):
        relationship_names = [_direction_name(is_forward, r)
                              for is_forward, r in self._relationships_with_direction]
        return '.'.join(relationship_names)
    def entities(self):
        if self:
            # Yield first entity.
            is_forward, relationship = self[0]
            if is_forward:
                yield relationship.child_entity.id
            else:
                yield relationship.parent_entity.id
        # Yield the entity pointed to by each relationship.
        for is_forward, relationship in self:
            if is_forward:
                yield relationship.parent_entity.id
            else:
                yield relationship.child_entity.id
    def __add__(self, other):
        return RelationshipPath(self._relationships_with_direction +
                                other._relationships_with_direction)
    def __getitem__(self, index):
        return self._relationships_with_direction[index]
    def __iter__(self):
        for is_forward, relationship in self._relationships_with_direction:
            yield is_forward, relationship
    def __len__(self):
        return len(self._relationships_with_direction)
    def __eq__(self, other):
        return isinstance(other, RelationshipPath) and \
            self._relationships_with_direction == other._relationships_with_direction
    def __ne__(self, other):
        return not self == other
    def __repr__(self):
        if self._relationships_with_direction:
            path = '%s.%s' % (next(self.entities()), self.name)
        else:
            path = '[]'
        return '<RelationshipPath %s>' % path
def _direction_name(is_forward, relationship):
    if is_forward:
        return relationship.parent_name
    else:
        return relationship.child_name