57
58
return repr(self.value)
60
class TruncateStringIO(StringIO.StringIO):
61
""" A class that wraps around StringIO and truncates the buffer when the
62
contents are read (except for when using getvalue).
64
def __init__(self, buffer=None):
65
StringIO.StringIO.__init__(self, buffer)
68
""" Read at most size bytes from the file (less if the read hits EOF
69
before obtaining size bytes).
71
If the size argument is negative or omitted, read all data until EOF is
72
reached. The bytes are returned as a string object. An empty string is
73
returned when EOF is encountered immediately.
79
res = StringIO.StringIO.read(self, n)
83
def readline(self, length=None):
84
""" Read one entire line from the file.
86
A trailing newline character is kept in the string (but may be absent
87
when a file ends with an incomplete line). If the size argument is
88
present and non-negative, it is a maximum byte count (including the
89
trailing newline) and an incomplete line may be returned.
91
An empty string is returned only when EOF is encountered immediately.
93
Note: Unlike stdio's fgets(), the returned string contains null
94
characters ('\0') if they occurred in the input.
96
Removes the line from the buffer.
100
res = StringIO.StringIO.readline(self, length)
101
rest = StringIO.StringIO.read(self)
106
def readlines(self, sizehint=0):
107
""" Read until EOF using readline() and return a list containing the
110
If the optional sizehint argument is present, instead of reading up to
111
EOF, whole lines totalling approximately sizehint bytes (or more to
112
accommodate a final whole line).
114
Truncates the buffer.
118
res = StringIO.StringIO.readlines(self, length)
59
122
class Console(object):
60
123
""" Provides a nice python interface to the console
67
130
self.jail_path = jail_path
68
131
self.working_dir = working_dir
134
self.stdin = TruncateStringIO()
135
self.stdout = TruncateStringIO()
136
self.stderr = TruncateStringIO()
138
# Fire up the console
71
141
def restart(self):
142
# Empty all the buffers
143
self.stdin.truncate(0)
144
self.stdout.truncate(0)
145
self.stderr.truncate(0)
72
147
# TODO: Check if we are already running a console. If we are shut it
139
214
raise ConsoleError(
140
215
"Could not understand the python console response")
142
# Look for user errors
219
def __handle_chat(self, cmd, args):
220
""" A wrapper around self.__chat that handles all the messy responses
221
of chat for higher level interfaces such as inspect
224
response = self.__chat(cmd, args)
226
# Process I/O requests
227
while 'output' in response or 'input' in response:
228
if 'output' in response:
229
self.stdout.write(response['output'])
230
response = self.chat()
231
elif 'input' in response:
232
response = self.chat(self.stdin.readline())
234
# Process user exceptions
143
235
if 'exc' in response:
144
236
raise ConsoleException(response['exc'])
148
240
def chat(self, code=''):
160
252
raise ConsoleException("Bad response from console: %s"%str(block))
162
def flush(self, globs=None):
163
""" Resets the consoles globals() to the default and optionally augment
164
them with a dictionary simple globals. (Must be able to be pickled)
254
def globals(self, globs=None):
255
""" Returns a dictionary of the console's globals and optionally set
166
258
# Pickle the globals
168
260
if globs is not None:
170
263
pickled_globs[g] = cPickle.dumps(globs[g])
172
flush = self.__chat('flush', pickled_globs)
173
if 'response' in flush and flush['response'] == 'okay':
176
raise ConsoleError("Bad response from console: %s"%str(flush))
265
globals = self.__handle_chat('globals', pickled_globs)
267
# Unpickle the globals
268
for g in globals['globals']:
269
globals['globals'][g] = cPickle.loads(globals['globals'][g])
271
return globals['globals']
178
274
def call(self, function, *args, **kwargs):
179
275
""" Calls a function in the python console. Can take in a list of
184
280
'function': function,
186
282
'kwargs': kwargs}
187
call = self.__chat('call', call_args)
283
call = self.__handle_chat('call', call_args)
189
285
# Unpickle any exceptions
190
286
if 'exception' in call:
191
287
call['exception']['except'] = \
196
def inspect(self, code=''):
197
""" Runs a block of code in the python console returning a dictionary
198
summary of the evaluation. Currently this includes the values of
199
stdout, stderr, simple global varibles.
200
If an exception was thrown then this dictionary also includes a
201
exception dictionary containg a traceback string and the exception
292
def execute(self, code=''):
293
""" Runs a block of code in the python console.
294
If an exception was thrown then returns an exception object.
204
inspection = self.__chat('inspect', code)
206
# Unpickle the globals
207
for g in inspection['globals']:
208
inspection['globals'][g] = cPickle.loads(inspection['globals'][g])
296
execute = self.__handle_chat('execute', code)
210
298
# Unpickle any exceptions
211
if 'exception' in inspection:
212
inspection['exception']['except'] = \
213
cPickle.loads(inspection['exception']['except'])
299
if 'exception' in execute:
300
return cPickle.loads(execute['exception'])
217
305
def set_vars(self, variables):
218
306
""" Takes a dictionary of varibles to add to the console's global
223
311
for v in variables:
224
312
vars[v] = repr(variables[v])
226
set_vars = self.__chat('set_vars', vars)
314
set_vars = self.__handle_chat('set_vars', vars)
228
316
if set_vars.get('response') != 'okay':
229
317
raise ConsoleError("Could not set variables")
232
320
""" Causes the console process to terminate """
233
self.__chat('restart', None)
321
return self.__chat('terminate', None)