|
1 | 1 | import os
|
2 | 2 | import sys
|
3 |
| -from .graphbuilder import extract_formulas_and_build_dependencies |
| 3 | +import argparse |
| 4 | +import logging |
| 5 | +from .graphbuilder import build_graph_and_stats |
4 | 6 | from .graph_summarizer import print_summary
|
5 | 7 | from .graph_visualizer import visualize_dependency_graph
|
| 8 | +import src.graphedexcel.logger_config # noqa |
6 | 9 |
|
7 |
| -if __name__ == "__main__": |
8 |
| - if len(sys.argv) > 1: |
9 |
| - path_to_excel = sys.argv[1] |
10 |
| - else: |
11 |
| - print("Please provide the path to the Excel file as an argument.") |
12 |
| - sys.exit(1) |
| 10 | +logger = logging.getLogger("graphedexcel.main") |
| 11 | + |
| 12 | + |
| 13 | +def parse_arguments(): |
| 14 | + parser = argparse.ArgumentParser( |
| 15 | + prog="graphedexcel", |
| 16 | + description="Process an Excel file to build and visualize dependency graphs.", |
| 17 | + ) |
| 18 | + |
| 19 | + # Positional argument for the path to the Excel file |
| 20 | + parser.add_argument( |
| 21 | + "path_to_excel", type=str, help="Path to the Excel file to process." |
| 22 | + ) |
| 23 | + |
| 24 | + # Optional flags with shorthand aliases |
| 25 | + parser.add_argument( |
| 26 | + "--remove-unconnected", |
| 27 | + "-r", |
| 28 | + action="store_true", |
| 29 | + help="Remove unconnected nodes from the dependency graph.", |
| 30 | + ) |
| 31 | + |
| 32 | + parser.add_argument( |
| 33 | + "--as-directed-graph", |
| 34 | + "-d", |
| 35 | + action="store_true", |
| 36 | + help="Treat the dependency graph as directed.", |
| 37 | + ) |
| 38 | + |
| 39 | + parser.add_argument( |
| 40 | + "--no-visualize", |
| 41 | + "-n", |
| 42 | + action="store_true", |
| 43 | + help="Skip the visualization of the dependency graph.", |
| 44 | + ) |
| 45 | + |
| 46 | + parser.add_argument( |
| 47 | + "--layout", |
| 48 | + "-l", |
| 49 | + type=str, |
| 50 | + default="spring", |
| 51 | + choices=["spring", "circular", "kamada_kawai", "shell", "spectral"], |
| 52 | + help="Layout algorithm for graph visualization (default: spring).", |
| 53 | + ) |
| 54 | + |
| 55 | + parser.add_argument( |
| 56 | + "--config", |
| 57 | + "-c", |
| 58 | + type=str, |
| 59 | + help="Path to the configuration file for visualization. See README for details.", |
| 60 | + ) |
| 61 | + |
| 62 | + parser.add_argument( |
| 63 | + "--output-path", |
| 64 | + "-o", |
| 65 | + type=str, |
| 66 | + default=None, |
| 67 | + help="Specify the output path for the generated graph image.", |
| 68 | + ) |
| 69 | + |
| 70 | + parser.add_argument( |
| 71 | + "--open-image", |
| 72 | + action="store_true", |
| 73 | + help="Open the generated image after visualization.", |
| 74 | + ) |
| 75 | + |
| 76 | + return parser.parse_args() |
13 | 77 |
|
14 |
| - # does the file exist? |
| 78 | + |
| 79 | +def main(): |
| 80 | + args = parse_arguments() |
| 81 | + |
| 82 | + path_to_excel = args.path_to_excel |
| 83 | + |
| 84 | + # Check if the file exists |
15 | 85 | if not os.path.exists(path_to_excel):
|
16 |
| - print(f"File not found: {path_to_excel}") |
| 86 | + logger.error(f"File not found: {path_to_excel}") |
17 | 87 | sys.exit(1)
|
18 | 88 |
|
19 |
| - # Extract formulas and build the dependency graph |
20 |
| - dependency_graph, functions = extract_formulas_and_build_dependencies(path_to_excel) |
| 89 | + # Build the dependency graph and gather statistics |
| 90 | + dependency_graph, function_stats = build_graph_and_stats( |
| 91 | + path_to_excel, |
| 92 | + remove_unconnected=args.remove_unconnected, |
| 93 | + as_directed=args.as_directed_graph, |
| 94 | + ) |
| 95 | + |
| 96 | + # Print summary of the dependency graph |
| 97 | + print_summary(dependency_graph, function_stats) |
| 98 | + |
| 99 | + if args.no_visualize: |
| 100 | + logger.info("Skipping visualization as per the '--no-visualize' flag.") |
| 101 | + sys.exit(0) |
| 102 | + |
| 103 | + logger.info("Visualizing the graph of dependencies. (This might take a while...)") |
| 104 | + |
| 105 | + # Determine layout |
| 106 | + layout = args.layout |
21 | 107 |
|
22 |
| - print_summary(dependency_graph, functions) |
| 108 | + # Configuration path |
| 109 | + config_path = args.config |
23 | 110 |
|
24 |
| - if "--no-visualize" not in sys.argv: |
25 |
| - print( |
26 |
| - "\033[1;30;40m\nVisualizing the graph of dependencies.\nThis might take a while...\033[0;37;40m\n" # noqa |
27 |
| - ) |
| 111 | + # Determine output filename |
| 112 | + if args.output_path: |
| 113 | + filename = args.output_path |
| 114 | + else: |
| 115 | + # Create a default filename based on the Excel file name |
| 116 | + base_name = os.path.splitext(os.path.basename(path_to_excel))[0] |
| 117 | + filename = f"{base_name}_dependency_graph.png" |
| 118 | + |
| 119 | + # Visualize the dependency graph |
| 120 | + visualize_dependency_graph(dependency_graph, filename, config_path, layout) |
| 121 | + |
| 122 | + logger.info(f"Dependency graph image saved to {filename}.") |
| 123 | + |
| 124 | + # Open the image file if requested |
| 125 | + if args.open_image: |
| 126 | + try: |
| 127 | + os.startfile(filename) # Note: os.startfile is Windows-specific |
| 128 | + except AttributeError: |
| 129 | + # For macOS and Linux, use 'open' and 'xdg-open' respectively |
| 130 | + import subprocess |
| 131 | + import platform |
28 | 132 |
|
29 |
| - # if commandline argument --config is provided with a path to a JSON file, pass that path to the visualizer |
| 133 | + if platform.system() == "Darwin": # macOS |
| 134 | + subprocess.call(["open", filename]) |
| 135 | + elif platform.system() == "Linux": |
| 136 | + subprocess.call(["xdg-open", filename]) |
| 137 | + else: |
| 138 | + logger.warning("Unable to open the image automatically on this OS.") |
30 | 139 |
|
31 |
| - if "--config" in sys.argv: |
32 |
| - config_index = sys.argv.index("--config") |
33 |
| - config_path = sys.argv[config_index + 1] |
34 |
| - visualize_dependency_graph(dependency_graph, path_to_excel, config_path) |
35 |
| - else: |
36 |
| - visualize_dependency_graph(dependency_graph, path_to_excel) |
| 140 | + |
| 141 | +if __name__ == "__main__": |
| 142 | + try: |
| 143 | + main() |
| 144 | + except Exception as e: |
| 145 | + logger.exception("An unexpected error occurred:", e) |
| 146 | + sys.exit(1) |
0 commit comments