6
6
import io
7
7
import json
8
8
import os
9
+ import re
9
10
import shutil
10
11
import warnings
11
12
20
21
21
22
NATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2'
22
23
24
+
23
25
class KernelSpec (HasTraits ):
24
26
argv = List ()
25
27
display_name = Unicode ()
@@ -54,19 +56,43 @@ def to_json(self):
54
56
"""
55
57
return json .dumps (self .to_dict ())
56
58
59
+
60
+ _kernel_name_pat = re .compile (r'^[a-z0-9._\-]+$' , re .IGNORECASE )
61
+
62
+ def _is_valid_kernel_name (name ):
63
+ """Check that a kernel name is valid."""
64
+ # quote is not unicode-safe on Python 2
65
+ return _kernel_name_pat .match (name )
66
+
67
+
68
+ _kernel_name_description = "Kernel names can only contain ASCII letters and numbers and these separators: -._"
69
+
70
+
57
71
def _is_kernel_dir (path ):
58
72
"""Is ``path`` a kernel directory?"""
59
73
return os .path .isdir (path ) and os .path .isfile (pjoin (path , 'kernel.json' ))
60
74
75
+
61
76
def _list_kernels_in (dir ):
62
77
"""Return a mapping of kernel names to resource directories from dir.
63
78
64
79
If dir is None or does not exist, returns an empty dict.
65
80
"""
66
81
if dir is None or not os .path .isdir (dir ):
67
82
return {}
68
- return {f .lower (): pjoin (dir , f ) for f in os .listdir (dir )
69
- if _is_kernel_dir (pjoin (dir , f ))}
83
+ kernels = {}
84
+ for f in os .listdir (dir ):
85
+ path = pjoin (dir , f )
86
+ if not _is_kernel_dir (path ):
87
+ continue
88
+ key = f .lower ()
89
+ if not _is_valid_kernel_name (key ):
90
+ warnings .warn ("Invalid kernelspec directory name (%s): %s" ,
91
+ _kernel_name_description , path , stacklevel = 3 ,
92
+ )
93
+ kernels [key ] = path
94
+ return kernels
95
+
70
96
71
97
class NoSuchKernel (KeyError ):
72
98
def __init__ (self , name ):
@@ -75,6 +101,7 @@ def __init__(self, name):
75
101
def __str__ (self ):
76
102
return "No such kernel named {}" .format (self .name )
77
103
104
+
78
105
class KernelSpecManager (LoggingConfigurable ):
79
106
80
107
kernel_spec_class = Type (KernelSpec , config = True ,
@@ -242,10 +269,12 @@ def install_kernel_spec(self, source_dir, kernel_name=None, user=False,
242
269
if not kernel_name :
243
270
kernel_name = os .path .basename (source_dir )
244
271
kernel_name = kernel_name .lower ()
245
-
272
+ if not _is_valid_kernel_name (kernel_name ):
273
+ raise ValueError ("Invalid kernel name %r. %s" % (kernel_name , _kernel_name_description ))
274
+
246
275
if user and prefix :
247
276
raise ValueError ("Can't specify both user and prefix. Please choose one or the other." )
248
-
277
+
249
278
if replace is not None :
250
279
warnings .warn (
251
280
"replace is ignored. Installing a kernelspec always replaces an existing installation" ,
0 commit comments