WIP: Expand the developer documentation #27
13 changed files with 389 additions and 90 deletions
|
@ -27,10 +27,11 @@ You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
"""
|
"""
|
||||||
from tiramisu import Config
|
from tiramisu import Config, undefined
|
||||||
from tiramisu.error import PropertiesOptionError
|
from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from re import compile, findall
|
||||||
|
|
||||||
from .convert import RougailConvert
|
from .convert import RougailConvert
|
||||||
from .config import RougailConfig
|
from .config import RougailConfig
|
||||||
|
@ -39,15 +40,20 @@ from .object_model import CONVERT_OPTION
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
|
|
||||||
|
|
||||||
def tiramisu_display_name(kls, subconfig) -> str:
|
def tiramisu_display_name(kls,
|
||||||
|
subconfig,
|
||||||
|
with_quote: bool=False,
|
||||||
|
) -> str:
|
||||||
"""Replace the Tiramisu display_name function to display path + description"""
|
"""Replace the Tiramisu display_name function to display path + description"""
|
||||||
doc = kls._get_information(subconfig, "doc", None)
|
doc = kls._get_information(subconfig, "doc", None)
|
||||||
comment = f" ({doc})" if doc and doc != kls.impl_getname() else ""
|
comment = f" ({doc})" if doc and doc != kls.impl_getname() else ""
|
||||||
if "{{ suffix }}" in comment:
|
if "{{ identifier }}" in comment:
|
||||||
comment = comment.replace('{{ suffix }}', str(subconfig.suffixes[-1]))
|
comment = comment.replace('{{ identifier }}', str(subconfig.identifiers[-1]))
|
||||||
path = kls.impl_getpath()
|
path = kls.impl_getpath()
|
||||||
if "{{ suffix }}" in path:
|
if "{{ identifier }}" in path and subconfig.identifiers:
|
||||||
path = path.replace('{{ suffix }}', normalize_family(str(subconfig.suffixes[-1])))
|
path = path.replace('{{ identifier }}', normalize_family(str(subconfig.identifiers[-1])))
|
||||||
|
if with_quote:
|
||||||
|
return f'"{path}"{comment}'
|
||||||
return f"{path}{comment}"
|
return f"{path}{comment}"
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,37 +102,194 @@ class Rougail:
|
||||||
errors = []
|
errors = []
|
||||||
warnings = []
|
warnings = []
|
||||||
for datas in user_datas:
|
for datas in user_datas:
|
||||||
|
options = datas.get('options', {})
|
||||||
for name, data in datas.get('values', {}).items():
|
for name, data in datas.get('values', {}).items():
|
||||||
values.setdefault(name, {}).update(data)
|
values[name] = {'values': data,
|
||||||
|
'options': options.copy(),
|
||||||
|
}
|
||||||
errors.extend(datas.get('errors', []))
|
errors.extend(datas.get('errors', []))
|
||||||
warnings.extend(datas.get('warnings', []))
|
warnings.extend(datas.get('warnings', []))
|
||||||
|
self._auto_configure_dynamics(values)
|
||||||
while values:
|
while values:
|
||||||
value_is_set = False
|
value_is_set = False
|
||||||
for option in self.config:
|
for option in self._get_variable(self.config):
|
||||||
if option.path() in values and option.index() in values[option.path()]:
|
path = option.path()
|
||||||
try:
|
if path not in values:
|
||||||
option.value.set(values[option.path()])
|
path = path.upper()
|
||||||
value_is_set = True
|
options = values.get(path, {}).get('options', {})
|
||||||
values.pop(option.path())
|
if path not in values or options.get('upper') is not True:
|
||||||
except:
|
continue
|
||||||
pass
|
else:
|
||||||
|
options = values[path].get('options', {})
|
||||||
|
value = values[path]["values"]
|
||||||
|
if option.ismulti():
|
||||||
|
if options.get('multi_separator') and not isinstance(value, list):
|
||||||
|
value = value.split(options['multi_separator'])
|
||||||
|
values[path]["values"] = value
|
||||||
|
if options.get('needs_convert'):
|
||||||
|
value = [convert_value(option, val) for val in value]
|
||||||
|
values[path]["values"] = value
|
||||||
|
values[path]["options"]["needs_convert"] = False
|
||||||
|
elif options.get('needs_convert'):
|
||||||
|
value = convert_value(option, value)
|
||||||
|
index = option.index()
|
||||||
|
if index is not None:
|
||||||
|
if not isinstance(value, list) or index >= len(value):
|
||||||
|
continue
|
||||||
|
value = value[index]
|
||||||
|
try:
|
||||||
|
option.value.set(value)
|
||||||
|
value_is_set = True
|
||||||
|
if index is not None:
|
||||||
|
values[path]['values'][index] = undefined
|
||||||
|
if set(values[path]['values']) == {undefined}:
|
||||||
|
values.pop(path)
|
||||||
|
else:
|
||||||
|
values.pop(path)
|
||||||
|
except Exception as err:
|
||||||
|
if path != option.path():
|
||||||
|
values[option.path()] = values.pop(path)
|
||||||
if not value_is_set:
|
if not value_is_set:
|
||||||
break
|
break
|
||||||
for path, data in values.items():
|
for path, data in values.items():
|
||||||
for index, value in data.items():
|
try:
|
||||||
try:
|
option = self.config.option(path)
|
||||||
print('attention', path, value)
|
value = data['values']
|
||||||
self.config.option(path).value.set(value)
|
if option.isfollower():
|
||||||
print('pfff')
|
for index, val in enumerate(value):
|
||||||
except AttributeError as err:
|
if val is undefined:
|
||||||
errors.append(str(err))
|
continue
|
||||||
except ValueError as err:
|
self.config.option(path, index).value.set(val)
|
||||||
errors.append(str(err).replace('"', "'"))
|
else:
|
||||||
except PropertiesOptionError as err:
|
option.value.set(value)
|
||||||
# warnings.append(f'"{err}" but is defined in "{self.filename}"')
|
except AttributeError as err:
|
||||||
warnings.append(str(err))
|
errors.append(str(err))
|
||||||
|
except (ValueError, LeadershipError) as err:
|
||||||
|
#errors.append(str(err).replace('"', "'"))
|
||||||
|
errors.append(str(err))
|
||||||
|
except PropertiesOptionError as err:
|
||||||
|
# warnings.append(f'"{err}" but is defined in "{self.filename}"')
|
||||||
|
warnings.append(str(err))
|
||||||
return {'errors': errors,
|
return {'errors': errors,
|
||||||
'warnings': warnings,
|
'warnings': warnings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _get_variable(self, config):
|
||||||
|
for subconfig in config:
|
||||||
|
if subconfig.isoptiondescription():
|
||||||
|
yield from self._get_variable(subconfig)
|
||||||
|
else:
|
||||||
|
yield subconfig
|
||||||
|
|
||||||
|
def _auto_configure_dynamics(self,
|
||||||
|
values,
|
||||||
|
):
|
||||||
|
cache = {}
|
||||||
|
added = []
|
||||||
|
for path, data in list(values.items()):
|
||||||
|
value = data['values']
|
||||||
|
# for value in data['values'].items():
|
||||||
|
try:
|
||||||
|
option = self.config.option(path)
|
||||||
|
option.name()
|
||||||
|
except (ConfigError, PropertiesOptionError):
|
||||||
|
pass
|
||||||
|
except AttributeError:
|
||||||
|
config = self.config
|
||||||
|
current_path = ''
|
||||||
|
identifiers = []
|
||||||
|
for name in path.split('.')[:-1]:
|
||||||
|
if current_path:
|
||||||
|
current_path += '.'
|
||||||
|
current_path += name
|
||||||
|
if current_path in cache:
|
||||||
|
config, identifier = cache[current_path]
|
||||||
|
identifiers.append(identifier)
|
||||||
|
else:
|
||||||
|
tconfig = config.option(name)
|
||||||
|
try:
|
||||||
|
tconfig.group_type()
|
||||||
|
config = tconfig
|
||||||
|
except AttributeError:
|
||||||
|
for tconfig in config.list(uncalculated=True):
|
||||||
|
if tconfig.isdynamic(only_self=True):
|
||||||
|
identifier = self._get_identifier(tconfig.name(), name)
|
||||||
|
if identifier is None:
|
||||||
|
continue
|
||||||
|
dynamic_variable = tconfig.information.get('dynamic_variable',
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if not dynamic_variable:
|
||||||
|
continue
|
||||||
|
option_type = self.config.option(dynamic_variable).information.get('type')
|
||||||
|
if identifiers:
|
||||||
|
for s in identifiers:
|
||||||
|
dynamic_variable = dynamic_variable.replace('{{ identifier }}', str(s), 1)
|
||||||
|
if dynamic_variable not in values:
|
||||||
|
values[dynamic_variable] = {'values': []}
|
||||||
|
added.append(dynamic_variable)
|
||||||
|
elif dynamic_variable not in added:
|
||||||
|
continue
|
||||||
|
config = tconfig
|
||||||
|
# option_type = option.information.get('type')
|
||||||
|
typ = CONVERT_OPTION.get(option_type, {}).get("func")
|
||||||
|
if typ:
|
||||||
|
identifier = typ(identifier)
|
||||||
|
if identifier not in values[dynamic_variable]['values']:
|
||||||
|
values[dynamic_variable]['values'].append(identifier)
|
||||||
|
identifiers.append(identifier)
|
||||||
|
cache[current_path] = config, identifier
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if option.isdynamic():
|
||||||
|
parent_option = self.config.option(path.rsplit('.', 1)[0])
|
||||||
|
identifiers = self._get_identifier(parent_option.name(uncalculated=True),
|
||||||
|
parent_option.name(),
|
||||||
|
)
|
||||||
|
dynamic_variable = None
|
||||||
|
while True:
|
||||||
|
dynamic_variable = parent_option.information.get('dynamic_variable',
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if dynamic_variable:
|
||||||
|
break
|
||||||
|
parent_option = self.config.option(parent_option.path().rsplit('.', 1)[0])
|
||||||
|
if '.' not in parent_option.path():
|
||||||
|
parent_option = None
|
||||||
|
break
|
||||||
|
if not parent_option:
|
||||||
|
continue
|
||||||
|
identifiers = parent_option.identifiers()
|
||||||
|
for identifier in identifiers:
|
||||||
|
dynamic_variable = dynamic_variable.replace('{{ identifier }}', str(identifier), 1)
|
||||||
|
if dynamic_variable not in values:
|
||||||
|
values[dynamic_variable] = {'values': []}
|
||||||
|
added.append(dynamic_variable)
|
||||||
|
elif dynamic_variable not in added:
|
||||||
|
continue
|
||||||
|
option_type = option.information.get('type')
|
||||||
|
typ = CONVERT_OPTION.get(option_type, {}).get("func")
|
||||||
|
if typ:
|
||||||
|
identifier = typ(identifier)
|
||||||
|
if identifier not in values[dynamic_variable]['values']:
|
||||||
|
values[dynamic_variable]['values'].append(identifier)
|
||||||
|
cache[option.path()] = option, identifier
|
||||||
|
|
||||||
|
def _get_identifier(self, true_name, name) -> str:
|
||||||
|
regexp = true_name.replace("{{ identifier }}", "(.*)")
|
||||||
|
finded = findall(regexp, name)
|
||||||
|
if len(finded) != 1 or not finded[0]:
|
||||||
|
return
|
||||||
|
return finded[0]
|
||||||
|
|
||||||
|
def convert_value(option, value):
|
||||||
|
if value == '':
|
||||||
|
return None
|
||||||
|
option_type = option.information.get('type')
|
||||||
|
func = CONVERT_OPTION.get(option_type, {}).get("func")
|
||||||
|
if func:
|
||||||
|
return func(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
__all__ = ("Rougail", "RougailConfig", "RougailUpgrade")
|
__all__ = ("Rougail", "RougailConfig", "RougailUpgrade")
|
||||||
|
|
|
@ -178,13 +178,7 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
msg = _(f'the variable "{variable.path}" has regexp attribut but has not the "regexp" type')
|
msg = _(f'the variable "{variable.path}" has regexp attribut but has not the "regexp" type')
|
||||||
raise DictConsistencyError(msg, 37, variable.xmlfiles)
|
raise DictConsistencyError(msg, 37, variable.xmlfiles)
|
||||||
if variable.mandatory is None:
|
if variable.mandatory is None:
|
||||||
family_path = variable.path
|
variable.mandatory = True
|
||||||
hidden = variable.hidden is True
|
|
||||||
while '.' in family_path and not hidden:
|
|
||||||
family_path = family_path.rsplit(".", 1)[0]
|
|
||||||
family = self.objectspace.paths[family_path]
|
|
||||||
hidden = family.hidden is True
|
|
||||||
variable.mandatory = not hidden
|
|
||||||
|
|
||||||
def convert_test(self):
|
def convert_test(self):
|
||||||
"""Convert variable tests value"""
|
"""Convert variable tests value"""
|
||||||
|
|
|
@ -193,7 +193,7 @@ def get_rougail_config(*,
|
||||||
main_namespace_default = 'rougail'
|
main_namespace_default = 'rougail'
|
||||||
else:
|
else:
|
||||||
main_namespace_default = 'null'
|
main_namespace_default = 'null'
|
||||||
rougail_options = """default_dictionary_format_version:
|
rougail_options = f"""default_dictionary_format_version:
|
||||||
description: Dictionary format version by default, if not specified in dictionary file
|
description: Dictionary format version by default, if not specified in dictionary file
|
||||||
alternative_name: v
|
alternative_name: v
|
||||||
choices:
|
choices:
|
||||||
|
@ -219,7 +219,7 @@ sort_dictionaries_all:
|
||||||
|
|
||||||
main_namespace:
|
main_namespace:
|
||||||
description: Main namespace name
|
description: Main namespace name
|
||||||
default: MAIN_MAMESPACE_DEFAULT
|
default: {main_namespace_default}
|
||||||
alternative_name: s
|
alternative_name: s
|
||||||
mandatory: false
|
mandatory: false
|
||||||
|
|
||||||
|
@ -289,18 +289,29 @@ functions_files:
|
||||||
|
|
||||||
modes_level:
|
modes_level:
|
||||||
description: All modes level available
|
description: All modes level available
|
||||||
|
multi: true
|
||||||
|
mandatory: false
|
||||||
|
"""
|
||||||
|
if backward_compatibility:
|
||||||
|
rougail_options += """
|
||||||
default:
|
default:
|
||||||
- basic
|
- basic
|
||||||
- standard
|
- standard
|
||||||
- advanced
|
- advanced
|
||||||
commandline: false
|
"""
|
||||||
|
rougail_options += """
|
||||||
default_family_mode:
|
default_family_mode:
|
||||||
description: Default mode for a family
|
description: Default mode for a family
|
||||||
default:
|
default:
|
||||||
type: jinja
|
|
||||||
jinja: |
|
jinja: |
|
||||||
|
{% if modes_level %}
|
||||||
{{ modes_level[0] }}
|
{{ modes_level[0] }}
|
||||||
|
{% endif %}
|
||||||
|
disabled:
|
||||||
|
jinja: |
|
||||||
|
{% if not modes_level %}
|
||||||
|
No mode
|
||||||
|
{% endif %}
|
||||||
validators:
|
validators:
|
||||||
- type: jinja
|
- type: jinja
|
||||||
jinja: |
|
jinja: |
|
||||||
|
@ -312,9 +323,19 @@ default_family_mode:
|
||||||
default_variable_mode:
|
default_variable_mode:
|
||||||
description: Default mode for a variable
|
description: Default mode for a variable
|
||||||
default:
|
default:
|
||||||
type: jinja
|
|
||||||
jinja: |
|
jinja: |
|
||||||
|
{% if modes_level %}
|
||||||
|
{% if modes_level | length == 1 %}
|
||||||
|
{{ modes_level[0] }}
|
||||||
|
{% else %}
|
||||||
{{ modes_level[1] }}
|
{{ modes_level[1] }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
disabled:
|
||||||
|
jinja: |
|
||||||
|
{% if not modes_level %}
|
||||||
|
No mode
|
||||||
|
{% endif %}
|
||||||
validators:
|
validators:
|
||||||
- type: jinja
|
- type: jinja
|
||||||
jinja: |
|
jinja: |
|
||||||
|
@ -364,7 +385,7 @@ suffix:
|
||||||
default: ''
|
default: ''
|
||||||
mandatory: false
|
mandatory: false
|
||||||
commandline: false
|
commandline: false
|
||||||
""".replace('MAIN_MAMESPACE_DEFAULT', main_namespace_default)
|
"""
|
||||||
processes = {'structural': [],
|
processes = {'structural': [],
|
||||||
'output': [],
|
'output': [],
|
||||||
'user data': [],
|
'user data': [],
|
||||||
|
|
|
@ -133,7 +133,7 @@ class Paths:
|
||||||
if not force and is_dynamic:
|
if not force and is_dynamic:
|
||||||
self._dynamics[path] = dynamic
|
self._dynamics[path] = dynamic
|
||||||
|
|
||||||
def get_relative_path(self,
|
def get_full_path(self,
|
||||||
path: str,
|
path: str,
|
||||||
current_path: str,
|
current_path: str,
|
||||||
):
|
):
|
||||||
|
@ -148,21 +148,22 @@ class Paths:
|
||||||
def get_with_dynamic(
|
def get_with_dynamic(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
suffix_path: str,
|
identifier_path: str,
|
||||||
current_path: str,
|
current_path: str,
|
||||||
version: str,
|
version: str,
|
||||||
namespace: str,
|
namespace: str,
|
||||||
xmlfiles: List[str],
|
xmlfiles: List[str],
|
||||||
) -> Any:
|
) -> Any:
|
||||||
suffix = None
|
identifier = None
|
||||||
if version != '1.0' and self.regexp_relative.search(path):
|
if version != '1.0' and self.regexp_relative.search(path):
|
||||||
path = self.get_relative_path(path,
|
path = self.get_full_path(path,
|
||||||
current_path,
|
current_path,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
path = get_realpath(path, suffix_path)
|
path = get_realpath(path, identifier_path)
|
||||||
dynamic = None
|
dynamic = None
|
||||||
if not path in self._data and "{{ suffix }}" not in path:
|
# version 1.0
|
||||||
|
if version == "1.0" and not path in self._data and "{{ identifier }}" not in path:
|
||||||
new_path = None
|
new_path = None
|
||||||
current_path = None
|
current_path = None
|
||||||
for name in path.split("."):
|
for name in path.split("."):
|
||||||
|
@ -184,10 +185,9 @@ class Paths:
|
||||||
parent_dynamic = None
|
parent_dynamic = None
|
||||||
name_dynamic = dynamic_path
|
name_dynamic = dynamic_path
|
||||||
if (
|
if (
|
||||||
version == "1.0"
|
parent_dynamic == parent_path
|
||||||
and parent_dynamic == parent_path
|
and name_dynamic.endswith("{{ identifier }}")
|
||||||
and name_dynamic.endswith("{{ suffix }}")
|
and name == name_dynamic.replace("{{ identifier }}", "")
|
||||||
and name == name_dynamic.replace("{{ suffix }}", "")
|
|
||||||
):
|
):
|
||||||
new_path += "." + name_dynamic
|
new_path += "." + name_dynamic
|
||||||
break
|
break
|
||||||
|
@ -197,12 +197,12 @@ class Paths:
|
||||||
else:
|
else:
|
||||||
new_path = name
|
new_path = name
|
||||||
path = new_path
|
path = new_path
|
||||||
if not path in self._data:
|
if version != "1.0" and not path in self._data:
|
||||||
current_path = None
|
current_path = None
|
||||||
|
parent_path = None
|
||||||
new_path = current_path
|
new_path = current_path
|
||||||
suffixes = []
|
identifiers = []
|
||||||
for name in path.split("."):
|
for name in path.split("."):
|
||||||
parent_path = current_path
|
|
||||||
if current_path:
|
if current_path:
|
||||||
current_path += "." + name
|
current_path += "." + name
|
||||||
else:
|
else:
|
||||||
|
@ -213,6 +213,7 @@ class Paths:
|
||||||
new_path += "." + name
|
new_path += "." + name
|
||||||
else:
|
else:
|
||||||
new_path = name
|
new_path = name
|
||||||
|
parent_path = current_path
|
||||||
continue
|
continue
|
||||||
for dynamic_path in self._dynamics:
|
for dynamic_path in self._dynamics:
|
||||||
if '.' in dynamic_path:
|
if '.' in dynamic_path:
|
||||||
|
@ -221,30 +222,35 @@ class Paths:
|
||||||
parent_dynamic = None
|
parent_dynamic = None
|
||||||
name_dynamic = dynamic_path
|
name_dynamic = dynamic_path
|
||||||
if (
|
if (
|
||||||
"{{ suffix }}" not in name_dynamic
|
"{{ identifier }}" not in name_dynamic
|
||||||
or parent_path != parent_dynamic
|
or parent_path != parent_dynamic
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
regexp = "^" + name_dynamic.replace("{{ suffix }}", "(.*)")
|
regexp = "^" + name_dynamic.replace("{{ identifier }}", "(.*)")
|
||||||
finded = findall(regexp, name)
|
finded = findall(regexp, name)
|
||||||
if len(finded) != 1 or not finded[0]:
|
if len(finded) != 1 or not finded[0]:
|
||||||
continue
|
continue
|
||||||
suffixes.append(finded[0])
|
if finded[0] == "{{ identifier }}":
|
||||||
|
identifiers.append(None)
|
||||||
|
else:
|
||||||
|
identifiers.append(finded[0])
|
||||||
if new_path is None:
|
if new_path is None:
|
||||||
new_path = name_dynamic
|
new_path = name_dynamic
|
||||||
else:
|
else:
|
||||||
new_path += "." + name_dynamic
|
new_path += "." + name_dynamic
|
||||||
|
parent_path = dynamic_path
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if new_path:
|
if new_path:
|
||||||
new_path += "." + name
|
new_path += "." + name
|
||||||
else:
|
else:
|
||||||
new_path = name
|
new_path = name
|
||||||
if "{{ suffix }}" in name:
|
if "{{ identifier }}" in name:
|
||||||
suffixes.append(None)
|
identifiers.append(None)
|
||||||
|
parent_path = current_path
|
||||||
path = new_path
|
path = new_path
|
||||||
else:
|
else:
|
||||||
suffixes = None
|
identifiers = None
|
||||||
if path not in self._data:
|
if path not in self._data:
|
||||||
return None, None
|
return None, None
|
||||||
option = self._data[path]
|
option = self._data[path]
|
||||||
|
@ -258,7 +264,7 @@ class Paths:
|
||||||
f'shall not be used in the "{namespace}" namespace'
|
f'shall not be used in the "{namespace}" namespace'
|
||||||
)
|
)
|
||||||
raise DictConsistencyError(msg, 38, xmlfiles)
|
raise DictConsistencyError(msg, 38, xmlfiles)
|
||||||
return option, suffixes
|
return option, identifiers
|
||||||
|
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self,
|
self,
|
||||||
|
@ -316,8 +322,8 @@ class Informations:
|
||||||
|
|
||||||
class ParserVariable:
|
class ParserVariable:
|
||||||
def __init__(self, rougailconfig):
|
def __init__(self, rougailconfig):
|
||||||
self.load_config(rougailconfig)
|
|
||||||
self.rougailconfig = rougailconfig
|
self.rougailconfig = rougailconfig
|
||||||
|
self.load_config()
|
||||||
self.paths = Paths(self.main_namespace)
|
self.paths = Paths(self.main_namespace)
|
||||||
self.families = []
|
self.families = []
|
||||||
self.variables = []
|
self.variables = []
|
||||||
|
@ -342,12 +348,14 @@ class ParserVariable:
|
||||||
self.is_init = False
|
self.is_init = False
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def load_config(self,
|
def load_config(self) -> None:
|
||||||
rougailconfig: 'RougailConfig',
|
rougailconfig = self.rougailconfig
|
||||||
) -> None:
|
self.sort_dictionaries_all = rougailconfig['sort_dictionaries_all']
|
||||||
self.rougailconfig = rougailconfig
|
try:
|
||||||
|
self.main_dictionaries = rougailconfig["main_dictionaries"]
|
||||||
|
except:
|
||||||
|
self.main_dictionaries = []
|
||||||
self.main_namespace = rougailconfig["main_namespace"]
|
self.main_namespace = rougailconfig["main_namespace"]
|
||||||
self.main_dictionaries = rougailconfig["main_dictionaries"]
|
|
||||||
if self.main_namespace:
|
if self.main_namespace:
|
||||||
self.extra_dictionaries = rougailconfig["extra_dictionaries"]
|
self.extra_dictionaries = rougailconfig["extra_dictionaries"]
|
||||||
self.suffix = rougailconfig["suffix"]
|
self.suffix = rougailconfig["suffix"]
|
||||||
|
@ -355,14 +363,15 @@ class ParserVariable:
|
||||||
self.custom_types = rougailconfig["custom_types"]
|
self.custom_types = rougailconfig["custom_types"]
|
||||||
self.functions_files = rougailconfig["functions_files"]
|
self.functions_files = rougailconfig["functions_files"]
|
||||||
self.modes_level = rougailconfig["modes_level"]
|
self.modes_level = rougailconfig["modes_level"]
|
||||||
self.default_variable_mode = rougailconfig["default_variable_mode"]
|
if self.modes_level:
|
||||||
self.default_family_mode = rougailconfig["default_family_mode"]
|
self.default_variable_mode = rougailconfig["default_variable_mode"]
|
||||||
|
self.default_family_mode = rougailconfig["default_family_mode"]
|
||||||
self.extra_annotators = rougailconfig["extra_annotators"]
|
self.extra_annotators = rougailconfig["extra_annotators"]
|
||||||
self.base_option_name = rougailconfig["base_option_name"]
|
self.base_option_name = rougailconfig["base_option_name"]
|
||||||
self.export_with_import = rougailconfig["export_with_import"]
|
self.export_with_import = rougailconfig["export_with_import"]
|
||||||
self.internal_functions = rougailconfig["internal_functions"]
|
self.internal_functions = rougailconfig["internal_functions"]
|
||||||
self.add_extra_options = rougailconfig["structural_commandline.add_extra_options"]
|
self.add_extra_options = rougailconfig["structural_commandline.add_extra_options"]
|
||||||
self.plugins = []
|
self.plugins = rougailconfig["plugins"]
|
||||||
|
|
||||||
def _init(self):
|
def _init(self):
|
||||||
if self.is_init:
|
if self.is_init:
|
||||||
|
@ -557,8 +566,10 @@ class ParserVariable:
|
||||||
# it's just for modify subfamily or subvariable, do not redefine
|
# it's just for modify subfamily or subvariable, do not redefine
|
||||||
if family_obj:
|
if family_obj:
|
||||||
if not obj.pop("redefine", False):
|
if not obj.pop("redefine", False):
|
||||||
raise Exception(
|
raise DictConsistencyError(
|
||||||
f"The family {path} already exists and she is not redefined in {filename}"
|
f'The family "{path}" already exists and it is not redefined',
|
||||||
|
32,
|
||||||
|
[filename],
|
||||||
)
|
)
|
||||||
# convert to Calculation objects
|
# convert to Calculation objects
|
||||||
self.parse_parameters(
|
self.parse_parameters(
|
||||||
|
@ -604,12 +615,12 @@ class ParserVariable:
|
||||||
if obj_type == "dynamic":
|
if obj_type == "dynamic":
|
||||||
family_is_dynamic = True
|
family_is_dynamic = True
|
||||||
parent_dynamic = path
|
parent_dynamic = path
|
||||||
if '{{ suffix }}' not in name:
|
if '{{ identifier }}' not in name:
|
||||||
if "variable" in family_obj:
|
if "variable" in family_obj:
|
||||||
name += '{{ suffix }}'
|
name += '{{ identifier }}'
|
||||||
path += '{{ suffix }}'
|
path += '{{ identifier }}'
|
||||||
else:
|
else:
|
||||||
msg = f'dynamic family name must have "{{{{ suffix }}}}" in his name for "{path}"'
|
msg = f'dynamic family name must have "{{{{ identifier }}}}" in his name for "{path}"'
|
||||||
raise DictConsistencyError(msg, 13, [filename])
|
raise DictConsistencyError(msg, 13, [filename])
|
||||||
if version != '1.0' and not family_obj and comment:
|
if version != '1.0' and not family_obj and comment:
|
||||||
family_obj['description'] = comment
|
family_obj['description'] = comment
|
||||||
|
@ -938,6 +949,7 @@ class ParserVariable:
|
||||||
|
|
||||||
variable["namespace"] = self.namespace
|
variable["namespace"] = self.namespace
|
||||||
variable["version"] = version
|
variable["version"] = version
|
||||||
|
variable["path_prefix"] = self.path_prefix
|
||||||
variable["xmlfiles"] = filename
|
variable["xmlfiles"] = filename
|
||||||
variable_type = self.get_family_or_variable_type(variable)
|
variable_type = self.get_family_or_variable_type(variable)
|
||||||
obj = {
|
obj = {
|
||||||
|
@ -1074,8 +1086,8 @@ class ParserVariable:
|
||||||
try:
|
try:
|
||||||
params.append(PARAM_TYPES[param_typ](**val))
|
params.append(PARAM_TYPES[param_typ](**val))
|
||||||
except ValidationError as err:
|
except ValidationError as err:
|
||||||
raise Exception(
|
raise DictConsistencyError(
|
||||||
f'"{attribute}" has an invalid "{key}" for {path}: {err}'
|
f'"{attribute}" has an invalid "{key}" for {path}: {err}', 29, xmlfiles
|
||||||
) from err
|
) from err
|
||||||
calculation_object["params"] = params
|
calculation_object["params"] = params
|
||||||
#
|
#
|
||||||
|
@ -1086,8 +1098,8 @@ class ParserVariable:
|
||||||
f'unknown "return_type" in {attribute} of variable "{path}"'
|
f'unknown "return_type" in {attribute} of variable "{path}"'
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
if typ == "suffix" and not family_is_dynamic:
|
if typ == "identifier" and not family_is_dynamic:
|
||||||
msg = f'suffix calculation for "{attribute}" in "{path}" cannot be set none dynamic family'
|
msg = f'identifier calculation for "{attribute}" in "{path}" cannot be set none dynamic family'
|
||||||
raise DictConsistencyError(msg, 53, xmlfiles)
|
raise DictConsistencyError(msg, 53, xmlfiles)
|
||||||
if attribute in PROPERTY_ATTRIBUTE:
|
if attribute in PROPERTY_ATTRIBUTE:
|
||||||
calc = CALCULATION_PROPERTY_TYPES[typ](**calculation_object)
|
calc = CALCULATION_PROPERTY_TYPES[typ](**calculation_object)
|
||||||
|
@ -1143,15 +1155,16 @@ class RougailConvert(ParserVariable):
|
||||||
"""Parse directories content"""
|
"""Parse directories content"""
|
||||||
self._init()
|
self._init()
|
||||||
if path_prefix:
|
if path_prefix:
|
||||||
if path_prefix in self.parents:
|
n_path_prefix = normalize_family(path_prefix)
|
||||||
|
if n_path_prefix in self.parents:
|
||||||
raise Exception("pfffff")
|
raise Exception("pfffff")
|
||||||
root_parent = path_prefix
|
root_parent = n_path_prefix
|
||||||
self.path_prefix = path_prefix
|
self.path_prefix = n_path_prefix
|
||||||
self.namespace = None
|
self.namespace = None
|
||||||
self.add_family(
|
self.add_family(
|
||||||
path_prefix,
|
n_path_prefix,
|
||||||
path_prefix,
|
n_path_prefix,
|
||||||
{},
|
{'description': path_prefix},
|
||||||
"",
|
"",
|
||||||
False,
|
False,
|
||||||
None,
|
None,
|
||||||
|
@ -1267,11 +1280,14 @@ class RougailConvert(ParserVariable):
|
||||||
"""Sort filename"""
|
"""Sort filename"""
|
||||||
if not isinstance(directories, list):
|
if not isinstance(directories, list):
|
||||||
directories = [directories]
|
directories = [directories]
|
||||||
|
if self.sort_dictionaries_all:
|
||||||
|
filenames = {}
|
||||||
for directory_name in directories:
|
for directory_name in directories:
|
||||||
directory = Path(directory_name)
|
directory = Path(directory_name)
|
||||||
if not directory.is_dir():
|
if not directory.is_dir():
|
||||||
continue
|
continue
|
||||||
filenames = {}
|
if not self.sort_dictionaries_all:
|
||||||
|
filenames = {}
|
||||||
for file_path in directory.iterdir():
|
for file_path in directory.iterdir():
|
||||||
if file_path.suffix not in [".yml", ".yaml"]:
|
if file_path.suffix not in [".yml", ".yaml"]:
|
||||||
continue
|
continue
|
||||||
|
@ -1282,6 +1298,10 @@ class RougailConvert(ParserVariable):
|
||||||
[filenames[file_path.name][1]],
|
[filenames[file_path.name][1]],
|
||||||
)
|
)
|
||||||
filenames[file_path.name] = str(file_path)
|
filenames[file_path.name] = str(file_path)
|
||||||
|
if not self.sort_dictionaries_all:
|
||||||
|
for filename in sorted(filenames):
|
||||||
|
yield filenames[filename]
|
||||||
|
if self.sort_dictionaries_all:
|
||||||
for filename in sorted(filenames):
|
for filename in sorted(filenames):
|
||||||
yield filenames[filename]
|
yield filenames[filename]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
version: 1.1
|
||||||
|
|
||||||
|
var1:
|
||||||
|
description: a first variable
|
||||||
|
default: value
|
||||||
|
|
||||||
|
var2:
|
||||||
|
description: a second variable
|
||||||
|
disabled:
|
||||||
|
variable: _.var1
|
||||||
|
when: value
|
||||||
|
|
||||||
|
var3:
|
||||||
|
description: a third variable
|
||||||
|
default:
|
||||||
|
jinja: |
|
||||||
|
{% if _.var1 == 'value' or _.var2 == 'blah' %}
|
||||||
|
value
|
||||||
|
{% endif %}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
"rougail.var3": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "value"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": "value",
|
||||||
|
"rougail.var3": "value"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
"rougail.var3": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "value"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
[]
|
|
@ -0,0 +1,18 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||||
|
try:
|
||||||
|
groups.namespace
|
||||||
|
except:
|
||||||
|
groups.addgroup('namespace')
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("standard")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("advanced")
|
||||||
|
dict_env['default_rougail.var3'] = "{% if _.var1 == 'value' or _.var2 == 'blah' %}\nvalue\n{% endif %}\n"
|
||||||
|
option_2 = StrOption(name="var1", doc="a first variable", default="value", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
option_3 = StrOption(name="var2", doc="a second variable", properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_2)), kwargs={'when': ParamValue("value"), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
|
||||||
|
option_4 = StrOption(name="var3", doc="a third variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var3"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['tests/dictionaries/04_1default_calculation_hidden/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var3"), '_.var2': ParamOption(option_3, notraisepropertyerror=True), '_.var1': ParamOption(option_2, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3, option_4], properties=frozenset({"basic"}))
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])
|
|
@ -0,0 +1,25 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||||
|
try:
|
||||||
|
groups.namespace
|
||||||
|
except:
|
||||||
|
groups.addgroup('namespace')
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("standard")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("advanced")
|
||||||
|
dict_env['default_1.rougail.var3'] = "{% if _.var1 == 'value' or _.var2 == 'blah' %}\nvalue\n{% endif %}\n"
|
||||||
|
dict_env['default_2.rougail.var3'] = "{% if _.var1 == 'value' or _.var2 == 'blah' %}\nvalue\n{% endif %}\n"
|
||||||
|
option_3 = StrOption(name="var1", doc="a first variable", default="value", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
option_4 = StrOption(name="var2", doc="a second variable", properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_3)), kwargs={'when': ParamValue("value"), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
|
||||||
|
option_5 = StrOption(name="var3", doc="a third variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_1.rougail.var3"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['tests/dictionaries/04_1default_calculation_hidden/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("1.rougail.var3"), '_.var2': ParamOption(option_4, notraisepropertyerror=True), '_.var1': ParamOption(option_3, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_3, option_4, option_5], properties=frozenset({"basic"}))
|
||||||
|
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"basic"}))
|
||||||
|
option_8 = StrOption(name="var1", doc="a first variable", default="value", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
option_9 = StrOption(name="var2", doc="a second variable", properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_8)), kwargs={'when': ParamValue("value"), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
|
||||||
|
option_10 = StrOption(name="var3", doc="a third variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_2.rougail.var3"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['tests/dictionaries/04_1default_calculation_hidden/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("2.rougail.var3"), '_.var2': ParamOption(option_9, notraisepropertyerror=True), '_.var1': ParamOption(option_8, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
optiondescription_7 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_8, option_9, option_10], properties=frozenset({"basic"}))
|
||||||
|
optiondescription_6 = OptionDescription(name="2", doc="2", children=[optiondescription_7], properties=frozenset({"basic"}))
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_6])
|
|
@ -0,0 +1,13 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("standard")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("advanced")
|
||||||
|
dict_env['default_var3'] = "{% if _.var1 == 'value' or _.var2 == 'blah' %}\nvalue\n{% endif %}\n"
|
||||||
|
option_1 = StrOption(name="var1", doc="a first variable", default="value", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
option_2 = StrOption(name="var2", doc="a second variable", properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_1)), kwargs={'when': ParamValue("value"), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
|
||||||
|
option_3 = StrOption(name="var3", doc="a third variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var3"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['tests/dictionaries/04_1default_calculation_hidden/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var3"), '_.var2': ParamOption(option_2, notraisepropertyerror=True), '_.var1': ParamOption(option_1, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2, option_3])
|
Loading…
Reference in a new issue