🔍 Code Extractor

class Relationship

Maturity: 51

A class representing a graph relationship between two nodes, wrapping a _Relationship object with start and end Node objects.

File:
/tf/active/vicechatdev/neo4j_driver/neo4j_objects.py
Lines:
291 - 390
Complexity:
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 node
  • relationship: Relationship definition (string, tuple, Node, or _Relationship)
  • end_node: Node object representing the target node
  • graph: 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 attributes
  • kwargs: 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

  • warnings
  • uuid

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

    A class representing a graph relationship (edge) with labels, properties, and an optional element ID, inheriting from PropertyDict to manage key-value properties.

    From: /tf/active/vicechatdev/neo4j_driver/neo4j_objects.py
  • class Graph 64.3% similar

    A Graph class that provides an interface for interacting with a Neo4j graph database, supporting CRUD operations on nodes and relationships through Cypher queries.

    From: /tf/active/vicechatdev/neo4j_driver/neo4j_driver.py
  • class Node 63.4% similar

    A Node class representing a graph node with labels and properties, designed to work with Neo4j graph databases. It extends PropertyDict to manage node properties and provides methods for label management and graph synchronization.

    From: /tf/active/vicechatdev/neo4j_driver/neo4j_objects.py
  • class RelTypes 59.6% similar

    A constants class that defines string literals representing relationship types used in a graph database (Neo4j) for document management and approval workflows.

    From: /tf/active/vicechatdev/CDocs/db/schema_manager.py
  • function create_relationship 58.1% similar

    Creates a directed relationship between two Neo4j graph database nodes identified by their UIDs, with optional properties attached to the relationship.

    From: /tf/active/vicechatdev/CDocs/db/db_operations.py
← Back to Browse