Skip to content

Commit e6b13c4

Browse files
committed
Improve error messages and fail if conda/virtualenv paths don't exist
1 parent 253c927 commit e6b13c4

File tree

2 files changed

+67
-32
lines changed

2 files changed

+67
-32
lines changed

envkernel.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import subprocess
1414
import sys
1515
import tempfile
16+
import textwrap
1617

1718
LOG = logging.getLogger('envkernel')
1819
LOG.setLevel(logging.INFO)
@@ -242,11 +243,12 @@ def install_kernel(self, kernel, name, user=False, replace=None, prefix=None, lo
242243
user=user, replace=replace, prefix=prefix)
243244

244245
LOG.info("")
246+
LOG.info(" Kernel command: %s", kernel['argv'])
245247
try:
246-
LOG.info(" Kernel saved to {}".format(jupyter_client.kernelspec.KernelSpecManager().get_kernel_spec(name).resource_dir))
248+
LOG.info(" Success: Kernel saved to {}".format(jupyter_client.kernelspec.KernelSpecManager().get_kernel_spec(name).resource_dir))
247249
except jupyter_client.kernelspec.NoSuchKernel:
248250
LOG.info(" Note: Kernel not detected with current search path.")
249-
LOG.info(" Command line: %s", kernel['argv'])
251+
#LOG.info(" Kernel file:\n%s", textwrap.indent(json.dumps(kernel, sort_keys=True, indent=1), ' '))
250252

251253
def run(self):
252254
"""Hook that gets run before kernel invoked"""
@@ -322,22 +324,48 @@ def setup(self):
322324
args, unknown_args = parser.parse_known_args(self.argv)
323325

324326
kernel = self.get_kernel()
327+
path = args.path
328+
path = os.path.abspath(path)
325329
kernel['argv'] = [
326330
os.path.realpath(sys.argv[0]),
327331
self.__class__.__name__, 'run',
328332
*unknown_args,
329-
args.path,
333+
path,
330334
'--',
331335
*kernel['argv'],
332336
]
333337
if 'display_name' not in kernel:
334338
kernel['display_name'] = "{} ({}, {})".format(
335339
os.path.basename(args.path.strip('/')),
336340
self.__class__.__name__,
337-
args.path)
341+
path)
342+
if args.path != 'TESTTARGET': # un-expanded
343+
if not os.path.exists(path):
344+
print(self.notfound_message%(self.__class__.__name__, path))
345+
LOG.critical("ERROR: %s does not exist: %s", self.__class__.__name__, path)
346+
sys.exit(1)
347+
if not os.path.exists(pjoin(path, 'bin')):
348+
print(self.notfound_message%(self.__class__.__name__, path+'/bin'))
349+
LOG.critical("ERROR: %s bin does not exist: %s/bin", self.__class__.__name__, path)
350+
sys.exit(1)
338351
self.install_kernel(kernel, name=self.name, user=self.user,
339352
replace=self.replace, prefix=self.prefix)
340353

354+
notfound_message = """\
355+
ERROR: %s path does not exist: %s
356+
357+
You need to give a path to the environment, not just the name. (A
358+
relative path gets expanded to an absolute path.)
359+
360+
For conda, you can get this from:
361+
conda env list
362+
363+
If it's a conda environment and it is activated, you can use
364+
$CONDA_PREFIX like such:
365+
envkernel conda [other arguments] $CONDA_PREFIX
366+
"""
367+
368+
341369
def run(self):
342370
"""load modules and run:
343371
@@ -385,6 +413,12 @@ def _run(self, args, rest):
385413
os.environ['PS1'] = "(venv3) " + os.environ['PS1']
386414

387415
self.execvp(rest[0], rest)
416+
notfound_message = """\
417+
ERROR: %s path does not exist: %s
418+
419+
You need to give a path to the environment, not just the name. A
420+
relative path gets expanded to an absolute path.
421+
"""
388422

389423

390424

@@ -533,12 +567,13 @@ def setup(self):
533567
LOG.debug('setup: remaining args: %s', unknown_args)
534568

535569
kernel = self.get_kernel()
570+
image = os.path.abspath(args.image)
536571
kernel['argv'] = [
537572
os.path.realpath(sys.argv[0]),
538573
'singularity', 'run',
539574
'--connection-file', '{connection_file}',
540575
#*[ '--mount={}'.format(x) for x in args.mount],
541-
args.image,
576+
image,
542577
*unknown_args,
543578
'--',
544579
*kernel['argv'],

test_envkernel.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -94,21 +94,21 @@ def is_sublist(list_, sublist):
9494

9595
@all_modes()
9696
def test_basic(d, mode):
97-
kern = install(d, "%s MOD1"%mode)
97+
kern = install(d, "%s TESTTARGET"%mode)
9898
#assert kern['argv'][0] == 'envkernel' # defined above
9999
assert kern['ek'][1:3] == [mode, 'run']
100100

101101
@all_modes()
102102
def test_display_name(d, mode):
103-
kern = install(d, "%s --display-name=AAA MOD1"%mode)
103+
kern = install(d, "%s --display-name=AAA TESTTARGET"%mode)
104104
assert kern['kernel']['display_name'] == 'AAA'
105105

106106
@all_modes(['conda'])
107107
def test_template(d, mode):
108108
os.environ['JUPYTER_PATH'] = pjoin(d, 'share/jupyter')
109109
subprocess.call("python -m ipykernel install --name=aaa-ipy --display-name=BBB --prefix=%s"%d, shell=True)
110110
#os.environ['ENVKERNEL_TESTPATH'] = os.path.join(d, 'share/jupyter/kernels')
111-
kern = install(d, "%s --kernel-template aaa-ipy MOD1"%mode)
111+
kern = install(d, "%s --kernel-template aaa-ipy TESTTARGET"%mode)
112112
assert kern['kernel']['display_name'] == 'BBB'
113113

114114
@all_modes(['conda'])
@@ -118,7 +118,7 @@ def test_template_copyfiles(d, mode):
118118
f = open(pjoin(d, 'share/jupyter/kernels/', 'aaa-ipy', 'A.txt'), 'w')
119119
f.write('LMNO')
120120
f.close()
121-
kern = install(d, "%s --kernel-template aaa-ipy MOD1"%mode)
121+
kern = install(d, "%s --kernel-template aaa-ipy TESTTARGET"%mode)
122122
assert os.path.exists(pjoin(kern['dir'], 'A.txt'))
123123
assert open(pjoin(kern['dir'], 'A.txt')).read() == 'LMNO'
124124

@@ -127,10 +127,10 @@ def test_template_make_path_relative(d, mode):
127127
os.environ['JUPYTER_PATH'] = pjoin(d, 'share/jupyter')
128128
subprocess.call("python -m ipykernel install --name=aaa-ipy --display-name=BBB --prefix=%s"%d, shell=True)
129129
# First test it without, ensure it has the full path
130-
kern = install(d, "%s --kernel-template aaa-ipy MOD1"%mode)
130+
kern = install(d, "%s --kernel-template aaa-ipy TESTTARGET"%mode)
131131
assert kern['k'][0] != 'python' # This is an absolete path
132132
# Now test it with --kernel-make-path-relative and ensure it's relative
133-
kern = install(d, "%s --kernel-template aaa-ipy --kernel-make-path-relative MOD1"%mode)
133+
kern = install(d, "%s --kernel-template aaa-ipy --kernel-make-path-relative TESTTARGET"%mode)
134134
assert kern['k'][0] == 'python' # This is an absolete path
135135

136136
def test_help():
@@ -148,7 +148,7 @@ def test_logging(d, caplog):
148148
Run first without -v and make sure some stuff isn't printed.
149149
Then, run with -v and ensure that the argument processing is output.
150150
"""
151-
cmd = "python3 -m envkernel lmod --name=ABC --display-name=AAA MOD1 --prefix=%s"%d
151+
cmd = "python3 -m envkernel lmod --name=ABC --display-name=AAA LMOD --prefix=%s"%d
152152
print(d)
153153
env = os.environ.copy()
154154
env['JUPYTER_PATH'] = pjoin(d, 'share/jupyter')
@@ -160,7 +160,7 @@ def test_logging(d, caplog):
160160
print(stdout)
161161
assert 'Namespace' not in stdout
162162
assert 'kernel-specific' not in stdout
163-
assert 'Command line:' in stdout
163+
assert 'Kernel command:' in stdout
164164
# Now test verbose (should have some debugging info)
165165
p = subprocess.Popen(cmd+' -v', env=env,
166166
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
@@ -169,37 +169,37 @@ def test_logging(d, caplog):
169169
#print(stdout)
170170
assert 'Namespace' in stdout
171171
assert 'kernel-specific' in stdout
172-
assert 'Command line:' in stdout
172+
assert 'Kernel command:' in stdout
173173

174174
def test_umask(d):
175175
orig_umask = os.umask(0)
176176
# Test multiple umasks, and kerneldir + kernel.json
177177
for umask in [0, 0o022]:
178178
os.umask(umask)
179-
kern = install(d, "lmod MOD1")
179+
kern = install(d, "lmod TESTTARGET")
180180
assert os.stat(kern['dir']).st_mode & 0o777 == 0o777&(~umask)
181181
assert os.stat(pjoin(kern['dir'], 'kernel.json')).st_mode & 0o777 == 0o666&(~umask)
182182
os.umask(orig_umask)
183183

184184

185185
@all_modes()
186186
def test_set_python(d, mode):
187-
kern = install(d, "%s --python=AAA MOD1"%mode)
187+
kern = install(d, "%s --python=AAA TESTTARGET"%mode)
188188
assert kern['k'][0] == 'AAA'
189189

190190
@all_modes()
191191
def test_set_kernel_cmd(d, mode):
192-
kern = install(d, "%s --kernel-cmd='a b c d' MOD1"%mode)
192+
kern = install(d, "%s --kernel-cmd='a b c d' TESTTARGET"%mode)
193193
assert kern['k'] == ['a', 'b', 'c', 'd']
194194

195195
@all_modes()
196196
def test_language(d, mode):
197-
kern = install(d, "%s --language=AAA MOD1"%mode)
197+
kern = install(d, "%s --language=AAA TESTTARGET"%mode)
198198
assert kern['kernel']['language'] == 'AAA'
199199

200200
@all_modes()
201201
def test_env(d, mode):
202-
kern = install(d, "%s --env=AAA=BBB --env=CCC=DDD MOD1"%mode)
202+
kern = install(d, "%s --env=AAA=BBB --env=CCC=DDD TESTTARGET"%mode)
203203
assert kern['kernel']['env']['AAA'] == 'BBB'
204204
assert kern['kernel']['env']['CCC'] == 'DDD'
205205

@@ -234,28 +234,28 @@ def test_exec(_file, _args):
234234
@all_modes()
235235
def test_default_language(d, mode):
236236
# default language is ipykernel
237-
kern = install(d, "%s MOD1"%mode)
237+
kern = install(d, "%s TESTTARGET"%mode)
238238
assert kern['kernel']['language'] == 'python'
239239
assert kern['k'][0] == 'python'
240240
assert kern['k'][1:4] == ['-m', 'ipykernel_launcher', '-f']
241241

242242
@all_modes()
243243
def test_ipykernel(d, mode):
244-
kern = install(d, "%s --kernel=ipykernel MOD1"%mode)
244+
kern = install(d, "%s --kernel=ipykernel TESTTARGET"%mode)
245245
assert kern['kernel']['language'] == 'python'
246246
assert kern['k'][0] == 'python'
247247
assert kern['k'][1:4] == ['-m', 'ipykernel_launcher', '-f']
248248

249249
@all_modes()
250250
def test_ir(d, mode):
251-
kern = install(d, "%s --kernel=ir MOD1"%mode)
251+
kern = install(d, "%s --kernel=ir TESTTARGET"%mode)
252252
assert kern['kernel']['language'] == 'R'
253253
assert kern['k'][0] == 'R'
254254
assert kern['k'][1:5] == ['--slave', '-e', 'IRkernel::main()', '--args']
255255

256256
@all_modes()
257257
def test_imatlab(d, mode):
258-
kern = install(d, "%s --kernel=imatlab MOD1"%mode)
258+
kern = install(d, "%s --kernel=imatlab TESTTARGET"%mode)
259259
assert kern['kernel']['language'] == 'matlab'
260260
assert kern['k'][0].endswith('python')
261261
assert kern['k'][1:4] == ['-m', 'imatlab', '-f']
@@ -277,29 +277,29 @@ def test_lmod_purge(d):
277277
assert kern['ek'][-1] == 'MOD3'
278278

279279
def test_conda(d):
280-
kern = install(d, "conda /PATH/BBB")
280+
kern = install(d, "conda TESTTARGET")
281281
#assert kern['argv'][0] == 'envkernel' # defined above
282282
assert kern['ek'][1:3] == ['conda', 'run']
283-
assert kern['ek'][-1] == '/PATH/BBB'
283+
assert kern['ek'][-1].endswith('TESTTARGET')
284284

285285
def test_virtualenv(d):
286-
kern = install(d, "virtualenv /PATH/CCC")
286+
kern = install(d, "virtualenv TESTTARGET")
287287
#assert kern['argv'][0] == 'envkernel' # defined above
288288
assert kern['ek'][1:3] == ['virtualenv', 'run']
289-
assert kern['ek'][-1] == '/PATH/CCC'
289+
assert kern['ek'][-1].endswith('TESTTARGET')
290290

291291
def test_docker(d):
292-
kern = install(d, "docker --some-arg=AAA IMAGE1")
292+
kern = install(d, "docker --some-arg=AAA TESTIMAGE")
293293
#assert kern['argv'][0] == 'envkernel' # defined above
294294
assert kern['ek'][1:3] == ['docker', 'run']
295-
assert kern['ek'][-2] == 'IMAGE1'
295+
assert kern['ek'][-2] == 'TESTIMAGE'
296296
assert '--some-arg=AAA' in kern['ek']
297297

298298
def test_singularity(d):
299-
kern = install(d, "singularity --some-arg=AAA /PATH/TO/IMAGE2")
299+
kern = install(d, "singularity --some-arg=AAA /PATH/TO/TESTIMAGE2")
300300
#assert kern['argv'][0] == 'envkernel' # defined above
301301
assert kern['ek'][1:3] == ['singularity', 'run']
302-
assert kern['ek'][-2] == '/PATH/TO/IMAGE2'
302+
assert kern['ek'][-2] == '/PATH/TO/TESTIMAGE2'
303303
assert '--some-arg=AAA' in kern['ek']
304304

305305

@@ -369,7 +369,7 @@ def test_run_singularity(d):
369369
def test_exec(_file, argv):
370370
assert argv[0] == 'singularity'
371371
assert '--some-arg=AAA' in argv
372-
assert 'IMAGE' in argv
372+
assert os.path.join(os.getcwd(), 'IMAGE') in argv
373373
kern = install(d, "singularity --some-arg=AAA IMAGE")
374374
run(d, kern, test_exec)
375375

0 commit comments

Comments
 (0)