##// END OF EJS Templates
Fixing minor bug.
Brian Granger -
Show More
@@ -1,196 +1,196 b''
1 1 """A notebook manager that uses the local file system for storage.
2 2
3 3 Authors:
4 4
5 5 * Brian Granger
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import datetime
20 20 import io
21 21 import os
22 22 import glob
23 23
24 24 from tornado import web
25 25
26 26 from .basenbmanager import BaseNotebookManager
27 27 from IPython.nbformat import current
28 28 from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Classes
32 32 #-----------------------------------------------------------------------------
33 33
34 34 class FileNotebookManager(BaseNotebookManager):
35 35
36 36 save_script = Bool(False, config=True,
37 37 help="""Automatically create a Python script when saving the notebook.
38 38
39 39 For easier use of import, %run and %load across notebooks, a
40 40 <notebook-name>.py script will be created next to any
41 41 <notebook-name>.ipynb on each save. This can also be set with the
42 42 short `--script` flag.
43 43 """
44 44 )
45 45
46 46 filename_ext = Unicode(u'.ipynb')
47 47
48 48 # Map notebook names to notebook_ids
49 49 rev_mapping = Dict()
50 50
51 51 def get_notebook_names(self):
52 52 """List all notebook names in the notebook dir."""
53 53 names = glob.glob(os.path.join(self.notebook_dir,
54 54 '*' + self.filename_ext))
55 55 names = [os.path.splitext(os.path.basename(name))[0]
56 56 for name in names]
57 57 return names
58 58
59 59 def list_notebooks(self):
60 60 """List all notebooks in the notebook dir."""
61 61 names = self.get_notebook_names()
62 62
63 63 data = []
64 64 for name in names:
65 65 if name not in self.rev_mapping:
66 66 notebook_id = self.new_notebook_id(name)
67 67 else:
68 68 notebook_id = self.rev_mapping[name]
69 69 data.append(dict(notebook_id=notebook_id,name=name))
70 70 data = sorted(data, key=lambda item: item['name'])
71 71 return data
72 72
73 73 def new_notebook_id(self, name):
74 74 """Generate a new notebook_id for a name and store its mappings."""
75 75 notebook_id = super(FileNotebookManager, self).new_notebook_id(name)
76 76 self.rev_mapping[name] = notebook_id
77 77 return notebook_id
78 78
79 79 def delete_notebook_id(self, notebook_id):
80 80 """Delete a notebook's id in the mapping."""
81 81 name = self.mapping[notebook_id]
82 82 super(FileNotebookManager, self).delete_notebook_id(notebook_id)
83 83 del self.rev_mapping[name]
84 84
85 85 def notebook_exists(self, notebook_id):
86 86 """Does a notebook exist?"""
87 87 exists = super(FileNotebookManager, self).notebook_exists(notebook_id)
88 88 if not exists:
89 89 return False
90 90 path = self.get_path_by_name(self.mapping[notebook_id])
91 91 return os.path.isfile(path)
92 92
93 93 def find_path(self, notebook_id):
94 94 """Return a full path to a notebook given its notebook_id."""
95 95 try:
96 96 name = self.mapping[notebook_id]
97 97 except KeyError:
98 98 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
99 99 return self.get_path_by_name(name)
100 100
101 101 def get_path_by_name(self, name):
102 102 """Return a full path to a notebook given its name."""
103 103 filename = name + self.filename_ext
104 104 path = os.path.join(self.notebook_dir, filename)
105 105 return path
106 106
107 107 def read_notebook_object(self, notebook_id):
108 108 """Get the NotebookNode representation of a notebook by notebook_id."""
109 109 path = self.find_path(notebook_id)
110 110 if not os.path.isfile(path):
111 111 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
112 112 info = os.stat(path)
113 113 last_modified = datetime.datetime.utcfromtimestamp(info.st_mtime)
114 114 with open(path,'r') as f:
115 115 s = f.read()
116 116 try:
117 117 # v1 and v2 and json in the .ipynb files.
118 118 nb = current.reads(s, u'json')
119 119 except:
120 120 raise web.HTTPError(500, u'Unreadable JSON notebook.')
121 121 # Always use the filename as the notebook name.
122 122 nb.metadata.name = os.path.splitext(os.path.basename(path))[0]
123 123 return last_modified, nb
124 124
125 125 def write_notebook_object(self, nb, notebook_id=None):
126 126 """Save an existing notebook object by notebook_id."""
127 127 try:
128 128 new_name = nb.metadata.name
129 129 except AttributeError:
130 130 raise web.HTTPError(400, u'Missing notebook name')
131 131
132 132 if notebook_id is None:
133 133 notebook_id = self.new_notebook_id(new_name)
134 134
135 135 if notebook_id not in self.mapping:
136 136 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
137 137
138 138 old_name = self.mapping[notebook_id]
139 139 path = self.get_path_by_name(new_name)
140 140 try:
141 141 with open(path,'w') as f:
142 142 current.write(nb, f, u'json')
143 143 except Exception as e:
144 144 raise web.HTTPError(400, u'Unexpected error while saving notebook: %s' % e)
145 145
146 146 # save .py script as well
147 147 if self.save_script:
148 148 pypath = os.path.splitext(path)[0] + '.py'
149 149 try:
150 150 with io.open(pypath,'w', encoding='utf-8') as f:
151 151 current.write(nb, f, u'py')
152 152 except Exception as e:
153 153 raise web.HTTPError(400, u'Unexpected error while saving notebook as script: %s' % e)
154 154
155 155 # remove old files if the name changed
156 156 if old_name != new_name:
157 157 old_path = self.get_path_by_name(old_name)
158 158 if os.path.isfile(old_path):
159 159 os.unlink(old_path)
160 160 if self.save_script:
161 161 old_pypath = os.path.splitext(old_path)[0] + '.py'
162 162 if os.path.isfile(old_pypath):
163 163 os.unlink(old_pypath)
164 164 self.mapping[notebook_id] = new_name
165 165 self.rev_mapping[new_name] = notebook_id
166 166 del self.rev_mapping[old_name]
167 167
168 168 return notebook_id
169 169
170 170 def delete_notebook(self, notebook_id):
171 171 """Delete notebook by notebook_id."""
172 172 path = self.find_path(notebook_id)
173 173 if not os.path.isfile(path):
174 174 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
175 175 os.unlink(path)
176 176 self.delete_notebook_id(notebook_id)
177 177
178 178 def increment_filename(self, basename):
179 179 """Return a non-used filename of the form basename<int>.
180 180
181 181 This searches through the filenames (basename0, basename1, ...)
182 182 until is find one that is not already being used. It is used to
183 183 create Untitled and Copy names that are unique.
184 184 """
185 185 i = 0
186 186 while True:
187 187 name = u'%s%i' % (basename,i)
188 188 path = self.get_path_by_name(name)
189 189 if not os.path.isfile(path):
190 190 break
191 191 else:
192 192 i = i+1
193 193 return name
194 194
195 195 def log_info(self):
196 self.log.info("Serving notebooks from local directory: %s", self.notebook_manager.notebook_dir)
196 self.log.info("Serving notebooks from local directory: %s", self.notebook_dir)
General Comments 0
You need to be logged in to leave comments. Login now