""" 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 option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . """ from ruamel.yaml import CommentedMap from ruamel.yaml.representer import RoundTripRepresenter from tiramisu import Calculation, owners from .utils import _, dump, to_phrase # XXX explicit null (see rougail-output-formatter # pylint: disable=W0511 def represent_none( self, data ): # pylint: disable=missing-function-docstring,unused-argument return self.represent_scalar("tag:yaml.org,2002:null", "null") def represent_str(self, data): # pylint: disable=missing-function-docstring if data == "": return self.represent_scalar("tag:yaml.org,2002:null", "") return self.represent_scalar("tag:yaml.org,2002:str", data) RoundTripRepresenter.add_representer(type(None), represent_none) RoundTripRepresenter.add_representer(str, represent_str) # XXX # pylint: disable=W0511 class Examples: # pylint: disable=no-member,too-few-public-methods """Build examples""" def __init__(self): self.comment_examples = None self.level = None self.comment_examples_column = None def gen_doc_examples(self): """Return examples""" self.comment_examples = self.rougailconfig["doc.examples.comment"] self.level = self.rougailconfig["doc.title_level"] if self.comment_examples: self.comment_examples_column = self.rougailconfig[ "doc.examples.comment_column" ] config = self.true_config.config.copy() config.information.set("description_type", "description") config.property.read_write() self._set_mandatories(config) datas = [] for only_modified in [True, False]: if not only_modified: self._set_examples(config) results = CommentedMap() true_results = results if self.true_config == self.config: root_config = config else: root_config = config.option(self.config.path()) current_option = self.true_config subpaths = self.config.path().split(".") if not self.config.isoptiondescription(): subpaths = subpaths[:-1] for subpath in subpaths: current_option = current_option.option(subpath) name = current_option.name() results[name] = CommentedMap() self._set_description(results, name, current_option) results = results[name] if root_config.isoptiondescription(): self._example_parse_family( root_config.value.get(), results, only_modified ) else: self._set_example_value( results, root_config, root_config.value.get(), only_modified ) if results: if only_modified: title = _("Example with mandatory variables not filled in") else: title = _("Example with all variables modifiable") datas.extend( [ self.formatter.title(title, self.level), self.formatter.yaml(dump(true_results)), self.formatter.end_family(self.level), ] ) return self.formatter.compute(datas) def _set_mandatories(self, config): for calculated_too in [False, True]: for option in config.value.mandatory(): if not calculated_too: uncalculated = option.value.default(uncalculated=True) if isinstance(uncalculated, Calculation): continue self._set_value_example(option, self._get_an_example(option)) def _get_an_example(self, option): value = self._get_value_from_example(option) if value is None: variable_type = option.information.get("type") if variable_type == "choice": value = option.value.list() if not self._is_multi(option) and value: if value[0] is not None: value = value[0] elif len(value) > 1: value = value[1] else: value = self.convert_option.get(option.information.get("type"), {}).get( "example" ) if value is None: value = "example" if self._is_multi(option): value = [value] if option.isfollower() and option.index() and variable_type == "string": value += str(option.index()) return value def _set_examples(self, config): def _set_example(subconfig): for option in subconfig: if option.isoptiondescription(): _set_example(option) else: # force examples value + do not let empty value examples = self._get_value_from_example(option) if examples is None: if self._is_multi(option): if not option.value.get(): examples = self._get_an_example(option) elif option.value.get() is None: examples = self._get_an_example(option) if examples is None: continue self._set_value_example(option, examples) _set_example(config) self._set_mandatories(config) def _set_value_example(self, option, value): if option.isleader(): ori_len = option.value.len() current_len = len(value) if ori_len > current_len: for idx in reversed(range(current_len, ori_len)): option.value.pop(idx) option.value.set(value) def _get_value_from_example(self, option): examples = option.information.get("examples", None) if examples is None: return None if self._is_multi(option): examples = list(examples) else: examples = examples[0] return examples def _is_multi(self, option): if option.isfollower(): return option.issubmulti() return option.ismulti() def _example_parse_family(self, config, results, only_modified): for option, values in config.items(): if option.isoptiondescription(): if option.isleadership(): subresults = self._example_parse_leadership(values, only_modified) if subresults: name = option.name() results[name] = subresults self._set_description(results, name, option) else: subresults = CommentedMap() self._example_parse_family(values, subresults, only_modified) if subresults: name = option.name() results[name] = subresults self._set_description(results, name, option) else: self._set_example_value(results, option, values, only_modified) def _set_example_value(self, results, option, values, only_modified): if self._is_valid_owner(option, only_modified): name = option.name() results[name] = values self._set_description(results, name, option) def _is_valid_owner(self, option, only_modified): return ( option.type(only_self=True, translation=False) != "symlink" and not only_modified or (not option.owner.isdefault() and option.owner.get() != owners.forced) ) def _example_parse_leadership(self, values, only_modified): leadership_iter = iter(values.items()) leader, leader_values = next(leadership_iter) if not self._is_valid_owner(leader, only_modified): return None leadership = [CommentedMap() for idx in range(len(leader_values))] for idx, value in enumerate(leader_values): self._set_example_value(leadership[idx], leader, value, only_modified) for option, value in leadership_iter: idx = option.index() self._set_example_value(leadership[idx], option, value, only_modified) return leadership def _set_description(self, results, name, option): if not self.comment_examples or option.information.get( "forced_description", False ): return description = to_phrase(option.description()) if description.endswith("."): description = description[:-1] results.yaml_add_eol_comment( description, name, column=self.comment_examples_column )