blob: 24bdfaaaef6e202f88444a70f9b8d8c9c871b690 [file] [log] [blame]
#
# -*- coding: utf-8 -*-
#
# This file is part of reclass (http://github.com/madduck/reclass)
#
# Copyright © 2007–14 martin f. krafft <madduck@madduck.net>
# Released under the terms of the Artistic Licence 2.0
#
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import posix, sys
import traceback
from reclass.defaults import REFERENCE_SENTINELS, EXPORT_SENTINELS
from reclass.utils.dictpath import DictPath
class ReclassException(Exception):
def __init__(self, rc=posix.EX_SOFTWARE, msg=None, tbFlag=True):
super(ReclassException, self).__init__()
self._rc = rc
self._msg = msg
if tbFlag:
self._traceback = traceback.format_exc()
else:
self._traceback = None
self._full_traceback = False
message = property(lambda self: self._get_message())
rc = property(lambda self: self._rc)
def __str__(self):
return self.message + '\n' + super(ReclassException, self).__str__()
def _get_message(self):
if self._msg:
return self._msg
else:
return 'No error message provided.'
def exit_with_message(self, out=sys.stderr):
if self._full_traceback:
t, v, tb = sys.exc_info()
print('Full Traceback', file=out)
for l in traceback.format_tb(tb):
print(l, file=out)
if self._traceback:
print(self._traceback, file=out)
print(self.message, file=out)
sys.exit(self.rc)
class PermissionError(ReclassException):
def __init__(self, msg, rc=posix.EX_NOPERM):
super(PermissionError, self).__init__(rc=rc, msg=msg)
class InvocationError(ReclassException):
def __init__(self, msg, rc=posix.EX_USAGE):
super(InvocationError, self).__init__(rc=rc, msg=msg)
class ConfigError(ReclassException):
def __init__(self, msg, rc=posix.EX_CONFIG):
super(ConfigError, self).__init__(rc=rc, msg=msg)
class DuplicateUriError(ConfigError):
def __init__(self, nodes_uri, classes_uri):
super(DuplicateUriError, self).__init__(msg=None)
self._nodes_uri = nodes_uri
self._classes_uri = classes_uri
def _get_message(self):
return "The inventory URIs must not be the same " \
"for nodes and classes: {0}".format(self._nodes_uri)
class UriOverlapError(ConfigError):
def __init__(self, nodes_uri, classes_uri):
super(UriOverlapError, self).__init__(msg=None)
self._nodes_uri = nodes_uri
self._classes_uri = classes_uri
def _get_message(self):
msg = "The URIs for the nodes and classes inventories must not " \
"overlap, but {0} and {1} do."
return msg.format(self._nodes_uri, self._classes_uri)
class NotFoundError(ReclassException):
def __init__(self, msg, rc=posix.EX_IOERR):
super(NotFoundError, self).__init__(rc=rc, msg=msg)
class NodeNotFound(NotFoundError):
def __init__(self, storage, nodename, uri):
super(NodeNotFound, self).__init__(msg=None)
self.storage = storage
self.name = nodename
self.uri = uri
def _get_message(self):
msg = "Node '{0}' not found under {1}://{2}"
return msg.format(self.name, self.storage, self.uri)
class InterpolationError(ReclassException):
def __init__(self, msg, rc=posix.EX_DATAERR, nodename='', uri=None, context=None, tbFlag=True):
super(InterpolationError, self).__init__(rc=rc, msg=msg, tbFlag=tbFlag)
self.nodename = nodename
self.uri = uri
self.context = context
def _get_message(self):
msg = '-> {0}\n'.format(self.nodename)
msg += self._render_error_message(self._get_error_message(), 1)
msg = msg[:-1]
return msg
def _render_error_message(self, message_list, indent):
msg = ''
for l in message_list:
if isinstance(l, list):
msg += self._render_error_message(l, indent + 1)
else:
msg += (' ' * indent * 3) + l + '\n'
return msg
def _add_context_and_uri(self):
msg = ''
if self.context:
msg += ', at %s' % str(self.context)
if self.uri:
msg += ', in %s' % self.uri
return msg
class ClassNotFound(InterpolationError):
def __init__(self, storage, classname, path, nodename='', uri=None):
super(ClassNotFound, self).__init__(msg=None, uri=uri, nodename=nodename)
self.storage = storage
self.name = classname
self.path = path
def _get_error_message(self):
msg = [ 'In {0}'.format(self.uri),
'Class {0} not found under {1}://{2}'.format(self.name, self.storage, self.path) ]
return msg
class ClassNameResolveError(InterpolationError):
def __init__(self, classname, nodename, uri):
super(ClassNameResolveError, self).__init__(msg=None, uri=uri, nodename=nodename)
self.name = classname
def _get_error_message(self):
msg = [ 'In {0}'.format(self.uri),
'Class name {0} not resolvable'.format(self.name) ]
return msg
class InvQueryClassNotFound(InterpolationError):
def __init__(self, classNotFoundError, nodename=''):
super(InvQueryClassNotFound, self).__init__(msg=None, nodename=nodename)
self.classNotFoundError = classNotFoundError
self._traceback = self.classNotFoundError._traceback
def _get_error_message(self):
msg = [ 'Inventory Queries:',
'-> {0}'.format(self.classNotFoundError.nodename) ]
msg.append(self.classNotFoundError._get_error_message())
return msg
class InvQueryClassNameResolveError(InterpolationError):
def __init__(self, classNameResolveError, nodename=''):
super(InvQueryClassNameResolveError, self).__init__(msg=None, nodename=nodename)
self.classNameResolveError = classNameResolveError
self._traceback = self.classNameResolveError._traceback
def _get_error_message(self):
msg = [ 'Inventory Queries:',
'-> {0}'.format(self.classNameResolveError.nodename) ]
msg.append(self.classNameResolveError._get_error_message())
return msg
class ResolveError(InterpolationError):
def __init__(self, reference, uri=None, context=None):
super(ResolveError, self).__init__(msg=None)
self.reference = reference
def _get_error_message(self):
msg = 'Cannot resolve {0}'.format(self.reference.join(REFERENCE_SENTINELS)) + self._add_context_and_uri()
return [ msg ]
class ResolveErrorList(InterpolationError):
def __init__(self):
super(ResolveErrorList, self).__init__(msg=None)
self.resolve_errors = []
self._traceback = False
def add(self, resolve_error):
self.resolve_errors.append(resolve_error)
def have_errors(self):
return len(self.resolve_errors) > 0
def _get_error_message(self):
msgs = []
for e in self.resolve_errors:
msgs.extend(e._get_error_message())
return msgs
class InvQueryError(InterpolationError):
def __init__(self, query, resolveError, uri=None, context=None):
super(InvQueryError, self).__init__(msg=None)
self.query = query
self.resolveError = resolveError
self._traceback = self.resolveError._traceback
def _get_error_message(self):
msg1 = 'Failed inv query {0}'.format(self.query.join(EXPORT_SENTINELS)) + self._add_context_and_uri()
msg2 = '-> {0}'.format(self.resolveError.nodename)
msg3 = self.resolveError._get_error_message()
return [ msg1, msg2, msg3 ]
class ParseError(InterpolationError):
def __init__(self, msg, line, col, lineno, rc=posix.EX_DATAERR):
super(ParseError, self).__init__(rc=rc, msg=None)
self._err = msg
self._line = line
self._col = col
self._lineno = lineno
def _get_error_message(self):
msg = [ 'Parse error: {0}'.format(self._line.join(EXPORT_SENTINELS)) + self._add_context_and_uri() ]
msg.append('{0} at char {1}'.format(self._err, self._col - 1))
return msg
class InfiniteRecursionError(InterpolationError):
def __init__(self, context, ref, uri):
super(InfiniteRecursionError, self).__init__(msg=None, tbFlag=False, uri=uri)
self.context = context
self.ref = ref
def _get_error_message(self):
msg = [ 'Infinite recursion: {0}'.format(self.ref.join(REFERENCE_SENTINELS)) + self._add_context_and_uri() ]
return msg
class BadReferencesError(InterpolationError):
def __init__(self, refs, context, uri):
super(BadReferencesError, self).__init__(msg=None, context=context, uri=uri, tbFlag=False)
self.refs = [ r.join(REFERENCE_SENTINELS) for r in refs ]
def _get_error_message(self):
msg = [ 'Bad references' + self._add_context_and_uri(),
' ' + ', '.join(self.refs) ]
return msg
class TypeMergeError(InterpolationError):
def __init__(self, value1, value2, uri):
super(TypeMergeError, self).__init__(msg=None, uri=uri, tbFlag=False)
self.type1 = value1.item_type_str()
self.type2 = value2.item_type_str()
def _get_error_message(self):
msg = [ 'Cannot merge {0} over {1}'.format(self.type1, self.type2) + self._add_context_and_uri() ]
return msg
class ExpressionError(InterpolationError):
def __init__(self, msg, rc=posix.EX_DATAERR, tbFlag=True):
super(ExpressionError, self).__init__(rc=rc, msg=None, tbFlag=tbFlag)
self._error_msg = msg
def _get_error_message(self):
msg = [ 'Expression error: {0}'.format(self._error_msg) + self._add_context_and_uri() ]
return msg
class ChangedConstantError(InterpolationError):
def __init__(self, uri):
super(ChangedConstantError, self).__init__(msg=None, uri=uri, tbFlag=False)
def _get_error_message(self):
msg = [ 'Attempt to change constant value' + self._add_context_and_uri() ]
return msg
class MappingError(ReclassException):
def __init__(self, msg, rc=posix.EX_DATAERR):
super(MappingError, self).__init__(rc=rc, msg=msg)
class MappingFormatError(MappingError):
def __init__(self, msg):
super(MappingFormatError, self).__init__(msg)
class NameError(ReclassException):
def __init__(self, msg, rc=posix.EX_DATAERR):
super(NameError, self).__init__(rc=rc, msg=msg)
class InvalidClassnameError(NameError):
def __init__(self, invalid_character, classname):
super(InvalidClassnameError, self).__init__(msg=None)
self._char = invalid_character
self._classname = classname
def _get_message(self):
msg = "Invalid character '{0}' in class name '{1}'."
return msg.format(self._char, self._classname)
class DuplicateNodeNameError(NameError):
def __init__(self, storage, name, uri1, uri2):
super(DuplicateNodeNameError, self).__init__(msg=None)
self._storage = storage
self._name = name
self._uris = (uri1, uri2)
def _get_message(self):
msg = "{0}: Definition of node '{1}' in '{2}' collides with " \
"definition in '{3}'. Nodes can only be defined once " \
"per inventory."
return msg.format(self._storage, self._name, self._uris[1], self._uris[0])
class MissingModuleError(ReclassException):
def __init__(self, modname):
msg = "Module %s is missing" % modname
super(MissingModuleError, self).__init__(rc=posix.EX_DATAERR, msg=msg)