wxPython Coding Guidelines

HI all,

Robin just reminded us of the wxPython Coding Guidelines page in the Wiki. As it happens, I had just started a little style guide with my ideas about how to write modern pythonic wxPython code.

The Coding Guidelines currently in the Wiki cover the usual stuff about how to style your code, but nothing wxPython specific. As wxPython has evolved over the years, a number of changes have been introduced that make the code cleaner, clearer, and more pythonic. Unfortunately, as the various demo code out there has been written over the years, it's not always clear to new users (or old users) what the best style is.

My goal is for us to come to a consensus (with Robin the ultimate decision maker) about what is good wxPython style, then ideally, we can all work together to go back and edit the demo, wiki, etc, to make it consistent with this style. That's a bit ambitious, but perhaps we can at least get new code in the wiki, etc to be a consistent style.

I'll kick this off my submitting my first thoughts on good wxPython style. Please add your suggestions and discussion of mine, where you might disagree.

-Chris

A Style Guide for wxPython
   --Chris Barker (Chris.Barker@noaa.gov)

This is a little style guide for using wxPython. It's not the be-all and
end-all of how wxPython code should be written, but I what I've tried to
capture is away to write wxPython code that is clear and Pythonic.

1) Use "import wx" NEVER use "from wxPython.wx import *".
    Don't use "import *" for other libs either.

2) Use keyword arguments in constructors:

    MainFrame = wx.Frame(None, title = "A Title", size = (500, 400))

    This lets you avoid putting in a bunch of unneeded defaults, like:
    wx.DefaultSize, wx.DefaultPosition, wx.ID_ANY, etc.

3) Don't use IDs. There is very rarely a good reason to use them.

   a) Most Widget constructors will fill in a default ID for you, so you
   don't have to specify one at all. Other arguments can be specified as
   key word arguments (see above):

   MyFrame = wx.Frame(None, title="A Title", size = (400,400))

   AButton = wx.Button(self, label="Push Me")

   b) If the id is a required argument, use wx.ID_ANY. wx.ID_ANY == -1,
   but I like to use it because it makes the code very clear. And who
   knows, maybe that magic value will change one day.

4) Use the Bind() method to bind events:

    a)
    AButton = wx.Button(self, label="Push Me")
    AButton.Bind(wx.EVT_BUTTON, self.OnButtonPush)

    b) You can use Bind() for menus too, even though they don't have a
    Bind() method, in this way:

    FileMenu = wx.Menu()

    item = wx.MenuItem(FileMenu, wx.ID_ANY, "&Quit")
    FileMenu.AppendItem(item)
    self.Bind(wx.EVT_MENU, self.OnQuit, item)

    (where self is a wx.Frame)

5) wx.App() now has the same built in functionality as wx.PySimpleApp(),
    so there is no need for the later.

7) Use Sizers!

6) Use separate, custom classes rather than nesting lots of wx.Panels in
    one class. If you find yourself doing this in an __init__:

    self.MainPanel = wx.Panel(self, ...
    self.SubPanel1 = wx.Panel(self.MainPanel, ..)
    self.SubPanel2 = wx.Panel(self.SubPanel1, ...)
    MyButton = wx.Button(self.SubPanel2, ....)

    Then you are creating an ugly, hard to maintain mess! Instead, create
    custom classes for the stuff that all is working together in a panel:

    class MainPanel(wx.Panel):
        ....

    class SubPanel1(wx.Panel):
        ....

    etc.

    You'll also find that by doing this, you're less likely to break the
    "Don't Repeat Yourself" (DRY) principle. Often you'll find that you
    have group of widgets that are common to various parts of your
    app. If you put them on a custom panel, you'll be able to re-use that
    code.

7) Here's a very small sample demonstrating this style:

#!/usr/bin/env python2.4

import wx

class DemoFrame(wx.Frame):
     """ This window displays a button """
     def __init__(self, title = "Micro App"):
         wx.Frame.__init__(self, None , -1, title)

         MenuBar = wx.MenuBar()

         FileMenu = wx.Menu()

         item = wx.MenuItem(FileMenu, text = "&Quit")
         FileMenu.AppendItem(item)
         self.Bind(wx.EVT_MENU, self.OnQuit, item)

         MenuBar.Append(FileMenu, "&File")
         self.SetMenuBar(MenuBar)

         btn = wx.Button(self, label = "Quit")

         btn.Bind(wx.EVT_BUTTON, self.OnQuit )

         self.Bind(wx.EVT_CLOSE, self.OnQuit)

         self.Fit()

     def OnQuit(self,Event):
         self.Destroy()

app = wx.App()
frame = DemoFrame()
frame.Show()
app.MainLoop()

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

Hello Chris,

    very nice idea, in my opinion. I agree with all your coding guidelines,
this should be the "standard" way to code. If I may add 2 points to this
discussion, they are:

Point (1):

4) Use the Bind() method to bind events:

    a)
    AButton = wx.Button(self, label="Push Me")
    AButton.Bind(wx.EVT_BUTTON, self.OnButtonPush)

(where "self" is a wx.Frame). There is also another possibility, less nice
and less useful in my opinion, but that is used sometimes (and also some GUI
builders, like wxGlade, use it):

self.Bind(wx.EVT_BUTTON, self.OnButtonPush, AButton)

In general, I don't like this construction, but I can live with it.

Point (2):

<snip>

import wx

class DemoFrame(wx.Frame):
     """ This window displays a button """
     def __init__(self, title = "Micro App"):
         wx.Frame.__init__(self, None , -1, title)

<snap>

         btn = wx.Button(self, label = "Quit")

         btn.Bind(wx.EVT_BUTTON, self.OnQuit )

Usually it is better to place non top-level widgets inside a panel, instead
that directly on a frame. So, I would add simply a wx.Panel() to your demo
and I would place the button on the panel, instead of on the frame. But that
is just a minor point.

Very nice discussion, in my opinion. If it's possible, I would like to
participate in this kind of process of rewriting, even if I am not that
wxPython guru.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77

[snip]

This is a little style guide for using wxPython. It's not the be-all and
end-all of how wxPython code should be written, but I what I've tried to
capture is away to write wxPython code that is clear and Pythonic.

missing reference :wink:
http://www.python.org/doc/Humor.html#zen

1) Use "import wx" NEVER use "from wxPython.wx import *".
    Don't use "import *" for other libs either.

BECAUSE: Namespaces are one honking great idea

2) Use keyword arguments in constructors:

    MainFrame = wx.Frame(None, title = "A Title", size = (500, 400))

    This lets you avoid putting in a bunch of unneeded defaults, like:
    wx.DefaultSize, wx.DefaultPosition, wx.ID_ANY, etc.

BECAUSE: Explicit is better than implicit.

3) Don't use IDs. There is very rarely a good reason to use them.

   a) Most Widget constructors will fill in a default ID for you, so you
   don't have to specify one at all. Other arguments can be specified as
   key word arguments (see above):

   MyFrame = wx.Frame(None, title="A Title", size = (400,400))

   AButton = wx.Button(self, label="Push Me")

   b) If the id is a required argument, use wx.ID_ANY. wx.ID_ANY == -1,
   but I like to use it because it makes the code very clear. And who
   knows, maybe that magic value will change one day.

BECAUSE: Simple is better than complex.

etc...

···

On Thu, 29 Dec 2005 20:25:46 +0200, Christopher Barker <Chris.Barker@noaa.gov> wrote:

Andrea Gavana wrote:

Very nice discussion, in my opinion.

I agree, although I'll withold my comments on various styles until other folks have commented.

If it's possible, I would like to
participate in this kind of process of rewriting, even if I am not that
wxPython guru.

IMHO guru status is not needed for a discussion like this. All that is necessary is having written enough code to have a feeling what works well for you and others reading your code, and what doesn't work well.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

One more thing...
If some kind soul with a little bit of experience with patterns would explain something like MVP with python code.... it would be a lot easier for beginners.
I found through personal experiments that splitting code like that really makes things easier. Unfortunately my understanding of the pattern is somehow limmited.

Peter.

Chris,

   Excellent idea, well written, highly useful. It's also a great template for
others to use as they expand on your core.

Rich

···

On Thu, 29 Dec 2005, Christopher Barker wrote:

I'll kick this off my submitting my first thoughts on good wxPython style.
Please add your suggestions and discussion of mine, where you might
disagree.

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

Robin Dunn wrote:

I agree, although I'll withold my comments on various styles until other folks have commented.

Fair enough, but if you have any ideas that are set in stone, you might as well let us know now!

Also, I just realized that "the book" is coming out soon. Intentional or not, it's likely to become the style guide for the future.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

Hello List:

Chris, I agree with all the points you make. Although it may be
slightly off topic, I would like to raise once more the issue of
indentation (which is, after all , a matter of coding style). For many
years, with many different programming languages, I have always used
tabs for indentation rather than spaces. However, Chris, Robin, and
many other Python experts recommend using 4 spaces. Guido van Rossum
simply says:

"Never mix tabs and spaces. The most popular way of indenting Python
is with spaces only. The second-most popular way is with tabs only."

Here is how I see the trade-offs of using 1 tab versus 4 spaces per
indent level in Python.

1 tab per indent level:

Advantages
- No possibility of being "between levels".

- Each user may display indentation as he prefers, without changing the code.

Disadvantages
- I don't see any.

4 spaces per indent level:

Advantages
- I don't see any.

Disadvantages
- It is easy to accidentally get 3 or 5 space indent. With other
programming languages, this is just cosmetic, but with Python, it may
cause a syntax error.

- Each user is stuck with the same indentation size on screen.

I am prepared to change my opinion on this, but I can't see any
advantage at all to using spaces over using tabs for indentation. Can
someone please enlighten me?

I hope this does not become a tabs/spaces discussion. I was enjoying the topic. :slight_smile:

If you are talking about the proposed coding guidelines: a big advantage is that almost all Python code a newbie is likely to encounter will be indented with spaces. Note that I did not say spaces are better/worse.

Actually, I don't see why this needs to be mentioned in the wxPython Coding Guidelines. It is more applicable to Python as a language.

Regards,
Nate

···

On Dec 29, 2005, at 11:40 AM, Michael Moriarity wrote:

I am prepared to change my opinion on this, but I can't see any
advantage at all to using spaces over using tabs for indentation. Can
someone please enlighten me?

Agreed.

All tabs vs. spaces discussion should be directed at comp.lang.python or
the equivalent python-list mailing list. Also, all those discussing
tabs vs. spaces (and Python style in general) should read PEP 8
(PEP 8 – Style Guide for Python Code | peps.python.org), specifically the 3 line
indentation section.

- Josiah

···

Nate Silva <nate@northwe.st> wrote:

On Dec 29, 2005, at 11:40 AM, Michael Moriarity wrote:

> I am prepared to change my opinion on this, but I can't see any
> advantage at all to using spaces over using tabs for indentation. Can
> someone please enlighten me?

I hope this does not become a tabs/spaces discussion. I was enjoying
the topic. :slight_smile:

If you are talking about the proposed coding guidelines: a big
advantage is that almost all Python code a newbie is likely to
encounter will be indented with spaces. Note that I did not say
spaces are better/worse.

Actually, I don't see why this needs to be mentioned in the wxPython
Coding Guidelines. It is more applicable to Python as a language.

Michael,

   Some editors -- at least Emacs -- insert spaces when the tab key is
pressed. Best of both worlds, I guess.

Rich

···

On Thu, 29 Dec 2005, Michael Moriarity wrote:

"Never mix tabs and spaces. The most popular way of indenting Python
is with spaces only. The second-most popular way is with tabs only."

Here is how I see the trade-offs of using 1 tab versus 4 spaces per
indent level in Python.

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

To a degree, yes. But keep in mind that most people coming into wxPython will be looking at the examples on the web, and will only be buying "the book" if they decide to spend some time with wxPython development. If you're serious about giving everyone a good idea how to do wxPython coding, it's much more important to update all the web examples to match.

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On Dec 29, 2005, at 2:35 PM, Christopher Barker wrote:

Also, I just realized that "the book" is coming out soon. Intentional or not, it's likely to become the style guide for the future.

Ed Leafe wrote:

    To a degree, yes. But keep in mind that most people coming into wxPython will be looking at the examples on the web, and will only be buying "the book" if they decide to spend some time with wxPython development. If you're serious about giving everyone a good idea how to do wxPython coding, it's much more important to update all the web examples to match.

I wasn't suggesting that the book made this effort obsolete, what i was suggesting is that we might want to use the style in the book as the "standard", and update as much as possible to match.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

I don't know where I read this (maybe on www.python.org), that if you specify
parameters, you shouldn't add spaces; only when assigning to variables.

so:
MainFrame = wx.Frame(None, title="A Title", size =(500, 400))

···

On Thu, 29 Dec 2005 10:25:46 -0800, Christopher Barker <Chris.Barker@noaa.gov> wrote:

2) Use keyword arguments in constructors:

   MainFrame = wx.Frame(None, title = "A Title", size = (500, 400))

   This lets you avoid putting in a bunch of unneeded defaults, like:
   wx.DefaultSize, wx.DefaultPosition, wx.ID_ANY, etc.

--
Franz Steinhaeusler

I'll kick this off my submitting my first thoughts on good wxPython
style. Please add your suggestions and discussion of mine, where you
might disagree.

-Chris

Hi Chris,

I like your ideas and I think it is a *very* good idea to talk about this before
updating the wiki. Some other ideas we could add:

1. Don't use SetAutoLayout. It is called implicitly by wxWindow::SetSizer but
many of the cookbook examples still call it.

2. In many examples you find something like that: Create a sizer, create some
controls, add the controls to the sizer and after that call SetSizer. I think it
is better to call SetSizer immedeatly after creating the sizer, so you cannot
forget to do it. There has been some questions on this group, where someone
forgot to call SetSizer. But as always this may be a matter of taste.

3. In Point 7 you are saying use sizers. So perhaps you should add sizers to
your example code :wink:

...we can all work together to go back and edit the demo, wiki, etc, to make it

consistent with this style

I am willing to help on that. Because we are really in need of an updated, more
consistent wiki.

Peter Damoc wrote:
One more thing...
If some kind soul with a little bit of experience with patterns would explain

something like MVP with python code....

I would be very interested in that, too.

Greetings

Guido

Peter Damoc wrote:

One more thing...
If some kind soul with a little bit of experience with patterns would explain something like MVP with python code.... it would be a lot easier for beginners.
I found through personal experiments that splitting code like that really makes things easier. Unfortunately my understanding of the pattern is somehow limmited.

I agree this would be very useful.

···

Peter.

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Hi Chris,

Very good idea.

I have one question:

1) Use "import wx" NEVER use "from wxPython.wx import *".
   Don't use "import *" for other libs either.

Is this also acceptable?
import somepackage.somemodule as myxyz

See you
Werner

Franz,

   I believe that it's on Guido's web page where he writes about his
preferences.

Rich

···

On Fri, 30 Dec 2005, Franz Steinhaeusler wrote:

I don't know where I read this (maybe on www.python.org), that if you specify
parameters, you shouldn't add spaces; only when assigning to variables.

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

Yes, since all you are doing is creating another name for the module; you're not polluting any other namespaces.

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On Dec 30, 2005, at 8:54 AM, Werner F. Bruhin wrote:

Is this also acceptable?
import somepackage.somemodule as myxyz

Christopher Barker schrieb:

3) Don't use IDs. There is very rarely a good reason to use them.

  a) Most Widget constructors will fill in a default ID for you, so you
  don't have to specify one at all. Other arguments can be specified as
  key word arguments (see above):

I am trying to avoid IDs but I have no idea how I can avoid them in this example:

        new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize)
               tb.AddSimpleTool(10,new_bmp, "New", "Long help for 'New'")
        self.Bind(wx.EVT_TOOL, self.addTodo, id=10)

Please, can somebody give me a hint. Many thanks.

Ralf Schoenian