@catch_nb_assignment<EOL><INDENT>def notebook_complete(self, **kwargs):<DEDENT>
self.end_time = self.now()<EOL>self.nb.metadata.papermill['<STR_LIT>'] = self.end_time.isoformat()<EOL>if self.nb.metadata.papermill.get('<STR_LIT>'):<EOL><INDENT>self.nb.metadata.papermill['<STR_LIT>'] = (<EOL>self.end_time - self.start_time<EOL>).total_seconds()<EOL><DEDENT>for cell in self.nb.cells:<EOL><INDENT>if cell.metadata.papermill['<STR_LIT:status>'] == self.FAILED:<EOL><INDENT>break<EOL><DEDENT>elif cell.metadata.papermill['<STR_LIT:status>'] == self.PENDING:<EOL><INDENT>cell.metadata.papermill['<STR_LIT:status>'] = self.COMPLETED<EOL><DEDENT><DEDENT>self.complete_pbar()<EOL>self.cleanup_pbar()<EOL>self.save()<EOL>
Finalize the metadata for a notebook and save the notebook to
the output path.

Called by Engine when execution concludes, regardless of exceptions.