diff --git a/janus_core/cli.py b/janus_core/cli.py index 4569531a..9a146c4b 100644 --- a/janus_core/cli.py +++ b/janus_core/cli.py @@ -1,6 +1,7 @@ """Set up commandline interface.""" import ast +from pathlib import Path from typing import Annotated import typer @@ -107,7 +108,7 @@ def singlepoint( ), ] = None, log_file: Annotated[ - str, typer.Option("--log", help="File to save logs") + Path, typer.Option("--log", help="Path to save logs to") ] = "singlepoint.log", ): """ @@ -130,8 +131,8 @@ def singlepoint( Keyword arguments to pass to the selected calculator. Default is {}. write_kwargs : Optional[dict[str, Any]] Keyword arguments to pass to ase.io.write when saving results. Default is {}. - log_file : Optional[str] - Name of log file to write logs to. Default is "singlepoint.log". + log_file : Optional[Path] + Path to write logs to. Default is "singlepoint.log". """ read_kwargs = read_kwargs.value if read_kwargs else {} calc_kwargs = calc_kwargs.value if calc_kwargs else {} diff --git a/janus_core/janus_types.py b/janus_core/janus_types.py index 83e06d0b..810b323f 100644 --- a/janus_core/janus_types.py +++ b/janus_core/janus_types.py @@ -58,7 +58,7 @@ class ASEOptRunArgs(TypedDict, total=False): steps: int -class Log(Enum): +class LogLevel(Enum): """Supported options for logger levels.""" DEBUG = logging.DEBUG @@ -67,9 +67,6 @@ class Log(Enum): ERROR = logging.ERROR -LogType = Literal[Log.DEBUG, Log.INFO, Log.ERROR, Log.WARNING] - - # Janus specific Architectures = Literal["mace", "mace_mp", "mace_off", "m3gnet", "chgnet"] Devices = Literal["cpu", "cuda", "mps"] diff --git a/janus_core/log.py b/janus_core/log.py index 4773d9bc..1763832a 100644 --- a/janus_core/log.py +++ b/janus_core/log.py @@ -1,8 +1,9 @@ -"""Configure logger.""" +"""Configure logger with yaml-styled format.""" import logging +from typing import Optional -from janus_core.janus_types import LogType +from janus_core.janus_types import LogLevel FORMAT = """ - timestamp: %(asctime)s @@ -15,37 +16,40 @@ def config_logger( name: str, - level: LogType = logging.INFO, - filename: str = "janus.log", + filename: Optional[str] = None, + level: LogLevel = logging.INFO, capture_warnings: bool = True, ): """ - Configure logger. + Configure logger with yaml-styled format. Parameters ---------- name : str - Name of logger. - level : LogType + Name of logger. Default is None. + filename : Optional[str] + Name of log file if writing logs. Default is None. + level : LogLevel Threshold for logger. Default is logging.INFO. - filename : str - Name of log file to write logs to. Default is "janus.log". capture_warnings : bool Whether to capture warnings in log. Default is True. Returns ------- - logging.Logger - Configured logger. + Optional[logging.Logger] + Configured logger if `filename` has been specified. """ - logger = logging.getLogger(name) - logging.basicConfig( - level=level, - filename=filename, - filemode="w", - format=FORMAT, - encoding="utf-8", - ) - logging.captureWarnings(capture=capture_warnings) - + if filename: + logger = logging.getLogger(name) + + logging.basicConfig( + level=level, + filename=filename, + filemode="w", + format=FORMAT, + encoding="utf-8", + ) + logging.captureWarnings(capture=capture_warnings) + else: + logger = None return logger diff --git a/janus_core/single_point.py b/janus_core/single_point.py index 88a217f4..60e5cb48 100644 --- a/janus_core/single_point.py +++ b/janus_core/single_point.py @@ -15,6 +15,7 @@ Devices, MaybeList, MaybeSequence, + PathLike, ) from janus_core.log import config_logger from janus_core.mlip_calculators import choose_calculator @@ -37,7 +38,7 @@ class SinglePoint: Keyword arguments to pass to ase.io.read. Default is {}. calc_kwargs : Optional[dict[str, Any]] Keyword arguments to pass to the selected calculator. Default is {}. - log_file : Optional[str] + log_file : Optional[PathLike] Name of log file if writing logs. Default is None. Attributes @@ -72,7 +73,7 @@ def __init__( device: Devices = "cpu", read_kwargs: Optional[ASEReadArgs] = None, calc_kwargs: Optional[dict[str, Any]] = None, - log_file: Optional[str] = None, + log_file: Optional[PathLike] = None, ) -> None: """ Read the structure being simulated and attach an MLIP calculator. @@ -90,13 +91,10 @@ def __init__( Keyword arguments to pass to ase.io.read. Default is {}. calc_kwargs : Optional[dict[str, Any]] Keyword arguments to pass to the selected calculator. Default is {}. - log_file : Optional[str] + log_file : Optional[PathLike] Name of log file if writing logs. Default is None. """ - if log_file is not None: - self.logger = config_logger(name=__name__, filename=log_file) - else: - self.logger = None + self.logger = config_logger(name=__name__, filename=log_file) self.architecture = architecture self.device = device @@ -279,7 +277,7 @@ def run_single_point( if write_kwargs and "filename" not in write_kwargs: raise ValueError("'filename' must be included in write_kwargs") - if self.logger is not None: + if self.logger: self.logger.info("Starting single point calculation") if "energy" in properties or len(properties) == 0: @@ -291,7 +289,7 @@ def run_single_point( self._clean_results(properties=properties) - if self.logger is not None: + if self.logger: self.logger.info("Single point calculation complete") if write_results: