Posts about python (old posts, page 19)

2008-08-20 11:34

Lessons learned in a month of hobby programming

A little over a month ago, on July 15th, I opened a Google Code project called uRSSus. Here's the commit. My goal was to try building a desktop application like if I were building a web application, using a ORM, templating, generic views, and other things.

The first thing I learned is that it was more fun to just write the application and see it grow than spending time writing the framework needed to do what I wanted, so I just kept the ORM, and the rest is pretty traditional code.

The second thing I learned is that for a hobbyist programmer, this is a golden age. I am not exactly an awesome programmer myself, and with today´s tools, I could almost wish my app into existence. When I started programming on a PC, I had to swap floppies to change from the IDE to the compiler [1]. And if I made a mistake, the computer crashed. No, not the program. The computer crashed.

Now? I get a pretty dialog, a link to the position, a stack dump, etc, etc, etc. Not missing the old days at all.

Another way this is a golden age is that there is a lot of code out there. I literally had to learn my code from books. I first "got" C by reading the help for a pirated copy of Autodesk Animator's POCO extension language. There were no collections of code I could look at and learn. There were not even any large libraries of code I could legally use!

And that´s another reason why this is a golden age: Open Source and Free Software. You really can be a programmer just by willing it and effort. You will not lack tools, you will find users (if you are good), you will find helpers (if you are lucky), you will find free infrastructure (svn repos, free wikis, free file hosting, free everything), you will find libraries you can use!.

The third thing I learned is that Python does come with batteries included. Many things that would be annoying effort in other languages are just there, ready to be used. Add the internet, and it´s a Mr. Fusion instead of a battery.

The application I developed is a News aggregator and thanks to Mark Pilgrim I had Feed Parser and thanks to Troll Tech (Now Nokia) I had Qt for the UI, and many many other things. I could focus on application logic, not on parsing and drawing.

The fourth thing I learned is that a month is a long time when you have productive tools. Urssus (that's my application) was functional (but awful) in a day or two. It was not awful in 2 weeks. It was pretty good in 3.In a month? Download it and see for yourself, I like it, the SVN version is much better most of the time, try revision 619 ;-)

The fifth thing I learned is that Python performance is good enough. I don´t see much performance difference between uRSSus and, say, Akregator, which is C++, except on places which are obviously broken. Sure, the database is C, the UI toolkit is C++... they are all black boxes to me here. I code Python. My pieces do well.

The last thing I learned is that I can still code free software. I had not written a useful/usable large free software application in perhaps 8 years. I am 36.9 years old... excuse me if I feel middle-aged, surrounded by youngsters which are faster, more dedicated and actually have free time.

Because of the productivity of the tools, I managed to code just a couple of hours a day for the first weeks, and progress was still good, so I didn´t get discouraged, which is the worst enemy of free software.

It has been a fun experiment, hopefully it will be a fun ongoing hobby.

[1] Can you guess what I was using?

2008-08-12 22:22

uRSSus: is that an icon in your pocket?

Yes, sometimes I think a feature is much harder than it really is.

urssus21

So, since revision 571, every once in a while a new favicon will appear in your feed tree when you use uRSSus. No, they won't all appear at once. They will appear whenever:

  1. You actually fetched new posts from a feed
  2. You restart the app

Once they appear they will never change, either.

2008-08-12 21:46

urssus at 27 days old

After 27 days of development, uRSSus is finally a really usable app. I miss nothing from Akregator, although there are a few unimplemented things. It was broken the alst couple of days, because I was rewriting large chunks of its guts, but the new guts work much better ;-)

The missing pieces (I know about):

  • Favicons
  • Save column width in post list
  • Show total posts in feed list
  • Drag&Drop is not reliable (weird things happen every few tries)
  • Metafeeds (ex. your unread posts/ your starred posts) are not updated automatically
  • Del.icio.us sync is not working at all
  • No help
  • No decent config dialog (but a functional replacement!)
  • Very occasional DB locking.
  • Logging is broken
  • Need to implement backup of the DB

That's not really more than a day or two of work.

Right now (revision 570) it's working pretty good, so it's a good revision to try, if you feel up to it.

2008-08-11 11:06

Urssus goes meta!

I have been delaying this functionality because I expected it to be hard to do, then... it was very easy! Now you can create "metafeeds" based on queries. Here's the first example: "Post.important==True".

urssus20

Of course, beyond a set of standard metafeeds, a UI to allow the user to create them will be hard but at least the basic functionality is there (BTW, it's 15 (fifteen!) lines of code)

2008-08-11 10:34

Pickling can be expensive

When trying to serialize python data, often the first thing we look at is pickle. Well, sometimes pickle can be very expensive!

Here Post is an elixir class, which means it's an object mapped to a relational database, and comparing its properties to something is pretty much a piece of a SQL WHERE statement.

>>> print Post.important==True
posts.important = ?

What happens when we pickle it?

>>> print len(pickle.dumps(Post.important==True))
27287
>>> print pickle.loads(s)
posts.important = :important_1

Yikes. What's a better solution?

>>> print eval('Post.important==True')
posts.important = ?

As long as we are sure no weird data will get into the eval...

2008-08-08 22:55

uRSSus: first post 0.2.10 features (has screenie)

It's running prety stable (at least for me) so I decided to fix some issues and add some features. First a screenshot:

urssus19

And now text:

  • A new feature that also fixes an issue:

    vgarvardt asked about sorting by feed,for example when reading a folder. Implemented it using a "feed" column that you can enable/disable. Since your choice is persistent, there's no need to add a configuration option to the dialog.

  • Important is now Starred. I relly like google's idea of using stars at hand to mark things important. So, there they are. The star icon I did myself, in Inkscape, trying to respect the Reinhardt style. I think it looks nice.

  • Google News feeds! Yes, I know I could just go to http://news.google.com, make a search and subscribe to the results page. Can my mom? Nope. So, when adding new feed, just choose "Create google news feed" enter some keywords, and it's ready.

    I need to add "custom fields" to the feed config dialog, though, since once it's creted it's just a regular feed with a long URL.

  • Also did some performance and reliability work, and current SVN (r476) is actually quite a bit nicer than 0.2.10 already. So there may be another release soonish.

2008-08-08 14:41

uRSSus 0.2.10 is out!

Yes friends, my desktop feed agregator uRSSus has a brand new release.

You can get it at http://urssus.googlecode.com or http://pypi.python.org or via easy_install.

There is a rather large bug in that the configuration dialog may or may not work for you. Don't worry, there is no life-or-death option there, just ignore it.

As always, I am looking for a hand making it work well on Windows and Mac.

Let me know if you like it (or if you don't).

2008-08-06 17:12

uRSSus: now with configuration dialog goodness!

I felt that a "user-friendly" configuration dialog for uRSSus was not a good way to spend effort, because I expect options to change often for a while, and I didn't want an outdated dialog, either. The solution? Autogenerate a mediocre configuration dialog!

First, define what options uRSSus supports (Update: suggestion by Alejandro Cura, using tuples works much better!):

options = (
  ('ui',
    (
      ('alwaysShowFeed',  ('bool', False, "Always show a link to the post's feed when diplaying a post")),
      ('hideOnTrayClick', ('bool', True, "Hide the main window when clicking on the tray icon")),
    )
  ),
  ('options',
    (
      ('defaultRefresh'      ,  ('int', 1800, "How often feeds should be refreshed by default (in seconds).", 300, None )),
      ('maxPostsDisplayed'   ,  ('int', 1000, "Limit the display to this many posts. If set too high, opening 'All Feeds' may take forever", 0, None)),
      ('defaultExpiration'   ,  ('int',    7, "How long should articles be kept by default. (In days)", 0, 9999)),
    )
  ),
  ('twitter',
    (
      ('username',  ('string', None, 'Your Twitter user name.' )),
      ('password',  ('password', None, 'Your Twitter password.' )),
    )
  )
)

Then a little magic, and this comes out:

urssus13

How magic? This magic:

class ConfigDialog(QtGui.QDialog):
  def __init__(self, parent):
    QtGui.QDialog.__init__(self, parent)
    # Set up the UI from designer
    self.ui=UI_ConfigDialog()
    self.ui.setupUi(self)
    pages=[]
    sections=[]
    self.values={}

    for sectionName, options in config.options:
      # Create a page widget/layout for this section:
      page=QtGui.QScrollArea()
      layout=QtGui.QGridLayout()
      row=-2
      for optionName, definition in options:
        row+=2
        if definition[0]=='bool':
          cb=QtGui.QCheckBox(optionName)
          cb.setChecked(config.getValue(sectionName, optionName, definition[1]))
          layout.addWidget(cb, row, 0, 1, 2)
          self.values[sectionName+'/'+optionName]=[cb, lambda(cb): cb.isChecked()]


        elif definition[0]=='int':
          label=QtGui.QLabel(optionName+":")
          label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter)
          spin=QtGui.QSpinBox()
          if definition[3] is not None:
            spin.setMinimum(definition[3])
          else:
            spin.setMinimum(-99999)
          if definition[4] is not None:
            spin.setMaximum(definition[4])
          else:
            spin.setMaximum(99999)
          spin.setValue(config.getValue(sectionName, optionName, definition[1]))
          layout.addWidget(label, row, 0, 1, 1)
          layout.addWidget(spin, row, 1, 1, 1)
          self.values[sectionName+'/'+optionName]=[spin, lambda(spin): spin.value()]

        elif definition[0]=='string':
          label=QtGui.QLabel(optionName+":")
          label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter)
          text=QtGui.QLineEdit()
          text.setText(config.getValue(sectionName, optionName, definition[1]))
          layout.addWidget(label, row, 0, 1, 1)
          layout.addWidget(text, row, 1, 1, 1)
          self.values[sectionName+'/'+optionName]=[text, lambda(text): unicode(text.text())]

        elif definition[0]=='password':
          label=QtGui.QLabel(optionName+":")
          label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter)
          text=QtGui.QLineEdit()
          text.setEchoMode(QtGui.QLineEdit.Password)
          text.setText(config.getValue(sectionName, optionName, definition[1]))
          layout.addWidget(label, row, 0, 1, 1)
          layout.addWidget(text, row, 1, 1, 1)
          self.values[sectionName+'/'+optionName]=[text, lambda(text): unicode(text.text())]

        help=QtGui.QLabel(definition[2])
        help.setWordWrap(True)
        layout.addWidget(help, row, 2, 1, 1)
        separator=QtGui.QFrame()
        separator.setFrameStyle(QtGui.QFrame.HLine|QtGui.QFrame.Plain)
        layout.addWidget(separator, row+1, 0, 1, 3)
      page.setLayout(layout)
      pages.append(page)
      sections.append(sectionName)

    for page, name in zip(pages,sections) :
      # Make a tab out of it
      self.ui.tabs.addTab(page, name)
    self.ui.tabs.setCurrentIndex(1)
    self.ui.tabs.removeTab(0)

My first ever thing that I just don't see how it would work without a lambda ;-)

2008-08-04 15:43

Urssus: Sorry about 0.2.9

Truly a paperbag release. But there's still hope!

While 0.2.9 had a number of bugs and awful performance, I have to say that the current svn revisions are much, much, better.

  • Snappy performance (ok, not quite snappy, but snappier than 0.2.0)
  • Finally a coherent nex/previous/whatever mechanism. The only broken piece is that posts may vanish from view when the feed is updated (and I can fix that, too).
  • Fixed issues 16,14 and 22

So, 0.2.10, coming tonight, should be a pretty good one.

Contents © 2000-2018 Roberto Alsina