-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathswiftkernel.py
111 lines (92 loc) · 4.04 KB
/
swiftkernel.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# coding: utf-8
# a swift kernel for Jupyter
# copyright Tim Nugent, made available under the MIT License
# see the repository https://github.com/McJones/jupyter-swift-kernel/ for full details
import subprocess, os, shutil, tempfile, re
from ipykernel.kernelbase import Kernel
class SwiftKernel(Kernel):
# Jupiter stuff
implementation = 'Swift'
implementation_version = '1.1.1'
language = 'swift'
language_version = '3.0.2'
language_info = {'mimetype': 'text/plain', 'file_extension': 'swift', 'name': 'swift'}
banner = "Swift kernel"
# my stuff
output = ""
swiftDirectory = tempfile.mkdtemp()
def do_execute(self, code, silent, store_history=True, user_expressions=None, allow_stdin=False):
errorCode, dump = self.runCode(code)
if errorCode == 0:
if not silent:
stream = {'name':'stdout', 'text':dump}
self.send_response(self.iopub_socket, 'stream', stream)
return {
'status':'ok',
'execution_count':self.execution_count,
'payload':[],
'user_expressions':{}
}
else:
# every example does it like this but this just feels weird
# why does the execution_count increment?!
if not silent:
stream = {
'status' : 'error',
'ename': 'ERROR',
'evalue': 'error',
'traceback': dump
}
self.send_response(self.iopub_socket, 'error', stream)
return {
'status':'error',
'execution_count':self.execution_count,
'ename': 'ERROR',
'evalue': 'error',
'traceback': dump
}
def do_shutdown(self, restart):
# delete the temporary swift file(s) and directory
shutil.rmtree(self.swiftDirectory)
# appends the new text to the swift file
# runs the swift file
# capture all output
# returns the result
def runCode(self, command):
swiftFileLocation = os.path.join(self.swiftDirectory, 'scratch.swift')
canonicalFile = os.path.join(self.swiftDirectory, 'canonical.swift')
# now copy everything from canonical into the scratch
if os.path.isfile(canonicalFile):
shutil.copyfile(canonicalFile, swiftFileLocation)
with open(swiftFileLocation, 'a') as swiftFile:
unicodeCommand = (command + "\n").encode("UTF-8")
swiftFile.write(unicodeCommand)
errorOutput = []
# because who needs warnings, right?!
# queue up mental picture of Holtzman while reading the above comment please
cmd = 'swift -suppress-warnings {0}'.format(swiftFileLocation)
swift = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# handle all valid output
newOutput = swift.stdout.read()
# handle any errors
for line in swift.stderr.readlines():
# to clean up the default error message swift returns
line = re.sub('^.*error: ', '', line)
errorOutput.append(line.rstrip("\n\r"))
retval = swift.wait()
# ran without error
if retval == 0:
# putting the valid code back into the canonical file
shutil.copyfile(swiftFileLocation, canonicalFile)
# returning the result
diff = newOutput[len(self.output):]
self.output = newOutput
return 0, diff
else:
# dumping the dodgy file
os.remove(swiftFileLocation)
# returning the error(s)
return 1, errorOutput
if __name__ == '__main__':
from ipykernel.kernelapp import IPKernelApp
IPKernelApp.launch_instance(kernel_class=SwiftKernel)