Learning the MVP Pattern

try this

    def OnQuit(self, event):
        presenter.quitApp()

···

On 11/21/06, Rich Shepard <rshepard@appl-ecosys.com> wrote:

   In the main module is the menu with File->Quit; ctrl-q is the hotkey for
this function. Bound to this item/hotkey is the method OnQuit(). This bound
method is

Rich Shepard wrote:

  In the calling module I now have:

def OnQuit(self, event):
    presenter().quitApp(self)

and this takes me to the functions module, where I have:

def quitApp(self, event):
    self.Close()

and this produces this python response:

Traceback (most recent call last):
  File "eikos.py", line 162, in OnQuit
    presenter().quitApp(self)
  File "/data1/eikos/functions.py", line 63, in quitApp
    self.Close()
AttributeError: presenter instance has no attribute 'Close'

you seem to get tangled up in namespaces a lot -- does anyone know a good tutorial on that -- it's key to understanding python code structure.

  Could this be because quitApp() is not bound to the frame in which the
menu item/hot key are located? There is no problem quitting the application
from within the calling module.

This in not about what module you are in-- it's about what "self" is. "self" can be a touch confusing, as the same name is used everywhere, but in fact, it's really just a convention:

in:
def quitApp(self, event):
      self.Close()

"self" is simply the first argument passed to quitApp. I'm assuming quitApp() is a method of some class, in which case, self will be automatically assigned to teh instance that the method is called on, in this case, the presenter instance you just instantiated.

Does the presenter class have a Close() method? Apparently not. Should it? or are you trying to Close the main frame?

Perhaps this is one method that needs to
remain in that module and not be relocated elsewhere?

It's not so much about what module, and it is what class. In general, an App is shut down when all its top-level windows (Frames) are closed. If you have only one MainFrame class, then you can put your OnQuit method there. If you might have multiple Frames, then you may want to put your OnQuit method in the App class. Then how do you call it? Since there is only one App, you can call:

wx.GetApp()

anywhere to get the running App instance.

I think you're getting confused because, in refactoring, you're moving methods around, but when you move a method to a different class, then "self" becomes a different class also, so things need to change.

Another note:

presenter() will create a new presenter instance -- I'm guessing you want the same presenter instance during the whole run of the app -- in that case, you should create it during app initialization, and store it somewhere handy -- in the App class, in the mainframe, class, in the model class -- somewhere that you can access it when you need it.

On the MVP Wiki page, I only see the AlbumPresenter instantiated in a unit test, so I'm not sure where it should go in that case.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Rich Shepard wrote:

  I understand the concept of namespaces, and I think that I now have a good handle on scope. It's finding non-trivial applications from which I can see
how to do what I'm trying to do that has been difficult.

non-trivial examples are needed to help figure out how you want to structure you code, but many of the errors you have posted here are namespace issues. I think they result due to re-factoring, so the seem name doesn't mean the same thing in a different context.

  The two things I've not yet mastered, and they're simple but critical
concepts are 1) how to call the function in a different module (.py)

umm:

import modulename
modulename.functionName(...)

There's got to be more to your confusion.

> and

whether that module needs a class to contain all the functions,

ahh -- I think this may be it.

No a module doesn't need a class to contain all functions (example above -- no class). However, the only time I'd put a function in a module outside of a class is when it is a simple "takes input, gives output" function:

def square(x):
     return x*x

If the function needs to manipulate a dataset, then you need to keep track of that data somewhere. We're using an OO language, so that somewhere is a class. In theory, you can manipulate data in the module namespace directly, but then you need to use global all over the place, and you can't have more than one version (instance) of your data.

So most of the time, I have classes in my modules. If it looks like a application is going to have only a single instance of a class, and I want to be able to access that instance from a number of places in my code ( I use this for configuration data, for instance), I'll create and instantiate a class in a module on import:

#ConfigData.py
class SomeDataClass:
      ...

AppData = SomeData()

Now, in any other module, I can do:

import ConfigData

AppData = ConfigData.AppData

AppData.GetSomething()

AppData.AddSomething()

etc, etc.

2) how to implement the called function.

Well, there's no general advise for that! except maybe standard OO design -- a class holds a set of data, and the methods for manipulating that data.

it's tripping
me up everytime I try to move a method (such as creating a new database or
opening an existing one) out of the module/class that displays the button
(or menu item) to invoke that method

Well, creating and Opening a database sounds like something that should be done in some kind of Model class:

class MyDataBase():
     ....
     def OpenDataBase(self, DataBaseToOpen):
         ....

Somewhere you create an instance of the MyDataBase class -- maybe in the App OnInit -- or maybe when there is a GUI event that triggers the creation.

Now in your GUI class:

...
class GUI_Element(wx.Something)
     def __init__(self, Database, ...)
         self.DataBase = Database
         # database is an instance of class MyDataBase
         ...

         OpenButton.Bind(wx.EVT_BUTTON, self,OnOpenButton)
     ...
     def OnOpenButton(self, event)
         ...
         <get name of database to open somehow...>
         self.DataBase.OpenDataBase()

So all the GUI_Element class knows is that it has a MyDataBase instance as a member, and what methods that class has that it can call. all the details of how the data is implemented are inside the MyDataBase class.

Does this help any?

Happy Thanksgiving,

you too, I hope you can put this down for a few days!

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov