feat: add 'document_a_type' option

This commit is contained in:
egarette@silique.fr 2026-01-14 13:56:51 +01:00
parent 8d305c96fb
commit 8e2e70486c
5 changed files with 105 additions and 63 deletions

View file

@ -49,13 +49,17 @@ class Annotator(Walk):
self,
objectspace,
*args, # pylint: disable=unused-argument
**kwargs,
) -> None:
if not objectspace.paths:
return
self.objectspace = objectspace
self.default_values = self.objectspace.rougailconfig[
"doc.default_values"
]
if "force_default_value" in kwargs:
self.default_values = kwargs["force_default_value"]
else:
self.default_values = self.objectspace.rougailconfig[
"doc.default_values"
]
self.regexp_description_get_paths = None
self.populate_family()
self.populate_variable()
@ -283,12 +287,16 @@ class Annotator(Walk):
"propertyerror": values.propertyerror,
}
if isinstance(values, InformationCalculation):
return {
"type": "information",
"value": self.calculation_to_information_information(
value, variable_path = self.calculation_to_information_information(
values, version, path
),
)
ret = {
"type": "information",
"value": value,
}
if variable_path:
ret["path"] = variable_path
return ret
if isinstance(values, (IdentifierCalculation, IdentifierPropertyCalculation)):
return {
"type": "identifier",
@ -347,10 +355,10 @@ class Annotator(Walk):
) -> Union[str, bool]:
if values.variable:
variable_path = self.get_path_from_variable(values, version, path)
return _('the value of the information "{0}" of the variable "{1}"').format(
values.information, variable_path
)
return _('the value of the global information "{0}"').format(values.information)
return _('the value of the information "{0}" of the variable "{{0}}"').format(
values.information
), variable_path
return _('the value of the global information "{0}"').format(values.information), None
def calculation_to_information_identifier(
self, values, prop: str, version: str

View file

@ -202,6 +202,10 @@ doc:
types:
- file
document_a_type:
description: {_("Documentation a structural type")}
default: false
tabulars:
description: {_('Variables and changelog documentation')}
disabled:

View file

@ -44,6 +44,7 @@ class RougailOutputDoc(Examples, Changelog):
"""Rougail Output Doc:
Generate documentation from rougail description files
"""
output_name = "doc"
def __init__(
self,
@ -61,34 +62,17 @@ class RougailOutputDoc(Examples, Changelog):
from rougail import RougailConfig
rougailconfig = RougailConfig
if rougailconfig["step.output"] != "doc":
rougailconfig["step.output"] = "doc"
if rougailconfig["step.output"] != "doc":
raise Exception("doc is not set as step.output")
self.outputs = OutPuts().get()
self.conf = config
if rougailconfig["step.output"] != self.output_name:
rougailconfig["step.output"] = self.output_name
if rougailconfig["step.output"] != self.output_name:
raise Exception(_("{0} is not set as step.output").format(self.output_name))
self.config = config
if true_config is None:
self.true_config = config
else:
self.true_config = true_config
self.modes_level = rougailconfig["modes_level"]
self.disabled_modes = []
if self.modes_level:
for mode in self.modes_level:
for prop in self.conf.property.get():
if mode != prop:
continue
self.disabled_modes.append(prop)
# self.conf.property.read_write()
# # self.conf.property.remove("cache")
self.rougailconfig = rougailconfig
self.informations = None
try:
groups.namespace
self.support_namespace = True
except AttributeError:
self.support_namespace = False
self.property_to_string = get_properties_to_string()
self.formatter = None
super().__init__()
@ -116,17 +100,33 @@ class RougailOutputDoc(Examples, Changelog):
return ret
def load(self):
self.document_a_type = self.rougailconfig["doc.document_a_type"]
self.modes_level = self.rougailconfig["modes_level"]
self.disabled_modes = []
if self.modes_level:
for mode in self.modes_level:
for prop in self.true_config.property.get():
if mode != prop:
continue
self.disabled_modes.append(prop)
try:
groups.namespace
self.support_namespace = True
except AttributeError:
self.support_namespace = False
self.property_to_string = get_properties_to_string()
self.outputs = OutPuts().get()
self.dynamic_paths = {}
config = self.conf.unrestraint
config = self.config.unrestraint
self.populate_dynamics(config=config)
informations = self.parse_families(config)
if informations is None:
informations = {}
elif self.conf.type() not in ['config', 'metaconfig', 'groupconfig', 'mixconfig']:
elif self.config.type() not in ['config', 'metaconfig', 'groupconfig', 'mixconfig']:
root_informations = {}
infos = root_informations
family = self.true_config
for path in self.conf.path().split('.'):
for path in self.config.path().split('.'):
family = family.option(path)
name = family.name(uncalculated=True)
infos[name] = self.get_root_family(family)
@ -148,7 +148,7 @@ class RougailOutputDoc(Examples, Changelog):
def populate_dynamics(self, *, config=None, reload=False):
if config is None:
config = self.conf.unrestraint
config = self.config.unrestraint
self._populate_dynamics(config, reload)
def _populate_dynamics(self, family, reload, uncalculated=False) -> None:
@ -177,7 +177,7 @@ class RougailOutputDoc(Examples, Changelog):
self.dynamic_paths[path] = {
"names": [],
"identifiers": [],
"path": path,
"path": self.doc_path(path),
}
if not obj.information.get("forced_description", False):
self.dynamic_paths[path]["description"] = self._convert_description(
@ -459,7 +459,7 @@ class RougailOutputDoc(Examples, Changelog):
child.description(uncalculated=True), type_, its_a_path=False
)
if not child.isdynamic():
informations["path"] = child.path(uncalculated=True)
informations["path"] = self.doc_path(child.path(uncalculated=True))
informations["names"] = [child.name()]
if description is not None:
informations["description"] = description
@ -672,21 +672,22 @@ class RougailOutputDoc(Examples, Changelog):
if isinstance(calculation, list):
values = []
for cal in calculation:
value = self._calculation_to_string(child, cal, prop, inside_list=True)
value = self._calculation_to_string(child, cal, prop)
if value is not None:
values.append(value)
return values
return self._calculation_to_string(child, calculation, prop)
def _calculation_to_string(self, child, calculation, prop, inside_list=False):
def _calculation_to_string(self, child, calculation, prop):
if "description" in calculation:
values = calculation["description"]
# if not values.endswith("."):
# values += "."
return calculation
if "type" not in calculation:
return calculation["value"]
if calculation["type"] == "jinja":
values = calculation
if self.document_a_type and "variables" in values:
for variable in list(values["variables"]):
variable["path"] = self.doc_path(variable["path"])
elif "type" not in calculation:
values = calculation["value"]
elif calculation["type"] == "jinja":
values = self._calculation_jinja_to_string(child, calculation, prop)
elif calculation["type"] == "variable":
values = self._calculation_variable_to_string(child, calculation, prop)
@ -697,10 +698,11 @@ class RougailOutputDoc(Examples, Changelog):
values = _("the value of the identifier")
elif calculation["type"] == "information":
values = calculation["value"]
if "path" in calculation:
variable_path = self.doc_path(calculation["path"])
values = values.format(variable_path)
else:
values = _("the value of the {0}").format(calculation["type"])
# if not inside_list and isinstance(values, str) and not values.endswith("."):
# values += "."
return values
def _calculation_jinja_to_string(self, child, calculation, prop):
@ -717,7 +719,7 @@ class RougailOutputDoc(Examples, Changelog):
'"{0}" is a calculation for {1} but has no description in {2}'
).format(
prop,
child.path(),
self.doc_path(child.path()),
display_xmlfiles(child.information.get("ymlfiles")),
)
warn(
@ -751,7 +753,7 @@ class RougailOutputDoc(Examples, Changelog):
if cpath:
all_is_undocumented = False
path_obj = {
"path": cpath,
"path": self.doc_path(cpath),
}
if identifiers:
path_obj["identifiers"] = identifiers
@ -813,7 +815,7 @@ class RougailOutputDoc(Examples, Changelog):
values = {
"message": true_msg,
"path": {
"path": calculation["ori_path"],
"path": self.doc_path(calculation["ori_path"]),
},
"description": description,
}
@ -901,7 +903,7 @@ class RougailOutputDoc(Examples, Changelog):
else:
msg = _('when the variable "{{0}}" has the value "{0}"')
path_obj = {
"path": variable_path,
"path": self.doc_path(variable_path),
}
if identifiers:
path_obj["identifiers"] = identifiers
@ -925,7 +927,7 @@ class RougailOutputDoc(Examples, Changelog):
+ "$"
)
information = self.dynamic_paths[current_path]
path = information["path"]
path = current_path
for identifiers in information["identifiers"]:
cpath = calc_path(path, identifiers=identifiers)
if regexp and not regexp.search(cpath):
@ -948,3 +950,10 @@ class RougailOutputDoc(Examples, Changelog):
if variable and self.is_inaccessible_user_data(variable):
return self._get_unmodified_default_value(variable)
raise VariableCalculationDependencyError()
def doc_path(self, path):
if self.document_a_type:
if not '.' in path:
return None
return path.split('.', 1)[-1]
return path

View file

@ -57,18 +57,34 @@ class Examples: # pylint: disable=no-member,too-few-public-methods
return_string = ""
datas = []
if self.examples_mandatories:
if self.document_a_type:
col = list(self.examples_mandatories)
if len(col) == 1:
examples_mandatories = self.examples_mandatories[col[0]]
else:
examples_mandatories = self.examples_mandatories
else:
examples_mandatories = self.examples_mandatories
datas.extend([
self.formatter.title(
_("Example with mandatory variables not filled in"), self.level
),
self.formatter.yaml(self.examples_mandatories),
self.formatter.yaml(examples_mandatories),
self.formatter.end_family(self.level),
])
if self.examples:
if self.document_a_type:
col = list(self.examples)
if len(col) == 1:
examples = self.examples[col[0]]
else:
examples = self.examples
else:
examples = self.examples
datas.extend([self.formatter.title(
_("Example with all variables modifiable"), self.level
),
self.formatter.yaml(self.examples),
self.formatter.yaml(examples),
self.formatter.end_family(self.level),
])
return self.formatter.compute(datas)

View file

@ -1,7 +1,7 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2026
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
@ -332,6 +332,8 @@ class CommonFormatter:
return path
ret_paths = []
path = informations["path"]
if not path:
return None
if is_bold:
bold = self.bold
else:
@ -426,15 +428,14 @@ class CommonFormatter:
ret = [self.namespace_to_title(informations, level)]
else:
ret = [self.title(self.get_description("family", informations, {}, None), level)]
fam_info = self.family_informations()
if fam_info:
ret.append(fam_info)
msg = []
helps = informations.get("help")
if helps:
for help_ in helps:
msg.extend([to_phrase(h) for h in help_.strip().split('\n')])
msg.append(self.section(_("Path"), self.display_paths(informations, {}, None, with_anchor=False, is_bold=False), type_="family"))
path = self.display_paths(informations, {}, None, with_anchor=False, is_bold=False)
if path:
msg.append(self.section(_("Path"), path, type_="family"))
calculated_properties = []
property_str = self.property_to_string(informations, calculated_properties, {})
if property_str:
@ -447,7 +448,11 @@ class CommonFormatter:
self.section(_("Identifiers"), informations["identifier"], type_="family")
)
starts_line = self.family_informations_starts_line()
ret.append(self.family_informations_ends_line().join([starts_line + m for m in msg]) + self.end_family_informations())
if msg:
fam_info = self.family_informations()
if fam_info:
ret.append(fam_info)
ret.append(self.family_informations_ends_line().join([starts_line + m for m in msg]) + self.end_family_informations())
return ret
def family_informations_starts_line(self) -> str: