kernelspec.py
141 lines
| 4.9 KiB
| text/x-python
|
PythonLexer
Thomas Kluyver
|
r16260 | import io | |
import json | |||
import os | |||
Thomas Kluyver
|
r16261 | import sys | |
Thomas Kluyver
|
r16260 | ||
pjoin = os.path.join | |||
from IPython.utils.path import get_ipython_dir | |||
from IPython.utils.py3compat import PY3 | |||
Thomas Kluyver
|
r16349 | from IPython.utils.traitlets import HasTraits, List, Unicode, Dict | |
Thomas Kluyver
|
r16260 | ||
if os.name == 'nt': | |||
programdata = os.environ.get('PROGRAMDATA', None) | |||
if programdata: | |||
SYSTEM_KERNEL_DIR = pjoin(programdata, 'ipython', 'kernels') | |||
else: # PROGRAMDATA is not defined by default on XP. | |||
SYSTEM_KERNEL_DIR = None | |||
else: | |||
SYSTEM_KERNEL_DIR = "/usr/share/ipython/kernels" | |||
NATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2' | |||
class KernelSpec(HasTraits): | |||
argv = List() | |||
display_name = Unicode() | |||
language = Unicode() | |||
Thomas Kluyver
|
r16271 | codemirror_mode = None | |
Thomas Kluyver
|
r16349 | env = Dict() | |
Thomas Kluyver
|
r16260 | ||
resource_dir = Unicode() | |||
def __init__(self, resource_dir, argv, display_name, language, | |||
codemirror_mode=None): | |||
super(KernelSpec, self).__init__(resource_dir=resource_dir, argv=argv, | |||
display_name=display_name, language=language, | |||
codemirror_mode=codemirror_mode) | |||
if not self.codemirror_mode: | |||
self.codemirror_mode = self.language | |||
@classmethod | |||
def from_resource_dir(cls, resource_dir): | |||
Thomas Kluyver
|
r16262 | """Create a KernelSpec object by reading kernel.json | |
Pass the path to the *directory* containing kernel.json. | |||
""" | |||
kernel_file = pjoin(resource_dir, 'kernel.json') | |||
Thomas Kluyver
|
r16260 | with io.open(kernel_file, 'r', encoding='utf-8') as f: | |
kernel_dict = json.load(f) | |||
return cls(resource_dir=resource_dir, **kernel_dict) | |||
def _is_kernel_dir(path): | |||
Thomas Kluyver
|
r16262 | """Is ``path`` a kernel directory?""" | |
Thomas Kluyver
|
r16260 | return os.path.isdir(path) and os.path.isfile(pjoin(path, 'kernel.json')) | |
def _list_kernels_in(dir): | |||
Thomas Kluyver
|
r16382 | """Return a mapping of kernel names to resource directories from dir. | |
If dir is None or does not exist, returns an empty dict. | |||
Thomas Kluyver
|
r16262 | """ | |
Thomas Kluyver
|
r16271 | if dir is None or not os.path.isdir(dir): | |
Thomas Kluyver
|
r16260 | return {} | |
return {f.lower(): pjoin(dir, f) for f in os.listdir(dir) | |||
if _is_kernel_dir(pjoin(dir, f))} | |||
Thomas Kluyver
|
r16383 | class NoSuchKernel(KeyError): | |
def __init__(self, name): | |||
self.name = name | |||
Thomas Kluyver
|
r16382 | class KernelSpecManager(HasTraits): | |
ipython_dir = Unicode() | |||
def _ipython_dir_default(self): | |||
return get_ipython_dir() | |||
user_kernel_dir = Unicode() | |||
def _user_kernel_dir_default(self): | |||
return pjoin(self.ipython_dir, 'kernels') | |||
Thomas Kluyver
|
r16262 | ||
Thomas Kluyver
|
r16382 | kernel_dirs = List( | |
help="List of kernel directories to search. Later ones take priority over earlier." | |||
) | |||
def _kernel_dirs_default(self): | |||
return [ | |||
SYSTEM_KERNEL_DIR, | |||
self.user_kernel_dir, | |||
] | |||
def _make_native_kernel_dir(self): | |||
"""Makes a kernel directory for the native kernel. | |||
The native kernel is the kernel using the same Python runtime as this | |||
process. This will put its informatino in the user kernels directory. | |||
""" | |||
path = pjoin(self.user_kernel_dir, NATIVE_KERNEL_NAME) | |||
os.makedirs(path, mode=0o755) | |||
with open(pjoin(path, 'kernel.json'), 'w') as f: | |||
json.dump({'argv':[NATIVE_KERNEL_NAME, '-c', | |||
'from IPython.kernel.zmq.kernelapp import main; main()', | |||
'-f', '{connection_file}'], | |||
'display_name': 'Python 3' if PY3 else 'Python 2', | |||
'language': 'python', | |||
'codemirror_mode': {'name': 'python', | |||
'version': sys.version_info[0]}, | |||
}, | |||
f, indent=1) | |||
# TODO: Copy icons into directory | |||
return path | |||
def find_kernel_specs(self): | |||
"""Returns a dict mapping kernel names to resource directories.""" | |||
d = {} | |||
for kernel_dir in self.kernel_dirs: | |||
d.update(_list_kernels_in(kernel_dir)) | |||
if NATIVE_KERNEL_NAME not in d: | |||
d[NATIVE_KERNEL_NAME] = self._make_native_kernel_dir() | |||
return d | |||
# TODO: Caching? | |||
def get_kernel_spec(self, kernel_name): | |||
"""Returns a :class:`KernelSpec` instance for the given kernel_name. | |||
Thomas Kluyver
|
r16383 | Raises :exc:`NoSuchKernel` if the given kernel name is not found. | |
Thomas Kluyver
|
r16382 | """ | |
if kernel_name == 'python': | |||
kernel_name = NATIVE_KERNEL_NAME | |||
d = self.find_kernel_specs() | |||
Thomas Kluyver
|
r16383 | try: | |
resource_dir = d[kernel_name.lower()] | |||
except KeyError: | |||
raise NoSuchKernel(kernel_name) | |||
Thomas Kluyver
|
r16382 | return KernelSpec.from_resource_dir(resource_dir) | |
Thomas Kluyver
|
r16261 | ||
Thomas Kluyver
|
r16276 | def find_kernel_specs(): | |
Thomas Kluyver
|
r16262 | """Returns a dict mapping kernel names to resource directories.""" | |
Thomas Kluyver
|
r16382 | return KernelSpecManager().find_kernel_specs() | |
Thomas Kluyver
|
r16260 | ||
def get_kernel_spec(kernel_name): | |||
Thomas Kluyver
|
r16262 | """Returns a :class:`KernelSpec` instance for the given kernel_name. | |
Thomas Kluyver
|
r16260 | ||
Raises KeyError if the given kernel name is not found. | |||
""" | |||
Thomas Kluyver
|
r16382 | return KernelSpecManager().get_kernel_spec(kernel_name) |