Hướng dẫn load yaml file python

Show

    I made my own script for this. Feel free to use it, as long as you keep the attribution. The script can parse yaml from a file (function load), parse yaml from a string (function loads) and convert a dictionary into yaml (function dumps). It respects all variable types.

    # © didlly AGPL-3.0 License - github.com/didlly
    
    def is_float(string: str) -> bool:
        try:
            float(string)
            return True
        except ValueError:
            return False
    
    
    def is_integer(string: str) -> bool:
        try:
            int(string)
            return True
        except ValueError:
            return False
    
    
    def load(path: str) -> dict:
        with open(path, "r") as yaml:
            levels = []
            data = {}
            indentation_str = ""
    
            for line in yaml.readlines():
                if line.replace(line.lstrip(), "") != "" and indentation_str == "":
                    indentation_str = line.replace(line.lstrip(), "").rstrip("\n")
                if line.strip() == "":
                    continue
                elif line.rstrip()[-1] == ":":
                    key = line.strip()[:-1]
                    quoteless = (
                        is_float(key)
                        or is_integer(key)
                        or key == "True"
                        or key == "False"
                        or ("[" in key and "]" in key)
                    )
    
                    if len(line.replace(line.strip(), "")) // 2 < len(levels):
                        if quoteless:
                            levels[len(line.replace(line.strip(), "")) // 2] = f"[{key}]"
                        else:
                            levels[len(line.replace(line.strip(), "")) // 2] = f"['{key}']"
                    else:
                        if quoteless:
                            levels.append(f"[{line.strip()[:-1]}]")
                        else:
                            levels.append(f"['{line.strip()[:-1]}']")
                    if quoteless:
                        exec(
                            f"data{''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}[{key}]"
                            + " = {}"
                        )
                    else:
                        exec(
                            f"data{''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}['{key}']"
                            + " = {}"
                        )
    
                    continue
    
                key = line.split(":")[0].strip()
                value = ":".join(line.split(":")[1:]).strip()
    
                if (
                    is_float(value)
                    or is_integer(value)
                    or value == "True"
                    or value == "False"
                    or ("[" in value and "]" in value)
                ):
                    if (
                        is_float(key)
                        or is_integer(key)
                        or key == "True"
                        or key == "False"
                        or ("[" in key and "]" in key)
                    ):
                        exec(
                            f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}[{key}] = {value}"
                        )
                    else:
                        exec(
                            f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}['{key}'] = {value}"
                        )
                else:
                    if (
                        is_float(key)
                        or is_integer(key)
                        or key == "True"
                        or key == "False"
                        or ("[" in key and "]" in key)
                    ):
                        exec(
                            f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}[{key}] = '{value}'"
                        )
                    else:
                        exec(
                            f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}['{key}'] = '{value}'"
                        )
        return data
    
    
    def loads(yaml: str) -> dict:
        levels = []
        data = {}
        indentation_str = ""
    
        for line in yaml.split("\n"):
            if line.replace(line.lstrip(), "") != "" and indentation_str == "":
                indentation_str = line.replace(line.lstrip(), "")
            if line.strip() == "":
                continue
            elif line.rstrip()[-1] == ":":
                key = line.strip()[:-1]
                quoteless = (
                    is_float(key)
                    or is_integer(key)
                    or key == "True"
                    or key == "False"
                    or ("[" in key and "]" in key)
                )
    
                if len(line.replace(line.strip(), "")) // 2 < len(levels):
                    if quoteless:
                        levels[len(line.replace(line.strip(), "")) // 2] = f"[{key}]"
                    else:
                        levels[len(line.replace(line.strip(), "")) // 2] = f"['{key}']"
                else:
                    if quoteless:
                        levels.append(f"[{line.strip()[:-1]}]")
                    else:
                        levels.append(f"['{line.strip()[:-1]}']")
                if quoteless:
                    exec(
                        f"data{''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}[{key}]"
                        + " = {}"
                    )
                else:
                    exec(
                        f"data{''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}['{key}']"
                        + " = {}"
                    )
    
                continue
    
            key = line.split(":")[0].strip()
            value = ":".join(line.split(":")[1:]).strip()
    
            if (
                is_float(value)
                or is_integer(value)
                or value == "True"
                or value == "False"
                or ("[" in value and "]" in value)
            ):
                if (
                    is_float(key)
                    or is_integer(key)
                    or key == "True"
                    or key == "False"
                    or ("[" in key and "]" in key)
                ):
                    exec(
                        f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}[{key}] = {value}"
                    )
                else:
                    exec(
                        f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}['{key}'] = {value}"
                    )
            else:
                if (
                    is_float(key)
                    or is_integer(key)
                    or key == "True"
                    or key == "False"
                    or ("[" in key and "]" in key)
                ):
                    exec(
                        f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}[{key}] = '{value}'"
                    )
                else:
                    exec(
                        f"data{'' if line == line.strip() else ''.join(str(i) for i in levels[:line.replace(line.lstrip(), '').count(indentation_str) if indentation_str != '' else 0])}['{key}'] = '{value}'"
                    )
    
        return data
    
    
    def dumps(yaml: dict, indent="") -> str:
        """A procedure which converts the dictionary passed to the procedure into it's yaml equivalent.
    
        Args:
            yaml (dict): The dictionary to be converted.
    
        Returns:
            data (str): The dictionary in yaml form.
        """
    
        data = ""
    
        for key in yaml.keys():
            if type(yaml[key]) == dict:
                data += f"\n{indent}{key}:\n"
                data += dumps(yaml[key], f"{indent}  ")
            else:
                data += f"{indent}{key}: {yaml[key]}\n"
    
        return data
    
    
    print(load("config.yml"))
    

    Example

    config.yml

    level 0 value: 0
    
    level 1:
      level 1 value: 1
      level 2:
        level 2 value: 2
    
    level 1 2:
      level 1 2 value: 1 2
      level 2 2:
        level 2 2 value: 2 2
    

    Output

    {'level 0 value': 0, 'level 1': {'level 1 value': 1, 'level 2': {'level 2 value': 2}}, 'level 1 2': {'level 1 2 value': '1 2', 'level 2 2': {'level 2 2 value': 2 2}}}