Source code for bout_runners.log.log_reader

"""Module containing the LogReader class."""


import logging
import re
from datetime import datetime
from pathlib import Path
from typing import Optional


[docs]class LogReader: """ Class for reading BOUT++ log files. Attributes ---------- file_str : str The log file as a string start_time : None or str The time of the execution start (given that it has started) end_time : None or str The time of the execution end (given that it has started) pid : None or int The processor id of the part of the program writing to the log file Methods ------- started() Whether or not the execution has started ended() Whether or not the execution has ended pid_exist() Whether or not the pid can be found __is_str_in_file(pattern) Check whether regex-pattern exists in file __find_locale_time(pattern) Return the locale time of a regex capture Examples -------- >>> from pathlib import Path >>> path = Path().joinpath('path', 'to', 'BOUT.log.0') >>> log_reader = LogReader(path) >>> log_reader.start_time '2020-05-01 17:07:10' >>> log_reader.end_time '2020-05-01 17:07:14' >>> log_reader.pid 1190 """ def __init__(self, log_path: Path) -> None: """ Open and read a log file. Parameters ---------- log_path : str or Path Absolute path to log file """ with Path(log_path).open("r") as log_file: self.file_str = log_file.read() logging.debug("Opened log_file %s", log_path)
[docs] def started(self) -> bool: """ Check whether the run has a start time. Returns ------- bool True if the start signature is found in the file """ return self.__is_str_in_file(r"^Run started at")
[docs] def ended(self) -> bool: """ Check whether the run has an end time. Returns ------- bool True if the end signature is found in the file """ return self.__is_str_in_file(r"^Run finished at")
[docs] def pid_exist(self) -> bool: """ Check whether a process id exist. Returns ------- bool True if the pid is found """ return self.__is_str_in_file(r"^pid\s*:\s*")
@property def start_time(self) -> Optional[datetime]: """ Return the start time of the process. Returns ------- datetime or None The start time on date time format """ if self.started(): return self.__find_locale_time(r"^Run started at : (.*)") return None @property def end_time(self) -> Optional[datetime]: """ Return the end time of the process. Returns ------- datetime or None The end time on date time format """ if self.ended(): return self.__find_locale_time(r"^Run finished at : (.*)") return None @property def pid(self) -> Optional[int]: """ Return the pid of the process. Returns ------- int or None The pid of the process """ if self.pid_exist(): pattern = r"^pid:\s*(\d*)\s*$" # Using search as match will only search the beginning of # the string # https://stackoverflow.com/a/32134461/2786884 match = re.search(pattern, self.file_str, flags=re.MULTILINE) if match is None: return None return int(match.group(1)) return None def __is_str_in_file(self, pattern: str) -> bool: """ Check whether regex-pattern exists in file. Parameters ---------- pattern : str Regex pattern to search for Returns ------- bool True if pattern exist """ # Using search as match will only search the beginning of the # string # https://stackoverflow.com/a/32134461/2786884 match = re.search(pattern, self.file_str, flags=re.MULTILINE) if match is None: return False return True def __find_locale_time(self, pattern: str) -> datetime: """ Return the locale time of a regex capture. Parameters ---------- pattern : str String to search for Returns ------- time : datetime The locale datetime Raises ------ ValueError If no matches for pattern is found in self.file_str """ # Using search as match will only search the beginning of the # string # https://stackoverflow.com/a/32134461/2786884 match = re.search(pattern, self.file_str, flags=re.MULTILINE) if match is None: raise ValueError(f"No matches in {self.file_str} with pattern {pattern}") time_str = match.group(1) time = datetime.strptime(time_str, "%c") return time