Tao of the Machine

Programming, Python, my projects, card games, books, music, Zoids, bettas, manga, cool stuff, and whatever comes to mind.

To generate or not to generate

Yesterday's "generator puzzle" prompted several people to send in solutions, none of which worked. ;-) This problem is trickier than it seems.

In the meantime, I came up with a far-fetched solution myself. Let's recap: I want to write a portable application, that works in Python 2.1, 2.2 and 2.3. One object could benefit from the use of generators, so I want to include these generator methods if generators are present (in 2.2 and up), and exclude/ignore them in earlier versions.

Sounds easy, right? Not really. The code presented yesterday doesn't work, because the __future__ import must be the first line of the file. What about inspecting sys.version?

use_generators = sys.version_info[:2] > (2, 1)

    class Foo:
        ...
        if use_generators:
            # define generator-using methods
That would work, for 2.1 and 2.3, but not for 2.2 which needs a __future__ import statement.

The solution I came up with is:

  1. Create a generator-using file gen22.py with __future__ import and a class GeneratorMixin. This class has generator-using methods.
  2. Create a 2.1-friendly file gen21.py with class GeneratorMixin. This class doesn't define anything at all, or maybe non-generator versions of the 2.2 GeneratorMixin methods.
  3. In your main file, use this code like this:
# portable-generators.py

import sys

print sys.version_info
if sys.version_info[:2] > (2, 1):
    from gen22 import GeneratorMixin
else:
    from gen21 import GeneratorMixin

class Foo(GeneratorMixin):
    # this will now have generator methods for 2.2+,
    # but not for 2.1 and lower
Lots of work for something relatively simple. It's good to see that it *is* possible, after all, but I won't push generators for my app if not strictly necessary or very beneficial.

Posted by Hans Nowak on 2003-01-31 19:35:25   {link}
Categories: Python

More Swing

More Swing hacking today. This time I tried a more complex example, ListDialog. Conversion to Jython went without much trouble. Jython maps very well to Java, and the Swing documentation is excellent.

In spite of that, I will probably stick with wxPython as my main GUI for Firedrop... for now at least. Getting a Swing implementation to work will probably take too much time. However, once I got a rudimentary version working, I will consider adding a second GUI in Swing. In other words, Firedrop may have multiple front-ends, one in wxPython, one in Swing, maybe even more.

This led to an interesting puzzle, aside... the FDB had two methods using generators, which are Python 2.2+. Jython, however, covers Python 2.1 (without generators). Problem: find a portable way to include the generator methods if generators are available, and exclude them if not.

Obvious solutions like

try:
    from __future__ import generators
    use_generators = 1
except:
    use_generators = 0

# later...
if use_generators:
    # define generator-using methods here
don't work, because the __future__ statement must be the first (non-comment, non-empty) line of the file.

Posted by Hans Nowak on 2003-01-30 23:24:59   {link}
Categories: Python

A fling with Swing

After peeking at some example code in the Jython book, I decided to try my hand at converting the first example from a Swing tutorial. It was shockingly easy to convert the Java code! Granted, the example isn't very convoluted, but it speaks for the power of Jython that this can be so easy. As expected, the Python code is a bit more readable too, mostly because of events that can be methods rather than something wrapped in an ActionListener.

For those who are interested, here's the code. It works, although it may not be perfect. (For example, you have to call main() after creating the class, to make everything visible. Shouldn't that have been in __init__?)

Posted by Hans Nowak on 2003-01-29 23:03:20   {link}
Categories: Python

Ooey GUI

In my search for a suitable GUI for Firedrop, we have the following contenders:
  • Tkinter
  • wxPython
  • Jython/Swing
  • Delphi
I want to decouple the GUI from the functionality. (That is always a good idea, but it doesn't always come out in the actual implementation.) My plan is to design the most important parts of the GUI first (basically the main window). I will use a "mock" Firedrop class, that has no actual functionality. The GUI will have an instance of this class and call methods on it. The class itself should not need to know about the GUI.

Which makes me wonder, maybe I can write multiple GUI front-ends... but I digress.

I don't want a really complex GUI. In spite of that, Tkinter as-is doesn't really look up to the job; maybe with Pmw. wxPython would be a better candidate, but will it work on the Mac? That may be very important because I might want to develop parts of the app there. Delphi is cool, but restricts the app to Windows. Jython and Swing is looking better and better. I don't know much about Java, but using some simple Swing classes doesn't seem too difficult. Of course I may be wrong, so some experimentation is required. Jython would actually have some cool benefits... you can compile the eventual "product"... and it will/should work on any system that has a recent Java VM. The Jython examples work flawlessly on my Mac. ^_^

So, I will need to do some more experimentation first... also, the GUI design isn't quite done yet. More later.

Posted by Hans Nowak on 2003-01-29 10:47:36   {link}
Categories: Firedrop

The new frame

Magic the Gathering card frames will change. As expected, many people protested, and as expected, Mark Rosewater explains why the new frames are a good idea. Curiously, he repeatedly brings up that the new font is more readable "from a distance". Yes, I always put Magic cards a few feet away and then try to read them, I'm sure others do too. Also, one alleged reason is that the textures of the frames don't always match the "flavor of the colors". "Look at a white card, for example. The background is a lace doily. What does a doily have to with white's flavor? I have no idea." Maybe you should have thought of that earlier. This "lace doily" has been the hallmark of white for ten years, and has appeared on more than a thousand different cards.

Then there's this:

"Probably the biggest aesthetic change with the new card frames is that the focus is now more clearly on the art. For starters the art box is larger, but more importantly the card frames now focus the eye to the art. This is why, by the way, I don't agree with the assessment that the new frames are less "fantasy" than the old ones. I believe that the fantasy focus is merely different. The old frames added fantasy elements all over the card. The new frames instead draw the focus to the one card element that I believe is the most effective in capturing the fantasy flavor: the art."
Yes, except that the art all too often is *not* fantasy-related. At least with the original font, cards always had a fantasy flavor, even if the art did not. It was a consistent fantasy element on the card. That is gone now.

The new design isn't bad. One could wonder if it was necessary though.

Posted by Hans Nowak on 2003-01-27 09:30:50   {link}
Categories: CCGs

It's on

Introducing: FDB, the Firedrop Database. This is a (very) simple OO database system, that will be used in Firedrop (and maybe in Kaa, although Firedrop will probably make Kaa obsolete).

FDB uses the underlying file system to store files. Files are stored in subdirectories ("sections") under the root directory. Files whose names match the regular expression "^\d\d\d\d\d$" (five digits, basically, like "00001" or "82934") are considered to be "entries" (or "nodes", in FDB-speak), and are seen by the database if you loop over all entries, or over all entries in a section. Files with other names are not seen directly, but can be retrieved on demand. This allows us to store all kinds of things in a section directory without corrupting the database.

You "connect" by simply creating an FDB object with a root directory. You must also specify an encoder and decoder. By default, these are a pickler and an unpickler (yes, from the pickle module). FDB stores and retrieves Python objects, and it does so by serializing them. Currently (and by default) pickle is used, but Firedrop may use a custom serializer that is less powerful but more readable (and editable).

Some trivial example code:

f = fdb.FDB("testdb")

user = User(name="John", age=32) # some user object
# store in 'users' section with id 100
f.save("users", 100, user)

# store 42 in 'foo' section with auto-generated id
id = f.save("foo", -1, 42)

# retrieve that value again
value = f.get("foo", id)

# loop over all nodes
for (section, id, node) in f.get_all():
    # do something with node

This system is unorthodox, but I wanted a database that was as open as possible, in many ways. You can inspect and even edit files (nodes) directly, drop new stuff in a directory to add a node, add a section by creating a subdir, etc. Also, from within Firedrop (and its embedded code, templates, etc) it will be easy to access any entry you want. Thus, writing embedded code will be easier.

The system is not super fast, nor is database integrity high on its agenda. It's easy to mess up a database if you don't know what you're doing (but meddle around anyway). So don't do that, then. :-) But if you do know what you're doing, you're not stopped by obscure file formats.

I have interesting plans for Firedrop. But it will take a while to design it and write it. I haven't even decided on the GUI yet. If any (!). ;-)

Posted by Hans Nowak on 2003-01-25 22:03:49   {link}
Categories: Firedrop

--
Generated by Firedrop2.