summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2009-04-20 13:58:26 -0400
committerRob Crittenden <rcritten@redhat.com>2009-04-20 13:58:26 -0400
commit64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a (patch)
treea4543df175f8bf0efcd200662a9e7f00fea7bf52
parenta9387b48e66ca93cc8323869de25fe3f777567b6 (diff)
downloadfreeipa-64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a.tar.gz
freeipa-64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a.tar.xz
freeipa-64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a.zip
Finish work replacing the errors module with errors2
Once this is committed we can start the process of renaming errors2 as errors. I thought that combinig this into one commit would be more difficult to review.
-rwxr-xr-xinstall/tools/ipa-compat-manage2
-rw-r--r--ipalib/cli.py8
-rw-r--r--ipalib/errors.py441
-rw-r--r--ipalib/errors2.py174
-rw-r--r--ipalib/plugins/basegroup.py2
-rw-r--r--ipalib/plugins/passwd.py14
-rw-r--r--ipalib/util.py21
-rw-r--r--ipaserver/install/ldapupdate.py12
-rw-r--r--ipaserver/ipaldap.py110
-rw-r--r--ipaserver/plugins/ldap2.py94
-rw-r--r--ipaserver/servercore.py32
-rw-r--r--tests/test_ipalib/test_errors.py289
-rw-r--r--tests/test_ipalib/test_frontend.py2
-rw-r--r--tests/test_ipalib/test_plugable.py2
-rw-r--r--tests/test_xmlrpc/xmlrpc_test.py1
15 files changed, 350 insertions, 854 deletions
diff --git a/install/tools/ipa-compat-manage b/install/tools/ipa-compat-manage
index b3217876..8c707e5b 100755
--- a/install/tools/ipa-compat-manage
+++ b/install/tools/ipa-compat-manage
@@ -26,7 +26,7 @@ try:
from ipapython import entity, ipautil, config
from ipaserver.install import installutils
from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax, UPDATES_DIR
- from ipalib import errors, errors2
+ from ipalib import errors2
import ldap
import logging
import re
diff --git a/ipalib/cli.py b/ipalib/cli.py
index 11b56e36..36c945f2 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -36,8 +36,7 @@ import frontend
import backend
import plugable
import util
-from errors2 import PublicError, CommandError, HelpError, InternalError
-import errors
+from errors2 import PublicError, CommandError, HelpError, InternalError, NoSuchNamespaceError, ValidationError
from constants import CLI_TAB
from parameters import Password, Bytes
from request import ugettext as _
@@ -456,7 +455,7 @@ class show_api(frontend.Application):
else:
for name in namespaces:
if name not in self.api:
- raise errors.NoSuchNamespaceError(name)
+ raise NoSuchNamespaceError(name=name)
names = namespaces
lines = self.__traverse(names)
ml = max(len(l[1]) for l in lines)
@@ -478,7 +477,6 @@ class show_api(frontend.Application):
s = '%d attributes show.' % len(lines)
self.Backend.textui.print_dashed(s)
-
def __traverse(self, names):
lines = []
for name in names:
@@ -635,7 +633,7 @@ class cli(backend.Executioner):
if value is not None:
kw[param.name] = value
break
- except errors.ValidationError, e:
+ except ValidationError, e:
error = e.error
diff --git a/ipalib/errors.py b/ipalib/errors.py
deleted file mode 100644
index c27d85de..00000000
--- a/ipalib/errors.py
+++ /dev/null
@@ -1,441 +0,0 @@
-# Authors:
-# Jason Gerard DeRose <jderose@redhat.com>
-#
-# Copyright (C) 2008 Red Hat
-# see file 'COPYING' for use and warranty inmsgion
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; version 2 only
-#
-# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-"""
-All custom errors raised by `ipalib` package.
-
-Also includes a few utility functions for raising exceptions.
-"""
-
-IPA_ERROR_BASE = 1000
-
-TYPE_FORMAT = '%s: need a %r; got %r'
-
-def raise_TypeError(value, type_, name):
- """
- Raises a TypeError with a nicely formatted message and helpful attributes.
-
- The TypeError raised will have three custom attributes:
-
- ``value`` - The value (of incorrect type) passed as argument.
-
- ``type`` - The type expected for the argument.
-
- ``name`` - The name (identifier) of the argument in question.
-
- There is no edict that all TypeError should be raised with raise_TypeError,
- but when it fits, use it... it makes the unit tests faster to write and
- the debugging easier to read.
-
- Here is an example:
-
- >>> raise_TypeError(u'Hello, world!', str, 'message')
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "ipalib/errors.py", line 65, in raise_TypeError
- raise e
- TypeError: message: need a <type 'str'>; got u'Hello, world!'
-
- :param value: The value (of incorrect type) passed as argument.
- :param type_: The type expected for the argument.
- :param name: The name (identifier) of the argument in question.
- """
-
- assert type(type_) is type, TYPE_FORMAT % ('type_', type, type_)
- assert type(value) is not type_, 'value: %r is a %r' % (value, type_)
- assert type(name) is str, TYPE_FORMAT % ('name', str, name)
- e = TypeError(TYPE_FORMAT % (name, type_, value))
- setattr(e, 'value', value)
- setattr(e, 'type', type_)
- setattr(e, 'name', name)
- raise e
-
-
-def check_type(value, type_, name, allow_none=False):
- assert type(name) is str, TYPE_FORMAT % ('name', str, name)
- assert type(type_) is type, TYPE_FORMAT % ('type_', type, type_)
- assert type(allow_none) is bool, TYPE_FORMAT % ('allow_none', bool, allow_none)
- if value is None and allow_none:
- return
- if type(value) is not type_:
- raise_TypeError(value, type_, name)
- return value
-
-
-def check_isinstance(value, type_, name, allow_none=False):
- assert type(type_) is type, TYPE_FORMAT % ('type_', type, type_)
- assert type(name) is str, TYPE_FORMAT % ('name', str, name)
- assert type(allow_none) is bool, TYPE_FORMAT % ('allow_none', bool, allow_none)
- if value is None and allow_none:
- return
- if not isinstance(value, type_):
- raise_TypeError(value, type_, name)
- return value
-
-
-class IPAError(StandardError):
- """
- Base class for all custom IPA errors.
-
- Use this base class for your custom IPA errors unless there is a
- specific reason to subclass from AttributeError, KeyError, etc.
- """
-
- format = None
- faultCode = 1
-
- def __init__(self, *args):
- self.args = args
-
- def __str__(self):
- """
- Returns the string representation of this exception.
- """
- return self.format % self.args
-
-
-class InvocationError(IPAError):
- pass
-
-
-class UnknownCommandError(InvocationError):
- format = 'unknown command "%s"'
-
-class NoSuchNamespaceError(InvocationError):
- format = 'api has no such namespace: %s'
-
-def _(text):
- return text
-
-
-class SubprocessError(StandardError):
- def __init__(self, returncode, argv):
- self.returncode = returncode
- self.argv = argv
- StandardError.__init__(self,
- 'return code %d from %r' % (returncode, argv)
- )
-
-class HandledError(StandardError):
- """
- Base class for errors that can be raised across a remote procedure call.
- """
-
- code = 1
-
- def __init__(self, message=None, **kw):
- self.kw = kw
- if message is None:
- message = self.format % kw
- StandardError.__init__(self, message)
-
-
-class UnknownError(HandledError):
- """
- Raised when the true error is not a handled error.
- """
-
- format = _('An unknown internal error has occurred')
-
-
-class CommandError(HandledError):
- """
- Raised when an unknown command is called client-side.
- """
- format = _('Unknown command %(name)r')
-
-
-class RemoteCommandError(HandledError):
- format = 'Server at %(uri)r has no command %(name)r'
-
-
-class UnknownHelpError(InvocationError):
- format = 'no command nor topic "%s"'
-
-
-class ArgumentError(IPAError):
- """
- Raised when a command is called with wrong number of arguments.
- """
-
- format = '%s %s'
-
- def __init__(self, command, error):
- self.command = command
- self.error = error
- IPAError.__init__(self, command.name, error)
-
-
-class ValidationError(IPAError):
- """
- Base class for all types of validation errors.
- """
-
- format = 'invalid %r value %r: %s'
-
- def __init__(self, name, value, error, index=None):
- """
- :param name: The name of the value that failed validation.
- :param value: The value that failed validation.
- :param error: The error message describing the failure.
- :param index: If multivalue, index of value in multivalue tuple
- """
- assert type(name) is str
- assert index is None or (type(index) is int and index >= 0)
- self.name = name
- self.value = value
- self.error = error
- self.index = index
- IPAError.__init__(self, name, value, error)
-
-
-class ConversionError(ValidationError):
- """
- Raised when a value cannot be converted to the correct type.
- """
-
- def __init__(self, name, value, type_, index=None):
- self.type = type_
- ValidationError.__init__(self, name, value, type_.conversion_error,
- index=index,
- )
-
-
-class RuleError(ValidationError):
- """
- Raised when a value fails a validation rule.
- """
- def __init__(self, name, value, error, rule, index=None):
- assert callable(rule)
- self.rule = rule
- ValidationError.__init__(self, name, value, error, index=index)
-
-
-class RequirementError(ValidationError):
- """
- Raised when a required option was not provided.
- """
- def __init__(self, name):
- ValidationError.__init__(self, name, None, 'Required')
-
-
-class RegistrationError(IPAError):
- """
- Base class for errors that occur during plugin registration.
- """
-
-
-class SubclassError(RegistrationError):
- """
- Raised when registering a plugin that is not a subclass of one of the
- allowed bases.
- """
- msg = 'plugin %r not subclass of any base in %r'
-
- def __init__(self, cls, allowed):
- self.cls = cls
- self.allowed = allowed
-
- def __str__(self):
- return self.msg % (self.cls, self.allowed)
-
-
-class DuplicateError(RegistrationError):
- """
- Raised when registering a plugin whose exact class has already been
- registered.
- """
- msg = '%r at %d was already registered'
-
- def __init__(self, cls):
- self.cls = cls
-
- def __str__(self):
- return self.msg % (self.cls, id(self.cls))
-
-
-class OverrideError(RegistrationError):
- """
- Raised when override=False yet registering a plugin that overrides an
- existing plugin in the same namespace.
- """
- msg = 'unexpected override of %s.%s with %r (use override=True if intended)'
-
- def __init__(self, base, cls):
- self.base = base
- self.cls = cls
-
- def __str__(self):
- return self.msg % (self.base.__name__, self.cls.__name__, self.cls)
-
-
-class MissingOverrideError(RegistrationError):
- """
- Raised when override=True yet no preexisting plugin with the same name
- and base has been registered.
- """
- msg = '%s.%s has not been registered, cannot override with %r'
-
- def __init__(self, base, cls):
- self.base = base
- self.cls = cls
-
- def __str__(self):
- return self.msg % (self.base.__name__, self.cls.__name__, self.cls)
-
-class GenericError(IPAError):
- """Base class for our custom exceptions"""
- faultCode = 1000
- fromFault = False
- def __str__(self):
- try:
- return str(self.args[0]['args'][0])
- except:
- try:
- return str(self.args[0])
- except:
- return str(self.__dict__)
-
-class DatabaseError(GenericError):
- """A database error has occurred"""
- faultCode = 1001
-
-class MidairCollision(GenericError):
- """Change collided with another change"""
- faultCode = 1002
-
-class MissingDN(GenericError):
- """The distinguished name (DN) is missing"""
- faultCode = 1005
-
-class EmptyModlist(GenericError):
- """No modifications to be performed"""
- faultCode = 1006
-
-class InputError(GenericError):
- """Error on input"""
- faultCode = 1007
-
-class SameGroupError(InputError):
- """You can't add a group to itself"""
- faultCode = 1008
-
-class NotGroupMember(InputError):
- """This entry is not a member of the group"""
- faultCode = 1009
-
-class AdminsImmutable(InputError):
- """The admins group cannot be renamed"""
- faultCode = 1010
-
-class UsernameTooLong(InputError):
- """The requested username is too long"""
- faultCode = 1011
-
-class PrincipalError(GenericError):
- """There is a problem with the kerberos principal"""
- faultCode = 1012
-
-class PrincipalRequired(PrincipalError):
- """You cannot remove IPA server service principals"""
- faultCode = 1015
-
-class InactivationError(GenericError):
- """This entry cannot be inactivated"""
- faultCode = 1016
-
-class AlreadyActiveError(InactivationError):
- """This entry is already locked"""
- faultCode = 1017
-
-class AlreadyInactiveError(InactivationError):
- """This entry is already unlocked"""
- faultCode = 1018
-
-class HasNSAccountLock(InactivationError):
- """This entry appears to have the nsAccountLock attribute in it so the Class of Service activation/inactivation will not work. You will need to remove the attribute nsAccountLock for this to work."""
- faultCode = 1019
-
-class ConnectionError(GenericError):
- """Connection to database failed"""
- faultCode = 1020
-
-class NoCCacheError(GenericError):
- """No Kerberos credentials cache is available. Connection cannot be made"""
- faultCode = 1021
-
-class GSSAPIError(GenericError):
- """GSSAPI Authorization error"""
- faultCode = 1022
-
-class ServerUnwilling(GenericError):
- """Account inactivated. Server is unwilling to perform"""
- faultCode = 1023
-
-class ConfigurationError(GenericError):
- """A configuration error occurred"""
- faultCode = 1024
-
-class DefaultGroup(ConfigurationError):
- """You cannot remove the default users group"""
- faultCode = 1025
-
-class InvalidUserPrincipal(GenericError):
- """Invalid user principal"""
- faultCode = 1028
-
-class FunctionDeprecated(GenericError):
- """Raised by a deprecated function"""
- faultCode = 2000
-
-def convertFault(fault):
- """Convert a fault to the corresponding Exception type, if possible"""
- code = getattr(fault,'faultCode',None)
- if code is None:
- return fault
- for v in globals().values():
- if type(v) == type(Exception) and issubclass(v,GenericError) and \
- code == getattr(v,'faultCode',None):
- ret = v(fault.faultString)
- ret.fromFault = True
- return ret
- #otherwise...
- return fault
-
-def listFaults():
- """Return a list of faults
-
- Returns a list of dictionaries whose keys are:
- faultCode: the numeric code used in fault conversion
- name: the name of the exception
- desc: the description of the exception (docstring)
- """
- ret = []
- for n,v in globals().items():
- if type(v) == type(Exception) and issubclass(v,GenericError):
- code = getattr(v,'faultCode',None)
- if code is None:
- continue
- info = {}
- info['faultCode'] = code
- info['name'] = n
- info['desc'] = getattr(v,'__doc__',None)
- ret.append(info)
- ret.sort(lambda a,b: cmp(a['faultCode'],b['faultCode']))
- return ret
diff --git a/ipalib/errors2.py b/ipalib/errors2.py
index 7e752d82..341421e5 100644
--- a/ipalib/errors2.py
+++ b/ipalib/errors2.py
@@ -699,6 +699,21 @@ class ValidationError(InvocationError):
format = _('invalid %(name)r: %(error)s')
+class NoSuchNamespaceError(InvocationError):
+ """
+ **3010** Raised when an unknown namespace is requested.
+
+ For example:
+
+ >>> raise NoSuchNamespaceError(name='Plugins')
+ Traceback (most recent call last):
+ ...
+ NoSuchNamespaceError: api has no such namespace: Plugins
+ """
+
+ errno = 3010
+ format = _('api has no such namespace: %(name)r')
+
##############################################################################
# 4000 - 4999: Execution errors
@@ -822,6 +837,102 @@ class AlreadyPosixGroup(ExecutionError):
errno = 4007
format = _('This is already a posix group')
+class MalformedUserPrincipal(ExecutionError):
+ """
+ **4008** Raised when a user principal is not of the form: user@REALM
+
+ For example:
+
+ >>> raise MalformedUserPrincipal(principal=jsmith@@EXAMPLE.COM)
+ Traceback (most recent call last):
+ ...
+ MalformedUserPrincipal: Principal is not of the form user@REALM: jsmith@@EXAMPLE.COM
+
+ """
+
+ errno = 4008
+ format = _('Principal is not of the form user@REALM: %(principal)r')
+
+class AlreadyActive(ExecutionError):
+ """
+ **4009** Raised when an entry is made active that is already active
+
+ For example:
+
+ >>> raise AlreadyActive()
+ Traceback (most recent call last):
+ ...
+ AlreadyActive: This entry is already unlocked
+
+ """
+
+ errno = 4009
+ format = _('This entry is already unlocked')
+
+class AlreadyInactive(ExecutionError):
+ """
+ **4010** Raised when an entry is made inactive that is already inactive
+
+ For example:
+
+ >>> raise AlreadyInactive()
+ Traceback (most recent call last):
+ ...
+ AlreadyInactive: This entry is already locked
+
+ """
+
+ errno = 4010
+ format = _('This entry is already locked')
+
+class HasNSAccountLock(ExecutionError):
+ """
+ **4011** Raised when an entry has the nsAccountLock attribute set
+
+ For example:
+
+ >>> raise HasNSAccountLock()
+ Traceback (most recent call last):
+ ...
+ HasNSAccountLock: This entry has nsAccountLock set, it cannot be locked or unlocked
+
+ """
+
+ errno = 4011
+ format = _('This entry has nsAccountLock set, it cannot be locked or unlocked')
+
+class NotGroupMember(ExecutionError):
+ """
+ **4012** Raised when a non-member is attempted to be removed from a group
+
+ For example:
+
+ >>> raise NotGroupMember()
+ Traceback (most recent call last):
+ ...
+ NotGroupMember: This entry is not a member of the group
+
+ """
+
+ errno = 4012
+ format = _('This entry is not a member of the group')
+
+class RecursiveGroup(ExecutionError):
+ """
+ **4013** Raised when a group is added as a member of itself
+
+ For example:
+
+ >>> raise RecursiveGroup()
+ Traceback (most recent call last):
+ ...
+ RecursiveGroup: A group may not be a member of itself
+
+ """
+
+ errno = 4013
+ format = _('A group may not be a member of itself')
+
class BuiltinError(ExecutionError):
"""
**4100** Base class for builtin execution errors (*4100 - 4199*).
@@ -854,6 +965,69 @@ class LDAPError(ExecutionError):
errno = 4200
+class MidairCollision(ExecutionError):
+ """
+ **4201** Raised when a change collides with another change
+
+ For example:
+
+ >>> raise MidairCollision()
+ Traceback (most recent call last):
+ ...
+ MidairCollision: change collided with another change
+ """
+
+ errno = 4201
+ format = _('change collided with another change')
+
+
+class EmptyModlist(ExecutionError):
+ """
+ **4202** Raised when an LDAP update makes no changes
+
+ For example:
+
+ >>> raise EmptyModlist()
+ Traceback (most recent call last):
+ ...
+ EmptyModlist: no modifications to be performed
+ """
+
+ errno = 4202
+ format = _('no modifications to be performed')
+
+
+class DatabaseError(ExecutionError):
+ """
+ **4203** Raised when an LDAP error is not otherwise handled
+
+ For example:
+
+ >>> raise DatabaseError(desc="Can't contact LDAP server", info="")
+ Traceback (most recent call last):
+ ...
+ DatabaseError: Can't contact LDAP server:
+ """
+
+ errno = 4203
+ format = _('%(desc)r:%(info)r')
+
+
+class LimitsExceeded(ExecutionError):
+ """
+ **4204** Raised when search limits are exceeded.
+
+ For example:
+
+ >>> raise LimitsExceeded()
+ Traceback (most recent call last):
+ ...
+ LimitsExceeded: limits exceeded for this query
+ """
+
+ errno = 4204
+ format = _('limits exceeded for this query')
+
##############################################################################
# 5000 - 5999: Generic errors
diff --git a/ipalib/plugins/basegroup.py b/ipalib/plugins/basegroup.py
index 7cba75a4..b93fdc8d 100644
--- a/ipalib/plugins/basegroup.py
+++ b/ipalib/plugins/basegroup.py
@@ -21,7 +21,7 @@
Base plugin for groups.
"""
-from ipalib import api, crud, errors, errors2
+from ipalib import api, crud, errors2
from ipalib import Object, Command # Plugin base classes
from ipalib import Str, Int, Flag, List # Parameter types
from ldap.dn import escape_dn_chars
diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py
index a599276f..cc7ab586 100644
--- a/ipalib/plugins/passwd.py
+++ b/ipalib/plugins/passwd.py
@@ -21,7 +21,7 @@
Frontend plugins for password changes.
"""
-from ipalib import api, errors, util
+from ipalib import api, errors2, util
from ipalib import Command # Plugin base classes
from ipalib import Str, Password # Parameter types
@@ -30,13 +30,13 @@ class passwd(Command):
'Edit existing password policy.'
takes_args = (
- Password('password'),
- Str('principal?',
+ Str('principal',
cli_name='user',
primary_key=True,
autofill=True,
- default_from=util.get_current_principal,
+ create_default=lambda **kw: util.get_current_principal(),
),
+ Password('password'),
)
def execute(self, principal, password):
@@ -48,13 +48,13 @@ class passwd(Command):
Returns the entry
- :param param uid: The login name of the user being updated.
- :param kw: Not used.
+ :param principal: The login name or principal of the user
+ :param password: the new password
"""
if principal.find('@') > 0:
u = principal.split('@')
if len(u) > 2:
- raise errors.InvalidUserPrincipal(principal)
+ raise errors2.MalformedUserPrincipal(principal=principal)
else:
principal = principal+"@"+self.api.env.realm
dn = self.Backend.ldap.find_entry_dn(
diff --git a/ipalib/util.py b/ipalib/util.py
index 3e47cc3a..54529b14 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -22,24 +22,21 @@ Various utility functions.
"""
import os
-from os import path
import imp
import optparse
import logging
import time
-from types import NoneType
-from xmlrpclib import Binary
import krbV
import socket
+from ipalib import errors2
def get_current_principal():
try:
- return krbV.default_context().default_ccache().principal().name
+ return unicode(krbV.default_context().default_ccache().principal().name)
except krbV.Krb5Error:
- #TODO: do a kinit
- print "Unable to get kerberos principal"
- return None
+ #TODO: do a kinit?
+ raise errors2.CCacheError()
def get_fqdn():
fqdn = ""
@@ -57,16 +54,16 @@ def find_modules_in_dir(src_dir):
"""
Iterate through module names found in ``src_dir``.
"""
- if not (path.abspath(src_dir) == src_dir and path.isdir(src_dir)):
+ if not (os.path.abspath(src_dir) == src_dir and os.path.isdir(src_dir)):
return
- if path.islink(src_dir):
+ if os.path.islink(src_dir):
return
suffix = '.py'
for name in sorted(os.listdir(src_dir)):
if not name.endswith(suffix):
continue
- pyfile = path.join(src_dir, name)
- if path.islink(pyfile) or not path.isfile(pyfile):
+ pyfile = os.path.join(src_dir, name)
+ if os.path.islink(pyfile) or not os.path.isfile(pyfile):
continue
module = name[:-len(suffix)]
if module == '__init__':
@@ -92,7 +89,7 @@ def import_plugins_subpackage(name):
plugins = __import__(name + '.plugins').plugins
except ImportError:
return
- src_dir = path.dirname(path.abspath(plugins.__file__))
+ src_dir = os.path.dirname(os.path.abspath(plugins.__file__))
for name in find_modules_in_dir(src_dir):
full_name = '%s.%s' % (plugins.__name__, name)
__import__(full_name)
diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py
index f002595d..17b519b3 100644
--- a/ipaserver/install/ldapupdate.py
+++ b/ipaserver/install/ldapupdate.py
@@ -29,7 +29,7 @@ from ipaserver.install import installutils
from ipaserver import ipaldap
from ipapython import entity, ipautil
from ipalib import util
-from ipalib import errors, errors2
+from ipalib import errors2
import ldap
import logging
import krbV
@@ -310,10 +310,10 @@ class LDAPUpdate:
while True:
try:
entry = self.conn.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)", attrlist)
- except errors2.NotFound:
+ except errors2.NotFound, e:
logging.error("Task not found: %s", dn)
return
- except errors.DatabaseError, e:
+ except errors2.DatabaseError, e:
logging.error("Task lookup failure %s", e)
return
@@ -484,7 +484,7 @@ class LDAPUpdate:
# Doesn't exist, start with the default entry
entry = new_entry
logging.info("New entry: %s", entry.dn)
- except errors.DatabaseError:
+ except errors2.DatabaseError:
# Doesn't exist, start with the default entry
entry = new_entry
logging.info("New entry, using default value: %s", entry.dn)
@@ -521,10 +521,10 @@ class LDAPUpdate:
if self.live_run and updated:
self.conn.updateEntry(entry.dn, entry.origDataDict(), entry.toDict())
logging.info("Done")
- except errors.EmptyModlist:
+ except errors2.EmptyModlist:
logging.info("Entry already up-to-date")
updated = False
- except errors.DatabaseError, e:
+ except errors2.DatabaseError, e:
logging.error("Update failed: %s", e)
updated = False
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index 01370b86..e63fe55b 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -32,7 +32,7 @@ import ldap.sasl
from ldap.controls import LDAPControl,DecodeControlTuples,EncodeControlTuples
from ldap.ldapobject import SimpleLDAPObject
from ipaserver import ipautil
-from ipalib import errors, errors2
+from ipalib import errors2
# Global variable to define SASL auth
sasl_auth = ldap.sasl.sasl({},'GSSAPI')
@@ -264,6 +264,50 @@ class IPAdmin(SimpleLDAPObject):
return sctrl
+ def __handle_errors(self, e, **kw):
+ """
+ Centralize error handling in one place.
+
+ e is the error to be raised
+ **kw is an exception-specific list of options
+ """
+ if not isinstance(e,ldap.TIMEOUT):
+ desc = e.args[0]['desc'].strip()
+ info = e.args[0].get('info','').strip()
+ else:
+ desc = ''
+ info = ''
+
+ try:
+ # re-raise the error so we can handle it
+ raise e
+ except ldap.NO_SUCH_OBJECT, e:
+ args = kw.get('args', '')
+ raise errors2.NotFound(msg=notfound(args))
+ except ldap.ALREADY_EXISTS, e:
+ raise errors2.DuplicateEntry()
+ except ldap.CONSTRAINT_VIOLATION, e:
+ # This error gets thrown by the uniqueness plugin
+ if info == 'Another entry with the same attribute value already exists':
+ raise errors2.DuplicateEntry()
+ else:
+ raise errors2.DatabaseError(desc=desc,info=info)
+ except ldap.INSUFFICIENT_ACCESS, e:
+ raise errors2.ACIError(info=info)
+ except ldap.NO_SUCH_ATTRIBUTE:
+ # this is raised when a 'delete' attribute isn't found.
+ # it indicates the previous attribute was removed by another
+ # update, making the oldentry stale.
+ raise errors2.MidairCollision()
+ except ldap.ADMINLIMIT_EXCEEDED, e:
+ raise errors2.LimitsExceeded()
+ except ldap.SIZELIMIT_EXCEEDED, e:
+ raise errors2.LimitsExceeded()
+ except ldap.TIMELIMIT_EXCEEDED, e:
+ raise errors2.LimitsExceeded()
+ except ldap.LDAPError, e:
+ raise errors2.DatabaseError(desc=desc,info=info)
+
def toLDAPURL(self):
return "ldap://%s:%d/" % (self.host,self.port)
@@ -271,11 +315,14 @@ class IPAdmin(SimpleLDAPObject):
self.proxydn = proxydn
def set_krbccache(self, krbccache, principal):
- if krbccache is not None:
- os.environ["KRB5CCNAME"] = krbccache
- self.sasl_interactive_bind_s("", sasl_auth)
- self.principal = principal
- self.proxydn = None
+ try:
+ if krbccache is not None:
+ os.environ["KRB5CCNAME"] = krbccache
+ self.sasl_interactive_bind_s("", sasl_auth)
+ self.principal = principal
+ self.proxydn = None
+ except ldap.LDAPError, e:
+ self.__handle_errors(e, **{})
def do_simple_bind(self, binddn="cn=directory manager", bindpw=""):
self.binddn = binddn
@@ -293,10 +340,9 @@ class IPAdmin(SimpleLDAPObject):
try:
res = self.search(*args)
objtype, obj = self.result(res)
- except ldap.NO_SUCH_OBJECT, e:
- raise errors2.NotFound(msg=notfound(args))
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
if not obj:
raise errors2.NotFound(msg=notfound(args))
@@ -316,11 +362,9 @@ class IPAdmin(SimpleLDAPObject):
try:
res = self.search(*args)
objtype, obj = self.result(res)
- except (ldap.ADMINLIMIT_EXCEEDED, ldap.SIZELIMIT_EXCEEDED), e:
- # Too many results returned by search
- raise e
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
if not obj:
raise errors2.NotFound(msg=notfound(args))
@@ -357,7 +401,8 @@ class IPAdmin(SimpleLDAPObject):
ldap.TIMELIMIT_EXCEEDED), e:
partial = 1
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
if not entries:
raise errors2.NotFound(msg=notfound(args))
@@ -379,18 +424,9 @@ class IPAdmin(SimpleLDAPObject):
if sctrl is not None:
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
self.add_s(*args)
- except ldap.ALREADY_EXISTS, e:
- raise errors2.DuplicateEntry
- except ldap.CONSTRAINT_VIOLATION, e:
- # This error gets thrown by the uniqueness plugin
- if e.args[0].get('info','') == 'Another entry with the same attribute value already exists':
- raise errors2.DuplicateEntry
- else:
- raise errors.DatabaseError, e
- except ldap.INSUFFICIENT_ACCESS, e:
- raise errors2.ACIError(info=e.args[0].get('info',''))
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
return True
def updateRDN(self, dn, newrdn):
@@ -407,7 +443,8 @@ class IPAdmin(SimpleLDAPObject):
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
self.modrdn_s(dn, newrdn, delold=1)
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
return True
def updateEntry(self,dn,oldentry,newentry):
@@ -425,15 +462,9 @@ class IPAdmin(SimpleLDAPObject):
if sctrl is not None:
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
self.modify_s(dn, modlist)
- # this is raised when a 'delete' attribute isn't found.
- # it indicates the previous attribute was removed by another
- # update, making the oldentry stale.
- except ldap.NO_SUCH_ATTRIBUTE:
- raise errors.MidairCollision
- except ldap.INSUFFICIENT_ACCESS, e:
- raise errors2.ACIError(info=e.args[0].get('info',''))
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
return True
def generateModList(self, old_entry, new_entry):
@@ -491,7 +522,8 @@ class IPAdmin(SimpleLDAPObject):
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
self.modify_s(dn, modlist)
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
return True
def deleteEntry(self,*args):
@@ -503,10 +535,9 @@ class IPAdmin(SimpleLDAPObject):
if sctrl is not None:
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
self.delete_s(*args)
- except ldap.INSUFFICIENT_ACCESS, e:
- raise errors2.ACIError(info=e.args[0].get('info',''))
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
return True
def modifyPassword(self,dn,oldpass,newpass):
@@ -524,7 +555,8 @@ class IPAdmin(SimpleLDAPObject):
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
self.passwd_s(dn, oldpass, newpass)
except ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ kw = {'args': args}
+ self.__handle_errors(e, **kw)
return True
def __wrapmethods(self):
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index ca084902..b823c2ac 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -44,7 +44,7 @@ from ldap.controls import LDAPControl
from ldap.ldapobject import SimpleLDAPObject
from ipalib import api
-from ipalib import errors, errors2
+from ipalib import errors2
from ipalib.crud import CrudBackend
# attribute syntax to python type mapping, 'SYNTAX OID': type
@@ -87,7 +87,7 @@ def _load_schema(host, port):
conn.unbind_s()
except _ldap.LDAPError, e:
# TODO: raise a more appropriate exception
- raise errors.DatabaseError
+ self.__handle_errors(e, **{})
except IndexError:
# no 'cn=schema' entry in LDAP? some servers use 'cn=subschema'
# TODO: DS uses 'cn=schema', support for other server?
@@ -168,6 +168,51 @@ class ldap2(CrudBackend):
else:
entry_attrs[k] = attr_type(v)
+ def __handle_errors(self, e, **kw):
+ """
+ Centralize error handling in one place.
+
+ e is the error to be raised
+ **kw is an exception-specific list of options
+ """
+ if not isinstance(e,ldap.TIMEOUT):
+ desc = e.args[0]['desc'].strip()
+ info = e.args[0].get('info','').strip()
+ else:
+ desc = ''
+ info = ''
+
+ try:
+ # re-raise the error so we can handle it
+ raise e
+ except _ldap.NO_SUCH_OBJECT, e:
+ # args = kw.get('args', '')
+ # raise errors2.NotFound(msg=notfound(args))
+ raise errors2.NotFound()
+ except _ldap.ALREADY_EXISTS, e:
+ raise errors2.DuplicateEntry()
+ except _ldap.CONSTRAINT_VIOLATION, e:
+ # This error gets thrown by the uniqueness plugin
+ if info == 'Another entry with the same attribute value already exists':
+ raise errors2.DuplicateEntry()
+ else:
+ raise errors2.DatabaseError(desc=desc,info=info)
+ except _ldap.INSUFFICIENT_ACCESS, e:
+ raise errors2.ACIError(info=info)
+ except _ldap.NO_SUCH_ATTRIBUTE:
+ # this is raised when a 'delete' attribute isn't found.
+ # it indicates the previous attribute was removed by another
+ # update, making the oldentry stale.
+ raise errors2.MidairCollision()
+ except _ldap.ADMINLIMIT_EXCEEDED, e:
+ raise errors2.LimitsExceeded()
+ except _ldap.SIZELIMIT_EXCEEDED, e:
+ raise errors2.LimitsExceeded()
+ except _ldap.TIMELIMIT_EXCEEDED, e:
+ raise errors2.LimitsExceeded()
+ except _ldap.LDAPError, e:
+ raise errors2.DatabaseError(desc=desc,info=info)
+
def create_connection(self, host=None, port=None, ccache=None,
bind_dn='', bind_pw='', debug_level=255,
tls_cacertfile=None, tls_certfile=None, tls_keyfile=None):
@@ -291,15 +336,8 @@ class ldap2(CrudBackend):
# pass arguments to python-ldap
try:
self.conn.add_s(dn, list(entry_attrs_copy.iteritems()))
- except _ldap.ALREADY_EXISTS, e:
- raise errors2.DuplicateEntry
- except _ldap.CONSTRAINT_VIOLATION, e:
- if e.args[0].get('info', '') == _uniqueness_plugin_error:
- raise errors2.DuplicateEntry
- else:
- raise errors.DatabaseError, e
except _ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ self.__handle_errors(e, **{})
# generating filters for find_entry
# some examples:
@@ -403,7 +441,7 @@ class ldap2(CrudBackend):
_ldap.SIZELIMIT_EXCEEDED), e:
raise e
except _ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ self.__handle_errors(e, **{})
if not res:
raise errors2.NotFound()
@@ -450,7 +488,7 @@ class ldap2(CrudBackend):
try:
self.conn.rename_s(dn, new_rdn, delold=int(del_old))
except _ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ self.__handle_errors(e, **{})
def _generate_modlist(self, dn, entry_attrs):
# get original entry
@@ -500,15 +538,13 @@ class ldap2(CrudBackend):
# generate modlist
modlist = self._generate_modlist(dn, entry_attrs_copy)
if not modlist:
- raise errors.EmptyModlist
+ raise errors2.EmptyModlist()
# pass arguments to python-ldap
try:
self.conn.modify_s(dn, modlist)
- except _ldap.NO_SUCH_ATTRIBUTE:
- raise errors.MidairCollision
except _ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ self.__handle_errors(e, **{})
def delete_entry(self, dn):
"""Delete entry."""
@@ -519,10 +555,8 @@ class ldap2(CrudBackend):
# pass arguments to python-ldap
try:
self.conn.delete_s(dn)
- except _ldap.INSUFFICIENT_ACCESS, e:
- raise errors.InsuficientAccess, e
except _ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ self.__handle_errors(e, **{})
def modify_password(self, dn, old_pass, new_pass):
"""Set user password."""
@@ -536,7 +570,7 @@ class ldap2(CrudBackend):
try:
self.passwd_s(dn, odl_pass, new_pass)
except _ldap.LDAPError, e:
- raise errors.DatabaseError, e
+ self.__handle_errors(e, **{})
def add_entry_to_group(self, dn, group_dn, member_attr='member'):
"""Add entry to group."""
@@ -545,7 +579,7 @@ class ldap2(CrudBackend):
group_dn = self.normalize_dn(group_dn)
# check if we're not trying to add group into itself
if dn == group_dn:
- raise errors.SameGroupError
+ raise errors2.SameGroupError()
# check if the entry exists
(dn, entry_attrs) = self.get_entry(dn, ['objectClass'])
@@ -575,7 +609,7 @@ class ldap2(CrudBackend):
try:
members.remove(dn)
except ValueError:
- raise errors.NotGroupMember
+ raise errors2.NotGroupMember()
group_entry_attrs[member_attr] = members
# update group entry
@@ -592,11 +626,11 @@ class ldap2(CrudBackend):
account_lock_attr = account_lock_attr[0].lower()
if active:
if account_lock_attr == 'false':
- raise errors.AlreadyActiveError
+ raise errors2.AlreadyActive()
else:
if account_lock_attr == 'true':
- raise errors.AlreadyInactiveError
-
+ raise errors2.AlreadyInactive()
+
# check if nsAccountLock attribute is in the entry itself
is_member = False
member_of_attr = entry_attrs.get('memberOf', [])
@@ -605,7 +639,7 @@ class ldap2(CrudBackend):
is_member = True
break
if not is_member and entry_attrs.has_key('nsAccountLock'):
- raise errors.HasNSAccountLock
+ raise errors2.HasNSAccountLock()
activated_filter = '(cn=activated)'
inactivated_filter = '(cn=inactivated)'
@@ -619,7 +653,7 @@ class ldap2(CrudBackend):
(group_dn, group_entry_attrs) = entries[0]
try:
self.remove_entry_from_group(dn, group_dn)
- except errors.NotGroupMember:
+ except errors2.NotGroupMember:
pass
# add the entry to the activated/inactivated group if necessary
@@ -638,11 +672,11 @@ class ldap2(CrudBackend):
(group_dn, group_entry_attrs) = entries[0]
try:
self.add_entry_to_group(dn, group_dn)
- except errors.EmptyModlist:
+ except errors2.EmptyModlist:
if active:
- raise errors.AlreadyActiveError
+ raise errors2.AlreadyActive()
else:
- raise errors.AlreadyInactiveError
+ raise errors2.AlreadyInactive()
def activate_entry(self, dn):
"""Mark entry active."""
diff --git a/ipaserver/servercore.py b/ipaserver/servercore.py
index bf3b457f..ee0e518d 100644
--- a/ipaserver/servercore.py
+++ b/ipaserver/servercore.py
@@ -23,7 +23,7 @@ import re
from ipalib.request import context
from ipaserver import ipaldap
import ipautil
-from ipalib import errors, errors2
+from ipalib import errors2
from ipalib import api
def convert_entry(ent):
@@ -341,16 +341,16 @@ def mark_entry_active (dn):
if entry.get('nsaccountlock', 'false').lower() == "false":
api.log.debug("IPA: already active")
- raise errors.AlreadyActiveError
+ raise errors2.AlreadyActive()
if has_nsaccountlock(dn):
api.log.debug("IPA: appears to have the nsaccountlock attribute")
- raise errors.HasNSAccountLock
+ raise errors2.HasNSAccountLock()
group = get_entry_by_cn("inactivated", None)
try:
remove_member_from_group(entry.get('dn'), group.get('dn'))
- except errors.NotGroupMember:
+ except errors2.NotGroupMember:
# Perhaps the user is there as a result of group membership
pass
@@ -377,18 +377,18 @@ def mark_entry_inactive (dn):
if entry.get('nsaccountlock', 'false').lower() == "true":
api.log.debug("IPA: already marked as inactive")
- raise errors.AlreadyInactiveError
+ raise errors2.AlreadyInactive()
if has_nsaccountlock(dn):
api.log.debug("IPA: appears to have the nsaccountlock attribute")
- raise errors.HasNSAccountLock
+ raise errors2.HasNSAccountLock()
# First see if they are in the activated group as this will override
# the our inactivation.
group = get_entry_by_cn("activated", None)
try:
remove_member_from_group(dn, group.get('dn'))
- except errors.NotGroupMember:
+ except errors2.NotGroupMember:
# this is fine, they may not be explicitly in this group
pass
@@ -405,7 +405,7 @@ def add_member_to_group(member_dn, group_dn, memberattr='member'):
api.log.info("IPA: add_member_to_group '%s' to '%s'" % (member_dn, group_dn))
if member_dn.lower() == group_dn.lower():
# You can't add a group to itself
- raise errors.SameGroupError
+ raise errors2.RecursiveGroup()
group = get_entry_by_dn(group_dn, None)
if group is None:
@@ -423,10 +423,7 @@ def add_member_to_group(member_dn, group_dn, memberattr='member'):
members.append(member_dn)
group[memberattr] = members
- try:
- return update_entry(group)
- except errors.EmptyModlist:
- raise
+ return update_entry(group)
def remove_member_from_group(member_dn, group_dn, memberattr='member'):
"""Remove a member_dn from an existing group."""
@@ -444,7 +441,7 @@ def remove_member_from_group(member_dn, group_dn, memberattr='member'):
members = group.get(memberattr, False)
if not members:
- raise errors.NotGroupMember
+ raise errors2.NotGroupMember()
if isinstance(members,basestring):
members = [members]
@@ -453,15 +450,10 @@ def remove_member_from_group(member_dn, group_dn, memberattr='member'):
try:
members.remove(member_dn)
except ValueError:
- # member is not in the group
- # FIXME: raise more specific error?
- raise errors.NotGroupMember
+ raise errors2.NotGroupMember()
except Exception, e:
raise e
group[memberattr] = members
- try:
- return update_entry(group)
- except errors.EmptyModlist:
- raise
+ return update_entry(group)
diff --git a/tests/test_ipalib/test_errors.py b/tests/test_ipalib/test_errors.py
deleted file mode 100644
index f1dd5dc8..00000000
--- a/tests/test_ipalib/test_errors.py
+++ /dev/null
@@ -1,289 +0,0 @@
-# Authors:
-# Jason Gerard DeRose <jderose@redhat.com>
-#
-# Copyright (C) 2008 Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; version 2 only
-#
-# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-"""
-Test the `ipalib.errors` module.
-"""
-
-from tests.util import raises, ClassChecker
-from ipalib import errors
-
-
-type_format = '%s: need a %r; got %r'
-
-
-def check_TypeError(f, value, type_, name, **kw):
- e = raises(TypeError, f, value, type_, name, **kw)
- assert e.value is value
- assert e.type is type_
- assert e.name is name
- assert str(e) == type_format % (name, type_, value)
-
-
-def test_raise_TypeError():
- """
- Test the `ipalib.errors.raise_TypeError` function.
- """
- f = errors.raise_TypeError
- value = 'Hello.'
- type_ = unicode
- name = 'message'
-
- check_TypeError(f, value, type_, name)
-
- # name not an str
- fail_name = 42
- e = raises(AssertionError, f, value, type_, fail_name)
- assert str(e) == type_format % ('name', str, fail_name), str(e)
-
- # type_ not a type:
- fail_type = unicode()
- e = raises(AssertionError, f, value, fail_type, name)
- assert str(e) == type_format % ('type_', type, fail_type)
-
- # type(value) is type_:
- fail_value = u'How are you?'
- e = raises(AssertionError, f, fail_value, type_, name)
- assert str(e) == 'value: %r is a %r' % (fail_value, type_)
-
-
-def test_check_type():
- """
- Test the `ipalib.errors.check_type` function.
- """
- f = errors.check_type
- value = 'How are you?'
- type_ = str
- name = 'greeting'
-
- # Should pass:
- assert value is f(value, type_, name)
- assert None is f(None, type_, name, allow_none=True)
-
- # Should raise TypeError
- check_TypeError(f, None, type_, name)
- check_TypeError(f, value, basestring, name)
- check_TypeError(f, value, unicode, name)
-
- # name not an str
- fail_name = unicode(name)
- e = raises(AssertionError, f, value, type_, fail_name)
- assert str(e) == type_format % ('name', str, fail_name)
-
- # type_ not a type:
- fail_type = 42
- e = raises(AssertionError, f, value, fail_type, name)
- assert str(e) == type_format % ('type_', type, fail_type)
-
- # allow_none not a bool:
- fail_bool = 0
- e = raises(AssertionError, f, value, type_, name, allow_none=fail_bool)
- assert str(e) == type_format % ('allow_none', bool, fail_bool)
-
-
-def test_check_isinstance():
- """
- Test the `ipalib.errors.check_isinstance` function.
- """
- f = errors.check_isinstance
- value = 'How are you?'
- type_ = str
- name = 'greeting'
-
- # Should pass:
- assert value is f(value, type_, name)
- assert value is f(value, basestring, name)
- assert None is f(None, type_, name, allow_none=True)
-
- # Should raise TypeError
- check_TypeError(f, None, type_, name)
- check_TypeError(f, value, unicode, name)
-
- # name not an str
- fail_name = unicode(name)
- e = raises(AssertionError, f, value, type_, fail_name)
- assert str(e) == type_format % ('name', str, fail_name)
-
- # type_ not a type:
- fail_type = 42
- e = raises(AssertionError, f, value, fail_type, name)
- assert str(e) == type_format % ('type_', type, fail_type)
-
- # allow_none not a bool:
- fail_bool = 0
- e = raises(AssertionError, f, value, type_, name, allow_none=fail_bool)
- assert str(e) == type_format % ('allow_none', bool, fail_bool)
-
-
-class test_IPAError(ClassChecker):
- """
- Test the `ipalib.errors.IPAError` exception.
- """
- _cls = errors.IPAError
-
- def test_class(self):
- """
- Test the `ipalib.errors.IPAError` exception.
- """
- assert self.cls.__bases__ == (StandardError,)
-
- def test_init(self):
- """
- Test the `ipalib.errors.IPAError.__init__` method.
- """
- args = ('one fish', 'two fish')
- e = self.cls(*args)
- assert e.args == args
- assert self.cls().args == tuple()
-
- def test_str(self):
- """
- Test the `ipalib.errors.IPAError.__str__` method.
- """
- f = 'The %s color is %s.'
- class custom_error(self.cls):
- format = f
- for args in [('sexiest', 'red'), ('most-batman-like', 'black')]:
- e = custom_error(*args)
- assert e.args == args
- assert str(e) == f % args
-
-
-class test_ValidationError(ClassChecker):
- """
- Test the `ipalib.errors.ValidationError` exception.
- """
- _cls = errors.ValidationError
-
- def test_class(self):
- """
- Test the `ipalib.errors.ValidationError` exception.
- """
- assert self.cls.__bases__ == (errors.IPAError,)
-
- def test_init(self):
- """
- Test the `ipalib.errors.ValidationError.__init__` method.
- """
- name = 'login'
- value = 'Whatever'
- error = 'Must be lowercase.'
- for index in (None, 3):
- e = self.cls(name, value, error, index=index)
- assert e.name is name
- assert e.value is value
- assert e.error is error
- assert e.index is index
- assert str(e) == 'invalid %r value %r: %s' % (name, value, error)
- # Check that index default is None:
- assert self.cls(name, value, error).index is None
- # Check non str name raises AssertionError:
- raises(AssertionError, self.cls, unicode(name), value, error)
- # Check non int index raises AssertionError:
- raises(AssertionError, self.cls, name, value, error, index=5.0)
- # Check negative index raises AssertionError:
- raises(AssertionError, self.cls, name, value, error, index=-2)
-
-
-class test_ConversionError(ClassChecker):
- """
- Test the `ipalib.errors.ConversionError` exception.
- """
- _cls = errors.ConversionError
-
- def test_class(self):
- """
- Test the `ipalib.errors.ConversionError` exception.
- """
- assert self.cls.__bases__ == (errors.ValidationError,)
-
- def test_init(self):
- """
- Test the `ipalib.errors.ConversionError.__init__` method.
- """
- name = 'some_arg'
- value = '42.0'
- class type_(object):
- conversion_error = 'Not an integer'
- for index in (None, 7):
- e = self.cls(name, value, type_, index=index)
- assert e.name is name
- assert e.value is value
- assert e.type is type_
- assert e.error is type_.conversion_error
- assert e.index is index
- assert str(e) == 'invalid %r value %r: %s' % (name, value,
- type_.conversion_error)
- # Check that index default is None:
- assert self.cls(name, value, type_).index is None
-
-
-class test_RuleError(ClassChecker):
- """
- Test the `ipalib.errors.RuleError` exception.
- """
- _cls = errors.RuleError
-
- def test_class(self):
- """
- Test the `ipalib.errors.RuleError` exception.
- """
- assert self.cls.__bases__ == (errors.ValidationError,)
-
- def test_init(self):
- """
- Test the `ipalib.errors.RuleError.__init__` method.
- """
- name = 'whatever'
- value = 'The smallest weird number.'
- def my_rule(value):
- return 'Value is bad.'
- error = my_rule(value)
- for index in (None, 42):
- e = self.cls(name, value, error, my_rule, index=index)
- assert e.name is name
- assert e.value is value
- assert e.error is error
- assert e.rule is my_rule
- # Check that index default is None:
- assert self.cls(name, value, error, my_rule).index is None
-
-
-class test_RequirementError(ClassChecker):
- """
- Test the `ipalib.errors.RequirementError` exception.
- """
- _cls = errors.RequirementError
-
- def test_class(self):
- """
- Test the `ipalib.errors.RequirementError` exception.
- """
- assert self.cls.__bases__ == (errors.ValidationError,)
-
- def test_init(self):
- """
- Test the `ipalib.errors.RequirementError.__init__` method.
- """
- name = 'givenname'
- e = self.cls(name)
- assert e.name is name
- assert e.value is None
- assert e.error == 'Required'
- assert e.index is None
diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py
index 7be94c4f..74437041 100644
--- a/tests/test_ipalib/test_frontend.py
+++ b/tests/test_ipalib/test_frontend.py
@@ -26,7 +26,7 @@ from tests.util import check_TypeError, ClassChecker, create_test_api
from tests.util import assert_equal
from ipalib.constants import TYPE_ERROR
from ipalib.base import NameSpace
-from ipalib import frontend, backend, plugable, errors2, errors, parameters, config
+from ipalib import frontend, backend, plugable, errors2, parameters, config
def test_RULE_FLAG():
assert frontend.RULE_FLAG == 'validation_rule'
diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py
index c6c84fa1..4f54d3f7 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, errors2
+from ipalib import plugable, errors2
class test_SetProxy(ClassChecker):
diff --git a/tests/test_xmlrpc/xmlrpc_test.py b/tests/test_xmlrpc/xmlrpc_test.py
index 8e626600..7ff43c74 100644
--- a/tests/test_xmlrpc/xmlrpc_test.py
+++ b/tests/test_xmlrpc/xmlrpc_test.py
@@ -26,7 +26,6 @@ import socket
import nose
from ipalib import api, request
from ipalib import errors2
-from ipalib import errors
# Initialize the API. We do this here so that one can run the tests
# individually instead of at the top-level. If API.bootstrap()