checkpoints.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. """
  2. Classes for managing Checkpoints.
  3. """
  4. # Copyright (c) Jupyter Development Team.
  5. # Distributed under the terms of the Modified BSD License.
  6. from tornado.web import HTTPError
  7. from traitlets.config.configurable import LoggingConfigurable
  8. class Checkpoints(LoggingConfigurable):
  9. """
  10. Base class for managing checkpoints for a ContentsManager.
  11. Subclasses are required to implement:
  12. create_checkpoint(self, contents_mgr, path)
  13. restore_checkpoint(self, contents_mgr, checkpoint_id, path)
  14. rename_checkpoint(self, checkpoint_id, old_path, new_path)
  15. delete_checkpoint(self, checkpoint_id, path)
  16. list_checkpoints(self, path)
  17. """
  18. def create_checkpoint(self, contents_mgr, path):
  19. """Create a checkpoint."""
  20. raise NotImplementedError
  21. def restore_checkpoint(self, contents_mgr, checkpoint_id, path):
  22. """Restore a checkpoint"""
  23. raise NotImplementedError
  24. def rename_checkpoint(self, checkpoint_id, old_path, new_path):
  25. """Rename a single checkpoint from old_path to new_path."""
  26. raise NotImplementedError
  27. def delete_checkpoint(self, checkpoint_id, path):
  28. """delete a checkpoint for a file"""
  29. raise NotImplementedError
  30. def list_checkpoints(self, path):
  31. """Return a list of checkpoints for a given file"""
  32. raise NotImplementedError
  33. def rename_all_checkpoints(self, old_path, new_path):
  34. """Rename all checkpoints for old_path to new_path."""
  35. for cp in self.list_checkpoints(old_path):
  36. self.rename_checkpoint(cp["id"], old_path, new_path)
  37. def delete_all_checkpoints(self, path):
  38. """Delete all checkpoints for the given path."""
  39. for checkpoint in self.list_checkpoints(path):
  40. self.delete_checkpoint(checkpoint["id"], path)
  41. class GenericCheckpointsMixin:
  42. """
  43. Helper for creating Checkpoints subclasses that can be used with any
  44. ContentsManager.
  45. Provides a ContentsManager-agnostic implementation of `create_checkpoint`
  46. and `restore_checkpoint` in terms of the following operations:
  47. - create_file_checkpoint(self, content, format, path)
  48. - create_notebook_checkpoint(self, nb, path)
  49. - get_file_checkpoint(self, checkpoint_id, path)
  50. - get_notebook_checkpoint(self, checkpoint_id, path)
  51. To create a generic CheckpointManager, add this mixin to a class that
  52. implement the above four methods plus the remaining Checkpoints API
  53. methods:
  54. - delete_checkpoint(self, checkpoint_id, path)
  55. - list_checkpoints(self, path)
  56. - rename_checkpoint(self, checkpoint_id, old_path, new_path)
  57. """
  58. def create_checkpoint(self, contents_mgr, path):
  59. model = contents_mgr.get(path, content=True)
  60. type_ = model["type"]
  61. if type_ == "notebook":
  62. return self.create_notebook_checkpoint(
  63. model["content"],
  64. path,
  65. )
  66. elif type_ == "file":
  67. return self.create_file_checkpoint(
  68. model["content"],
  69. model["format"],
  70. path,
  71. )
  72. else:
  73. raise HTTPError(500, "Unexpected type %s" % type)
  74. def restore_checkpoint(self, contents_mgr, checkpoint_id, path):
  75. """Restore a checkpoint."""
  76. type_ = contents_mgr.get(path, content=False)["type"]
  77. if type_ == "notebook":
  78. model = self.get_notebook_checkpoint(checkpoint_id, path)
  79. elif type_ == "file":
  80. model = self.get_file_checkpoint(checkpoint_id, path)
  81. else:
  82. raise HTTPError(500, "Unexpected type %s" % type_)
  83. contents_mgr.save(model, path)
  84. # Required Methods
  85. def create_file_checkpoint(self, content, format, path):
  86. """Create a checkpoint of the current state of a file
  87. Returns a checkpoint model for the new checkpoint.
  88. """
  89. raise NotImplementedError
  90. def create_notebook_checkpoint(self, nb, path):
  91. """Create a checkpoint of the current state of a file
  92. Returns a checkpoint model for the new checkpoint.
  93. """
  94. raise NotImplementedError
  95. def get_file_checkpoint(self, checkpoint_id, path):
  96. """Get the content of a checkpoint for a non-notebook file.
  97. Returns a dict of the form::
  98. {
  99. 'type': 'file',
  100. 'content': <str>,
  101. 'format': {'text','base64'},
  102. }
  103. """
  104. raise NotImplementedError
  105. def get_notebook_checkpoint(self, checkpoint_id, path):
  106. """Get the content of a checkpoint for a notebook.
  107. Returns a dict of the form::
  108. {
  109. 'type': 'notebook',
  110. 'content': <output of nbformat.read>,
  111. }
  112. """
  113. raise NotImplementedError
  114. class AsyncCheckpoints(Checkpoints):
  115. """
  116. Base class for managing checkpoints for a ContentsManager asynchronously.
  117. """
  118. async def create_checkpoint(self, contents_mgr, path):
  119. """Create a checkpoint."""
  120. raise NotImplementedError
  121. async def restore_checkpoint(self, contents_mgr, checkpoint_id, path):
  122. """Restore a checkpoint"""
  123. raise NotImplementedError
  124. async def rename_checkpoint(self, checkpoint_id, old_path, new_path):
  125. """Rename a single checkpoint from old_path to new_path."""
  126. raise NotImplementedError
  127. async def delete_checkpoint(self, checkpoint_id, path):
  128. """delete a checkpoint for a file"""
  129. raise NotImplementedError
  130. async def list_checkpoints(self, path):
  131. """Return a list of checkpoints for a given file"""
  132. raise NotImplementedError
  133. async def rename_all_checkpoints(self, old_path, new_path):
  134. """Rename all checkpoints for old_path to new_path."""
  135. for cp in await self.list_checkpoints(old_path):
  136. await self.rename_checkpoint(cp["id"], old_path, new_path)
  137. async def delete_all_checkpoints(self, path):
  138. """Delete all checkpoints for the given path."""
  139. for checkpoint in await self.list_checkpoints(path):
  140. await self.delete_checkpoint(checkpoint["id"], path)
  141. class AsyncGenericCheckpointsMixin(GenericCheckpointsMixin):
  142. """
  143. Helper for creating Asynchronous Checkpoints subclasses that can be used with any
  144. ContentsManager.
  145. """
  146. async def create_checkpoint(self, contents_mgr, path):
  147. model = await contents_mgr.get(path, content=True)
  148. type_ = model["type"]
  149. if type_ == "notebook":
  150. return await self.create_notebook_checkpoint(
  151. model["content"],
  152. path,
  153. )
  154. elif type_ == "file":
  155. return await self.create_file_checkpoint(
  156. model["content"],
  157. model["format"],
  158. path,
  159. )
  160. else:
  161. raise HTTPError(500, "Unexpected type %s" % type_)
  162. async def restore_checkpoint(self, contents_mgr, checkpoint_id, path):
  163. """Restore a checkpoint."""
  164. content_model = await contents_mgr.get(path, content=False)
  165. type_ = content_model["type"]
  166. if type_ == "notebook":
  167. model = await self.get_notebook_checkpoint(checkpoint_id, path)
  168. elif type_ == "file":
  169. model = await self.get_file_checkpoint(checkpoint_id, path)
  170. else:
  171. raise HTTPError(500, "Unexpected type %s" % type_)
  172. await contents_mgr.save(model, path)
  173. # Required Methods
  174. async def create_file_checkpoint(self, content, format, path):
  175. """Create a checkpoint of the current state of a file
  176. Returns a checkpoint model for the new checkpoint.
  177. """
  178. raise NotImplementedError
  179. async def create_notebook_checkpoint(self, nb, path):
  180. """Create a checkpoint of the current state of a file
  181. Returns a checkpoint model for the new checkpoint.
  182. """
  183. raise NotImplementedError
  184. async def get_file_checkpoint(self, checkpoint_id, path):
  185. """Get the content of a checkpoint for a non-notebook file.
  186. Returns a dict of the form::
  187. {
  188. 'type': 'file',
  189. 'content': <str>,
  190. 'format': {'text','base64'},
  191. }
  192. """
  193. raise NotImplementedError
  194. async def get_notebook_checkpoint(self, checkpoint_id, path):
  195. """Get the content of a checkpoint for a notebook.
  196. Returns a dict of the form::
  197. {
  198. 'type': 'notebook',
  199. 'content': <output of nbformat.read>,
  200. }
  201. """
  202. raise NotImplementedError