Source code for dpg.utils
import os
import re
import shutil
import yaml
from graphviz import Digraph
import networkx as nx
import pandas as pd
import numpy as np
[docs]
def highlight_class_node(dot, dpg_config=None):
"""
Highlights nodes in the Graphviz Digraph that contain "Class" in their identifiers by changing their fill color
and adding a rounded shape.
Args:
dot: A Graphviz Digraph object.
dpg_config: Optional DPG config dict (from DecisionPredicateGraph)
Returns:
dot: The modified Graphviz Digraph object with the class nodes highlighted.
"""
if not isinstance(dot, Digraph):
raise ValueError("Input must be a Graphviz Digraph object")
# Get class node styling from config or use defaults
if dpg_config is not None:
class_style = dpg_config.get('dpg', {}).get('visualization', {}).get('class_node', {})
else:
# Fallback to loading from config file
config_path="config.yaml"
try:
with open(config_path) as f:
config = yaml.safe_load(f)
class_style = config.get('dpg', {}).get('visualization', {}).get('class_node', {})
except FileNotFoundError:
class_style = {}
except yaml.YAMLError as e:
raise yaml.YAMLError(f"Invalid YAML in config file: {str(e)}")
# Get values with defaults
fillcolor = class_style.get('fillcolor', '#a4c2f4') # Default light blue
shape = class_style.get('shape', 'box')
style = class_style.get('style', 'rounded, filled')
# Iterate over each line in the dot body
for i, line in enumerate(dot.body):
# Check for class labels in the node attributes
if 'label="Class' in line:
new_attrs = f'fillcolor="{fillcolor}" shape={shape} style="{style}"'
if '[' in line:
pre, rest = line.split('[', 1)
attrs = rest.rsplit(']', 1)[0]
# Remove existing attributes we're replacing (quoted or unquoted)
attrs = re.sub(r'\b(fillcolor|shape|style)=(".*?"|[^ \]]+)', '', attrs)
attrs = re.sub(r'\s+', ' ', attrs).strip()
if attrs:
attrs = attrs + ' '
dot.body[i] = f"{pre}[{attrs}{new_attrs}]"
else:
node_id = line.split(' ')[0]
dot.body[i] = f'{node_id} [{new_attrs}]'
# Return the modified Graphviz Digraph object
return dot
[docs]
def change_node_color(graph, node_id, new_color):
"""
Changes the fill color of a specified node in the Graphviz Digraph.
Args:
graph: A Graphviz Digraph object.
node_id: The identifier of the node whose color is to be changed.
new_color: The new color to be applied to the node.
Returns:
None
"""
if not any(node_id in line for line in graph.body):
raise ValueError(f"Node {node_id} not found in graph")
# Remove existing color attribute if present
for i, line in enumerate(graph.body):
if node_id in line and 'fillcolor=' in line:
parts = line.split('fillcolor=')
graph.body[i] = parts[0] + parts[1].split(']')[0][-1] + ']'
# Append a new line to the graph body to change the fill color of the specified node
graph.body.append(f'{node_id} [fillcolor="{new_color}"]')
[docs]
def delete_folder_contents(folder_path):
"""
Deletes all contents of the specified folder.
Args:
folder_path: The path to the folder whose contents are to be deleted.
Returns:
None
"""
if not os.path.isdir(folder_path):
raise ValueError(f"Path {folder_path} is not a valid directory")
# Iterate over each item in the folder
for item in os.listdir(folder_path):
item_path = os.path.join(folder_path, item) # Get the full path of the item
try:
# Check if the item is a file or a symbolic link
if os.path.isfile(item_path) or os.path.islink(item_path):
os.unlink(item_path) # Remove the file or link
elif os.path.isdir(item_path):
shutil.rmtree(item_path) # Remove the directory and its contents
except Exception as e:
# Print an error message if the deletion fails
print(f'Failed to delete {item_path}. Reason: {e}')