Update webpython.py
This commit is contained in:
@ -1,178 +1 @@
|
||||
#!/usr/bin/python3
|
||||
# Main interpreter entry for webpython
|
||||
import io, select, sys, os, threading, code
|
||||
import pickle, struct, builtins, json
|
||||
#, ressource
|
||||
from queue import Queue
|
||||
from argparse import ArgumentParser
|
||||
|
||||
# hard limit to 64M
|
||||
#try:
|
||||
# resource.setrlimit(resource.RLIMIT_AS, (1<<26, 1<<26))
|
||||
#except ValueError:
|
||||
# tried to raise it
|
||||
# pass
|
||||
|
||||
# output limit 16MiB
|
||||
output_capacity = 16*1024*1024
|
||||
# adapted from IDLE (PyShell.py)
|
||||
class PseudoFile(io.TextIOBase):
|
||||
|
||||
def __init__(self, shell, name):
|
||||
self.shell = shell
|
||||
self._name = name
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return "UTF-8"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return '<%s>' % self._name
|
||||
|
||||
def isatty(self):
|
||||
return True
|
||||
|
||||
class PseudoInputFile(PseudoFile):
|
||||
|
||||
def __init__(self, shell, name):
|
||||
PseudoFile.__init__(self, shell, name)
|
||||
self._line_buffer = ''
|
||||
|
||||
def readable(self):
|
||||
return True
|
||||
|
||||
def read(self, size=-1):
|
||||
if self.closed:
|
||||
raise ValueError("read from closed file")
|
||||
if size is None:
|
||||
size = -1
|
||||
elif not isinstance(size, int):
|
||||
raise TypeError('must be int, not ' + type(size).__name__)
|
||||
result = self._line_buffer
|
||||
self._line_buffer = ''
|
||||
if size < 0:
|
||||
while True:
|
||||
line = self.shell.readline()
|
||||
if not line: break
|
||||
result += line
|
||||
else:
|
||||
while len(result) < size:
|
||||
line = self.shell.readline()
|
||||
if not line: break
|
||||
result += line
|
||||
self._line_buffer = result[size:]
|
||||
result = result[:size]
|
||||
return result
|
||||
|
||||
def readline(self, size=-1):
|
||||
if self.closed:
|
||||
raise ValueError("read from closed file")
|
||||
if size is None:
|
||||
size = -1
|
||||
elif not isinstance(size, int):
|
||||
raise TypeError('must be int, not ' + type(size).__name__)
|
||||
line = self._line_buffer or self.shell.readline()
|
||||
if size < 0:
|
||||
size = len(line)
|
||||
self._line_buffer = line[size:]
|
||||
return line[:size]
|
||||
|
||||
def close(self):
|
||||
self.shell.close()
|
||||
|
||||
class PseudoOutputFile(PseudoFile):
|
||||
|
||||
def writable(self):
|
||||
return True
|
||||
|
||||
def write(self, s):
|
||||
if self.closed:
|
||||
raise ValueError("write to closed file")
|
||||
if not isinstance(s, str):
|
||||
raise TypeError('must be str, not ' + type(s).__name__)
|
||||
return self.shell.write(s, self._name)
|
||||
|
||||
# RPC proxy
|
||||
orig_stdin = sys.stdin
|
||||
orig_stdout = sys.stdout
|
||||
orig_stderr = sys.stderr
|
||||
class Shell:
|
||||
def __init__(self):
|
||||
self.stdin = io.FileIO(0)
|
||||
self.buf = b''
|
||||
self.canvas = []
|
||||
self.messages = []
|
||||
self.capacity = output_capacity
|
||||
|
||||
# PseudoFile interaction
|
||||
#def readline(self):
|
||||
# self.sendpickle({'cmd':'readline',
|
||||
# 'stream':'stdin',
|
||||
# })
|
||||
# return self.inputq.get()
|
||||
|
||||
def write(self, data, name):
|
||||
self.sendpickle({'cmd':'write',
|
||||
'stream':name,
|
||||
'data':data
|
||||
})
|
||||
|
||||
def input(self, prompt=''):
|
||||
self.sendpickle({'cmd':'input',
|
||||
'stream':'stdin',
|
||||
'data':prompt})
|
||||
result = self.receivemsg()
|
||||
return result['data']
|
||||
|
||||
# internal
|
||||
def sendpickle(self, data):
|
||||
data = json.dumps(data) + "\n\r"
|
||||
self.capacity -= len(data)
|
||||
if self.capacity < 0:
|
||||
data = json.dumps({'cmd':'stop',
|
||||
'timedout':True}, 2)
|
||||
orig_stdout.write(data)
|
||||
raise SystemExit
|
||||
orig_stdout.write(data)
|
||||
|
||||
def receivepickle(self):
|
||||
msg = json.loads(orig_stdin.readline())
|
||||
if msg['cmd'] == 'canvasevent':
|
||||
self.canvas.append(msg)
|
||||
else:
|
||||
self.messages.append(msg)
|
||||
|
||||
def receivemsg(self):
|
||||
while not self.messages:
|
||||
self.receivepickle()
|
||||
return self.messages.pop()
|
||||
|
||||
def receivecanvas(self):
|
||||
while not self.canvas:
|
||||
self.receivepickle()
|
||||
return self.canvas.pop(0)
|
||||
|
||||
# Hide 0/1 from sys
|
||||
shell = Shell()
|
||||
sys.__stdin__ = sys.stdin = PseudoInputFile(shell, 'stdin')
|
||||
sys.__stdout__ = sys.stdout = PseudoOutputFile(shell, 'stdout')
|
||||
#sys.__stderr__ = sys.stderr = PseudoOutputFile(shell, 'stderr')
|
||||
builtins.input = shell.input
|
||||
|
||||
#iothread = threading.Thread(target=shell.run)
|
||||
#iothread.start()
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser(description='A python interpreter that generates json commands based on the standard I/O streams.')
|
||||
parser.add_argument('-f', '--filename', type=str, required=True, default='exercise.py', help='Python file to be interpreted.')
|
||||
args = parser.parse_args()
|
||||
|
||||
filepath = os.path.join("/", "workspace", args.filename)
|
||||
with open(filepath, "r", encoding='utf-8') as f:
|
||||
script = f.read()
|
||||
c = compile(script, args.filename, 'exec')
|
||||
exec(c, {})
|
||||
|
||||
# work-around for docker not terminating properly
|
||||
shell.sendpickle({'cmd':'exit'})
|
||||
# moved to dockerfiles/ubuntu-python/webpython.py
|
||||
|
Reference in New Issue
Block a user