##// END OF EJS Templates
allow specifying destination in copy_notebook
MinRK -
Show More
@@ -1,169 +1,173
1 1 """A base class notebook manager.
2 2
3 3 Authors:
4 4
5 5 * Brian Granger
6 6 * Zach Sailer
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 import os
21 21
22 22 from IPython.config.configurable import LoggingConfigurable
23 23 from IPython.nbformat import current
24 24 from IPython.utils.traitlets import List, Dict, Unicode, TraitError
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Classes
28 28 #-----------------------------------------------------------------------------
29 29
30 30 class NotebookManager(LoggingConfigurable):
31 31
32 32 # Todo:
33 33 # The notebook_dir attribute is used to mean a couple of different things:
34 34 # 1. Where the notebooks are stored if FileNotebookManager is used.
35 35 # 2. The cwd of the kernel for a project.
36 36 # Right now we use this attribute in a number of different places and
37 37 # we are going to have to disentangle all of this.
38 38 notebook_dir = Unicode(os.getcwdu(), config=True, help="""
39 39 The directory to use for notebooks.
40 40 """)
41 41
42 42 filename_ext = Unicode(u'.ipynb')
43 43
44 44 def path_exists(self, path):
45 45 """Does the API-style path (directory) actually exist?
46 46
47 47 Override this method in subclasses.
48 48
49 49 Parameters
50 50 ----------
51 51 path : string
52 52 The
53 53
54 54 Returns
55 55 -------
56 56 exists : bool
57 57 Whether the path does indeed exist.
58 58 """
59 59 raise NotImplementedError
60 60
61 61 def _notebook_dir_changed(self, name, old, new):
62 62 """Do a bit of validation of the notebook dir."""
63 63 if not os.path.isabs(new):
64 64 # If we receive a non-absolute path, make it absolute.
65 65 self.notebook_dir = os.path.abspath(new)
66 66 return
67 67 if os.path.exists(new) and not os.path.isdir(new):
68 68 raise TraitError("notebook dir %r is not a directory" % new)
69 69 if not os.path.exists(new):
70 70 self.log.info("Creating notebook dir %s", new)
71 71 try:
72 72 os.mkdir(new)
73 73 except:
74 74 raise TraitError("Couldn't create notebook dir %r" % new)
75 75
76 76 # Main notebook API
77 77
78 78 def increment_filename(self, basename, path=''):
79 79 """Increment a notebook filename without the .ipynb to make it unique.
80 80
81 81 Parameters
82 82 ----------
83 83 basename : unicode
84 84 The name of a notebook without the ``.ipynb`` file extension.
85 85 path : unicode
86 86 The URL path of the notebooks directory
87 87 """
88 88 return basename
89 89
90 90 def list_notebooks(self, path=''):
91 91 """Return a list of notebook dicts without content.
92 92
93 93 This returns a list of dicts, each of the form::
94 94
95 95 dict(notebook_id=notebook,name=name)
96 96
97 97 This list of dicts should be sorted by name::
98 98
99 99 data = sorted(data, key=lambda item: item['name'])
100 100 """
101 101 raise NotImplementedError('must be implemented in a subclass')
102 102
103 103 def get_notebook_model(self, name, path='', content=True):
104 104 """Get the notebook model with or without content."""
105 105 raise NotImplementedError('must be implemented in a subclass')
106 106
107 107 def save_notebook_model(self, model, name, path=''):
108 108 """Save the notebook model and return the model with no content."""
109 109 raise NotImplementedError('must be implemented in a subclass')
110 110
111 111 def update_notebook_model(self, model, name, path=''):
112 112 """Update the notebook model and return the model with no content."""
113 113 raise NotImplementedError('must be implemented in a subclass')
114 114
115 115 def delete_notebook_model(self, name, path=''):
116 116 """Delete notebook by name and path."""
117 117 raise NotImplementedError('must be implemented in a subclass')
118 118
119 119 def create_notebook_model(self, model=None, path=''):
120 120 """Create a new untitled notebook and return its model with no content."""
121 121 path = path.strip('/')
122 122 if model is None:
123 123 model = {}
124 124 if 'content' not in model:
125 125 metadata = current.new_metadata(name=u'')
126 126 model['content'] = current.new_notebook(metadata=metadata)
127 127 if 'name' not in model:
128 128 model['name'] = self.increment_filename('Untitled', path)
129 129
130 130 model['path'] = path
131 131 model = self.save_notebook_model(model, model['name'], model['path'])
132 132 return model
133 133
134 def copy_notebook(self, name, path=''):
135 """Copy an existing notebook and return its new model."""
134 def copy_notebook(self, from_name, to_name=None, path=''):
135 """Copy an existing notebook and return its new model.
136
137 If to_name not specified, increment `from_name-Copy#.ipynb`.
138 """
136 139 path = path.strip('/')
137 model = self.get_notebook_model(name, path)
138 name = os.path.splitext(name)[0] + '-Copy'
139 name = self.increment_filename(name, path)
140 model['name'] = name
141 model = self.save_notebook_model(model, name, path)
140 model = self.get_notebook_model(from_name, path)
141 if not to_name:
142 base = os.path.splitext(from_name)[0] + '-Copy'
143 to_name = self.increment_filename(base, path)
144 model['name'] = to_name
145 model = self.save_notebook_model(model, to_name, path)
142 146 return model
143 147
144 148 # Checkpoint-related
145 149
146 150 def create_checkpoint(self, name, path=''):
147 151 """Create a checkpoint of the current state of a notebook
148 152
149 153 Returns a checkpoint_id for the new checkpoint.
150 154 """
151 155 raise NotImplementedError("must be implemented in a subclass")
152 156
153 157 def list_checkpoints(self, name, path=''):
154 158 """Return a list of checkpoints for a given notebook"""
155 159 return []
156 160
157 161 def restore_checkpoint(self, checkpoint_id, name, path=''):
158 162 """Restore a notebook from one of its checkpoints"""
159 163 raise NotImplementedError("must be implemented in a subclass")
160 164
161 165 def delete_checkpoint(self, checkpoint_id, name, path=''):
162 166 """delete a checkpoint for a notebook"""
163 167 raise NotImplementedError("must be implemented in a subclass")
164 168
165 169 def log_info(self):
166 170 self.log.info(self.info_string())
167 171
168 172 def info_string(self):
169 173 return "Serving notebooks"
General Comments 0
You need to be logged in to leave comments. Login now