detect infinite loop

This commit is contained in:
Emmanuel Garette 2022-01-19 18:24:00 +01:00
parent e8667848e9
commit 4c011ee551
8 changed files with 44 additions and 13 deletions

View file

@ -99,6 +99,8 @@ class Annotator(TargetAnnotator, ParamAnnotator):
if param.type != 'number': if param.type != 'number':
msg = _(f'param in "valid_entier" must be an "integer", not "{param.type}"') msg = _(f'param in "valid_entier" must be an "integer", not "{param.type}"')
raise DictConsistencyError(msg, 18, check.xmlfiles) raise DictConsistencyError(msg, 18, check.xmlfiles)
if not hasattr(param, 'name'):
continue
for target in check.target: for target in check.target:
if param.name == 'mini': if param.name == 'mini':
target.name.min_number = int(param.text) target.name.min_number = int(param.text)

View file

@ -115,6 +115,7 @@ class Annotator:
if not hasattr(service, 'information'): if not hasattr(service, 'information'):
service.information = self.objectspace.information(service.xmlfiles) service.information = self.objectspace.information(service.xmlfiles)
setattr(service.information, elttype, values) setattr(service.information, elttype, values)
service.path = '.'.join(['services', service.name])
manage = self._generate_element('boolean', manage = self._generate_element('boolean',
None, None,
None, None,

View file

@ -188,7 +188,7 @@ class TiramisuReflector:
def get_text(self): def get_text(self):
"""Get text """Get text
""" """
self.baseelt.reflector_object.get() # pylint: disable=E1101 self.baseelt.reflector_object.get([]) # pylint: disable=E1101
return '\n'.join(self.text) return '\n'.join(self.text)
@ -207,9 +207,15 @@ class Common:
self.elt.reflector_object = self self.elt.reflector_object = self
self.object_type = None self.object_type = None
def get(self): def get(self, calls):
"""Get tiramisu's object """Get tiramisu's object
""" """
self_calls = calls.copy()
if self.elt.path in self_calls:
msg = f'"{self.elt.path}" will make an infinite loop'
raise DictConsistencyError(msg, 80, self.elt.xmlfiles)
self_calls.append(self.elt.path)
self.calls = self_calls
if self.option_name is None: if self.option_name is None:
self.option_name = self.elt.reflector_name self.option_name = self.elt.reflector_name
self.populate_attrib() self.populate_attrib()
@ -261,7 +267,7 @@ class Common:
) -> str: ) -> str:
"""Populate properties """Populate properties
""" """
option_name = child.source.reflector_object.get() option_name = child.source.reflector_object.get(self.calls)
kwargs = (f"'condition': ParamOption({option_name}, todict=True, notraisepropertyerror=True), " kwargs = (f"'condition': ParamOption({option_name}, todict=True, notraisepropertyerror=True), "
f"'expected': {self.populate_param(child.expected)}") f"'expected': {self.populate_param(child.expected)}")
if child.inverse: if child.inverse:
@ -311,16 +317,16 @@ class Common:
return 'ParamIndex()' return 'ParamIndex()'
raise Exception(_(f'unknown type {param.type}')) # pragma: no cover raise Exception(_(f'unknown type {param.type}')) # pragma: no cover
@staticmethod def build_option_param(self,
def build_option_param(param, param,
) -> str: ) -> str:
"""build variable parameters """build variable parameters
""" """
option_name = param.text.reflector_object.get() option_name = param.text.reflector_object.get(self.calls)
params = [f'{option_name}'] params = [f'{option_name}']
if hasattr(param, 'suffix'): if hasattr(param, 'suffix'):
param_type = 'ParamDynOption' param_type = 'ParamDynOption'
family = param.family.reflector_object.get() family = param.family.reflector_object.get(self.calls)
params.extend([f"'{param.suffix}'", f'{family}']) params.extend([f"'{param.suffix}'", f'{family}'])
else: else:
param_type = 'ParamOption' param_type = 'ParamOption'
@ -348,11 +354,11 @@ class Variable(Common):
keys: dict, keys: dict,
): ):
if hasattr(self.elt, 'opt'): if hasattr(self.elt, 'opt'):
keys['opt'] = self.elt.opt.reflector_object.get() keys['opt'] = self.elt.opt.reflector_object.get(self.calls)
if hasattr(self.elt, 'choice'): if hasattr(self.elt, 'choice'):
values = self.elt.choice values = self.elt.choice
if values[0].type == 'variable': if values[0].type == 'variable':
value = values[0].name.reflector_object.get() value = values[0].name.reflector_object.get(self.calls)
keys['values'] = f"Calculation(func.calc_value, Params((ParamOption({value}))))" keys['values'] = f"Calculation(func.calc_value, Params((ParamOption({value}))))"
elif values[0].type == 'function': elif values[0].type == 'function':
keys['values'] = self.calculation_value(values[0], []) keys['values'] = self.calculation_value(values[0], [])
@ -441,6 +447,6 @@ class Family(Common):
keys: list, keys: list,
) -> None: ) -> None:
if hasattr(self.elt, 'suffixes'): if hasattr(self.elt, 'suffixes'):
dyn = self.elt.suffixes.reflector_object.get() dyn = self.elt.suffixes.reflector_object.get(self.calls)
keys['suffixes'] = f"Calculation(func.calc_value, Params((ParamOption({dyn}, notraisepropertyerror=True))))" keys['suffixes'] = f"Calculation(func.calc_value, Params((ParamOption({dyn}, notraisepropertyerror=True))))"
keys['children'] = '[' + ', '.join([child.get() for child in self.children]) + ']' keys['children'] = '[' + ', '.join([child.get(self.calls) for child in self.children]) + ']'

View file

@ -0,0 +1,18 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail version="0.10">
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="string" description="No change">
<value>b</value>
</variable>
<variable name="int" type="number" description="No change"/>
</family>
</variables>
<constraints>
<check name="valid_lower">
<param name="mini" type="number">0</param>
<param name="maxi" type="variable">int</param>
<target>int</target>
</check>
</constraints>
</rougail>

View file

View file

@ -2,9 +2,11 @@ from lxml import etree
from os import getcwd from os import getcwd
from os.path import isfile, join, isdir from os.path import isfile, join, isdir
from pytest import fixture, raises from pytest import fixture, raises
from os import listdir from os import listdir, environ
from json import load from json import load
environ['TIRAMISU_LOCALE'] = 'en'
from rougail import RougailConvert, RougailConfig from rougail import RougailConvert, RougailConfig
from rougail.error import DictConsistencyError from rougail.error import DictConsistencyError

View file

@ -1,9 +1,11 @@
from lxml import etree from lxml import etree
from os.path import isfile, join, isdir from os.path import isfile, join, isdir
from pytest import fixture, mark from pytest import fixture, mark
from os import listdir, mkdir from os import listdir, mkdir, environ
from json import dump, load, dumps, loads from json import dump, load, dumps, loads
environ['TIRAMISU_LOCALE'] = 'en'
from tiramisu import Config from tiramisu import Config
from tiramisu.error import PropertiesOptionError from tiramisu.error import PropertiesOptionError