# Copyright 2021 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Globally accessible exception definitions for better granularity on exception behavior and
exception handling behavior.
"""
from armi import runLog
from inspect import stack, getframeinfo
[docs]def info(func):
    """Decorator to write to current log, using the info method."""
    def decorated(*args, **kwargs):
        r"""Decorated method."""
        runLog.info(func(*args, **kwargs))
    return decorated 
[docs]def important(func):
    """Decorator to write to current log, using the inportant method."""
    def decorated(*args, **kwargs):
        """Decorated method."""
        runLog.important(func(*args, **kwargs))
    return decorated 
[docs]def warn(func):
    """Decorates a method to produce a repeatable warning message."""
    def decorated(*args, **kwargs):
        """Decorated method."""
        runLog.warning(func(*args, **kwargs))
    return decorated 
def _message_when_root(func):
    """Do not use this decorator."""
    def decorated(*args, **kwargs):
        from armi import MPI_RANK
        if MPI_RANK == 0:
            func(*args, **kwargs)
    return decorated
[docs]def warn_when_root(func):
    """Decorates a method to produce a warning message only on the root node."""
    return _message_when_root(warn(func)) 
# ---------------------------------------------------
# ---------------------------------------------------
[docs]class SettingException(Exception):
    """Standardize behavior of setting-family errors."""
    def __init__(self, msg):
        Exception.__init__(self, msg) 
[docs]class InvalidSettingsStopProcess(SettingException):
    """
    Exception raised when setting file contains invalid settings and user aborts or process is
    uninteractive.
    """
    def __init__(self, reader):
        msg = "Input settings file {}".format(reader.inputPath)
        if reader.liveVersion != reader.inputVersion:
            msg += (
                '\n\twas made with version "{0}" which differs from the current version "{1}." '
                'Either create the input file with the "{1}", or switch to a development version '
                "of ARMI.".format(reader.inputVersion, reader.liveVersion)
            )
        if reader.invalidSettings:
            msg += (
                "\n\tcontains the following {} invalid settings:\n\t\t"
                "{}"
                "".format(
                    len(reader.invalidSettings), "\n\t\t".join(reader.invalidSettings)
                )
            )
        SettingException.__init__(self, msg) 
[docs]class NonexistentSetting(SettingException):
    """Exception raised when a non existent setting is asked for."""
    def __init__(self, setting):
        SettingException.__init__(
            self, "Attempted to locate non-existent setting {}.".format(setting)
        ) 
[docs]class InvalidSettingsFileError(SettingException):
    """Not a valid settings file."""
    def __init__(self, path, customMsgEnd=""):
        msg = "Attempted to load an invalid settings file from: {}. ".format(path)
        msg += customMsgEnd
        SettingException.__init__(self, msg) 
[docs]class NonexistentSettingsFileError(SettingException):
    """Settings file does not exist."""
    def __init__(self, path):
        SettingException.__init__(
            self, "Attempted to load settings file, cannot locate file: {}".format(path)
        )