##// END OF EJS Templates
log kernel specs that fail to load
Min RK -
Show More
@@ -1,52 +1,56 b''
1 """Tornado handlers for kernel specifications."""
1 """Tornado handlers for kernel specifications."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 import json
5 import json
6 from tornado import web
6 from tornado import web
7
7
8 from ...base.handlers import IPythonHandler, json_errors
8 from ...base.handlers import IPythonHandler, json_errors
9
9
10 from IPython.kernel.kernelspec import _pythonfirst
10 from IPython.kernel.kernelspec import _pythonfirst
11
11
12
12
13 class MainKernelSpecHandler(IPythonHandler):
13 class MainKernelSpecHandler(IPythonHandler):
14 SUPPORTED_METHODS = ('GET',)
14 SUPPORTED_METHODS = ('GET',)
15
15
16 @web.authenticated
16 @web.authenticated
17 @json_errors
17 @json_errors
18 def get(self):
18 def get(self):
19 ksm = self.kernel_spec_manager
19 ksm = self.kernel_spec_manager
20 results = []
20 results = []
21 for kernel_name in sorted(ksm.find_kernel_specs(), key=_pythonfirst):
21 for kernel_name in sorted(ksm.find_kernel_specs(), key=_pythonfirst):
22 try:
22 d = ksm.get_kernel_spec(kernel_name).to_dict()
23 d = ksm.get_kernel_spec(kernel_name).to_dict()
24 except Exception:
25 self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True)
26 continue
23 d['name'] = kernel_name
27 d['name'] = kernel_name
24 results.append(d)
28 results.append(d)
25
29
26 self.set_header("Content-Type", 'application/json')
30 self.set_header("Content-Type", 'application/json')
27 self.finish(json.dumps(results))
31 self.finish(json.dumps(results))
28
32
29
33
30 class KernelSpecHandler(IPythonHandler):
34 class KernelSpecHandler(IPythonHandler):
31 SUPPORTED_METHODS = ('GET',)
35 SUPPORTED_METHODS = ('GET',)
32
36
33 @web.authenticated
37 @web.authenticated
34 @json_errors
38 @json_errors
35 def get(self, kernel_name):
39 def get(self, kernel_name):
36 ksm = self.kernel_spec_manager
40 ksm = self.kernel_spec_manager
37 try:
41 try:
38 kernelspec = ksm.get_kernel_spec(kernel_name)
42 kernelspec = ksm.get_kernel_spec(kernel_name)
39 except KeyError:
43 except KeyError:
40 raise web.HTTPError(404, u'Kernel spec %s not found' % kernel_name)
44 raise web.HTTPError(404, u'Kernel spec %s not found' % kernel_name)
41 self.set_header("Content-Type", 'application/json')
45 self.set_header("Content-Type", 'application/json')
42 self.finish(kernelspec.to_json())
46 self.finish(kernelspec.to_json())
43
47
44
48
45 # URL to handler mappings
49 # URL to handler mappings
46
50
47 kernel_name_regex = r"(?P<kernel_name>\w+)"
51 kernel_name_regex = r"(?P<kernel_name>\w+)"
48
52
49 default_handlers = [
53 default_handlers = [
50 (r"/api/kernelspecs", MainKernelSpecHandler),
54 (r"/api/kernelspecs", MainKernelSpecHandler),
51 (r"/api/kernelspecs/%s" % kernel_name_regex, KernelSpecHandler),
55 (r"/api/kernelspecs/%s" % kernel_name_regex, KernelSpecHandler),
52 ]
56 ]
@@ -1,102 +1,122 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Test the kernel specs webservice API."""
2 """Test the kernel specs webservice API."""
3
3
4 import errno
4 import errno
5 import io
5 import io
6 import json
6 import json
7 import os
7 import os
8 import shutil
8
9
9 pjoin = os.path.join
10 pjoin = os.path.join
10
11
11 import requests
12 import requests
12
13
13 from IPython.kernel.kernelspec import NATIVE_KERNEL_NAME
14 from IPython.kernel.kernelspec import NATIVE_KERNEL_NAME
14 from IPython.html.utils import url_path_join
15 from IPython.html.utils import url_path_join
15 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
16 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
16
17
17 # Copied from IPython.kernel.tests.test_kernelspec so updating that doesn't
18 # Copied from IPython.kernel.tests.test_kernelspec so updating that doesn't
18 # break these tests
19 # break these tests
19 sample_kernel_json = {'argv':['cat', '{connection_file}'],
20 sample_kernel_json = {'argv':['cat', '{connection_file}'],
20 'display_name':'Test kernel',
21 'display_name':'Test kernel',
21 'language':'bash',
22 'language':'bash',
22 }
23 }
23
24
24 some_resource = u"The very model of a modern major general"
25 some_resource = u"The very model of a modern major general"
25
26
26
27
27 class KernelSpecAPI(object):
28 class KernelSpecAPI(object):
28 """Wrapper for notebook API calls."""
29 """Wrapper for notebook API calls."""
29 def __init__(self, base_url):
30 def __init__(self, base_url):
30 self.base_url = base_url
31 self.base_url = base_url
31
32
32 def _req(self, verb, path, body=None):
33 def _req(self, verb, path, body=None):
33 response = requests.request(verb,
34 response = requests.request(verb,
34 url_path_join(self.base_url, path),
35 url_path_join(self.base_url, path),
35 data=body,
36 data=body,
36 )
37 )
37 response.raise_for_status()
38 response.raise_for_status()
38 return response
39 return response
39
40
40 def list(self):
41 def list(self):
41 return self._req('GET', 'api/kernelspecs')
42 return self._req('GET', 'api/kernelspecs')
42
43
43 def kernel_spec_info(self, name):
44 def kernel_spec_info(self, name):
44 return self._req('GET', url_path_join('api/kernelspecs', name))
45 return self._req('GET', url_path_join('api/kernelspecs', name))
45
46
46 def kernel_resource(self, name, path):
47 def kernel_resource(self, name, path):
47 return self._req('GET', url_path_join('kernelspecs', name, path))
48 return self._req('GET', url_path_join('kernelspecs', name, path))
48
49
49 class APITest(NotebookTestBase):
50 class APITest(NotebookTestBase):
50 """Test the kernelspec web service API"""
51 """Test the kernelspec web service API"""
51 def setUp(self):
52 def setUp(self):
52 ipydir = self.ipython_dir.name
53 ipydir = self.ipython_dir.name
53 sample_kernel_dir = pjoin(ipydir, 'kernels', 'sample')
54 sample_kernel_dir = pjoin(ipydir, 'kernels', 'sample')
54 try:
55 try:
55 os.makedirs(sample_kernel_dir)
56 os.makedirs(sample_kernel_dir)
56 except OSError as e:
57 except OSError as e:
57 if e.errno != errno.EEXIST:
58 if e.errno != errno.EEXIST:
58 raise
59 raise
59
60
60 with open(pjoin(sample_kernel_dir, 'kernel.json'), 'w') as f:
61 with open(pjoin(sample_kernel_dir, 'kernel.json'), 'w') as f:
61 json.dump(sample_kernel_json, f)
62 json.dump(sample_kernel_json, f)
62
63
63 with io.open(pjoin(sample_kernel_dir, 'resource.txt'), 'w',
64 with io.open(pjoin(sample_kernel_dir, 'resource.txt'), 'w',
64 encoding='utf-8') as f:
65 encoding='utf-8') as f:
65 f.write(some_resource)
66 f.write(some_resource)
66
67
67 self.ks_api = KernelSpecAPI(self.base_url())
68 self.ks_api = KernelSpecAPI(self.base_url())
68
69
70 def test_list_kernelspecs_bad(self):
71 """Can list kernelspecs when one is invalid"""
72 bad_kernel_dir = pjoin(self.ipython_dir.name, 'kernels', 'bad')
73 try:
74 os.makedirs(bad_kernel_dir)
75 except OSError as e:
76 if e.errno != errno.EEXIST:
77 raise
78
79 with open(pjoin(bad_kernel_dir, 'kernel.json'), 'w') as f:
80 f.write("garbage")
81
82 specs = self.ks_api.list().json()
83 assert isinstance(specs, list)
84 # 2: the sample kernelspec created in setUp, and the native Python kernel
85 self.assertGreaterEqual(len(specs), 2)
86
87 shutil.rmtree(bad_kernel_dir)
88
69 def test_list_kernelspecs(self):
89 def test_list_kernelspecs(self):
70 specs = self.ks_api.list().json()
90 specs = self.ks_api.list().json()
71 assert isinstance(specs, list)
91 assert isinstance(specs, list)
72
92
73 # 2: the sample kernelspec created in setUp, and the native Python kernel
93 # 2: the sample kernelspec created in setUp, and the native Python kernel
74 self.assertGreaterEqual(len(specs), 2)
94 self.assertGreaterEqual(len(specs), 2)
75
95
76 def is_sample_kernelspec(s):
96 def is_sample_kernelspec(s):
77 return s['name'] == 'sample' and s['display_name'] == 'Test kernel'
97 return s['name'] == 'sample' and s['display_name'] == 'Test kernel'
78
98
79 def is_default_kernelspec(s):
99 def is_default_kernelspec(s):
80 return s['name'] == NATIVE_KERNEL_NAME and s['display_name'].startswith("IPython")
100 return s['name'] == NATIVE_KERNEL_NAME and s['display_name'].startswith("IPython")
81
101
82 assert any(is_sample_kernelspec(s) for s in specs), specs
102 assert any(is_sample_kernelspec(s) for s in specs), specs
83 assert any(is_default_kernelspec(s) for s in specs), specs
103 assert any(is_default_kernelspec(s) for s in specs), specs
84
104
85 def test_get_kernelspec(self):
105 def test_get_kernelspec(self):
86 spec = self.ks_api.kernel_spec_info('Sample').json() # Case insensitive
106 spec = self.ks_api.kernel_spec_info('Sample').json() # Case insensitive
87 self.assertEqual(spec['language'], 'bash')
107 self.assertEqual(spec['language'], 'bash')
88
108
89 def test_get_nonexistant_kernelspec(self):
109 def test_get_nonexistant_kernelspec(self):
90 with assert_http_error(404):
110 with assert_http_error(404):
91 self.ks_api.kernel_spec_info('nonexistant')
111 self.ks_api.kernel_spec_info('nonexistant')
92
112
93 def test_get_kernel_resource_file(self):
113 def test_get_kernel_resource_file(self):
94 res = self.ks_api.kernel_resource('sAmple', 'resource.txt')
114 res = self.ks_api.kernel_resource('sAmple', 'resource.txt')
95 self.assertEqual(res.text, some_resource)
115 self.assertEqual(res.text, some_resource)
96
116
97 def test_get_nonexistant_resource(self):
117 def test_get_nonexistant_resource(self):
98 with assert_http_error(404):
118 with assert_http_error(404):
99 self.ks_api.kernel_resource('nonexistant', 'resource.txt')
119 self.ks_api.kernel_resource('nonexistant', 'resource.txt')
100
120
101 with assert_http_error(404):
121 with assert_http_error(404):
102 self.ks_api.kernel_resource('sample', 'nonexistant.txt')
122 self.ks_api.kernel_resource('sample', 'nonexistant.txt')
General Comments 0
You need to be logged in to leave comments. Login now