WIP: Expand the developer documentation #27
20 changed files with 649 additions and 422 deletions
|
@ -27,6 +27,7 @@ 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, undefined
|
from tiramisu import Config, undefined
|
||||||
from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError
|
from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
@ -40,18 +41,21 @@ from .object_model import CONVERT_OPTION
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
|
|
||||||
|
|
||||||
def tiramisu_display_name(kls,
|
def tiramisu_display_name(
|
||||||
subconfig,
|
kls,
|
||||||
with_quote: bool=False,
|
subconfig,
|
||||||
) -> str:
|
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 "{{ identifier }}" in comment:
|
if "{{ identifier }}" in comment:
|
||||||
comment = comment.replace('{{ identifier }}', str(subconfig.identifiers[-1]))
|
comment = comment.replace("{{ identifier }}", str(subconfig.identifiers[-1]))
|
||||||
path = kls.impl_getpath()
|
path = kls.impl_getpath()
|
||||||
if "{{ identifier }}" in path and subconfig.identifiers:
|
if "{{ identifier }}" in path and subconfig.identifiers:
|
||||||
path = path.replace('{{ identifier }}', normalize_family(str(subconfig.identifiers[-1])))
|
path = path.replace(
|
||||||
|
"{{ identifier }}", normalize_family(str(subconfig.identifiers[-1]))
|
||||||
|
)
|
||||||
if with_quote:
|
if with_quote:
|
||||||
return f'"{path}"{comment}'
|
return f'"{path}"{comment}'
|
||||||
return f"{path}{comment}"
|
return f"{path}{comment}"
|
||||||
|
@ -83,7 +87,10 @@ class Rougail:
|
||||||
if not self.config:
|
if not self.config:
|
||||||
tiram_obj = self.converted.save(self.rougailconfig["tiramisu_cache"])
|
tiram_obj = self.converted.save(self.rougailconfig["tiramisu_cache"])
|
||||||
optiondescription = {}
|
optiondescription = {}
|
||||||
custom_types = {custom.__name__: custom for custom in self.rougailconfig["custom_types"].values()}
|
custom_types = {
|
||||||
|
custom.__name__: custom
|
||||||
|
for custom in self.rougailconfig["custom_types"].values()
|
||||||
|
}
|
||||||
exec(tiram_obj, custom_types, optiondescription) # pylint: disable=W0122
|
exec(tiram_obj, custom_types, optiondescription) # pylint: disable=W0122
|
||||||
self.config = Config(
|
self.config = Config(
|
||||||
optiondescription["option_0"],
|
optiondescription["option_0"],
|
||||||
|
@ -93,22 +100,26 @@ class Rougail:
|
||||||
return self.config
|
return self.config
|
||||||
|
|
||||||
def get_config(self):
|
def get_config(self):
|
||||||
warn("get_config is deprecated, use run instead", DeprecationWarning, stacklevel=2)
|
warn(
|
||||||
|
"get_config is deprecated, use run instead",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
return self.run()
|
return self.run()
|
||||||
|
|
||||||
def user_datas(self,
|
def user_datas(self, user_datas: List[dict]):
|
||||||
user_datas: List[dict]):
|
|
||||||
values = {}
|
values = {}
|
||||||
errors = []
|
errors = []
|
||||||
warnings = []
|
warnings = []
|
||||||
for datas in user_datas:
|
for datas in user_datas:
|
||||||
options = datas.get('options', {})
|
options = datas.get("options", {})
|
||||||
for name, data in datas.get('values', {}).items():
|
for name, data in datas.get("values", {}).items():
|
||||||
values[name] = {'values': data,
|
values[name] = {
|
||||||
'options': options.copy(),
|
"values": data,
|
||||||
}
|
"options": options.copy(),
|
||||||
errors.extend(datas.get('errors', []))
|
}
|
||||||
warnings.extend(datas.get('warnings', []))
|
errors.extend(datas.get("errors", []))
|
||||||
|
warnings.extend(datas.get("warnings", []))
|
||||||
self._auto_configure_dynamics(values)
|
self._auto_configure_dynamics(values)
|
||||||
while values:
|
while values:
|
||||||
value_is_set = False
|
value_is_set = False
|
||||||
|
@ -116,21 +127,21 @@ class Rougail:
|
||||||
path = option.path()
|
path = option.path()
|
||||||
if path not in values:
|
if path not in values:
|
||||||
path = path.upper()
|
path = path.upper()
|
||||||
options = values.get(path, {}).get('options', {})
|
options = values.get(path, {}).get("options", {})
|
||||||
if path not in values or options.get('upper') is not True:
|
if path not in values or options.get("upper") is not True:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
options = values[path].get('options', {})
|
options = values[path].get("options", {})
|
||||||
value = values[path]["values"]
|
value = values[path]["values"]
|
||||||
if option.ismulti():
|
if option.ismulti():
|
||||||
if options.get('multi_separator') and not isinstance(value, list):
|
if options.get("multi_separator") and not isinstance(value, list):
|
||||||
value = value.split(options['multi_separator'])
|
value = value.split(options["multi_separator"])
|
||||||
values[path]["values"] = value
|
values[path]["values"] = value
|
||||||
if options.get('needs_convert'):
|
if options.get("needs_convert"):
|
||||||
value = [convert_value(option, val) for val in value]
|
value = [convert_value(option, val) for val in value]
|
||||||
values[path]["values"] = value
|
values[path]["values"] = value
|
||||||
values[path]["options"]["needs_convert"] = False
|
values[path]["options"]["needs_convert"] = False
|
||||||
elif options.get('needs_convert'):
|
elif options.get("needs_convert"):
|
||||||
value = convert_value(option, value)
|
value = convert_value(option, value)
|
||||||
index = option.index()
|
index = option.index()
|
||||||
if index is not None:
|
if index is not None:
|
||||||
|
@ -141,8 +152,8 @@ class Rougail:
|
||||||
option.value.set(value)
|
option.value.set(value)
|
||||||
value_is_set = True
|
value_is_set = True
|
||||||
if index is not None:
|
if index is not None:
|
||||||
values[path]['values'][index] = undefined
|
values[path]["values"][index] = undefined
|
||||||
if set(values[path]['values']) == {undefined}:
|
if set(values[path]["values"]) == {undefined}:
|
||||||
values.pop(path)
|
values.pop(path)
|
||||||
else:
|
else:
|
||||||
values.pop(path)
|
values.pop(path)
|
||||||
|
@ -154,7 +165,7 @@ class Rougail:
|
||||||
for path, data in values.items():
|
for path, data in values.items():
|
||||||
try:
|
try:
|
||||||
option = self.config.option(path)
|
option = self.config.option(path)
|
||||||
value = data['values']
|
value = data["values"]
|
||||||
if option.isfollower():
|
if option.isfollower():
|
||||||
for index, val in enumerate(value):
|
for index, val in enumerate(value):
|
||||||
if val is undefined:
|
if val is undefined:
|
||||||
|
@ -165,14 +176,15 @@ class Rougail:
|
||||||
except AttributeError as err:
|
except AttributeError as err:
|
||||||
errors.append(str(err))
|
errors.append(str(err))
|
||||||
except (ValueError, LeadershipError) as err:
|
except (ValueError, LeadershipError) as err:
|
||||||
#errors.append(str(err).replace('"', "'"))
|
# errors.append(str(err).replace('"', "'"))
|
||||||
errors.append(str(err))
|
errors.append(str(err))
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
# warnings.append(f'"{err}" but is defined in "{self.filename}"')
|
# warnings.append(f'"{err}" but is defined in "{self.filename}"')
|
||||||
warnings.append(str(err))
|
warnings.append(str(err))
|
||||||
return {'errors': errors,
|
return {
|
||||||
'warnings': warnings,
|
"errors": errors,
|
||||||
}
|
"warnings": warnings,
|
||||||
|
}
|
||||||
|
|
||||||
def _get_variable(self, config):
|
def _get_variable(self, config):
|
||||||
for subconfig in config:
|
for subconfig in config:
|
||||||
|
@ -181,14 +193,15 @@ class Rougail:
|
||||||
else:
|
else:
|
||||||
yield subconfig
|
yield subconfig
|
||||||
|
|
||||||
def _auto_configure_dynamics(self,
|
def _auto_configure_dynamics(
|
||||||
values,
|
self,
|
||||||
):
|
values,
|
||||||
|
):
|
||||||
cache = {}
|
cache = {}
|
||||||
added = []
|
added = []
|
||||||
for path, data in list(values.items()):
|
for path, data in list(values.items()):
|
||||||
value = data['values']
|
value = data["values"]
|
||||||
# for value in data['values'].items():
|
# for value in data['values'].items():
|
||||||
try:
|
try:
|
||||||
option = self.config.option(path)
|
option = self.config.option(path)
|
||||||
option.name()
|
option.name()
|
||||||
|
@ -196,11 +209,11 @@ class Rougail:
|
||||||
pass
|
pass
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
config = self.config
|
config = self.config
|
||||||
current_path = ''
|
current_path = ""
|
||||||
identifiers = []
|
identifiers = []
|
||||||
for name in path.split('.')[:-1]:
|
for name in path.split(".")[:-1]:
|
||||||
if current_path:
|
if current_path:
|
||||||
current_path += '.'
|
current_path += "."
|
||||||
current_path += name
|
current_path += name
|
||||||
if current_path in cache:
|
if current_path in cache:
|
||||||
config, identifier = cache[current_path]
|
config, identifier = cache[current_path]
|
||||||
|
@ -213,66 +226,86 @@ class Rougail:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
for tconfig in config.list(uncalculated=True):
|
for tconfig in config.list(uncalculated=True):
|
||||||
if tconfig.isdynamic(only_self=True):
|
if tconfig.isdynamic(only_self=True):
|
||||||
identifier = self._get_identifier(tconfig.name(), name)
|
identifier = self._get_identifier(
|
||||||
|
tconfig.name(), name
|
||||||
|
)
|
||||||
if identifier is None:
|
if identifier is None:
|
||||||
continue
|
continue
|
||||||
dynamic_variable = tconfig.information.get('dynamic_variable',
|
dynamic_variable = tconfig.information.get(
|
||||||
None,
|
"dynamic_variable",
|
||||||
)
|
None,
|
||||||
|
)
|
||||||
if not dynamic_variable:
|
if not dynamic_variable:
|
||||||
continue
|
continue
|
||||||
option_type = self.config.option(dynamic_variable).information.get('type')
|
option_type = self.config.option(
|
||||||
|
dynamic_variable
|
||||||
|
).information.get("type")
|
||||||
if identifiers:
|
if identifiers:
|
||||||
for s in identifiers:
|
for s in identifiers:
|
||||||
dynamic_variable = dynamic_variable.replace('{{ identifier }}', str(s), 1)
|
dynamic_variable = dynamic_variable.replace(
|
||||||
|
"{{ identifier }}", str(s), 1
|
||||||
|
)
|
||||||
if dynamic_variable not in values:
|
if dynamic_variable not in values:
|
||||||
values[dynamic_variable] = {'values': []}
|
values[dynamic_variable] = {"values": []}
|
||||||
added.append(dynamic_variable)
|
added.append(dynamic_variable)
|
||||||
elif dynamic_variable not in added:
|
elif dynamic_variable not in added:
|
||||||
continue
|
continue
|
||||||
config = tconfig
|
config = tconfig
|
||||||
# option_type = option.information.get('type')
|
# option_type = option.information.get('type')
|
||||||
typ = CONVERT_OPTION.get(option_type, {}).get("func")
|
typ = CONVERT_OPTION.get(option_type, {}).get(
|
||||||
|
"func"
|
||||||
|
)
|
||||||
if typ:
|
if typ:
|
||||||
identifier = typ(identifier)
|
identifier = typ(identifier)
|
||||||
if identifier not in values[dynamic_variable]['values']:
|
if (
|
||||||
values[dynamic_variable]['values'].append(identifier)
|
identifier
|
||||||
|
not in values[dynamic_variable]["values"]
|
||||||
|
):
|
||||||
|
values[dynamic_variable]["values"].append(
|
||||||
|
identifier
|
||||||
|
)
|
||||||
identifiers.append(identifier)
|
identifiers.append(identifier)
|
||||||
cache[current_path] = config, identifier
|
cache[current_path] = config, identifier
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if option.isdynamic():
|
if option.isdynamic():
|
||||||
parent_option = self.config.option(path.rsplit('.', 1)[0])
|
parent_option = self.config.option(path.rsplit(".", 1)[0])
|
||||||
identifiers = self._get_identifier(parent_option.name(uncalculated=True),
|
identifiers = self._get_identifier(
|
||||||
parent_option.name(),
|
parent_option.name(uncalculated=True),
|
||||||
)
|
parent_option.name(),
|
||||||
|
)
|
||||||
dynamic_variable = None
|
dynamic_variable = None
|
||||||
while True:
|
while True:
|
||||||
dynamic_variable = parent_option.information.get('dynamic_variable',
|
dynamic_variable = parent_option.information.get(
|
||||||
None,
|
"dynamic_variable",
|
||||||
)
|
None,
|
||||||
|
)
|
||||||
if dynamic_variable:
|
if dynamic_variable:
|
||||||
break
|
break
|
||||||
parent_option = self.config.option(parent_option.path().rsplit('.', 1)[0])
|
parent_option = self.config.option(
|
||||||
if '.' not in parent_option.path():
|
parent_option.path().rsplit(".", 1)[0]
|
||||||
|
)
|
||||||
|
if "." not in parent_option.path():
|
||||||
parent_option = None
|
parent_option = None
|
||||||
break
|
break
|
||||||
if not parent_option:
|
if not parent_option:
|
||||||
continue
|
continue
|
||||||
identifiers = parent_option.identifiers()
|
identifiers = parent_option.identifiers()
|
||||||
for identifier in identifiers:
|
for identifier in identifiers:
|
||||||
dynamic_variable = dynamic_variable.replace('{{ identifier }}', str(identifier), 1)
|
dynamic_variable = dynamic_variable.replace(
|
||||||
|
"{{ identifier }}", str(identifier), 1
|
||||||
|
)
|
||||||
if dynamic_variable not in values:
|
if dynamic_variable not in values:
|
||||||
values[dynamic_variable] = {'values': []}
|
values[dynamic_variable] = {"values": []}
|
||||||
added.append(dynamic_variable)
|
added.append(dynamic_variable)
|
||||||
elif dynamic_variable not in added:
|
elif dynamic_variable not in added:
|
||||||
continue
|
continue
|
||||||
option_type = option.information.get('type')
|
option_type = option.information.get("type")
|
||||||
typ = CONVERT_OPTION.get(option_type, {}).get("func")
|
typ = CONVERT_OPTION.get(option_type, {}).get("func")
|
||||||
if typ:
|
if typ:
|
||||||
identifier = typ(identifier)
|
identifier = typ(identifier)
|
||||||
if identifier not in values[dynamic_variable]['values']:
|
if identifier not in values[dynamic_variable]["values"]:
|
||||||
values[dynamic_variable]['values'].append(identifier)
|
values[dynamic_variable]["values"].append(identifier)
|
||||||
cache[option.path()] = option, identifier
|
cache[option.path()] = option, identifier
|
||||||
|
|
||||||
def _get_identifier(self, true_name, name) -> str:
|
def _get_identifier(self, true_name, name) -> str:
|
||||||
|
@ -282,10 +315,11 @@ class Rougail:
|
||||||
return
|
return
|
||||||
return finded[0]
|
return finded[0]
|
||||||
|
|
||||||
|
|
||||||
def convert_value(option, value):
|
def convert_value(option, value):
|
||||||
if value == '':
|
if value == "":
|
||||||
return None
|
return None
|
||||||
option_type = option.information.get('type')
|
option_type = option.information.get("type")
|
||||||
func = CONVERT_OPTION.get(option_type, {}).get("func")
|
func = CONVERT_OPTION.get(option_type, {}).get("func")
|
||||||
if func:
|
if func:
|
||||||
return func(value)
|
return func(value)
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import importlib.resources
|
import importlib.resources
|
||||||
from os.path import isfile
|
from os.path import isfile
|
||||||
from ..utils import load_modules
|
from ..utils import load_modules
|
||||||
|
@ -68,20 +69,20 @@ class SpaceAnnotator: # pylint: disable=R0903
|
||||||
get_annotators(ANNOTATORS, extra_annotator)
|
get_annotators(ANNOTATORS, extra_annotator)
|
||||||
for plugin in objectspace.plugins:
|
for plugin in objectspace.plugins:
|
||||||
try:
|
try:
|
||||||
get_annotators(ANNOTATORS, f'rougail.{plugin}.annotator')
|
get_annotators(ANNOTATORS, f"rougail.{plugin}.annotator")
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
pass
|
pass
|
||||||
annotators = ANNOTATORS["rougail.annotator"].copy()
|
annotators = ANNOTATORS["rougail.annotator"].copy()
|
||||||
for extra_annotator in objectspace.extra_annotators:
|
for extra_annotator in objectspace.extra_annotators:
|
||||||
annotators.extend(ANNOTATORS[extra_annotator])
|
annotators.extend(ANNOTATORS[extra_annotator])
|
||||||
for plugin in objectspace.plugins:
|
for plugin in objectspace.plugins:
|
||||||
annotators.extend(ANNOTATORS[f'rougail.{plugin}.annotator'])
|
annotators.extend(ANNOTATORS[f"rougail.{plugin}.annotator"])
|
||||||
annotators = sorted(annotators, key=get_level)
|
annotators = sorted(annotators, key=get_level)
|
||||||
functions = {}
|
functions = {}
|
||||||
functions_files = objectspace.functions_files
|
functions_files = objectspace.functions_files
|
||||||
for functions_file in functions_files:
|
for functions_file in functions_files:
|
||||||
if isfile(functions_file):
|
if isfile(functions_file):
|
||||||
loaded_modules = load_modules('function_file', functions_file)
|
loaded_modules = load_modules("function_file", functions_file)
|
||||||
for function in dir(loaded_modules):
|
for function in dir(loaded_modules):
|
||||||
if function.startswith("_"):
|
if function.startswith("_"):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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 typing import Optional
|
from typing import Optional
|
||||||
from rougail.i18n import _
|
from rougail.i18n import _
|
||||||
from rougail.error import DictConsistencyError
|
from rougail.error import DictConsistencyError
|
||||||
|
@ -69,8 +70,7 @@ class Annotator(Walk):
|
||||||
self.family_description()
|
self.family_description()
|
||||||
if self.objectspace.modes_level:
|
if self.objectspace.modes_level:
|
||||||
self.modes = {
|
self.modes = {
|
||||||
name: Mode(idx)
|
name: Mode(idx) for idx, name in enumerate(self.objectspace.modes_level)
|
||||||
for idx, name in enumerate(self.objectspace.modes_level)
|
|
||||||
}
|
}
|
||||||
self.default_variable_mode = self.objectspace.default_variable_mode
|
self.default_variable_mode = self.objectspace.default_variable_mode
|
||||||
self.default_family_mode = self.objectspace.default_family_mode
|
self.default_family_mode = self.objectspace.default_family_mode
|
||||||
|
@ -100,7 +100,10 @@ class Annotator(Walk):
|
||||||
if isinstance(family, self.objectspace.family) and not self._has_variable(
|
if isinstance(family, self.objectspace.family) and not self._has_variable(
|
||||||
family.path
|
family.path
|
||||||
):
|
):
|
||||||
if self.objectspace.paths.default_namespace is None or "." in family.path:
|
if (
|
||||||
|
self.objectspace.paths.default_namespace is None
|
||||||
|
or "." in family.path
|
||||||
|
):
|
||||||
removed_families.append(family.path)
|
removed_families.append(family.path)
|
||||||
removed_families.reverse()
|
removed_families.reverse()
|
||||||
for family in removed_families:
|
for family in removed_families:
|
||||||
|
@ -122,10 +125,13 @@ class Annotator(Walk):
|
||||||
for family in self.get_families():
|
for family in self.get_families():
|
||||||
if not family.description:
|
if not family.description:
|
||||||
family.description = family.name
|
family.description = family.name
|
||||||
if family.type == 'dynamic' and isinstance(family.dynamic, VariableCalculation):
|
if family.type == "dynamic" and isinstance(
|
||||||
path = self.objectspace.paths.get_full_path(family.dynamic.variable,
|
family.dynamic, VariableCalculation
|
||||||
family.path,
|
):
|
||||||
)
|
path = self.objectspace.paths.get_full_path(
|
||||||
|
family.dynamic.variable,
|
||||||
|
family.path,
|
||||||
|
)
|
||||||
self.objectspace.informations.add(family.path, "dynamic_variable", path)
|
self.objectspace.informations.add(family.path, "dynamic_variable", path)
|
||||||
|
|
||||||
def change_modes(self):
|
def change_modes(self):
|
||||||
|
@ -153,14 +159,18 @@ class Annotator(Walk):
|
||||||
for family in families:
|
for family in families:
|
||||||
self._change_family_mode(family)
|
self._change_family_mode(family)
|
||||||
if self.objectspace.paths.default_namespace is None:
|
if self.objectspace.paths.default_namespace is None:
|
||||||
for variable_path in self.objectspace.parents['.']:
|
for variable_path in self.objectspace.parents["."]:
|
||||||
variable = self.objectspace.paths[variable_path]
|
variable = self.objectspace.paths[variable_path]
|
||||||
if variable.type == "symlink" or variable_path in self.objectspace.families:
|
if (
|
||||||
|
variable.type == "symlink"
|
||||||
|
or variable_path in self.objectspace.families
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
self._set_default_mode_variable(variable,
|
self._set_default_mode_variable(
|
||||||
self.default_variable_mode,
|
variable,
|
||||||
check_level=False,
|
self.default_variable_mode,
|
||||||
)
|
check_level=False,
|
||||||
|
)
|
||||||
|
|
||||||
def valid_mode(
|
def valid_mode(
|
||||||
self,
|
self,
|
||||||
|
@ -220,7 +230,7 @@ class Annotator(Walk):
|
||||||
self,
|
self,
|
||||||
variable: "self.objectspace.variable",
|
variable: "self.objectspace.variable",
|
||||||
family_mode: Optional[str],
|
family_mode: Optional[str],
|
||||||
check_level: bool=True,
|
check_level: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
# auto_save variable is set to 'basic' mode
|
# auto_save variable is set to 'basic' mode
|
||||||
# if its mode is not defined by the user
|
# if its mode is not defined by the user
|
||||||
|
@ -234,7 +244,11 @@ class Annotator(Walk):
|
||||||
and variable.path not in self.objectspace.default_multi
|
and variable.path not in self.objectspace.default_multi
|
||||||
):
|
):
|
||||||
variable_mode = self.objectspace.modes_level[0]
|
variable_mode = self.objectspace.modes_level[0]
|
||||||
if check_level and family_mode and self.modes[variable_mode] < self.modes[family_mode]:
|
if (
|
||||||
|
check_level
|
||||||
|
and family_mode
|
||||||
|
and self.modes[variable_mode] < self.modes[family_mode]
|
||||||
|
):
|
||||||
msg = _(
|
msg = _(
|
||||||
f'the variable "{variable.name}" is mandatory so in "{variable_mode}" mode '
|
f'the variable "{variable.name}" is mandatory so in "{variable_mode}" mode '
|
||||||
f'but family has the higher family mode "{family_mode}"'
|
f'but family has the higher family mode "{family_mode}"'
|
||||||
|
@ -261,9 +275,7 @@ class Annotator(Walk):
|
||||||
if leader == follower:
|
if leader == follower:
|
||||||
# it's a leader
|
# it's a leader
|
||||||
if not leader.mode:
|
if not leader.mode:
|
||||||
self._set_auto_mode(
|
self._set_auto_mode(leader, self.default_variable_mode)
|
||||||
leader, self.default_variable_mode
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
if self._has_mode(follower):
|
if self._has_mode(follower):
|
||||||
follower_mode = follower.mode
|
follower_mode = follower.mode
|
||||||
|
@ -310,8 +322,10 @@ class Annotator(Walk):
|
||||||
# set the lower variable mode to family
|
# set the lower variable mode to family
|
||||||
self._set_auto_mode(family, min_variable_mode)
|
self._set_auto_mode(family, min_variable_mode)
|
||||||
if self.modes[family.mode] < self.modes[min_variable_mode]:
|
if self.modes[family.mode] < self.modes[min_variable_mode]:
|
||||||
msg = _(f'the family "{family.name}" is in "{family.mode}" mode but variables and '
|
msg = _(
|
||||||
f'families inside have the higher modes "{min_variable_mode}"')
|
f'the family "{family.name}" is in "{family.mode}" mode but variables and '
|
||||||
|
f'families inside have the higher modes "{min_variable_mode}"'
|
||||||
|
)
|
||||||
raise DictConsistencyError(msg, 62, family.xmlfiles)
|
raise DictConsistencyError(msg, 62, family.xmlfiles)
|
||||||
|
|
||||||
def _change_variable_mode(
|
def _change_variable_mode(
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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 typing import Union
|
from typing import Union
|
||||||
from rougail.i18n import _
|
from rougail.i18n import _
|
||||||
from rougail.error import DictConsistencyError
|
from rougail.error import DictConsistencyError
|
||||||
|
@ -123,7 +124,7 @@ class Annotator(Walk):
|
||||||
value = []
|
value = []
|
||||||
for calculation in frozen:
|
for calculation in frozen:
|
||||||
calculation_copy = calculation.copy()
|
calculation_copy = calculation.copy()
|
||||||
calculation_copy.attribute_name = 'frozen'
|
calculation_copy.attribute_name = "frozen"
|
||||||
calculation_copy.ori_path = calculation_copy.path
|
calculation_copy.ori_path = calculation_copy.path
|
||||||
calculation_copy.path = path
|
calculation_copy.path = path
|
||||||
value.append(calculation_copy)
|
value.append(calculation_copy)
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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 rougail.annotator.variable import Walk
|
from rougail.annotator.variable import Walk
|
||||||
|
|
||||||
from rougail.i18n import _
|
from rougail.i18n import _
|
||||||
|
@ -55,7 +56,7 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
for variable in self.get_variables():
|
for variable in self.get_variables():
|
||||||
if variable.type == "symlink":
|
if variable.type == "symlink":
|
||||||
continue
|
continue
|
||||||
if variable.version != '1.0' and variable.type == 'port':
|
if variable.version != "1.0" and variable.type == "port":
|
||||||
self._convert_port(variable)
|
self._convert_port(variable)
|
||||||
self._convert_value(variable)
|
self._convert_value(variable)
|
||||||
|
|
||||||
|
@ -85,16 +86,16 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
else:
|
else:
|
||||||
if variable.path not in self.objectspace.leaders:
|
if variable.path not in self.objectspace.leaders:
|
||||||
if multi == "submulti":
|
if multi == "submulti":
|
||||||
self.objectspace.default_multi[
|
self.objectspace.default_multi[variable.path] = variable.default
|
||||||
variable.path
|
|
||||||
] = variable.default
|
|
||||||
variable.default = None
|
variable.default = None
|
||||||
else:
|
else:
|
||||||
self.objectspace.default_multi[variable.path] = variable.default[
|
self.objectspace.default_multi[variable.path] = (
|
||||||
0
|
variable.default[0]
|
||||||
]
|
)
|
||||||
elif variable.multi:
|
elif variable.multi:
|
||||||
msg = _(f'the variable "{variable.name}" is multi but has a non list default value')
|
msg = _(
|
||||||
|
f'the variable "{variable.name}" is multi but has a non list default value'
|
||||||
|
)
|
||||||
raise DictConsistencyError(msg, 12, variable.xmlfiles)
|
raise DictConsistencyError(msg, 12, variable.xmlfiles)
|
||||||
elif variable.path in self.objectspace.followers:
|
elif variable.path in self.objectspace.followers:
|
||||||
self.objectspace.default_multi[variable.path] = variable.default
|
self.objectspace.default_multi[variable.path] = variable.default
|
||||||
|
|
|
@ -66,15 +66,18 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
return
|
return
|
||||||
self.objectspace = objectspace
|
self.objectspace = objectspace
|
||||||
if self.objectspace.main_namespace:
|
if self.objectspace.main_namespace:
|
||||||
self.forbidden_name = [
|
self.forbidden_name = [self.objectspace.main_namespace]
|
||||||
self.objectspace.main_namespace
|
|
||||||
]
|
|
||||||
for extra in self.objectspace.extra_dictionaries:
|
for extra in self.objectspace.extra_dictionaries:
|
||||||
self.forbidden_name.append(extra)
|
self.forbidden_name.append(extra)
|
||||||
else:
|
else:
|
||||||
self.forbidden_name = []
|
self.forbidden_name = []
|
||||||
# default type inference from a default value with :term:`basic types`
|
# default type inference from a default value with :term:`basic types`
|
||||||
self.basic_types = {str: "string", int: "number", bool: "boolean", float: "float"}
|
self.basic_types = {
|
||||||
|
str: "string",
|
||||||
|
int: "number",
|
||||||
|
bool: "boolean",
|
||||||
|
float: "float",
|
||||||
|
}
|
||||||
self.verify_choices()
|
self.verify_choices()
|
||||||
self.convert_variable()
|
self.convert_variable()
|
||||||
self.convert_test()
|
self.convert_test()
|
||||||
|
@ -97,14 +100,12 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
variable.multi = False
|
variable.multi = False
|
||||||
if variable.type is None:
|
if variable.type is None:
|
||||||
variable.type = "string"
|
variable.type = "string"
|
||||||
self.objectspace.informations.add(
|
self.objectspace.informations.add(variable.path, "type", variable.type)
|
||||||
variable.path, "type", variable.type
|
|
||||||
)
|
|
||||||
self._convert_variable(variable)
|
self._convert_variable(variable)
|
||||||
|
|
||||||
def _convert_variable_inference(
|
def _convert_variable_inference(
|
||||||
self,
|
self,
|
||||||
variable,
|
variable,
|
||||||
) -> None:
|
) -> None:
|
||||||
# variable has no type
|
# variable has no type
|
||||||
if variable.type is None:
|
if variable.type is None:
|
||||||
|
@ -120,23 +121,32 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
tested_value = variable.default
|
tested_value = variable.default
|
||||||
variable.type = self.basic_types.get(type(tested_value), None)
|
variable.type = self.basic_types.get(type(tested_value), None)
|
||||||
# variable has no multi attribute
|
# variable has no multi attribute
|
||||||
if variable.multi is None and not (variable.type is None and isinstance(variable.default, VariableCalculation)):
|
if variable.multi is None and not (
|
||||||
|
variable.type is None and isinstance(variable.default, VariableCalculation)
|
||||||
|
):
|
||||||
if variable.path in self.objectspace.leaders:
|
if variable.path in self.objectspace.leaders:
|
||||||
variable.multi = True
|
variable.multi = True
|
||||||
else:
|
else:
|
||||||
variable.multi = isinstance(variable.default, list)
|
variable.multi = isinstance(variable.default, list)
|
||||||
|
|
||||||
def _default_variable_copy_informations(
|
def _default_variable_copy_informations(
|
||||||
self,
|
self,
|
||||||
variable,
|
variable,
|
||||||
) -> None:
|
) -> None:
|
||||||
# if a variable has a variable as default value, that means the type/params or multi should has same value
|
# if a variable has a variable as default value, that means the type/params or multi should has same value
|
||||||
if variable.type is not None or not isinstance(variable.default, VariableCalculation):
|
if variable.type is not None or not isinstance(
|
||||||
|
variable.default, VariableCalculation
|
||||||
|
):
|
||||||
return
|
return
|
||||||
# copy type and params
|
# copy type and params
|
||||||
calculated_variable_path = variable.default.variable
|
calculated_variable_path = variable.default.variable
|
||||||
calculated_variable, identifier = self.objectspace.paths.get_with_dynamic(
|
calculated_variable, identifier = self.objectspace.paths.get_with_dynamic(
|
||||||
calculated_variable_path, variable.default.path_prefix, variable.path, variable.version, variable.namespace, variable.xmlfiles
|
calculated_variable_path,
|
||||||
|
variable.default.path_prefix,
|
||||||
|
variable.path,
|
||||||
|
variable.version,
|
||||||
|
variable.namespace,
|
||||||
|
variable.xmlfiles,
|
||||||
)
|
)
|
||||||
if calculated_variable is None:
|
if calculated_variable is None:
|
||||||
return
|
return
|
||||||
|
@ -146,7 +156,11 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
# copy multi attribut
|
# copy multi attribut
|
||||||
if variable.multi is None:
|
if variable.multi is None:
|
||||||
calculated_path = calculated_variable.path
|
calculated_path = calculated_variable.path
|
||||||
if calculated_path in self.objectspace.leaders and variable.path in self.objectspace.followers and calculated_path.rsplit('.')[0] == variable.path.rsplit('.')[0]:
|
if (
|
||||||
|
calculated_path in self.objectspace.leaders
|
||||||
|
and variable.path in self.objectspace.followers
|
||||||
|
and calculated_path.rsplit(".")[0] == variable.path.rsplit(".")[0]
|
||||||
|
):
|
||||||
variable.multi = False
|
variable.multi = False
|
||||||
else:
|
else:
|
||||||
variable.multi = calculated_variable.multi
|
variable.multi = calculated_variable.multi
|
||||||
|
@ -171,11 +185,13 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
family = self.objectspace.paths[variable.path.rsplit(".", 1)[0]]
|
family = self.objectspace.paths[variable.path.rsplit(".", 1)[0]]
|
||||||
if variable.hidden:
|
if variable.hidden:
|
||||||
family.hidden = variable.hidden
|
family.hidden = variable.hidden
|
||||||
# elif family.hidden:
|
# elif family.hidden:
|
||||||
# variable.hidden = family.hidden
|
# variable.hidden = family.hidden
|
||||||
variable.hidden = None
|
variable.hidden = None
|
||||||
if variable.regexp is not None and variable.type != 'regexp':
|
if variable.regexp is not None and variable.type != "regexp":
|
||||||
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:
|
||||||
variable.mandatory = True
|
variable.mandatory = True
|
||||||
|
@ -215,10 +231,12 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
if variable.type is None and variable.choices:
|
if variable.type is None and variable.choices:
|
||||||
# choice type inference from the `choices` attribute
|
# choice type inference from the `choices` attribute
|
||||||
variable.type = "choice"
|
variable.type = "choice"
|
||||||
if variable.choices is not None and variable.type != 'choice':
|
if variable.choices is not None and variable.type != "choice":
|
||||||
msg = _(f'the variable "{variable.path}" has choices attribut but has not the "choice" type')
|
msg = _(
|
||||||
|
f'the variable "{variable.path}" has choices attribut but has not the "choice" type'
|
||||||
|
)
|
||||||
raise DictConsistencyError(msg, 11, variable.xmlfiles)
|
raise DictConsistencyError(msg, 11, variable.xmlfiles)
|
||||||
if variable.type != 'choice':
|
if variable.type != "choice":
|
||||||
continue
|
continue
|
||||||
if variable.default is None:
|
if variable.default is None:
|
||||||
continue
|
continue
|
||||||
|
@ -242,5 +260,7 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
if isinstance(value, Calculation):
|
if isinstance(value, Calculation):
|
||||||
continue
|
continue
|
||||||
if value not in choices:
|
if value not in choices:
|
||||||
msg = _(f'the variable "{variable.path}" has an unvalid default value "{value}" should be in {display_list(choices, separator="or", add_quote=True)}')
|
msg = _(
|
||||||
|
f'the variable "{variable.path}" has an unvalid default value "{value}" should be in {display_list(choices, separator="or", add_quote=True)}'
|
||||||
|
)
|
||||||
raise DictConsistencyError(msg, 26, variable.xmlfiles)
|
raise DictConsistencyError(msg, 26, variable.xmlfiles)
|
||||||
|
|
|
@ -28,6 +28,7 @@ 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 pathlib import Path
|
from pathlib import Path
|
||||||
from tiramisu import Config
|
from tiramisu import Config
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
|
@ -35,12 +36,14 @@ from .utils import _, load_modules, normalize_family
|
||||||
from .convert import RougailConvert
|
from .convert import RougailConvert
|
||||||
|
|
||||||
|
|
||||||
RENAMED = {'dictionaries_dir': 'main_dictionaries',
|
RENAMED = {
|
||||||
'variable_namespace': 'main_namespace',
|
"dictionaries_dir": "main_dictionaries",
|
||||||
'functions_file': 'functions_files',
|
"variable_namespace": "main_namespace",
|
||||||
}
|
"functions_file": "functions_files",
|
||||||
NOT_IN_TIRAMISU = {'custom_types': {},
|
}
|
||||||
}
|
NOT_IN_TIRAMISU = {
|
||||||
|
"custom_types": {},
|
||||||
|
}
|
||||||
SUBMODULES = None
|
SUBMODULES = None
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,29 +52,27 @@ def get_sub_modules():
|
||||||
if SUBMODULES is None:
|
if SUBMODULES is None:
|
||||||
SUBMODULES = {}
|
SUBMODULES = {}
|
||||||
for submodule in Path(__file__).parent.iterdir():
|
for submodule in Path(__file__).parent.iterdir():
|
||||||
if submodule.name.startswith('_') or not submodule.is_dir():
|
if submodule.name.startswith("_") or not submodule.is_dir():
|
||||||
continue
|
continue
|
||||||
config_file = submodule / 'config.py'
|
config_file = submodule / "config.py"
|
||||||
if config_file.is_file():
|
if config_file.is_file():
|
||||||
SUBMODULES[submodule.name] = load_modules('rougail.' + submodule.name + '.config', str(config_file))
|
SUBMODULES[submodule.name] = load_modules(
|
||||||
|
"rougail." + submodule.name + ".config", str(config_file)
|
||||||
|
)
|
||||||
return SUBMODULES
|
return SUBMODULES
|
||||||
|
|
||||||
|
|
||||||
def get_level(module):
|
def get_level(module):
|
||||||
return module['level']
|
return module["level"]
|
||||||
|
|
||||||
|
|
||||||
class _RougailConfig:
|
class _RougailConfig:
|
||||||
def __init__(self,
|
def __init__(self, backward_compatibility: bool, root, extra_vars: dict):
|
||||||
backward_compatibility: bool,
|
|
||||||
root,
|
|
||||||
extra_vars: dict
|
|
||||||
):
|
|
||||||
self.backward_compatibility = backward_compatibility
|
self.backward_compatibility = backward_compatibility
|
||||||
self.root = root
|
self.root = root
|
||||||
self.config = Config(
|
self.config = Config(
|
||||||
self.root,
|
self.root,
|
||||||
)
|
)
|
||||||
self.config.property.read_only()
|
self.config.property.read_only()
|
||||||
self.extra_vars = extra_vars
|
self.extra_vars = extra_vars
|
||||||
self.not_in_tiramisu = NOT_IN_TIRAMISU | extra_vars
|
self.not_in_tiramisu = NOT_IN_TIRAMISU | extra_vars
|
||||||
|
@ -81,7 +82,9 @@ class _RougailConfig:
|
||||||
setattr(self, variable, default_value)
|
setattr(self, variable, default_value)
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
rougailconfig = _RougailConfig(self.backward_compatibility, self.root, self.extra_vars)
|
rougailconfig = _RougailConfig(
|
||||||
|
self.backward_compatibility, self.root, self.extra_vars
|
||||||
|
)
|
||||||
rougailconfig.config.value.importation(self.config.value.exportation())
|
rougailconfig.config.value.importation(self.config.value.exportation())
|
||||||
rougailconfig.config.property.importation(self.config.property.exportation())
|
rougailconfig.config.property.importation(self.config.property.exportation())
|
||||||
rougailconfig.config.property.read_only()
|
rougailconfig.config.property.read_only()
|
||||||
|
@ -92,16 +95,17 @@ class _RougailConfig:
|
||||||
setattr(rougailconfig, variable, value)
|
setattr(rougailconfig, variable, value)
|
||||||
return rougailconfig
|
return rougailconfig
|
||||||
|
|
||||||
def __setitem__(self,
|
def __setitem__(
|
||||||
key,
|
self,
|
||||||
value,
|
key,
|
||||||
) -> None:
|
value,
|
||||||
|
) -> None:
|
||||||
if key in self.not_in_tiramisu:
|
if key in self.not_in_tiramisu:
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
else:
|
else:
|
||||||
self.config.property.read_write()
|
self.config.property.read_write()
|
||||||
if key == 'export_with_import':
|
if key == "export_with_import":
|
||||||
key = 'not_export_with_import'
|
key = "not_export_with_import"
|
||||||
key = RENAMED.get(key, key)
|
key = RENAMED.get(key, key)
|
||||||
option = self.config.option(key)
|
option = self.config.option(key)
|
||||||
if option.isoptiondescription() and option.isleadership():
|
if option.isoptiondescription() and option.isleadership():
|
||||||
|
@ -111,30 +115,29 @@ class _RougailConfig:
|
||||||
follower = option.followers()[0]
|
follower = option.followers()[0]
|
||||||
for idx, val in enumerate(value.values()):
|
for idx, val in enumerate(value.values()):
|
||||||
self.config.option(follower.path(), idx).value.set(val)
|
self.config.option(follower.path(), idx).value.set(val)
|
||||||
elif key == 'not_export_with_import':
|
elif key == "not_export_with_import":
|
||||||
option.value.set(not value)
|
option.value.set(not value)
|
||||||
else:
|
else:
|
||||||
option.value.set(value)
|
option.value.set(value)
|
||||||
self.config.property.read_only()
|
self.config.property.read_only()
|
||||||
|
|
||||||
def __getitem__(self,
|
def __getitem__(
|
||||||
key,
|
self,
|
||||||
) -> None:
|
key,
|
||||||
|
) -> None:
|
||||||
if key in self.not_in_tiramisu:
|
if key in self.not_in_tiramisu:
|
||||||
return getattr(self, key)
|
return getattr(self, key)
|
||||||
if key == 'export_with_import':
|
if key == "export_with_import":
|
||||||
key = 'not_export_with_import'
|
key = "not_export_with_import"
|
||||||
option = self.config.option(key)
|
option = self.config.option(key)
|
||||||
if option.isoptiondescription() and option.isleadership():
|
if option.isoptiondescription() and option.isleadership():
|
||||||
return self.get_leadership(option)
|
return self.get_leadership(option)
|
||||||
ret = self.config.option(key).value.get()
|
ret = self.config.option(key).value.get()
|
||||||
if key == 'not_export_with_import':
|
if key == "not_export_with_import":
|
||||||
return not ret
|
return not ret
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def get_leadership(self,
|
def get_leadership(self, option) -> dict:
|
||||||
option
|
|
||||||
) -> dict:
|
|
||||||
leader = None
|
leader = None
|
||||||
followers = []
|
followers = []
|
||||||
for opt, value in option.value.get().items():
|
for opt, value in option.value.get().items():
|
||||||
|
@ -151,7 +154,7 @@ class _RougailConfig:
|
||||||
if option.isoptiondescription():
|
if option.isoptiondescription():
|
||||||
yield from self.parse(option)
|
yield from self.parse(option)
|
||||||
elif not option.issymlinkoption():
|
elif not option.issymlinkoption():
|
||||||
yield f'{option.path()}: {option.value.get()}'
|
yield f"{option.path()}: {option.value.get()}"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
self.config.property.read_write()
|
self.config.property.read_write()
|
||||||
|
@ -164,16 +167,17 @@ class _RougailConfig:
|
||||||
|
|
||||||
|
|
||||||
class FakeRougailConvert(RougailConvert):
|
class FakeRougailConvert(RougailConvert):
|
||||||
def __init__(self,
|
def __init__(
|
||||||
add_extra_options: bool,
|
self,
|
||||||
) -> None:
|
add_extra_options: bool,
|
||||||
|
) -> None:
|
||||||
self.add_extra_options = add_extra_options
|
self.add_extra_options = add_extra_options
|
||||||
super().__init__({})
|
super().__init__({})
|
||||||
|
|
||||||
def load_config(self) -> None:
|
def load_config(self) -> None:
|
||||||
self.sort_dictionaries_all = False
|
self.sort_dictionaries_all = False
|
||||||
self.main_namespace = None
|
self.main_namespace = None
|
||||||
self.suffix = ''
|
self.suffix = ""
|
||||||
self.custom_types = {}
|
self.custom_types = {}
|
||||||
self.functions_files = []
|
self.functions_files = []
|
||||||
self.modes_level = []
|
self.modes_level = []
|
||||||
|
@ -181,18 +185,19 @@ class FakeRougailConvert(RougailConvert):
|
||||||
self.base_option_name = "baseoption"
|
self.base_option_name = "baseoption"
|
||||||
self.export_with_import = True
|
self.export_with_import = True
|
||||||
self.internal_functions = []
|
self.internal_functions = []
|
||||||
self.plugins = ['structural_commandline']
|
self.plugins = ["structural_commandline"]
|
||||||
self.add_extra_options = self.add_extra_options
|
self.add_extra_options = self.add_extra_options
|
||||||
|
|
||||||
|
|
||||||
def get_rougail_config(*,
|
def get_rougail_config(
|
||||||
backward_compatibility: bool=True,
|
*,
|
||||||
add_extra_options: bool=True,
|
backward_compatibility: bool = True,
|
||||||
) -> _RougailConfig:
|
add_extra_options: bool = True,
|
||||||
|
) -> _RougailConfig:
|
||||||
if backward_compatibility:
|
if backward_compatibility:
|
||||||
main_namespace_default = 'rougail'
|
main_namespace_default = "rougail"
|
||||||
else:
|
else:
|
||||||
main_namespace_default = 'null'
|
main_namespace_default = "null"
|
||||||
rougail_options = f"""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
|
||||||
|
@ -386,13 +391,14 @@ suffix:
|
||||||
mandatory: false
|
mandatory: false
|
||||||
commandline: false
|
commandline: false
|
||||||
"""
|
"""
|
||||||
processes = {'structural': [],
|
processes = {
|
||||||
'output': [],
|
"structural": [],
|
||||||
'user data': [],
|
"output": [],
|
||||||
}
|
"user data": [],
|
||||||
|
}
|
||||||
for module in get_sub_modules().values():
|
for module in get_sub_modules().values():
|
||||||
data = module.get_rougail_config()
|
data = module.get_rougail_config()
|
||||||
processes[data['process']].append(data)
|
processes[data["process"]].append(data)
|
||||||
# reorder
|
# reorder
|
||||||
for process in processes:
|
for process in processes:
|
||||||
processes[process] = list(sorted(processes[process], key=get_level))
|
processes[process] = list(sorted(processes[process], key=get_level))
|
||||||
|
@ -407,17 +413,22 @@ suffix:
|
||||||
description: Select for {NAME}
|
description: Select for {NAME}
|
||||||
alternative_name: {NAME[0]}
|
alternative_name: {NAME[0]}
|
||||||
choices:
|
choices:
|
||||||
""".format(NAME=normalize_family(process),
|
""".format(
|
||||||
)
|
NAME=normalize_family(process),
|
||||||
|
)
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
rougail_process += f" - {obj['name']}\n"
|
rougail_process += f" - {obj['name']}\n"
|
||||||
if process == 'structural':
|
if process == "structural":
|
||||||
rougail_process += " commandline: false"
|
rougail_process += " commandline: false"
|
||||||
elif process == 'user data':
|
elif process == "user data":
|
||||||
rougail_process += """ multi: true
|
rougail_process += """ multi: true
|
||||||
mandatory: false
|
mandatory: false
|
||||||
"""
|
"""
|
||||||
hidden_outputs = [process['name'] for process in processes['output'] if not process.get('allow_user_data', True)]
|
hidden_outputs = [
|
||||||
|
process["name"]
|
||||||
|
for process in processes["output"]
|
||||||
|
if not process.get("allow_user_data", True)
|
||||||
|
]
|
||||||
if hidden_outputs:
|
if hidden_outputs:
|
||||||
rougail_process += """ hidden:
|
rougail_process += """ hidden:
|
||||||
type: jinja
|
type: jinja
|
||||||
|
@ -427,9 +438,13 @@ suffix:
|
||||||
rougail_process += """ {% if _.output == 'NAME' %}
|
rougail_process += """ {% if _.output == 'NAME' %}
|
||||||
Cannot load user data for NAME output
|
Cannot load user data for NAME output
|
||||||
{% endif %}
|
{% endif %}
|
||||||
""".replace('NAME', hidden_output)
|
""".replace(
|
||||||
|
"NAME", hidden_output
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
rougail_process += ' default: {DEFAULT}'.format(DEFAULT=objects[0]['name'])
|
rougail_process += " default: {DEFAULT}".format(
|
||||||
|
DEFAULT=objects[0]["name"]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
rougail_process += """
|
rougail_process += """
|
||||||
{NAME}:
|
{NAME}:
|
||||||
|
@ -437,39 +452,41 @@ suffix:
|
||||||
hidden: true
|
hidden: true
|
||||||
mandatory: false
|
mandatory: false
|
||||||
multi: true
|
multi: true
|
||||||
""".format(NAME=normalize_family(process),
|
""".format(
|
||||||
)
|
NAME=normalize_family(process),
|
||||||
|
)
|
||||||
rougail_options += rougail_process
|
rougail_options += rougail_process
|
||||||
convert = FakeRougailConvert(add_extra_options)
|
convert = FakeRougailConvert(add_extra_options)
|
||||||
convert._init()
|
convert._init()
|
||||||
convert.namespace = None
|
convert.namespace = None
|
||||||
convert.parse_root_file(
|
convert.parse_root_file(
|
||||||
'rougail.config',
|
"rougail.config",
|
||||||
'',
|
"",
|
||||||
'1.1',
|
"1.1",
|
||||||
YAML().load(rougail_options),
|
YAML().load(rougail_options),
|
||||||
)
|
)
|
||||||
extra_vars = {}
|
extra_vars = {}
|
||||||
for process in processes:
|
for process in processes:
|
||||||
for obj in processes[process]:
|
for obj in processes[process]:
|
||||||
if 'extra_vars' in obj:
|
if "extra_vars" in obj:
|
||||||
extra_vars |= obj['extra_vars']
|
extra_vars |= obj["extra_vars"]
|
||||||
if not 'options' in obj:
|
if not "options" in obj:
|
||||||
continue
|
continue
|
||||||
convert.parse_root_file(
|
convert.parse_root_file(
|
||||||
f'rougail.config.{obj["name"]}',
|
f'rougail.config.{obj["name"]}',
|
||||||
'',
|
"",
|
||||||
'1.1',
|
"1.1",
|
||||||
YAML().load(obj['options']),
|
YAML().load(obj["options"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
tiram_obj = convert.save(None)
|
tiram_obj = convert.save(None)
|
||||||
optiondescription = {}
|
optiondescription = {}
|
||||||
exec(tiram_obj, {}, optiondescription) # pylint: disable=W0122
|
exec(tiram_obj, {}, optiondescription) # pylint: disable=W0122
|
||||||
return _RougailConfig(backward_compatibility,
|
return _RougailConfig(
|
||||||
optiondescription["option_0"],
|
backward_compatibility,
|
||||||
extra_vars=extra_vars,
|
optiondescription["option_0"],
|
||||||
)
|
extra_vars=extra_vars,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
RougailConfig = get_rougail_config()
|
RougailConfig = get_rougail_config()
|
||||||
|
|
|
@ -28,6 +28,7 @@ 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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -133,10 +134,11 @@ class Paths:
|
||||||
if not force and is_dynamic:
|
if not force and is_dynamic:
|
||||||
self._dynamics[path] = dynamic
|
self._dynamics[path] = dynamic
|
||||||
|
|
||||||
def get_full_path(self,
|
def get_full_path(
|
||||||
path: str,
|
self,
|
||||||
current_path: str,
|
path: str,
|
||||||
):
|
current_path: str,
|
||||||
|
):
|
||||||
relative, subpath = path.split(".", 1)
|
relative, subpath = path.split(".", 1)
|
||||||
relative_len = len(relative)
|
relative_len = len(relative)
|
||||||
path_len = current_path.count(".")
|
path_len = current_path.count(".")
|
||||||
|
@ -155,15 +157,20 @@ class Paths:
|
||||||
xmlfiles: List[str],
|
xmlfiles: List[str],
|
||||||
) -> Any:
|
) -> Any:
|
||||||
identifier = 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_full_path(path,
|
path = self.get_full_path(
|
||||||
current_path,
|
path,
|
||||||
)
|
current_path,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
path = get_realpath(path, identifier_path)
|
path = get_realpath(path, identifier_path)
|
||||||
dynamic = None
|
dynamic = None
|
||||||
# version 1.0
|
# version 1.0
|
||||||
if version == "1.0" and not path in self._data and "{{ identifier }}" not in path:
|
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("."):
|
||||||
|
@ -179,7 +186,7 @@ class Paths:
|
||||||
new_path = name
|
new_path = name
|
||||||
continue
|
continue
|
||||||
for dynamic_path in self._dynamics:
|
for dynamic_path in self._dynamics:
|
||||||
if '.' in dynamic_path:
|
if "." in dynamic_path:
|
||||||
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
|
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
|
||||||
else:
|
else:
|
||||||
parent_dynamic = None
|
parent_dynamic = None
|
||||||
|
@ -216,7 +223,7 @@ class Paths:
|
||||||
parent_path = current_path
|
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:
|
||||||
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
|
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
|
||||||
else:
|
else:
|
||||||
parent_dynamic = None
|
parent_dynamic = None
|
||||||
|
@ -350,7 +357,7 @@ class ParserVariable:
|
||||||
|
|
||||||
def load_config(self) -> None:
|
def load_config(self) -> None:
|
||||||
rougailconfig = self.rougailconfig
|
rougailconfig = self.rougailconfig
|
||||||
self.sort_dictionaries_all = rougailconfig['sort_dictionaries_all']
|
self.sort_dictionaries_all = rougailconfig["sort_dictionaries_all"]
|
||||||
try:
|
try:
|
||||||
self.main_dictionaries = rougailconfig["main_dictionaries"]
|
self.main_dictionaries = rougailconfig["main_dictionaries"]
|
||||||
except:
|
except:
|
||||||
|
@ -359,7 +366,9 @@ class ParserVariable:
|
||||||
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"]
|
||||||
self.default_dictionary_format_version = rougailconfig["default_dictionary_format_version"]
|
self.default_dictionary_format_version = rougailconfig[
|
||||||
|
"default_dictionary_format_version"
|
||||||
|
]
|
||||||
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"]
|
||||||
|
@ -370,7 +379,9 @@ class ParserVariable:
|
||||||
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 = rougailconfig["plugins"]
|
self.plugins = rougailconfig["plugins"]
|
||||||
|
|
||||||
def _init(self):
|
def _init(self):
|
||||||
|
@ -381,14 +392,22 @@ class ParserVariable:
|
||||||
if self.plugins:
|
if self.plugins:
|
||||||
root = Path(__file__).parent
|
root = Path(__file__).parent
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
module_path = root / plugin / 'object_model.py'
|
module_path = root / plugin / "object_model.py"
|
||||||
if not module_path.is_file():
|
if not module_path.is_file():
|
||||||
continue
|
continue
|
||||||
module = load_modules(f'rougail.{plugin}.object_model', str(module_path))
|
module = load_modules(
|
||||||
if 'Variable' in module.__all__:
|
f"rougail.{plugin}.object_model", str(module_path)
|
||||||
variable = type(variable.__name__ + '_' + plugin, (variable, module.Variable), {})
|
)
|
||||||
if 'Family' in module.__all__:
|
if "Variable" in module.__all__:
|
||||||
family = type(family.__name__ + '_' + plugin, (family, module.Family), {})
|
variable = type(
|
||||||
|
variable.__name__ + "_" + plugin,
|
||||||
|
(variable, module.Variable),
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
if "Family" in module.__all__:
|
||||||
|
family = type(
|
||||||
|
family.__name__ + "_" + plugin, (family, module.Family), {}
|
||||||
|
)
|
||||||
self.variable = variable
|
self.variable = variable
|
||||||
self.family = family
|
self.family = family
|
||||||
self.dynamic = type(Dynamic.__name__, (Dynamic, family), {})
|
self.dynamic = type(Dynamic.__name__, (Dynamic, family), {})
|
||||||
|
@ -604,26 +623,26 @@ class ParserVariable:
|
||||||
obj_type = self.get_family_or_variable_type(family_obj)
|
obj_type = self.get_family_or_variable_type(family_obj)
|
||||||
if obj_type is None:
|
if obj_type is None:
|
||||||
# auto set type
|
# auto set type
|
||||||
if '_dynamic' in family_obj:
|
if "_dynamic" in family_obj:
|
||||||
dynamic = family_obj['_dynamic']
|
dynamic = family_obj["_dynamic"]
|
||||||
elif 'dynamic' in family_obj:
|
elif "dynamic" in family_obj:
|
||||||
dynamic = family_obj['dynamic']
|
dynamic = family_obj["dynamic"]
|
||||||
else:
|
else:
|
||||||
dynamic = None
|
dynamic = None
|
||||||
if isinstance(dynamic, (list, dict)):
|
if isinstance(dynamic, (list, dict)):
|
||||||
family_obj['type'] = obj_type = 'dynamic'
|
family_obj["type"] = obj_type = "dynamic"
|
||||||
if obj_type == "dynamic":
|
if obj_type == "dynamic":
|
||||||
family_is_dynamic = True
|
family_is_dynamic = True
|
||||||
parent_dynamic = path
|
parent_dynamic = path
|
||||||
if '{{ identifier }}' not in name:
|
if "{{ identifier }}" not in name:
|
||||||
if "variable" in family_obj:
|
if "variable" in family_obj:
|
||||||
name += '{{ identifier }}'
|
name += "{{ identifier }}"
|
||||||
path += '{{ identifier }}'
|
path += "{{ identifier }}"
|
||||||
else:
|
else:
|
||||||
msg = f'dynamic family name must have "{{{{ identifier }}}}" 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
|
||||||
self.add_family(
|
self.add_family(
|
||||||
path,
|
path,
|
||||||
name,
|
name,
|
||||||
|
@ -679,7 +698,11 @@ class ParserVariable:
|
||||||
# it's a dict, so a new variables!
|
# it's a dict, so a new variables!
|
||||||
continue
|
continue
|
||||||
# 'variable' for compatibility to format 1.0
|
# 'variable' for compatibility to format 1.0
|
||||||
if key == "variable" and obj.get("type") != "dynamic" and obj.get("_type") != "dynamic":
|
if (
|
||||||
|
key == "variable"
|
||||||
|
and obj.get("type") != "dynamic"
|
||||||
|
and obj.get("_type") != "dynamic"
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
if key in self.family_attrs:
|
if key in self.family_attrs:
|
||||||
yield key
|
yield key
|
||||||
|
@ -724,17 +747,20 @@ class ParserVariable:
|
||||||
del family["variable"]
|
del family["variable"]
|
||||||
# FIXME only for 1.0
|
# FIXME only for 1.0
|
||||||
if "variable" in family:
|
if "variable" in family:
|
||||||
family['dynamic'] = {'type': 'variable',
|
family["dynamic"] = {
|
||||||
'variable': family['variable'],
|
"type": "variable",
|
||||||
'propertyerror': False,
|
"variable": family["variable"],
|
||||||
'allow_none': True,
|
"propertyerror": False,
|
||||||
}
|
"allow_none": True,
|
||||||
del family['variable']
|
}
|
||||||
|
del family["variable"]
|
||||||
if version != "1.0":
|
if version != "1.0":
|
||||||
warning = f'"variable" attribute in dynamic family "{ path }" is depreciated in {filename}'
|
warning = f'"variable" attribute in dynamic family "{ path }" is depreciated in {filename}'
|
||||||
warn(warning)
|
warn(warning)
|
||||||
if "variable" in family:
|
if "variable" in family:
|
||||||
raise Exception(f'dynamic family must not have "variable" attribute for "{family["path"]}" in {family["xmlfiles"]}')
|
raise Exception(
|
||||||
|
f'dynamic family must not have "variable" attribute for "{family["path"]}" in {family["xmlfiles"]}'
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
family_obj = self.family
|
family_obj = self.family
|
||||||
# convert to Calculation objects
|
# convert to Calculation objects
|
||||||
|
@ -969,7 +995,7 @@ class ParserVariable:
|
||||||
parent_dynamic,
|
parent_dynamic,
|
||||||
)
|
)
|
||||||
self.variables.append(variable["path"])
|
self.variables.append(variable["path"])
|
||||||
if '.' in variable["path"]:
|
if "." in variable["path"]:
|
||||||
parent_path = variable["path"].rsplit(".", 1)[0]
|
parent_path = variable["path"].rsplit(".", 1)[0]
|
||||||
else:
|
else:
|
||||||
parent_path = "."
|
parent_path = "."
|
||||||
|
@ -987,10 +1013,10 @@ class ParserVariable:
|
||||||
del self.paths[path]
|
del self.paths[path]
|
||||||
self.families.remove(path)
|
self.families.remove(path)
|
||||||
del self.parents[path]
|
del self.parents[path]
|
||||||
if '.' in path:
|
if "." in path:
|
||||||
parent = path.rsplit(".", 1)[0]
|
parent = path.rsplit(".", 1)[0]
|
||||||
else:
|
else:
|
||||||
parent = '.'
|
parent = "."
|
||||||
self.parents[parent].remove(path)
|
self.parents[parent].remove(path)
|
||||||
|
|
||||||
###############################################################################################
|
###############################################################################################
|
||||||
|
@ -1003,9 +1029,7 @@ class ParserVariable:
|
||||||
):
|
):
|
||||||
"""Set Tiramisu object name"""
|
"""Set Tiramisu object name"""
|
||||||
self.index += 1
|
self.index += 1
|
||||||
self.reflector_names[
|
self.reflector_names[obj.path] = f"{option_prefix}{self.index}{self.suffix}"
|
||||||
obj.path
|
|
||||||
] = f'{option_prefix}{self.index}{self.suffix}'
|
|
||||||
|
|
||||||
###############################################################################################
|
###############################################################################################
|
||||||
# calculations
|
# calculations
|
||||||
|
@ -1024,12 +1048,12 @@ class ParserVariable:
|
||||||
calculations = calculations[1]
|
calculations = calculations[1]
|
||||||
if not isinstance(value, dict) or attribute not in calculations:
|
if not isinstance(value, dict) or attribute not in calculations:
|
||||||
return False
|
return False
|
||||||
if 'type' in value:
|
if "type" in value:
|
||||||
return value['type'] in CALCULATION_TYPES
|
return value["type"] in CALCULATION_TYPES
|
||||||
# auto set type
|
# auto set type
|
||||||
typ = set(CALCULATION_TYPES) & set(value)
|
typ = set(CALCULATION_TYPES) & set(value)
|
||||||
if len(typ) == 1:
|
if len(typ) == 1:
|
||||||
value['type'] = list(typ)[0]
|
value["type"] = list(typ)[0]
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1068,7 +1092,7 @@ class ParserVariable:
|
||||||
# auto set type
|
# auto set type
|
||||||
param_typ = set(CALCULATION_TYPES) & set(val)
|
param_typ = set(CALCULATION_TYPES) & set(val)
|
||||||
if len(param_typ) == 1:
|
if len(param_typ) == 1:
|
||||||
val['type'] = list(param_typ)[0]
|
val["type"] = list(param_typ)[0]
|
||||||
if not isinstance(val, dict) or "type" not in val:
|
if not isinstance(val, dict) or "type" not in val:
|
||||||
param_typ = "any"
|
param_typ = "any"
|
||||||
val = {
|
val = {
|
||||||
|
@ -1087,7 +1111,9 @@ class ParserVariable:
|
||||||
params.append(PARAM_TYPES[param_typ](**val))
|
params.append(PARAM_TYPES[param_typ](**val))
|
||||||
except ValidationError as err:
|
except ValidationError as err:
|
||||||
raise DictConsistencyError(
|
raise DictConsistencyError(
|
||||||
f'"{attribute}" has an invalid "{key}" for {path}: {err}', 29, xmlfiles
|
f'"{attribute}" has an invalid "{key}" for {path}: {err}',
|
||||||
|
29,
|
||||||
|
xmlfiles,
|
||||||
) from err
|
) from err
|
||||||
calculation_object["params"] = params
|
calculation_object["params"] = params
|
||||||
#
|
#
|
||||||
|
@ -1164,11 +1190,11 @@ class RougailConvert(ParserVariable):
|
||||||
self.add_family(
|
self.add_family(
|
||||||
n_path_prefix,
|
n_path_prefix,
|
||||||
n_path_prefix,
|
n_path_prefix,
|
||||||
{'description': path_prefix},
|
{"description": path_prefix},
|
||||||
"",
|
"",
|
||||||
False,
|
False,
|
||||||
None,
|
None,
|
||||||
'',
|
"",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
root_parent = "."
|
root_parent = "."
|
||||||
|
@ -1196,12 +1222,13 @@ class RougailConvert(ParserVariable):
|
||||||
for idx, filename in enumerate(self.get_sorted_filename(extra_dirs)):
|
for idx, filename in enumerate(self.get_sorted_filename(extra_dirs)):
|
||||||
if not idx:
|
if not idx:
|
||||||
self.parse_family(
|
self.parse_family(
|
||||||
'',
|
"",
|
||||||
self.namespace,
|
self.namespace,
|
||||||
namespace_path,
|
namespace_path,
|
||||||
{'description': namespace,
|
{
|
||||||
},
|
"description": namespace,
|
||||||
'',
|
},
|
||||||
|
"",
|
||||||
)
|
)
|
||||||
self.parse_variable_file(
|
self.parse_variable_file(
|
||||||
filename,
|
filename,
|
||||||
|
@ -1210,7 +1237,7 @@ class RougailConvert(ParserVariable):
|
||||||
else:
|
else:
|
||||||
self.namespace = None
|
self.namespace = None
|
||||||
if root_parent == ".":
|
if root_parent == ".":
|
||||||
namespace_path = ''
|
namespace_path = ""
|
||||||
else:
|
else:
|
||||||
namespace_path = f"{root_parent}"
|
namespace_path = f"{root_parent}"
|
||||||
if namespace_path in self.parents:
|
if namespace_path in self.parents:
|
||||||
|
@ -1250,18 +1277,20 @@ class RougailConvert(ParserVariable):
|
||||||
)
|
)
|
||||||
if objects is None:
|
if objects is None:
|
||||||
return
|
return
|
||||||
self.parse_root_file(filename,
|
self.parse_root_file(
|
||||||
path,
|
filename,
|
||||||
version,
|
path,
|
||||||
objects,
|
version,
|
||||||
)
|
objects,
|
||||||
|
)
|
||||||
|
|
||||||
def parse_root_file(self,
|
def parse_root_file(
|
||||||
filename: str,
|
self,
|
||||||
path: str,
|
filename: str,
|
||||||
version: str,
|
path: str,
|
||||||
objects: dict,
|
version: str,
|
||||||
) -> None:
|
objects: dict,
|
||||||
|
) -> None:
|
||||||
for name, obj in objects.items():
|
for name, obj in objects.items():
|
||||||
comment = self.get_comment(name, objects)
|
comment = self.get_comment(name, objects)
|
||||||
self.family_or_variable(
|
self.family_or_variable(
|
||||||
|
@ -1367,5 +1396,5 @@ class RougailConvert(ParserVariable):
|
||||||
if filename:
|
if filename:
|
||||||
with open(filename, "w", encoding="utf-8") as tiramisu:
|
with open(filename, "w", encoding="utf-8") as tiramisu:
|
||||||
tiramisu.write(output)
|
tiramisu.write(output)
|
||||||
#print(output)
|
# print(output)
|
||||||
return output
|
return output
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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 .i18n import _
|
from .i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,13 +75,17 @@ class DictConsistencyError(Exception):
|
||||||
class UpgradeError(Exception):
|
class UpgradeError(Exception):
|
||||||
"""Error during XML upgrade"""
|
"""Error during XML upgrade"""
|
||||||
|
|
||||||
|
|
||||||
## ---- generic exceptions ----
|
## ---- generic exceptions ----
|
||||||
|
|
||||||
|
|
||||||
class NotFoundError(Exception):
|
class NotFoundError(Exception):
|
||||||
"not found error"
|
"not found error"
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
## ---- specific exceptions ----
|
## ---- specific exceptions ----
|
||||||
|
|
||||||
|
|
||||||
class VariableCalculationDependencyError(Exception):
|
class VariableCalculationDependencyError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -26,6 +26,7 @@ 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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -333,7 +333,7 @@ class JinjaCalculation(Calculation):
|
||||||
"type": "variable",
|
"type": "variable",
|
||||||
"variable": sub_variable,
|
"variable": sub_variable,
|
||||||
}
|
}
|
||||||
if self.version != '1.0':
|
if self.version != "1.0":
|
||||||
default["params"][true_path]["propertyerror"] = False
|
default["params"][true_path]["propertyerror"] = False
|
||||||
if identifier:
|
if identifier:
|
||||||
default["params"][true_path]["identifier"] = identifier
|
default["params"][true_path]["identifier"] = identifier
|
||||||
|
@ -405,9 +405,10 @@ class _VariableCalculation(Calculation):
|
||||||
propertyerror: bool = True
|
propertyerror: bool = True
|
||||||
allow_none: bool = False
|
allow_none: bool = False
|
||||||
|
|
||||||
def get_variable(self,
|
def get_variable(
|
||||||
objectspace,
|
self,
|
||||||
) -> "Variable":
|
objectspace,
|
||||||
|
) -> "Variable":
|
||||||
if self.ori_path is None:
|
if self.ori_path is None:
|
||||||
path = self.path
|
path = self.path
|
||||||
else:
|
else:
|
||||||
|
@ -467,7 +468,7 @@ class _VariableCalculation(Calculation):
|
||||||
calc_variable_is_multi = True
|
calc_variable_is_multi = True
|
||||||
else:
|
else:
|
||||||
calc_variable_is_multi = True
|
calc_variable_is_multi = True
|
||||||
elif identifier and '{{ identifier }}' in identifier:
|
elif identifier and "{{ identifier }}" in identifier:
|
||||||
calc_variable_is_multi = True
|
calc_variable_is_multi = True
|
||||||
if needs_multi:
|
if needs_multi:
|
||||||
if calc_variable_is_multi:
|
if calc_variable_is_multi:
|
||||||
|
@ -481,12 +482,15 @@ class _VariableCalculation(Calculation):
|
||||||
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list'
|
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list'
|
||||||
raise DictConsistencyError(msg, 23, self.xmlfiles)
|
raise DictConsistencyError(msg, 23, self.xmlfiles)
|
||||||
elif calc_variable_is_multi:
|
elif calc_variable_is_multi:
|
||||||
if variable.multi or variable.path.rsplit('.', 1)[0] != self.path.rsplit('.', 1)[0]:
|
if (
|
||||||
|
variable.multi
|
||||||
|
or variable.path.rsplit(".", 1)[0] != self.path.rsplit(".", 1)[0]
|
||||||
|
):
|
||||||
# it's not a follower or not in same leadership
|
# it's not a follower or not in same leadership
|
||||||
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi'
|
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi'
|
||||||
raise DictConsistencyError(msg, 21, self.xmlfiles)
|
raise DictConsistencyError(msg, 21, self.xmlfiles)
|
||||||
else:
|
else:
|
||||||
params[None][0]['index'] = {'index': {'type': 'index'}}
|
params[None][0]["index"] = {"index": {"type": "index"}}
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
@ -504,10 +508,11 @@ class VariableCalculation(_VariableCalculation):
|
||||||
variable, identifier = self.get_variable(objectspace)
|
variable, identifier = self.get_variable(objectspace)
|
||||||
if not variable and self.optional:
|
if not variable and self.optional:
|
||||||
raise VariableCalculationDependencyError()
|
raise VariableCalculationDependencyError()
|
||||||
params = self.get_params(objectspace,
|
params = self.get_params(
|
||||||
variable,
|
objectspace,
|
||||||
identifier,
|
variable,
|
||||||
)
|
identifier,
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"function": "calc_value",
|
"function": "calc_value",
|
||||||
"params": params,
|
"params": params,
|
||||||
|
@ -524,10 +529,12 @@ class VariablePropertyCalculation(_VariableCalculation):
|
||||||
objectspace,
|
objectspace,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
variable, identifier = self.get_variable(objectspace)
|
variable, identifier = self.get_variable(objectspace)
|
||||||
params = self.get_params(objectspace,
|
params = self.get_params(
|
||||||
variable,
|
objectspace,
|
||||||
identifier,
|
variable,
|
||||||
needs_multi=False,)
|
identifier,
|
||||||
|
needs_multi=False,
|
||||||
|
)
|
||||||
variable = params[None][0]["variable"]
|
variable = params[None][0]["variable"]
|
||||||
if self.when is not undefined:
|
if self.when is not undefined:
|
||||||
if self.version == "1.0":
|
if self.version == "1.0":
|
||||||
|
@ -650,10 +657,11 @@ class IdentifierPropertyCalculation(_IdentifierCalculation):
|
||||||
else:
|
else:
|
||||||
msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
|
msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
|
||||||
raise DictConsistencyError
|
raise DictConsistencyError
|
||||||
params = {None: [self.attribute_name, self.get_identifier()],
|
params = {
|
||||||
"when": when,
|
None: [self.attribute_name, self.get_identifier()],
|
||||||
"inverse": inverse,
|
"when": when,
|
||||||
}
|
"inverse": inverse,
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
"function": "variable_to_property",
|
"function": "variable_to_property",
|
||||||
"params": params,
|
"params": params,
|
||||||
|
|
|
@ -16,6 +16,7 @@ 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 rougail.objspace import get_variables
|
# from rougail.objspace import get_variables
|
||||||
# from rougail.utils import normalize_family
|
# from rougail.utils import normalize_family
|
||||||
#
|
#
|
||||||
|
|
|
@ -19,12 +19,15 @@ 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 rougail.annotator.variable import Walk
|
from rougail.annotator.variable import Walk
|
||||||
from rougail.utils import _
|
from rougail.utils import _
|
||||||
from rougail.error import DictConsistencyError
|
from rougail.error import DictConsistencyError
|
||||||
|
|
||||||
|
|
||||||
class Annotator(Walk):
|
class Annotator(Walk):
|
||||||
"""Annotate value"""
|
"""Annotate value"""
|
||||||
|
|
||||||
level = 80
|
level = 80
|
||||||
|
|
||||||
def __init__(self, objectspace, *args) -> None:
|
def __init__(self, objectspace, *args) -> None:
|
||||||
|
@ -37,9 +40,9 @@ class Annotator(Walk):
|
||||||
if family.commandline:
|
if family.commandline:
|
||||||
continue
|
continue
|
||||||
self.not_for_commandline(family)
|
self.not_for_commandline(family)
|
||||||
not_for_commandlines.append(family.path + '.')
|
not_for_commandlines.append(family.path + ".")
|
||||||
for variable in self.get_variables():
|
for variable in self.get_variables():
|
||||||
if variable.type == 'symlink':
|
if variable.type == "symlink":
|
||||||
continue
|
continue
|
||||||
variable_path = variable.path
|
variable_path = variable.path
|
||||||
for family_path in not_for_commandlines:
|
for family_path in not_for_commandlines:
|
||||||
|
@ -53,37 +56,58 @@ class Annotator(Walk):
|
||||||
self.manage_negative_description(variable)
|
self.manage_negative_description(variable)
|
||||||
|
|
||||||
def not_for_commandline(self, variable) -> None:
|
def not_for_commandline(self, variable) -> None:
|
||||||
self.objectspace.properties.add(variable.path, 'not_for_commandline', True)
|
self.objectspace.properties.add(variable.path, "not_for_commandline", True)
|
||||||
|
|
||||||
def manage_alternative_name(self, variable) -> None:
|
def manage_alternative_name(self, variable) -> None:
|
||||||
if not variable.alternative_name:
|
if not variable.alternative_name:
|
||||||
return
|
return
|
||||||
alternative_name = variable.alternative_name
|
alternative_name = variable.alternative_name
|
||||||
variable_path = variable.path
|
variable_path = variable.path
|
||||||
all_letters = ''
|
all_letters = ""
|
||||||
for letter in alternative_name:
|
for letter in alternative_name:
|
||||||
all_letters += letter
|
all_letters += letter
|
||||||
if all_letters == 'h':
|
if all_letters == "h":
|
||||||
msg = _(f'alternative_name "{alternative_name}" conflict with "--help"')
|
msg = _(f'alternative_name "{alternative_name}" conflict with "--help"')
|
||||||
raise DictConsistencyError(msg, 202, variable.xmlfiles)
|
raise DictConsistencyError(msg, 202, variable.xmlfiles)
|
||||||
if all_letters in self.alternative_names:
|
if all_letters in self.alternative_names:
|
||||||
msg = _(f'conflict alternative_name "{alternative_name}": "{variable_path}" and "{self.alternative_names[all_letters]}"')
|
msg = _(
|
||||||
|
f'conflict alternative_name "{alternative_name}": "{variable_path}" and "{self.alternative_names[all_letters]}"'
|
||||||
|
)
|
||||||
raise DictConsistencyError(msg, 202, variable.xmlfiles)
|
raise DictConsistencyError(msg, 202, variable.xmlfiles)
|
||||||
|
|
||||||
self.alternative_names[alternative_name] = variable_path
|
self.alternative_names[alternative_name] = variable_path
|
||||||
if '.' not in variable_path:
|
if "." not in variable_path:
|
||||||
path = alternative_name
|
path = alternative_name
|
||||||
else:
|
else:
|
||||||
path = variable_path.rsplit('.', 1)[0] + '.' + alternative_name
|
path = variable_path.rsplit(".", 1)[0] + "." + alternative_name
|
||||||
self.objectspace.add_variable(alternative_name, {'type': 'symlink', 'path': path, 'opt': variable}, variable.xmlfiles, False, False, variable.version)
|
self.objectspace.add_variable(
|
||||||
|
alternative_name,
|
||||||
|
{"type": "symlink", "path": path, "opt": variable},
|
||||||
|
variable.xmlfiles,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
variable.version,
|
||||||
|
)
|
||||||
|
|
||||||
def manage_negative_description(self, variable) -> None:
|
def manage_negative_description(self, variable) -> None:
|
||||||
if not variable.negative_description:
|
if not variable.negative_description:
|
||||||
if variable.type == 'boolean' and not self.objectspace.add_extra_options:
|
if variable.type == "boolean" and not self.objectspace.add_extra_options:
|
||||||
raise DictConsistencyError(_(f'negative_description is mandatory for boolean variable, but "{variable.path}" hasn\'t'), 200, variable.xmlfiles)
|
raise DictConsistencyError(
|
||||||
|
_(
|
||||||
|
f'negative_description is mandatory for boolean variable, but "{variable.path}" hasn\'t'
|
||||||
|
),
|
||||||
|
200,
|
||||||
|
variable.xmlfiles,
|
||||||
|
)
|
||||||
return
|
return
|
||||||
if variable.type != 'boolean':
|
if variable.type != "boolean":
|
||||||
raise DictConsistencyError(_(f'negative_description is only available for boolean variable, but "{variable.path}" is "{variable.type}"'), 201, variable.xmlfiles)
|
raise DictConsistencyError(
|
||||||
|
_(
|
||||||
|
f'negative_description is only available for boolean variable, but "{variable.path}" is "{variable.type}"'
|
||||||
|
),
|
||||||
|
201,
|
||||||
|
variable.xmlfiles,
|
||||||
|
)
|
||||||
self.objectspace.informations.add(
|
self.objectspace.informations.add(
|
||||||
variable.path, "negative_description", variable.negative_description
|
variable.path, "negative_description", variable.negative_description
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,9 +20,12 @@ 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
|
||||||
"""
|
"""
|
||||||
def get_rougail_config(*,
|
|
||||||
backward_compatibility=True,
|
|
||||||
) -> dict:
|
def get_rougail_config(
|
||||||
|
*,
|
||||||
|
backward_compatibility=True,
|
||||||
|
) -> dict:
|
||||||
options = """
|
options = """
|
||||||
structural_commandline:
|
structural_commandline:
|
||||||
description: Configuration rougail-structural_commandline
|
description: Configuration rougail-structural_commandline
|
||||||
|
@ -31,12 +34,12 @@ structural_commandline:
|
||||||
description: Add extra options to tiramisu-cmdline-parser
|
description: Add extra options to tiramisu-cmdline-parser
|
||||||
default: true
|
default: true
|
||||||
"""
|
"""
|
||||||
return {'name': 'exporter',
|
return {
|
||||||
'process': 'structural',
|
"name": "exporter",
|
||||||
'options': options,
|
"process": "structural",
|
||||||
'level': 20,
|
"options": options,
|
||||||
}
|
"level": 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__all__ = ('get_rougail_config')
|
__all__ = "get_rougail_config"
|
||||||
|
|
||||||
|
|
|
@ -19,18 +19,19 @@ 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 typing import Optional
|
from typing import Optional
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class Variable(BaseModel):
|
class Variable(BaseModel):
|
||||||
alternative_name: Optional[str]=None
|
alternative_name: Optional[str] = None
|
||||||
commandline: bool=True
|
commandline: bool = True
|
||||||
negative_description: Optional[str]=None
|
negative_description: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class Family(BaseModel):
|
class Family(BaseModel):
|
||||||
commandline: bool=True
|
commandline: bool = True
|
||||||
|
|
||||||
|
|
||||||
__all__ = ('Variable', 'Family')
|
__all__ = ("Variable", "Family")
|
||||||
|
|
|
@ -27,13 +27,18 @@ 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 typing import Any
|
from typing import Any
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from tiramisu5 import DynOptionDescription, calc_value
|
from tiramisu5 import DynOptionDescription, calc_value
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
from tiramisu import DynOptionDescription, calc_value
|
from tiramisu import DynOptionDescription, calc_value
|
||||||
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
from importlib.machinery import SourceFileLoader as _SourceFileLoader
|
||||||
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
|
from importlib.util import (
|
||||||
|
spec_from_loader as _spec_from_loader,
|
||||||
|
module_from_spec as _module_from_spec,
|
||||||
|
)
|
||||||
from jinja2 import StrictUndefined, DictLoader
|
from jinja2 import StrictUndefined, DictLoader
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
from rougail.object_model import CONVERT_OPTION
|
from rougail.object_model import CONVERT_OPTION
|
||||||
|
@ -43,16 +48,16 @@ from tiramisu.error import ValueWarning, ConfigError, PropertiesOptionError
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
global func
|
global func
|
||||||
dict_env = {}
|
dict_env = {}
|
||||||
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
||||||
func = ENV.filters
|
func = ENV.filters
|
||||||
ENV.compile_templates('jinja_caches', zip=None)
|
ENV.compile_templates("jinja_caches", zip=None)
|
||||||
|
|
||||||
|
|
||||||
class JinjaError:
|
class JinjaError:
|
||||||
__slot__ = ('_err',)
|
__slot__ = ("_err",)
|
||||||
|
|
||||||
def __init__(self, err):
|
def __init__(self, err):
|
||||||
self._err = err
|
self._err = err
|
||||||
|
|
||||||
|
@ -85,17 +90,17 @@ def test_propertyerror(value: Any) -> bool:
|
||||||
return isinstance(value, JinjaError)
|
return isinstance(value, JinjaError)
|
||||||
|
|
||||||
|
|
||||||
ENV.tests['propertyerror'] = test_propertyerror
|
ENV.tests["propertyerror"] = test_propertyerror
|
||||||
|
|
||||||
|
|
||||||
def load_functions(path):
|
def load_functions(path):
|
||||||
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
|
||||||
loader = _SourceFileLoader('func', path)
|
loader = _SourceFileLoader("func", path)
|
||||||
spec = _spec_from_loader(loader.name, loader)
|
spec = _spec_from_loader(loader.name, loader)
|
||||||
func_ = _module_from_spec(spec)
|
func_ = _module_from_spec(spec)
|
||||||
loader.exec_module(func_)
|
loader.exec_module(func_)
|
||||||
for function in dir(func_):
|
for function in dir(func_):
|
||||||
if function.startswith('_'):
|
if function.startswith("_"):
|
||||||
continue
|
continue
|
||||||
func[function] = getattr(func_, function)
|
func[function] = getattr(func_, function)
|
||||||
|
|
||||||
|
@ -108,37 +113,52 @@ def rougail_calc_value(*args, __default_value=None, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
@function_waiting_for_error
|
@function_waiting_for_error
|
||||||
def jinja_to_function(__internal_variable, __internal_attribute, __internal_jinja, __internal_type, __internal_multi, __internal_files, __default_value=None, **kwargs):
|
def jinja_to_function(
|
||||||
|
__internal_variable,
|
||||||
|
__internal_attribute,
|
||||||
|
__internal_jinja,
|
||||||
|
__internal_type,
|
||||||
|
__internal_multi,
|
||||||
|
__internal_files,
|
||||||
|
__default_value=None,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
global ENV, CONVERT_OPTION
|
global ENV, CONVERT_OPTION
|
||||||
kw = {}
|
kw = {}
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
if isinstance(value, PropertiesOptionError):
|
if isinstance(value, PropertiesOptionError):
|
||||||
value = JinjaError(value)
|
value = JinjaError(value)
|
||||||
if '.' in key:
|
if "." in key:
|
||||||
c_kw = kw
|
c_kw = kw
|
||||||
path, var = key.rsplit('.', 1)
|
path, var = key.rsplit(".", 1)
|
||||||
for subkey in path.split('.'):
|
for subkey in path.split("."):
|
||||||
c_kw = c_kw.setdefault(subkey, {})
|
c_kw = c_kw.setdefault(subkey, {})
|
||||||
c_kw[var] = value
|
c_kw[var] = value
|
||||||
else:
|
else:
|
||||||
if key in kw:
|
if key in kw:
|
||||||
raise ConfigError(f'internal error, multi key for "{key}" in jinja_to_function')
|
raise ConfigError(
|
||||||
|
f'internal error, multi key for "{key}" in jinja_to_function'
|
||||||
|
)
|
||||||
kw[key] = value
|
kw[key] = value
|
||||||
try:
|
try:
|
||||||
values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
|
values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise ConfigError(f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}') from err
|
raise ConfigError(
|
||||||
convert = CONVERT_OPTION[__internal_type].get('func', str)
|
f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}'
|
||||||
|
) from err
|
||||||
|
convert = CONVERT_OPTION[__internal_type].get("func", str)
|
||||||
if __internal_multi:
|
if __internal_multi:
|
||||||
values = [convert(val) for val in values.split('\n') if val != ""]
|
values = [convert(val) for val in values.split("\n") if val != ""]
|
||||||
if not values and __default_value is not None:
|
if not values and __default_value is not None:
|
||||||
return __default_value
|
return __default_value
|
||||||
return values
|
return values
|
||||||
try:
|
try:
|
||||||
values = convert(values)
|
values = convert(values)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise ConfigError(f'cannot converting "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}') from err
|
raise ConfigError(
|
||||||
values = values if values != '' and values != 'None' else None
|
f'cannot converting "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}'
|
||||||
|
) from err
|
||||||
|
values = values if values != "" and values != "None" else None
|
||||||
if values is None and __default_value is not None:
|
if values is None and __default_value is not None:
|
||||||
return __default_value
|
return __default_value
|
||||||
return values
|
return values
|
||||||
|
@ -156,33 +176,33 @@ def variable_to_property(prop, value, when, inverse):
|
||||||
|
|
||||||
@function_waiting_for_error
|
@function_waiting_for_error
|
||||||
def jinja_to_property(prop, when, inverse, **kwargs):
|
def jinja_to_property(prop, when, inverse, **kwargs):
|
||||||
value = func['jinja_to_function'](**kwargs)
|
value = func["jinja_to_function"](**kwargs)
|
||||||
return func['variable_to_property'](prop, value is not None, when, inverse)
|
return func["variable_to_property"](prop, value is not None, when, inverse)
|
||||||
|
|
||||||
|
|
||||||
@function_waiting_for_error
|
@function_waiting_for_error
|
||||||
def jinja_to_property_help(prop, **kwargs):
|
def jinja_to_property_help(prop, **kwargs):
|
||||||
value = func['jinja_to_function'](**kwargs)
|
value = func["jinja_to_function"](**kwargs)
|
||||||
return (prop, f'\"{prop}\" ({value})')
|
return (prop, f'"{prop}" ({value})')
|
||||||
|
|
||||||
|
|
||||||
@function_waiting_for_error
|
@function_waiting_for_error
|
||||||
def valid_with_jinja(warnings_only=False, **kwargs):
|
def valid_with_jinja(warnings_only=False, **kwargs):
|
||||||
global ValueWarning
|
global ValueWarning
|
||||||
value = func['jinja_to_function'](**kwargs)
|
value = func["jinja_to_function"](**kwargs)
|
||||||
if value:
|
if value:
|
||||||
if warnings_only:
|
if warnings_only:
|
||||||
raise ValueWarning(value)
|
raise ValueWarning(value)
|
||||||
else:
|
else:
|
||||||
raise ValueError(value)
|
raise ValueError(value)
|
||||||
|
|
||||||
|
|
||||||
func['calc_value'] = rougail_calc_value
|
func["calc_value"] = rougail_calc_value
|
||||||
func['jinja_to_function'] = jinja_to_function
|
func["jinja_to_function"] = jinja_to_function
|
||||||
func['jinja_to_property'] = jinja_to_property
|
func["jinja_to_property"] = jinja_to_property
|
||||||
func['jinja_to_property_help'] = jinja_to_property_help
|
func["jinja_to_property_help"] = jinja_to_property_help
|
||||||
func['variable_to_property'] = variable_to_property
|
func["variable_to_property"] = variable_to_property
|
||||||
func['valid_with_jinja'] = valid_with_jinja
|
func["valid_with_jinja"] = valid_with_jinja
|
||||||
|
|
||||||
|
|
||||||
class ConvertDynOptionDescription(DynOptionDescription):
|
class ConvertDynOptionDescription(DynOptionDescription):
|
||||||
|
@ -213,9 +233,12 @@ class ConvertDynOptionDescription(DynOptionDescription):
|
||||||
def impl_get_display_name(
|
def impl_get_display_name(
|
||||||
self,
|
self,
|
||||||
subconfig,
|
subconfig,
|
||||||
with_quote: bool=False,
|
with_quote: bool = False,
|
||||||
) -> str:
|
) -> str:
|
||||||
display = super().impl_get_display_name(subconfig, with_quote=with_quote)
|
display = super().impl_get_display_name(subconfig, with_quote=with_quote)
|
||||||
if "{{ identifier }}" in display:
|
if "{{ identifier }}" in display:
|
||||||
return display.replace("{{ identifier }}", self.convert_identifier_to_path(self.get_identifiers(subconfig)[-1]))
|
return display.replace(
|
||||||
|
"{{ identifier }}",
|
||||||
|
self.convert_identifier_to_path(self.get_identifiers(subconfig)[-1]),
|
||||||
|
)
|
||||||
return display
|
return display
|
||||||
|
|
|
@ -28,6 +28,7 @@ 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 typing import Optional, Union
|
from typing import Optional, Union
|
||||||
from json import dumps
|
from json import dumps
|
||||||
from os.path import isfile, basename
|
from os.path import isfile, basename
|
||||||
|
@ -90,11 +91,14 @@ class TiramisuReflector:
|
||||||
self.text["header"].append(f"load_functions('{funcs_path}')")
|
self.text["header"].append(f"load_functions('{funcs_path}')")
|
||||||
if self.objectspace.export_with_import:
|
if self.objectspace.export_with_import:
|
||||||
if objectspace.main_namespace:
|
if objectspace.main_namespace:
|
||||||
self.text["header"].extend(["try:",
|
self.text["header"].extend(
|
||||||
" groups.namespace",
|
[
|
||||||
"except:",
|
"try:",
|
||||||
" groups.addgroup('namespace')",
|
" groups.namespace",
|
||||||
])
|
"except:",
|
||||||
|
" groups.addgroup('namespace')",
|
||||||
|
]
|
||||||
|
)
|
||||||
for mode in self.objectspace.modes_level:
|
for mode in self.objectspace.modes_level:
|
||||||
self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
|
self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
|
||||||
self.make_tiramisu_objects()
|
self.make_tiramisu_objects()
|
||||||
|
@ -112,9 +116,9 @@ class TiramisuReflector:
|
||||||
def make_tiramisu_objects(self) -> None:
|
def make_tiramisu_objects(self) -> None:
|
||||||
"""make tiramisu objects"""
|
"""make tiramisu objects"""
|
||||||
baseelt = BaseElt()
|
baseelt = BaseElt()
|
||||||
self.objectspace.reflector_names[
|
self.objectspace.reflector_names[baseelt.path] = (
|
||||||
baseelt.path
|
f"option_0{self.objectspace.suffix}"
|
||||||
] = f"option_0{self.objectspace.suffix}"
|
)
|
||||||
basefamily = Family(
|
basefamily = Family(
|
||||||
baseelt,
|
baseelt,
|
||||||
self,
|
self,
|
||||||
|
@ -340,7 +344,7 @@ class Common:
|
||||||
param.get("propertyerror", True),
|
param.get("propertyerror", True),
|
||||||
param.get("identifier"),
|
param.get("identifier"),
|
||||||
param.get("dynamic"),
|
param.get("dynamic"),
|
||||||
param.get('whole', False),
|
param.get("whole", False),
|
||||||
)
|
)
|
||||||
if param["type"] == "any":
|
if param["type"] == "any":
|
||||||
if isinstance(param["value"], str):
|
if isinstance(param["value"], str):
|
||||||
|
@ -375,7 +379,7 @@ class Common:
|
||||||
if isinstance(ident, str):
|
if isinstance(ident, str):
|
||||||
ident = self.convert_str(ident)
|
ident = self.convert_str(ident)
|
||||||
identifiers.append(str(ident))
|
identifiers.append(str(ident))
|
||||||
params.append('[' + ', '.join(identifiers) + ']')
|
params.append("[" + ", ".join(identifiers) + "]")
|
||||||
else:
|
else:
|
||||||
param_type = "ParamOption"
|
param_type = "ParamOption"
|
||||||
if not propertyerror:
|
if not propertyerror:
|
||||||
|
@ -475,13 +479,15 @@ class Variable(Common):
|
||||||
keys["values"] = self.populate_calculation(
|
keys["values"] = self.populate_calculation(
|
||||||
self.elt.choices, return_a_tuple=True
|
self.elt.choices, return_a_tuple=True
|
||||||
)
|
)
|
||||||
if self.elt.type == 'regexp':
|
if self.elt.type == "regexp":
|
||||||
self.object_type = 'Regexp_' + self.option_name
|
self.object_type = "Regexp_" + self.option_name
|
||||||
self.tiramisu.text['header'].append(f'''class {self.object_type}(RegexpOption):
|
self.tiramisu.text["header"].append(
|
||||||
|
f"""class {self.object_type}(RegexpOption):
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'value'
|
_type = 'value'
|
||||||
{self.object_type}._regexp = re_compile(r"{self.elt.regexp}")
|
{self.object_type}._regexp = re_compile(r"{self.elt.regexp}")
|
||||||
''')
|
"""
|
||||||
|
)
|
||||||
if self.elt.path in self.objectspace.multis:
|
if self.elt.path in self.objectspace.multis:
|
||||||
keys["multi"] = self.objectspace.multis[self.elt.path]
|
keys["multi"] = self.objectspace.multis[self.elt.path]
|
||||||
if hasattr(self.elt, "default") and self.elt.default is not None:
|
if hasattr(self.elt, "default") and self.elt.default is not None:
|
||||||
|
@ -528,8 +534,8 @@ class Family(Common):
|
||||||
self.object_type = "Leadership"
|
self.object_type = "Leadership"
|
||||||
else:
|
else:
|
||||||
self.object_type = "OptionDescription"
|
self.object_type = "OptionDescription"
|
||||||
if hasattr(self.elt, 'name') and self.elt.name == self.elt.namespace:
|
if hasattr(self.elt, "name") and self.elt.name == self.elt.namespace:
|
||||||
self.group_type = 'groups.namespace'
|
self.group_type = "groups.namespace"
|
||||||
else:
|
else:
|
||||||
self.group_type = None
|
self.group_type = None
|
||||||
self.children = []
|
self.children = []
|
||||||
|
|
|
@ -18,4 +18,5 @@ 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 .update import RougailUpgrade
|
from .update import RougailUpgrade
|
||||||
|
|
|
@ -63,7 +63,7 @@ class upgrade_010_to_10:
|
||||||
xmlsrc: str,
|
xmlsrc: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.xmlsrc = xmlsrc
|
self.xmlsrc = xmlsrc
|
||||||
self.paths = {"family": {}, "variable": {}, 'dynamic': {}}
|
self.paths = {"family": {}, "variable": {}, "dynamic": {}}
|
||||||
self.lists = {
|
self.lists = {
|
||||||
"service": {},
|
"service": {},
|
||||||
"ip": {},
|
"ip": {},
|
||||||
|
@ -82,18 +82,26 @@ class upgrade_010_to_10:
|
||||||
sub_path: str,
|
sub_path: str,
|
||||||
true_sub_path: str,
|
true_sub_path: str,
|
||||||
*,
|
*,
|
||||||
root: bool=False,
|
root: bool = False,
|
||||||
is_dynamic: bool=False,
|
is_dynamic: bool = False,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
new_families = {}
|
new_families = {}
|
||||||
if root:
|
if root:
|
||||||
new_families['version'] = None
|
new_families["version"] = None
|
||||||
if "variables" in family:
|
if "variables" in family:
|
||||||
for subelt in family["variables"]:
|
for subelt in family["variables"]:
|
||||||
for typ, obj in subelt.items():
|
for typ, obj in subelt.items():
|
||||||
for subobj in obj:
|
for subobj in obj:
|
||||||
local_is_dynamic = is_dynamic or subobj.get('dynamic') is not None
|
local_is_dynamic = (
|
||||||
getattr(self, f"convert_{typ}")(subobj, new_families, sub_path, true_sub_path, local_is_dynamic)
|
is_dynamic or subobj.get("dynamic") is not None
|
||||||
|
)
|
||||||
|
getattr(self, f"convert_{typ}")(
|
||||||
|
subobj,
|
||||||
|
new_families,
|
||||||
|
sub_path,
|
||||||
|
true_sub_path,
|
||||||
|
local_is_dynamic,
|
||||||
|
)
|
||||||
family.pop("variables")
|
family.pop("variables")
|
||||||
return new_families
|
return new_families
|
||||||
|
|
||||||
|
@ -112,7 +120,7 @@ class upgrade_010_to_10:
|
||||||
else:
|
else:
|
||||||
true_sub_path = name
|
true_sub_path = name
|
||||||
if is_dynamic:
|
if is_dynamic:
|
||||||
name += '{{ suffix }}'
|
name += "{{ suffix }}"
|
||||||
if sub_path:
|
if sub_path:
|
||||||
sub_path = sub_path + "." + name
|
sub_path = sub_path + "." + name
|
||||||
else:
|
else:
|
||||||
|
@ -126,7 +134,9 @@ class upgrade_010_to_10:
|
||||||
if typ == "dynamic":
|
if typ == "dynamic":
|
||||||
family["variable"] = self.get_variable_path(value)
|
family["variable"] = self.get_variable_path(value)
|
||||||
# add sub families and sub variables
|
# add sub families and sub variables
|
||||||
sub_families = self.parse_variables(family, sub_path, true_sub_path, is_dynamic=is_dynamic)
|
sub_families = self.parse_variables(
|
||||||
|
family, sub_path, true_sub_path, is_dynamic=is_dynamic
|
||||||
|
)
|
||||||
for sub_name, sub_family in sub_families.copy().items():
|
for sub_name, sub_family in sub_families.copy().items():
|
||||||
if sub_name not in family:
|
if sub_name not in family:
|
||||||
continue
|
continue
|
||||||
|
@ -152,13 +162,13 @@ class upgrade_010_to_10:
|
||||||
else:
|
else:
|
||||||
true_sub_path = name
|
true_sub_path = name
|
||||||
self.flatten_paths["variable"][name] = true_sub_path
|
self.flatten_paths["variable"][name] = true_sub_path
|
||||||
name += '{{ suffix }}'
|
name += "{{ suffix }}"
|
||||||
if sub_path:
|
if sub_path:
|
||||||
sub_path = sub_path + "." + name
|
sub_path = sub_path + "." + name
|
||||||
else:
|
else:
|
||||||
sub_path = name
|
sub_path = name
|
||||||
if is_dynamic:
|
if is_dynamic:
|
||||||
self.paths['dynamic'][true_sub_path] = sub_path
|
self.paths["dynamic"][true_sub_path] = sub_path
|
||||||
new_families[name] = variable
|
new_families[name] = variable
|
||||||
self.flatten_paths["variable"][name] = sub_path
|
self.flatten_paths["variable"][name] = sub_path
|
||||||
self.paths["variable"][sub_path] = variable
|
self.paths["variable"][sub_path] = variable
|
||||||
|
@ -198,17 +208,18 @@ class upgrade_010_to_10:
|
||||||
)(test)
|
)(test)
|
||||||
)
|
)
|
||||||
variable["test"] = tests
|
variable["test"] = tests
|
||||||
if variable.get('mandatory', False):
|
if variable.get("mandatory", False):
|
||||||
del variable["mandatory"]
|
del variable["mandatory"]
|
||||||
CONVERT_TYPE = {'filename': 'unix_filename',
|
CONVERT_TYPE = {
|
||||||
'password': 'secret',
|
"filename": "unix_filename",
|
||||||
}
|
"password": "secret",
|
||||||
if variable.get('type') in CONVERT_TYPE:
|
}
|
||||||
variable['type'] = CONVERT_TYPE[variable['type']]
|
if variable.get("type") in CONVERT_TYPE:
|
||||||
|
variable["type"] = CONVERT_TYPE[variable["type"]]
|
||||||
|
|
||||||
def parse_variables_with_path(self):
|
def parse_variables_with_path(self):
|
||||||
for variable in self.paths["variable"].values():
|
for variable in self.paths["variable"].values():
|
||||||
multi = variable.get('multi', False)
|
multi = variable.get("multi", False)
|
||||||
if "value" in variable:
|
if "value" in variable:
|
||||||
default = variable.pop("value")
|
default = variable.pop("value")
|
||||||
if default is not None:
|
if default is not None:
|
||||||
|
@ -223,7 +234,8 @@ class upgrade_010_to_10:
|
||||||
variable["choices"] = variable.pop("choice")
|
variable["choices"] = variable.pop("choice")
|
||||||
else:
|
else:
|
||||||
variable["choices"] = [
|
variable["choices"] = [
|
||||||
self.get_value(choice, multi) for choice in variable.pop("choice")
|
self.get_value(choice, multi)
|
||||||
|
for choice in variable.pop("choice")
|
||||||
]
|
]
|
||||||
|
|
||||||
def parse_services(
|
def parse_services(
|
||||||
|
@ -350,21 +362,21 @@ class upgrade_010_to_10:
|
||||||
if variable_path is None:
|
if variable_path is None:
|
||||||
continue
|
continue
|
||||||
variable = self.paths["variable"][variable_path]
|
variable = self.paths["variable"][variable_path]
|
||||||
if variable.get('multi', False):
|
if variable.get("multi", False):
|
||||||
multi = True
|
multi = True
|
||||||
if apply_on_fallback:
|
if apply_on_fallback:
|
||||||
condition_value = True
|
condition_value = True
|
||||||
else:
|
else:
|
||||||
if "{{ suffix }}" in source:
|
if "{{ suffix }}" in source:
|
||||||
force_param = {'__var': source}
|
force_param = {"__var": source}
|
||||||
source = '__var'
|
source = "__var"
|
||||||
else:
|
else:
|
||||||
force_param = None
|
force_param = None
|
||||||
condition_value = self.params_condition_to_jinja(
|
condition_value = self.params_condition_to_jinja(
|
||||||
prop, source, condition["param"], name.endswith("if_in"), multi
|
prop, source, condition["param"], name.endswith("if_in"), multi
|
||||||
)
|
)
|
||||||
if force_param:
|
if force_param:
|
||||||
condition_value.setdefault('params', {}).update(force_param)
|
condition_value.setdefault("params", {}).update(force_param)
|
||||||
for target in condition["target"]:
|
for target in condition["target"]:
|
||||||
typ = target.get("type", "variable")
|
typ = target.get("type", "variable")
|
||||||
if typ == "variable":
|
if typ == "variable":
|
||||||
|
@ -417,7 +429,9 @@ class upgrade_010_to_10:
|
||||||
check["param"] = [
|
check["param"] = [
|
||||||
{"text": variable_path, "type": "variable"}
|
{"text": variable_path, "type": "variable"}
|
||||||
] + check.get("param", [])
|
] + check.get("param", [])
|
||||||
check_value = self.convert_param_function(check, variable.get('multi', False))
|
check_value = self.convert_param_function(
|
||||||
|
check, variable.get("multi", False)
|
||||||
|
)
|
||||||
variable.setdefault("validators", []).append(check_value)
|
variable.setdefault("validators", []).append(check_value)
|
||||||
|
|
||||||
def parse_fill(
|
def parse_fill(
|
||||||
|
@ -437,12 +451,16 @@ class upgrade_010_to_10:
|
||||||
"jinja": fill["name"],
|
"jinja": fill["name"],
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
fill_value = self.convert_param_function(fill, variable.get('multi', False))
|
fill_value = self.convert_param_function(
|
||||||
|
fill, variable.get("multi", False)
|
||||||
|
)
|
||||||
variable["default"] = fill_value
|
variable["default"] = fill_value
|
||||||
if variable.get('mandatory') is False:
|
if variable.get("mandatory") is False:
|
||||||
del variable['mandatory']
|
del variable["mandatory"]
|
||||||
else:
|
else:
|
||||||
raise Exception(f'cannot set fill to unknown variable "{variable_path}"')
|
raise Exception(
|
||||||
|
f'cannot set fill to unknown variable "{variable_path}"'
|
||||||
|
)
|
||||||
|
|
||||||
def params_condition_to_jinja(
|
def params_condition_to_jinja(
|
||||||
self,
|
self,
|
||||||
|
@ -538,8 +556,8 @@ class upgrade_010_to_10:
|
||||||
new_param = {attr_name: value}
|
new_param = {attr_name: value}
|
||||||
value = attr_name
|
value = attr_name
|
||||||
elif typ in ["index", "suffix"]:
|
elif typ in ["index", "suffix"]:
|
||||||
if 'name' in value:
|
if "name" in value:
|
||||||
attr_name = value['name']
|
attr_name = value["name"]
|
||||||
else:
|
else:
|
||||||
attr_name = f"__{typ}"
|
attr_name = f"__{typ}"
|
||||||
new_param = {attr_name: {"type": typ}}
|
new_param = {attr_name: {"type": typ}}
|
||||||
|
@ -550,7 +568,7 @@ class upgrade_010_to_10:
|
||||||
value = value[typ]
|
value = value[typ]
|
||||||
elif "{{ suffix }}" in value[typ]:
|
elif "{{ suffix }}" in value[typ]:
|
||||||
path = value[typ]
|
path = value[typ]
|
||||||
attr_name = path.split('.')[-1][:-12] # remove {{ suffix }}
|
attr_name = path.split(".")[-1][:-12] # remove {{ suffix }}
|
||||||
new_param = {attr_name: value}
|
new_param = {attr_name: value}
|
||||||
value = attr_name
|
value = attr_name
|
||||||
else:
|
else:
|
||||||
|
@ -568,16 +586,22 @@ class upgrade_010_to_10:
|
||||||
) -> str:
|
) -> str:
|
||||||
text = param["name"]
|
text = param["name"]
|
||||||
params = {}
|
params = {}
|
||||||
# multi = False
|
# multi = False
|
||||||
if "param" in param and param["param"]:
|
if "param" in param and param["param"]:
|
||||||
if text == 'calc_value' and len(param["param"]) == 1 and isinstance(param["param"][0], dict) and param["param"][0].get('type') == 'variable' and param["param"][0].get("text"):
|
if (
|
||||||
|
text == "calc_value"
|
||||||
|
and len(param["param"]) == 1
|
||||||
|
and isinstance(param["param"][0], dict)
|
||||||
|
and param["param"][0].get("type") == "variable"
|
||||||
|
and param["param"][0].get("text")
|
||||||
|
):
|
||||||
value = param["param"][0]["text"]
|
value = param["param"][0]["text"]
|
||||||
path = self.get_variable_path(value)
|
path = self.get_variable_path(value)
|
||||||
if not path:
|
if not path:
|
||||||
path = value
|
path = value
|
||||||
ret = {"type": "variable", "variable": path}
|
ret = {"type": "variable", "variable": path}
|
||||||
if 'optional' in param["param"][0]:
|
if "optional" in param["param"][0]:
|
||||||
ret['optional'] = param["param"][0]["optional"]
|
ret["optional"] = param["param"][0]["optional"]
|
||||||
return ret
|
return ret
|
||||||
first, *others = param["param"]
|
first, *others = param["param"]
|
||||||
new_param, first = self.get_jinja_param_and_value(first, multi)
|
new_param, first = self.get_jinja_param_and_value(first, multi)
|
||||||
|
@ -604,9 +628,13 @@ class upgrade_010_to_10:
|
||||||
if not multi:
|
if not multi:
|
||||||
text = "{{ " + text + " }}"
|
text = "{{ " + text + " }}"
|
||||||
else:
|
else:
|
||||||
text = """{% for __variable in """ + text + """ %}
|
text = (
|
||||||
|
"""{% for __variable in """
|
||||||
|
+ text
|
||||||
|
+ """ %}
|
||||||
{{ __variable }}
|
{{ __variable }}
|
||||||
{% endfor %}"""
|
{% endfor %}"""
|
||||||
|
)
|
||||||
ret = {"type": "jinja", "jinja": text}
|
ret = {"type": "jinja", "jinja": text}
|
||||||
if params:
|
if params:
|
||||||
ret["params"] = params
|
ret["params"] = params
|
||||||
|
@ -659,16 +687,21 @@ class RougailUpgrade:
|
||||||
def run(
|
def run(
|
||||||
self,
|
self,
|
||||||
):
|
):
|
||||||
for dict_dir, dest_dir in zip(self.rougailconfig["main_dictionaries"], self.rougailconfig["upgrade_options.main_dictionaries"]):
|
for dict_dir, dest_dir in zip(
|
||||||
|
self.rougailconfig["main_dictionaries"],
|
||||||
|
self.rougailconfig["upgrade_options.main_dictionaries"],
|
||||||
|
):
|
||||||
self._load_dictionaries(
|
self._load_dictionaries(
|
||||||
dict_dir,
|
dict_dir,
|
||||||
dest_dir,
|
dest_dir,
|
||||||
normalize_family(self.rougailconfig["main_namespace"]),
|
normalize_family(self.rougailconfig["main_namespace"]),
|
||||||
)
|
)
|
||||||
if self.rougailconfig['main_namespace']:
|
if self.rougailconfig["main_namespace"]:
|
||||||
if self.rougailconfig["extra_dictionaries"]:
|
if self.rougailconfig["extra_dictionaries"]:
|
||||||
dst_extra_dir = self.rougailconfig["upgrade_options.extra_dictionary"]
|
dst_extra_dir = self.rougailconfig["upgrade_options.extra_dictionary"]
|
||||||
for namespace, extra_dirs in self.rougailconfig["extra_dictionaries"].items():
|
for namespace, extra_dirs in self.rougailconfig[
|
||||||
|
"extra_dictionaries"
|
||||||
|
].items():
|
||||||
extra_dstsubfolder = Path(dst_extra_dir) / namespace
|
extra_dstsubfolder = Path(dst_extra_dir) / namespace
|
||||||
if not extra_dstsubfolder.is_dir():
|
if not extra_dstsubfolder.is_dir():
|
||||||
extra_dstsubfolder.mkdir()
|
extra_dstsubfolder.mkdir()
|
||||||
|
@ -677,7 +710,7 @@ class RougailUpgrade:
|
||||||
str(extra_dir),
|
str(extra_dir),
|
||||||
str(extra_dstsubfolder),
|
str(extra_dstsubfolder),
|
||||||
normalize_family(namespace),
|
normalize_family(namespace),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load_dictionaries(
|
def _load_dictionaries(
|
||||||
self,
|
self,
|
||||||
|
@ -697,7 +730,7 @@ class RougailUpgrade:
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
xmlsrc = Path(srcfolder) / Path(filename)
|
xmlsrc = Path(srcfolder) / Path(filename)
|
||||||
|
|
||||||
ymldst = Path(dstfolder) / (Path(filename).stem + '.yml')
|
ymldst = Path(dstfolder) / (Path(filename).stem + ".yml")
|
||||||
if filename.endswith(".xml"):
|
if filename.endswith(".xml"):
|
||||||
if parse is None:
|
if parse is None:
|
||||||
raise Exception("XML module is not installed")
|
raise Exception("XML module is not installed")
|
||||||
|
@ -732,7 +765,7 @@ class RougailUpgrade:
|
||||||
root_services = root_services_
|
root_services = root_services_
|
||||||
if function_version == search_function_name:
|
if function_version == search_function_name:
|
||||||
function_found = True
|
function_found = True
|
||||||
if root != {'version': None}:
|
if root != {"version": None}:
|
||||||
root["version"] = float(version)
|
root["version"] = float(version)
|
||||||
with ymldst.open("w") as ymlfh:
|
with ymldst.open("w") as ymlfh:
|
||||||
yaml = YAML()
|
yaml = YAML()
|
||||||
|
@ -923,25 +956,26 @@ class RougailUpgrade:
|
||||||
"variable": value.pop("variable"),
|
"variable": value.pop("variable"),
|
||||||
"propertyerror": False,
|
"propertyerror": False,
|
||||||
}
|
}
|
||||||
if '{{ suffix }}' not in key:
|
if "{{ suffix }}" not in key:
|
||||||
new_root[key + '{{ suffix }}'] = new_root.pop(key)
|
new_root[key + "{{ suffix }}"] = new_root.pop(key)
|
||||||
update_root = True
|
update_root = True
|
||||||
self._update_1_1(value)
|
self._update_1_1(value)
|
||||||
for typ, obj in {'boolean': bool,
|
for typ, obj in {
|
||||||
'number': int,
|
"boolean": bool,
|
||||||
'string': str,
|
"number": int,
|
||||||
'float': float,
|
"string": str,
|
||||||
}.items():
|
"float": float,
|
||||||
if value.get('type') == typ:
|
}.items():
|
||||||
default = value.get('default')
|
if value.get("type") == typ:
|
||||||
|
default = value.get("default")
|
||||||
if default is None or default == []:
|
if default is None or default == []:
|
||||||
continue
|
continue
|
||||||
if isinstance(default, obj):
|
if isinstance(default, obj):
|
||||||
del value['type']
|
del value["type"]
|
||||||
elif isinstance(default, list) and isinstance(default[0], obj):
|
elif isinstance(default, list) and isinstance(default[0], obj):
|
||||||
del value['type']
|
del value["type"]
|
||||||
if value.get('multi') and isinstance(value.get('default'), list):
|
if value.get("multi") and isinstance(value.get("default"), list):
|
||||||
del value['multi']
|
del value["multi"]
|
||||||
if update_root:
|
if update_root:
|
||||||
root.clear()
|
root.clear()
|
||||||
root.update(new_root)
|
root.update(new_root)
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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 typing import List, Union
|
from typing import List, Union
|
||||||
from unicodedata import normalize, combining
|
from unicodedata import normalize, combining
|
||||||
import re
|
import re
|
||||||
|
@ -117,7 +118,9 @@ def get_jinja_variable_to_param(
|
||||||
for g in parsed_content.find_all(Getattr):
|
for g in parsed_content.find_all(Getattr):
|
||||||
variables.add(recurse_getattr(g))
|
variables.add(recurse_getattr(g))
|
||||||
except TemplateSyntaxError as err:
|
except TemplateSyntaxError as err:
|
||||||
msg = _(f'error in jinja "{jinja_text}" for the variable "{ current_path }": {err}')
|
msg = _(
|
||||||
|
f'error in jinja "{jinja_text}" for the variable "{ current_path }": {err}'
|
||||||
|
)
|
||||||
raise DictConsistencyError(msg, 39, xmlfiles) from err
|
raise DictConsistencyError(msg, 39, xmlfiles) from err
|
||||||
variables = list(variables)
|
variables = list(variables)
|
||||||
variables.sort(reverse=True)
|
variables.sort(reverse=True)
|
||||||
|
@ -135,7 +138,7 @@ def get_jinja_variable_to_param(
|
||||||
if variable and variable.path in objectspace.variables:
|
if variable and variable.path in objectspace.variables:
|
||||||
founded_variables[variable_path] = (identifier, variable)
|
founded_variables[variable_path] = (identifier, variable)
|
||||||
else:
|
else:
|
||||||
sub_family = variable_path + '.'
|
sub_family = variable_path + "."
|
||||||
for founded_variable in chain(founded_variables, unknown_variables):
|
for founded_variable in chain(founded_variables, unknown_variables):
|
||||||
if founded_variable.startswith(sub_family):
|
if founded_variable.startswith(sub_family):
|
||||||
break
|
break
|
||||||
|
@ -149,8 +152,8 @@ def get_jinja_variable_to_param(
|
||||||
else:
|
else:
|
||||||
root_path = None
|
root_path = None
|
||||||
vpath = variable_path
|
vpath = variable_path
|
||||||
while '.' in vpath:
|
while "." in vpath:
|
||||||
vpath = vpath.rsplit('.', 1)[0]
|
vpath = vpath.rsplit(".", 1)[0]
|
||||||
variable, identifier = objectspace.paths.get_with_dynamic(
|
variable, identifier = objectspace.paths.get_with_dynamic(
|
||||||
vpath,
|
vpath,
|
||||||
path_prefix,
|
path_prefix,
|
||||||
|
|
Loading…
Reference in a new issue