class Relationship
A class representing a graph relationship between two nodes, wrapping a _Relationship object with start and end Node objects.
/tf/active/vicechatdev/neo4j_driver/neo4j_objects.py
291 - 390
moderate
Purpose
The Relationship class models a directed edge in a graph database (Neo4j-style), connecting two Node objects through a labeled relationship. It encapsulates the start node, end node, and relationship properties, providing a unified interface for managing graph relationships. The class supports multiple initialization formats (string, tuple, Node, _Relationship) and can be bound to a graph instance for database operations.
Source Code
class Relationship():
"""
A relationship is represented as a collection of two nodes and a base _Relationship, which is similar to a Node except it may only have 1 label and does not enforce the UID property
"""
def __init__(self, start_node, relationship, end_node, graph=None):
assert isinstance(start_node, Node), "Please supply a Node as start_node"
assert isinstance(end_node, Node), "Please supply a Node as end_node"
if graph is None and any([start_node.graph, end_node.graph]):
graph = start_node.graph or end_node.graph
self._graph=graph
self.start_node=start_node
self.end_node=end_node
self._nodes = frozenset([self.start_node, self.end_node])
self._relationships=[self]
if isinstance(relationship, _Relationship):
self.relationship = relationship
elif isinstance(relationship, Node):
assert len(relationship.labels) == 1, "When passing a Node object as relationship, make sure it has exactly 1 label"
warnings.warn("Please be aware Node objects are forced to have a UID properties, and this property is carried over to the Relationship, which does not enforce UIDs")
self.relationship = _Relationship(relationship.labels, **relationship)
elif isinstance(relationship, str):
self.relationship = _Relationship(relationship)
elif isinstance(relationship, tuple):
assert len(relationship) < 3, "When passing a tuple, please ensure only one label is passed and all properties are formatted as a dict, e.g. (RELATIONSHIP, {PROPERTIES})"
if isinstance(relationship[-1], dict):
self.relationship = _Relationship(relationship[0], **relationship[-1])
else:
warnings.warn("When passing a tuple, properties must be formatted as a single dictionary or they will be ignored")
self.relationship = _Relationship(relationship[0])
else:
raise TypeError("Please supply a Node, string or tuple as relationship")
@classmethod
def _from_neo4j_node(cls, original, **kwargs):
start_node = Node._from_neo4j_node(original.start_node, graph=kwargs.get('graph',None))
start_node.pull()
end_node = Node._from_neo4j_node(original.end_node, graph=kwargs.get('graph',None))
end_node.pull()
try:
element_id = int(original.element_id)
except:
if ':' in original.element_id:
element_id = int(original.element_id.split(':')[-1])
else:
raise Exception(f"Could not obtain element ID. Found ID: {original.element_id}")
return cls(start_node,
_Relationship(original.type, _element_id=element_id, **dict(original)),
end_node,
graph=kwargs.get('graph',None))
@property
def graph(self):
return self._graph
@graph.setter
def graph(self, graph):
self._graph = graph
@property
def nodes(self):
return set(self._nodes)
@property
def relationships(self):
return self._relationships
@property
def element_id(self):
return self.relationship.element_id
@element_id.setter
def element_id(self, element_id):
self.relationship.element_id = element_id
@property
def labels(self):
return self.relationship.labels
@labels.setter
def labels(self, labels):
self.relationship.labels = labels
def unbind(self):
"""Returns an unbound copy of itself"""
return Relationship(self.start_node.unbind(), _Relationship(*self.relationship.labels, **self.relationship), self.end_node.unbind())
def __str__(self):
return "Relationship(%s [%s] %s)" % (self.start_node, self.relationship, self.end_node)
def __repr__(self):
return "Relationship(%s %s %s)" % (self.start_node, self.relationship, self.end_node)
def clear(self):
"Redirect PropertyDict funcs to the underlying _relationship class"
self._relationship.clear()
def update(self, **kwargs):
"Redirect PropertyDict funcs to the underlying _relationship class"
self._relationship.update(**kwargs)
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
start_node: A Node object representing the source/origin node of the relationship. Must be an instance of the Node class.
relationship: The relationship definition, which can be: (1) a _Relationship object, (2) a Node object with exactly 1 label (will be converted to _Relationship), (3) a string representing the relationship label, or (4) a tuple in format (label, properties_dict) where properties_dict is optional.
end_node: A Node object representing the target/destination node of the relationship. Must be an instance of the Node class.
graph: Optional graph instance to bind this relationship to. If None, will attempt to use the graph from start_node or end_node if either has one. Defaults to None.
Return Value
Instantiation returns a Relationship object that encapsulates the start node, end node, and relationship properties. The object provides access to graph database operations and relationship metadata through properties and methods.
Class Interface
Methods
__init__(self, start_node, relationship, end_node, graph=None)
Purpose: Initialize a Relationship object with start node, relationship definition, and end node
Parameters:
start_node: Node object representing the source noderelationship: Relationship definition (string, tuple, Node, or _Relationship)end_node: Node object representing the target nodegraph: Optional graph instance to bind to
Returns: None (constructor)
_from_neo4j_node(cls, original, **kwargs) -> Relationship
Purpose: Class method to reconstruct a Relationship object from a Neo4j relationship object
Parameters:
original: Neo4j relationship object with start_node, end_node, type, and element_id attributeskwargs: Additional keyword arguments, particularly 'graph' for binding
Returns: A new Relationship instance reconstructed from the Neo4j object
@property graph(self)
property
Purpose: Get the graph instance this relationship is bound to
Returns: The graph instance or None if unbound
@graph.setter graph(self, graph)
property
Purpose: Set the graph instance this relationship is bound to
Parameters:
graph: Graph instance to bind to
Returns: None
@property nodes(self) -> set
property
Purpose: Get a set containing both start and end nodes
Returns: A set containing the start_node and end_node
@property relationships(self) -> list
property
Purpose: Get a list of relationships (contains self)
Returns: A list containing this relationship instance
@property element_id(self)
property
Purpose: Get the database element ID of the relationship
Returns: The element_id from the underlying _Relationship object
@element_id.setter element_id(self, element_id)
property
Purpose: Set the database element ID of the relationship
Parameters:
element_id: The element ID to assign
Returns: None
@property labels(self)
property
Purpose: Get the labels of the relationship
Returns: The labels from the underlying _Relationship object
@labels.setter labels(self, labels)
property
Purpose: Set the labels of the relationship
Parameters:
labels: The labels to assign to the relationship
Returns: None
unbind(self) -> Relationship
Purpose: Create and return an unbound copy of this relationship
Returns: A new Relationship instance with unbound nodes and relationship, detached from any graph
__str__(self) -> str
Purpose: Return a human-readable string representation of the relationship
Returns: String in format 'Relationship(start_node [relationship] end_node)'
__repr__(self) -> str
Purpose: Return a developer-friendly string representation of the relationship
Returns: String in format 'Relationship(start_node relationship end_node)'
clear(self)
Purpose: Clear all properties from the underlying relationship object
Returns: None
update(self, **kwargs)
Purpose: Update properties of the underlying relationship object
Parameters:
kwargs: Key-value pairs of properties to update
Returns: None
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
_graph |
object or None | Private attribute storing the graph instance this relationship is bound to | instance |
start_node |
Node | The source/origin node of the relationship | instance |
end_node |
Node | The target/destination node of the relationship | instance |
_nodes |
frozenset | Immutable set containing both start_node and end_node | instance |
_relationships |
list | List containing this relationship instance (for interface consistency) | instance |
relationship |
_Relationship | The underlying _Relationship object containing the label and properties | instance |
Dependencies
warningsuuid
Required Imports
from uuid import uuid4
from itertools import chain
import warnings
Usage Example
# Basic instantiation with string relationship
start = Node('Person', name='Alice')
end = Node('Person', name='Bob')
rel = Relationship(start, 'KNOWS', end)
# With properties using tuple format
rel = Relationship(start, ('KNOWS', {'since': 2020, 'strength': 0.8}), end)
# With graph binding
rel = Relationship(start, 'KNOWS', end, graph=my_graph)
# Access properties
print(rel.labels) # Relationship labels
print(rel.nodes) # Set of start and end nodes
print(rel.element_id) # Database element ID if bound
# Create unbound copy
unbound_rel = rel.unbind()
# Update relationship properties
rel.update(weight=5, active=True)
Best Practices
- Always ensure start_node and end_node are valid Node instances before instantiation
- When using a Node object as relationship parameter, ensure it has exactly one label
- Use tuple format (label, properties_dict) for relationships with properties
- Be aware that Node objects used as relationships carry over UID properties which _Relationship does not enforce
- Use unbind() method to create a copy detached from the graph database
- The graph parameter is automatically inferred from nodes if not provided
- The relationship is directional: start_node -> end_node
- Use _from_neo4j_node() classmethod when reconstructing relationships from database queries
- The _nodes attribute is a frozenset for immutability, but nodes property returns a mutable set
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class _Relationship 79.2% similar
-
class Graph 64.3% similar
-
class Node 63.4% similar
-
class RelTypes 59.6% similar
-
function create_relationship 58.1% similar