WIP: Expand the developer documentation #27

Draft
gremond wants to merge 204 commits from develop into developer_docs
4 changed files with 127 additions and 77 deletions
Showing only changes of commit feff5dbd75 - Show all commits

View file

@ -78,7 +78,7 @@ class SpaceAnnotator: # pylint: disable=R0903
) )
except ModuleNotFoundError: except ModuleNotFoundError:
pass pass
for user_data in objectspace.user_datas: for user_data in objectspace.user_data:
try: try:
get_annotators( get_annotators(
ANNOTATORS, f"rougail.user_data_{user_data}", "annotator" ANNOTATORS, f"rougail.user_data_{user_data}", "annotator"
@ -97,7 +97,7 @@ class SpaceAnnotator: # pylint: disable=R0903
annotators.extend(ANNOTATORS[extra_annotator]) annotators.extend(ANNOTATORS[extra_annotator])
for structural in objectspace.structurals: for structural in objectspace.structurals:
annotators.extend(ANNOTATORS[f"rougail.structural_{structural}.annotator"]) annotators.extend(ANNOTATORS[f"rougail.structural_{structural}.annotator"])
for user_data in objectspace.user_datas: for user_data in objectspace.user_data:
annotators.extend(ANNOTATORS[f"rougail.user_data_{user_data}.annotator"]) annotators.extend(ANNOTATORS[f"rougail.user_data_{user_data}.annotator"])
if objectspace.output: if objectspace.output:
annotators.extend( annotators.extend(

View file

@ -21,11 +21,11 @@ from warnings import warn
from .convert import RougailConvert from .convert import RougailConvert
from ..config import RougailConfig from ..config import RougailConfig
from ..user_datas import UserDatas from ..user_data import UserData
from ..tiramisu import tiramisu_display_name from ..tiramisu import tiramisu_display_name
class Rougail(UserDatas): class Rougail(UserData):
"""Main Rougail object""" """Main Rougail object"""
def __init__( def __init__(

View file

@ -180,9 +180,9 @@ class ParserVariable:
] ]
self.structurals = rougailconfig["step.structural"] self.structurals = rougailconfig["step.structural"]
try: try:
self.user_datas = rougailconfig["step.user_data"] self.user_data = rougailconfig["step.user_data"]
except: except:
self.user_datas = [] self.user_data = []
try: try:
self.output = rougailconfig["step.output"] self.output = rougailconfig["step.output"]
except: except:

View file

@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from typing import List from typing import List
from tiramisu import Calculation, owners from tiramisu import Calculation, Params, ParamValue, owners
from tiramisu.error import ( from tiramisu.error import (
PropertiesOptionError, PropertiesOptionError,
AttributeOptionError, AttributeOptionError,
@ -41,30 +41,31 @@ from .error import DictConsistencyError
from .i18n import _ from .i18n import _
class UserDatas: class UserData:
def __init__(self, config) -> None: def __init__(self, config) -> None:
self.config = config self.config = config
def user_datas( def user_data(
self, self,
user_datas: List[dict], user_data: List[dict],
*, *,
invalid_user_datas_error: bool = False, invalid_user_data_error: bool = False,
unknown_user_datas_error: bool = False, unknown_user_data_error: bool = False,
): ):
self.values = {} self.values = {}
self.errors = [] self.errors = []
self.warnings = [] self.warnings = []
if invalid_user_datas_error: self.invalid_user_data_error = invalid_user_data_error
if self.invalid_user_data_error:
self.invalids = self.errors self.invalids = self.errors
else: else:
self.invalids = self.warnings self.invalids = self.warnings
if unknown_user_datas_error: if unknown_user_data_error:
self.unknowns = self.errors self.unknowns = self.errors
else: else:
self.unknowns = self.warnings self.unknowns = self.warnings
self.show_secrets = False self.show_secrets = False
self._populate_values(user_datas) self._populate_values(user_data)
self._auto_configure_dynamics() self._auto_configure_dynamics()
self._populate_config() self._populate_config()
self.properties_to_string = get_properties_to_string() self.properties_to_string = get_properties_to_string()
@ -74,8 +75,8 @@ class UserDatas:
"warnings": self.warnings, "warnings": self.warnings,
} }
def _populate_values(self, user_datas): def _populate_values(self, user_data):
for datas in user_datas: for datas in user_data:
options = datas.get("options", {}) options = datas.get("options", {})
source = datas["source"] source = datas["source"]
for name, data in datas.get("values", {}).items(): for name, data in datas.get("values", {}).items():
@ -225,10 +226,10 @@ class UserDatas:
options.get("allow_secrets_variables", True) is False options.get("allow_secrets_variables", True) is False
and option.type() == "password" and option.type() == "password"
): ):
self.errors.append( self.errors.append({
_( _(
'the variable "{0}" contains secrets and should not be defined in {1}' 'the variable contains secrets and should not be defined in {0}'
).format(path, self.values[values_path]["source"]) ).format(self.values[values_path]["source"]): option._subconfig}
) )
self.values.pop(path) self.values.pop(path)
continue continue
@ -257,7 +258,6 @@ class UserDatas:
option.value.pop(idx) option.value.pop(idx)
try: try:
self.set_value(option, value, options) self.set_value(option, value, options)
# option.value.set(value)
value_is_set = True value_is_set = True
except Exception as err: except Exception as err:
if path != option.path(): if path != option.path():
@ -297,8 +297,8 @@ class UserDatas:
def _populate_error_warnings(self): def _populate_error_warnings(self):
# we don't find variable, apply value just to get error or warning messages # we don't find variable, apply value just to get error or warning messages
for path, options in self.values.items(): for path, options in self.values.items():
if "{{ identifier }}" in path: # if "{{ identifier }}" in path:
continue # continue
value = options["values"] value = options["values"]
if options.get("secret_manager"): if options.get("secret_manager"):
option = self.config.forcepermissive.option(path) option = self.config.forcepermissive.option(path)
@ -307,32 +307,47 @@ class UserDatas:
try: try:
if option.isoptiondescription(): if option.isoptiondescription():
if value: if value:
self.invalids.append( if self.invalid_user_data_error:
_( msg = _(
'cannot set the value "{0}" to the family {1}, it will be ignored when loading from {2}' 'is a family so we cannot set the value "{0}", it has been loading from {1}'
).format(
self._display_value(option, value),
option.description(with_quote=True),
options["source"],
) )
else:
msg = _(
'is a family so we cannot set the value "{0}", it will be ignored when loading from {1}'
)
self.invalids.append({msg.format(
self._display_value(option, value),
options["source"],
): option._subconfig}
) )
continue continue
except PropertiesOptionError as err: except (ConfigError, PropertiesOptionError) as err:
self.unknowns.append( self.unknowns.append({
_("{0} loaded from {1}").format(err, options["source"]) _("{0}, it has been loaded from {1}").format(err, options["source"]): option._subconfig}
) )
continue
except AttributeOptionError as err: except AttributeOptionError as err:
if err.code == "option-not-found": if err.code == "option-not-found":
self.unknowns.append( if self.invalid_user_data_error:
_( msg = _(
'variable or family "{0}" does not exist, it will be ignored when loading from {1}' 'variable or family "{0}" does not exist, it has been loading from {1}'
).format(err.path, options["source"])
) )
else:
msg = _(
'variable or family "{0}" does not exist, it will be ignored when loading from {1}'
)
self.unknowns.append(msg.format(err.path, options["source"]))
elif err.code == "option-dynamic": elif err.code == "option-dynamic":
self.invalids.append( if self.invalid_user_data_error:
_( msg = _(
'"{0}" is the name of a dynamic family, it has been loading from {1}'
)
else:
msg = _(
'"{0}" is the name of a dynamic family, it will be ignored when loading from {1}' '"{0}" is the name of a dynamic family, it will be ignored when loading from {1}'
).format(option.description(with_quote=True), options["source"]) )
self.invalids.append(
{msg.format(option.description(with_quote=True), options["source"]): option._subconfig}
) )
else: else:
self.invalids.append( self.invalids.append(
@ -361,86 +376,122 @@ class UserDatas:
properties = display_list( properties = display_list(
[_(prop) for prop in err.proptype], add_quote=False [_(prop) for prop in err.proptype], add_quote=False
) )
err_path = err._subconfig.path err_path = err.subconfig.path
err_description = err.subconfig.option.impl_get_display_name(err.subconfig)
display_name = option.description(with_quote=True) display_name = option.description(with_quote=True)
if index is not None: if index is not None:
if path == err_path: if path == err_path:
self.unknowns.append( if self.invalid_user_data_error:
_( msg = _(
'variable {0} at index "{1}" is {2}, it will be ignored when loading from {3}' 'variable {0} at index "{1}" is {2}, it has been loading from {3}'
).format(
display_name,
index,
properties,
options["source"],
)
) )
else: else:
self.unknowns.append( msg = _(
_( 'variable {0} at index "{1}" is {2}, it will be ignored when loading from {3}'
'family {0} is {1}, {2} at index "{3}" will be ignored when loading from {4}' )
).format( self.unknowns.append({
err._name, msg.format(
display_name,
index,
properties,
options["source"],
): option._subconfig}
)
else:
if self.invalid_user_data_error:
msg = _(
'family {0} is {1}, {2} at index "{3}", it has been loading from {4}'
)
else:
msg = _(
'family {0} is {1}, {2} at index "{3}", it will be ignored when loading from {4}'
)
self.unknowns.append({
msg.format(
err_description,
properties, properties,
display_name, display_name,
index, index,
options["source"], options["source"],
) ): option._subconfig}
) )
else: else:
if path == err_path: if path == err_path:
self.unknowns.append( if self.invalid_user_data_error:
_( msg = _(
"variable {0} is {1}, it will be ignored when loading from {2}" "variable is {0}, it has been loading from {1}"
).format(
display_name, properties, options["source"]
)
) )
else: else:
self.unknowns.append( msg = _(
_( "variable is {0}, it will be ignored when loading from {1}"
"family {0} is {1}, {2} will be ignored when loading from {3}" )
).format( self.unknowns.append({
err._name, msg.format(
properties, options["source"]
): option._subconfig}
)
else:
if self.invalid_user_data_error:
msg = _(
"family {0} is {1}, so cannot access to {2}, it has been loading from {3}"
)
else:
msg = _(
"family {0} is {1}, so cannot access to {2}, it will be ignored when loading from {3}"
)
self.unknowns.append({
msg.format(
err_description,
properties, properties,
display_name, display_name,
options["source"], options["source"],
) ): option._subconfig}
) )
else: else:
self.unknowns.append( self.unknowns.append({
_("{0} in {1}").format(err, options["source"]) _("{0} in {1}").format(err, options["source"]): option._subconfig}
) )
except LeadershipError as err: except LeadershipError as err:
self.unknowns.append(_("{0} in {1}").format(err, options["source"])) self.unknowns.append({_("{0} in {1}").format(err, options["source"]): option._subconfig})
except ValueError as err: except ValueError as err:
err.prefix = "" err.prefix = ""
if index is not None: if index is not None:
type_ = option.type(translation=True) type_ = option.type(translation=True)
self.invalids.append( if self.invalid_user_data_error:
_( msg = _(
'the value "{0}" is an invalid {1} for {2} at index "{3}", {4}, it has been loading from {5}'
)
else:
msg = _(
'the value "{0}" is an invalid {1} for {2} at index "{3}", {4}, it will be ignored when loading from {5}' 'the value "{0}" is an invalid {1} for {2} at index "{3}", {4}, it will be ignored when loading from {5}'
).format( )
self.invalids.append({
msg.format(
self._display_value(option, value), self._display_value(option, value),
type_, type_,
option.description(with_quote=True), option.description(with_quote=True),
index, index,
err, err,
options["source"], options["source"],
) ): option._subconfig}
) )
else: else:
type_ = option.type(translation=True) type_ = option.type(translation=True)
self.invalids.append( if self.invalid_user_data_error:
_( msg = _(
'the value "{0}" is an invalid {1} for {2}, {3}, it will be ignored when loading from {4}' 'the value "{0}" is an invalid {1}, {2}, it has been loading from {3}'
).format( )
else:
msg = _(
'the value "{0}" is an invalid {1}, {2}, it will be ignored when loading from {3}'
)
self.invalids.append({
msg.format(
self._display_value(option, value), self._display_value(option, value),
type_, type_,
option.description(with_quote=True),
err, err,
options["source"], options["source"],
) ): option._subconfig}
) )
except AttributeOptionError as err: except AttributeOptionError as err:
if err.code == "option-dynamic": if err.code == "option-dynamic":
@ -451,9 +502,8 @@ class UserDatas:
is_secret_manager = options.get("secret_manager", False) is_secret_manager = options.get("secret_manager", False)
if is_secret_manager and isinstance(value, tuple): if is_secret_manager and isinstance(value, tuple):
# it's a function # it's a function
value = value[0]( params = tuple([ParamValue(val) for val in value[1:]])
*value[1:], option=option, warnings=self.warnings, errors=self.errors value = Calculation(value[0], Params(params, kwargs={"option": ParamValue(option)}))
)
option.value.set(value) option.value.set(value)