diff --git a/src/rougail/annotator/check.py b/src/rougail/annotator/check.py index 13fca9603..a959b8c48 100644 --- a/src/rougail/annotator/check.py +++ b/src/rougail/annotator/check.py @@ -72,7 +72,7 @@ class Annotator(TargetAnnotator, ParamAnnotator): """ remove_indexes = [] for check_idx, check in enumerate(constraints.check): - if not check.name in self.functions: + if not check.name in self.functions and not self.objectspace.just_doc: msg = _(f'cannot find check function "{check.name}"') raise DictConsistencyError(msg, 1, check.xmlfiles) if hasattr(check, 'param') and check.param == []: diff --git a/src/rougail/annotator/condition.py b/src/rougail/annotator/condition.py index cf6be2219..bfd5413b2 100644 --- a/src/rougail/annotator/condition.py +++ b/src/rougail/annotator/condition.py @@ -38,6 +38,11 @@ from rougail.annotator.param import ParamAnnotator from rougail.annotator.variable import Walk +class FakeVariable: + def __getattr__(self, name): + return None + + class Annotator(TargetAnnotator, ParamAnnotator, Walk): """Annotate condition """ @@ -222,7 +227,7 @@ class Annotator(TargetAnnotator, ParamAnnotator, Walk): listvars, fills, ) - elif not target.optional: + elif not target.optional and self.objectspace.just_doc is False: msg = f'cannot found target "{target.type}" "{target.name}"' raise DictConsistencyError(_(msg), 2, target.xmlfiles) remove_targets.append(target_idx) @@ -323,6 +328,9 @@ class Annotator(TargetAnnotator, ParamAnnotator, Walk): add_path_prefix=True, ) except DictConsistencyError as err: + if self.objectspace.just_doc: + condition.source = FakeVariable() + continue if err.errno == 36: msg = _(f'the source "{condition.source}" in condition cannot be a dynamic ' f'variable') diff --git a/src/rougail/annotator/fill.py b/src/rougail/annotator/fill.py index 3ad1a81ea..984fa8184 100644 --- a/src/rougail/annotator/fill.py +++ b/src/rougail/annotator/fill.py @@ -76,7 +76,7 @@ class Annotator(TargetAnnotator, ParamAnnotator): """ for fill in constraints.fill: # test if the function exists - if fill.name not in self.functions: + if not self.objectspace.just_doc and fill.name not in self.functions: msg = _(f'cannot find fill function "{fill.name}"') raise DictConsistencyError(msg, 25, fill.xmlfiles) for target in fill.target: diff --git a/src/rougail/annotator/param.py b/src/rougail/annotator/param.py index bf46cbc04..7529cf58f 100644 --- a/src/rougail/annotator/param.py +++ b/src/rougail/annotator/param.py @@ -90,7 +90,7 @@ class ParamAnnotator: path_prefix, ) except DictConsistencyError as err: - if err.errno != 42 or not param.optional: + if not self.objectspace.just_doc and (err.errno != 42 or not param.optional): raise err param_to_delete.append(param_idx) elif param.type == 'function': @@ -118,7 +118,7 @@ class ParamAnnotator: raise DictConsistencyError(msg, 53, obj.xmlfiles) elif param.type == 'index': for target in obj.target: - if not self.objectspace.paths.is_follower(target.name): + if not self.objectspace.just_doc and not self.objectspace.paths.is_follower(target.name): msg = _(f'"{param.type}" parameter cannot be set with target ' f'"{target.name.name}" which is not a follower variable') raise DictConsistencyError(msg, 60, obj.xmlfiles) diff --git a/src/rougail/annotator/target.py b/src/rougail/annotator/target.py index 339909864..0f9938794 100644 --- a/src/rougail/annotator/target.py +++ b/src/rougail/annotator/target.py @@ -91,7 +91,7 @@ class TargetAnnotator(Walk): if err.errno != 42: raise err # for optional variable - if not target.optional: + if not target.optional and not self.objectspace.just_doc: msg = f'cannot found target "{target.type}" "{target.name}"' raise DictConsistencyError(_(msg), 12, target.xmlfiles) from err remove_targets.append(index) diff --git a/src/rougail/convert.py b/src/rougail/convert.py index 5c0ec5932..752f92f32 100644 --- a/src/rougail/convert.py +++ b/src/rougail/convert.py @@ -63,6 +63,7 @@ class RougailConvert: """ def __init__(self, rougailconfig: RougailConfig=None, + just_doc: bool=False, ) -> None: if rougailconfig is None: rougailconfig = RougailConfig @@ -70,11 +71,9 @@ class RougailConvert: xmlreflector = Reflector(self.rougailconfig) self.rougailobjspace = RougailObjSpace(xmlreflector, self.rougailconfig, + just_doc, ) self.internal_functions = self.rougailconfig['internal_functions'] - self.functions_file = self.rougailconfig['functions_file'] - if not isinstance(self.functions_file, list): - self.functions_file = [self.functions_file] self.dictionaries = False self.annotator = False self.reflector = None @@ -111,7 +110,7 @@ class RougailConvert: path_prefix: str, namespace_description: str=None, ) -> List[str]: - for xmlfile, document in xmlreflector.load_dictionaries_from_folders(xmlfolders): + for xmlfile, document in xmlreflector.load_dictionaries_from_folders(xmlfolders, self.rougailobjspace.just_doc): self.rougailobjspace.xml_parse_document(xmlfile, document, namespace, @@ -122,9 +121,7 @@ class RougailConvert: def annotate(self): if self.annotator: raise DictConsistencyError(_('Cannot execute annotate multiple time'), 85, None) - SpaceAnnotator(self.rougailobjspace, - self.functions_file, - ) + SpaceAnnotator(self.rougailobjspace) self.annotator = True def reflexion(self, @@ -136,7 +133,10 @@ class RougailConvert: self.annotate() if self.reflector: raise DictConsistencyError(_('Cannot execute reflexion multiple time'), 86, None) - functions_file = [func for func in self.functions_file if func not in exclude_imports] + functions_file = self.rougailconfig['functions_file'] + if not isinstance(functions_file, list): + functions_file = [functions_file] + functions_file = [func for func in functions_file if func not in exclude_imports] self.reflector = TiramisuReflector(self.rougailobjspace, functions_file, self.internal_functions, diff --git a/src/rougail/objspace.py b/src/rougail/objspace.py index 0e857f9a8..4e7e923b8 100644 --- a/src/rougail/objspace.py +++ b/src/rougail/objspace.py @@ -28,7 +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 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -from typing import Optional +from typing import Optional, List from .i18n import _ from .reflector import Reflector @@ -106,7 +106,9 @@ class RougailObjSpace: def __init__(self, xmlreflector: Reflector, rougailconfig: 'RougailConfig', + just_doc: bool, ) -> None: + self.just_doc = just_doc self.space = ObjSpace() self.paths = Path(rougailconfig) @@ -201,6 +203,7 @@ class RougailObjSpace: namespace_description, redefine_variables, False, + True, ) def _xml_parse(self, # pylint: disable=R0913 @@ -211,6 +214,7 @@ class RougailObjSpace: namespace_description, redefine_variables, is_dynamic, + first_level, ) -> None: # var to check unique family name in a XML file family_names = [] @@ -218,6 +222,8 @@ class RougailObjSpace: if not isinstance(child.tag, str): # doesn't proceed the XML commentaries continue + if first_level and self.just_doc and child.tag == 'services': + continue if is_dynamic: is_sub_dynamic = True else: @@ -246,11 +252,12 @@ class RougailObjSpace: child, variableobj, ) - self.remove(child, - variableobj, - redefine_variables, - namespace, - ) + if not self.just_doc: + self.remove(child, + variableobj, + redefine_variables, + namespace, + ) if not exists: self.set_path(namespace, document, @@ -276,6 +283,7 @@ class RougailObjSpace: namespace_description, redefine_variables, is_sub_dynamic, + False, ) def get_variableobj(self, @@ -370,7 +378,7 @@ class RougailObjSpace: # manage object only if already exists, so cancel raise SpaceObjShallNotBeUpdated() redefine = convert_boolean(subspace.get('redefine', False)) - if redefine is True: + if redefine is True and not self.just_doc: # cannot redefine an inexistant object msg = _(f'Redefined object: "{name}" does not exist yet') raise DictConsistencyError(msg, 46, [xmlfile]) @@ -432,9 +440,10 @@ class RougailObjSpace: redefine = convert_boolean(child.attrib.get('redefine', False)) if redefine and child.tag == 'variable': # delete old values - has_value = hasattr(variableobj, 'value') - if has_value and len(child) != 0: + if hasattr(variableobj, 'value') and len(child) != 0: del variableobj.value + if self.just_doc: + variableobj.multi = len(child) > 1 for attr, val in child.attrib.items(): if attr == 'text' and child.tag in self.forced_text_elts_as_name: continue @@ -469,12 +478,12 @@ class RougailObjSpace: if child.attrib.get('remove_condition', False): self.remove_condition(variableobj.name) if child.attrib.get('remove_fill', False): - self.remove_fill(variableobj.name) + self.remove_fill(variableobj.name, variableobj.xmlfiles) elif child.tag == 'fill': for target in child: if target.tag == 'target' and \ self.paths.get_path(target.text, namespace) in redefine_variables: - self.remove_fill(target.text) + self.remove_fill(target.text, variableobj.xmlfiles) def remove_check(self, name): """Remove a check with a specified target @@ -515,11 +524,15 @@ class RougailObjSpace: def remove_fill(self, name: str, + xmlfiles: List[str], ) -> None: """Remove a fill with a specified target """ remove_fills = [] constraints = self.get_constraints() + if not hasattr(constraints, 'fill'): + msg = _(f'Cannot remove fill to "{name}", the variable has no fill yet') + raise DictConsistencyError(msg, 89, xmlfiles) for idx, fill in enumerate(constraints.fill): # pylint: disable=E1101 for target in fill.target: if target.name == name: @@ -579,6 +592,8 @@ class RougailObjSpace: def get_variables(objectspace): """Iter all variables from the objectspace """ + if not hasattr(objectspace.space, 'variables'): + return for family in objectspace.space.variables.values(): yield from _get_variables(family, objectspace.family) diff --git a/src/rougail/reflector.py b/src/rougail/reflector.py index 049370b49..a36961f08 100644 --- a/src/rougail/reflector.py +++ b/src/rougail/reflector.py @@ -71,6 +71,7 @@ class Reflector: def load_dictionaries_from_folders(self, folders: List[str], + just_doc: bool, ): """Loads all the dictionary files located in the folders' list @@ -90,8 +91,8 @@ class Reflector: if filename in filenames: raise DictConsistencyError(_(f'duplicate dictionary file name {filename}'), 78, [filenames[filename], full_filename]) filenames[filename] = (ext, full_filename) - if not filenames: - raise DictConsistencyError(_('there is no dictionary file'), 77, [folder]) + if not filenames and not just_doc: + raise DictConsistencyError(_('there is no dictionary file'), 77, folders) file_names = list(filenames.keys()) file_names.sort() for filename in file_names: