diff --git a/.gitignore b/.gitignore index 9ae382b28b0..fb8273d8a49 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,10 @@ __pycache__ *.[aox] *.mod *.sw[a-p] +._* .DS_Store .idea/ +.vscode/ # Ignore editor generated backup files #------------------------------------- diff --git a/ush/python/pygw/src/pygw/fsutils.py b/ush/python/pygw/src/pygw/fsutils.py index f0d41fb54fa..50d7d10bbff 100644 --- a/ush/python/pygw/src/pygw/fsutils.py +++ b/ush/python/pygw/src/pygw/fsutils.py @@ -47,10 +47,27 @@ def rm_p(path): raise OSError(f"unable to remove {path}") -def cp(src, dest): +def cp(source: str, target: str) -> None: + """ + copy `source` file to `target` using `shutil.copyfile` + If `target` is a directory, then the filename from `source` is retained into the `target` + Parameters + ---------- + source : str + Source filename + target : str + Destination filename or directory + Returns + ------- + None + """ + + if os.path.isdir(target): + target = os.path.join(target, os.path.basename(source)) + try: - shutil.copyfile(src, dest) - except OSError as exc: - raise OSError(f"unable to copy {src} to {dest}") - except FileNotFoundError as exc: - raise FileNotFoundError(exc) + shutil.copyfile(source, target) + except OSError: + raise OSError(f"unable to copy {source} to {target}") + except Exception as exc: + raise Exception(exc) diff --git a/ush/python/pygw/src/pygw/logger.py b/ush/python/pygw/src/pygw/logger.py index 30d02106651..9fd781cce0c 100644 --- a/ush/python/pygw/src/pygw/logger.py +++ b/ush/python/pygw/src/pygw/logger.py @@ -227,17 +227,19 @@ def add_file_handler(cls, logfile_path: Union[str, Path], def logit(logger, name=None, message=None): """ - Add logging to a function. + Logger decorator to add logging to a function. + Simply add: + @logit(logger) before any function Parameters ---------- - logger : Logger - Logger object - name : str - Name of the module to be logged - default: __module__ - message : str - Name of the function to be logged - default: __name__ + logger : Logger + Logger object + name : str + Name of the module to be logged + default: __module__ + message : str + Name of the function to be logged + default: __name__ """ def decorate(func): @@ -250,17 +252,18 @@ def wrapper(*args, **kwargs): passed_args = [repr(aa) for aa in args] passed_kwargs = [f"{kk}={repr(vv)}" for kk, vv in list(kwargs.items())] - call_msg = 'BEGIN: ' + log_msg + f"( {', '.join(passed_args + passed_kwargs)} )" - # Begin the logging with printing input arguments - logger.debug(call_msg) + call_msg = 'BEGIN: ' + log_msg + logger.info(call_msg) + logger.debug(f"( {', '.join(passed_args + passed_kwargs)} )") # Call the function retval = func(*args, **kwargs) # Close the logging with printing the return val - ret_msg = ' END: ' + log_msg + f" returning {retval}" - logger.debug(ret_msg) + ret_msg = ' END: ' + log_msg + logger.info(ret_msg) + logger.debug(f" returning: {retval}") return retval diff --git a/ush/python/pygw/src/pygw/task.py b/ush/python/pygw/src/pygw/task.py index 14d365cbecc..71b427e4bfa 100644 --- a/ush/python/pygw/src/pygw/task.py +++ b/ush/python/pygw/src/pygw/task.py @@ -1,9 +1,17 @@ +import logging +from typing import Dict + +from pygw.attrdict import AttrDict + +logger = logging.getLogger(__name__.split('.')[-1]) + + class Task: """ Base class for all tasks """ - def __init__(self, config, *args, **kwargs): + def __init__(self, config: Dict, *args, **kwargs): """ Every task needs a config. Additional arguments (or key-value arguments) can be provided. @@ -21,7 +29,7 @@ def __init__(self, config, *args, **kwargs): """ # Store the config and arguments as attributes of the object - self.config = config + self.config = AttrDict(config) for arg in args: setattr(self, str(arg), arg) @@ -29,6 +37,15 @@ def __init__(self, config, *args, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) + # Pull out basic runtime keys values from config into its own runtime config + self.runtime_config = AttrDict() + runtime_keys = ['PDY', 'cyc', 'DATA', 'RUN', 'CDUMP'] # TODO: eliminate CDUMP and use RUN instead + for kk in runtime_keys: + try: + self.runtime_config[kk] = config[kk] + except KeyError: + raise KeyError(f"Encountered an unreferenced runtime_key {kk} in 'config'") + def initialize(self): """ Initialize methods for a task