tiramisu/tiramisu/error.py

215 lines
6.7 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
# Copyright (C) 2012-2021 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ____________________________________________________________
"user defined exceptions"
import weakref
from .i18n import _
def display_list(lst, separator='and', add_quote=False):
if separator == 'and':
separator = _('and')
elif separator == 'or':
separator = _('or')
if isinstance(lst, tuple) or isinstance(lst, frozenset):
lst = list(lst)
if len(lst) == 1:
ret = lst[0]
if not isinstance(ret, str):
ret = str(ret)
if add_quote and not ret.startswith('"'):
ret = '"{}"'.format(ret)
return ret
lst_ = []
for l in lst:
if not isinstance(l, str):
l = str(l)
lst_.append(_(l))
lst__ = []
for l in lst_:
if add_quote and not l.startswith('"'):
l = '"{}"'.format(l)
lst__.append(l)
lst__.sort()
last = lst__[-1]
return ', '.join(lst__[:-1]) + _(' {} ').format(separator) + '{}'.format(last)
# Exceptions for an Option
class PropertiesOptionError(AttributeError):
"attempt to access to an option with a property that is not allowed"
def __init__(self,
option_bag,
proptype,
settings,
opt_type=None,
name=None,
orig_opt=None,
help_properties=None):
if opt_type:
self._opt_type = opt_type
self._name = name
self._orig_opt = orig_opt
else:
if option_bag.option.impl_is_optiondescription():
self._opt_type = 'optiondescription'
else:
self._opt_type = 'option'
self._name = option_bag.option.impl_get_display_name()
self._orig_opt = None
self._option_bag = option_bag
self.proptype = proptype
self.help_properties = help_properties
self._settings = settings
self.msg = None
super().__init__(None)
def set_orig_opt(self, opt):
self._orig_opt = opt
def __str__(self):
# this part is a bit slow, so only execute when display
if self.msg is not None:
return self.msg
if self._settings is None:
return 'error'
if self.help_properties:
properties = list(self.help_properties)
else:
properties = list(self.proptype)
only_one = len(properties) == 1
properties_msg = display_list(properties, add_quote=True)
if only_one:
prop_msg = _('property')
else:
prop_msg = _('properties')
if properties == ['frozen']:
if self._orig_opt:
msg = 'cannot modify the {0} "{1}" because "{2}" has {3} {4}'
else:
msg = 'cannot modify the {0} "{1}" because has {2} {3}'
else:
if self._orig_opt:
msg = 'cannot access to {0} "{1}" because "{2}" has {3} {4}'
else:
msg = 'cannot access to {0} "{1}" because has {2} {3}'
if self._orig_opt:
self.msg = _(msg).format(self._opt_type,
self._orig_opt.impl_get_display_name(),
self._name,
prop_msg,
properties_msg)
else:
self.msg = _(msg).format(self._opt_type,
self._name,
prop_msg,
properties_msg)
del self._opt_type, self._name
del self._settings, self._orig_opt
return self.msg
#____________________________________________________________
# Exceptions for a Config
class ConfigError(Exception):
"""attempt to change an option's owner without a value
or in case of `_cfgimpl_descr` is None
or if a calculation cannot be carried out"""
def __init__(self,
exp,
ori_err=None):
super().__init__(exp)
self.ori_err = ori_err
class ConflictError(Exception):
"duplicate options are present in a single config"
pass
#____________________________________________________________
# miscellaneous exceptions
class LeadershipError(Exception):
"problem with a leadership's value length"
pass
class ConstError(TypeError):
"no uniq value in _NameSpace"
pass
class _CommonError:
def __init__(self,
val,
display_type,
opt,
err_msg,
index):
self.val = val
self.display_type = display_type
self.opt = weakref.ref(opt)
self.name = opt.impl_get_display_name()
self.err_msg = err_msg
self.index = index
super().__init__(self.err_msg)
def __str__(self):
try:
msg = self.prefix
except AttributeError:
self.prefix = self.tmpl.format(self.val,
self.display_type,
self.name)
msg = self.prefix
if self.err_msg:
if msg:
msg += ', {}'.format(self.err_msg)
else:
msg = self.err_msg
if not msg:
msg = _('invalid value')
return msg
class ValueWarning(_CommonError, UserWarning):
tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"')
def __init__(self, *args, **kwargs):
if len(args) == 1 and not kwargs:
self.msg = args[0]
pass
else:
super().__init__(*args, **kwargs)
self.msg = None
def __str__(self):
if self.msg is None:
return super().__str__()
return self.msg
class ValueOptionError(_CommonError, ValueError):
tmpl = _('"{0}" is an invalid {1} for "{2}"')
class ValueErrorWarning(ValueWarning):
tmpl = _('"{0}" is an invalid {1} for "{2}"')
class APIError(Exception):
pass