Mercurial > hg > Members > aka > jupyter_CbC_kernel
comparison c_kernel/kernel.py @ 2:b46b2e5b6c08
Improve error management by separating stdout and stderr
author | Brendan Rius <brendan@omixy.com> |
---|---|
date | Fri, 25 Mar 2016 14:08:26 +0000 |
parents | 50ea00cf5896 |
children | 8ddfdd2a8574 |
comparison
equal
deleted
inserted
replaced
1:5618ac3a53f5 | 2:b46b2e5b6c08 |
---|---|
1 from ipykernel.kernelbase import Kernel | 1 from ipykernel.kernelbase import Kernel |
2 import subprocess | 2 import subprocess |
3 import tempfile | 3 import tempfile |
4 import os | |
4 | 5 |
5 | 6 |
6 class CKernel(Kernel): | 7 class CKernel(Kernel): |
7 implementation = 'c_kernel' | 8 implementation = 'c_kernel' |
8 implementation_version = '1.0' | 9 implementation_version = '1.0' |
9 language = 'c' | 10 language = 'c' |
10 language_version = 'C11' | 11 language_version = 'C11' |
11 language_info = {'name': 'c', 'mimetype': 'text/plain', 'file_extension': 'c'} | 12 language_info = {'name': 'c', |
12 _banner = None | 13 'mimetype': 'text/plain', |
14 'file_extension': 'c'} | |
15 banner = "C kernel.\n" \ | |
16 "Uses gcc, compiles in C11, and creates source code files and executables in temporary folder.\n" | |
13 | 17 |
14 @property | 18 def __init__(self, *args, **kwargs): |
15 def banner(self): | 19 super(CKernel, self).__init__(*args, **kwargs) |
16 if self._banner is None: | 20 self.files = [] |
17 self._banner = subprocess.check_output(['gcc', '-v']).decode('utf-8') | 21 |
18 return self._banner | 22 def cleanup_files(self): |
23 """Remove all the temporary files created by the kernel""" | |
24 for file in self.files: | |
25 os.remove(file) | |
26 | |
27 def new_temp_file(self, **kwargs): | |
28 """Create a new temp file to be deleted when the kernel shuts down""" | |
29 # We don't want the file to be deleted when closed, but only when the kernel stops | |
30 kwargs['delete'] = False | |
31 file = tempfile.NamedTemporaryFile(**kwargs) | |
32 self.files.append(file.name) | |
33 return file | |
34 | |
35 @staticmethod | |
36 def execute_command(cmd): | |
37 """Execute a command and returns the return code, stdout and stderr""" | |
38 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
39 stdout, stderr = p.communicate() | |
40 return p.returncode, stdout, stderr | |
41 | |
42 @staticmethod | |
43 def compile_with_gcc(source_filename, binary_filename): | |
44 args = ['gcc', source_filename, '-std=c11', '-o', binary_filename] | |
45 return CKernel.execute_command(args) | |
19 | 46 |
20 def do_execute(self, code, silent, store_history=True, | 47 def do_execute(self, code, silent, store_history=True, |
21 user_expressions=None, allow_stdin=False): | 48 user_expressions=None, allow_stdin=False): |
22 code = code.strip() | |
23 if not code: | |
24 return {'status': 'ok', | |
25 'execution_count': self.execution_count, | |
26 'payload': [], | |
27 'user_expressions': {}} | |
28 | 49 |
29 output = '### COMPILATION ###\n' | 50 retcode, stdout, stderr = None, '', '' |
30 try: | 51 with self.new_temp_file(suffix='.c') as source_file: |
31 sourcefile = tempfile.NamedTemporaryFile(suffix='.c', delete=False) | 52 source_file.write(code) |
32 sourcefile.write(code) | 53 source_file.flush() |
33 sourcefile.close() | 54 with self.new_temp_file(suffix='.out') as binary_file: |
34 binaryfile = tempfile.NamedTemporaryFile(suffix='.out', delete=False) | 55 retcode, stdout, stderr = self.compile_with_gcc(source_file.name, binary_file.name) |
35 binaryfile.close() | 56 self.log.error(retcode) |
36 output += subprocess.check_output(['gcc', '-std=c11', sourcefile.name, '-o', binaryfile.name], | 57 self.log.error(stdout) |
37 stderr=subprocess.STDOUT).decode('utf-8') | 58 self.log.error(stderr) |
38 except subprocess.CalledProcessError as e: | |
39 print(e) | |
40 return {'status': 'error', 'ename': 'Compilation error', 'evalue': e.output} | |
41 | 59 |
42 output += '\n### EXECUTION ###\n' | 60 retcode, out, err = CKernel.execute_command([binary_file.name]) |
43 try: | 61 stdout += out |
44 output += subprocess.check_output([binaryfile.name], stderr=subprocess.STDOUT).decode('utf-8') | 62 stderr += err |
45 except subprocess.CalledProcessError as e: | 63 self.log.error(retcode) |
46 output += e.output | 64 self.log.error(out) |
65 self.log.error(err) | |
66 | |
47 if not silent: | 67 if not silent: |
48 stream_content = {'name': 'stdout', 'text': output} | 68 stream_content = {'name': 'stderr', 'text': stderr} |
49 self.send_response(self.iopub_socket, 'stream', stream_content) | 69 self.send_response(self.iopub_socket, 'stream', stream_content) |
70 stream_content = {'name': 'stdout', 'text': stdout} | |
71 self.send_response(self.iopub_socket, 'stream', stream_content) | |
72 return {'status': 'ok', 'execution_count': self.execution_count, 'payload': [], 'user_expressions': {}} |