Source code for multidoc.parsing.io

import os

from . import logger
import yaml
from yaml.parser import ParserError, ScannerError
from multidoc.regex import p_api_tag
import re

[docs]def yaml2dict(path, include_name_error=False, **kwargs): """Yaml file parser. Parameters ---------- path : os.PathLike or str Path of the ``yaml`` file to be loaded. _locals : dict[str, Any] List of definitions to parse in the yaml files. See examples for how they affect yaml loading. include_name_error : bool, default=True Include tag evaluations that return a NameError Examples ======== Given the following example ``yaml`` file: .. code-block:: yaml :caption: example.yaml package: name: name-cpp # [cpp] name: name-py # [py] modules: - module - module-py # [py] - module-cpp # [cpp] - module-not-cpp # [not cpp] - module-not-py # [not py] - module-both # [py or cpp] - module-both # [py and cpp] >>> yaml2dict("../tests/example.yaml") {'package': None, 'modules': ['module']} >>> yaml2dict("../tests/example.yaml", cpp=True) {'package': {'name': 'name-cpp'}, 'modules': ['module', 'module-cpp']} >>> yaml2dict("../tests/example.yaml", py=True) {'package': {'name': 'name-py'}, 'modules': ['module', 'module-py']} >>> yaml2dict("../tests/example.yaml", cpp=True, py=False) {'package': {'name': 'name-cpp'}, 'modules': ['module', 'module-cpp', 'module-not-py']} Returns ------- dict ``yaml`` loaded into memory as Python dict, parsed for definitions. """ # update the local variable space for eval of tag locals().update(kwargs) if kwargs else None logger.info(f"Parsing yaml file: {path} with kwargs: {kwargs}") p_api_tag = re.compile(r"(?P<parsed>.*)#\s*\[(?P<expr>.*)\]") # open the yaml file! with open(path) as file: # logger.info(f"Parsing yaml file :{file}") # read the raw lines raw_lines = file.readlines() # create list for processed lines processed_lines = [] # iterate through lines for line in raw_lines: match = p_api_tag.match(line) # -> re.compile(r"(?P<parsed>.*)#\s*\[(?P<expr>.*)\]") if match: # there's an expr on this line try: # if the expr is True, add to lines, else ignore if eval(match.group("expr")): processed_lines += match.group("parsed") + "\n" except NameError: # if the expr raises a NameError (e.g. undefined var in expr) if include_name_error: processed_lines += match.group("parsed") + "\n" else: pass else: processed_lines += line # apply line check truth to all raw lines, retrieving those that return true try: return yaml.load("".join(processed_lines), yaml.Loader) except (ParserError, ScannerError) as e: broken_path = f"BROKEN-{kwargs}-{os.path.basename(path)}" with open(broken_path, "w") as f: f.write("".join(processed_lines)) logger.error(f"Broken .yaml file {path} dumped as {broken_path}.") raise e
if __name__ == "__main__": d = yaml2dict("../testing/example-1.yaml", cpp=True, py=False) print(d)