class Node
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.
/tf/active/vicechatdev/neo4j_driver/neo4j_objects.py
97 - 238
moderate
Purpose
This class represents a node in a graph database (specifically Neo4j). It manages node labels, properties, and maintains a connection to a graph instance. The Node can be bound to a database (with an element_id) or exist as an unbound entity. It provides functionality for label manipulation, property management through inheritance from PropertyDict, and synchronization with the database through pull operations. The class supports creating nodes from Neo4j native node objects and maintains a unique identifier (UID) for each instance.
Source Code
class Node(PropertyDict):
"""
"""
_lock = False
def __init__(self, *labels, _element_id=None, _graph=None, **properties):
if _element_id is None:
self._element_id = None
else:
try:
self._element_id = int(_element_id)
except ValueError:
raise ValueError(f"element_id must be an integer or None, got {_element_id}")
self._graph = _graph
self._labels = set(labels)
self._nodes = [self]
PropertyDict.__init__(self, properties)
self._uid = self.setdefault('UID', str(uuid4()))
@classmethod
def _from_neo4j_node(cls, original, **kwargs):
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(*list(original.labels), _element_id=element_id, _graph=kwargs.get('graph', None), **dict(original))
def __ensure_labels(self):
if self._graph and self.element_id and not self._lock:
self.graph.pull(self)
def keys(self):
return PropertyDict.keys(self)
def __hash__(self):
return hash(self._uid)
def __str__(self):
kwargs = dict(self)
labels_str = ", ".join(self.labels)
props_str = ", ".join("{}: {!r}".format(k, v) for k, v in kwargs.items())
return "Node({} {{ {} }})".format(labels_str, props_str)
def __repr__(self):
kwargs = dict(self)
labels_str = ", ".join(self.labels)
props_str = ", ".join("{}={!r}".format(k, v) for k, v in kwargs.items())
return "Node({}, {})".format(labels_str, props_str)
def pull(self):
if self._graph and self.element_id and not self._lock:
self.graph.pull(self)
def unbind(self):
"""Returns an unbound copy of itself"""
return Node(*self.labels, **dict(self))
@property
def nodes(self):
return self._nodes
@property
def relationships(self):
return set([])
@property
def element_id(self):
return self._element_id
@element_id.setter
def element_id(self, x):
try:
int(x)
except:
raise TypeError("Invalid input for element_id, value cannot be coerced to int")
self._element_id = x
@property
def graph(self):
return self._graph
@graph.setter
def graph(self, graph):
self._graph = graph
@property
def labels(self):
""" The full set of labels associated with with this *node*.
This set is immutable and cannot be used to add or remove
labels. Use methods such as :meth:`.add_label` and
:meth:`.remove_label` for that instead.
"""
return set(self._labels)
def clear_element_id(self):
self._element_id = None
def has_label(self, label):
""" Return :const:`True` if this node has the label `label`,
:const:`False` otherwise.
"""
self.__ensure_labels()
if isinstance(label, tuple):
return all(lab in self._labels for lab in label)
else:
return label in self._labels
def add_label(self, label):
""" Add the label `label` to this node.
"""
self.__ensure_labels()
if isinstance(label, tuple):
self._labels.update(label)
else:
self._labels.add(label)
def remove_label(self, label):
""" Remove the label `label` from this node, if it exists.
"""
self.__ensure_labels()
if isinstance(label, tuple):
for lab in label:
self._labels.discard(lab)
else:
self._labels.discard(label)
def clear_labels(self):
""" Remove all labels from this node.
"""
self._labels.clear()
def update_labels(self, labels):
""" Add multiple labels to this node from the iterable
`labels`.
"""
self.__ensure_labels()
for label in labels:
self.add_label(label)
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
PropertyDict | - |
Parameter Details
*labels: Variable number of string arguments representing the labels to assign to this node. Labels are used to categorize nodes in the graph database (e.g., 'Person', 'Company').
_element_id: Optional integer or None. The unique identifier assigned by Neo4j when the node is persisted to the database. None indicates an unbound node that hasn't been saved yet. Must be coercible to an integer.
_graph: Optional reference to a Graph object that this node belongs to. Used for database operations like pulling updated data from the database. None indicates the node is not associated with a graph instance.
**properties: Arbitrary keyword arguments representing the properties (key-value pairs) to store on this node. These are passed to the PropertyDict parent class for management.
Return Value
Instantiation returns a Node object. The object contains labels, properties, and optional graph binding. Key method returns: pull() returns None but updates the node's state; unbind() returns a new unbound Node instance; has_label() returns boolean; labels property returns an immutable set of label strings; element_id property returns integer or None; graph property returns Graph object or None.
Class Interface
Methods
__init__(self, *labels, _element_id=None, _graph=None, **properties)
Purpose: Initialize a new Node instance with labels, optional database binding, and properties
Parameters:
*labels: Variable number of label strings to assign to the node_element_id: Optional integer ID from Neo4j database, or None for unbound nodes_graph: Optional Graph object reference for database operations**properties: Key-value pairs for node properties
Returns: None (constructor)
_from_neo4j_node(cls, original, **kwargs) -> Node
Purpose: Class method to create a Node instance from a Neo4j native node object
Parameters:
original: Neo4j node object with element_id, labels, and properties**kwargs: Optional keyword arguments, particularly 'graph' for binding to a Graph instance
Returns: New Node instance populated with data from the Neo4j node
keys(self) -> KeysView
Purpose: Return the keys of the node's properties (inherited from PropertyDict)
Returns: View of property keys
__hash__(self) -> int
Purpose: Return hash value based on the node's UID for use in sets and dictionaries
Returns: Integer hash value
__str__(self) -> str
Purpose: Return human-readable string representation of the node
Returns: String in format 'Node(Label1, Label2 { prop1: value1, prop2: value2 })'
__repr__(self) -> str
Purpose: Return developer-friendly string representation suitable for debugging
Returns: String in format 'Node(Label1, Label2, prop1=value1, prop2=value2)'
pull(self) -> None
Purpose: Synchronize node data from the database if bound to a graph
Returns: None, but updates the node's labels and properties from the database
unbind(self) -> Node
Purpose: Create an unbound copy of the node without graph or element_id references
Returns: New Node instance with same labels and properties but no database binding
nodes(self) -> list
property
Purpose: Property that returns a list containing this node (for compatibility with graph structures)
Returns: List containing only this node instance
relationships(self) -> set
property
Purpose: Property that returns relationships connected to this node
Returns: Empty set (base implementation, may be overridden in subclasses)
element_id(self) -> int | None
property
Purpose: Property to get or set the Neo4j database element ID
Returns: Integer element ID if bound to database, None otherwise
graph(self) -> Graph | None
property
Purpose: Property to get or set the Graph instance this node is bound to
Returns: Graph object if bound, None otherwise
labels(self) -> set
property
Purpose: Property that returns an immutable set of all labels on this node
Returns: Set of label strings (immutable copy)
clear_element_id(self) -> None
Purpose: Remove the element_id, effectively unbinding the node from the database
Returns: None, sets element_id to None
has_label(self, label) -> bool
Purpose: Check if the node has a specific label or tuple of labels
Parameters:
label: String label or tuple of label strings to check for
Returns: True if node has the label(s), False otherwise. For tuples, returns True only if all labels are present
add_label(self, label) -> None
Purpose: Add a label or multiple labels (if tuple) to the node
Parameters:
label: String label or tuple of label strings to add
Returns: None, modifies the node's label set
remove_label(self, label) -> None
Purpose: Remove a label or multiple labels (if tuple) from the node
Parameters:
label: String label or tuple of label strings to remove
Returns: None, modifies the node's label set. Does nothing if label doesn't exist
clear_labels(self) -> None
Purpose: Remove all labels from the node
Returns: None, empties the node's label set
update_labels(self, labels) -> None
Purpose: Add multiple labels from an iterable to the node
Parameters:
labels: Iterable of label strings to add
Returns: None, adds all labels from the iterable to the node
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
_lock |
bool | Class variable that prevents automatic database pulls when True. Default is False | class |
_element_id |
int | None | The Neo4j database element ID for this node. None if unbound | instance |
_graph |
Graph | None | Reference to the Graph object this node belongs to. None if unbound | instance |
_labels |
set | Internal set storing the node's labels | instance |
_nodes |
list | List containing this node instance (for graph structure compatibility) | instance |
_uid |
str | Unique identifier (UUID) for this node instance, stored as 'UID' property | instance |
Dependencies
uuid
Required Imports
from uuid import uuid4
Usage Example
# Create an unbound node
node = Node('Person', 'Employee', name='John Doe', age=30)
# Access labels
print(node.labels) # {'Person', 'Employee'}
# Check for label
if node.has_label('Person'):
print('Is a Person')
# Add/remove labels
node.add_label('Manager')
node.remove_label('Employee')
# Access properties (inherited from PropertyDict)
print(node['name']) # 'John Doe'
node['department'] = 'Engineering'
# Create from Neo4j node object
# neo4j_node = session.run('MATCH (n) RETURN n').single()['n']
# node = Node._from_neo4j_node(neo4j_node, graph=my_graph)
# Bind to graph and pull updates
# node.graph = my_graph
# node.element_id = 123
# node.pull() # Syncs with database
# Create unbound copy
unbound_copy = node.unbind()
# Access unique identifier
print(node._uid) # UUID string
Best Practices
- Always check if a node is bound to a graph (has element_id and graph) before performing database operations
- Use unbind() to create independent copies of nodes that won't sync with the database
- The _lock class variable prevents automatic database pulls when True - use carefully to avoid unintended synchronization
- Labels are stored in a set and are case-sensitive; ensure consistent label naming conventions
- The UID property is automatically generated and should not be manually modified
- When working with Neo4j nodes, use the _from_neo4j_node() class method for proper conversion
- The __ensure_labels() private method automatically pulls from database before label operations if the node is bound
- Use clear_element_id() to unbind a node from the database without creating a new instance
- Properties are managed through PropertyDict inheritance, so use dictionary-style access for properties
- The node maintains immutable label sets through the labels property; use add_label/remove_label methods to modify
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class NodeLabels_v1 69.7% similar
-
class _Relationship 69.3% similar
-
class NodeLabels 69.3% similar
-
function create_node_v1 68.3% similar
-
class Graph 66.8% similar