Mercurial > hg > Members > aka > jupyter_CbC_kernel
comparison jupyter_c_kernel/kernel.py @ 20:696cc0775abb
Change package name
author | Brendan Rius <brendan@omixy.com> |
---|---|
date | Fri, 29 Apr 2016 09:58:55 +0100 |
parents | c_kernel/kernel.py@101e99452042 |
children | ee3ac764f5f0 |
comparison
equal
deleted
inserted
replaced
19:92e342d23ebc | 20:696cc0775abb |
---|---|
1 from ipykernel.kernelbase import Kernel | |
2 import subprocess | |
3 import tempfile | |
4 import os | |
5 | |
6 | |
7 class CKernel(Kernel): | |
8 implementation = 'jupyter_c_kernel' | |
9 implementation_version = '1.0' | |
10 language = 'c' | |
11 language_version = 'C11' | |
12 language_info = {'name': 'c', | |
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" | |
17 | |
18 def __init__(self, *args, **kwargs): | |
19 super(CKernel, self).__init__(*args, **kwargs) | |
20 self.files = [] | |
21 | |
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 kwargs['mode'] = 'w' | |
32 file = tempfile.NamedTemporaryFile(**kwargs) | |
33 self.files.append(file.name) | |
34 return file | |
35 | |
36 @staticmethod | |
37 def execute_command(cmd): | |
38 """Execute a command and returns the return code, stdout and stderr""" | |
39 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
40 stdout, stderr = p.communicate() | |
41 return p.returncode, stdout.decode('utf-8'), stderr.decode('utf-8') | |
42 | |
43 @staticmethod | |
44 def compile_with_gcc(source_filename, binary_filename): | |
45 args = ['gcc', source_filename, '-std=c11', '-o', binary_filename] | |
46 return CKernel.execute_command(args) | |
47 | |
48 def do_execute(self, code, silent, store_history=True, | |
49 user_expressions=None, allow_stdin=False): | |
50 | |
51 retcode, stdout, stderr = None, '', '' | |
52 with self.new_temp_file(suffix='.c') as source_file: | |
53 source_file.write(code) | |
54 source_file.flush() | |
55 with self.new_temp_file(suffix='.out') as binary_file: | |
56 retcode, stdout, stderr = self.compile_with_gcc(source_file.name, binary_file.name) | |
57 if retcode != 0: | |
58 stderr += "[C kernel] GCC exited with code {}, the executable will not be executed".format(retcode) | |
59 self.log.info("GCC return code: {}".format(retcode)) | |
60 self.log.info("GCC stdout: {}".format(stdout)) | |
61 self.log.info("GCC stderr: {}".format(stderr)) | |
62 | |
63 if retcode == 0: # If the compilation succeeded | |
64 retcode, out, err = CKernel.execute_command([binary_file.name]) | |
65 if retcode != 0: | |
66 stderr += "[C kernel] Executable exited with code {}".format(retcode) | |
67 self.log.info("Executable retcode: {}".format(retcode)) | |
68 self.log.info("Executable stdout: {}".format(out)) | |
69 self.log.info("Executable stderr: {}".format(err)) | |
70 stdout += out | |
71 stderr += err | |
72 else: | |
73 self.log.info('Compilation failed, the program will not be executed') | |
74 | |
75 if not silent: | |
76 stream_content = {'name': 'stderr', 'text': stderr} | |
77 self.send_response(self.iopub_socket, 'stream', stream_content) | |
78 stream_content = {'name': 'stdout', 'text': stdout} | |
79 self.send_response(self.iopub_socket, 'stream', stream_content) | |
80 return {'status': 'ok', 'execution_count': self.execution_count, 'payload': [], 'user_expressions': {}} | |
81 | |
82 def do_shutdown(self, restart): | |
83 """Cleanup the created source code files and executables when shutting down the kernel""" | |
84 self.cleanup_files() |