Source code for bout_runners.parameters.bout_paths

"""Contains the class setting the BOUT++ paths."""


import logging
import shutil
from datetime import datetime
from pathlib import Path
from typing import Optional, Union

from bout_runners.utils.file_operations import get_caller_dir


[docs]class BoutPaths: """ Class which sets the paths. Attributes ---------- __project_path : None or Path Getter and setter variable for project_path __bout_inp_src_dir : None or Path Getter and setter variable for bout_inp_src_dir __bout_inp_dst_dir : None or Path Getter and setter variable for bout_inp_dst_dir project_path : Path The root path of the project bout_inp_src_dir : Path The path to the BOUT.inp source directory bout_inp_dst_dir : Path The path to the BOUT.inp destination directory Methods ------- _copy_files() Copy BOUT.inp from bout_inp_src_dir to bout_inp_dst_dir Examples -------- >>> bout_paths = BoutPaths() >>> bout_paths.project_path Path(/root/BOUT-dev/examples/conduction) >>> bout_paths.bout_inp_src_dir Path(/root/BOUT-dev/examples/conduction/data) >>> bout_paths.bout_inp_dst_dir Path(/root/BOUT-dev/examples/conduction/2020-02-12_21-59-00_227295) >>> bout_paths.bout_inp_dst_dir = 'foo' Path(/root/BOUT-dev/examples/conduction/foo) """ def __init__( self, project_path: Optional[Union[Path, str]] = None, bout_inp_src_dir: Optional[Union[Path, str]] = None, bout_inp_dst_dir: Optional[Union[Path, str]] = None, ) -> None: """ Set the paths. Parameters ---------- project_path : None or Path or str Root path of make file If None, the path of the path of the root caller will be used bout_inp_src_dir : None or str or Path The path to the BOUT.inp source directory (relative to self.project_path) If None, data will be used bout_inp_dst_dir : None or str or Path The path to the BOUT.inp bout_inp_dst_dir directory (relative to self.project_path) If None, the current time will be used """ logging.info("Start: Making a BoutPahts object") # Declare variables to be used in the getters and setters # NOTE: When the variables will be set to absolute paths in the setters. # Thus, Path() can be regarded as None self.__project_path: Path = Path() self.__bout_inp_src_dir: Path = Path() self.__bout_inp_dst_dir: Path = Path() # NOTE: type: ignore due to https://github.com/python/mypy/issues/3004 # Set the project path self.project_path = project_path # type: ignore # Set the bout_inp_src_dir self.bout_inp_src_dir = bout_inp_src_dir # type: ignore # Set the bout_inp_dst_dir self.bout_inp_dst_dir = bout_inp_dst_dir # type: ignore logging.info("Done: Making a BoutPahts object") @property def project_path(self) -> Path: """ Set the properties of self.project_path. If None is specified, the path of the path of the root caller will be used Returns ------- Path Absolute path to the root of make file """ return self.__project_path @project_path.setter def project_path(self, project_path: Optional[Union[Path, str]]) -> None: if project_path is None: project_path = get_caller_dir() project_path = Path(project_path).absolute() self.__project_path = project_path logging.debug("self.project_path set to %s", project_path) @property def bout_inp_src_dir(self) -> Path: """ Set the properties of bout_inp_src_dir. The setter will convert bout_inp_src_dir an absolute path (as the input is relative to the project path), check that the directory exists, and copy the BOUT.inp file to the bout_inp_dst_dir path (self.bout_inp_dst_dir) The input should be the path to the BOUT.inp source directory (relative to self.project_path) If None, "data" will be used Returns ------- self.__bout_inp_src_dir : Path The absolute path to the BOUT.inp source directory Raises ------ FileNotFoundError If no BOUT.inp file is found in the directory """ return self.__bout_inp_src_dir @bout_inp_src_dir.setter def bout_inp_src_dir(self, bout_inp_src_dir: Optional[Union[Path, str]]) -> None: bout_inp_src_dir = ( Path(bout_inp_src_dir) if bout_inp_src_dir is not None else Path("data") ) self.__bout_inp_src_dir = self.project_path.joinpath(bout_inp_src_dir) if not self.__bout_inp_src_dir.joinpath("BOUT.inp").is_file(): msg = f"No BOUT.inp file found in " f"{self.__bout_inp_src_dir}" logging.critical(msg) raise FileNotFoundError(msg) logging.debug("self.bout_inp_src_dir set to %s", self.__bout_inp_src_dir) # Copy file to bout_inp_dst_dir if set if self.bout_inp_dst_dir != Path(): self._copy_files() @property def bout_inp_dst_dir(self) -> Path: """ Set the properties of bout_inp_dst_dir. The setter will convert bout_inp_dst_dir an absolute path (as the input is relative to the project path), and copy BOUT.inp from self.bout_inp_src_dir to self.bout_inp_dst_dir The input should be the path to the BOUT.inp bout_inp_dst_dir directory (relative to self.project_path) If None, the current time will be used Returns ------- Path Path to the destination directory """ return self.__bout_inp_dst_dir @bout_inp_dst_dir.setter def bout_inp_dst_dir(self, bout_inp_dst_dir: Optional[Union[Path, str]]) -> None: time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S_%f") bout_inp_dst_dir = ( Path(bout_inp_dst_dir) if bout_inp_dst_dir is not None else Path(time) ) self.__bout_inp_dst_dir = self.project_path.joinpath(bout_inp_dst_dir) self.__bout_inp_dst_dir.mkdir(exist_ok=True, parents=True) logging.debug("self.bout_inp_dst_dir set to %s", self.__bout_inp_dst_dir) self._copy_files() def _copy_files(self) -> None: """Copy BOUT.inp from bout_inp_src_dir to bout_inp_dst_dir.""" if self.bout_inp_src_dir != self.bout_inp_dst_dir: src = self.bout_inp_src_dir.joinpath("BOUT.inp") dst = self.bout_inp_dst_dir.joinpath(src.name) shutil.copy(src, dst) logging.debug("Copied %s to %s", src, dst)