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

1#!/usr/bin/env python3 

2# -*- coding: UTF-8 -*- 

3"""Helper functions to log which output was created by Sparkle where.""" 

4 

5from __future__ import annotations 

6import time 

7from pathlib import Path 

8 

9from runrunner.logger import Log as RunRunnerLog 

10 

11from sparkle.platform import Settings 

12 

13 

14# Keep track of which command called Sparkle 

15global caller 

16caller: str = "unknown" 

17 

18# Current caller file path 

19global caller_log_path 

20caller_log_path: Path = "not set" 

21 

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(".") 

26 

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(".") 

31 

32 

33def _update_caller(argv: list[str]) -> None: 

34 """Update which command is currently active. 

35 

36 Args: 

37 argv: List containing the command line arguments derived from sys.argv. 

38 

39 """ 

40 global caller 

41 caller = Path(argv[0]).stem 

42 

43 

44def _update_caller_file_path(timestamp: str) -> None: 

45 """Create a new file path for the caller with the given timestamp. 

46 

47 Args: 

48 timestamp: String representation of the time. 

49 

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 

61 

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) 

66 

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) 

72 

73 

74def add_output(output_path: str, description: str) -> None: 

75 """Add output location and description to the log of the current command. 

76 

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. 

80 

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) 

88 

89 

90def log_command(argv: list[str], seed: int = None) -> None: 

91 """Write to file which command was executed. 

92 

93 Includes information on when it was executed, with which arguments, and 

94 where details about it's output are stored (if any). 

95 

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) 

102 

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" 

109 

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 

115 

116 # Write to log file 

117 with log_path.open("a") as log_file: 

118 log_file.write(log_str) 

119 

120 # Pipe RunRunner log to the caller log 

121 RunRunnerLog.set_log_file(caller_log_path)