We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
When kernel is missing, notebook fails to load
Using master as of 0f92b92748b0dc07dd, I tried loading a notebook with a kernel I don't have configured (Python 3). Instead of getting the message indicating I should install it and at least being able to read the notebook, the popup said

```
Notebook failed to load
The error was:
TypeError: Cannot read property 'resources' of undefined
```

And the notebook didn't load at all.

This is obviously a hard blocker for release.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `IPython/kernel/kernelspec.py`
Content:
```
1 import io
2 import json
3 import os
4 import shutil
5 import sys
6 
7 pjoin = os.path.join
8 
9 from IPython.utils.path import get_ipython_dir
10 from IPython.utils.py3compat import PY3
11 from IPython.utils.traitlets import HasTraits, List, Unicode, Dict, Any
12 from .launcher import make_ipkernel_cmd
13 
14 if os.name == 'nt':
15     programdata = os.environ.get('PROGRAMDATA', None)
16     if programdata:
17         SYSTEM_KERNEL_DIRS = [pjoin(programdata, 'jupyter', 'kernels')]
18     else:  # PROGRAMDATA is not defined by default on XP.
19         SYSTEM_KERNEL_DIRS = []
20 else:
21     SYSTEM_KERNEL_DIRS = ["/usr/share/jupyter/kernels",
22                           "/usr/local/share/jupyter/kernels",
23                          ]
24     
25 NATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2'
26 
27 def _pythonfirst(s):
28     "Sort key function that will put strings starting with 'python' first."
29     if s == NATIVE_KERNEL_NAME:
30         return '  ' + s  # Two spaces to sort this first of all
31     elif s.startswith('python'):
32         # Space is not valid in kernel names, so this should sort first
33         return ' ' + s
34     return s
35 
36 class KernelSpec(HasTraits):
37     argv = List()
38     display_name = Unicode()
39     env = Dict()
40     resource_dir = Unicode()
41     
42     @classmethod
43     def from_resource_dir(cls, resource_dir):
44         """Create a KernelSpec object by reading kernel.json
45         
46         Pass the path to the *directory* containing kernel.json.
47         """
48         kernel_file = pjoin(resource_dir, 'kernel.json')
49         with io.open(kernel_file, 'r', encoding='utf-8') as f:
50             kernel_dict = json.load(f)
51         return cls(resource_dir=resource_dir, **kernel_dict)
52     
53     def to_dict(self):
54         d = dict(argv=self.argv,
55                  env=self.env,
56                  display_name=self.display_name,
57                 )
58 
59         return d
60 
61     def to_json(self):
62         return json.dumps(self.to_dict())
63 
64 def _is_kernel_dir(path):
65     """Is ``path`` a kernel directory?"""
66     return os.path.isdir(path) and os.path.isfile(pjoin(path, 'kernel.json'))
67 
68 def _list_kernels_in(dir):
69     """Return a mapping of kernel names to resource directories from dir.
70     
71     If dir is None or does not exist, returns an empty dict.
72     """
73     if dir is None or not os.path.isdir(dir):
74         return {}
75     return {f.lower(): pjoin(dir, f) for f in os.listdir(dir)
76                         if _is_kernel_dir(pjoin(dir, f))}
77 
78 class NoSuchKernel(KeyError):
79     def __init__(self, name):
80         self.name = name
81 
82 class KernelSpecManager(HasTraits):
83     ipython_dir = Unicode()
84     def _ipython_dir_default(self):
85         return get_ipython_dir()
86 
87     user_kernel_dir = Unicode()
88     def _user_kernel_dir_default(self):
89         return pjoin(self.ipython_dir, 'kernels')
90 
91     @property
92     def env_kernel_dir(self):
93         return pjoin(sys.prefix, 'share', 'jupyter', 'kernels')
94     
95     kernel_dirs = List(
96         help="List of kernel directories to search. Later ones take priority over earlier."    
97     )    
98     def _kernel_dirs_default(self):
99         dirs = SYSTEM_KERNEL_DIRS[:]
100         if self.env_kernel_dir not in dirs:
101             dirs.append(self.env_kernel_dir)
102         dirs.append(self.user_kernel_dir)
103         return dirs
104 
105     @property
106     def _native_kernel_dict(self):
107         """Makes a kernel directory for the native kernel.
108         
109         The native kernel is the kernel using the same Python runtime as this
110         process. This will put its information in the user kernels directory.
111         """
112         return {'argv': make_ipkernel_cmd(),
113                 'display_name': 'Python %i' % (3 if PY3 else 2),
114                }
115 
116     @property
117     def _native_kernel_resource_dir(self):
118         return pjoin(os.path.dirname(__file__), 'resources')
119 
120     def find_kernel_specs(self):
121         """Returns a dict mapping kernel names to resource directories."""
122         d = {}
123         for kernel_dir in self.kernel_dirs:
124             d.update(_list_kernels_in(kernel_dir))
125 
126         d[NATIVE_KERNEL_NAME] = self._native_kernel_resource_dir
127         return d
128         # TODO: Caching?
129 
130     def get_kernel_spec(self, kernel_name):
131         """Returns a :class:`KernelSpec` instance for the given kernel_name.
132         
133         Raises :exc:`NoSuchKernel` if the given kernel name is not found.
134         """
135         if kernel_name in {'python', NATIVE_KERNEL_NAME}:
136             return KernelSpec(resource_dir=self._native_kernel_resource_dir,
137                               **self._native_kernel_dict)
138 
139         d = self.find_kernel_specs()
140         try:
141             resource_dir = d[kernel_name.lower()]
142         except KeyError:
143             raise NoSuchKernel(kernel_name)
144         return KernelSpec.from_resource_dir(resource_dir)
145     
146     def _get_destination_dir(self, kernel_name, user=False):
147         if user:
148             return os.path.join(self.user_kernel_dir, kernel_name)
149         else:
150             if SYSTEM_KERNEL_DIRS:
151                 return os.path.join(SYSTEM_KERNEL_DIRS[-1], kernel_name)
152             else:
153                 raise EnvironmentError("No system kernel directory is available")
154 
155 
156     def install_kernel_spec(self, source_dir, kernel_name=None, user=False,
157                             replace=False):
158         """Install a kernel spec by copying its directory.
159         
160         If ``kernel_name`` is not given, the basename of ``source_dir`` will
161         be used.
162         
163         If ``user`` is False, it will attempt to install into the systemwide
164         kernel registry. If the process does not have appropriate permissions,
165         an :exc:`OSError` will be raised.
166         
167         If ``replace`` is True, this will replace an existing kernel of the same
168         name. Otherwise, if the destination already exists, an :exc:`OSError`
169         will be raised.
170         """
171         if not kernel_name:
172             kernel_name = os.path.basename(source_dir)
173         kernel_name = kernel_name.lower()
174         
175         destination = self._get_destination_dir(kernel_name, user=user)
176 
177         if replace and os.path.isdir(destination):
178             shutil.rmtree(destination)
179 
180         shutil.copytree(source_dir, destination)
181 
182     def install_native_kernel_spec(self, user=False):
183         """Install the native kernel spec to the filesystem
184         
185         This allows a Python 3 frontend to use a Python 2 kernel, or vice versa.
186         The kernelspec will be written pointing to the Python executable on
187         which this is run.
188         
189         If ``user`` is False, it will attempt to install into the systemwide
190         kernel registry. If the process does not have appropriate permissions, 
191         an :exc:`OSError` will be raised.
192         """
193         path = self._get_destination_dir(NATIVE_KERNEL_NAME, user=user)
194         os.makedirs(path, mode=0o755)
195         with open(pjoin(path, 'kernel.json'), 'w') as f:
196             json.dump(self._native_kernel_dict, f, indent=1)
197         copy_from = self._native_kernel_resource_dir
198         for file in os.listdir(copy_from):
199             shutil.copy(pjoin(copy_from, file), path)
200         return path
201 
202 def find_kernel_specs():
203     """Returns a dict mapping kernel names to resource directories."""
204     return KernelSpecManager().find_kernel_specs()
205 
206 def get_kernel_spec(kernel_name):
207     """Returns a :class:`KernelSpec` instance for the given kernel_name.
208     
209     Raises KeyError if the given kernel name is not found.
210     """
211     return KernelSpecManager().get_kernel_spec(kernel_name)
212 
213 def install_kernel_spec(source_dir, kernel_name=None, user=False, replace=False):
214     return KernelSpecManager().install_kernel_spec(source_dir, kernel_name,
215                                                     user, replace)
216 
217 install_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__
218 
219 def install_native_kernel_spec(user=False):
220     return KernelSpecManager().install_native_kernel_spec(user=user)
221 
222 install_native_kernel_spec.__doc__ = KernelSpecManager.install_native_kernel_spec.__doc__
223
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/IPython/kernel/kernelspec.py b/IPython/kernel/kernelspec.py
--- a/IPython/kernel/kernelspec.py
+++ b/IPython/kernel/kernelspec.py
@@ -36,6 +36,7 @@
 class KernelSpec(HasTraits):
     argv = List()
     display_name = Unicode()
+    language = Unicode()
     env = Dict()
     resource_dir = Unicode()
     
@@ -54,6 +55,7 @@
         d = dict(argv=self.argv,
                  env=self.env,
                  display_name=self.display_name,
+                 language=self.language,
                 )
 
         return d
@@ -109,8 +111,10 @@
         The native kernel is the kernel using the same Python runtime as this
         process. This will put its information in the user kernels directory.
         """
-        return {'argv': make_ipkernel_cmd(),
+        return {
+                'argv': make_ipkernel_cmd(),
                 'display_name': 'Python %i' % (3 if PY3 else 2),
+                'language': 'python',
                }
 
     @property

{"golden_diff": "diff --git a/IPython/kernel/kernelspec.py b/IPython/kernel/kernelspec.py\n--- a/IPython/kernel/kernelspec.py\n+++ b/IPython/kernel/kernelspec.py\n@@ -36,6 +36,7 @@\n class KernelSpec(HasTraits):\n     argv = List()\n     display_name = Unicode()\n+    language = Unicode()\n     env = Dict()\n     resource_dir = Unicode()\n     \n@@ -54,6 +55,7 @@\n         d = dict(argv=self.argv,\n                  env=self.env,\n                  display_name=self.display_name,\n+                 language=self.language,\n                 )\n \n         return d\n@@ -109,8 +111,10 @@\n         The native kernel is the kernel using the same Python runtime as this\n         process. This will put its information in the user kernels directory.\n         \"\"\"\n-        return {'argv': make_ipkernel_cmd(),\n+        return {\n+                'argv': make_ipkernel_cmd(),\n                 'display_name': 'Python %i' % (3 if PY3 else 2),\n+                'language': 'python',\n                }\n \n     @property\n", "issue": "When kernel is missing, notebook fails to load\nUsing master as of 0f92b92748b0dc07dd, I tried loading a notebook with a kernel I don't have configured (Python 3). Instead of getting the message indicating I should install it and at least being able to read the notebook, the popup said\n\n```\nNotebook failed to load\nThe error was:\nTypeError: Cannot read property 'resources' of undefined\n```\n\nAnd the notebook didn't load at all.\n\nThis is obviously a hard blocker for release.\n\n", "before_files": [{"content": "import io\nimport json\nimport os\nimport shutil\nimport sys\n\npjoin = os.path.join\n\nfrom IPython.utils.path import get_ipython_dir\nfrom IPython.utils.py3compat import PY3\nfrom IPython.utils.traitlets import HasTraits, List, Unicode, Dict, Any\nfrom .launcher import make_ipkernel_cmd\n\nif os.name == 'nt':\n    programdata = os.environ.get('PROGRAMDATA', None)\n    if programdata:\n        SYSTEM_KERNEL_DIRS = [pjoin(programdata, 'jupyter', 'kernels')]\n    else:  # PROGRAMDATA is not defined by default on XP.\n        SYSTEM_KERNEL_DIRS = []\nelse:\n    SYSTEM_KERNEL_DIRS = [\"/usr/share/jupyter/kernels\",\n                          \"/usr/local/share/jupyter/kernels\",\n                         ]\n    \nNATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2'\n\ndef _pythonfirst(s):\n    \"Sort key function that will put strings starting with 'python' first.\"\n    if s == NATIVE_KERNEL_NAME:\n        return '  ' + s  # Two spaces to sort this first of all\n    elif s.startswith('python'):\n        # Space is not valid in kernel names, so this should sort first\n        return ' ' + s\n    return s\n\nclass KernelSpec(HasTraits):\n    argv = List()\n    display_name = Unicode()\n    env = Dict()\n    resource_dir = Unicode()\n    \n    @classmethod\n    def from_resource_dir(cls, resource_dir):\n        \"\"\"Create a KernelSpec object by reading kernel.json\n        \n        Pass the path to the *directory* containing kernel.json.\n        \"\"\"\n        kernel_file = pjoin(resource_dir, 'kernel.json')\n        with io.open(kernel_file, 'r', encoding='utf-8') as f:\n            kernel_dict = json.load(f)\n        return cls(resource_dir=resource_dir, **kernel_dict)\n    \n    def to_dict(self):\n        d = dict(argv=self.argv,\n                 env=self.env,\n                 display_name=self.display_name,\n                )\n\n        return d\n\n    def to_json(self):\n        return json.dumps(self.to_dict())\n\ndef _is_kernel_dir(path):\n    \"\"\"Is ``path`` a kernel directory?\"\"\"\n    return os.path.isdir(path) and os.path.isfile(pjoin(path, 'kernel.json'))\n\ndef _list_kernels_in(dir):\n    \"\"\"Return a mapping of kernel names to resource directories from dir.\n    \n    If dir is None or does not exist, returns an empty dict.\n    \"\"\"\n    if dir is None or not os.path.isdir(dir):\n        return {}\n    return {f.lower(): pjoin(dir, f) for f in os.listdir(dir)\n                        if _is_kernel_dir(pjoin(dir, f))}\n\nclass NoSuchKernel(KeyError):\n    def __init__(self, name):\n        self.name = name\n\nclass KernelSpecManager(HasTraits):\n    ipython_dir = Unicode()\n    def _ipython_dir_default(self):\n        return get_ipython_dir()\n\n    user_kernel_dir = Unicode()\n    def _user_kernel_dir_default(self):\n        return pjoin(self.ipython_dir, 'kernels')\n\n    @property\n    def env_kernel_dir(self):\n        return pjoin(sys.prefix, 'share', 'jupyter', 'kernels')\n    \n    kernel_dirs = List(\n        help=\"List of kernel directories to search. Later ones take priority over earlier.\"    \n    )    \n    def _kernel_dirs_default(self):\n        dirs = SYSTEM_KERNEL_DIRS[:]\n        if self.env_kernel_dir not in dirs:\n            dirs.append(self.env_kernel_dir)\n        dirs.append(self.user_kernel_dir)\n        return dirs\n\n    @property\n    def _native_kernel_dict(self):\n        \"\"\"Makes a kernel directory for the native kernel.\n        \n        The native kernel is the kernel using the same Python runtime as this\n        process. This will put its information in the user kernels directory.\n        \"\"\"\n        return {'argv': make_ipkernel_cmd(),\n                'display_name': 'Python %i' % (3 if PY3 else 2),\n               }\n\n    @property\n    def _native_kernel_resource_dir(self):\n        return pjoin(os.path.dirname(__file__), 'resources')\n\n    def find_kernel_specs(self):\n        \"\"\"Returns a dict mapping kernel names to resource directories.\"\"\"\n        d = {}\n        for kernel_dir in self.kernel_dirs:\n            d.update(_list_kernels_in(kernel_dir))\n\n        d[NATIVE_KERNEL_NAME] = self._native_kernel_resource_dir\n        return d\n        # TODO: Caching?\n\n    def get_kernel_spec(self, kernel_name):\n        \"\"\"Returns a :class:`KernelSpec` instance for the given kernel_name.\n        \n        Raises :exc:`NoSuchKernel` if the given kernel name is not found.\n        \"\"\"\n        if kernel_name in {'python', NATIVE_KERNEL_NAME}:\n            return KernelSpec(resource_dir=self._native_kernel_resource_dir,\n                              **self._native_kernel_dict)\n\n        d = self.find_kernel_specs()\n        try:\n            resource_dir = d[kernel_name.lower()]\n        except KeyError:\n            raise NoSuchKernel(kernel_name)\n        return KernelSpec.from_resource_dir(resource_dir)\n    \n    def _get_destination_dir(self, kernel_name, user=False):\n        if user:\n            return os.path.join(self.user_kernel_dir, kernel_name)\n        else:\n            if SYSTEM_KERNEL_DIRS:\n                return os.path.join(SYSTEM_KERNEL_DIRS[-1], kernel_name)\n            else:\n                raise EnvironmentError(\"No system kernel directory is available\")\n\n\n    def install_kernel_spec(self, source_dir, kernel_name=None, user=False,\n                            replace=False):\n        \"\"\"Install a kernel spec by copying its directory.\n        \n        If ``kernel_name`` is not given, the basename of ``source_dir`` will\n        be used.\n        \n        If ``user`` is False, it will attempt to install into the systemwide\n        kernel registry. If the process does not have appropriate permissions,\n        an :exc:`OSError` will be raised.\n        \n        If ``replace`` is True, this will replace an existing kernel of the same\n        name. Otherwise, if the destination already exists, an :exc:`OSError`\n        will be raised.\n        \"\"\"\n        if not kernel_name:\n            kernel_name = os.path.basename(source_dir)\n        kernel_name = kernel_name.lower()\n        \n        destination = self._get_destination_dir(kernel_name, user=user)\n\n        if replace and os.path.isdir(destination):\n            shutil.rmtree(destination)\n\n        shutil.copytree(source_dir, destination)\n\n    def install_native_kernel_spec(self, user=False):\n        \"\"\"Install the native kernel spec to the filesystem\n        \n        This allows a Python 3 frontend to use a Python 2 kernel, or vice versa.\n        The kernelspec will be written pointing to the Python executable on\n        which this is run.\n        \n        If ``user`` is False, it will attempt to install into the systemwide\n        kernel registry. If the process does not have appropriate permissions, \n        an :exc:`OSError` will be raised.\n        \"\"\"\n        path = self._get_destination_dir(NATIVE_KERNEL_NAME, user=user)\n        os.makedirs(path, mode=0o755)\n        with open(pjoin(path, 'kernel.json'), 'w') as f:\n            json.dump(self._native_kernel_dict, f, indent=1)\n        copy_from = self._native_kernel_resource_dir\n        for file in os.listdir(copy_from):\n            shutil.copy(pjoin(copy_from, file), path)\n        return path\n\ndef find_kernel_specs():\n    \"\"\"Returns a dict mapping kernel names to resource directories.\"\"\"\n    return KernelSpecManager().find_kernel_specs()\n\ndef get_kernel_spec(kernel_name):\n    \"\"\"Returns a :class:`KernelSpec` instance for the given kernel_name.\n    \n    Raises KeyError if the given kernel name is not found.\n    \"\"\"\n    return KernelSpecManager().get_kernel_spec(kernel_name)\n\ndef install_kernel_spec(source_dir, kernel_name=None, user=False, replace=False):\n    return KernelSpecManager().install_kernel_spec(source_dir, kernel_name,\n                                                    user, replace)\n\ninstall_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__\n\ndef install_native_kernel_spec(user=False):\n    return KernelSpecManager().install_native_kernel_spec(user=user)\n\ninstall_native_kernel_spec.__doc__ = KernelSpecManager.install_native_kernel_spec.__doc__\n", "path": "IPython/kernel/kernelspec.py"}], "after_files": [{"content": "import io\nimport json\nimport os\nimport shutil\nimport sys\n\npjoin = os.path.join\n\nfrom IPython.utils.path import get_ipython_dir\nfrom IPython.utils.py3compat import PY3\nfrom IPython.utils.traitlets import HasTraits, List, Unicode, Dict, Any\nfrom .launcher import make_ipkernel_cmd\n\nif os.name == 'nt':\n    programdata = os.environ.get('PROGRAMDATA', None)\n    if programdata:\n        SYSTEM_KERNEL_DIRS = [pjoin(programdata, 'jupyter', 'kernels')]\n    else:  # PROGRAMDATA is not defined by default on XP.\n        SYSTEM_KERNEL_DIRS = []\nelse:\n    SYSTEM_KERNEL_DIRS = [\"/usr/share/jupyter/kernels\",\n                          \"/usr/local/share/jupyter/kernels\",\n                         ]\n    \nNATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2'\n\ndef _pythonfirst(s):\n    \"Sort key function that will put strings starting with 'python' first.\"\n    if s == NATIVE_KERNEL_NAME:\n        return '  ' + s  # Two spaces to sort this first of all\n    elif s.startswith('python'):\n        # Space is not valid in kernel names, so this should sort first\n        return ' ' + s\n    return s\n\nclass KernelSpec(HasTraits):\n    argv = List()\n    display_name = Unicode()\n    language = Unicode()\n    env = Dict()\n    resource_dir = Unicode()\n    \n    @classmethod\n    def from_resource_dir(cls, resource_dir):\n        \"\"\"Create a KernelSpec object by reading kernel.json\n        \n        Pass the path to the *directory* containing kernel.json.\n        \"\"\"\n        kernel_file = pjoin(resource_dir, 'kernel.json')\n        with io.open(kernel_file, 'r', encoding='utf-8') as f:\n            kernel_dict = json.load(f)\n        return cls(resource_dir=resource_dir, **kernel_dict)\n    \n    def to_dict(self):\n        d = dict(argv=self.argv,\n                 env=self.env,\n                 display_name=self.display_name,\n                 language=self.language,\n                )\n\n        return d\n\n    def to_json(self):\n        return json.dumps(self.to_dict())\n\ndef _is_kernel_dir(path):\n    \"\"\"Is ``path`` a kernel directory?\"\"\"\n    return os.path.isdir(path) and os.path.isfile(pjoin(path, 'kernel.json'))\n\ndef _list_kernels_in(dir):\n    \"\"\"Return a mapping of kernel names to resource directories from dir.\n    \n    If dir is None or does not exist, returns an empty dict.\n    \"\"\"\n    if dir is None or not os.path.isdir(dir):\n        return {}\n    return {f.lower(): pjoin(dir, f) for f in os.listdir(dir)\n                        if _is_kernel_dir(pjoin(dir, f))}\n\nclass NoSuchKernel(KeyError):\n    def __init__(self, name):\n        self.name = name\n\nclass KernelSpecManager(HasTraits):\n    ipython_dir = Unicode()\n    def _ipython_dir_default(self):\n        return get_ipython_dir()\n\n    user_kernel_dir = Unicode()\n    def _user_kernel_dir_default(self):\n        return pjoin(self.ipython_dir, 'kernels')\n\n    @property\n    def env_kernel_dir(self):\n        return pjoin(sys.prefix, 'share', 'jupyter', 'kernels')\n    \n    kernel_dirs = List(\n        help=\"List of kernel directories to search. Later ones take priority over earlier.\"    \n    )    \n    def _kernel_dirs_default(self):\n        dirs = SYSTEM_KERNEL_DIRS[:]\n        if self.env_kernel_dir not in dirs:\n            dirs.append(self.env_kernel_dir)\n        dirs.append(self.user_kernel_dir)\n        return dirs\n\n    @property\n    def _native_kernel_dict(self):\n        \"\"\"Makes a kernel directory for the native kernel.\n        \n        The native kernel is the kernel using the same Python runtime as this\n        process. This will put its information in the user kernels directory.\n        \"\"\"\n        return {\n                'argv': make_ipkernel_cmd(),\n                'display_name': 'Python %i' % (3 if PY3 else 2),\n                'language': 'python',\n               }\n\n    @property\n    def _native_kernel_resource_dir(self):\n        return pjoin(os.path.dirname(__file__), 'resources')\n\n    def find_kernel_specs(self):\n        \"\"\"Returns a dict mapping kernel names to resource directories.\"\"\"\n        d = {}\n        for kernel_dir in self.kernel_dirs:\n            d.update(_list_kernels_in(kernel_dir))\n\n        d[NATIVE_KERNEL_NAME] = self._native_kernel_resource_dir\n        return d\n        # TODO: Caching?\n\n    def get_kernel_spec(self, kernel_name):\n        \"\"\"Returns a :class:`KernelSpec` instance for the given kernel_name.\n        \n        Raises :exc:`NoSuchKernel` if the given kernel name is not found.\n        \"\"\"\n        if kernel_name in {'python', NATIVE_KERNEL_NAME}:\n            return KernelSpec(resource_dir=self._native_kernel_resource_dir,\n                              **self._native_kernel_dict)\n\n        d = self.find_kernel_specs()\n        try:\n            resource_dir = d[kernel_name.lower()]\n        except KeyError:\n            raise NoSuchKernel(kernel_name)\n        return KernelSpec.from_resource_dir(resource_dir)\n    \n    def _get_destination_dir(self, kernel_name, user=False):\n        if user:\n            return os.path.join(self.user_kernel_dir, kernel_name)\n        else:\n            if SYSTEM_KERNEL_DIRS:\n                return os.path.join(SYSTEM_KERNEL_DIRS[-1], kernel_name)\n            else:\n                raise EnvironmentError(\"No system kernel directory is available\")\n\n\n    def install_kernel_spec(self, source_dir, kernel_name=None, user=False,\n                            replace=False):\n        \"\"\"Install a kernel spec by copying its directory.\n        \n        If ``kernel_name`` is not given, the basename of ``source_dir`` will\n        be used.\n        \n        If ``user`` is False, it will attempt to install into the systemwide\n        kernel registry. If the process does not have appropriate permissions,\n        an :exc:`OSError` will be raised.\n        \n        If ``replace`` is True, this will replace an existing kernel of the same\n        name. Otherwise, if the destination already exists, an :exc:`OSError`\n        will be raised.\n        \"\"\"\n        if not kernel_name:\n            kernel_name = os.path.basename(source_dir)\n        kernel_name = kernel_name.lower()\n        \n        destination = self._get_destination_dir(kernel_name, user=user)\n\n        if replace and os.path.isdir(destination):\n            shutil.rmtree(destination)\n\n        shutil.copytree(source_dir, destination)\n\n    def install_native_kernel_spec(self, user=False):\n        \"\"\"Install the native kernel spec to the filesystem\n        \n        This allows a Python 3 frontend to use a Python 2 kernel, or vice versa.\n        The kernelspec will be written pointing to the Python executable on\n        which this is run.\n        \n        If ``user`` is False, it will attempt to install into the systemwide\n        kernel registry. If the process does not have appropriate permissions, \n        an :exc:`OSError` will be raised.\n        \"\"\"\n        path = self._get_destination_dir(NATIVE_KERNEL_NAME, user=user)\n        os.makedirs(path, mode=0o755)\n        with open(pjoin(path, 'kernel.json'), 'w') as f:\n            json.dump(self._native_kernel_dict, f, indent=1)\n        copy_from = self._native_kernel_resource_dir\n        for file in os.listdir(copy_from):\n            shutil.copy(pjoin(copy_from, file), path)\n        return path\n\ndef find_kernel_specs():\n    \"\"\"Returns a dict mapping kernel names to resource directories.\"\"\"\n    return KernelSpecManager().find_kernel_specs()\n\ndef get_kernel_spec(kernel_name):\n    \"\"\"Returns a :class:`KernelSpec` instance for the given kernel_name.\n    \n    Raises KeyError if the given kernel name is not found.\n    \"\"\"\n    return KernelSpecManager().get_kernel_spec(kernel_name)\n\ndef install_kernel_spec(source_dir, kernel_name=None, user=False, replace=False):\n    return KernelSpecManager().install_kernel_spec(source_dir, kernel_name,\n                                                    user, replace)\n\ninstall_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__\n\ndef install_native_kernel_spec(user=False):\n    return KernelSpecManager().install_native_kernel_spec(user=user)\n\ninstall_native_kernel_spec.__doc__ = KernelSpecManager.install_native_kernel_spec.__doc__\n", "path": "IPython/kernel/kernelspec.py"}]}