Deadly Bloody Serious


Default arguments in Python: two easy blunders

Posted in Django, Misc, Python by garth on the May 9th, 2008

I’m glad I stumbled across Patrick Altman’s tweet about a “default bug in Django“. I’d never have guessed you can pass a callable to a field’s default= argument, otherwise. That’s quite a powerful idiom, and I think I’ll use it a lot.

To balance the karma, I’d like to post a quick reminder to everyone else that expressions in default arguments are calculated when the function is defined, not when it’s called. In Patrick’s code, for example, all objects created in the same running session got the same timestamp. Try this in the Python interactive prompt:

>>>import time
>>> def report(when=time.time()):
…     print when
…
>>> report()
1210294387.19
>>> time.sleep(5)
>>> report()
1210294387.19

Until the interpreter quits, you’ll always get the same timestamp. The correct way to go about this is to default to None or some other sentinel, then replace it inside the function:

>>> def report(when=None):
…     if when is None:when = time.time()
…     print when
…
>>> report()
1210294762.29
>>> time.sleep(5)
>>> report()
1210294772.23

Now that you know about that blunder, you should be able to figure out what’s going on with this second classic blunder when using default arguments in Python:

>>> def spam(eggs=[]):
…     eggs.append(”spam”)
…     return eggs
…
>>> spam()
['spam']
>>> spam()
['spam', 'spam']
>>> spam()
['spam', 'spam', 'spam']
>>> spam()
['spam', 'spam', 'spam', 'spam']

Twitter Emergency Backup

Posted in Python by garth on the May 5th, 2008

Dave Winer has been thinking about ways to preserve the Twitter community even when Twitter is down. His latest effort is a web service to save Twitter feeds and expose their content via another feed.

I tried it out, but couldn’t parse the response:

Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import xmlrpclib, urllib2
>>> twittergram = xmlrpclib.Server(”http://rpc.twittergram.com/RPC2/”)
>>> content = urllib2.urlopen(”http://twitter.com/statuses/user_timeline/704593.rss”).read()
>>> twittergram.saveFeed(’garthk’, ‘*****’, content)
Traceback (most recent call last):
  File ““, line 1, in 
  File “/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xmlrpclib.py”, line 1147, in __call__
    return self.__send(self.__name, args)
  File “/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xmlrpclib.py”, line 1437, in __request
    verbose=self.__verbose
  File “/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xmlrpclib.py”, line 1201, in request
    return self._parse_response(h.getfile(), sock)
  File “/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xmlrpclib.py”, line 1335, in _parse_response
    p.feed(response)
  File “/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xmlrpclib.py”, line 547, in feed
    self._parser.Parse(data, 0)
xml.parsers.expat.ExpatError: mismatched tag: line 10, column 7

I’ll investigate later.

I’d love to wade into this kind of problem domain, perhaps using Google App Engine for hosting so I didn’t have to worry about usage spikes. Feed backup is a brilliant start. We also need to helping our followers find the feeds, and I’m sure more thought will yield more areas for funimprovement.

Django vs feedparser on dates

Posted in Django, Python by garth on the September 1st, 2007

I'm having trouble storing feedparser results in a Django model.

It's all about timestamps. Feedparser returns timestamps in a standard time nine-tuple, asserting UTC. Django wants datetime objects. So, I'm trying to translate:

django_timestamp = datetime.datetime.fromtimestamp(time.mktime(feedparser_timestamp))

feedparser_timestamp = django_timestamp.utctimetuple()

This works fine for the majority of timestamps, but sometimes translating to datetime and back mutates the timestamp. In turn, that makes get-if-modified-since somewhat unreliable. Here are some examples, from my log file:

WARNING: (2004, 11, 19, 5, 13, 31, 4, 324, 0) => datetime.datetime(2004, 11, 19, 6, 13, 31) => (2004, 11, 19, 6, 13, 31, 4, 324, 0)

WARNING: (2005, 11, 2, 2, 17, 55, 2, 306, 0) => datetime.datetime(2005, 11, 2, 3, 17, 55) => (2005, 11, 2, 3, 17, 55, 2, 306, 0)

WARNING: (2006, 12, 13, 0, 21, 25, 2, 347, 0) => datetime.datetime(2006, 12, 13, 1, 21, 25) => (2006, 12, 13, 1, 21, 25, 2, 347, 0)

WARNING: (2004, 11, 14, 23, 55, 31, 6, 319, 0) => datetime.datetime(2004, 11, 15, 0, 55, 31) => (2004, 11, 15, 0, 55, 31, 0, 320, 0) 

I'm off by an hour. I smell a problem with daylight savings. I just wish I knew what to do about it. 

I've waved a dead chicken at this one all the ways I know how. Every change I make breaks the conversion entirely. So, I'm throwing this out to the community in the hope that someone can help me. 

Fix: Python Script Arguments Not Passed

Posted in Python by garth on the May 4th, 2007

On Windows, you can run a Python script on the PATH simply with its name. These should be equivalent: 

c:>congeal blood

c:>congeal.py blood

c:>python congeal.py blood

If it's not working that way, fixing PATHEXT and correcting the file type associations with ASSOC and FTYPE will usually do the trick: 

c:>set PATHEXT=%PATHEXT%:.PY

c:>ftype Python.File="C:Python25python25.exe" "%1" %*

c:>assoc .py=Python.File

If that still isn't working, try deleting the following registry key:

HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorerFileExts.PY

There's plenty of advice about PATHEXT, FTYPE, and ASSOC, but none of the search terms I tried dug up the registry key. I knew there had to be one, because giving FTYPE silly arguments didn't stop the script from being executed. I found the registry key by brute-force searching the registry for .PY. I'm posting this so that someone else can save that hour of hassle.

iTunes 7 Considered Harmful

Posted in Apple, Podcasting, Python by garth on the September 14th, 2006

I’ve got good and bad news for Juice users on Windows.

First, the bad news: iTunes 7 breaks Juice. Apple might have changed the COM interface on which Juice relies to do its work, but they haven’t updated the SDK so I can’t find out. Perhaps it’s something in our code. Regardless: If you upgrade to iTunes 7, Juice can’t add downloaded tracks to the library.

(Reinstalling iTunes might help; see the updates below.)

Now, the good news: I upgraded, too. My podcast listening life is going to be a hassle until I fix the bug. I listen to a lot of podcasts, so it’s safe to say I’ll get this one fixed as soon as I can given three factors:

  1. My understanding of win32com not being wonderful;
  2. Apple’s changes, if any, being un-documented until the SDK is revised; and
  3. Me being an old geezer.

For the time being, there’s a relatively easy work-around (if re-installing iTunes doesn’t work):

  • Have Juice download your podcasts as usual;
  • Run iTunes;
  • Select Add Folder to Library from the File menu;
  • Select your My Received Podcasts folder again; and
  • Watch iTunes add your new podcasts to the library.

I’m banging my head against the win32com documentation as I write. We tried using static dispatch with a past version of iTunes, but any iTunes upgrade would break us. We switched back to dynamic dispatch, and that’s worked us fine across plenty of upgrades until now.

If there are any Python experts out there who spend a lot of time with COM and can help me nut this out, please let me know.

Updates:

  • Here’s an odd one: at least one Juice user has upgraded to iTunes 7 without trouble.
  • David Nicolson reports, on the python-win32 mailing list, that he’s seen this occasionally out of iTunes and that uninstalling and reinstalling iTunes usually fixes the problem. I’ve tried it, and it works. I’ll get confirmation from a few others, and publish if it’s not just me succeeding at this.
  • Further to that last one: it mostly works. Unfortunately, the gap is adding tracks. IITPlaylist doesn’t have AddFile any more? Gaaah. My “fixes” obviously aren’t. Time to destroy my makepy cache…(Sub-update: my binary install of 2.2.2a1 works fine, so this might be local to my development version.)
  • There might be other reasons not to upgrade: engadget report other problems with iTunes, including “scratchy playback”. Personally, I haven’t noticed any of the declared symptoms, and I love the scrolling album view.

Bad Behavior has blocked 2370 access attempts in the last 7 days.