diff --git a/src/rougail/convert/object_model.py b/src/rougail/convert/object_model.py index 41ba9c53f..0ab88d0b1 100644 --- a/src/rougail/convert/object_model.py +++ b/src/rougail/convert/object_model.py @@ -485,7 +485,7 @@ class JinjaCalculation(Calculation): class _VariableCalculation(Calculation): variable: StrictStr - propertyerror: bool = True + propertyerror: Union[Literal["transitive"], bool] = True allow_none: bool = False optional: bool = False diff --git a/src/rougail/convert/tiramisureflector.py b/src/rougail/convert/tiramisureflector.py index 5ff402e67..a2e51c295 100644 --- a/src/rougail/convert/tiramisureflector.py +++ b/src/rougail/convert/tiramisureflector.py @@ -372,8 +372,11 @@ class Common: params.append("optional=True") else: param_type = "ParamOption" - if not param.get("propertyerror", True): + propertyerror = param.get("propertyerror", True) + if not propertyerror: params.append("notraisepropertyerror=True") + elif propertyerror == "transitive": + params.append("raisepropertyerror=True") return f'{param_type}({", ".join(params)})' def calculation_value( diff --git a/src/rougail/user_data.py b/src/rougail/user_data.py index 8f86b9b82..0e362b702 100644 --- a/src/rougail/user_data.py +++ b/src/rougail/user_data.py @@ -353,17 +353,32 @@ class UserData: _("{0}, it has been loaded from {1}").format(err, options["source"]): option._subconfig} ) continue + except AttributeOptionError as err: if err.code == "option-not-found": + err_path = err.path + if "." not in err_path: + subconfig = None + child_name = err_path + else: + parent_path, child_name = err_path.rsplit('.', 1) + subconfig = self.config.option(parent_path) + subconfig._set_subconfig() + err_msg = _( + 'variable or family "{0}" does not exist so cannot load "{1}' + ).format(child_name, path) if self.unknown_user_data_error: msg = _( - 'variable or family "{0}" does not exist, it has been loading from {1}' + '{0}, it has been loading from {1}' ) else: msg = _( - 'variable or family "{0}" does not exist, it will be ignored when loading from {1}' + '{0}, it will be ignored when loading from {1}' ) - self.unknowns.append(msg.format(err.path, options["source"])) + msg = msg.format(err_msg, options["source"]) + if subconfig is not None: + msg = {msg: subconfig._subconfig} + self.unknowns.append(msg) elif err.code == "option-dynamic": if self.invalid_user_data_error: msg = _( @@ -373,9 +388,7 @@ class UserData: msg = _( '"{0}" is the name of a dynamic family, it will be ignored when loading from {1}' ) - self.invalids.append( - {msg.format(option.description(with_quote=True), options["source"]): option._subconfig} - ) + self.invalids.append({msg.format(option.description(with_quote=True), options["source"]): option._subconfig}) else: self.invalids.append( _("{0} loaded from {1}").format(err, options["source"])