Archive for the 'Python' Category

Jul 27 2008

My first encounter with py2app

Published by Winni under Mac OS X, Python

As I’ve posted, I’ve recently begun to ‘breed snakes’, meaning that I’m learning Python when I’m in the mood for some private hacking.

My Python and wxPython installations are the default ones that come pre-installed on OS X Leopard. So far, I’ve been avoiding a customized installation.

I’m using the Eclipse/PyDev combo for my editing, and I really, really begin to like it. No offense to anybody else, but Eclipse is one of the three great Java desktop applications that I’ve seen. (The other two are ‘Tribal Trouble’ and ‘Cyberduck’). Eclipse performs very well, and I just like using it. It’s a personal preference - just use whatever you like and prefer and be happy with it. I’m not religious about that stuff. But I also openly say that I’ve yet to see other good Java desktop applications; most of the Java desktop stuff that I’ve come across looks either out of place or is slow or just plainly sucks. But this posting is not about Java.

Coming back to Python. Today, I’ve been toying a bit with wxPython and I wanted to see how easy - or difficult - it is to create a Macintosh application bundle of a wxPython application with py2app.

So I have this mini wxPython source code here that does not much except for drawing an application window - pardon: frame - and showing a Mac-style menu:

   import wx

   class App(wx.App):
      def OnInit(self):
         frame=wx.Frame(parent=None, title='MyTitle')

         frame.menu_bar = wx.MenuBar()
         frame.help_menu = wx.Menu()

         frame.help_menu.Append(wx.ID_ABOUT, "&About MyTitle")
         frame.menu_bar.Append(frame.help_menu, "&Help")

         frame.SetMenuBar(frame.menu_bar)
         frame.Bind(wx.EVT_MENU, self.on_about_request, id=wx.ID_ABOUT)

         frame.Show()
         self.SetTopWindow(frame)
         return True

      def MacOpenFile(self, filename):
         print filename

      def on_about_request(self,event):
         print "About."

   app=App()
   app.MainLoop()


The few lines of Python code above are stored in a file named NNTP.py in my Eclipse project, and the following code is stored in setup.py in the very same project:

   from distutils.core import setup
   import py2app

   setup(
      app=['NNTP.py']
   )


This should be run like so:

   python setup.py py2app


Or, to make your life even simpler, right click on “setup.py” in the Eclipse Navigator, select “Properties”, then “Edit” the “Run/Debug settings” of setup.py, click on “(x)= Arguments” and add “py2app” to the “Program arguments”. “Apply”/”OK” everything. When you now run the script within Eclipse, you won’t see any error messages, but it will actually create the Macintosh application bundle for you. You will find it in the “dist” folder within your project’s structure in the directory that holds your Eclipse workspace.

The good news is that py2app generates a Universal Binary for you, and in my case it runs both on my PowerPC notebook and my Intel Mac Pro.

The bad news are that it is more than 23 Megabytes in size and it does not run on OS X Tiger. The latter does not make me very happy: It makes the deployment of Python application bundles messy at best.

I have also seen this problem before. The Python game Solarwolf, for example, does not run on OS X Leopard; it was built for OS X Tiger (PowerPC) and that is the only version of Mac OS X on which it runs.

This is bad and in my opinion, deployment nightmares like this should have been fixed years ago - on any system and for any development platform. BlitzMax, the so-called game programming language, does a much better job here than Python. Sure, you won’t get a Universal Binary out of the box in BlitzMax (you actually have to compile your app on both an Intel and a PowerPC machine and then have to do some hand work), but at least the application bundle will not only run on one specific version of Mac OS X.

Deploying Python applications is not yet an issue for me, so I’ve got plenty of time to look into this more thoroughly. There probably is a solution, and maybe even a simple one. But I have a mixed first impression nevertheless. On one side, I am quite happy that so far creating an application bundle is relatively simple. On the other side, I am disappointed that a created bundle only seems to work on the OS X version on which it was built.

Well, let’s see what more I will find out when I dive deeper into this.

UPDATE:

The answer is not to use the Python/wxPython/py2app versions that come with Leopard, but the ‘official’ distributions from Python.org and wxPython.org:

1. Download MacPython 2.5.2 from http://www.python.org/ftp/python/2.5.2/python-2.5.2-macosx.dmg and install it.

2. Download wxPython from http://downloads.sourceforge.net/wxpython/wxPython2.8-osx-unicode-2.8.8.1-universal-py2.5.dmg and install it.

3. Download the source tarball version of py2app from http://pypi.python.org/pypi/py2app/0.3.6 and ’sudo python setup.py’-install it.

4. I also made sure that in Eclipse’s preferences in the PyDev section, the Python interpreter ‘python2.5′ in /Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python is used.

(Note: I intentionally did not use hyperlinks here.)

After that, the bundles created on Leopard also run on Tiger.

2 responses so far

Jun 26 2008

I’ve finally begun to breed snakes

Published by Winni under Programming, Python

After long and exhaustive discussions and an even longer period of frustrating experiments with all kinds of curly braces and toy languages, I’ve spent the last couple of days on some more exhaustive and frustrating experiments.

Wanna hear about how lovely Netbeans 6.1 runs on Apple’s Java 6 implementation? Well, maybe it will suffice to say that it runs dog slow on my Quad Core Xeon Mac Pro with 8 GB RAM and that it is like watching a slow motion movie on my PowerBook G4 1.67 GHz with 2 GB RAM.

Netbeans does not even react to keyboard input when it is configure to use JRE/JDK 6. On JRE/JDK 5, it does react to keyboard input, but printing is less than sub-optimal: All letters are out of place and certainly not printed proportional to one another. With Java 6, printing works fine, but you can’t type.

Pardon my sinister sarcasm, but Java’s Swing is so ‘beautiful’ on OS X Leopard that I no longer have any questions why nobody in their right mind wants to use it.

So I’ve deleted Netbeans from my hard disks, and with that I finally buried any fancy ideas about using Java as my programming language of choice for anything.

Seeing that Objective-C is about as attractive as the contents of my bio-waste container, and having to admit that my favorite toy BlitzMax is not leaving its gaming niche anytime soon and neither supports 64-bit CPUs nor multi-threading, I am now going back to trying to breed snakes in my basement.

The Python books are back on my desk, Eclipse Ganymede with PyDev is installed and pyglet, pysqlite2 and PyGreSQL are also ready to be used.

The Eclipse/PyDev combo actually is fun to use, and unlike Netbeans, it runs fast enough even on my PowerBook. And it does not have the printer bug: The release version of Eclipse Ganymede CANNOT even print, the function is grayed out. Now that is a workaround! But may I ask why the SWT framework on which Eclipse is built still does not support printing on OS X? Anyway, other than that Eclipse is a very fine tool.

But more importantly, I’ve already had my first real ‘wow’ with Python today. Just try something like this in your own old fashioned language of choice:

   def MyFunc():
      print "Hello from MyFunc."

   x=MyFunc
   x()

Yes, you are assigning a function to your variable x. Now obviously everything in Python is an object, including functions, and since variables are only pointers to an object, this works.

Now add this to our little program:

   def AnotherFunc(param):
      print param
      param()

   AnotherFunc(x)

It shouldn’t be surprising anymore that this also works, after all we’re only passing the reference to an object as a parameter to the function, even if this object is a function. But coming from languages with many rules and constraints, this now smells like real programmer’s freedom.

No responses yet

« Prev