~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to lib/common/console.py

  • Committer: dcoles
  • Date: 2008-08-20 08:10:40 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:1034
Console: Refactored the code to support supplying of stdin to the console.  
Renamed and unified a few call in the module - inspect is now execute since 
stdout is written to the console.stdout file-like object rather than being 
returned as part of the call. __chat becomes split into __chat which deals with 
the low level chat protocol issues and __handle_chat which deals with console's 
own protocol.

Updated tutorial service to use these new calls. Still have to fix the 
'add_stdin' function but should be very simple now. (Just write to 
console.stdin)

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import os
28
28
import random
29
29
import socket
 
30
import StringIO
30
31
import uuid
31
32
 
32
33
import cjson
56
57
    def __str__(self):
57
58
        return repr(self.value)
58
59
 
 
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).
 
63
    """
 
64
    def __init__(self, buffer=None):
 
65
        StringIO.StringIO.__init__(self, buffer)
 
66
    
 
67
    def read(self, n=-1):
 
68
        """ Read at most size bytes from the file (less if the read hits EOF 
 
69
        before obtaining size bytes).
 
70
 
 
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.
 
74
 
 
75
        Truncates the buffer.
 
76
        """
 
77
 
 
78
        self.seek(0)
 
79
        res = StringIO.StringIO.read(self, n)
 
80
        self.truncate(0)
 
81
        return res
 
82
 
 
83
    def readline(self, length=None):
 
84
        """ Read one entire line from the file.
 
85
 
 
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.
 
90
 
 
91
        An empty string is returned only when EOF is encountered immediately.
 
92
        
 
93
        Note: Unlike stdio's fgets(), the returned string contains null   
 
94
        characters ('\0') if they occurred in the input.
 
95
 
 
96
        Removes the line from the buffer.
 
97
        """
 
98
 
 
99
        self.seek(0)
 
100
        res = StringIO.StringIO.readline(self, length)
 
101
        rest = StringIO.StringIO.read(self)
 
102
        self.truncate(0)
 
103
        self.write(rest)
 
104
        return res
 
105
 
 
106
    def readlines(self, sizehint=0):
 
107
        """ Read until EOF using readline() and return a list containing the        
 
108
        lines thus read.
 
109
        
 
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).
 
113
 
 
114
        Truncates the buffer.
 
115
        """
 
116
 
 
117
        self.seek(0)
 
118
        res = StringIO.StringIO.readlines(self, length)
 
119
        self.truncate(0)
 
120
        return res
 
121
 
59
122
class Console(object):
60
123
    """ Provides a nice python interface to the console
61
124
    """
66
129
        self.uid = uid
67
130
        self.jail_path = jail_path
68
131
        self.working_dir = working_dir
 
132
 
 
133
        # Set up the buffers
 
134
        self.stdin = TruncateStringIO()
 
135
        self.stdout = TruncateStringIO()
 
136
        self.stderr = TruncateStringIO()
 
137
 
 
138
        # Fire up the console
69
139
        self.restart()
70
140
 
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)
 
146
 
72
147
        # TODO: Check if we are already running a console. If we are shut it 
73
148
        # down first.
74
149
 
139
214
            raise ConsoleError(
140
215
                "Could not understand the python console response")
141
216
 
142
 
        # Look for user errors
 
217
        return response
 
218
 
 
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
 
222
        """
 
223
        # Do the request
 
224
        response = self.__chat(cmd, args)
 
225
 
 
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())
 
233
 
 
234
        # Process user exceptions
143
235
        if 'exc' in response:
144
236
            raise ConsoleException(response['exc'])
145
 
        
 
237
 
146
238
        return response
147
239
 
148
240
    def chat(self, code=''):
151
243
 
152
244
    def block(self, code):
153
245
        """ Executes a block of code and returns the output """
154
 
        block = self.__chat('block', code)
 
246
        block = self.__handle_chat('block', code)
155
247
        if 'output' in block:
156
248
            return block['output']
157
249
        elif 'okay' in block:
159
251
        else:
160
252
            raise ConsoleException("Bad response from console: %s"%str(block))
161
253
 
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 
 
256
        them to a new value
165
257
        """
166
258
        # Pickle the globals
167
 
        pickled_globs = {}
 
259
        pickled_globs = None
168
260
        if globs is not None:
 
261
            pickled_globs = {}
169
262
            for g in globs:
170
263
                pickled_globs[g] = cPickle.dumps(globs[g])
171
264
 
172
 
        flush = self.__chat('flush', pickled_globs)
173
 
        if 'response' in flush and flush['response'] == 'okay':
174
 
            return
175
 
        else:
176
 
            raise ConsoleError("Bad response from console: %s"%str(flush))
 
265
        globals = self.__handle_chat('globals', pickled_globs)
 
266
 
 
267
        # Unpickle the globals
 
268
        for g in globals['globals']:
 
269
            globals['globals'][g] = cPickle.loads(globals['globals'][g])
 
270
 
 
271
        return globals['globals']
 
272
        
177
273
 
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,
185
281
            'args': args,
186
282
            'kwargs': kwargs}
187
 
        call = self.__chat('call', call_args)
188
 
        
 
283
        call = self.__handle_chat('call', call_args)
 
284
 
189
285
        # Unpickle any exceptions
190
286
        if 'exception' in call:
191
287
            call['exception']['except'] = \
193
289
 
194
290
        return call
195
291
 
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 
202
 
        except.
 
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.
203
295
        """
204
 
        inspection = self.__chat('inspect', code)
205
 
       
206
 
        # Unpickle the globals
207
 
        for g in inspection['globals']:
208
 
            inspection['globals'][g] = cPickle.loads(inspection['globals'][g])
209
 
        
 
296
        execute = self.__handle_chat('execute', code)
 
297
              
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'])
 
301
        else:
 
302
            return execute
214
303
 
215
 
        return inspection
216
304
 
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])
225
313
 
226
 
        set_vars = self.__chat('set_vars', vars)
 
314
        set_vars = self.__handle_chat('set_vars', vars)
227
315
 
228
316
        if set_vars.get('response') != 'okay':
229
317
            raise ConsoleError("Could not set variables")
230
318
 
231
319
    def close(self):
232
320
        """ Causes the console process to terminate """
233
 
        self.__chat('restart', None)
 
321
        return self.__chat('terminate', None)
234
322
    
235
323