Python API
While grph CLI is primarily a command-line tool, you can also use its components directly in Python code.
Installation
pip install gfx-cli
Core Classes
GEXFGraph
The main class for parsing and querying GEXF files.
from gfx.parser import GEXFGraph
# Load a graph
graph = GEXFGraph("network.gexf")
# Access metadata
print(f"Nodes: {graph.metadata.node_count}")
print(f"Edges: {graph.metadata.edge_count}")
print(f"Creator: {graph.metadata.creator}")
# Get graph info
info = graph.get_info()
print(f"Node attributes: {info['node_attributes']}")
print(f"Edge attributes: {info['edge_attributes']}")
Querying Nodes
from gfx.parser import GEXFGraph
graph = GEXFGraph("network.gexf")
# List all nodes
for node in graph.nodes():
print(f"{node.id}: {node.label}")
# Filter by attribute
servers = graph.nodes(attr_filters=[("type", "server")])
for node in servers:
print(f"Server: {node.label}")
# Filter by label pattern
web_nodes = graph.nodes(label_pattern="Web*")
for node in web_nodes:
print(f"Web node: {node.label}")
# Combine filters (AND logic)
heavy_servers = graph.nodes(
attr_filters=[("type", "server"), ("weight", "2.0")]
)
# Get a specific node
node = graph.get_node("server1")
if node:
print(f"Found: {node.label}")
Querying Edges
from gfx.parser import GEXFGraph
graph = GEXFGraph("network.gexf")
# List all edges
for edge in graph.edges():
print(f"{edge.source} -> {edge.target}")
# Filter by source
lb_edges = graph.edges(source_filter="lb1")
# Filter by target
db_edges = graph.edges(target_filter="db1")
# Filter by attribute
query_edges = graph.edges(attr_filters=[("relationship", "queries")])
# Combine filters
specific_edges = graph.edges(
source_filter="server1",
target_filter="db1",
attr_filters=[("relationship", "queries")]
)
Data Models
from gfx.models import Node, Edge, GraphMetadata
# Nodes are dataclasses
node = Node(
id="n1",
label="My Node",
attributes={"type": "server", "weight": 1.5}
)
# Convert to dict for JSON serialization
node_dict = node.to_dict()
# {"id": "n1", "label": "My Node", "attributes": {"type": "server", "weight": 1.5}}
# Check if node matches filters
matches = node.matches_filters(
attr_filters=[("type", "server")],
label_pattern="My*"
)
Error Handling
from gfx.parser import GEXFGraph, GEXFParseError
try:
graph = GEXFGraph("invalid.gexf")
except GEXFParseError as e:
print(f"Failed to parse: {e}")
Common errors:
File not found: <path>- File doesn't existNot a file: <path>- Path is a directoryFailed to parse GEXF file: <details>- Invalid GEXF content
Output Formatting
from gfx.parser import GEXFGraph
from gfx.formatters import (
print_metadata_table,
print_nodes_table,
print_edges_table,
print_info_table,
format_json,
)
from rich.console import Console
graph = GEXFGraph("network.gexf")
console = Console()
# Print as tables
print_metadata_table(graph.metadata, console)
print_nodes_table(graph.nodes(), console=console)
print_edges_table(graph.edges(), console=console)
print_info_table(graph.get_info(), console=console)
# Get JSON string
nodes_json = format_json(list(graph.nodes()))
print(nodes_json)
Complete Example
#!/usr/bin/env python3
"""Analyze a graph and find important nodes."""
from gfx.parser import GEXFGraph, GEXFParseError
from collections import Counter
def analyze_connectivity(filepath: str) -> None:
"""Find the most connected nodes in a graph."""
try:
graph = GEXFGraph(filepath)
except GEXFParseError as e:
print(f"Error: {e}")
return
print(f"Analyzing: {filepath}")
print(f" Nodes: {graph.metadata.node_count}")
print(f" Edges: {graph.metadata.edge_count}")
print()
# Count outgoing edges per node
edges = list(graph.edges())
out_degree = Counter(e.source for e in edges)
in_degree = Counter(e.target for e in edges)
# Find hub nodes (high out-degree)
print("Top 5 Hub Nodes (outgoing edges):")
for node_id, count in out_degree.most_common(5):
node = graph.get_node(node_id)
label = node.label if node else node_id
print(f" {label}: {count} outgoing edges")
print()
# Find authority nodes (high in-degree)
print("Top 5 Authority Nodes (incoming edges):")
for node_id, count in in_degree.most_common(5):
node = graph.get_node(node_id)
label = node.label if node else node_id
print(f" {label}: {count} incoming edges")
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <file.gexf>")
sys.exit(1)
analyze_connectivity(sys.argv[1])
Type Hints
All public APIs are fully typed:
from gfx.parser import GEXFGraph
from gfx.models import Node, Edge, GraphMetadata
from typing import Iterator
def process_servers(graph: GEXFGraph) -> list[Node]:
"""Get all server nodes."""
servers: Iterator[Node] = graph.nodes(attr_filters=[("type", "server")])
return list(servers)