Mercurial > hg > Members > aka > jupyter_CbC_kernel
annotate jupyter_c_kernel/kernel.py @ 33:f842dabb75d7
wip
author | Brendan Rius <brendan@omixy.com> |
---|---|
date | Sat, 30 Apr 2016 21:45:41 +0100 |
parents | ee3ac764f5f0 |
children | b5bc8483ac3e |
rev | line source |
---|---|
33 | 1 from threading import Thread |
2 | |
3 import time | |
0 | 4 from ipykernel.kernelbase import Kernel |
5 import subprocess | |
6 import tempfile | |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
7 import os |
33 | 8 from Queue import Queue, Empty |
0 | 9 |
10 | |
11 class CKernel(Kernel): | |
20 | 12 implementation = 'jupyter_c_kernel' |
0 | 13 implementation_version = '1.0' |
14 language = 'c' | |
15 language_version = 'C11' | |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
16 language_info = {'name': 'c', |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
17 'mimetype': 'text/plain', |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
18 'file_extension': 'c'} |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
19 banner = "C kernel.\n" \ |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
20 "Uses gcc, compiles in C11, and creates source code files and executables in temporary folder.\n" |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
21 |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
22 def __init__(self, *args, **kwargs): |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
23 super(CKernel, self).__init__(*args, **kwargs) |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
24 self.files = [] |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
25 |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
26 def cleanup_files(self): |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
27 """Remove all the temporary files created by the kernel""" |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
28 for file in self.files: |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
29 os.remove(file) |
0 | 30 |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
31 def new_temp_file(self, **kwargs): |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
32 """Create a new temp file to be deleted when the kernel shuts down""" |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
33 # We don't want the file to be deleted when closed, but only when the kernel stops |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
34 kwargs['delete'] = False |
9 | 35 kwargs['mode'] = 'w' |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
36 file = tempfile.NamedTemporaryFile(**kwargs) |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
37 self.files.append(file.name) |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
38 return file |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
39 |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
40 @staticmethod |
33 | 41 def launch_process(cmd): |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
42 """Execute a command and returns the return code, stdout and stderr""" |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
43 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
33 | 44 |
45 stdout_queue = Queue() | |
46 stdout_thread = Thread(target=CKernel.enqueue_output, args=(p.stdout, stdout_queue)) | |
47 stdout_thread.daemon = True | |
48 stdout_thread.start() | |
49 | |
50 stderr_queue = Queue() | |
51 stderr_thread = Thread(target=CKernel.enqueue_output, args=(p.stderr, stderr_queue)) | |
52 stderr_thread.daemon = True | |
53 stderr_thread.start() | |
54 | |
55 return p, stdout_queue, stderr_queue | |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
56 |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
57 @staticmethod |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
58 def compile_with_gcc(source_filename, binary_filename): |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
59 args = ['gcc', source_filename, '-std=c11', '-o', binary_filename] |
33 | 60 return CKernel.launch_process(args) |
61 | |
62 @staticmethod | |
63 def enqueue_output(out, queue): | |
64 for line in iter(out.readline, b''): | |
65 queue.put(line) | |
66 out.close() | |
0 | 67 |
68 def do_execute(self, code, silent, store_history=True, | |
69 user_expressions=None, allow_stdin=False): | |
33 | 70 a = raw_input() |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
71 with self.new_temp_file(suffix='.c') as source_file: |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
72 source_file.write(code) |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
73 source_file.flush() |
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
74 with self.new_temp_file(suffix='.out') as binary_file: |
33 | 75 p, stdout_queue, stderr_queue = self.compile_with_gcc(source_file.name, binary_file.name) |
76 while p.poll() is None: | |
77 self.log.error("Waiting for compilation to end") | |
78 try: | |
79 stdout = stdout_queue.get_nowait() | |
80 except Empty: | |
81 self.log.error("stdout empty") | |
82 else: | |
83 self.log.error("stdout contains: {}".format(stdout)) | |
84 self.send_response(self.iopub_socket, 'stream', {'name': 'stdout', 'text': stdout}) | |
85 try: | |
86 stderr = stderr_queue.get_nowait() | |
87 except Empty: | |
88 self.log.error("stderr empty") | |
89 else: | |
90 self.log.error("stderr contains: {}".format(stderr)) | |
91 self.send_response(self.iopub_socket, 'stream', {'name': 'stderr', 'text': stderr}) | |
0 | 92 |
33 | 93 if p.returncode != 0: # Compilation failed |
94 stream_content = {'name': 'stderr', | |
95 'text': "[C kernel] GCC exited with code {}, the executable will not be executed".format( | |
96 p.returncode)} | |
97 self.send_response(self.iopub_socket, 'stream', stream_content) | |
98 return {'status': 'ok', 'execution_count': self.execution_count, 'payload': [], | |
99 'user_expressions': {}} | |
0 | 100 |
33 | 101 p, stdout_queue, stderr_queue = CKernel.launch_process([binary_file.name]) |
102 while p.poll() is None: | |
103 self.log.error("Waiting for execution to end") | |
104 try: | |
105 stdout = stdout_queue.get_nowait() | |
106 except Empty: | |
107 self.log.error("stdout empty") | |
108 else: | |
109 self.log.error("stdout contains: {}".format(stdout)) | |
110 self.send_response(self.iopub_socket, 'stream', {'name': 'stdout', 'text': stdout}) | |
111 try: | |
112 stderr = stderr_queue.get_nowait() | |
113 except Empty: | |
114 self.log.error("stderr empty") | |
115 else: | |
116 self.log.error("stderr contains: {}".format(stderr)) | |
117 self.send_response(self.iopub_socket, 'stream', {'name': 'stderr', 'text': stderr}) | |
118 | |
119 if p.returncode != 0: | |
120 stderr_queue += "[C kernel] Executable exited with code {}".format(p.returncode) | |
2
b46b2e5b6c08
Improve error management by separating stdout and stderr
Brendan Rius <brendan@omixy.com>
parents:
0
diff
changeset
|
121 return {'status': 'ok', 'execution_count': self.execution_count, 'payload': [], 'user_expressions': {}} |
7
aa54c85303b6
Remove temporary files when shutting down the kernel
Brendan Rius <brendan@omixy.com>
parents:
4
diff
changeset
|
122 |
aa54c85303b6
Remove temporary files when shutting down the kernel
Brendan Rius <brendan@omixy.com>
parents:
4
diff
changeset
|
123 def do_shutdown(self, restart): |
aa54c85303b6
Remove temporary files when shutting down the kernel
Brendan Rius <brendan@omixy.com>
parents:
4
diff
changeset
|
124 """Cleanup the created source code files and executables when shutting down the kernel""" |
aa54c85303b6
Remove temporary files when shutting down the kernel
Brendan Rius <brendan@omixy.com>
parents:
4
diff
changeset
|
125 self.cleanup_files() |