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