diff --git a/IPython/html/services/kernelspecs/handlers.py b/IPython/html/services/kernelspecs/handlers.py
index 2d1a75fc2..72397788f 100644
--- a/IPython/html/services/kernelspecs/handlers.py
+++ b/IPython/html/services/kernelspecs/handlers.py
@@ -2,11 +2,43 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
+
+import glob
import json
+import os
+pjoin = os.path.join
+
from tornado import web
from ...base.handlers import IPythonHandler, json_errors
+from ...utils import url_path_join
+def kernelspec_model(handler, name):
+ """Load a KernelSpec by name and return the REST API model"""
+ ksm = handler.kernel_spec_manager
+ spec = ksm.get_kernel_spec(name)
+ d = {'name': name}
+ d['spec'] = spec.to_dict()
+ d['resources'] = resources = {}
+ resource_dir = spec.resource_dir
+ for resource in ['kernel.js', 'kernel.css']:
+ if os.path.exists(pjoin(resource_dir, resource)):
+ resources[resource] = url_path_join(
+ handler.base_url,
+ 'kernelspecs',
+ name,
+ resource
+ )
+ for logo_file in glob.glob(pjoin(resource_dir, 'logo-*')):
+ fname = os.path.basename(logo_file)
+ no_ext, _ = os.path.splitext(fname)
+ resources[no_ext] = url_path_join(
+ handler.base_url,
+ 'kernelspecs',
+ name,
+ fname
+ )
+ return d
class MainKernelSpecHandler(IPythonHandler):
SUPPORTED_METHODS = ('GET',)
@@ -21,13 +53,11 @@ class MainKernelSpecHandler(IPythonHandler):
model['kernelspecs'] = specs = {}
for kernel_name in ksm.find_kernel_specs():
try:
- d = ksm.get_kernel_spec(kernel_name).to_dict()
+ d = kernelspec_model(self, kernel_name)
except Exception:
self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True)
continue
- d['name'] = kernel_name
specs[kernel_name] = d
-
self.set_header("Content-Type", 'application/json')
self.finish(json.dumps(model))
@@ -38,13 +68,12 @@ class KernelSpecHandler(IPythonHandler):
@web.authenticated
@json_errors
def get(self, kernel_name):
- ksm = self.kernel_spec_manager
try:
- kernelspec = ksm.get_kernel_spec(kernel_name)
+ model = kernelspec_model(self, kernel_name)
except KeyError:
raise web.HTTPError(404, u'Kernel spec %s not found' % kernel_name)
self.set_header("Content-Type", 'application/json')
- self.finish(kernelspec.to_json())
+ self.finish(json.dumps(model))
# URL to handler mappings
diff --git a/IPython/html/static/notebook/js/kernelselector.js b/IPython/html/static/notebook/js/kernelselector.js
index a9165b8a7..3cd13d39e 100644
--- a/IPython/html/static/notebook/js/kernelselector.js
+++ b/IPython/html/static/notebook/js/kernelselector.js
@@ -35,8 +35,8 @@ define([
var change_kernel_submenu = $("#menu-change-kernel-submenu");
var keys = Object.keys(data.kernelspecs).sort(function (a, b) {
// sort by display_name
- var da = data.kernelspecs[a].display_name;
- var db = data.kernelspecs[b].display_name;
+ var da = data.kernelspecs[a].spec.display_name;
+ var db = data.kernelspecs[b].spec.display_name;
if (da === db) {
return 0;
} else if (da > db) {
@@ -50,7 +50,7 @@ define([
var ks_submenu_entry = $("
").attr("id", "kernel-submenu-"+ks.name).append($('')
.attr('href', '#')
.click($.proxy(this.change_kernel, this, ks.name))
- .text(ks.display_name));
+ .text(ks.spec.display_name));
change_kernel_submenu.append(ks_submenu_entry);
}
};
@@ -59,25 +59,17 @@ define([
/**
* TODO, have a methods to set kernel spec directly ?
**/
- var that = this;
if (kernel_name === this.current_selection) {
return;
}
var ks = this.kernelspecs[kernel_name];
- var new_mode_url = 'kernelspecs/'+ks.name+'/kernel';
-
- var css_url = this.notebook.base_url+new_mode_url+'.css';
- $.ajax({
- type: 'HEAD',
- url: css_url,
- success: function(){
- $('#kernel-css')
- .attr('href',css_url);
- },
- error:function(){
- console.info("No custom kernel.css at URL:", css_url)
- }
- });
+
+ var css_url = ks.resources['kernel.css'];
+ if (css_url) {
+ $('#kernel-css').attr('href', css_url);
+ } else {
+ $('#kernel-css').attr('href', '');
+ }
try {
this.notebook.start_session(kernel_name);
@@ -92,26 +84,23 @@ define([
return;
}
this.events.trigger('spec_changed.Kernel', ks);
-
-
- // load new mode kernel.js if exist
- require([new_mode_url],
- // if new mode has custom.js
- function(new_mode){
- that.lock_switch();
- if(new_mode && new_mode.onload){
- new_mode.onload();
- } else {
- console.warn("The current kernel defined a kernel.js file but does not contain "+
- "any asynchronous module definition. This is undefined behavior "+
- "which is not recommended");
+
+ if (ks.resources['kernel.js']) {
+ require([ks.resources['kernel.js']],
+ function (kernel_mod) {
+ if (kernel_mod && kernel_mod.onload) {
+ kernel_mod.onload();
+ } else {
+ console.warn("Kernel " + ks.name + " has a kernel.js file that does not contain "+
+ "any asynchronous module definition. This is undefined behavior "+
+ "and not recommended.");
+ }
+ }, function (err) {
+ console.warn("Failed to load kernel.js from ", ks.resources['kernel.js'], err);
}
- },
- function(err){
- // if new mode does not have custom.js
- console.info("No custom kernel.css at URL:", new_mode_url)
- }
- );
+ );
+ }
+
};
KernelSelector.prototype.lock_switch = function() {
@@ -123,10 +112,16 @@ define([
KernelSelector.prototype.bind_events = function() {
var that = this;
+ var logo_img = this.element.find("img.current_kernel_logo");
this.events.on('spec_changed.Kernel', function(event, data) {
that.current_selection = data.name;
- $("#kernel_indicator").find('.kernel_indicator_name').text(data.display_name);
- that.element.find("img.current_kernel_logo").attr("src", that.notebook.base_url + "kernelspecs/" + data.name + "/logo-64x64.png");
+ $("#kernel_indicator").find('.kernel_indicator_name').text(data.spec.display_name);
+ if (data.resources['logo-64x64']) {
+ logo_img.attr("src", data.resources['logo-64x64']);
+ logo_img.show();
+ } else {
+ logo_img.hide();
+ }
});
this.events.on('kernel_created.Session', function(event, data) {
@@ -139,7 +134,6 @@ define([
}
});
- var logo_img = this.element.find("img.current_kernel_logo");
logo_img.on("load", function() {
logo_img.show();
});
diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js
index 94be416de..8e8fe5987 100644
--- a/IPython/html/static/notebook/js/notebook.js
+++ b/IPython/html/static/notebook/js/notebook.js
@@ -247,7 +247,7 @@ define([
this.events.on('spec_changed.Kernel', function(event, data) {
that.metadata.kernelspec =
- {name: data.name, display_name: data.display_name};
+ {name: data.name, display_name: data.spec.display_name};
});
this.events.on('kernel_ready.Kernel', function(event, data) {