David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 1 | """Remote |
| 2 | This module is imported by the loader and serves to control |
| 3 | the execution of the user program. It presently executes files |
| 4 | and reports exceptions to IDLE. It could be extended to provide |
| 5 | other services, such as interactive mode and debugging. To that |
| 6 | end, it could be a subclass of e.g. InteractiveInterpreter. |
| 7 | |
| 8 | Two other classes, pseudoIn and pseudoOut, are file emulators also |
| 9 | used by loader. |
| 10 | """ |
| 11 | import sys, os |
| 12 | import traceback |
| 13 | |
| 14 | class Remote: |
| 15 | def __init__(self, main, master): |
| 16 | self.main = main |
| 17 | self.master = master |
| 18 | self.this_file = self.canonic( self.__init__.im_func.func_code.co_filename ) |
| 19 | |
| 20 | def canonic(self, path): |
| 21 | return os.path.normcase(os.path.abspath(path)) |
| 22 | |
| 23 | def mainloop(self): |
| 24 | while 1: |
| 25 | args = self.master.get_command() |
| 26 | |
| 27 | try: |
| 28 | f = getattr(self,args[0]) |
| 29 | apply(f,args[1:]) |
| 30 | except: |
| 31 | if not self.report_exception(): raise |
| 32 | |
| 33 | def finish(self): |
| 34 | sys.exit() |
| 35 | |
| 36 | def run(self, *argv): |
| 37 | sys.argv = argv |
| 38 | |
| 39 | path = self.canonic( argv[0] ) |
| 40 | dir = self.dir = os.path.dirname(path) |
| 41 | os.chdir(dir) |
| 42 | |
| 43 | sys.path[0] = dir |
| 44 | |
| 45 | usercode = open(path) |
| 46 | exec usercode in self.main |
| 47 | |
| 48 | def report_exception(self): |
| 49 | try: |
| 50 | type, value, tb = sys.exc_info() |
| 51 | sys.last_type = type |
| 52 | sys.last_value = value |
| 53 | sys.last_traceback = tb |
| 54 | |
| 55 | tblist = traceback.extract_tb(tb) |
| 56 | |
| 57 | # Look through the traceback, canonicalizing filenames and |
| 58 | # eliminating leading and trailing system modules. |
| 59 | first = last = 1 |
| 60 | for i in range(len(tblist)): |
| 61 | filename, lineno, name, line = tblist[i] |
| 62 | filename = self.canonic(filename) |
| 63 | tblist[i] = filename, lineno, name, line |
| 64 | |
| 65 | dir = os.path.dirname(filename) |
| 66 | if filename == self.this_file: |
| 67 | first = i+1 |
| 68 | elif dir==self.dir: |
| 69 | last = i+1 |
| 70 | |
| 71 | # Canonicalize the filename in a syntax error, too: |
| 72 | if type is SyntaxError: |
| 73 | try: |
| 74 | msg, (filename, lineno, offset, line) = value |
| 75 | filename = self.canonic(filename) |
| 76 | value = msg, (filename, lineno, offset, line) |
| 77 | except: |
| 78 | pass |
| 79 | |
| 80 | return self.master.program_exception( type, value, tblist, first, last ) |
| 81 | finally: |
| 82 | # avoid any circular reference through the traceback |
| 83 | del tb |
| 84 | |
| 85 | class pseudoIn: |
| 86 | def __init__(self, readline): |
| 87 | self.readline = readline |
| 88 | def isatty(): |
| 89 | return 1 |
| 90 | |
| 91 | class pseudoOut: |
| 92 | def __init__(self, func, **kw): |
| 93 | self.func = func |
| 94 | self.kw = kw |
| 95 | def write(self, *args): |
| 96 | return apply( self.func, args, self.kw ) |
| 97 | def writelines(self, l): |
| 98 | map(self.write, l) |
| 99 | def flush(self): |
| 100 | pass |
| 101 | |