From d5129d6fe75df3a27dd658be4633b244f80799c0 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 15 Nov 2020 11:02:04 +0100 Subject: [PATCH] add float support --- src/rougail/annotator.py | 42 ++++++++++++++++--- src/rougail/tiramisureflector.py | 32 ++------------ tests/dictionaries/01base_float/00-base.xml | 16 +++++++ tests/dictionaries/01base_float/__init__.py | 0 .../01base_float/makedict/base.json | 1 + .../01base_float/tiramisu/__init__.py | 0 .../01base_float/tiramisu/base.py | 15 +++++++ tests/dictionaries/80unknown_type/00-base.xml | 10 +++++ tests/dictionaries/80unknown_type/__init__.py | 0 9 files changed, 83 insertions(+), 33 deletions(-) create mode 100644 tests/dictionaries/01base_float/00-base.xml create mode 100644 tests/dictionaries/01base_float/__init__.py create mode 100644 tests/dictionaries/01base_float/makedict/base.json create mode 100644 tests/dictionaries/01base_float/tiramisu/__init__.py create mode 100644 tests/dictionaries/01base_float/tiramisu/base.py create mode 100644 tests/dictionaries/80unknown_type/00-base.xml create mode 100644 tests/dictionaries/80unknown_type/__init__.py diff --git a/src/rougail/annotator.py b/src/rougail/annotator.py index 2f77c7893..77cb5f94d 100644 --- a/src/rougail/annotator.py +++ b/src/rougail/annotator.py @@ -34,6 +34,33 @@ def mode_factory(): modes = mode_factory() +CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int), + 'float': dict(opttype="FloatOption", func=float), + 'choice': dict(opttype="ChoiceOption"), + 'string': dict(opttype="StrOption"), + 'password': dict(opttype="PasswordOption"), + 'mail': dict(opttype="EmailOption"), + 'boolean': dict(opttype="BoolOption"), + 'symlink': dict(opttype="SymLinkOption"), + 'filename': dict(opttype="FilenameOption"), + 'date': dict(opttype="DateOption"), + 'unix_user': dict(opttype="UsernameOption"), + 'ip': dict(opttype="IPOption", initkwargs={'allow_reserved': True}), + 'local_ip': dict(opttype="IPOption", initkwargs={'private_only': True, 'warnings_only': True}), + 'netmask': dict(opttype="NetmaskOption"), + 'network': dict(opttype="NetworkOption"), + 'broadcast': dict(opttype="BroadcastOption"), + 'netbios': dict(opttype="DomainnameOption", initkwargs={'type': 'netbios', 'warnings_only': True}), + 'domain': dict(opttype="DomainnameOption", initkwargs={'type': 'domainname', 'allow_ip': False}), + 'hostname': dict(opttype="DomainnameOption", initkwargs={'type': 'hostname', 'allow_ip': False}), + 'web_address': dict(opttype="URLOption", initkwargs={'allow_ip': True, 'allow_without_dot': True}), + 'port': dict(opttype="PortOption", initkwargs={'allow_private': True}), + 'mac': dict(opttype="MACOption"), + 'cidr': dict(opttype="IPOption", initkwargs={'cidr': True}), + 'network_cidr': dict(opttype="NetworkOption", initkwargs={'cidr': True}), + } + + # a CreoleObjSpace's attribute has some annotations # that shall not be present in the exported (flatened) XML ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace', @@ -56,8 +83,6 @@ KEY_TYPE = {'variable': 'symlink', 'URLOption': 'web_address', 'FilenameOption': 'filename'} -CONVERSION = {'number': int} - FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie' PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze', @@ -465,7 +490,7 @@ class VariableAnnotator: for value in variable.value: if not hasattr(value, 'type'): value.type = variable.type - value.name = CONVERSION.get(value.type, str)(value.name) + value.name = CONVERT_OPTION.get(value.type, {}).get('func', str)(value.name) for key, value in RENAME_ATTIBUTES.items(): setattr(variable, value, getattr(variable, key)) setattr(variable, key, None) @@ -497,6 +522,11 @@ class VariableAnnotator: self.objectspace.space.constraints.check.append(check) variable.type = 'string' + def _valid_type(variable): + if variable.type not in CONVERT_OPTION: + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + raise DictConsistencyError(_(f'unvalid type "{variable.type}" for variable "{variable.name}" in {xmlfiles}')) + if not hasattr(self.objectspace.space, 'variables'): return for families in self.objectspace.space.variables.values(): @@ -526,6 +556,7 @@ class VariableAnnotator: follower, path, ) + _valid_type(follower) else: path = '{}.{}.{}'.format(namespace, normalize_family(family.name), variable.name) _convert_variable(variable, @@ -535,6 +566,7 @@ class VariableAnnotator: variable, path, ) + _valid_type(variable) def convert_helps(self): if not hasattr(self.objectspace.space, 'help'): @@ -941,7 +973,7 @@ class ConstraintAnnotator: choice = self.objectspace.choice(variable.xmlfiles) try: if value is not None: - choice.name = CONVERSION.get(type_, str)(value) + choice.name = CONVERT_OPTION[type_].get('func', str)(value) else: choice.name = value except: @@ -956,7 +988,7 @@ class ConstraintAnnotator: for value in variable.value: value.type = type_ try: - cvalue = CONVERSION.get(type_, str)(value.name) + cvalue = CONVERT_OPTION[type_].get('func', str)(value.name) except: raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"')) if cvalue not in choices: diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py index 307546629..80f37257f 100644 --- a/src/rougail/tiramisureflector.py +++ b/src/rougail/tiramisureflector.py @@ -4,7 +4,7 @@ flattened XML specific from .config import Config from .i18n import _ from .error import LoaderError -from .annotator import ERASED_ATTRIBUTES +from .annotator import ERASED_ATTRIBUTES, CONVERT_OPTION FUNC_TO_DICT = ['valid_not_equal'] @@ -12,32 +12,6 @@ FORCE_INFORMATIONS = ['help', 'test', 'separator', 'manage'] ATTRIBUTES_ORDER = ('name', 'doc', 'default', 'multi') -CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int), - 'choice': dict(opttype="ChoiceOption"), - 'string': dict(opttype="StrOption"), - 'password': dict(opttype="PasswordOption"), - 'mail': dict(opttype="EmailOption"), - 'boolean': dict(opttype="BoolOption"), - 'symlink': dict(opttype="SymLinkOption"), - 'filename': dict(opttype="FilenameOption"), - 'date': dict(opttype="DateOption"), - 'unix_user': dict(opttype="UsernameOption"), - 'ip': dict(opttype="IPOption", initkwargs={'allow_reserved': True}), - 'local_ip': dict(opttype="IPOption", initkwargs={'private_only': True, 'warnings_only': True}), - 'netmask': dict(opttype="NetmaskOption"), - 'network': dict(opttype="NetworkOption"), - 'broadcast': dict(opttype="BroadcastOption"), - 'netbios': dict(opttype="DomainnameOption", initkwargs={'type': 'netbios', 'warnings_only': True}), - 'domain': dict(opttype="DomainnameOption", initkwargs={'type': 'domainname', 'allow_ip': False}), - 'hostname': dict(opttype="DomainnameOption", initkwargs={'type': 'hostname', 'allow_ip': False}), - 'web_address': dict(opttype="URLOption", initkwargs={'allow_ip': True, 'allow_without_dot': True}), - 'port': dict(opttype="PortOption", initkwargs={'allow_private': True}), - 'mac': dict(opttype="MACOption"), - 'cidr': dict(opttype="IPOption", initkwargs={'cidr': True}), - 'network_cidr': dict(opttype="NetworkOption", initkwargs={'cidr': True}), - } - - class TiramisuReflector: def __init__(self, xmlroot, @@ -344,6 +318,8 @@ class Variable(Common): value = value.split(',') if self.object_type == 'IntOption': value = [int(v) for v in value] + elif self.object_type == 'FloatOption': + value = [float(v) for v in value] self.informations[key] = value else: self.attrib[key] = value @@ -443,7 +419,7 @@ class Variable(Common): self.attrib['default'].append(value) if not self.is_leader: self.attrib['default_multi'] = value - elif isinstance(value, int): + elif isinstance(value, (int, float)): self.attrib['default'].append(value) else: self.attrib['default'].append("'" + value + "'") diff --git a/tests/dictionaries/01base_float/00-base.xml b/tests/dictionaries/01base_float/00-base.xml new file mode 100644 index 000000000..94eb63033 --- /dev/null +++ b/tests/dictionaries/01base_float/00-base.xml @@ -0,0 +1,16 @@ + + + + + + 0.527 + + + 0.527 + + + + + + diff --git a/tests/dictionaries/01base_float/__init__.py b/tests/dictionaries/01base_float/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/dictionaries/01base_float/makedict/base.json b/tests/dictionaries/01base_float/makedict/base.json new file mode 100644 index 000000000..113d425d9 --- /dev/null +++ b/tests/dictionaries/01base_float/makedict/base.json @@ -0,0 +1 @@ +{"rougail.general.float": 0.527, "rougail.general.float_multi": [0.527]} diff --git a/tests/dictionaries/01base_float/tiramisu/__init__.py b/tests/dictionaries/01base_float/tiramisu/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/dictionaries/01base_float/tiramisu/base.py b/tests/dictionaries/01base_float/tiramisu/base.py new file mode 100644 index 000000000..792415e72 --- /dev/null +++ b/tests/dictionaries/01base_float/tiramisu/base.py @@ -0,0 +1,15 @@ +import imp +func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py') +for key, value in dict(locals()).items(): + if key != ['imp', 'func']: + setattr(func, key, value) +try: + from tiramisu3 import * +except: + from tiramisu import * +from rougail.tiramisu import ConvertDynOptionDescription +option_3 = FloatOption(properties=frozenset({'mandatory', 'normal'}), name='float', doc='Description', multi=False, default=0.527) +option_4 = FloatOption(properties=frozenset({'mandatory', 'normal'}), name='float_multi', doc='Description', multi=True, default=[0.527], default_multi=0.527) +option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4]) +option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2]) +option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1]) diff --git a/tests/dictionaries/80unknown_type/00-base.xml b/tests/dictionaries/80unknown_type/00-base.xml new file mode 100644 index 000000000..deb50aeba --- /dev/null +++ b/tests/dictionaries/80unknown_type/00-base.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/tests/dictionaries/80unknown_type/__init__.py b/tests/dictionaries/80unknown_type/__init__.py new file mode 100644 index 000000000..e69de29bb