🔍 Code Extractor

class Node

Maturity: 52

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.

File:
/tf/active/vicechatdev/neo4j_driver/neo4j_objects.py
Lines:
97 - 238
Complexity:
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

    A constants class that defines string labels for Neo4j graph database node types used in a controlled document management system (CDocs).

    From: /tf/active/vicechatdev/CDocs single class/db/schema_manager.py
  • class _Relationship 69.3% 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 NodeLabels 69.3% similar

    A constants class that defines string labels for different node types in a Neo4j graph database schema for a document management system (CDocs).

    From: /tf/active/vicechatdev/CDocs/db/schema_manager.py
  • function create_node_v1 68.3% similar

    Creates a node in a Neo4j graph database with a specified label and properties, automatically generating a unique ID and timestamp if not provided.

    From: /tf/active/vicechatdev/CDocs/db/db_operations.py
  • class Graph 66.8% 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
← Back to Browse