better support type in params
This commit is contained in:
@ -26,7 +26,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
from typing import List, Any
|
||||
|
||||
from .variable import CONVERT_OPTION
|
||||
from .target import TargetAnnotator
|
||||
from .param import ParamAnnotator
|
||||
|
||||
@ -61,6 +60,17 @@ class CheckAnnotator(TargetAnnotator, ParamAnnotator):
|
||||
self.convert_check()
|
||||
del objectspace.space.constraints.check
|
||||
|
||||
def valid_type_validation(self,
|
||||
obj,
|
||||
) -> None:
|
||||
variable_type = None
|
||||
if obj.name == 'valid_enum':
|
||||
for target in obj.target:
|
||||
if variable_type and target.name.type != variable_type:
|
||||
raise Exception('pfff')
|
||||
variable_type = target.name.type
|
||||
return variable_type
|
||||
|
||||
def check_check(self): # pylint: disable=R0912
|
||||
"""valid and manage <check>
|
||||
"""
|
||||
@ -119,7 +129,7 @@ class CheckAnnotator(TargetAnnotator, ParamAnnotator):
|
||||
variable.mandatory = True
|
||||
# build choice
|
||||
variable.values = []
|
||||
variable_type = variable.type
|
||||
variable.ori_type = variable.type
|
||||
variable.type = 'choice'
|
||||
|
||||
has_variable = False
|
||||
@ -129,7 +139,7 @@ class CheckAnnotator(TargetAnnotator, ParamAnnotator):
|
||||
msg = _(f'only one "variable" parameter is allowed for valid_enum '
|
||||
f'of variable "{variable.name}"')
|
||||
raise DictConsistencyError(msg, 5, param.xmlfiles)
|
||||
param_type = variable_type
|
||||
param_type = variable.ori_type
|
||||
if param.type == 'variable':
|
||||
has_variable = True
|
||||
if param.optional is True:
|
||||
@ -141,24 +151,9 @@ class CheckAnnotator(TargetAnnotator, ParamAnnotator):
|
||||
f'of variable "{variable.name}"')
|
||||
raise DictConsistencyError(msg, 6, param.xmlfiles)
|
||||
param_type = 'calculation'
|
||||
value = param.text
|
||||
elif param.type == 'nil':
|
||||
value = None
|
||||
else:
|
||||
if 'type' in vars(param) and variable_type != param.type:
|
||||
msg = _(f'parameter in valid_enum has incompatible type "{param.type}" '
|
||||
f'with type of the variable "{variable.name}" ("{variable_type}")')
|
||||
raise DictConsistencyError(msg, 7, param.xmlfiles)
|
||||
if hasattr(param, 'text'):
|
||||
try:
|
||||
value = CONVERT_OPTION[variable_type].get('func', str)(param.text)
|
||||
except ValueError as err:
|
||||
msg = _(f'unable to change type of a valid_enum entry "{param.text}" '
|
||||
f'is not a valid "{variable_type}" for "{variable.name}"')
|
||||
raise DictConsistencyError(msg, 13, variable.xmlfiles) from err
|
||||
values.append(value)
|
||||
values.append(param.text)
|
||||
choice = self.objectspace.choice(variable.xmlfiles)
|
||||
choice.name = value
|
||||
choice.name = param.text
|
||||
choice.type = param_type
|
||||
variable.values.append(choice)
|
||||
|
||||
@ -166,7 +161,7 @@ class CheckAnnotator(TargetAnnotator, ParamAnnotator):
|
||||
return None
|
||||
|
||||
for target in check.target:
|
||||
self.objectspace.valid_enums[target.name.path] = {'type': variable_type,
|
||||
self.objectspace.valid_enums[target.name.path] = {'type': variable.ori_type,
|
||||
'values': values,
|
||||
'xmlfiles': check.xmlfiles,
|
||||
}
|
||||
|
@ -54,15 +54,22 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
self.target_is_uniq = False
|
||||
self.only_variable = False
|
||||
self.convert_target(self.objectspace.space.constraints.condition)
|
||||
self.check_condition_fallback()
|
||||
self.convert_condition_source()
|
||||
self.convert_param(self.objectspace.space.constraints.condition)
|
||||
self.check_source_target()
|
||||
self.check_condition_fallback()
|
||||
self.convert_xxxlist()
|
||||
self.convert_condition_source()
|
||||
self.check_choice_option_condition()
|
||||
self.remove_condition_with_empty_target()
|
||||
self.convert_condition()
|
||||
|
||||
def valid_type_validation(self,
|
||||
obj,
|
||||
) -> None:
|
||||
if obj.source.type == 'choice':
|
||||
return obj.source.ori_type
|
||||
return obj.source.type
|
||||
|
||||
def convert_auto_freeze(self):
|
||||
"""convert auto_freeze
|
||||
only if FREEZE_AUTOFREEZE_VARIABLE == 'oui' this variable is frozen
|
||||
@ -101,9 +108,9 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
for condition in self.objectspace.space.constraints.condition:
|
||||
for target in condition.target:
|
||||
if target.type == 'variable' and \
|
||||
condition.source in [target.name.name, target.name.path]:
|
||||
condition.source.path == target.name.path:
|
||||
msg = _('target name and source name must be different: '
|
||||
f'{condition.source}')
|
||||
f'{condition.source.path}')
|
||||
raise DictConsistencyError(msg, 11, condition.xmlfiles)
|
||||
|
||||
def check_condition_fallback(self):
|
||||
@ -242,11 +249,12 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
param3 = self.objectspace.param(target.xmlfiles)
|
||||
param3.name = f'condition_{fill.index}'
|
||||
param3.type = 'variable'
|
||||
param3.text = condition.source
|
||||
param3.text = condition.source.path
|
||||
fill.param.append(param3)
|
||||
param4 = self.objectspace.param(target.xmlfiles)
|
||||
param4.name = f'expected_{fill.index}'
|
||||
param4.text = values
|
||||
param4.type = condition.param[0].type
|
||||
fill.param.append(param4)
|
||||
if condition.name != 'disabled_if_in':
|
||||
param5 = self.objectspace.param(target.xmlfiles)
|
||||
@ -314,7 +322,6 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
for condition in self.objectspace.space.constraints.condition:
|
||||
actions = self.get_actions_from_condition(condition.name)
|
||||
for param in condition.param:
|
||||
text = getattr(param, 'text', None)
|
||||
for target in condition.target:
|
||||
leader_or_variable, variables = self._get_family_variables_from_target(target)
|
||||
# if option is already disable, do not apply disable_if_in
|
||||
@ -324,7 +331,7 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
if getattr(leader_or_variable, main_action, False) is True:
|
||||
continue
|
||||
self.build_property(leader_or_variable,
|
||||
text,
|
||||
param,
|
||||
condition,
|
||||
main_action,
|
||||
)
|
||||
@ -336,14 +343,14 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
# other actions are set to the variable or children of family
|
||||
for variable in variables:
|
||||
self.build_property(variable,
|
||||
text,
|
||||
param,
|
||||
condition,
|
||||
action,
|
||||
)
|
||||
|
||||
def build_property(self,
|
||||
obj,
|
||||
text: Any,
|
||||
param: 'self.objectspace.param',
|
||||
condition: 'self.objectspace.condition',
|
||||
action: str,
|
||||
) -> 'self.objectspace.property_':
|
||||
@ -353,7 +360,7 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
prop.type = 'calculation'
|
||||
prop.inverse = condition.name.endswith('_if_not_in')
|
||||
prop.source = condition.source
|
||||
prop.expected = text
|
||||
prop.expected = param
|
||||
prop.name = action
|
||||
if not hasattr(obj, 'properties'):
|
||||
obj.properties = []
|
||||
|
@ -24,11 +24,18 @@ 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
|
||||
"""
|
||||
from .variable import CONVERT_OPTION
|
||||
|
||||
from ..i18n import _
|
||||
from ..error import DictConsistencyError
|
||||
|
||||
|
||||
class ParamAnnotator:
|
||||
def valid_type_validation(self,
|
||||
obj,
|
||||
) -> None:
|
||||
return None
|
||||
|
||||
def convert_param(self, objects) -> None:
|
||||
""" valid and convert param
|
||||
"""
|
||||
@ -36,6 +43,7 @@ class ParamAnnotator:
|
||||
if not hasattr(obj, 'param'):
|
||||
continue
|
||||
param_to_delete = []
|
||||
variable_type = self.valid_type_validation(obj)
|
||||
for param_idx, param in enumerate(obj.param):
|
||||
if param.type == 'suffix':
|
||||
if hasattr(param, 'text'):
|
||||
@ -50,15 +58,18 @@ class ParamAnnotator:
|
||||
if not param.type == 'nil':
|
||||
msg = _(f'"{param.type}" parameter must have a value')
|
||||
raise DictConsistencyError(msg, 27, obj.xmlfiles)
|
||||
param.text = None
|
||||
elif param.type == 'nil':
|
||||
msg = _(f'"{param.type}" parameter must not have a value')
|
||||
raise DictConsistencyError(msg, 40, obj.xmlfiles)
|
||||
if param.type == 'variable':
|
||||
elif param.type == 'variable':
|
||||
try:
|
||||
path, suffix = self.objectspace.paths.get_variable_path(param.text,
|
||||
obj.namespace,
|
||||
)
|
||||
param.text = self.objectspace.paths.get_variable(path)
|
||||
if variable_type and param.text.type != variable_type:
|
||||
raise Exception('pfff', variable_type, param.text.type)
|
||||
if suffix:
|
||||
param.suffix = suffix
|
||||
family_path = self.objectspace.paths.get_variable_family_path(path)
|
||||
@ -69,6 +80,18 @@ class ParamAnnotator:
|
||||
if err.errno != 42 or not param.optional:
|
||||
raise err
|
||||
param_to_delete.append(param_idx)
|
||||
elif variable_type:
|
||||
if 'type' in vars(param) and variable_type != param.type:
|
||||
msg = _(f'parameter has incompatible type "{param.type}" '
|
||||
f'with type "{variable_type}")')
|
||||
raise DictConsistencyError(msg, 7, param.xmlfiles)
|
||||
try:
|
||||
param.text = CONVERT_OPTION[variable_type].get('func', str)(param.text)
|
||||
except ValueError as err:
|
||||
msg = _(f'unable to change type of "{param.text}" '
|
||||
f'is not a valid "{variable_type}"')
|
||||
raise DictConsistencyError(msg, 13, param.xmlfiles) from err
|
||||
param.type = variable_type
|
||||
param_to_delete.sort(reverse=True)
|
||||
for param_idx in param_to_delete:
|
||||
obj.param.pop(param_idx)
|
||||
|
@ -25,6 +25,8 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
|
||||
from ..objspace import convert_boolean
|
||||
|
||||
|
||||
CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
|
||||
'float': dict(opttype="FloatOption", func=float),
|
||||
@ -32,7 +34,7 @@ CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
|
||||
'string': dict(opttype="StrOption"),
|
||||
'password': dict(opttype="PasswordOption"),
|
||||
'mail': dict(opttype="EmailOption"),
|
||||
'boolean': dict(opttype="BoolOption"),
|
||||
'boolean': dict(opttype="BoolOption", func=convert_boolean),
|
||||
'symlink': dict(opttype="SymLinkOption"),
|
||||
'filename': dict(opttype="FilenameOption"),
|
||||
'date': dict(opttype="DateOption"),
|
||||
|
@ -72,11 +72,11 @@
|
||||
<!ATTLIST file group CDATA "root">
|
||||
<!ATTLIST file filelist CDATA #IMPLIED>
|
||||
<!ATTLIST file redefine (True|False) "False">
|
||||
<!ATTLIST file templating (True|False) "True">
|
||||
<!ATTLIST file templating (creole|none) "creole">
|
||||
|
||||
<!ELEMENT override EMPTY>
|
||||
<!ATTLIST override source CDATA #IMPLIED>
|
||||
<!ATTLIST override templating (True|False) "True">
|
||||
<!ATTLIST override templating (creole|none) "creole">
|
||||
|
||||
<!ELEMENT variables ((variable*|family*)*)>
|
||||
|
||||
|
@ -85,6 +85,16 @@ class ObjSpace: # pylint: disable=R0903
|
||||
"""
|
||||
|
||||
|
||||
def convert_boolean(value: str) -> bool:
|
||||
"""Boolean coercion. The Rougail XML may contain srings like `True` or `False`
|
||||
"""
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if value == 'True':
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class RougailObjSpace:
|
||||
"""Rougail ObjectSpace is an object's reflexion of the XML elements
|
||||
"""
|
||||
@ -127,7 +137,7 @@ class RougailObjSpace:
|
||||
# set default value for this attribute
|
||||
default_value = dtd_attr.default_value
|
||||
if dtd_attr.name in self.booleans_attributs:
|
||||
default_value = self.convert_boolean(default_value)
|
||||
default_value = convert_boolean(default_value)
|
||||
attrs[dtd_attr.name] = default_value
|
||||
if dtd_attr.name == 'redefine':
|
||||
# has a redefine attribute, so it's a Redefinable object
|
||||
@ -292,7 +302,7 @@ class RougailObjSpace:
|
||||
# if redefine is set to object, default value is False
|
||||
# otherwise it's always a redefinable object
|
||||
default_redefine = child.tag in FORCE_REDEFINABLES
|
||||
redefine = self.convert_boolean(subspace.get('redefine', default_redefine))
|
||||
redefine = convert_boolean(subspace.get('redefine', default_redefine))
|
||||
if redefine is True:
|
||||
if isinstance(existed_var, self.variable): # pylint: disable=E1101
|
||||
if namespace == Config['variable_namespace']:
|
||||
@ -301,18 +311,18 @@ class RougailObjSpace:
|
||||
redefine_variables.append(space.path + '.' + name)
|
||||
existed_var.xmlfiles.append(xmlfile)
|
||||
return existed_var
|
||||
exists = self.convert_boolean(subspace.get('exists', True))
|
||||
exists = convert_boolean(subspace.get('exists', True))
|
||||
if exists is False:
|
||||
raise SpaceObjShallNotBeUpdated()
|
||||
msg = _(f'"{child.tag}" named "{name}" cannot be re-created in "{xmlfile}", '
|
||||
f'already defined')
|
||||
raise DictConsistencyError(msg, 45, existed_var.xmlfiles)
|
||||
# object deos not exists
|
||||
exists = self.convert_boolean(subspace.get('exists', False))
|
||||
exists = convert_boolean(subspace.get('exists', False))
|
||||
if exists is True:
|
||||
# manage object only if already exists, so cancel
|
||||
raise SpaceObjShallNotBeUpdated()
|
||||
redefine = self.convert_boolean(subspace.get('redefine', False))
|
||||
redefine = convert_boolean(subspace.get('redefine', False))
|
||||
if redefine is True:
|
||||
# cannot redefine an inexistant object
|
||||
msg = _(f'Redefined object: "{name}" does not exist yet')
|
||||
@ -350,16 +360,6 @@ class RougailObjSpace:
|
||||
return children[name]
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def convert_boolean(value: str) -> bool:
|
||||
"""Boolean coercion. The Rougail XML may contain srings like `True` or `False`
|
||||
"""
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if value == 'True':
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_text(self,
|
||||
child,
|
||||
variableobj,
|
||||
@ -379,7 +379,7 @@ class RougailObjSpace:
|
||||
):
|
||||
""" set attributes to an object
|
||||
"""
|
||||
redefine = self.convert_boolean(child.attrib.get('redefine', False))
|
||||
redefine = convert_boolean(child.attrib.get('redefine', False))
|
||||
if redefine and child.tag == 'variable':
|
||||
# delete old values
|
||||
has_value = hasattr(variableobj, 'value')
|
||||
@ -391,7 +391,7 @@ class RougailObjSpace:
|
||||
f' in "{xmlfile}", already defined')
|
||||
raise DictConsistencyError(msg, 48, variableobj.xmlfiles[:-1])
|
||||
if attr in self.booleans_attributs:
|
||||
val = self.convert_boolean(val)
|
||||
val = convert_boolean(val)
|
||||
if attr == 'name' and getattr(variableobj, 'name', None):
|
||||
# do not redefine name
|
||||
continue
|
||||
|
@ -332,7 +332,7 @@ class CreoleTemplateEngine:
|
||||
else:
|
||||
var = None
|
||||
source = join(tmp_dir, filevar['source'])
|
||||
if filevar['templating']:
|
||||
if filevar['templating'] == 'creole':
|
||||
self.process(source,
|
||||
filename,
|
||||
destfilename,
|
||||
|
@ -215,15 +215,8 @@ class Common:
|
||||
"""Populate properties
|
||||
"""
|
||||
option_name = child.source.reflector_object.get()
|
||||
kwargs = f"'condition': ParamOption({option_name}, todict=True), "
|
||||
if child.expected is None or isinstance(child.expected, int):
|
||||
kwargs += f"'expected': ParamValue({child.expected})"
|
||||
elif isinstance(child.expected, str):
|
||||
val = self.convert_str(child.expected)
|
||||
kwargs += f"'expected': ParamValue({val})"
|
||||
else:
|
||||
val = child.expected.reflector_object.get()
|
||||
kwargs += f"'expected': ParamOption({val})"
|
||||
kwargs = (f"'condition': ParamOption({option_name}, todict=True), "
|
||||
f"'expected': {self.populate_param(child.expected)}")
|
||||
if child.inverse:
|
||||
kwargs += ", 'reverse_condition': ParamValue(True)"
|
||||
return (f"Calculation(func.calc_value, Params(ParamValue('{child.name}'), "
|
||||
@ -241,6 +234,40 @@ class Common:
|
||||
value = self.convert_str(value)
|
||||
self.text.append(f"{self.option_name}.impl_set_information('{key}', {value})")
|
||||
|
||||
def populate_param(self,
|
||||
param,
|
||||
):
|
||||
"""Populate variable parameters
|
||||
"""
|
||||
if param.type in ['number', 'boolean', 'nil', 'string']:
|
||||
value = param.text
|
||||
if param.type == 'string' and value is not None:
|
||||
value = self.convert_str(value)
|
||||
return f'ParamValue({value})'
|
||||
if param.type == 'variable':
|
||||
return self.build_option_param(param)
|
||||
if param.type == 'information':
|
||||
return f'ParamInformation("{param.text}", None)'
|
||||
if param.type == 'suffix':
|
||||
return 'ParamSuffix()'
|
||||
raise Exception(f'unknown type {param.type}') # pragma: no cover
|
||||
|
||||
@staticmethod
|
||||
def build_option_param(param,
|
||||
) -> str:
|
||||
"""build variable parameters
|
||||
"""
|
||||
option_name = param.text.reflector_object.get()
|
||||
params = [f'{option_name}']
|
||||
if hasattr(param, 'suffix'):
|
||||
param_type = 'ParamDynOption'
|
||||
params.extend([f"'{param.suffix}'", f'{param.family.reflector_name}'])
|
||||
else:
|
||||
param_type = 'ParamOption'
|
||||
if not param.propertyerror:
|
||||
params.append('notraisepropertyerror=True')
|
||||
return "{}({})".format(param_type, ', '.join(params))
|
||||
|
||||
|
||||
class Variable(Common):
|
||||
"""Manage variable
|
||||
@ -297,7 +324,7 @@ class Variable(Common):
|
||||
function = child.name
|
||||
if hasattr(child, 'param'):
|
||||
for param in child.param:
|
||||
value = self.populate_param(function, param)
|
||||
value = self.populate_param(param)
|
||||
if not hasattr(param, 'name'):
|
||||
args.append(str(value))
|
||||
else:
|
||||
@ -310,46 +337,6 @@ class Variable(Common):
|
||||
ret += f', warnings_only={child.warnings_only}'
|
||||
return ret + ')'
|
||||
|
||||
def populate_param(self,
|
||||
function: str,
|
||||
param,
|
||||
):
|
||||
"""Populate variable parameters
|
||||
"""
|
||||
if param.type == 'string':
|
||||
value = param.text
|
||||
if value is not None:
|
||||
value = self.convert_str(value)
|
||||
return f"ParamValue({value})"
|
||||
if param.type in ['number', 'boolean']:
|
||||
return f'ParamValue({param.text})'
|
||||
if param.type == 'nil':
|
||||
return 'ParamValue(None)'
|
||||
if param.type == 'variable':
|
||||
return self.build_param(param, function)
|
||||
if param.type == 'information':
|
||||
return f'ParamInformation("{param.text}", None)'
|
||||
if param.type == 'suffix':
|
||||
return 'ParamSuffix()'
|
||||
raise Exception(f'unknown type {param.type}') # pragma: no cover
|
||||
|
||||
@staticmethod
|
||||
def build_param(param,
|
||||
function: str, # pylint: disable=W0613
|
||||
) -> str:
|
||||
"""build variable parameters
|
||||
"""
|
||||
option_name = param.text.reflector_object.get()
|
||||
params = [f'{option_name}']
|
||||
if hasattr(param, 'suffix'):
|
||||
param_type = 'ParamDynOption'
|
||||
params.extend([f"'{param.suffix}'", f'{param.family.reflector_name}'])
|
||||
else:
|
||||
param_type = 'ParamOption'
|
||||
if not param.propertyerror:
|
||||
params.append('notraisepropertyerror=True')
|
||||
return "{}({})".format(param_type, ', '.join(params))
|
||||
|
||||
|
||||
class Family(Common):
|
||||
"""Manage family
|
||||
|
Reference in New Issue
Block a user