summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/errors2.py83
-rw-r--r--ipalib/plugable.py21
-rw-r--r--tests/test_ipalib/test_error2.py78
-rw-r--r--tests/test_ipalib/test_plugable.py22
4 files changed, 183 insertions, 21 deletions
diff --git a/ipalib/errors2.py b/ipalib/errors2.py
index 676dd79f3..7793a9146 100644
--- a/ipalib/errors2.py
+++ b/ipalib/errors2.py
@@ -43,7 +43,7 @@ import request
class PrivateError(StandardError):
"""
- Base class for exceptions that are *never* returned in an RPC response.
+ Base class for exceptions that are *never* forwarded in an RPC response.
"""
format = ''
@@ -72,15 +72,82 @@ class SubprocessError(PrivateError):
1
>>> e.argv
('/bin/false',)
+ >>> e.message
+ "return code 1 from ('/bin/false',)"
>>> str(e)
"return code 1 from ('/bin/false',)"
"""
+
format = 'return code %(returncode)d from %(argv)r'
+class PluginSubclassError(PrivateError):
+ """
+ Raised when a plugin doesn't subclass from an allowed base.
+
+ For example:
+
+ >>> raise PluginSubclassError(plugin='bad', bases=('base1', 'base2'))
+ Traceback (most recent call last):
+ ...
+ PluginSubclassError: 'bad' not subclass of any base in ('base1', 'base2')
+
+ """
+
+ format = '%(plugin)r not subclass of any base in %(bases)r'
+
+
+class PluginDuplicateError(PrivateError):
+ """
+ Raised when the same plugin class is registered more than once.
+
+ For example:
+
+ >>> raise PluginDuplicateError(plugin='my_plugin')
+ Traceback (most recent call last):
+ ...
+ PluginDuplicateError: 'my_plugin' was already registered
+ """
+
+ format = '%(plugin)r was already registered'
+
+
+class PluginOverrideError(PrivateError):
+ """
+ Raised when a plugin overrides another without using ``override=True``.
+
+ For example:
+
+ >>> raise PluginOverrideError(base='Command', name='env', plugin='my_env')
+ Traceback (most recent call last):
+ ...
+ PluginOverrideError: unexpected override of Command.env with 'my_env'
+ """
+
+ format = 'unexpected override of %(base)s.%(name)s with %(plugin)r'
+
+
+class PluginMissingOverrideError(PrivateError):
+ """
+ Raised when a plugin overrides another that has not been registered.
+
+ For example:
+
+ >>> raise PluginMissingOverrideError(base='Command', name='env', plugin='my_env')
+ Traceback (most recent call last):
+ ...
+ PluginMissingOverrideError: Command.env not registered, cannot override with 'my_env'
+ """
+
+ format = '%(base)s.%(name)s not registered, cannot override with %(plugin)r'
+
+
+
+##############################################################################
+# Public errors:
class PublicError(StandardError):
"""
- **900** Base class for exceptions that can be returned in an RPC response.
+ **900** Base class for exceptions that can be forwarded in an RPC response.
"""
code = 900
@@ -96,8 +163,6 @@ class PublicError(StandardError):
-
-
class InternalError(PublicError):
"""
**901** Used to conceal a non-public exception.
@@ -108,7 +173,7 @@ class InternalError(PublicError):
##############################################################################
-# 1000 - 1999: Authentication Errors
+# 1000 - 1999: Authentication errors
class AuthenticationError(PublicError):
"""
**1000** Base class for authentication errors (*1000 - 1999*).
@@ -119,7 +184,7 @@ class AuthenticationError(PublicError):
##############################################################################
-# 2000 - 2999: Authorization Errors
+# 2000 - 2999: Authorization errors
class AuthorizationError(PublicError):
"""
**2000** Base class for authorization errors (*2000 - 2999*).
@@ -130,7 +195,7 @@ class AuthorizationError(PublicError):
##############################################################################
-# 3000 - 3999: Invocation Errors
+# 3000 - 3999: Invocation errors
class InvocationError(PublicError):
"""
@@ -201,7 +266,7 @@ class ValidationError(InvocationError):
##############################################################################
-# 4000 - 4999: Execution Errors
+# 4000 - 4999: Execution errors
class ExecutionError(PublicError):
"""
@@ -213,7 +278,7 @@ class ExecutionError(PublicError):
##############################################################################
-# 5000 - 5999: Generic Errors
+# 5000 - 5999: Generic errors
class GenericError(PublicError):
"""
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index 4ef2135b5..094634d33 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -34,6 +34,7 @@ import os
from os import path
import subprocess
import errors
+import errors2
from config import Env
import util
from base import ReadOnly, NameSpace, lock, islocked, check_name
@@ -461,7 +462,9 @@ class Registrar(DictProxy):
found = True
yield (base, sub_d)
if not found:
- raise errors.SubclassError(klass, self.__allowed.keys())
+ raise errors2.PluginSubclassError(
+ plugin=klass, bases=self.__allowed.keys()
+ )
def __call__(self, klass, override=False):
"""
@@ -471,11 +474,11 @@ class Registrar(DictProxy):
:param override: If true, override an already registered plugin.
"""
if not inspect.isclass(klass):
- raise TypeError('plugin must be a class: %r' % klass)
+ raise TypeError('plugin must be a class; got %r' % klass)
# Raise DuplicateError if this exact class was already registered:
if klass in self.__registered:
- raise errors.DuplicateError(klass)
+ raise errors2.PluginDuplicateError(plugin=klass)
# Find the base class or raise SubclassError:
for (base, sub_d) in self.__findbases(klass):
@@ -483,11 +486,19 @@ class Registrar(DictProxy):
if klass.__name__ in sub_d:
if not override:
# Must use override=True to override:
- raise errors.OverrideError(base, klass)
+ raise errors2.PluginOverrideError(
+ base=base.__name__,
+ name=klass.__name__,
+ plugin=klass,
+ )
else:
if override:
# There was nothing already registered to override:
- raise errors.MissingOverrideError(base, klass)
+ raise errors2.PluginMissingOverrideError(
+ base=base.__name__,
+ name=klass.__name__,
+ plugin=klass,
+ )
# The plugin is okay, add to sub_d:
sub_d[klass.__name__] = klass
diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py
index f8b1a314d..9be247561 100644
--- a/tests/test_ipalib/test_error2.py
+++ b/tests/test_ipalib/test_error2.py
@@ -92,16 +92,92 @@ class test_SubprocessError(PrivateExceptionTester):
"""
Test the `ipalib.errors2.SubprocessError` exception.
"""
+
_klass = errors2.SubprocessError
def test_init(self):
"""
Test the `ipalib.errors2.SubprocessError.__init__` method.
"""
- inst = self.klass(returncode=1, argv=('/bin/false',))
+ inst = self.new(returncode=1, argv=('/bin/false',))
assert inst.returncode == 1
assert inst.argv == ('/bin/false',)
assert str(inst) == "return code 1 from ('/bin/false',)"
+ assert inst.message == str(inst)
+
+
+class test_PluginSubclassError(PrivateExceptionTester):
+ """
+ Test the `ipalib.errors2.PluginSubclassError` exception.
+ """
+
+ _klass = errors2.PluginSubclassError
+
+ def test_init(self):
+ """
+ Test the `ipalib.errors2.PluginSubclassError.__init__` method.
+ """
+ inst = self.new(plugin='bad', bases=('base1', 'base2'))
+ assert inst.plugin == 'bad'
+ assert inst.bases == ('base1', 'base2')
+ assert str(inst) == \
+ "'bad' not subclass of any base in ('base1', 'base2')"
+ assert inst.message == str(inst)
+
+
+class test_PluginDuplicateError(PrivateExceptionTester):
+ """
+ Test the `ipalib.errors2.PluginDuplicateError` exception.
+ """
+
+ _klass = errors2.PluginDuplicateError
+
+ def test_init(self):
+ """
+ Test the `ipalib.errors2.PluginDuplicateError.__init__` method.
+ """
+ inst = self.new(plugin='my_plugin')
+ assert inst.plugin == 'my_plugin'
+ assert str(inst) == "'my_plugin' was already registered"
+ assert inst.message == str(inst)
+
+
+class test_PluginOverrideError(PrivateExceptionTester):
+ """
+ Test the `ipalib.errors2.PluginOverrideError` exception.
+ """
+
+ _klass = errors2.PluginOverrideError
+
+ def test_init(self):
+ """
+ Test the `ipalib.errors2.PluginOverrideError.__init__` method.
+ """
+ inst = self.new(base='Base', name='cmd', plugin='my_cmd')
+ assert inst.base == 'Base'
+ assert inst.name == 'cmd'
+ assert inst.plugin == 'my_cmd'
+ assert str(inst) == "unexpected override of Base.cmd with 'my_cmd'"
+ assert inst.message == str(inst)
+
+
+class test_PluginMissingOverrideError(PrivateExceptionTester):
+ """
+ Test the `ipalib.errors2.PluginMissingOverrideError` exception.
+ """
+
+ _klass = errors2.PluginMissingOverrideError
+
+ def test_init(self):
+ """
+ Test the `ipalib.errors2.PluginMissingOverrideError.__init__` method.
+ """
+ inst = self.new(base='Base', name='cmd', plugin='my_cmd')
+ assert inst.base == 'Base'
+ assert inst.name == 'cmd'
+ assert inst.plugin == 'my_cmd'
+ assert str(inst) == "Base.cmd not registered, cannot override with 'my_cmd'"
+ assert inst.message == str(inst)
def test_public_errors():
diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py
index 9eb102ff4..dbf0cc3ff 100644
--- a/tests/test_ipalib/test_plugable.py
+++ b/tests/test_ipalib/test_plugable.py
@@ -25,7 +25,7 @@ import inspect
from tests.util import raises, no_set, no_del, read_only
from tests.util import getitem, setitem, delitem
from tests.util import ClassChecker, create_test_api
-from ipalib import plugable, errors
+from ipalib import plugable, errors, errors2
class test_SetProxy(ClassChecker):
@@ -534,11 +534,14 @@ def test_Registrar():
# Check that TypeError is raised trying to register something that isn't
# a class:
- raises(TypeError, r, plugin1())
+ p = plugin1()
+ e = raises(TypeError, r, p)
+ assert str(e) == 'plugin must be a class; got %r' % p
# Check that SubclassError is raised trying to register a class that is
# not a subclass of an allowed base:
- raises(errors.SubclassError, r, plugin3)
+ e = raises(errors2.PluginSubclassError, r, plugin3)
+ assert e.plugin is plugin3
# Check that registration works
r(plugin1)
@@ -548,7 +551,8 @@ def test_Registrar():
# Check that DuplicateError is raised trying to register exact class
# again:
- raises(errors.DuplicateError, r, plugin1)
+ e = raises(errors2.PluginDuplicateError, r, plugin1)
+ assert e.plugin is plugin1
# Check that OverrideError is raised trying to register class with same
# name and same base:
@@ -557,7 +561,10 @@ def test_Registrar():
pass
class plugin1(base1_extended):
pass
- raises(errors.OverrideError, r, plugin1)
+ e = raises(errors2.PluginOverrideError, r, plugin1)
+ assert e.base == 'Base1'
+ assert e.name == 'plugin1'
+ assert e.plugin is plugin1
# Check that overriding works
r(plugin1, override=True)
@@ -567,7 +574,10 @@ def test_Registrar():
# Check that MissingOverrideError is raised trying to override a name
# not yet registerd:
- raises(errors.MissingOverrideError, r, plugin2, override=True)
+ e = raises(errors2.PluginMissingOverrideError, r, plugin2, override=True)
+ assert e.base == 'Base2'
+ assert e.name == 'plugin2'
+ assert e.plugin is plugin2
# Test that another plugin can be registered:
assert len(r.Base2) == 0