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