Utilities Module API
The utils module provides helper functions for file and path management.
Module: file_utils.py
File system utilities and project path management.
Functions
get_project_paths()
Get standardized project directory paths.
Parameters: None
Returns:
dict: Dictionary with Path objects for all project directories
Structure:
{
'root': Path('/path/to/OpenTestability'),
'data': Path('/path/to/OpenTestability/data'),
'input': Path('/path/to/OpenTestability/data/input'),
'parsed': Path('/path/to/OpenTestability/data/parsed'),
'dag_output': Path('/path/to/OpenTestability/data/dag_output'),
'results': Path('/path/to/OpenTestability/data/results'),
'reconvergence_output': Path('/path/to/OpenTestability/data/reconvergence_output'),
'graphs': Path('/path/to/OpenTestability/data/graphs')
}
Example:
from opentestability.utils.file_utils import get_project_paths
paths = get_project_paths()
input_dir = paths['input']
output_dir = paths['parsed']
print(f"Input directory: {input_dir}")
print(f"Parsed directory: {output_dir}")
# Use paths for file operations
input_file = input_dir / "circuit.v"
output_file = output_dir / "circuit.json"
ensure_directory(directory_path)
Ensure a directory exists, creating it if necessary.
Parameters:
directory_path(Path or str): Path to the directory
Returns: None
Side Effects:
- Creates directory and all parent directories if they don’t exist
Example:
from opentestability.utils.file_utils import ensure_directory, get_project_paths
from pathlib import Path
paths = get_project_paths()
# Ensure standard directory exists
ensure_directory(paths['parsed'])
# Ensure custom subdirectory exists
custom_dir = paths['results'] / 'experiments' / 'test1'
ensure_directory(custom_dir)
# Works with string paths too
ensure_directory("/path/to/custom/output")
Usage Patterns
Standard Project Setup
from opentestability.utils.file_utils import get_project_paths, ensure_directory
# Get project paths
paths = get_project_paths()
# Ensure all directories exist
for name, path in paths.items():
if name != 'root': # Skip root directory
ensure_directory(path)
print("Project structure ready!")
File Path Construction
from opentestability.utils.file_utils import get_project_paths
paths = get_project_paths()
# Construct input file path
input_file = paths['input'] / "serial_ALU.v"
# Construct output file path
output_file = paths['parsed'] / f"{input_file.stem}_parsed.json"
# Check if file exists
if input_file.exists():
print(f"Processing {input_file.name}")
else:
print(f"File not found: {input_file}")
Multiple Output Locations
from opentestability.utils.file_utils import get_project_paths, ensure_directory
paths = get_project_paths()
# Create timestamped output directory
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
experiment_dir = paths['results'] / f"experiment_{timestamp}"
ensure_directory(experiment_dir)
# Save results
output_file = experiment_dir / "scoap_results.json"
Integration Examples
With Parser Module
from opentestability.utils.file_utils import get_project_paths, ensure_directory
from opentestability.parsers.verilog_parser import parse_verilog_netlist
import json
paths = get_project_paths()
# Input and output paths
input_path = paths['input'] / "circuit.v"
output_dir = paths['parsed']
ensure_directory(output_dir)
# Parse
modules = parse_verilog_netlist(str(input_path))
# Save to custom location
output_path = output_dir / "circuit_parsed.json"
with open(output_path, 'w') as f:
json.dump(modules, f, indent=2)
With Core Modules
from opentestability.utils.file_utils import get_project_paths
from opentestability.core.dag_builder import create_dag_from_netlist
from opentestability.core.scoap import run as scoap_run
paths = get_project_paths()
# All modules use get_project_paths internally
# So they work together seamlessly
dag_file = "circuit_parsed.json"
create_dag_from_netlist(dag_file)
# DAG saved to paths['dag_output']
scoap_run("circuit.txt", "scoap.json", json_flag=True)
# Results saved to paths['results']
Custom Directory Structure
from opentestability.utils.file_utils import get_project_paths, ensure_directory
paths = get_project_paths()
# Create custom experiment structure
experiment_name = "fanout_analysis"
experiment_root = paths['results'] / experiment_name
subdirs = ['raw_data', 'processed', 'visualizations', 'reports']
experiment_paths = {}
for subdir in subdirs:
dir_path = experiment_root / subdir
ensure_directory(dir_path)
experiment_paths[subdir] = dir_path
print(f"Experiment structure created: {experiment_root}")
Path Resolution
Relative vs Absolute Paths
from opentestability.utils.file_utils import get_project_paths
paths = get_project_paths()
# All returned paths are absolute
print(f"Root (absolute): {paths['root']}")
print(f"Is absolute: {paths['root'].is_absolute()}") # True
# Convert to relative path
from pathlib import Path
relative = Path('data') / 'input'
absolute = paths['root'] / relative
print(f"Absolute path: {absolute}")
Cross-Platform Compatibility
from opentestability.utils.file_utils import get_project_paths
from pathlib import Path
paths = get_project_paths()
# Path objects work across platforms (Windows, Linux, macOS)
# Use forward slashes in code, Path handles conversion
input_file = paths['input'] / "circuit.v"
# Works on:
# - Windows: C:\Users\...\OpenTestability\data\input\circuit.v
# - Linux: /home/.../OpenTestability/data/input/circuit.v
# - macOS: /Users/.../OpenTestability/data/input/circuit.v
Best Practices
Always Use get_project_paths()
# Good: Portable and consistent
from opentestability.utils.file_utils import get_project_paths
paths = get_project_paths()
input_file = paths['input'] / "circuit.v"
# Bad: Hardcoded paths
input_file = "/home/user/OpenTestability/data/input/circuit.v" # Not portable!
Check Before Operating
from opentestability.utils.file_utils import get_project_paths
paths = get_project_paths()
input_file = paths['input'] / "circuit.v"
if input_file.exists():
# Proceed with operation
with open(input_file, 'r') as f:
content = f.read()
else:
raise FileNotFoundError(f"Required file not found: {input_file}")
Create Directories Before Writing
from opentestability.utils.file_utils import get_project_paths, ensure_directory
paths = get_project_paths()
output_dir = paths['results'] / 'custom_analysis'
# Always ensure directory exists before writing
ensure_directory(output_dir)
output_file = output_dir / "results.json"
with open(output_file, 'w') as f:
json.dump(data, f)
Error Handling
Path Not Found
from opentestability.utils.file_utils import get_project_paths
from pathlib import Path
paths = get_project_paths()
try:
input_file = paths['input'] / "circuit.v"
if not input_file.exists():
raise FileNotFoundError(f"Input file not found: {input_file}")
# Process file
with open(input_file, 'r') as f:
data = f.read()
except FileNotFoundError as e:
print(f"Error: {e}")
print(f"Please place your Verilog files in: {paths['input']}")
Permission Errors
from opentestability.utils.file_utils import ensure_directory
import os
try:
ensure_directory("/restricted/path")
except PermissionError as e:
print(f"Permission denied: {e}")
print("Please choose a writable location")
Advanced Usage
Listing Files in Directories
from opentestability.utils.file_utils import get_project_paths
paths = get_project_paths()
# List all Verilog files
verilog_files = list(paths['input'].glob("*.v"))
print(f"Found {len(verilog_files)} Verilog files:")
for vfile in verilog_files:
print(f" - {vfile.name}")
# List all JSON files recursively
json_files = list(paths['parsed'].rglob("*.json"))
print(f"\nFound {len(json_files)} JSON files (recursive)")
File Size and Modification Time
from opentestability.utils.file_utils import get_project_paths
from datetime import datetime
paths = get_project_paths()
for json_file in paths['parsed'].glob("*.json"):
size = json_file.stat().st_size
mtime = datetime.fromtimestamp(json_file.stat().st_mtime)
print(f"{json_file.name}:")
print(f" Size: {size:,} bytes")
print(f" Modified: {mtime.strftime('%Y-%m-%d %H:%M:%S')}")
Backup and Cleanup
from opentestability.utils.file_utils import get_project_paths
import shutil
from datetime import datetime
paths = get_project_paths()
# Create backup
backup_dir = paths['root'] / 'backups' / datetime.now().strftime("%Y%m%d")
ensure_directory(backup_dir)
for result_file in paths['results'].glob("*.json"):
backup_file = backup_dir / result_file.name
shutil.copy2(result_file, backup_file)
print(f"Backed up results to: {backup_dir}")
# Clean old temporary files
temp_files = paths['data'].glob("*.tmp")
for tmp in temp_files:
tmp.unlink()
Configuration
Custom Project Root
By default, get_project_paths() finds the project root automatically. To use a custom root:
from pathlib import Path
import os
# Set custom project root (before importing other modules)
os.environ['OPENTESTABILITY_ROOT'] = '/path/to/custom/location'
from opentestability.utils.file_utils import get_project_paths
paths = get_project_paths()
# Now uses custom root
Adding New Directory Types
To extend with custom directories:
from opentestability.utils.file_utils import get_project_paths, ensure_directory
paths = get_project_paths()
# Add custom paths
paths['experiments'] = paths['data'] / 'experiments'
paths['reports'] = paths['data'] / 'reports'
paths['temp'] = paths['data'] / 'temp'
# Ensure they exist
for key in ['experiments', 'reports', 'temp']:
ensure_directory(paths[key])
Dependencies
Required Packages
- pathlib: Built-in (Python 3.4+)
- os: Built-in
No External Dependencies
The utils module has no external dependencies, making it lightweight and always available.
Performance
Path Operations
get_project_paths(): O(1), cached internallyensure_directory(): O(1) if exists, O(n) for nested creation- Path objects are lightweight and fast
Best Practices
# Good: Call once, reuse
paths = get_project_paths()
for file in input_files:
process(paths['input'] / file)
# Less optimal: Multiple calls
for file in input_files:
paths = get_project_paths() # Unnecessary repeated calls
process(paths['input'] / file)
Complete Example
Full Project Workflow with Utils
from opentestability.utils.file_utils import get_project_paths, ensure_directory
from opentestability.parsers.verilog_parser import parse
from opentestability.core.dag_builder import create_dag_from_netlist
from opentestability.core.scoap import run as scoap_run
from opentestability.visualization.graph_renderer import visualize_gate_graph
import json
# Setup paths
paths = get_project_paths()
print(f"Working in: {paths['root']}")
# Ensure all directories exist
for name, path in paths.items():
if name != 'root':
ensure_directory(path)
# Find input files
verilog_files = list(paths['input'].glob("*.v"))
print(f"\nFound {len(verilog_files)} Verilog files")
# Process each file
for vfile in verilog_files:
print(f"\nProcessing {vfile.name}...")
# Parse
basename = vfile.stem
parse(vfile.name, f"{basename}.txt")
# Create DAG
create_dag_from_netlist(f"{basename}_parsed.json")
# SCOAP analysis
scoap_run(f"{basename}.txt", f"{basename}_scoap.json", json_flag=True)
# Visualize
visualize_gate_graph(f"{basename}_dag.json")
print(f"✓ Completed {basename}")
print("\nAll files processed!")
print(f"Results in: {paths['results']}")
print(f"Graphs in: {paths['graphs']}")