Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
scriptutils.py689 linesDownload Raw Back to framework
1"""2Various utilities for running/importing a script3"""4import bdb5import linecache6import os7import sys8import traceback9 10import __main__11import win32api12import win32con13import win32ui14from pywin.mfc import dialog15from pywin.mfc.docview import TreeView16 17from .cmdline import ParseArgs18 19RS_DEBUGGER_NONE = 0  # Dont run under the debugger.20RS_DEBUGGER_STEP = 1  # Start stepping under the debugger21RS_DEBUGGER_GO = 2  # Just run under the debugger, stopping only at break-points.22RS_DEBUGGER_PM = 3  # Dont run under debugger, but do post-mortem analysis on exception.23 24debugging_options = """No debugging25Step-through in the debugger26Run in the debugger27Post-Mortem of unhandled exceptions""".split(28    "\n"29)30 31byte_cr = "\r".encode("ascii")32byte_lf = "\n".encode("ascii")33byte_crlf = "\r\n".encode("ascii")34 35 36# A dialog box for the "Run Script" command.37class DlgRunScript(dialog.Dialog):38    "A class for the 'run script' dialog"39 40    def __init__(self, bHaveDebugger):41        dialog.Dialog.__init__(self, win32ui.IDD_RUN_SCRIPT)42        self.AddDDX(win32ui.IDC_EDIT1, "script")43        self.AddDDX(win32ui.IDC_EDIT2, "args")44        self.AddDDX(win32ui.IDC_COMBO1, "debuggingType", "i")45        self.HookCommand(self.OnBrowse, win32ui.IDC_BUTTON2)46        self.bHaveDebugger = bHaveDebugger47 48    def OnInitDialog(self):49        rc = dialog.Dialog.OnInitDialog(self)50        cbo = self.GetDlgItem(win32ui.IDC_COMBO1)51        for o in debugging_options:52            cbo.AddString(o)53        cbo.SetCurSel(self["debuggingType"])54        if not self.bHaveDebugger:55            cbo.EnableWindow(0)56 57    def OnBrowse(self, id, code):58        if code != 0:  # BN_CLICKED59            return 160        openFlags = win32con.OFN_OVERWRITEPROMPT | win32con.OFN_FILEMUSTEXIST61        dlg = win32ui.CreateFileDialog(62            1, None, None, openFlags, "Python Scripts (*.py)|*.py||", self63        )64        dlg.SetOFNTitle("Run Script")65        if dlg.DoModal() != win32con.IDOK:66            return 067        self["script"] = dlg.GetPathName()68        self.UpdateData(0)69        return 070 71 72def GetDebugger():73    """Get the default Python debugger.  Returns the debugger, or None.74 75    It is assumed the debugger has a standard "pdb" defined interface.76    Currently always returns the 'pywin.debugger' debugger, or None77    (pdb is _not_ returned as it is not effective in this GUI environment)78    """79    try:80        import pywin.debugger81 82        return pywin.debugger83    except ImportError:84        return None85 86 87def IsOnPythonPath(path):88    "Given a path only, see if it is on the Pythonpath.  Assumes path is a full path spec."89    # must check that the command line arg's path is in sys.path90    for syspath in sys.path:91        try:92            # Python 1.5 and later allows an empty sys.path entry.93            if syspath and win32ui.FullPath(syspath) == path:94                return 195        except win32ui.error as details:96            print(97                "Warning: The sys.path entry '%s' is invalid\n%s" % (syspath, details)98            )99    return 0100 101 102def GetPackageModuleName(fileName):103    """Given a filename, return (module name, new path).104    eg - given "c:\a\b\c\my.py", return ("b.c.my",None) if "c:\a" is on sys.path.105    If no package found, will return ("my", "c:\a\b\c")106    """107    path, fname = os.path.split(fileName)108    path = origPath = win32ui.FullPath(path)109    fname = os.path.splitext(fname)[0]110    modBits = []111    newPathReturn = None112    if not IsOnPythonPath(path):113        # Module not directly on the search path - see if under a package.114        while len(path) > 3:  # ie 'C:\'115            path, modBit = os.path.split(path)116            modBits.append(modBit)117            # If on path, _and_ existing package of that name loaded.118            if (119                IsOnPythonPath(path)120                and modBit in sys.modules121                and (122                    os.path.exists(os.path.join(path, modBit, "__init__.py"))123                    or os.path.exists(os.path.join(path, modBit, "__init__.pyc"))124                    or os.path.exists(os.path.join(path, modBit, "__init__.pyo"))125                )126            ):127                modBits.reverse()128                return ".".join(modBits) + "." + fname, newPathReturn129            # Not found - look a level higher130        else:131            newPathReturn = origPath132 133    return fname, newPathReturn134 135 136def GetActiveView():137    """Gets the edit control (eg, EditView) with the focus, or None"""138    try:139        childFrame, bIsMaximised = win32ui.GetMainFrame().MDIGetActive()140        return childFrame.GetActiveView()141    except win32ui.error:142        return None143 144 145def GetActiveEditControl():146    view = GetActiveView()147    if view is None:148        return None149    if hasattr(view, "SCIAddText"):  # Is it a scintilla control?150        return view151    try:152        return view.GetRichEditCtrl()153    except AttributeError:154        pass155    try:156        return view.GetEditCtrl()157    except AttributeError:158        pass159 160 161def GetActiveEditorDocument():162    """Returns the active editor document and view, or (None,None) if no163    active document or its not an editor document.164    """165    view = GetActiveView()166    if view is None or isinstance(view, TreeView):167        return (None, None)168    doc = view.GetDocument()169    if hasattr(doc, "MarkerAdd"):  # Is it an Editor document?170        return doc, view171    return (None, None)172 173 174def GetActiveFileName(bAutoSave=1):175    """Gets the file name for the active frame, saving it if necessary.176 177    Returns None if it cant be found, or raises KeyboardInterrupt.178    """179    pathName = None180    active = GetActiveView()181    if active is None:182        return None183    try:184        doc = active.GetDocument()185        pathName = doc.GetPathName()186 187        if bAutoSave and (188            len(pathName) > 0189            or doc.GetTitle()[:8] == "Untitled"190            or doc.GetTitle()[:6] == "Script"191        ):  # if not a special purpose window192            if doc.IsModified():193                try:194                    doc.OnSaveDocument(pathName)195                    pathName = doc.GetPathName()196 197                    # clear the linecache buffer198                    linecache.clearcache()199 200                except win32ui.error:201                    raise KeyboardInterrupt202 203    except (win32ui.error, AttributeError):204        pass205    if not pathName:206        return None207    return pathName208 209 210lastScript = ""211lastArgs = ""212lastDebuggingType = RS_DEBUGGER_NONE213 214 215def RunScript(defName=None, defArgs=None, bShowDialog=1, debuggingType=None):216    global lastScript, lastArgs, lastDebuggingType217    _debugger_stop_frame_ = 1  # Magic variable so the debugger will hide me!218 219    # Get the debugger - may be None!220    debugger = GetDebugger()221 222    if defName is None:223        try:224            pathName = GetActiveFileName()225        except KeyboardInterrupt:226            return  # User cancelled save.227    else:228        pathName = defName229    if not pathName:230        pathName = lastScript231    if defArgs is None:232        args = ""233        if pathName == lastScript:234            args = lastArgs235    else:236        args = defArgs237    if debuggingType is None:238        debuggingType = lastDebuggingType239 240    if not pathName or bShowDialog:241        dlg = DlgRunScript(debugger is not None)242        dlg["script"] = pathName243        dlg["args"] = args244        dlg["debuggingType"] = debuggingType245        if dlg.DoModal() != win32con.IDOK:246            return247        script = dlg["script"]248        args = dlg["args"]249        debuggingType = dlg["debuggingType"]250        if not script:251            return252        if debuggingType == RS_DEBUGGER_GO and debugger is not None:253            # This may surprise users - they select "Run under debugger", but254            # it appears not to!  Only warn when they pick from the dialog!255            # First - ensure the debugger is activated to pickup any break-points256            # set in the editor.257            try:258                # Create the debugger, but _dont_ init the debugger GUI.259                rd = debugger._GetCurrentDebugger()260            except AttributeError:261                rd = None262            if rd is not None and len(rd.breaks) == 0:263                msg = "There are no active break-points.\r\n\r\nSelecting this debug option without any\r\nbreak-points is unlikely to have the desired effect\r\nas the debugger is unlikely to be invoked..\r\n\r\nWould you like to step-through in the debugger instead?"264                rc = win32ui.MessageBox(265                    msg,266                    win32ui.LoadString(win32ui.IDR_DEBUGGER),267                    win32con.MB_YESNOCANCEL | win32con.MB_ICONINFORMATION,268                )269                if rc == win32con.IDCANCEL:270                    return271                if rc == win32con.IDYES:272                    debuggingType = RS_DEBUGGER_STEP273 274        lastDebuggingType = debuggingType275        lastScript = script276        lastArgs = args277    else:278        script = pathName279 280    # try and open the script.281    if (282        len(os.path.splitext(script)[1]) == 0283    ):  # check if no extension supplied, and give one.284        script = script + ".py"285    # If no path specified, try and locate the file286    path, fnameonly = os.path.split(script)287    if len(path) == 0:288        try:289            os.stat(fnameonly)  # See if it is OK as is...290            script = fnameonly291        except os.error:292            fullScript = LocatePythonFile(script)293            if fullScript is None:294                win32ui.MessageBox("The file '%s' can not be located" % script)295                return296            script = fullScript297    else:298        path = win32ui.FullPath(path)299        if not IsOnPythonPath(path):300            sys.path.append(path)301 302    # py3k fun: If we use text mode to open the file, we get \r\n303    # translated so Python allows the syntax (good!), but we get back304    # text already decoded from the default encoding (bad!) and Python305    # ignores any encoding decls (bad!).  If we use binary mode we get306    # the raw bytes and Python looks at the encoding (good!) but \r\n307    # chars stay in place so Python throws a syntax error (bad!).308    # So: so the binary thing and manually normalize \r\n.309    try:310        f = open(script, "rb")311    except IOError as exc:312        win32ui.MessageBox(313            "The file could not be opened - %s (%d)" % (exc.strerror, exc.errno)314        )315        return316 317    # Get the source-code - as above, normalize \r\n318    code = f.read().replace(byte_crlf, byte_lf).replace(byte_cr, byte_lf) + byte_lf319 320    # Remember and hack sys.argv for the script.321    oldArgv = sys.argv322    sys.argv = ParseArgs(args)323    sys.argv.insert(0, script)324    # sys.path[0] is the path of the script325    oldPath0 = sys.path[0]326    newPath0 = os.path.split(script)[0]327    if not oldPath0:  # if sys.path[0] is empty328        sys.path[0] = newPath0329        insertedPath0 = 0330    else:331        sys.path.insert(0, newPath0)332        insertedPath0 = 1333    bWorked = 0334    win32ui.DoWaitCursor(1)335    base = os.path.split(script)[1]336    # Allow windows to repaint before starting.337    win32ui.PumpWaitingMessages()338    win32ui.SetStatusText("Running script %s..." % base, 1)339    exitCode = 0340    from pywin.framework import interact341 342    # Check the debugger flags343    if debugger is None and (debuggingType != RS_DEBUGGER_NONE):344        win32ui.MessageBox(345            "No debugger is installed.  Debugging options have been ignored!"346        )347        debuggingType = RS_DEBUGGER_NONE348 349    # Get a code object - ignore the debugger for this, as it is probably a syntax error350    # at this point351    try:352        codeObject = compile(code, script, "exec")353    except:354        # Almost certainly a syntax error!355        _HandlePythonFailure("run script", script)356        # No code object which to run/debug.357        return358    __main__.__file__ = script359    try:360        if debuggingType == RS_DEBUGGER_STEP:361            debugger.run(codeObject, __main__.__dict__, start_stepping=1)362        elif debuggingType == RS_DEBUGGER_GO:363            debugger.run(codeObject, __main__.__dict__, start_stepping=0)364        else:365            # Post mortem or no debugging366            exec(codeObject, __main__.__dict__)367        bWorked = 1368    except bdb.BdbQuit:369        # Dont print tracebacks when the debugger quit, but do print a message.370        print("Debugging session cancelled.")371        exitCode = 1372        bWorked = 1373    except SystemExit as code:374        exitCode = code375        bWorked = 1376    except KeyboardInterrupt:377        # Consider this successful, as we dont want the debugger.378        # (but we do want a traceback!)379        if interact.edit and interact.edit.currentView:380            interact.edit.currentView.EnsureNoPrompt()381        traceback.print_exc()382        if interact.edit and interact.edit.currentView:383            interact.edit.currentView.AppendToPrompt([])384        bWorked = 1385    except:386        if interact.edit and interact.edit.currentView:387            interact.edit.currentView.EnsureNoPrompt()388        traceback.print_exc()389        if interact.edit and interact.edit.currentView:390            interact.edit.currentView.AppendToPrompt([])391        if debuggingType == RS_DEBUGGER_PM:392            debugger.pm()393    del __main__.__file__394    sys.argv = oldArgv395    if insertedPath0:396        del sys.path[0]397    else:398        sys.path[0] = oldPath0399    f.close()400    if bWorked:401        win32ui.SetStatusText("Script '%s' returned exit code %s" % (script, exitCode))402    else:403        win32ui.SetStatusText("Exception raised while running script  %s" % base)404    try:405        sys.stdout.flush()406    except AttributeError:407        pass408 409    win32ui.DoWaitCursor(0)410 411 412def ImportFile():413    """This code looks for the current window, and determines if it can be imported.  If not,414    it will prompt for a file name, and allow it to be imported."""415    try:416        pathName = GetActiveFileName()417    except KeyboardInterrupt:418        pathName = None419 420    if pathName is not None:421        if os.path.splitext(pathName)[1].lower() not in (".py", ".pyw", ".pyx"):422            pathName = None423 424    if pathName is None:425        openFlags = win32con.OFN_OVERWRITEPROMPT | win32con.OFN_FILEMUSTEXIST426        dlg = win32ui.CreateFileDialog(427            1, None, None, openFlags, "Python Scripts (*.py;*.pyw)|*.py;*.pyw;*.pyx||"428        )429        dlg.SetOFNTitle("Import Script")430        if dlg.DoModal() != win32con.IDOK:431            return 0432 433        pathName = dlg.GetPathName()434 435    # If already imported, dont look for package436    path, modName = os.path.split(pathName)437    modName, modExt = os.path.splitext(modName)438    newPath = None439    # note that some packages (*cough* email *cough*) use "lazy importers"440    # meaning sys.modules can change as a side-effect of looking at441    # module.__file__ - so we must take a copy (ie, items() in py2k,442    # list(items()) in py3k)443    for key, mod in list(sys.modules.items()):444        if getattr(mod, "__file__", None):445            fname = mod.__file__446            base, ext = os.path.splitext(fname)447            if ext.lower() in (".pyo", ".pyc"):448                ext = ".py"449            fname = base + ext450            if win32ui.ComparePath(fname, pathName):451                modName = key452                break453    else:  # for not broken454        modName, newPath = GetPackageModuleName(pathName)455        if newPath:456            sys.path.append(newPath)457 458    if modName in sys.modules:459        bNeedReload = 1460        what = "reload"461    else:462        what = "import"463        bNeedReload = 0464 465    win32ui.SetStatusText(what.capitalize() + "ing module...", 1)466    win32ui.DoWaitCursor(1)467    # 	win32ui.GetMainFrame().BeginWaitCursor()468 469    try:470        # always do an import, as it is cheap if it's already loaded.  This ensures471        # it is in our name space.472        codeObj = compile("import " + modName, "<auto import>", "exec")473    except SyntaxError:474        win32ui.SetStatusText('Invalid filename for import: "' + modName + '"')475        return476    try:477        exec(codeObj, __main__.__dict__)478        mod = sys.modules.get(modName)479        if bNeedReload:480            from importlib import reload481 482            mod = reload(sys.modules[modName])483        win32ui.SetStatusText(484            "Successfully "485            + what486            + "ed module '"487            + modName488            + "': %s" % getattr(mod, "__file__", "<unkown file>")489        )490    except:491        _HandlePythonFailure(what)492    win32ui.DoWaitCursor(0)493 494 495def CheckFile():496    """This code looks for the current window, and gets Python to check it497    without actually executing any code (ie, by compiling only)498    """499    try:500        pathName = GetActiveFileName()501    except KeyboardInterrupt:502        return503 504    what = "check"505    win32ui.SetStatusText(what.capitalize() + "ing module...", 1)506    win32ui.DoWaitCursor(1)507    try:508        f = open(pathName)509    except IOError as details:510        print("Cant open file '%s' - %s" % (pathName, details))511        return512    try:513        code = f.read() + "\n"514    finally:515        f.close()516    try:517        codeObj = compile(code, pathName, "exec")518        if RunTabNanny(pathName):519            win32ui.SetStatusText(520                "Python and the TabNanny successfully checked the file '"521                + os.path.basename(pathName)522                + "'"523            )524    except SyntaxError:525        _HandlePythonFailure(what, pathName)526    except:527        traceback.print_exc()528        _HandlePythonFailure(what)529    win32ui.DoWaitCursor(0)530 531 532def RunTabNanny(filename):533    import io as io534 535    tabnanny = FindTabNanny()536    if tabnanny is None:537        win32ui.MessageBox("The TabNanny is not around, so the children can run amok!")538        return539 540    # Capture the tab-nanny output541    newout = io.StringIO()542    old_out = sys.stderr, sys.stdout543    sys.stderr = sys.stdout = newout544    try:545        tabnanny.check(filename)546    finally:547        # Restore output548        sys.stderr, sys.stdout = old_out549    data = newout.getvalue()550    if data:551        try:552            lineno = data.split()[1]553            lineno = int(lineno)554            _JumpToPosition(filename, lineno)555            try:  # Try and display whitespace556                GetActiveEditControl().SCISetViewWS(1)557            except:558                pass559            win32ui.SetStatusText("The TabNanny found trouble at line %d" % lineno)560        except (IndexError, TypeError, ValueError):561            print("The tab nanny complained, but I cant see where!")562            print(data)563        return 0564    return 1565 566 567def _JumpToPosition(fileName, lineno, col=1):568    JumpToDocument(fileName, lineno, col)569 570 571def JumpToDocument(fileName, lineno=0, col=1, nChars=0, bScrollToTop=0):572    # Jump to the position in a file.573    # If lineno is <= 0, dont move the position - just open/restore.574    # if nChars > 0, select that many characters.575    # if bScrollToTop, the specified line will be moved to the top of the window576    #  (eg, bScrollToTop should be false when jumping to an error line to retain the577    #  context, but true when jumping to a method defn, where we want the full body.578    # Return the view which is editing the file, or None on error.579    doc = win32ui.GetApp().OpenDocumentFile(fileName)580    if doc is None:581        return None582    frame = doc.GetFirstView().GetParentFrame()583    try:584        view = frame.GetEditorView()585        if frame.GetActiveView() != view:586            frame.SetActiveView(view)587        frame.AutoRestore()588    except AttributeError:  # Not an editor frame??589        view = doc.GetFirstView()590    if lineno > 0:591        charNo = view.LineIndex(lineno - 1)592        start = charNo + col - 1593        size = view.GetTextLength()594        try:595            view.EnsureCharsVisible(charNo)596        except AttributeError:597            print("Doesnt appear to be one of our views?")598        view.SetSel(min(start, size), min(start + nChars, size))599    if bScrollToTop:600        curTop = view.GetFirstVisibleLine()601        nScroll = (lineno - 1) - curTop602        view.LineScroll(nScroll, 0)603    view.SetFocus()604    return view605 606 607def _HandlePythonFailure(what, syntaxErrorPathName=None):608    typ, details, tb = sys.exc_info()609    if isinstance(details, SyntaxError):610        try:611            msg, (fileName, line, col, text) = details612            if (not fileName or fileName == "<string>") and syntaxErrorPathName:613                fileName = syntaxErrorPathName614            _JumpToPosition(fileName, line, col)615        except (TypeError, ValueError):616            msg = str(details)617        win32ui.SetStatusText("Failed to " + what + " - syntax error - %s" % msg)618    else:619        traceback.print_exc()620        win32ui.SetStatusText("Failed to " + what + " - " + str(details))621    tb = None  # Clean up a cycle.622 623 624# Find the Python TabNanny in either the standard library or the Python Tools/Scripts directory.625def FindTabNanny():626    try:627        return __import__("tabnanny")628    except ImportError:629        pass630    # OK - not in the standard library - go looking.631    filename = "tabnanny.py"632    try:633        path = win32api.RegQueryValue(634            win32con.HKEY_LOCAL_MACHINE,635            "SOFTWARE\\Python\\PythonCore\\%s\\InstallPath" % (sys.winver),636        )637    except win32api.error:638        print("WARNING - The Python registry does not have an 'InstallPath' setting")639        print("          The file '%s' can not be located" % (filename))640        return None641    fname = os.path.join(path, "Tools\\Scripts\\%s" % filename)642    try:643        os.stat(fname)644    except os.error:645        print(646            "WARNING - The file '%s' can not be located in path '%s'" % (filename, path)647        )648        return None649 650    tabnannyhome, tabnannybase = os.path.split(fname)651    tabnannybase = os.path.splitext(tabnannybase)[0]652    # Put tab nanny at the top of the path.653    sys.path.insert(0, tabnannyhome)654    try:655        return __import__(tabnannybase)656    finally:657        # remove the tab-nanny from the path658        del sys.path[0]659 660 661def LocatePythonFile(fileName, bBrowseIfDir=1):662    "Given a file name, return a fully qualified file name, or None"663    # first look for the exact file as specified664    if not os.path.isfile(fileName):665        # Go looking!666        baseName = fileName667        for path in sys.path:668            fileName = os.path.abspath(os.path.join(path, baseName))669            if os.path.isdir(fileName):670                if bBrowseIfDir:671                    d = win32ui.CreateFileDialog(672                        1, "*.py", None, 0, "Python Files (*.py)|*.py|All files|*.*"673                    )674                    d.SetOFNInitialDir(fileName)675                    rc = d.DoModal()676                    if rc == win32con.IDOK:677                        fileName = d.GetPathName()678                        break679                    else:680                        return None681            else:682                fileName = fileName + ".py"683                if os.path.isfile(fileName):684                    break  # Found it!685 686        else:  # for not broken out of687            return None688    return win32ui.FullPath(fileName)689 
codekingpro/portable-devtools · Team Ai