Source code for multiconf.config_errors
# Copyright (c) 2012 Lars Hupfeldt Nielsen, Hupfeldt IT
# All rights reserved. This work is under a BSD license, see LICENSE.TXT.
import sys
class ConfigBaseException(Exception):
is_summary = False
is_fatal = False
class ConfigDefinitionException(ConfigBaseException):
def __init__(self, msg):
super().__init__(msg)
class ConfigException(ConfigBaseException):
def __init__(self, msg, is_summary=False, is_fatal=False):
super().__init__(msg)
self.is_summary = is_summary
self.is_fatal = is_fatal
class InvalidUsageException(ConfigBaseException):
pass
class ConfigApiException(ConfigBaseException):
pass
class ConfigAttributeError(AttributeError):
def __init__(self, mc_object, attr_name, msg):
super().__init__("")
self.mc_object = mc_object
self.attr_name = attr_name
self.msg = msg
@property
def message(self):
error_message = "%(item_repr_and_type)s has no attribute %(attr_name)s."
if self.msg:
error_message += ' ' + self.msg
try:
rep = self.mc_object.json(compact=True, property_methods=True, builders=False, depth=1) + ", object"
except: # pylint: disable=bare-except
rep = "Object"
return error_message % {"item_repr_and_type": f"{rep} of type: {repr(type(self.mc_object))}", "attr_name": repr(self.attr_name)}
def __str__(self):
return self.message
class ConfigExcludedAttributeError(ConfigAttributeError):
def __init__(self, mc_object, attr_name, env):
super().__init__(mc_object, attr_name, None)
self.env = env
try:
self.value = mc_object._mc_attributes[attr_name].env_values[env]
except KeyError:
self.value = None
@property
def message(self):
error_message = "Accessing attribute '{attr_name}' for {env} on an excluded config item: {item_excl_repr}"
return error_message.format(attr_name=self.attr_name, env=self.env, item_excl_repr=self.mc_object._mc_excl_repr())
class ConfigExcludedKeyError(KeyError):
def __init__(self, mc_object, key_name):
super().__init__(key_name)
self.mc_object = mc_object
self.key_name = key_name
@property
def message(self):
error_message = "'{key_name}'. '{item_excl_repr}' for {env}."
return error_message.format(key_name=self.key_name, item_excl_repr=self.mc_object._mc_excl_repr(), env=self.mc_object.env)
def __str__(self):
return self.message
[docs]
def caller_file_line(up_level=2):
"""Return the file and line of the caller of the function calling this function (depending on up_level)"""
frame = sys._getframe(up_level)
return frame.f_globals['__file__'], frame.f_lineno
def find_user_file_line(up_level_start=2):
frame = sys._getframe(up_level_start)
while 1:
if frame.f_globals['__package__'] != 'multiconf':
return frame.f_globals['__file__'], frame.f_lineno
frame = frame.f_back
def _line_msg(up_level=2, file_name=None, line_num=None, msg=''):
"""Generate the file:line information for error messages.
Arguments:
up_level (int): If file_name is None then automatically determine the file and line 'up_level' stack frames up from here.
file_name (str): File name of user config with error.
line_num (int): Line number of user config with error.
"""
if file_name is None:
file_name, line_num = find_user_file_line(up_level + 1)
file_name = file_name.rstrip('c') # file_name may point to the *.pyc file
return ('File "%s", line %d' % (file_name, line_num)) + (', ' + msg if msg else '')
def _error_msg(message):
return 'ConfigError: ' + message
def _warning_msg(message):
return 'ConfigWarning: ' + message
failed_property_call_msg = "Attribute '{attr}' is defined as a multiconf attribute and as a @property method " \
"but value is undefined for {env} and @property method call failed with: {ex}"
not_repeatable_in_parent_msg = "'{repeatable_cls_key}': {repeatable_cls} is defined as repeatable, " \
"but this is not defined as a repeatable item in the containing class: '{ci_named_as}': {ci_cls}"
repeatable_in_parent_msg = "'{named_as}': {cls} is not defined as repeatable, " \
"but this is defined as a repeatable item in the containing class: {ci_item}"