##// END OF EJS Templates
reorganize who knows what about paths...
MinRK -
Show More
@@ -88,7 +88,7 b' from IPython.utils.localinterfaces import localhost'
88 88 from IPython.utils import submodule
89 89 from IPython.utils.traitlets import (
90 90 Dict, Unicode, Integer, List, Bool, Bytes,
91 DottedObjectName
91 DottedObjectName, TraitError,
92 92 )
93 93 from IPython.utils import py3compat
94 94 from IPython.utils.path import filefind, get_ipython_dir
@@ -201,8 +201,11 b' class NotebookWebApplication(web.Application):'
201 201 handlers.extend(load_handlers('services.clusters.handlers'))
202 202 handlers.extend(load_handlers('services.sessions.handlers'))
203 203 handlers.extend(load_handlers('services.nbconvert.handlers'))
204 handlers.extend([
205 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : settings['notebook_manager'].notebook_dir}),
204 # FIXME: /files/ should be handled by the Contents service when it exists
205 nbm = settings['notebook_manager']
206 if hasattr(nbm, 'notebook_dir'):
207 handlers.extend([
208 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : nbm.notebook_dir}),
206 209 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
207 210 ])
208 211 # prepend base_url onto the patterns that we match
@@ -278,7 +281,7 b' aliases.update({'
278 281 'transport': 'KernelManager.transport',
279 282 'keyfile': 'NotebookApp.keyfile',
280 283 'certfile': 'NotebookApp.certfile',
281 'notebook-dir': 'NotebookManager.notebook_dir',
284 'notebook-dir': 'NotebookApp.notebook_dir',
282 285 'browser': 'NotebookApp.browser',
283 286 })
284 287
@@ -507,6 +510,26 b' class NotebookApp(BaseIPythonApplication):'
507 510 def _info_file_default(self):
508 511 info_file = "nbserver-%s.json"%os.getpid()
509 512 return os.path.join(self.profile_dir.security_dir, info_file)
513
514 notebook_dir = Unicode(py3compat.getcwd(), config=True,
515 help="The directory to use for notebooks and kernels."
516 )
517
518 def _notebook_dir_changed(self, name, old, new):
519 """Do a bit of validation of the notebook dir."""
520 if not os.path.isabs(new):
521 # If we receive a non-absolute path, make it absolute.
522 self.notebook_dir = os.path.abspath(new)
523 return
524 if os.path.exists(new) and not os.path.isdir(new):
525 raise TraitError("notebook dir %r is not a directory" % new)
526 if not os.path.exists(new):
527 self.log.info("Creating notebook dir %s", new)
528 try:
529 os.mkdir(new)
530 except:
531 raise TraitError("Couldn't create notebook dir %r" % new)
532
510 533
511 534 def parse_command_line(self, argv=None):
512 535 super(NotebookApp, self).parse_command_line(argv)
@@ -519,7 +542,7 b' class NotebookApp(BaseIPythonApplication):'
519 542 self.log.critical("No such file or directory: %s", f)
520 543 self.exit(1)
521 544 if os.path.isdir(f):
522 self.config.FileNotebookManager.notebook_dir = f
545 self.notebook_dir = f
523 546 elif os.path.isfile(f):
524 547 self.file_to_run = f
525 548
@@ -730,7 +753,7 b' class NotebookApp(BaseIPythonApplication):'
730 753 'port': self.port,
731 754 'secure': bool(self.certfile),
732 755 'base_url': self.base_url,
733 'notebook_dir': os.path.abspath(self.notebook_manager.notebook_dir),
756 'notebook_dir': os.path.abspath(self.notebook_dir),
734 757 }
735 758
736 759 def write_server_info_file(self):
@@ -16,6 +16,8 b' Authors:'
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 import os
20
19 21 from tornado import web
20 22
21 23 from IPython.kernel.multikernelmanager import MultiKernelManager
@@ -23,6 +25,9 b' from IPython.utils.traitlets import ('
23 25 Dict, List, Unicode,
24 26 )
25 27
28 from IPython.html.utils import to_os_path
29 from IPython.utils.py3compat import getcwd
30
26 31 #-----------------------------------------------------------------------------
27 32 # Classes
28 33 #-----------------------------------------------------------------------------
@@ -35,6 +40,29 b' class MappingKernelManager(MultiKernelManager):'
35 40 return "IPython.kernel.ioloop.IOLoopKernelManager"
36 41
37 42 kernel_argv = List(Unicode)
43
44 root_dir = Unicode(getcwd(), config=True)
45 def _root_dir_default(self):
46 from IPython.html.notebookapp import NotebookApp
47 if NotebookApp.initialized():
48 try:
49 app = NotebookApp.instance()
50 except Exception:
51 # can raise MultipleInstanceError, ignore
52 pass
53 else:
54 return app.notebook_dir
55 return app.notebook_dir
56 return getcwd()
57
58 def _root_dir_changed(self, name, old, new):
59 """Do a bit of validation of the root dir."""
60 if not os.path.isabs(new):
61 # If we receive a non-absolute path, make it absolute.
62 self.root_dir = os.path.abspath(new)
63 return
64 if not os.path.exists(new) or not os.path.isdir(new):
65 raise TraitError("kernel root dir %r is not a directory" % new)
38 66
39 67 #-------------------------------------------------------------------------
40 68 # Methods for managing kernels and sessions
@@ -44,8 +72,17 b' class MappingKernelManager(MultiKernelManager):'
44 72 """notice that a kernel died"""
45 73 self.log.warn("Kernel %s died, removing from map.", kernel_id)
46 74 self.remove_kernel(kernel_id)
47
48 def start_kernel(self, kernel_id=None, **kwargs):
75
76 def cwd_for_path(self, path):
77 """Turn API path into absolute OS path."""
78 os_path = to_os_path(path, self.root_dir)
79 # in the case of notebooks and kernels not being on the same filesystem,
80 # walk up to root_dir if the paths don't exist
81 while not os.path.exists(os_path) and os_path != self.root_dir:
82 os_path = os.path.dirname(os_path)
83 return os_path
84
85 def start_kernel(self, kernel_id=None, path=None, **kwargs):
49 86 """Start a kernel for a session an return its kernel_id.
50 87
51 88 Parameters
@@ -54,9 +91,14 b' class MappingKernelManager(MultiKernelManager):'
54 91 The uuid to associate the new kernel with. If this
55 92 is not None, this kernel will be persistent whenever it is
56 93 requested.
94 path : API path
95 The API path (unicode, '/' delimited) for the cwd.
96 Will be transformed to an OS path relative to root_dir.
57 97 """
58 98 if kernel_id is None:
59 99 kwargs['extra_arguments'] = self.kernel_argv
100 if path is not None:
101 kwargs['cwd'] = self.cwd_for_path(path)
60 102 kernel_id = super(MappingKernelManager, self).start_kernel(**kwargs)
61 103 self.log.info("Kernel started: %s" % kernel_id)
62 104 self.log.debug("Kernel args: %r" % kwargs)
@@ -18,7 +18,6 b' Authors:'
18 18 #-----------------------------------------------------------------------------
19 19
20 20 import io
21 import itertools
22 21 import os
23 22 import glob
24 23 import shutil
@@ -28,8 +27,9 b' from tornado import web'
28 27 from .nbmanager import NotebookManager
29 28 from IPython.nbformat import current
30 29 from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError
30 from IPython.utils.py3compat import getcwd
31 31 from IPython.utils import tz
32 from IPython.html.utils import is_hidden
32 from IPython.html.utils import is_hidden, to_os_path
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Classes
@@ -46,7 +46,28 b' class FileNotebookManager(NotebookManager):'
46 46 short `--script` flag.
47 47 """
48 48 )
49 notebook_dir = Unicode(getcwd(), config=True)
50 def _notebook_dir_default(self):
51 from IPython.html.notebookapp import NotebookApp
52 if NotebookApp.initialized():
53 try:
54 app = NotebookApp.instance()
55 except Exception:
56 # can raise MultipleInstanceError, ignore
57 pass
58 else:
59 return app.notebook_dir
60 return getcwd()
49 61
62 def _notebook_dir_changed(self, name, old, new):
63 """Do a bit of validation of the notebook dir."""
64 if not os.path.isabs(new):
65 # If we receive a non-absolute path, make it absolute.
66 self.notebook_dir = os.path.abspath(new)
67 return
68 if not os.path.exists(new) or not os.path.isdir(new):
69 raise TraitError("notebook dir %r is not a directory" % new)
70
50 71 checkpoint_dir = Unicode(config=True,
51 72 help="""The location in which to keep notebook checkpoints
52 73
@@ -75,9 +96,9 b' class FileNotebookManager(NotebookManager):'
75 96 def get_notebook_names(self, path=''):
76 97 """List all notebook names in the notebook dir and path."""
77 98 path = path.strip('/')
78 if not os.path.isdir(self.get_os_path(path=path)):
99 if not os.path.isdir(self._get_os_path(path=path)):
79 100 raise web.HTTPError(404, 'Directory not found: ' + path)
80 names = glob.glob(self.get_os_path('*'+self.filename_ext, path))
101 names = glob.glob(self._get_os_path('*'+self.filename_ext, path))
81 102 names = [os.path.basename(name)
82 103 for name in names]
83 104 return names
@@ -97,7 +118,7 b' class FileNotebookManager(NotebookManager):'
97 118 Whether the path is indeed a directory.
98 119 """
99 120 path = path.strip('/')
100 os_path = self.get_os_path(path=path)
121 os_path = self._get_os_path(path=path)
101 122 return os.path.isdir(os_path)
102 123
103 124 def is_hidden(self, path):
@@ -116,10 +137,10 b' class FileNotebookManager(NotebookManager):'
116 137
117 138 """
118 139 path = path.strip('/')
119 os_path = self.get_os_path(path=path)
140 os_path = self._get_os_path(path=path)
120 141 return is_hidden(os_path, self.notebook_dir)
121 142
122 def get_os_path(self, name=None, path=''):
143 def _get_os_path(self, name=None, path=''):
123 144 """Given a notebook name and a URL path, return its file system
124 145 path.
125 146
@@ -138,12 +159,9 b' class FileNotebookManager(NotebookManager):'
138 159 server started), the relative path, and the filename with the
139 160 current operating system's url.
140 161 """
141 parts = path.strip('/').split('/')
142 parts = [p for p in parts if p != ''] # remove duplicate splits
143 162 if name is not None:
144 parts.append(name)
145 path = os.path.join(self.notebook_dir, *parts)
146 return path
163 path = path + '/' + name
164 return to_os_path(path, self.notebook_dir)
147 165
148 166 def notebook_exists(self, name, path=''):
149 167 """Returns a True if the notebook exists. Else, returns False.
@@ -160,7 +178,7 b' class FileNotebookManager(NotebookManager):'
160 178 bool
161 179 """
162 180 path = path.strip('/')
163 nbpath = self.get_os_path(name, path=path)
181 nbpath = self._get_os_path(name, path=path)
164 182 return os.path.isfile(nbpath)
165 183
166 184 # TODO: Remove this after we create the contents web service and directories are
@@ -168,13 +186,13 b' class FileNotebookManager(NotebookManager):'
168 186 def list_dirs(self, path):
169 187 """List the directories for a given API style path."""
170 188 path = path.strip('/')
171 os_path = self.get_os_path('', path)
189 os_path = self._get_os_path('', path)
172 190 if not os.path.isdir(os_path) or is_hidden(os_path, self.notebook_dir):
173 191 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
174 192 dir_names = os.listdir(os_path)
175 193 dirs = []
176 194 for name in dir_names:
177 os_path = self.get_os_path(name, path)
195 os_path = self._get_os_path(name, path)
178 196 if os.path.isdir(os_path) and not is_hidden(os_path, self.notebook_dir):
179 197 try:
180 198 model = self.get_dir_model(name, path)
@@ -189,7 +207,7 b' class FileNotebookManager(NotebookManager):'
189 207 def get_dir_model(self, name, path=''):
190 208 """Get the directory model given a directory name and its API style path"""
191 209 path = path.strip('/')
192 os_path = self.get_os_path(name, path)
210 os_path = self._get_os_path(name, path)
193 211 if not os.path.isdir(os_path):
194 212 raise IOError('directory does not exist: %r' % os_path)
195 213 info = os.stat(os_path)
@@ -245,7 +263,7 b' class FileNotebookManager(NotebookManager):'
245 263 path = path.strip('/')
246 264 if not self.notebook_exists(name=name, path=path):
247 265 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
248 os_path = self.get_os_path(name, path)
266 os_path = self._get_os_path(name, path)
249 267 info = os.stat(os_path)
250 268 last_modified = tz.utcfromtimestamp(info.st_mtime)
251 269 created = tz.utcfromtimestamp(info.st_ctime)
@@ -284,7 +302,7 b' class FileNotebookManager(NotebookManager):'
284 302 self.rename_notebook(name, path, new_name, new_path)
285 303
286 304 # Save the notebook file
287 os_path = self.get_os_path(new_name, new_path)
305 os_path = self._get_os_path(new_name, new_path)
288 306 nb = current.to_notebook_json(model['content'])
289 307
290 308 self.check_and_sign(nb, new_path, new_name)
@@ -324,7 +342,7 b' class FileNotebookManager(NotebookManager):'
324 342 def delete_notebook(self, name, path=''):
325 343 """Delete notebook by name and path."""
326 344 path = path.strip('/')
327 os_path = self.get_os_path(name, path)
345 os_path = self._get_os_path(name, path)
328 346 if not os.path.isfile(os_path):
329 347 raise web.HTTPError(404, u'Notebook does not exist: %s' % os_path)
330 348
@@ -346,8 +364,8 b' class FileNotebookManager(NotebookManager):'
346 364 if new_name == old_name and new_path == old_path:
347 365 return
348 366
349 new_os_path = self.get_os_path(new_name, new_path)
350 old_os_path = self.get_os_path(old_name, old_path)
367 new_os_path = self._get_os_path(new_name, new_path)
368 old_os_path = self._get_os_path(old_name, old_path)
351 369
352 370 # Should we proceed with the move?
353 371 if os.path.isfile(new_os_path):
@@ -409,7 +427,7 b' class FileNotebookManager(NotebookManager):'
409 427 def create_checkpoint(self, name, path=''):
410 428 """Create a checkpoint from the current state of a notebook"""
411 429 path = path.strip('/')
412 nb_path = self.get_os_path(name, path)
430 nb_path = self._get_os_path(name, path)
413 431 # only the one checkpoint ID:
414 432 checkpoint_id = u"checkpoint"
415 433 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
@@ -439,7 +457,7 b' class FileNotebookManager(NotebookManager):'
439 457 """restore a notebook to a checkpointed state"""
440 458 path = path.strip('/')
441 459 self.log.info("restoring Notebook %s from checkpoint %s", name, checkpoint_id)
442 nb_path = self.get_os_path(name, path)
460 nb_path = self._get_os_path(name, path)
443 461 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
444 462 if not os.path.isfile(cp_path):
445 463 self.log.debug("checkpoint file does not exist: %s", cp_path)
@@ -22,8 +22,7 b' import os'
22 22
23 23 from IPython.config.configurable import LoggingConfigurable
24 24 from IPython.nbformat import current, sign
25 from IPython.utils import py3compat
26 from IPython.utils.traitlets import Instance, Unicode, TraitError
25 from IPython.utils.traitlets import Instance, Unicode
27 26
28 27 #-----------------------------------------------------------------------------
29 28 # Classes
@@ -31,16 +30,6 b' from IPython.utils.traitlets import Instance, Unicode, TraitError'
31 30
32 31 class NotebookManager(LoggingConfigurable):
33 32
34 # Todo:
35 # The notebook_dir attribute is used to mean a couple of different things:
36 # 1. Where the notebooks are stored if FileNotebookManager is used.
37 # 2. The cwd of the kernel for a project.
38 # Right now we use this attribute in a number of different places and
39 # we are going to have to disentangle all of this.
40 notebook_dir = Unicode(py3compat.getcwd(), config=True, help="""
41 The directory to use for notebooks.
42 """)
43
44 33 filename_ext = Unicode(u'.ipynb')
45 34
46 35 notary = Instance(sign.NotebookNotary)
@@ -251,19 +240,4 b' class NotebookManager(LoggingConfigurable):'
251 240 if not trusted:
252 241 self.log.warn("Notebook %s/%s is not trusted", path, name)
253 242 self.notary.mark_cells(nb, trusted)
254
255 def _notebook_dir_changed(self, name, old, new):
256 """Do a bit of validation of the notebook dir."""
257 if not os.path.isabs(new):
258 # If we receive a non-absolute path, make it absolute.
259 self.notebook_dir = os.path.abspath(new)
260 return
261 if os.path.exists(new) and not os.path.isdir(new):
262 raise TraitError("notebook dir %r is not a directory" % new)
263 if not os.path.exists(new):
264 self.log.info("Creating notebook dir %s", new)
265 try:
266 os.mkdir(new)
267 except:
268 raise TraitError("Couldn't create notebook dir %r" % new)
269 243
@@ -23,12 +23,6 b' class TestFileNotebookManager(TestCase):'
23 23 fm = FileNotebookManager(notebook_dir=td)
24 24 self.assertEqual(fm.notebook_dir, td)
25 25
26 def test_create_nb_dir(self):
27 with TemporaryDirectory() as td:
28 nbdir = os.path.join(td, 'notebooks')
29 fm = FileNotebookManager(notebook_dir=nbdir)
30 self.assertEqual(fm.notebook_dir, nbdir)
31
32 26 def test_missing_nb_dir(self):
33 27 with TemporaryDirectory() as td:
34 28 nbdir = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
@@ -42,20 +36,20 b' class TestFileNotebookManager(TestCase):'
42 36 # full filesystem path should be returned with correct operating system
43 37 # separators.
44 38 with TemporaryDirectory() as td:
45 nbdir = os.path.join(td, 'notebooks')
39 nbdir = td
46 40 fm = FileNotebookManager(notebook_dir=nbdir)
47 path = fm.get_os_path('test.ipynb', '/path/to/notebook/')
41 path = fm._get_os_path('test.ipynb', '/path/to/notebook/')
48 42 rel_path_list = '/path/to/notebook/test.ipynb'.split('/')
49 43 fs_path = os.path.join(fm.notebook_dir, *rel_path_list)
50 44 self.assertEqual(path, fs_path)
51 45
52 46 fm = FileNotebookManager(notebook_dir=nbdir)
53 path = fm.get_os_path('test.ipynb')
47 path = fm._get_os_path('test.ipynb')
54 48 fs_path = os.path.join(fm.notebook_dir, 'test.ipynb')
55 49 self.assertEqual(path, fs_path)
56 50
57 51 fm = FileNotebookManager(notebook_dir=nbdir)
58 path = fm.get_os_path('test.ipynb', '////')
52 path = fm._get_os_path('test.ipynb', '////')
59 53 fs_path = os.path.join(fm.notebook_dir, 'test.ipynb')
60 54 self.assertEqual(path, fs_path)
61 55
@@ -62,7 +62,7 b' class SessionRootHandler(IPythonHandler):'
62 62 if sm.session_exists(name=name, path=path):
63 63 model = sm.get_session(name=name, path=path)
64 64 else:
65 kernel_id = km.start_kernel(cwd=nbm.get_os_path(path))
65 kernel_id = km.start_kernel(path=path)
66 66 model = sm.create_session(name=name, path=path, kernel_id=kernel_id)
67 67 location = url_path_join(self.base_url, 'api', 'sessions', model['id'])
68 68 self.set_header('Location', url_escape(location))
@@ -11,10 +11,16 b''
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13
14 import os
15 from tempfile import NamedTemporaryFile
16
14 17 import nose.tools as nt
15 18
19 from IPython.utils.tempdir import TemporaryDirectory
20 from IPython.utils.traitlets import TraitError
16 21 import IPython.testing.tools as tt
17 22 from IPython.html import notebookapp
23 NotebookApp = notebookapp.NotebookApp
18 24
19 25 #-----------------------------------------------------------------------------
20 26 # Test functions
@@ -25,7 +31,7 b' def test_help_output():'
25 31 tt.help_all_output_test('notebook')
26 32
27 33 def test_server_info_file():
28 nbapp = notebookapp.NotebookApp(profile='nbserver_file_test')
34 nbapp = NotebookApp(profile='nbserver_file_test')
29 35 def get_servers():
30 36 return list(notebookapp.list_running_servers(profile='nbserver_file_test'))
31 37 nbapp.initialize(argv=[])
@@ -38,4 +44,29 b' def test_server_info_file():'
38 44 nt.assert_equal(get_servers(), [])
39 45
40 46 # The ENOENT error should be silenced.
41 nbapp.remove_server_info_file() No newline at end of file
47 nbapp.remove_server_info_file()
48
49 def test_nb_dir():
50 with TemporaryDirectory() as td:
51 app = NotebookApp(notebook_dir=td)
52 nt.assert_equal(app.notebook_dir, td)
53
54 def test_create_nb_dir():
55 with TemporaryDirectory() as td:
56 nbdir = os.path.join(td, 'notebooks')
57 app = NotebookApp(notebook_dir=nbdir)
58 nt.assert_equal(app.notebook_dir, nbdir)
59
60 def test_missing_nb_dir():
61 with TemporaryDirectory() as td:
62 nbdir = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
63 app = NotebookApp()
64 with nt.assert_raises(TraitError):
65 app.notebook_dir = nbdir
66
67 def test_invalid_nb_dir():
68 with NamedTemporaryFile() as tf:
69 app = NotebookApp()
70 with nt.assert_raises(TraitError):
71 app.notebook_dir = tf
72
@@ -81,7 +81,7 b' def url_unescape(path):'
81 81 ])
82 82
83 83 def is_hidden(abs_path, abs_root=''):
84 """Is a file is hidden or contained in a hidden directory.
84 """Is a file hidden or contained in a hidden directory?
85 85
86 86 This will start with the rightmost path element and work backwards to the
87 87 given root to see if a path is hidden or in a hidden directory. Hidden is
@@ -112,3 +112,14 b" def is_hidden(abs_path, abs_root=''):"
112 112
113 113 return False
114 114
115 def to_os_path(path, root=''):
116 """Convert an API path to a filesystem path
117
118 If given, root will be prepended to the path.
119 root must be a filesystem path already.
120 """
121 parts = path.strip('/').split('/')
122 parts = [p for p in parts if p != ''] # remove duplicate splits
123 path = os.path.join(root, *parts)
124 return path
125
General Comments 0
You need to be logged in to leave comments. Login now