diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js
index 492793b..8181138 100644
--- a/IPython/html/static/notebook/js/notebook.js
+++ b/IPython/html/static/notebook/js/notebook.js
@@ -207,9 +207,18 @@ define([
});
this.events.on('spec_changed.Kernel', function(event, data) {
- that.set_kernelspec_metadata(data);
+ that.metadata.kernelspec =
+ {name: data.name, display_name: data.display_name};
+ });
+
+ this.events.on('kernel_ready.Kernel', function(event, data) {
+ var kinfo = data.kernel.info_reply
+ var langinfo = kinfo.language_info || {};
+ if (!langinfo.name) langinfo.name = kinfo.language;
+
+ that.metadata.language_info = langinfo;
// Mode 'null' should be plain, unhighlighted text.
- cm_mode = data.codemirror_mode || data.language || 'null'
+ var cm_mode = langinfo.codemirror_mode || langinfo.language || 'null'
that.set_codemirror_mode(cm_mode);
});
@@ -329,21 +338,11 @@ define([
md: this.metadata,
callback: function (md) {
that.metadata = md;
- },
+ },
name: 'Notebook',
notebook: this,
keyboard_manager: this.keyboard_manager});
};
-
- Notebook.prototype.set_kernelspec_metadata = function(ks) {
- var tostore = {};
- $.map(ks, function(value, field) {
- if (field !== 'argv' && field !== 'env') {
- tostore[field] = value;
- }
- });
- this.metadata.kernelspec = tostore;
- }
// Cell indexing, retrieval, etc.
@@ -1811,6 +1810,14 @@ define([
this.events.trigger('spec_changed.Kernel', this.metadata.kernelspec);
}
+ // Set the codemirror mode from language_info metadata
+ if (this.metadata.language_info !== undefined) {
+ var langinfo = this.metadata.language_info;
+ // Mode 'null' should be plain, unhighlighted text.
+ var cm_mode = langinfo.codemirror_mode || langinfo.language || 'null'
+ this.set_codemirror_mode(cm_mode);
+ }
+
// Only handle 1 worksheet for now.
var worksheet = content.worksheets[0];
if (worksheet !== undefined) {
diff --git a/IPython/html/static/services/kernels/kernel.js b/IPython/html/static/services/kernels/kernel.js
index 9ad4fcb..38ac473 100644
--- a/IPython/html/static/services/kernels/kernel.js
+++ b/IPython/html/static/services/kernels/kernel.js
@@ -46,6 +46,7 @@ define([
this.username = "username";
this.session_id = utils.uuid();
this._msg_callbacks = {};
+ this.info_reply = {}; // kernel_info_reply stored here after starting
if (typeof(WebSocket) !== 'undefined') {
this.WebSocket = WebSocket;
@@ -398,7 +399,8 @@ define([
this.events.trigger('kernel_starting.Kernel', {kernel: this});
// get kernel info so we know what state the kernel is in
var that = this;
- this.kernel_info(function () {
+ this.kernel_info(function (reply) {
+ that.info_reply = reply.content;
that.events.trigger('kernel_ready.Kernel', {kernel: that});
});
};
@@ -925,7 +927,8 @@ define([
} else if (execution_state === 'starting') {
this.events.trigger('kernel_starting.Kernel', {kernel: this});
var that = this;
- this.kernel_info(function () {
+ this.kernel_info(function (reply) {
+ that.info_reply = reply.content;
that.events.trigger('kernel_ready.Kernel', {kernel: that});
});
diff --git a/IPython/kernel/kernelspec.py b/IPython/kernel/kernelspec.py
index 63ea62a..58d3250 100644
--- a/IPython/kernel/kernelspec.py
+++ b/IPython/kernel/kernelspec.py
@@ -36,18 +36,9 @@ def _pythonfirst(s):
class KernelSpec(HasTraits):
argv = List()
display_name = Unicode()
- language = Unicode()
- codemirror_mode = Any() # can be unicode or dict
- pygments_lexer = Unicode()
env = Dict()
resource_dir = Unicode()
- def _codemirror_mode_default(self):
- return self.language
-
- def _pygments_lexer_default(self):
- return self.language
-
@classmethod
def from_resource_dir(cls, resource_dir):
"""Create a KernelSpec object by reading kernel.json
@@ -63,12 +54,7 @@ class KernelSpec(HasTraits):
d = dict(argv=self.argv,
env=self.env,
display_name=self.display_name,
- language=self.language,
)
- if self.codemirror_mode != self.language:
- d['codemirror_mode'] = self.codemirror_mode
- if self.pygments_lexer != self.language:
- d['pygments_lexer'] = self.pygments_lexer
return d
@@ -118,12 +104,8 @@ class KernelSpecManager(HasTraits):
process. This will put its informatino in the user kernels directory.
"""
return {'argv': make_ipkernel_cmd(),
- 'display_name': 'IPython (Python %d)' % (3 if PY3 else 2),
- 'language': 'python',
- 'codemirror_mode': {'name': 'ipython',
- 'version': sys.version_info[0]},
- 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
- }
+ 'display_name': 'IPython (Python %d)' % (3 if PY3 else 2),
+ }
@property
def _native_kernel_resource_dir(self):
diff --git a/IPython/kernel/tests/test_kernelspec.py b/IPython/kernel/tests/test_kernelspec.py
index 5275943..d909784 100644
--- a/IPython/kernel/tests/test_kernelspec.py
+++ b/IPython/kernel/tests/test_kernelspec.py
@@ -9,7 +9,6 @@ from IPython.kernel import kernelspec
sample_kernel_json = {'argv':['cat', '{connection_file}'],
'display_name':'Test kernel',
- 'language':'bash',
}
class KernelSpecTests(unittest.TestCase):
@@ -39,8 +38,6 @@ class KernelSpecTests(unittest.TestCase):
self.assertEqual(ks.resource_dir, self.sample_kernel_dir)
self.assertEqual(ks.argv, sample_kernel_json['argv'])
self.assertEqual(ks.display_name, sample_kernel_json['display_name'])
- self.assertEqual(ks.language, sample_kernel_json['language'])
- self.assertEqual(ks.codemirror_mode, sample_kernel_json['language'])
self.assertEqual(ks.env, {})
def test_install_kernel_spec(self):
diff --git a/IPython/kernel/tests/test_message_spec.py b/IPython/kernel/tests/test_message_spec.py
index 3716a9f..3a72275 100644
--- a/IPython/kernel/tests/test_message_spec.py
+++ b/IPython/kernel/tests/test_message_spec.py
@@ -157,6 +157,7 @@ class KernelInfoReply(Reference):
implementation_version = Version(min='2.1')
language_version = Version(min='2.7')
language = Unicode('python')
+ language_info = Dict()
banner = Unicode()
diff --git a/IPython/kernel/zmq/ipkernel.py b/IPython/kernel/zmq/ipkernel.py
index 8c6e8c8..d64b521 100644
--- a/IPython/kernel/zmq/ipkernel.py
+++ b/IPython/kernel/zmq/ipkernel.py
@@ -71,6 +71,11 @@ class IPythonKernel(KernelBase):
implementation_version = release.version
language = 'python'
language_version = sys.version.split()[0]
+ language_info = {'mimetype': 'text/x-python',
+ 'codemirror_mode': {'name': 'ipython',
+ 'version': sys.version_info[0]},
+ 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
+ }
@property
def banner(self):
return self.shell.banner
diff --git a/IPython/kernel/zmq/kernelbase.py b/IPython/kernel/zmq/kernelbase.py
index 85f7beb..42b38c0 100755
--- a/IPython/kernel/zmq/kernelbase.py
+++ b/IPython/kernel/zmq/kernelbase.py
@@ -60,6 +60,10 @@ class Kernel(SingletonConfigurable):
def _ident_default(self):
return unicode_type(uuid.uuid4())
+ # This should be overridden by wrapper kernels that implement any real
+ # language.
+ language_info = {}
+
# Private interface
_darwin_app_nap = Bool(True, config=True,
@@ -453,6 +457,7 @@ class Kernel(SingletonConfigurable):
'implementation_version': self.implementation_version,
'language': self.language,
'language_version': self.language_version,
+ 'language_info': self.language_info,
'banner': self.banner,
}
diff --git a/IPython/nbconvert/exporters/html.py b/IPython/nbconvert/exporters/html.py
index 3bd4851..4af0967 100644
--- a/IPython/nbconvert/exporters/html.py
+++ b/IPython/nbconvert/exporters/html.py
@@ -59,8 +59,8 @@ class HTMLExporter(TemplateExporter):
return c
def from_notebook_node(self, nb, resources=None, **kw):
- kernelspec = nb.metadata.get('kernelspec', {})
- lexer = kernelspec.get('pygments_lexer', kernelspec.get('language', None))
+ langinfo = nb.metadata.get('language_info', {})
+ lexer = langinfo.get('pygments_lexer', langinfo.get('name', None))
self.register_filter('highlight_code',
Highlight2HTML(pygments_lexer=lexer, parent=self))
return super(HTMLExporter, self).from_notebook_node(nb, resources, **kw)
diff --git a/IPython/nbconvert/exporters/latex.py b/IPython/nbconvert/exporters/latex.py
index 94aad0e..8b387ac 100644
--- a/IPython/nbconvert/exporters/latex.py
+++ b/IPython/nbconvert/exporters/latex.py
@@ -89,8 +89,8 @@ class LatexExporter(TemplateExporter):
return c
def from_notebook_node(self, nb, resources=None, **kw):
- kernelspec = nb.metadata.get('kernelspec', {})
- lexer = kernelspec.get('pygments_lexer', kernelspec.get('language', None))
+ langinfo = nb.metadata.get('language_info', {})
+ lexer = langinfo.get('pygments_lexer', langinfo.get('name', None))
self.register_filter('highlight_code',
Highlight2Latex(pygments_lexer=lexer, parent=self))
return super(LatexExporter, self).from_notebook_node(nb, resources, **kw)
diff --git a/IPython/nbconvert/filters/highlight.py b/IPython/nbconvert/filters/highlight.py
index 9b0b6e6..59c0df1 100644
--- a/IPython/nbconvert/filters/highlight.py
+++ b/IPython/nbconvert/filters/highlight.py
@@ -27,7 +27,7 @@ class Highlight2HTML(NbConvertBase):
def _default_language_changed(self, name, old, new):
warn('Setting default_language in config is deprecated, '
- 'please use kernelspecs instead.')
+ 'please use language_info metadata instead.')
self.pygments_lexer = new
def __call__(self, source, language=None, metadata=None):
@@ -61,7 +61,7 @@ class Highlight2Latex(NbConvertBase):
def _default_language_changed(self, name, old, new):
warn('Setting default_language in config is deprecated, '
- 'please use kernelspecs instead.')
+ 'please use language_info metadata instead.')
self.pygments_lexer = new
def __call__(self, source, language=None, metadata=None, strip_verbatim=False):
diff --git a/IPython/nbconvert/utils/base.py b/IPython/nbconvert/utils/base.py
index 68b3880..c336bd2 100644
--- a/IPython/nbconvert/utils/base.py
+++ b/IPython/nbconvert/utils/base.py
@@ -35,7 +35,7 @@ class NbConvertBase(LoggingConfigurable):
)
default_language = Unicode('ipython', config=True,
- help='DEPRECATED default highlight language, please use kernelspecs instead')
+ help='DEPRECATED default highlight language, please use language_info metadata instead')
def __init__(self, **kw):
super(NbConvertBase, self).__init__(**kw)
diff --git a/docs/source/development/kernels.rst b/docs/source/development/kernels.rst
index 5c8fd0f..6336dc1 100644
--- a/docs/source/development/kernels.rst
+++ b/docs/source/development/kernels.rst
@@ -112,34 +112,16 @@ JSON serialised dictionary containing the following keys and values:
- **display_name**: The kernel's name as it should be displayed in the UI.
Unlike the kernel name used in the API, this can contain arbitrary unicode
characters.
-- **language**: The programming language which this kernel runs. This will be
- stored in notebook metadata. This may be used by syntax highlighters to guess
- how to parse code in a notebook, and frontends may eventually use it to
- identify alternative kernels that can run some code.
-- **codemirror_mode** (optional): The `codemirror mode `_
- to use for code in this language. This can be a string or a dictionary, as
- passed to codemirror config. This only needs to be specified if it does not
- match the value in *language*.
-- **pygments_lexer** (optional): The name of a `Pygments lexer `_
- to use for code in this language, as a string. This only needs to be specified
- if it does not match the value in *language*.
- **env** (optional): A dictionary of environment variables to set for the kernel.
These will be added to the current environment variables before the kernel is
started.
-- **help_links** (optional): A list of dictionaries, each with keys 'text' and
- 'url'. These will be displayed in the help menu in the notebook UI.
For example, the kernel.json file for IPython looks like this::
{
"argv": ["python3", "-c", "from IPython.kernel.zmq.kernelapp import main; main()",
- "-f", "{connection_file}"],
- "codemirror_mode": {
- "version": 3,
- "name": "ipython"
- },
+ "-f", "{connection_file}"],
"display_name": "IPython (Python 3)",
- "language": "python"
}
To see the available kernel specs, run::
diff --git a/docs/source/development/messaging.rst b/docs/source/development/messaging.rst
index f2a3be1..813fd8b 100644
--- a/docs/source/development/messaging.rst
+++ b/docs/source/development/messaging.rst
@@ -685,11 +685,33 @@ Message type: ``kernel_info_reply``::
# included in IPython.
'language_version': 'X.Y.Z',
+ # Information about the language of code for the kernel
+ 'language_info': {
+ 'mimetype': str,
+
+ # Pygments lexer, for highlighting
+ # Only needed if it differs from the top level 'language' field.
+ 'pygments_lexer': str,
+
+ # Codemirror mode, for for highlighting in the notebook.
+ # Only needed if it differs from the top level 'language' field.
+ 'codemirror_mode': str or dict,
+ },
+
# A banner of information about the kernel,
# which may be desplayed in console environments.
'banner' : str,
+
+ # Optional: A list of dictionaries, each with keys 'text' and 'url'.
+ # These will be displayed in the help menu in the notebook UI.
+ 'help_links': [
+ {'text': str, 'url': str}
+ ],
}
+Refer to the lists of available `Pygments lexers `_
+and `codemirror modes `_ for those fields.
+
.. versionchanged:: 5.0
Versions changed from lists of integers to strings.
@@ -700,7 +722,8 @@ Message type: ``kernel_info_reply``::
.. versionchanged:: 5.0
- ``implementation``, ``implementation_version``, and ``banner`` keys are added.
+ ``language_info``, ``implementation``, ``implementation_version``, ``banner``
+ and ``help_links`` keys are added.
.. _msging_shutdown:
diff --git a/docs/source/development/wrapperkernels.rst b/docs/source/development/wrapperkernels.rst
index 73fc405..271c5da 100644
--- a/docs/source/development/wrapperkernels.rst
+++ b/docs/source/development/wrapperkernels.rst
@@ -34,6 +34,16 @@ following methods and attributes:
interprets (e.g. Python). The 'banner' is displayed to the user in console
UIs before the first prompt. All of these values are strings.
+ .. attribute:: language_info
+
+ Language information for :ref:`msging_kernel_info` replies, in a dictionary.
+ This should contain the key ``mimetype`` with the mimetype of code in the
+ target language (e.g. ``'text/x-python'``). It may also contain keys
+ ``codemirror_mode`` and ``pygments_lexer`` if they need to differ from
+ :attr:`language`.
+
+ Other keys may be added to this later.
+
.. method:: do_execute(code, silent, store_history=True, user_expressions=None, allow_stdin=False)
Execute user code.
@@ -71,6 +81,7 @@ Example
implementation_version = '1.0'
language = 'no-op'
language_version = '0.1'
+ language_info = {'mimetype': 'text/plain'}
banner = "Echo kernel - as useful as a parrot"
def do_execute(self, code, silent, store_history=True, user_expressions=None,
@@ -94,7 +105,6 @@ Here's the Kernel spec ``kernel.json`` file for this::
{"argv":["python","-m","echokernel", "-f", "{connection_file}"],
"display_name":"Echo",
- "language":"no-op"
}