checkpoints.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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("must be implemented in a subclass")
  21. def restore_checkpoint(self, contents_mgr, checkpoint_id, path):
  22. """Restore a checkpoint"""
  23. raise NotImplementedError("must be implemented in a subclass")
  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("must be implemented in a subclass")
  27. def delete_checkpoint(self, checkpoint_id, path):
  28. """delete a checkpoint for a file"""
  29. raise NotImplementedError("must be implemented in a subclass")
  30. def list_checkpoints(self, path):
  31. """Return a list of checkpoints for a given file"""
  32. raise NotImplementedError("must be implemented in a subclass")
  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(object):
  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, u'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, u'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("must be implemented in a subclass")
  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("must be implemented in a subclass")
  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("must be implemented in a subclass")
  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("must be implemented in a subclass")