mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Added Command.args_options_2_params() method and its unit tests
This commit is contained in:
parent
4febb4dd14
commit
ae39dece13
@ -463,25 +463,75 @@ class BinaryEncodingError(InvocationError):
|
||||
errno = 3002
|
||||
|
||||
|
||||
class ArgumentError(InvocationError):
|
||||
class ZeroArgumentError(InvocationError):
|
||||
"""
|
||||
**3003** Raised when a command is called with wrong number of arguments.
|
||||
**3003** Raised when a command is called with arguments but takes none.
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise ZeroArgumentError(name='ping')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ZeroArgumentError: command 'ping' takes no arguments
|
||||
"""
|
||||
|
||||
errno = 3003
|
||||
format = _('command %(name)r takes no arguments')
|
||||
|
||||
|
||||
class OptionError(InvocationError):
|
||||
class MaxArgumentError(InvocationError):
|
||||
"""
|
||||
**3004** Raised when a command is called with unknown options.
|
||||
**3004** Raised when a command is called with too many arguments.
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise MaxArgumentError(name='user_add', count=2)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
MaxArgumentError: command 'user_add' takes at most 2 arguments
|
||||
"""
|
||||
|
||||
errno = 3004
|
||||
|
||||
def __init__(self, message=None, **kw):
|
||||
if message is None:
|
||||
format = ungettext(
|
||||
'command %(name)r takes at most %(count)d argument',
|
||||
'command %(name)r takes at most %(count)d arguments',
|
||||
kw['count']
|
||||
)
|
||||
else:
|
||||
format = None
|
||||
InvocationError.__init__(self, format, message, **kw)
|
||||
|
||||
|
||||
class OptionError(InvocationError):
|
||||
"""
|
||||
**3005** Raised when a command is called with unknown options.
|
||||
"""
|
||||
|
||||
errno = 3005
|
||||
|
||||
|
||||
class OverlapError(InvocationError):
|
||||
"""
|
||||
**3006** Raised when arguments and options overlap.
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise OverlapError(names=['givenname', 'login'])
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
OverlapError: overlapping arguments and options: ['givenname', 'login']
|
||||
"""
|
||||
|
||||
errno = 3006
|
||||
format = _('overlapping arguments and options: %(names)r')
|
||||
|
||||
|
||||
class RequirementError(InvocationError):
|
||||
"""
|
||||
**3005** Raised when a required parameter is not provided.
|
||||
**3007** Raised when a required parameter is not provided.
|
||||
|
||||
For example:
|
||||
|
||||
@ -491,13 +541,13 @@ class RequirementError(InvocationError):
|
||||
RequirementError: 'givenname' is required
|
||||
"""
|
||||
|
||||
errno = 3005
|
||||
errno = 3007
|
||||
format = _('%(name)r is required')
|
||||
|
||||
|
||||
class ConversionError(InvocationError):
|
||||
"""
|
||||
**3006** Raised when parameter value can't be converted to correct type.
|
||||
**3008** Raised when parameter value can't be converted to correct type.
|
||||
|
||||
For example:
|
||||
|
||||
@ -507,13 +557,13 @@ class ConversionError(InvocationError):
|
||||
ConversionError: invalid 'age': must be an integer
|
||||
"""
|
||||
|
||||
errno = 3006
|
||||
errno = 3008
|
||||
format = _('invalid %(name)r: %(error)s')
|
||||
|
||||
|
||||
class ValidationError(InvocationError):
|
||||
"""
|
||||
**3007** Raised when a parameter value fails a validation rule.
|
||||
**3009** Raised when a parameter value fails a validation rule.
|
||||
|
||||
For example:
|
||||
|
||||
@ -523,7 +573,7 @@ class ValidationError(InvocationError):
|
||||
ValidationError: invalid 'sn': can be at most 128 characters
|
||||
"""
|
||||
|
||||
errno = 3007
|
||||
errno = 3009
|
||||
format = _('invalid %(name)r: %(error)s')
|
||||
|
||||
|
||||
|
@ -30,6 +30,9 @@ from errors import check_type, check_isinstance, raise_TypeError
|
||||
from parameters import create_param, Param, Str, Flag
|
||||
from util import make_repr
|
||||
|
||||
from errors2 import ZeroArgumentError, MaxArgumentError, OverlapError
|
||||
from constants import TYPE_ERROR
|
||||
|
||||
|
||||
RULE_FLAG = 'validation_rule'
|
||||
|
||||
@ -77,6 +80,7 @@ class Command(plugable.Plugin):
|
||||
'params',
|
||||
'args_to_kw',
|
||||
'params_2_args_options',
|
||||
'args_options_2_params',
|
||||
'output_for_cli',
|
||||
))
|
||||
takes_options = tuple()
|
||||
@ -140,19 +144,57 @@ class Command(plugable.Plugin):
|
||||
else:
|
||||
break
|
||||
|
||||
def args_options_2_params(self, args, options):
|
||||
pass
|
||||
def args_options_2_params(self, *args, **options):
|
||||
"""
|
||||
Merge (args, options) into params.
|
||||
"""
|
||||
if self.max_args is not None and len(args) > self.max_args:
|
||||
if self.max_args == 0:
|
||||
raise ZeroArgumentError(name=self.name)
|
||||
raise MaxArgumentError(name=self.name, count=self.max_args)
|
||||
params = dict(self.__options_2_params(options))
|
||||
if len(args) > 0:
|
||||
arg_kw = dict(self.__args_2_params(args))
|
||||
intersection = set(arg_kw).intersection(params)
|
||||
if len(intersection) > 0:
|
||||
raise OverlapError(names=sorted(intersection))
|
||||
params.update(arg_kw)
|
||||
return params
|
||||
|
||||
def __args_2_params(self, values):
|
||||
multivalue = False
|
||||
for (i, arg) in enumerate(self.args()):
|
||||
assert not multivalue
|
||||
if len(values) > i:
|
||||
if arg.multivalue:
|
||||
multivalue = True
|
||||
if len(values) == i + 1 and type(values[i]) in (list, tuple):
|
||||
yield (arg.name, values[i])
|
||||
else:
|
||||
yield (arg.name, values[i:])
|
||||
else:
|
||||
yield (arg.name, values[i])
|
||||
else:
|
||||
break
|
||||
|
||||
def __options_2_params(self, options):
|
||||
for name in self.params:
|
||||
if name in options:
|
||||
yield (name, options[name])
|
||||
|
||||
def params_2_args_options(self, params):
|
||||
"""
|
||||
Split params into (args, kw).
|
||||
"""
|
||||
args = tuple(params.get(name, None) for name in self.args)
|
||||
options = dict(
|
||||
(name, params.get(name, None)) for name in self.options
|
||||
)
|
||||
options = dict(self.__params_2_options(params))
|
||||
return (args, options)
|
||||
|
||||
def __params_2_options(self, params):
|
||||
for name in self.options:
|
||||
if name in params:
|
||||
yield(name, params[name])
|
||||
|
||||
def normalize(self, **kw):
|
||||
"""
|
||||
Return a dictionary of normalized values.
|
||||
|
@ -231,6 +231,7 @@ class Param(ReadOnly):
|
||||
('autofill', bool, False),
|
||||
('query', bool, False),
|
||||
('attribute', bool, False),
|
||||
('limit_to', frozenset, None),
|
||||
('flags', frozenset, frozenset()),
|
||||
|
||||
# The 'default' kwarg gets appended in Param.__init__():
|
||||
|
@ -329,14 +329,61 @@ class test_Command(ClassChecker):
|
||||
e = raises(errors.ArgumentError, o.args_to_kw, 1, 2, 3)
|
||||
assert str(e) == 'example takes at most 2 arguments'
|
||||
|
||||
def test_args_options_2_params(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.args_options_2_params` method.
|
||||
"""
|
||||
assert 'args_options_2_params' in self.cls.__public__ # Public
|
||||
|
||||
# Test that ZeroArgumentError is raised:
|
||||
o = self.get_instance()
|
||||
e = raises(errors2.ZeroArgumentError, o.args_options_2_params, 1)
|
||||
assert e.name == 'example'
|
||||
|
||||
# Test that MaxArgumentError is raised (count=1)
|
||||
o = self.get_instance(args=('one?',))
|
||||
e = raises(errors2.MaxArgumentError, o.args_options_2_params, 1, 2)
|
||||
assert e.name == 'example'
|
||||
assert e.count == 1
|
||||
assert str(e) == "command 'example' takes at most 1 argument"
|
||||
|
||||
# Test that MaxArgumentError is raised (count=2)
|
||||
o = self.get_instance(args=('one', 'two?'))
|
||||
e = raises(errors2.MaxArgumentError, o.args_options_2_params, 1, 2, 3)
|
||||
assert e.name == 'example'
|
||||
assert e.count == 2
|
||||
assert str(e) == "command 'example' takes at most 2 arguments"
|
||||
|
||||
# Test that OverlapError is raised:
|
||||
o = self.get_instance(args=('one', 'two'), options=('three', 'four'))
|
||||
e = raises(errors2.OverlapError, o.args_options_2_params,
|
||||
1, 2, three=3, two=2, four=4, one=1)
|
||||
assert e.names == ['one', 'two']
|
||||
|
||||
# Test the permutations:
|
||||
o = self.get_instance(args=('one', 'two*'), options=('three', 'four'))
|
||||
mthd = o.args_options_2_params
|
||||
assert mthd() == dict()
|
||||
assert mthd(1) == dict(one=1)
|
||||
assert mthd(1, 2) == dict(one=1, two=(2,))
|
||||
assert mthd(1, 21, 22, 23) == dict(one=1, two=(21, 22, 23))
|
||||
assert mthd(1, (21, 22, 23)) == dict(one=1, two=(21, 22, 23))
|
||||
assert mthd(three=3, four=4) == dict(three=3, four=4)
|
||||
assert mthd(three=3, four=4, one=1, two=2) == \
|
||||
dict(one=1, two=2, three=3, four=4)
|
||||
assert mthd(1, 21, 22, 23, three=3, four=4) == \
|
||||
dict(one=1, two=(21, 22, 23), three=3, four=4)
|
||||
assert mthd(1, (21, 22, 23), three=3, four=4) == \
|
||||
dict(one=1, two=(21, 22, 23), three=3, four=4)
|
||||
|
||||
def test_params_2_args_options(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.params_2_args_options` method.
|
||||
"""
|
||||
assert 'params_2_args_options' in self.cls.__public__ # Public
|
||||
o = self.get_instance(args=['one'], options=['two'])
|
||||
assert o.params_2_args_options({}) == ((None,), dict(two=None))
|
||||
assert o.params_2_args_options(dict(one=1)) == ((1,), dict(two=None))
|
||||
assert o.params_2_args_options({}) == ((None,), {})
|
||||
assert o.params_2_args_options(dict(one=1)) == ((1,), {})
|
||||
assert o.params_2_args_options(dict(two=2)) == ((None,), dict(two=2))
|
||||
assert o.params_2_args_options(dict(two=2, one=1)) == \
|
||||
((1,), dict(two=2))
|
||||
|
@ -165,6 +165,8 @@ class test_Param(ClassChecker):
|
||||
assert o._get_default is None
|
||||
assert o.autofill is False
|
||||
assert o.query is False
|
||||
assert o.attribute is False
|
||||
assert o.limit_to is None
|
||||
assert o.flags == frozenset()
|
||||
|
||||
# Test that ValueError is raised when a kwarg from a subclass
|
||||
|
@ -221,7 +221,7 @@ class test_xmlclient(PluginTester):
|
||||
'user_add',
|
||||
(rpc.xml_wrap(params),),
|
||||
{},
|
||||
Fault(3005, u"'four' is required"), # RequirementError
|
||||
Fault(3007, u"'four' is required"), # RequirementError
|
||||
),
|
||||
(
|
||||
'user_add',
|
||||
|
Loading…
Reference in New Issue
Block a user