Finalize metadata for a cell and save notebook.

        Optionally called by engines during execution to finalize the
        metadata for a cell and save the notebook to the output path.

def cell_complete(self, cell, cell_index=None, **kwargs):
        """
        Finalize metadata for a cell and save notebook.

        Optionally called by engines during execution to finalize the
        metadata for a cell and save the notebook to the output path.
        """
        end_time = self.now()

        if self.log_output:
            ceel_num = cell_index + 1 if cell_index is not None else ''
            logger.info('Ending Cell {:-<43}'.format(ceel_num))
            # Ensure our last cell messages are not buffered by python
            sys.stdout.flush()
            sys.stderr.flush()

        cell.metadata.papermill['end_time'] = end_time.isoformat()
        if cell.metadata.papermill.get('start_time'):
            start_time = dateutil.parser.parse(cell.metadata.papermill['start_time'])
            cell.metadata.papermill['duration'] = (end_time - start_time).total_seconds()
        if cell.metadata.papermill['status'] != self.FAILED:
            cell.metadata.papermill['status'] = self.COMPLETED

        self.save()
        if self.pbar:
            self.pbar.update(1)