alwbtc
alwbtc

Reputation: 29465

How does run.main() work?

Please explain how following statement runs a Python script. There are no custom function calls in this block:

if __name__ == '__main__':
    import sys,os
    import run
    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

Let me paste the entire script:

import wx
import wx.grid as grid
import wx.lib.mixins.gridlabelrenderer as glr

#----------------------------------------------------------------------

class MyGrid(grid.Grid, glr.GridWithLabelRenderersMixin):
    def __init__(self, *args, **kw):
        grid.Grid.__init__(self, *args, **kw)
        glr.GridWithLabelRenderersMixin.__init__(self)


class MyRowLabelRenderer(glr.GridLabelRenderer):
    def __init__(self, bgcolor):
        self._bgcolor = bgcolor

    def Draw(self, grid, dc, rect, row):
        dc.SetBrush(wx.Brush(self._bgcolor))
        dc.SetPen(wx.TRANSPARENT_PEN)
        dc.DrawRectangleRect(rect)
        hAlign, vAlign = grid.GetRowLabelAlignment()
        text = grid.GetRowLabelValue(row)
        self.DrawBorder(grid, dc, rect)
        self.DrawText(grid, dc, rect, text, hAlign, vAlign)


class MyColLabelRenderer(glr.GridLabelRenderer):
    def __init__(self, bgcolor):
        self._bgcolor = bgcolor

    def Draw(self, grid, dc, rect, col):
        dc.SetBrush(wx.Brush(self._bgcolor))
        dc.SetPen(wx.TRANSPARENT_PEN)
        dc.DrawRectangleRect(rect)
        hAlign, vAlign = grid.GetColLabelAlignment()
        text = grid.GetColLabelValue(col)
        self.DrawBorder(grid, dc, rect)
        self.DrawText(grid, dc, rect, text, hAlign, vAlign)


class MyCornerLabelRenderer(glr.GridLabelRenderer):
    def __init__(self):
        import images
        self._bmp = images.Smiles.getBitmap()

    def Draw(self, grid, dc, rect, rc):
        x = rect.left + (rect.width - self._bmp.GetWidth()) / 2
        y = rect.top + (rect.height - self._bmp.GetHeight()) / 2
        dc.DrawBitmap(self._bmp, x, y, True)



class TestPanel(wx.Panel):
    def __init__(self, parent, log):
        self.log = log
        wx.Panel.__init__(self, parent, -1)

        ROWS = 27
        COLS = 15

        g = MyGrid(self, size=(100,100))
        g.CreateGrid(ROWS, COLS)

        g.SetCornerLabelRenderer(MyCornerLabelRenderer())

        for row in range(0, ROWS, 3):
            g.SetRowLabelRenderer(row+0, MyRowLabelRenderer('#ffe0e0'))
            g.SetRowLabelRenderer(row+1, MyRowLabelRenderer('#e0ffe0'))
            g.SetRowLabelRenderer(row+2, MyRowLabelRenderer('#e0e0ff'))

        for col in range(0, COLS, 3):
            g.SetColLabelRenderer(col+0, MyColLabelRenderer('#e0ffe0'))
            g.SetColLabelRenderer(col+1, MyColLabelRenderer('#e0e0ff'))
            g.SetColLabelRenderer(col+2, MyColLabelRenderer('#ffe0e0'))

        self.Sizer = wx.BoxSizer()
        self.Sizer.Add(g, 1, wx.EXPAND)


#----------------------------------------------------------------------

def runTest(frame, nb, log):
    win = TestPanel(nb, log)
    return win

#----------------------------------------------------------------------



overview = """<html><body>
<h2><center>GridLabelRenderer</h2>

The <tt>wx.lib.mixins.gridlabelrenderer</tt> module provides a mixin
class for wx.grid.Grid that enables it to have plugin renderers that
work like the normal cell renderers do.  If desired you can specify a
different renderer for each row or col label, and even for the little
corner label in the upper left corner of the grid.  When each of those
labels needs to be drawn the mixin calls the render's Draw method with
the dc and rectangle, allowing your renderer class do do just about
anything that it wants.

</body></html>
"""



if __name__ == '__main__':
    import sys,os
    import run
    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

it appears that there is a run.py in the same directory with the script above:

#!/usr/bin/env python
#----------------------------------------------------------------------------
# Name:         run.py
# Purpose:      Simple framework for running individual demos
#
# Author:       Robin Dunn
#
# Created:      6-March-2000
# RCS-ID:       $Id: run.py 53286 2008-04-21 15:33:51Z RD $
# Copyright:    (c) 2000 by Total Control Software
# Licence:      wxWindows license
#----------------------------------------------------------------------------

"""
This program will load and run one of the individual demos in this
directory within its own frame window.  Just specify the module name
on the command line.
"""

import wx
import wx.lib.inspection
import wx.lib.mixins.inspection
import sys, os

# stuff for debugging
print "wx.version:", wx.version()
print "pid:", os.getpid()
##raw_input("Press Enter...")

assertMode = wx.PYAPP_ASSERT_DIALOG
##assertMode = wx.PYAPP_ASSERT_EXCEPTION


#----------------------------------------------------------------------------

class Log:
    def WriteText(self, text):
        if text[-1:] == '\n':
            text = text[:-1]
        wx.LogMessage(text)
    write = WriteText


class RunDemoApp(wx.App, wx.lib.mixins.inspection.InspectionMixin):
    def __init__(self, name, module, useShell):
        self.name = name
        self.demoModule = module
        self.useShell = useShell
        wx.App.__init__(self, redirect=False)


    def OnInit(self):
        wx.Log_SetActiveTarget(wx.LogStderr())

        self.SetAssertMode(assertMode)
        self.Init()  # InspectionMixin

        frame = wx.Frame(None, -1, "RunDemo: " + self.name, pos=(50,50), size=(200,100),
                        style=wx.DEFAULT_FRAME_STYLE, name="run a sample")
        frame.CreateStatusBar()

        menuBar = wx.MenuBar()
        menu = wx.Menu()
        item = menu.Append(-1, "&Widget Inspector\tF6", "Show the wxPython Widget Inspection Tool")
        self.Bind(wx.EVT_MENU, self.OnWidgetInspector, item)
        item = menu.Append(-1, "E&xit\tCtrl-Q", "Exit demo")
        self.Bind(wx.EVT_MENU, self.OnExitApp, item)
        menuBar.Append(menu, "&File")

        ns = {}
        ns['wx'] = wx
        ns['app'] = self
        ns['module'] = self.demoModule
        ns['frame'] = frame

        frame.SetMenuBar(menuBar)
        frame.Show(True)
        frame.Bind(wx.EVT_CLOSE, self.OnCloseFrame)

        win = self.demoModule.runTest(frame, frame, Log())

        # a window will be returned if the demo does not create
        # its own top-level window
        if win:
            # so set the frame to a good size for showing stuff
            frame.SetSize((640, 480))
            win.SetFocus()
            self.window = win
            ns['win'] = win
            frect = frame.GetRect()

        else:
            # It was probably a dialog or something that is already
            # gone, so we're done.
            frame.Destroy()
            return True

        self.SetTopWindow(frame)
        self.frame = frame
        #wx.Log_SetActiveTarget(wx.LogStderr())
        #wx.Log_SetTraceMask(wx.TraceMessages)

        if self.useShell:
            # Make a PyShell window, and position it below our test window
            from wx import py
            shell = py.shell.ShellFrame(None, locals=ns)
            frect.OffsetXY(0, frect.height)
            frect.height = 400
            shell.SetRect(frect)
            shell.Show()

            # Hook the close event of the test window so that we close
            # the shell at the same time
            def CloseShell(evt):
                if shell:
                    shell.Close()
                evt.Skip()
            frame.Bind(wx.EVT_CLOSE, CloseShell)

        return True


    def OnExitApp(self, evt):
        self.frame.Close(True)


    def OnCloseFrame(self, evt):
        if hasattr(self, "window") and hasattr(self.window, "ShutdownDemo"):
            self.window.ShutdownDemo()
        evt.Skip()

    def OnWidgetInspector(self, evt):
        wx.lib.inspection.InspectionTool().Show()


#----------------------------------------------------------------------------


def main(argv):
    useShell = False
    for x in range(len(sys.argv)):
        if sys.argv[x] in ['--shell', '-shell', '-s']:
            useShell = True
            del sys.argv[x]
            break

    if len(argv) < 2:
        print "Please specify a demo module name on the command-line"
        raise SystemExit

    name, ext  = os.path.splitext(argv[1])
    module = __import__(name)


    app = RunDemoApp(name, module, useShell)
    app.MainLoop()



if __name__ == "__main__":
    main(sys.argv)

Upvotes: 1

Views: 1079

Answers (2)

UltraInstinct
UltraInstinct

Reputation: 44454

Check the contents of run.py. From what you have posted, it pretty much becomes simple since you are able to trace the function calls.

  1. run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]): Calls the main function inside the run module. You are passing the script file name to this.
  2. inside run.main, the code is importing your package.
  3. Check for a line in run.py that says: win = self.demoModule.runTest(frame, frame, Log()). This line calling the function runTest in your script. Try removing this function, or renaming may be; the execution will fail.
  4. your runTest returns a TestPanel. The function in run.py calls a mainloop() which sets up the window event loop, and hence runs your script.

HTH

Upvotes: 2

SethMMorton
SethMMorton

Reputation: 48805

In the file run.py there is a statement like this:

def main(args):
    pass

You are importing run, and calling that main function.

The __name__ == '__main__' part just tells python not run execute that code if the file is being imported, only when run as a script.


I'm not sure of the contents of run.py, but

os.path.basename(sys.argv[0])

will give you the name of the script that is currently being called, so I'm guessing that it is passing the script name and the first argument (sys.argv[1]) to run.main, and that's how it knows how to run the script.

Upvotes: 4

Related Questions