Repository: ipython/ipython

Issue:
fix overwriting modes in project like IJulia
Current IJulia custom.js works by setting the right option of CodeCell , but do not have (yet) kernelspec. 

This leads to master not using the mode set by IJulia, and defaulting to 'null' which remove highlight.

This seem to do the trick by leaving default highliht mode and/or respecting metadata.language which is set by  alot of projects. 



Discussion:

Resolving patch:
diff --git a/IPython/kernel/adapter.py b/IPython/kernel/adapter.py
--- a/IPython/kernel/adapter.py
+++ b/IPython/kernel/adapter.py
@@ -102,16 +102,20 @@ def update_header(self, msg):
     # shell channel
     
     def kernel_info_reply(self, msg):
+        v4c = {}
         content = msg['content']
-        content.pop('banner', None)
         for key in ('language_version', 'protocol_version'):
             if key in content:
-                content[key] = _version_str_to_list(content[key])
-        if content.pop('implementation', '') == 'ipython' \
+                v4c[key] = _version_str_to_list(content[key])
+        if content.get('implementation', '') == 'ipython' \
             and 'implementation_version' in content:
-            content['ipython_version'] = content.pop('implmentation_version')
-        content.pop('implementation_version', None)
-        content.setdefault("implmentation", content['language'])
+            v4c['ipython_version'] = _version_str_to_list(content['implementation_version'])
+        language_info = content.get('language_info', {})
+        language = language_info.get('name', '')
+        v4c.setdefault('language', language)
+        if 'version' in language_info:
+            v4c.setdefault('language_version', _version_str_to_list(language_info['version']))
+        msg['content'] = v4c
         return msg
     
     def execute_request(self, msg):
@@ -204,14 +208,23 @@ def update_header(self, msg):
     
     def kernel_info_reply(self, msg):
         content = msg['content']
-        for key in ('language_version', 'protocol_version', 'ipython_version'):
+        for key in ('protocol_version', 'ipython_version'):
             if key in content:
-                content[key] = ".".join(map(str, content[key]))
+                content[key] = '.'.join(map(str, content[key]))
+        
+        content.setdefault('protocol_version', '4.1')
         
         if content['language'].startswith('python') and 'ipython_version' in content:
             content['implementation'] = 'ipython'
             content['implementation_version'] = content.pop('ipython_version')
         
+        language = content.pop('language')
+        language_info = content.setdefault('language_info', {})
+        language_info.setdefault('name', language)
+        if 'language_version' in content:
+            language_version = '.'.join(map(str, content.pop('language_version')))
+            language_info.setdefault('version', language_version)
+        
         content['banner'] = ''
         return msg
     
diff --git a/IPython/kernel/zmq/ipkernel.py b/IPython/kernel/zmq/ipkernel.py
--- a/IPython/kernel/zmq/ipkernel.py
+++ b/IPython/kernel/zmq/ipkernel.py
@@ -69,9 +69,10 @@ def __init__(self, **kwargs):
     # Kernel info fields
     implementation = 'ipython'
     implementation_version = release.version
-    language = 'python'
-    language_version = sys.version.split()[0]
-    language_info = {'mimetype': 'text/x-python',
+    language_info = {
+                     'name': 'python',
+                     'version': sys.version.split()[0],
+                     'mimetype': 'text/x-python',
                      'codemirror_mode': {'name': 'ipython',
                                          'version': sys.version_info[0]},
                      'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
diff --git a/IPython/kernel/zmq/kernelbase.py b/IPython/kernel/zmq/kernelbase.py
--- a/IPython/kernel/zmq/kernelbase.py
+++ b/IPython/kernel/zmq/kernelbase.py
@@ -455,8 +455,6 @@ def kernel_info(self):
             'protocol_version': release.kernel_protocol_version,
             'implementation': self.implementation,
             'implementation_version': self.implementation_version,
-            'language': self.language,
-            'language_version': self.language_version,
             'language_info': self.language_info,
             'banner': self.banner,
         }


Test patch:
diff --git a/IPython/kernel/tests/test_adapter.py b/IPython/kernel/tests/test_adapter.py
--- a/IPython/kernel/tests/test_adapter.py
+++ b/IPython/kernel/tests/test_adapter.py
@@ -169,6 +169,26 @@ def test_object_info_reply(self):
         text = v5c['data']['text/plain']
         self.assertEqual(text, '\n'.join([v4c['definition'], v4c['docstring']]))
     
+    def test_kernel_info_reply(self):
+        msg = self.msg("kernel_info_reply", {
+            'language': 'python',
+            'language_version': [2,8,0],
+            'ipython_version': [1,2,3],
+        })
+        v4, v5 = self.adapt(msg)
+        v4c = v4['content']
+        v5c = v5['content']
+        self.assertEqual(v5c, {
+            'protocol_version': '4.1',
+            'implementation': 'ipython',
+            'implementation_version': '1.2.3',
+            'language_info': {
+                'name': 'python',
+                'version': '2.8.0',
+            },
+            'banner' : '',
+        })
+    
     # iopub channel
     
     def test_display_data(self):
@@ -305,6 +325,29 @@ def test_inspect_reply(self):
         self.assertEqual(sorted(v4c), ['found', 'oname'])
         self.assertEqual(v4c['found'], False)
     
+    def test_kernel_info_reply(self):
+        msg = self.msg("kernel_info_reply", {
+            'protocol_version': '5.0',
+            'implementation': 'ipython',
+            'implementation_version': '1.2.3',
+            'language_info': {
+                'name': 'python',
+                'version': '2.8.0',
+                'mimetype': 'text/x-python',
+            },
+            'banner' : 'the banner',
+        })
+        v5, v4 = self.adapt(msg)
+        v4c = v4['content']
+        v5c = v5['content']
+        info = v5c['language_info']
+        self.assertEqual(v4c, {
+            'protocol_version': [5,0],
+            'language': 'python',
+            'language_version': [2,8,0],
+            'ipython_version': [1,2,3],
+        })
+    
     # iopub channel
     
     def test_display_data(self):
diff --git a/IPython/kernel/tests/test_message_spec.py b/IPython/kernel/tests/test_message_spec.py
--- a/IPython/kernel/tests/test_message_spec.py
+++ b/IPython/kernel/tests/test_message_spec.py
@@ -4,8 +4,8 @@
 # Distributed under the terms of the Modified BSD License.
 
 import re
+import sys
 from distutils.version import LooseVersion as V
-from subprocess import PIPE
 try:
     from queue import Empty  # Py 3
 except ImportError:
@@ -13,10 +13,8 @@
 
 import nose.tools as nt
 
-from IPython.kernel import KernelManager
-
 from IPython.utils.traitlets import (
-    HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum, Any,
+    HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum,
 )
 from IPython.utils.py3compat import string_types, iteritems
 
@@ -150,15 +148,20 @@ class CompleteReply(Reference):
     cursor_end = Integer()
     status = Unicode()
 
+class LanguageInfo(Reference):
+    name = Unicode('python')
+    version = Unicode(sys.version.split()[0])
 
 class KernelInfoReply(Reference):
     protocol_version = Version(min='5.0')
     implementation = Unicode('ipython')
     implementation_version = Version(min='2.1')
-    language_version = Version(min='2.7')
-    language = Unicode('python')
     language_info = Dict()
     banner = Unicode()
+    
+    def check(self, d):
+        Reference.check(self, d)
+        LanguageInfo().check(d['language_info'])
 
 
 class IsCompleteReply(Reference):