Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 1 | """Extension to execute code outside the Python shell window. |
| 2 | |
| 3 | This adds two commands (to the Edit menu, until there's a separate |
| 4 | Python menu): |
| 5 | |
| 6 | - Run module (F5) is equivalent to either import or reload of the |
| 7 | current module. The window must have been saved previously. The |
| 8 | module only gets added to sys.modules, it doesn't get added to |
| 9 | anyone's namespace; you can import it in the shell if you need to. If |
| 10 | this generates any output to sys.stdout or sys.stderr, a new output |
| 11 | window is created to display that output. The two streams are |
| 12 | distinguished by their text color. |
| 13 | |
| 14 | - Debug module (Control-F5) does the same but executes the module's |
| 15 | code in the debugger. |
| 16 | |
| 17 | When an unhandled exception occurs in Run module, the stack viewer is |
| 18 | popped up. This is not done in Debug module, because you've already |
| 19 | had an opportunity to view the stack. In either case, the variables |
| 20 | sys.last_type, sys.last_value, sys.last_traceback are set to the |
| 21 | exception info. |
| 22 | |
| 23 | """ |
| 24 | |
| 25 | import sys |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 26 | import os |
| 27 | import imp |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 28 | import linecache |
| 29 | import traceback |
| 30 | import tkMessageBox |
| 31 | from OutputWindow import OutputWindow |
| 32 | |
| 33 | # XXX These helper classes are more generally usable! |
| 34 | |
| 35 | class OnDemandOutputWindow: |
| 36 | |
| 37 | tagdefs = { |
| 38 | "stdout": {"foreground": "blue"}, |
| 39 | "stderr": {"foreground": "#007700"}, |
| 40 | } |
| 41 | |
| 42 | def __init__(self, flist): |
| 43 | self.flist = flist |
| 44 | self.owin = None |
| 45 | |
| 46 | def write(self, s, tags, mark): |
| 47 | if not self.owin: |
| 48 | self.setup() |
| 49 | self.owin.write(s, tags, mark) |
| 50 | |
| 51 | def setup(self): |
| 52 | self.owin = owin = OutputWindow(self.flist) |
| 53 | text = owin.text |
| 54 | for tag, cnf in self.tagdefs.items(): |
| 55 | if cnf: |
| 56 | apply(text.tag_configure, (tag,), cnf) |
| 57 | text.tag_raise('sel') |
| 58 | self.write = self.owin.write |
| 59 | |
| 60 | class PseudoFile: |
| 61 | |
| 62 | def __init__(self, owin, tags, mark="end"): |
| 63 | self.owin = owin |
| 64 | self.tags = tags |
| 65 | self.mark = mark |
| 66 | |
| 67 | def write(self, s): |
| 68 | self.owin.write(s, self.tags, self.mark) |
| 69 | |
| 70 | def writelines(self, l): |
| 71 | map(self.write, l) |
| 72 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 73 | |
| 74 | class ScriptBinding: |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 75 | |
| 76 | keydefs = { |
| 77 | '<<run-module>>': ['<F5>'], |
| 78 | '<<debug-module>>': ['<Control-F5>'], |
| 79 | } |
| 80 | |
| 81 | menudefs = [ |
| 82 | ('edit', [None, |
| 83 | ('Run module', '<<run-module>>'), |
| 84 | ('Debug module', '<<debug-module>>'), |
| 85 | ] |
| 86 | ), |
| 87 | ] |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 88 | |
| 89 | def __init__(self, editwin): |
| 90 | self.editwin = editwin |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 91 | # Provide instance variables referenced by Debugger |
| 92 | # XXX This should be done differently |
| 93 | self.flist = self.editwin.flist |
| 94 | self.root = self.flist.root |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 95 | |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 96 | def run_module_event(self, event, debugger=None): |
| 97 | if not self.editwin.get_saved(): |
| 98 | tkMessageBox.showerror("Not saved", |
| 99 | "Please save first!", |
| 100 | master=self.editwin.text) |
| 101 | self.editwin.text.focus_set() |
| 102 | return |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 103 | filename = self.editwin.io.filename |
| 104 | if not filename: |
| 105 | tkMessageBox.showerror("No file name", |
| 106 | "This window has no file name", |
| 107 | master=self.editwin.text) |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 108 | self.editwin.text.focus_set() |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 109 | return |
| 110 | modname, ext = os.path.splitext(os.path.basename(filename)) |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 111 | if sys.modules.has_key(modname): |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 112 | mod = sys.modules[modname] |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 113 | else: |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 114 | mod = imp.new_module(modname) |
| 115 | sys.modules[modname] = mod |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 116 | mod.__file__ = filename |
| 117 | saveout = sys.stdout |
| 118 | saveerr = sys.stderr |
| 119 | owin = OnDemandOutputWindow(self.editwin.flist) |
| 120 | try: |
| 121 | sys.stderr = PseudoFile(owin, "stderr") |
| 122 | try: |
| 123 | sys.stdout = PseudoFile(owin, "stdout") |
| 124 | try: |
| 125 | if debugger: |
| 126 | debugger.run("execfile(%s)" % `filename`, mod.__dict__) |
| 127 | else: |
| 128 | execfile(filename, mod.__dict__) |
| 129 | except: |
| 130 | (sys.last_type, sys.last_value, |
| 131 | sys.last_traceback) = sys.exc_info() |
| 132 | ## linecache.checkcache() |
| 133 | ## traceback.print_exc() |
| 134 | if not debugger: |
| 135 | from StackViewer import StackBrowser |
| 136 | sv = StackBrowser(self.root, self.flist) |
| 137 | finally: |
| 138 | sys.stdout = saveout |
| 139 | finally: |
| 140 | sys.stderr = saveerr |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 141 | |
Guido van Rossum | 9f42584 | 1999-01-09 05:00:17 +0000 | [diff] [blame^] | 142 | def debug_module_event(self, event): |
| 143 | import Debugger |
| 144 | debugger = Debugger.Debugger(self) |
| 145 | self.run_module_event(event, debugger) |
| 146 | |
| 147 | def close_debugger(self): |
| 148 | # Method called by Debugger |
| 149 | # XXX This should be done differently |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 150 | pass |