Show More
@@ -1,115 +1,119 b'' | |||
|
1 |
"""A |
|
|
1 | """A MultiKernelManager for use in the notebook webserver | |
|
2 | ||
|
3 | - raises HTTPErrors | |
|
4 | - creates REST API models | |
|
5 | """ | |
|
2 | 6 | |
|
3 | 7 | # Copyright (c) IPython Development Team. |
|
4 | 8 | # Distributed under the terms of the Modified BSD License. |
|
5 | 9 | |
|
6 | 10 | import os |
|
7 | 11 | |
|
8 | 12 | from tornado import web |
|
9 | 13 | |
|
10 | 14 | from IPython.kernel.multikernelmanager import MultiKernelManager |
|
11 | 15 | from IPython.utils.traitlets import Unicode, TraitError |
|
12 | 16 | |
|
13 | 17 | from IPython.html.utils import to_os_path |
|
14 | 18 | from IPython.utils.py3compat import getcwd |
|
15 | 19 | |
|
16 | 20 | |
|
17 | 21 | class MappingKernelManager(MultiKernelManager): |
|
18 | 22 | """A KernelManager that handles notebook mapping and HTTP error handling""" |
|
19 | 23 | |
|
20 | 24 | def _kernel_manager_class_default(self): |
|
21 | 25 | return "IPython.kernel.ioloop.IOLoopKernelManager" |
|
22 | 26 | |
|
23 | 27 | root_dir = Unicode(getcwd(), config=True) |
|
24 | 28 | |
|
25 | 29 | def _root_dir_changed(self, name, old, new): |
|
26 | 30 | """Do a bit of validation of the root dir.""" |
|
27 | 31 | if not os.path.isabs(new): |
|
28 | 32 | # If we receive a non-absolute path, make it absolute. |
|
29 | 33 | self.root_dir = os.path.abspath(new) |
|
30 | 34 | return |
|
31 | 35 | if not os.path.exists(new) or not os.path.isdir(new): |
|
32 | 36 | raise TraitError("kernel root dir %r is not a directory" % new) |
|
33 | 37 | |
|
34 | 38 | #------------------------------------------------------------------------- |
|
35 | 39 | # Methods for managing kernels and sessions |
|
36 | 40 | #------------------------------------------------------------------------- |
|
37 | 41 | |
|
38 | 42 | def _handle_kernel_died(self, kernel_id): |
|
39 | 43 | """notice that a kernel died""" |
|
40 | 44 | self.log.warn("Kernel %s died, removing from map.", kernel_id) |
|
41 | 45 | self.remove_kernel(kernel_id) |
|
42 | 46 | |
|
43 | 47 | def cwd_for_path(self, path): |
|
44 | 48 | """Turn API path into absolute OS path.""" |
|
45 | 49 | # short circuit for NotebookManagers that pass in absolute paths |
|
46 | 50 | if os.path.exists(path): |
|
47 | 51 | return path |
|
48 | 52 | |
|
49 | 53 | os_path = to_os_path(path, self.root_dir) |
|
50 | 54 | # in the case of notebooks and kernels not being on the same filesystem, |
|
51 | 55 | # walk up to root_dir if the paths don't exist |
|
52 | 56 | while not os.path.exists(os_path) and os_path != self.root_dir: |
|
53 | 57 | os_path = os.path.dirname(os_path) |
|
54 | 58 | return os_path |
|
55 | 59 | |
|
56 | 60 | def start_kernel(self, kernel_id=None, path=None, kernel_name='python', **kwargs): |
|
57 | 61 | """Start a kernel for a session and return its kernel_id. |
|
58 | 62 | |
|
59 | 63 | Parameters |
|
60 | 64 | ---------- |
|
61 | 65 | kernel_id : uuid |
|
62 | 66 | The uuid to associate the new kernel with. If this |
|
63 | 67 | is not None, this kernel will be persistent whenever it is |
|
64 | 68 | requested. |
|
65 | 69 | path : API path |
|
66 | 70 | The API path (unicode, '/' delimited) for the cwd. |
|
67 | 71 | Will be transformed to an OS path relative to root_dir. |
|
68 | 72 | kernel_name : str |
|
69 | 73 | The name identifying which kernel spec to launch. This is ignored if |
|
70 | 74 | an existing kernel is returned, but it may be checked in the future. |
|
71 | 75 | """ |
|
72 | 76 | if kernel_id is None: |
|
73 | 77 | if path is not None: |
|
74 | 78 | kwargs['cwd'] = self.cwd_for_path(path) |
|
75 | 79 | kernel_id = super(MappingKernelManager, self).start_kernel( |
|
76 | 80 | kernel_name=kernel_name, **kwargs) |
|
77 | 81 | self.log.info("Kernel started: %s" % kernel_id) |
|
78 | 82 | self.log.debug("Kernel args: %r" % kwargs) |
|
79 | 83 | # register callback for failed auto-restart |
|
80 | 84 | self.add_restart_callback(kernel_id, |
|
81 | 85 | lambda : self._handle_kernel_died(kernel_id), |
|
82 | 86 | 'dead', |
|
83 | 87 | ) |
|
84 | 88 | else: |
|
85 | 89 | self._check_kernel_id(kernel_id) |
|
86 | 90 | self.log.info("Using existing kernel: %s" % kernel_id) |
|
87 | 91 | return kernel_id |
|
88 | 92 | |
|
89 | 93 | def shutdown_kernel(self, kernel_id, now=False): |
|
90 | 94 | """Shutdown a kernel by kernel_id""" |
|
91 | 95 | self._check_kernel_id(kernel_id) |
|
92 | 96 | super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now) |
|
93 | 97 | |
|
94 | 98 | def kernel_model(self, kernel_id): |
|
95 | 99 | """Return a dictionary of kernel information described in the |
|
96 | 100 | JSON standard model.""" |
|
97 | 101 | self._check_kernel_id(kernel_id) |
|
98 | 102 | model = {"id":kernel_id, |
|
99 | 103 | "name": self._kernels[kernel_id].kernel_name} |
|
100 | 104 | return model |
|
101 | 105 | |
|
102 | 106 | def list_kernels(self): |
|
103 | 107 | """Returns a list of kernel_id's of kernels running.""" |
|
104 | 108 | kernels = [] |
|
105 | 109 | kernel_ids = super(MappingKernelManager, self).list_kernel_ids() |
|
106 | 110 | for kernel_id in kernel_ids: |
|
107 | 111 | model = self.kernel_model(kernel_id) |
|
108 | 112 | kernels.append(model) |
|
109 | 113 | return kernels |
|
110 | 114 | |
|
111 | 115 | # override _check_kernel_id to raise 404 instead of KeyError |
|
112 | 116 | def _check_kernel_id(self, kernel_id): |
|
113 | 117 | """Check a that a kernel_id exists and raise 404 if not.""" |
|
114 | 118 | if kernel_id not in self: |
|
115 | 119 | raise web.HTTPError(404, u'Kernel does not exist: %s' % kernel_id) |
General Comments 0
You need to be logged in to leave comments.
Login now