diff --git a/sahara/conductor/resource.py b/sahara/conductor/resource.py index 5080cd8a..38fafed5 100644 --- a/sahara/conductor/resource.py +++ b/sahara/conductor/resource.py @@ -28,6 +28,7 @@ import datetime import six from sahara.conductor import objects +from sahara import exceptions as ex from sahara.i18n import _ from sahara.swift import swift_helper from sahara.utils import types @@ -169,7 +170,7 @@ class Resource(types.FrozenDict): return self[item] def __setattr__(self, *args): - raise types.FrozenClassError(self) + raise ex.FrozenClassError(self) class NodeGroupTemplateResource(Resource, objects.NodeGroupTemplate): diff --git a/sahara/exceptions.py b/sahara/exceptions.py index 17894a5e..eb303b7a 100644 --- a/sahara/exceptions.py +++ b/sahara/exceptions.py @@ -25,92 +25,84 @@ class SaharaException(Exception): To correctly use this class, inherit from it and define a 'message' and 'code' properties. """ - message = _("An unknown exception occurred") code = "UNKNOWN_EXCEPTION" + message = _("An unknown exception occurred") def __str__(self): return self.message - def __init__(self): - super(SaharaException, self).__init__( - '%s: %s' % (self.code, self.message)) + def __init__(self, message=None, code=None): self.uuid = uuidutils.generate_uuid() + + if code: + self.code = code + if message: + self.message = message + + # Add Error UUID to the message self.message = (_('%(message)s\nError ID: %(id)s') % {'message': self.message, 'id': self.uuid}) + super(SaharaException, self).__init__( + '%s: %s' % (self.code, self.message)) + class NotFoundException(SaharaException): - message = _("Object '%s' is not found") + code = "NOT_FOUND" + message_template = _("Object '%s' is not found") # It could be a various property of object which was not found - value = None - def __init__(self, value, message=None): - self.code = "NOT_FOUND" + def __init__(self, value, message_template=None): self.value = value - if message: - self.message = message % value + if message_template: + formatted_message = message_template % value else: - self.message = self.message % value - super(NotFoundException, self).__init__() + formatted_message = self.message_template % value + + super(NotFoundException, self).__init__(formatted_message) class NameAlreadyExistsException(SaharaException): + code = "NAME_ALREADY_EXISTS" message = _("Name already exists") - def __init__(self, message=None): - self.code = "NAME_ALREADY_EXISTS" - if message: - self.message = message - super(NameAlreadyExistsException, self).__init__() - class InvalidCredentials(SaharaException): message = _("Invalid credentials") - - def __init__(self, message=None): - self.code = "INVALID_CREDENTIALS" - if message: - self.message = message - super(InvalidCredentials, self).__init__() + code = "INVALID_CREDENTIALS" class InvalidReferenceException(SaharaException): + code = "INVALID_REFERENCE" message = _("Invalid object reference") - def __init__(self, message=None): - self.code = "INVALID_REFERENCE" - if message: - self.message = message - super(InvalidReferenceException, self).__init__() - class RemoteCommandException(SaharaException): - message = _("Error during command execution: \"%s\"") + code = "REMOTE_COMMAND_FAILED" + message_template = _("Error during command execution: \"%s\"") def __init__(self, cmd, ret_code=None, stdout=None, stderr=None): - self.code = "REMOTE_COMMAND_FAILED" - self.cmd = cmd self.ret_code = ret_code self.stdout = stdout self.stderr = stderr - self.message = self.message % cmd + formatted_message = self.message_template % cmd if ret_code: - self.message = '%s\nReturn code: %s' % (self.message, - six.text_type(ret_code)) + formatted_message = '%s\nReturn code: %s' % ( + formatted_message, six.text_type(ret_code)) if stderr: - self.message = '%s\nSTDERR:\n%s' % ( - self.message, stderr.decode('ascii', 'ignore')) + formatted_message = '%s\nSTDERR:\n%s' % ( + formatted_message, stderr.decode('ascii', 'ignore')) if stdout: - self.message = '%s\nSTDOUT:\n%s' % ( - self.message, stdout.decode('ascii', 'ignore')) + formatted_message = '%s\nSTDOUT:\n%s' % ( + formatted_message, stdout.decode('ascii', 'ignore')) - super(RemoteCommandException, self).__init__() + super(RemoteCommandException, self).__init__(formatted_message) class InvalidDataException(SaharaException): @@ -119,83 +111,52 @@ class InvalidDataException(SaharaException): A more useful message should be passed to __init__ which tells the user more about why the data is invalid. """ - message = _("Data is invalid") code = "INVALID_DATA" - - def __init__(self, message=None): - if message: - self.message = message - super(InvalidDataException, self).__init__() + message = _("Data is invalid") class BadJobBinaryInternalException(SaharaException): + code = "BAD_JOB_BINARY" message = _("Job binary internal data must be a string of length " "greater than zero") - def __init__(self, message=None): - if message: - self.message = message - self.code = "BAD_JOB_BINARY" - super(BadJobBinaryInternalException, self).__init__() - class BadJobBinaryException(SaharaException): + code = "BAD_JOB_BINARY" message = _("To work with JobBinary located in internal swift add 'user'" " and 'password' to extra") - def __init__(self, message=None): - if message: - self.message = message - self.code = "BAD_JOB_BINARY" - super(BadJobBinaryException, self).__init__() - class DBDuplicateEntry(SaharaException): - message = _("Database object already exists") code = "DB_DUPLICATE_ENTRY" - - def __init__(self, message=None): - if message: - self.message = message - super(DBDuplicateEntry, self).__init__() + message = _("Database object already exists") class CreationFailed(SaharaException): message = _("Object was not created") code = "CREATION_FAILED" - def __init__(self, message=None): - if message: - self.message = message - super(CreationFailed, self).__init__() - class CancelingFailed(SaharaException): message = _("Operation was not canceled") code = "CANCELING_FAILED" - def __init__(self, message=None): - if message: - self.message = message - super(CancelingFailed, self).__init__() - class DeletionFailed(SaharaException): - message = _("Object was not deleted") code = "DELETION_FAILED" - - def __init__(self, message=None): - if message: - self.message = message - super(DeletionFailed, self).__init__() + message = _("Object was not deleted") class MissingFloatingNetworkException(SaharaException): + code = "MISSING_FLOATING_NETWORK" + message_template = _("Node Group %s is missing 'floating_ip_pool' " + "field") + def __init__(self, ng_name): - self.message = _("Node Group %s is missing 'floating_ip_pool' " - "field") % ng_name - self.code = "MISSING_FLOATING_NETWORK" - super(MissingFloatingNetworkException, self).__init__() + formatted_message = self.message_template % ng_name + + super(MissingFloatingNetworkException, self).__init__( + formatted_message) class SwiftClientException(SaharaException): @@ -205,168 +166,184 @@ class SwiftClientException(SaharaException): swiftclient.ClientException in a SaharaException. The ClientException should be caught and an instance of SwiftClientException raised instead. ''' - def __init__(self, message): - self.message = message - self.code = "SWIFT_CLIENT_EXCEPTION" - super(SwiftClientException, self).__init__() + + code = "SWIFT_CLIENT_EXCEPTION" + message = _("An error has occured while performing a request to Swift") class DataTooBigException(SaharaException): - message = _("Size of data (%(size)s) is greater than maximum " - "(%(maximum)s)") + code = "DATA_TOO_BIG" + message_template = _("Size of data (%(size)s) is greater than maximum " + "(%(maximum)s)") - def __init__(self, size, maximum, message=None): - if message: - self.message = message - self.message = self.message % ({'size': size, 'maximum': maximum}) - self.code = "DATA_TOO_BIG" - super(DataTooBigException, self).__init__() + def __init__(self, size, maximum, message_template=None): + if message_template: + self.message_template = message_template + + formatted_message = self.message_template % ( + {'size': size, 'maximum': maximum}) + + super(DataTooBigException, self).__init__(formatted_message) class ThreadException(SaharaException): + code = "THREAD_EXCEPTION" + message_template = _("An error occurred in thread '%(thread)s': %(e)s") + def __init__(self, thread_description, e): - self.message = (_("An error occurred in thread '%(thread)s': %(e)s") - % {'thread': thread_description, - 'e': six.text_type(e)}) - self.code = "THREAD_EXCEPTION" - super(ThreadException, self).__init__() + formatted_message = self.message_template % { + 'thread': thread_description, + 'e': six.text_type(e)} + + super(ThreadException, self).__init__(formatted_message) + + +class SubprocessException(SaharaException): + code = "SUBPROCESS_EXCEPTION" + message = _("Subprocess execution has failed") class NotImplementedException(SaharaException): code = "NOT_IMPLEMENTED" + message_template = _("Feature '%s' is not implemented") def __init__(self, feature): - self.message = _("Feature '%s' is not implemented") % feature - super(NotImplementedException, self).__init__() + formatted_message = self.message_template % feature + + super(NotImplementedException, self).__init__(formatted_message) class HeatStackException(SaharaException): + code = "HEAT_STACK_EXCEPTION" + message_template = _("Heat stack failed with status %s") + def __init__(self, heat_stack_status): - self.code = "HEAT_STACK_EXCEPTION" - self.message = (_("Heat stack failed with status %s") % - heat_stack_status) - super(HeatStackException, self).__init__() + formatted_message = self.message_template % heat_stack_status + + super(HeatStackException, self).__init__(formatted_message) class ConfigurationError(SaharaException): code = "CONFIGURATION_ERROR" - - def __init__(self, message): - self.message = message - super(ConfigurationError, self).__init__() + message = _("The configuration has failed") class IncorrectStateError(SaharaException): + message = _("The object is in an incorrect state") code = "INCORRECT_STATE_ERROR" - def __init__(self, message): - self.message = message - super(IncorrectStateError, self).__init__() + +class FrozenClassError(SaharaException): + code = "FROZEN_CLASS_ERROR" + message_template = _("Class %s is immutable!") + + def __init__(self, instance): + formatted_message = self.message_template % type(instance).__name__ + + super(FrozenClassError, self).__init__(formatted_message) class SystemError(SaharaException): code = "SYSTEM_ERROR" - - def __init__(self, message): - self.message = message - super(SystemError, self).__init__() + message = _("System error has occured") class EDPError(SaharaException): code = "EDP_ERROR" + message = _("Failed to complete EDP operation") - def __init__(self, message): - self.message = message - super(EDPError, self).__init__() + +class OozieException(SaharaException): + code = "OOZIE_EXCEPTION" + message = _("Failed to perform Oozie request") class TimeoutException(SaharaException): code = "TIMEOUT" - message = _("'%(operation)s' timed out after %(timeout)i second(s)") + message_template = _("'%(operation)s' timed out after %(timeout)i " + "second(s)") def __init__(self, timeout, op_name=None, timeout_name=None): if op_name: op_name = _("Operation with name '%s'") % op_name else: op_name = _("Operation") - self.message = self.message % { + formatted_message = self.message_template % { 'operation': op_name, 'timeout': timeout} if timeout_name: desc = _("%(message)s and following timeout was violated: " "%(timeout_name)s") - self.message = desc % { - 'message': self.message, 'timeout_name': timeout_name} + formatted_message = desc % { + 'message': formatted_message, 'timeout_name': timeout_name} - super(TimeoutException, self).__init__() + super(TimeoutException, self).__init__(formatted_message) class DeprecatedException(SaharaException): code = "DEPRECATED" - - def __init__(self, message): - self.message = message - super(DeprecatedException, self).__init__() + message = _("The version you are trying to use is deprecated") class Forbidden(SaharaException): code = "FORBIDDEN" - message = _("You are not authorized to complete this action.") - - def __init__(self, message=None): - if message: - self.message = message - super(Forbidden, self).__init__() + message = _("You are not authorized to complete this action") class ImageNotRegistered(SaharaException): code = "IMAGE_NOT_REGISTERED" - message = _("Image %s is not registered in Sahara") + message_template = _("Image %s is not registered in Sahara") def __init__(self, image): - self.message = self.message % image - super(ImageNotRegistered, self).__init__() + formatted_message = self.message_template % image + super(ImageNotRegistered, self).__init__(formatted_message) class MalformedRequestBody(SaharaException): code = "MALFORMED_REQUEST_BODY" - message = _("Malformed message body: %(reason)s") + message_template = _("Malformed message body: %(reason)s") def __init__(self, reason): - self.message = self.message % {"reason": reason} - super(MalformedRequestBody, self).__init__() + formatted_message = self.message_template % {"reason": reason} + super(MalformedRequestBody, self).__init__(formatted_message) class QuotaException(SaharaException): code = "QUOTA_ERROR" - message = _("Quota exceeded for %(resource)s: Requested %(requested)s," - " but available %(available)s") + message_template = _("Quota exceeded for %(resource)s: " + "Requested %(requested)s, " + "but available %(available)s") def __init__(self, resource, requested, available): - self.message = self.message % {'resource': resource, - 'requested': requested, - 'available': available} - super(QuotaException, self).__init__() + formatted_message = self.message_template % { + 'resource': resource, + 'requested': requested, + 'available': available} + + super(QuotaException, self).__init__(formatted_message) class UpdateFailedException(SaharaException): - message = _("Object '%s' could not be updated") + code = "UPDATE_FAILED" + message_template = _("Object '%s' could not be updated") # Object was unable to be updated - def __init__(self, value, message=None): - self.code = "UPDATE_FAILED" - if message: - self.message = message - self.message = self.message % value - super(UpdateFailedException, self).__init__() + def __init__(self, value, message_template=None): + if message_template: + self.message_template = message_template + + formatted_message = self.message_template % value + + super(UpdateFailedException, self).__init__(formatted_message) class MaxRetriesExceeded(SaharaException): code = "MAX_RETRIES_EXCEEDED" - message = _("Operation %(operation)s wasn't executed correctly after " - "%(attempts)d attempts") + message_template = _("Operation %(operation)s wasn't executed correctly " + "after %(attempts)d attempts") def __init__(self, attempts, operation): - self.message = self.message % {'operation': operation, - 'attempts': attempts} - super(MaxRetriesExceeded, self).__init__() + formatted_message = self.message_template % {'operation': operation, + 'attempts': attempts} + + super(MaxRetriesExceeded, self).__init__(formatted_message) diff --git a/sahara/plugins/vanilla/hadoop2/config_helper.py b/sahara/plugins/vanilla/hadoop2/config_helper.py index 686283fe..67b183bf 100644 --- a/sahara/plugins/vanilla/hadoop2/config_helper.py +++ b/sahara/plugins/vanilla/hadoop2/config_helper.py @@ -183,8 +183,8 @@ def get_config_value(pctx, service, name, cluster=None): return c.default_value raise ex.NotFoundException( - name, _("Unable to get parameter '%(name)s' from service %(service)s") - % {"name": name, "service": service}) + {"name": name, "service": service}, + _("Unable to get parameter '%(name)s' from service %(service)s")) def is_swift_enabled(pctx, cluster): diff --git a/sahara/service/edp/oozie/oozie.py b/sahara/service/edp/oozie/oozie.py index ea470e86..9e5fcc12 100644 --- a/sahara/service/edp/oozie/oozie.py +++ b/sahara/service/edp/oozie/oozie.py @@ -84,7 +84,7 @@ def _check_status_code(resp, expected_code): message = resp_text.split("
")[1] message = message.replace("

", "\n") message = re.sub('<[^<]+?>', ' ', message) - raise OozieException(message) + raise ex.OozieException(message) def get_json(response): @@ -95,9 +95,3 @@ def get_json(response): return response.json() else: return json.loads(response.content) - - -class OozieException(ex.SaharaException): - def __init__(self, message): - self.message = message - self.code = "OOZIE_EXCEPTION" diff --git a/sahara/service/edp/oozie/workflow_creator/base_workflow.py b/sahara/service/edp/oozie/workflow_creator/base_workflow.py index fa5e11e3..0ba30872 100644 --- a/sahara/service/edp/oozie/workflow_creator/base_workflow.py +++ b/sahara/service/edp/oozie/workflow_creator/base_workflow.py @@ -46,8 +46,8 @@ class OozieWorkflowCreator(object): def _add_to_prepare_element(self, element, paths): if element not in ['delete', 'mkdir']: raise ex.NotFoundException(element, - message=_('"%s" child cannot be ' - 'added to prepare element')) + _('"%s" child cannot be ' + 'added to prepare element')) prop = x.get_and_create_if_not_exist(self.doc, self.tag_name, 'prepare') for path in paths: @@ -57,8 +57,8 @@ class OozieWorkflowCreator(object): def _add_to_streaming_element(self, element, path): if element not in ['mapper', 'reducer']: raise ex.NotFoundException(element, - message=_('"%s" child cannot be added ' - 'to streaming element')) + _('"%s" child cannot be added ' + 'to streaming element')) x.get_and_create_if_not_exist(self.doc, self.tag_name, 'streaming') diff --git a/sahara/service/validations/clusters.py b/sahara/service/validations/clusters.py index 53e62e70..486464f1 100644 --- a/sahara/service/validations/clusters.py +++ b/sahara/service/validations/clusters.py @@ -96,7 +96,7 @@ def check_cluster_create(data, **kwargs): else: if CONF.use_neutron: raise ex.NotFoundException('neutron_management_network', - message=_("'%s' field is not found")) + _("'%s' field is not found")) def _get_cluster_field(cluster, field): diff --git a/sahara/tests/unit/conductor/test_resource.py b/sahara/tests/unit/conductor/test_resource.py index 48e0dc17..983189f7 100644 --- a/sahara/tests/unit/conductor/test_resource.py +++ b/sahara/tests/unit/conductor/test_resource.py @@ -18,9 +18,9 @@ import copy import testtools from sahara.conductor import resource as r +from sahara import exceptions as ex from sahara.swift import swift_helper from sahara.utils import edp -from sahara.utils import types SAMPLE_DICT = { @@ -147,13 +147,13 @@ class TestResource(testtools.TestCase): def test_resource_immutability(self): res = r.Resource(SAMPLE_DICT) - with testtools.ExpectedException(types.FrozenClassError): + with testtools.ExpectedException(ex.FrozenClassError): res.first.append(123) - with testtools.ExpectedException(types.FrozenClassError): + with testtools.ExpectedException(ex.FrozenClassError): res.first = 123 - with testtools.ExpectedException(types.FrozenClassError): + with testtools.ExpectedException(ex.FrozenClassError): res.second.a = 123 def test_nested_lists(self): diff --git a/sahara/tests/unit/test_exceptions.py b/sahara/tests/unit/test_exceptions.py index d53ed964..9e2bfdf3 100644 --- a/sahara/tests/unit/test_exceptions.py +++ b/sahara/tests/unit/test_exceptions.py @@ -149,7 +149,7 @@ class TestExceptions(base.SaharaTestCase): def test_forbidden(self): self._validate_exc(exc.Forbidden, "message", "message") self._validate_exc(exc.Forbidden, "You are not authorized " - "to complete this action.") + "to complete this action") def test_image_not_registered(self): self._validate_exc( diff --git a/sahara/utils/openstack/heat.py b/sahara/utils/openstack/heat.py index f67b7cc9..8722954b 100644 --- a/sahara/utils/openstack/heat.py +++ b/sahara/utils/openstack/heat.py @@ -53,8 +53,8 @@ def get_stack(stack_name): if stack.stack_name == stack_name: return stack - raise ex.NotFoundException(_('Failed to find stack %(stack)s') - % {'stack': stack_name}) + raise ex.NotFoundException({'stack': stack_name}, + _('Failed to find stack %(stack)s')) def wait_stack_completion(stack): diff --git a/sahara/utils/procutils.py b/sahara/utils/procutils.py index 64cfc989..58a0c5f6 100644 --- a/sahara/utils/procutils.py +++ b/sahara/utils/procutils.py @@ -22,6 +22,7 @@ from eventlet import timeout as e_timeout from oslo_log import log as logging from sahara import context +from sahara import exceptions LOG = logging.getLogger(__name__) @@ -49,7 +50,7 @@ def run_in_subprocess(proc, func, args=(), kwargs={}, interactive=False): result = pickle.load(proc.stdout) if 'exception' in result: - raise SubprocessException(result['exception']) + raise exceptions.SubprocessException(result['exception']) return result['output'] finally: @@ -91,8 +92,3 @@ def kill_subprocess(proc): except OSError: # could be caused by process already dead, so ignoring pass - - -class SubprocessException(Exception): - def __init__(self, e): - super(SubprocessException, self).__init__(e) diff --git a/sahara/utils/proxy.py b/sahara/utils/proxy.py index a3c0d204..8f771003 100644 --- a/sahara/utils/proxy.py +++ b/sahara/utils/proxy.py @@ -169,14 +169,15 @@ def domain_for_proxy(): domain_list = b.execute_with_retries( admin.domains.list, name=CONF.proxy_user_domain_name) if len(domain_list) == 0: - raise ex.NotFoundException(value=CONF.proxy_user_domain_name, - message=_('Failed to find domain %s')) + raise ex.NotFoundException( + value=CONF.proxy_user_domain_name, + message_template=_('Failed to find domain %s')) # the domain name should be globally unique in Keystone if len(domain_list) > 1: - raise ex.NotFoundException(value=CONF.proxy_user_domain_name, - message=_('Unexpected results found ' - 'when searching for domain ' - '%s')) + raise ex.NotFoundException( + value=CONF.proxy_user_domain_name, + message_template=_('Unexpected results found when searching ' + 'for domain %s')) PROXY_DOMAIN = domain_list[0] return PROXY_DOMAIN @@ -286,12 +287,14 @@ def proxy_user_delete(username=None, user_id=None): user_list = b.execute_with_retries( admin.users.list, domain=domain.id, name=username) if len(user_list) == 0: - raise ex.NotFoundException(value=username, - message=_('Failed to find user %s')) + raise ex.NotFoundException( + value=username, + message_template=_('Failed to find user %s')) if len(user_list) > 1: - raise ex.NotFoundException(value=username, - message=_('Unexpected results found ' - 'when searching for user %s')) + raise ex.NotFoundException( + value=username, + message_template=_('Unexpected results found when searching ' + 'for user %s')) user_id = user_list[0].id b.execute_with_retries(admin.users.delete, user_id) LOG.debug('Deleted proxy user id {user_id}'.format(user_id=user_id)) diff --git a/sahara/utils/ssh_remote.py b/sahara/utils/ssh_remote.py index 2d4204bd..c364e9a5 100644 --- a/sahara/utils/ssh_remote.py +++ b/sahara/utils/ssh_remote.py @@ -705,8 +705,8 @@ class InstanceInteropHelper(remote.Remote): session = _sessions.get((host, port), None) if session is None: raise ex.NotFoundException( - _('Session for %(host)s:%(port)s not cached') % { - 'host': host, 'port': port}) + {'host': host, 'port': port}, + _('Session for %(host)s:%(port)s not cached')) session.close() del _sessions[(host, port)] diff --git a/sahara/utils/types.py b/sahara/utils/types.py index c7989390..45662957 100644 --- a/sahara/utils/types.py +++ b/sahara/utils/types.py @@ -13,79 +13,74 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sahara.i18n import _ +from sahara import exceptions as ex class FrozenList(list): def append(self, p_object): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def extend(self, iterable): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def insert(self, index, p_object): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def pop(self, index=None): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def remove(self, value): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def reverse(self): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def sort(self, cmp=None, key=None, reverse=False): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __add__(self, y): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __delitem__(self, y): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __delslice__(self, i, j): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __iadd__(self, y): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __imul__(self, y): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __setitem__(self, i, y): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __setslice__(self, i, j, y): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) class FrozenDict(dict): def clear(self): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def pop(self, k, d=None): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def popitem(self): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def setdefault(self, k, d=None): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def update(self, E=None, **F): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __delitem__(self, y): - raise FrozenClassError(self) + raise ex.FrozenClassError(self) def __setitem__(self, i, y): - raise FrozenClassError(self) - - -class FrozenClassError(Exception): - def __init__(self, instance): - self.message = _("Class %s is immutable!") % type(instance).__name__ + raise ex.FrozenClassError(self) def is_int(s):