Constructor
ISONGraph(name: str = "graph", directed: bool = True)
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str | "graph" | Name identifier for the graph |
directed |
bool | True | Whether edges are directed |
Data Types
NodeRef
A tuple identifying a node: (type: str, id: Any)
NodeRef = Tuple[str, Any] # e.g., ('person', 1), ('company', 'acme')
Node
@dataclass
class Node:
type: str # Node type (e.g., 'person', 'product')
id: Any # Unique ID within type
properties: Dict # Key-value properties
Edge
@dataclass
class Edge:
rel_type: str # Relationship type (e.g., 'KNOWS', 'PURCHASED')
source: NodeRef # Source node reference
target: NodeRef # Target node reference
properties: Dict # Key-value properties
Path
@dataclass
class Path:
nodes: List[NodeRef] # Nodes in order
edges: List[Edge] # Edges connecting nodes
length: int # Number of edges
start: NodeRef # First node
end: NodeRef # Last node
Direction
class Direction(Enum):
OUT = "out" # Outgoing edges (default)
IN = "in" # Incoming edges
BOTH = "both" # Both directions
add_node
Add a node to the graph.
add_node(type: str, id: Any, **properties) -> Node
| Parameter | Type | Description |
|---|---|---|
type | str | Node type (e.g., 'person', 'product') |
id | Any | Unique identifier within type |
**properties | Any | Key-value properties |
graph.add_node('person', 1, name='Alice', age=30)
graph.add_node('company', 'acme', name='ACME Corp', employees=500)
get_node
Retrieve a node by type and ID.
get_node(type: str, id: Any) -> Optional[Node]
node = graph.get_node('person', 1)
if node:
print(node.properties['name']) # 'Alice'
has_node
Check if a node exists.
has_node(type: str, id: Any) -> bool
update_node
Update node properties (merges with existing).
update_node(type: str, id: Any, **properties) -> Optional[Node]
remove_node
Remove a node and all its edges.
remove_node(type: str, id: Any) -> bool
nodes
Iterate over nodes, optionally filtered by type.
nodes(type: Optional[str] = None) -> Iterator[Node]
# All nodes
for node in graph.nodes():
print(node)
# Only person nodes
for person in graph.nodes('person'):
print(person.properties['name'])
add_edge
Add an edge between two nodes.
add_edge(rel_type: str, source: NodeRef, target: NodeRef, **properties) -> Edge
graph.add_edge('KNOWS', ('person', 1), ('person', 2), since=2020)
graph.add_edge('WORKS_AT', ('person', 1), ('company', 'acme'), role='Engineer')
neighbors
Get adjacent nodes via a relationship type.
neighbors(
node: NodeRef,
rel_type: Optional[str] = None,
direction: Direction = Direction.OUT
) -> List[NodeRef]
# People Alice knows
friends = graph.neighbors(('person', 1), 'KNOWS')
# People who know Alice
followers = graph.neighbors(('person', 1), 'KNOWS', Direction.IN)
# All connections (any relationship)
all_neighbors = graph.neighbors(('person', 1), direction=Direction.BOTH)
multi_hop
Traverse N hops from a starting node.
multi_hop(
start: NodeRef,
rel_type: str,
hops: int,
direction: Direction = Direction.OUT
) -> List[NodeRef]
# Friends of friends
fof = graph.multi_hop(('person', 1), 'KNOWS', hops=2)
# 3 hops away
distant = graph.multi_hop(('person', 1), 'KNOWS', hops=3)
Fluent Traversal API
Chainable interface for complex traversals.
graph.start(node_ref)
.hop(rel_type, direction, where) # Single hop
.hops(n, rel_type, direction) # N hops
.filter(predicate_fn) # Filter nodes
.collect() # -> List[NodeRef]
.collect_nodes() # -> List[Node]
.count() # -> int
.first() # -> Optional[NodeRef]
# Complex traversal example
results = graph.start(('person', 1)) \
.hop('KNOWS') \
.hop('WORKS_AT') \
.filter(lambda n: n.properties.get('employees', 0) > 100) \
.collect_nodes()
for company in results:
print(company.properties['name'])
shortest_path
Find the shortest path between two nodes using BFS.
shortest_path(
start: NodeRef,
end: NodeRef,
rel_type: Optional[str] = None,
max_hops: int = 10
) -> Optional[Path]
path = graph.shortest_path(('person', 1), ('person', 5))
if path:
print(f"Length: {path.length}")
print(f"Nodes: {path.nodes}")
all_paths
Find all paths between two nodes using DFS.
all_paths(
start: NodeRef,
end: NodeRef,
rel_type: Optional[str] = None,
max_hops: int = 10
) -> List[Path]
Degree Analysis
# Incoming edges count
in_deg = graph.in_degree(('person', 1))
# Outgoing edges count
out_deg = graph.out_degree(('person', 1))
# Total degree
total = graph.degree(('person', 1))
is_connected
Check if all nodes are reachable from any starting node.
is_connected() -> bool
has_cycle
Detect cycles in the graph.
has_cycle(rel_type: Optional[str] = None) -> bool
# Check for cycles in KNOWS relationships
if graph.has_cycle('KNOWS'):
print("Circular friendships detected!")
# Check entire graph
if graph.has_cycle():
print("Graph contains cycles")