YAML

I use ruamel.yaml because it preserves comments, which are often used in config files.

Loading:

Load A YAML file or string:

with YAML() as yaml:
    yaml.load(source)

Load multiple YAML documents (delimited by ---) in the same source:

with YAML() as yaml:
    for entry in yaml.load_all(multi_doc_source): 
        pass

Example:

class AtomicFileUpdate():

    def __init__(self, filename):
        self.filename = filename
        self._commit = False

    def __enter__(self):
        self.input = open(self.filename, 'r')
        if isinstance(self.filename, Path):
            self.tmp_filename = Path(
                self.filename.parent,
                self.filename.name + '.tmp')
        else:
            self.tmp_filename = self.filename + '.tmp'
        self.output = open(self.tmp_filename, 'w')
        return self

    def __exit__(self, *args):
        self.input.close()

        self.output.flush()
        os.fsync(self.output.fileno())
        self.output.close()

        if self._commit:
            os.rename(self.tmp_filename, self.filename)
        else:
            os.remove(self.tmp_filename)

    def commit(self):
        self._commit = True


with AtomicFileUpdate(day_file) as file, YAML(output=file.output) as yaml:
    try:
        for i, data in enumerate(yaml.load_all(file.input)):
            time_log = self.time_log_schema.load(data)
            data, valid, = self._update_entry(i, data, time_log)
            if valid:
                data, message = self._upload_entry_to_harvest(day, data, time_log)
                results.append(message)
            else:
                results.append('Entry invalid, skipping')
            yaml.dump(data)
        file.commit()
    except MarshmallowValidationError:
        raise InvalidFileError(f'{i:02d} entry is not parseable, skipping this file')

Last updated

Was this helpful?