Coverage for sparkle/CLI/help/logging.py: 100%
44 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-29 10:17 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-29 10:17 +0000
1#!/usr/bin/env python3
2# -*- coding: UTF-8 -*-
3"""Helper functions to log which output was created by Sparkle where."""
5from __future__ import annotations
6import time
7from pathlib import Path
9from runrunner.logger import Log as RunRunnerLog
11from sparkle.platform import Settings
14# Keep track of which command called Sparkle
15global caller
16caller: str = "unknown"
18# Current caller file path
19global caller_log_path
20caller_log_path: Path = "not set"
22# Root output directory for the calling command in the form of
23# Output/<timestamp>_<command_name>/
24global caller_out_dir
25caller_out_dir: Path = Path(".")
27# Log directory for the calling command in the form of
28# Output/<timestamp>_<command_name>/Log/
29global caller_log_dir
30caller_log_dir: Path = Path(".")
33def _update_caller(argv: list[str]) -> None:
34 """Update which command is currently active.
36 Args:
37 argv: List containing the command line arguments derived from sys.argv.
39 """
40 global caller
41 caller = Path(argv[0]).stem
44def _update_caller_file_path(timestamp: str) -> None:
45 """Create a new file path for the caller with the given timestamp.
47 Args:
48 timestamp: String representation of the time.
50 """
51 caller_file = caller + "_main_log.txt"
52 caller_dir = Path(caller + "_" + timestamp)
53 log_dir = Settings.DEFAULT_log_output
54 # Set caller directory for other Sparkle functions to use
55 global caller_out_dir
56 caller_out_dir = Path(caller_dir)
57 global caller_log_path
58 caller_log_path = Path(log_dir / caller_out_dir / caller_file)
59 global caller_log_dir
60 caller_log_dir = log_dir / caller_out_dir
62 # Create needed directories if they don't exist
63 caller_dir = caller_log_path.parents[0]
64 caller_dir.mkdir(parents=True, exist_ok=True)
65 caller_log_dir.mkdir(parents=True, exist_ok=True)
67 # If the caller output file does not exist yet, write the header
68 if not caller_log_path.is_file():
69 output_header = "\t Timestamp\t\t\t\t\t\t\t Path\t\t\t\t\t\t\t Description\n"
70 with caller_log_path.open("a") as output_file:
71 output_file.write(output_header)
74def add_output(output_path: str, description: str) -> None:
75 """Add output location and description to the log of the current command.
77 Args:
78 output_path: The file path of where output is written to.
79 description: A short description of what kind of output is written to this file.
81 """
82 # Prepare logging information
83 timestamp = time.strftime("%Y-%m-%d-%H.%M.%S", time.localtime(time.time()))
84 output_str = f"{timestamp}\t{output_path}\t{description}\n"
85 # Write output path and description to caller file
86 with caller_log_path.open("a") as output_file:
87 output_file.write(output_str)
90def log_command(argv: list[str], seed: int = None) -> None:
91 """Write to file which command was executed.
93 Includes information on when it was executed, with which arguments, and
94 where details about it's output are stored (if any).
96 Args:
97 argv: List containing the command line arguments derived from sys.argv.
98 seed: Optionally, the seed that corresponds to the set random state.
99 """
100 # Determine caller
101 _update_caller(argv)
103 # Prepare logging information
104 timestamp = time.strftime("%Y-%m-%d-%H.%M.%S", time.localtime(time.time()))
105 _update_caller_file_path(timestamp)
106 args = " ".join(argv)
107 log_str = f"{timestamp} {args} {str(caller_log_path)}"
108 log_str += "\n" if seed is None else f" {seed}\n"
110 # If the log file does not exist yet, write the header
111 log_path = Settings.DEFAULT_output / "sparkle.log"
112 if not log_path.is_file():
113 log_header = "\t Timestamp\t\t\t\t\t\t\t Command\t\t\t\t\t\t\t Output details\t\t\t\t\t\t\t Seed\n"
114 log_str = log_header + log_str
116 # Write to log file
117 with log_path.open("a") as log_file:
118 log_file.write(log_str)
120 # Pipe RunRunner log to the caller log
121 RunRunnerLog.set_log_file(caller_log_path)