[enh] Manage extra parameters inside the parser to add 'required' parameter

This commit is contained in:
Jérôme Lebleu 2014-06-02 17:07:05 +02:00
parent 790eaf0783
commit 203c8fb511
3 changed files with 88 additions and 31 deletions

View file

@ -14,6 +14,7 @@
"ldap_operation_error" : "An error occured during LDAP operation", "ldap_operation_error" : "An error occured during LDAP operation",
"ldap_attribute_already_exists" : "Attribute already exists: '{:s}={:s}'", "ldap_attribute_already_exists" : "Attribute already exists: '{:s}={:s}'",
"argument_required" : "Argument {:s} is required",
"password" : "Password", "password" : "Password",
"invalid_password" : "Invalid password", "invalid_password" : "Invalid password",
"confirm" : "Confirm", "confirm" : "Confirm",

View file

@ -14,6 +14,7 @@
"ldap_operation_error" : "Une erreur est survenue lors de l'opération LDAP", "ldap_operation_error" : "Une erreur est survenue lors de l'opération LDAP",
"ldap_attribute_already_exists" : "L'attribut existe déjà : '{:s}={:s}'", "ldap_attribute_already_exists" : "L'attribut existe déjà : '{:s}={:s}'",
"argument_required" : "L'argument {:s} est requis",
"password" : "Mot de passe", "password" : "Mot de passe",
"invalid_password" : "Mot de passe incorrect", "invalid_password" : "Mot de passe incorrect",
"confirm" : "Confirmez", "confirm" : "Confirmez",

View file

@ -11,6 +11,9 @@ from collections import OrderedDict
from moulinette.core import (MoulinetteError, MoulinetteLock) from moulinette.core import (MoulinetteError, MoulinetteLock)
from moulinette.interfaces import BaseActionsMapParser from moulinette.interfaces import BaseActionsMapParser
GLOBAL_ARGUMENT = '_global'
## Extra parameters ---------------------------------------------------- ## Extra parameters ----------------------------------------------------
# Extra parameters definition # Extra parameters definition
@ -156,12 +159,34 @@ class PatternParameter(_ExtraParameter):
raise TypeError("Invalid type of 'pattern' extra parameter for '%s' argument" % arg_name) raise TypeError("Invalid type of 'pattern' extra parameter for '%s' argument" % arg_name)
return value return value
class RequiredParameter(_ExtraParameter):
"""
Check if a required argument is defined or not.
The value of this parameter must be a boolean which is set to False by
default.
"""
name = 'required'
def __call__(self, required, arg_name, arg_value):
if required and (arg_value is None or arg_value == ''):
raise MoulinetteError(errno.EINVAL, m18n.g('argument_required',
arg_name))
return arg_value
@staticmethod
def validate(value, arg_name):
if not isinstance(value, bool):
raise TypeError("Invalid type of 'required' extra parameter for '%s' argument" % arg_name)
return value
""" """
The list of available extra parameters classes. It will keep to this list The list of available extra parameters classes. It will keep to this list
order on argument parsing. order on argument parsing.
""" """
extraparameters_list = [AskParameter, PasswordParameter, PatternParameter] extraparameters_list = [ AskParameter, PasswordParameter, RequiredParameter,
PatternParameter ]
# Extra parameters argument Parser # Extra parameters argument Parser
@ -176,6 +201,7 @@ class ExtraArgumentParser(object):
def __init__(self, iface): def __init__(self, iface):
self.iface = iface self.iface = iface
self.extra = OrderedDict() self.extra = OrderedDict()
self._extra_params = { GLOBAL_ARGUMENT: {} }
# Append available extra parameters for the current interface # Append available extra parameters for the current interface
for klass in extraparameters_list: for klass in extraparameters_list:
@ -204,34 +230,62 @@ class ExtraArgumentParser(object):
return parameters return parameters
def parse(self, arg_name, arg_value, parameters): def add_argument(self, tid, arg_name, parameters, validate=True):
""" """
Parse argument with extra parameters Add extra parameters to apply on an action argument
Keyword arguments: Keyword arguments:
- tid -- The tuple identifier of the action or GLOBAL_ARGUMENT
for global extra parameters
- arg_name -- The argument name - arg_name -- The argument name
- arg_value -- The argument value
- parameters -- A dict of extra parameters with their values - parameters -- A dict of extra parameters with their values
- validate -- False to not validate extra parameters values
""" """
# Iterate over available parameters if validate:
for p, klass in self.extra.items(): parameters = self.validate(arg_name, parameters)
if p not in parameters.keys(): try:
self._extra_params[tid][arg_name] = parameters
except KeyError:
self._extra_params[tid] = { arg_name: parameters }
def parse_args(self, tid, args):
"""
Parse arguments for an action with extra parameters
Keyword arguments:
- tid -- The tuple identifier of the action
- args -- A dict of argument name associated to their value
"""
extra_args = self._extra_params.get(GLOBAL_ARGUMENT, {})
extra_args.update(self._extra_params.get(tid, {}))
# Iterate over action arguments with extra parameters
for arg_name, extra_params in extra_args.items():
# Iterate over available extra parameters
for p, cls in self.extra.items():
try:
extra_value = extra_params[p]
except KeyError:
continue continue
arg_value = args.get(arg_name, None)
# Initialize the extra parser # Initialize the extra parser
parser = klass(self.iface) parser = cls(self.iface)
# Parse the argument # Parse the argument
if isinstance(arg_value, list): if isinstance(arg_value, list):
for v in arg_value: for v in arg_value:
r = parser(parameters[p], arg_name, v) r = parser(extra_value, arg_name, v)
if r not in arg_value: if r not in arg_value:
arg_value.append(r) arg_value.append(r)
else: else:
arg_value = parser(parameters[p], arg_name, arg_value) arg_value = parser(extra_value, arg_name, arg_value)
return arg_value # Update argument value
args[arg_name] = arg_value
return args
## Main class ---------------------------------------------------------- ## Main class ----------------------------------------------------------
@ -328,11 +382,13 @@ class ActionsMap(object):
""" """
# Parse arguments # Parse arguments
arguments = vars(self.parser.parse_args(args, **kwargs)) arguments = vars(self.parser.parse_args(args, **kwargs))
for an, parameters in (arguments.pop('_extra', {})).items():
arguments[an] = self.extraparser.parse(an, arguments[an], parameters) # Retrieve tid and parse arguments with extra parameters
tid = arguments.pop('_tid')
arguments = self.extraparser.parse_args(tid, arguments)
# Retrieve action information # Retrieve action information
namespace, category, action = arguments.pop('_tid') namespace, category, action = tid
func_name = '%s_%s' % (category, action.replace('-', '_')) func_name = '%s_%s' % (category, action.replace('-', '_'))
# Lock the moulinette for the namespace # Lock the moulinette for the namespace
@ -414,13 +470,12 @@ class ActionsMap(object):
""" """
## Get extra parameters ## Get extra parameters
if not self.use_cache: if not self.use_cache:
_get_extra = lambda an, e: self.extraparser.validate(an, e) validate_extra = True
else: else:
_get_extra = lambda an, e: e validate_extra = False
## Add arguments to the parser ## Add arguments to the parser
def _add_arguments(parser, arguments): def _add_arguments(tid, parser, arguments):
extras = {}
for argn, argp in arguments.items(): for argn, argp in arguments.items():
names = top_parser.format_arg_names(argn, names = top_parser.format_arg_names(argn,
argp.pop('full', None)) argp.pop('full', None))
@ -430,12 +485,11 @@ class ActionsMap(object):
try: try:
extra = argp.pop('extra') extra = argp.pop('extra')
arg_dest = (parser.add_argument(*names, **argp)).dest arg_dest = (parser.add_argument(*names, **argp)).dest
extras[arg_dest] = _get_extra(arg_dest, extra) self.extraparser.add_argument(tid, arg_dest, extra,
validate_extra)
except KeyError: except KeyError:
# No extra parameters # No extra parameters
parser.add_argument(*names, **argp) parser.add_argument(*names, **argp)
if extras:
parser.set_defaults(_extra=extras)
# Instantiate parser # Instantiate parser
top_parser = self._parser_class() top_parser = self._parser_class()
@ -460,7 +514,8 @@ class ActionsMap(object):
pass pass
else: else:
# Add arguments # Add arguments
_add_arguments(parser, _global['arguments']) _add_arguments(GLOBAL_ARGUMENT, parser,
_global['arguments'])
# -- Parse categories # -- Parse categories
for cn, cp in actionsmap.items(): for cn, cp in actionsmap.items():
@ -497,7 +552,7 @@ class ActionsMap(object):
else: else:
# Store action identifier and add arguments # Store action identifier and add arguments
parser.set_defaults(_tid=tid) parser.set_defaults(_tid=tid)
_add_arguments(parser, args) _add_arguments(tid, parser, args)
_set_conf(cat_parser) _set_conf(cat_parser)
return top_parser return top_parser