diff --git a/src/graphedexcel/__main__.py b/src/graphedexcel/__main__.py index a583f94..c5e9f1a 100644 --- a/src/graphedexcel/__main__.py +++ b/src/graphedexcel/__main__.py @@ -6,7 +6,7 @@ import logging import src.graphedexcel.logger_config # noqa -logger = logging.getLogger(__name__) +logger = logging.getLogger("graphedexcel.main") if __name__ == "__main__": if len(sys.argv) > 1: @@ -25,22 +25,34 @@ print_summary(dependency_graph, functions) - if "--no-visualize" not in sys.argv: - logger.info( - "\033[1;30;40m\nVisualizing the graph of dependencies.\nThis might take a while...\033[0;37;40m\n" # noqa - ) - - # if commandline argument --config is provided with a path to a JSON file, pass that path to the visualizer - if "--layout" in sys.argv: - layout_index = sys.argv.index("--layout") - layout = sys.argv[layout_index + 1] - else: - layout = "spring" - - if "--config" in sys.argv: - config_index = sys.argv.index("--config") - config_path = sys.argv[config_index + 1] - else: - config_path = None - - visualize_dependency_graph(dependency_graph, path_to_excel, config_path, layout) + if "--no-visualize" in sys.argv: + logger.info("Skipping visualization.") + sys.exit(0) + + logger.info("Visualizing the graph of dependencies. (This might take a while...)") + + if "--layout" in sys.argv: + layout_index = sys.argv.index("--layout") + layout = sys.argv[layout_index + 1] + else: + layout = "spring" + + if "--config" in sys.argv: + config_index = sys.argv.index("--config") + config_path = sys.argv[config_index + 1] + else: + config_path = None + + filename = f"{path_to_excel}_dependency_graph.png" + + if "--output-path" in sys.argv: + output_index = sys.argv.index("--output-path") + filename = sys.argv[output_index + 1] + + visualize_dependency_graph( + dependency_graph, path_to_excel, filename, config_path, layout + ) + + # Open the image file + if "--open-image" in sys.argv: + os.startfile(filename) diff --git a/src/graphedexcel/graph_visualizer.py b/src/graphedexcel/graph_visualizer.py index bf4d33f..f4c96a9 100644 --- a/src/graphedexcel/graph_visualizer.py +++ b/src/graphedexcel/graph_visualizer.py @@ -9,18 +9,12 @@ import logging +logger = logging.getLogger(__name__) + # Use a non-interactive backend for matplotlib. # No need to show plots, just save them. matplotlib.use("Agg") -# Configure logging at the top of your script -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s [%(levelname)s] %(message)s", - handlers=[logging.StreamHandler()], -) - - # Default settings for the graph visualization base_graph_settings = { "node_size": 50, # the size of the node @@ -99,16 +93,16 @@ def get_graph_default_settings(graph_size: int, config_path: str = None) -> dict custom_settings = load_json_config(config_path) plot_settings = merge_configs(plot_settings, custom_settings) except FileNotFoundError: - logging.error( + logger.error( f"Config file not found: {config_path}. Using default settings." ) except json.JSONDecodeError: - logging.error( + logger.error( f"Invalid JSON format in config file: {config_path}. Using default settings." ) except Exception as e: - logging.error( + logger.error( f"Error loading config file: {config_path}. Using default settings.\n{e}" ) @@ -147,7 +141,11 @@ def get_node_colors_and_legend(graph: nx.DiGraph, cmap_id: str) -> tuple[list, l def visualize_dependency_graph( - graph: nx.DiGraph, file_path: str, config_path: str = None, layout: str = "spring" + graph: nx.DiGraph, + file_path: str, + output_path: str, + config_path: str = None, + layout: str = "spring", ): """ Render the dependency graph using matplotlib and networkx. @@ -160,17 +158,17 @@ def visualize_dependency_graph( # Set the default settings for the graph visualization based on the number of nodes graph_settings = get_graph_default_settings(len(graph.nodes), config_path) - logging.info( - f"Using the following settings for the graph visualization: \n{graph_settings}" + logger.info( + f"Using the following settings for the graph visualization: {graph_settings}" ) fig_size = calculate_fig_size(len(graph.nodes)) - logging.info(f"Calculated figure size: {fig_size}") + logger.info(f"Calculated figure size: {fig_size}") figsize_override = graph_settings.pop("fig_size", None) # Remove fig_size from graph_settings if figsize_override: - logging.info(f"Using size from settings: {figsize_override}") + logger.info(f"Using size from settings: {figsize_override}") fig_size = figsize_override plt.figure(figsize=fig_size) @@ -182,7 +180,7 @@ def visualize_dependency_graph( elif layout == "circular": pos = nx.circular_layout(graph) else: - logging.warning(f"Unknown layout '{layout}'. Falling back to spring layout.") + logger.warning(f"Unknown layout '{layout}'. Falling back to spring layout.") pos = nx.spring_layout(graph) # Assign colors and get legend patches @@ -199,14 +197,7 @@ def visualize_dependency_graph( plt.legend(handles=legend_patches, title="Sheets", loc="upper left") - filename = f"{file_path}.png" - plt.savefig(filename, bbox_inches="tight") # Ensure layout fits + plt.savefig(output_path, bbox_inches="tight") # Ensure layout fits plt.close() # Close the figure to free memory - logging.info(f"Graph visualization saved to {filename}") - - # Open the image file on Windows if specified - if "--open-image" in sys.argv: - import os - - os.startfile(filename) + logger.info(f"Graph visualization saved to {output_path}") diff --git a/src/graphedexcel/logger_config.py b/src/graphedexcel/logger_config.py index d3daba4..acfb6d7 100644 --- a/src/graphedexcel/logger_config.py +++ b/src/graphedexcel/logger_config.py @@ -13,6 +13,7 @@ "simple": { "format": "%(levelname)s: %(message)s", }, + "minimal": {"format": "%(message)s"}, }, "handlers": { "console": { @@ -20,6 +21,11 @@ "formatter": "simple", "class": "logging.StreamHandler", }, + "minimalconsole": { + "level": "INFO", + "formatter": "minimal", + "class": "logging.StreamHandler", + }, "file": { "level": "DEBUG", "formatter": "standard", @@ -27,16 +33,16 @@ "filename": "app.log", "encoding": "utf8", "mode": "w", # 'a' for append, 'w' for overwrite - }, # You can add more handlers (e.g., FileHandler) here + }, }, "loggers": { - "": { # Root logger + "graphedexcel": { "handlers": ["console", "file"], "level": "DEBUG", "propagate": False, }, - # Define loggers for specific modules if needed }, + "root": {"handlers": ["minimalconsole"], "level": "WARNING"}, } logging.config.dictConfig(logging_config)