Fixing Python’s DeprecationWarning sha

I thought I fixed this few days ago, but apparently I totally forgot to run the tests.

First time I have to go around a DeprecationWarning, and I thought it was cool to share. Maybe I’m totally doing it incorrectly, but at least I used a lambda! Whee!

../mysql/connector/protocol.py:21: DeprecationWarning: the sha module is deprecated; use the hashlib module instead

try:
from hashlib import sha1
except:
import sha
sha1 = lambda s: sha.new(s)

print sha1('geert').digest()

Update 2009-10-01: I’ve changed the above code yet again to make it simpler and more conform to PEP 8 which says to use ImportError exception (thanks to Marius for this tip!):

try:
from hashlib import sha1
except ImportError:
from sha import new as sha1

Getting illegal dates from MySQL with Connector/Python

Today we received a bug report saying that we shouldn’t throw an exception but instead return what MySQLdb is returning. Bit research and MySQLdb is actually returning None for illegal dates: good!
There is now a fix (showing up soon) on Launchpad which will return dates as None where they are inserted as '0000-00-00'.
A few lines of Python:

..
data = [
(datetime.now().date(),datetime.now()),
('0000-00-00','0000-00-00 00:00:00'),
('1000-00-00','9999-00-00 00:00:00'),
]

for d in data:
stmt_insert = "INSERT INTO %s (c1,c2) VALUES (%%s,%%s)" % (tbl)
try:
cursor.execute(stmt_insert, d)
except (mysql.connector.errors.InterfaceError, TypeError) as e:
print "Failed inserting %s\nError: %s\n" % (d,e)

if cursor.warnings:
print cursor.warnings
..

The script outputs the following data, and notice also the warnings (SQL Mode set to NO_ZERO_IN_DATE,NO_ZERO_DATE):

[(u'Warning', 1265L, u"Data truncated for column 'c1' at row 1"),
(u'Warning', 1264L, u"Out of range value for column 'c2' at row 1")]
[(u'Warning', 1265L, u"Data truncated for column 'c1' at row 1"),
(u'Warning', 1264L, u"Out of range value for column 'c2' at row 1")]
(datetime.date(2009, 9, 30), datetime.datetime(2009, 9, 30, 15, 12, 23))
(None, None)
(None, None)

Another change we did today was returning a row as tuple, and rows as list of tuples.

Tip: use STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE SQL modes in MySQL 5.0 and later for new projects to make sure no illegal dates are inserted, or fix your application.

MySQL Connector/Python and Windows: kinda works

I didn’t test MySQL Connector/Python on a Microsoft Windows machine, but after somebody did and filed a bug report, I couldn’t resist launching VirtualBox.

Fixing the problem with socket.MSG_WAITALL not being available on Windows wasn’t much work. However, adding support for MySQL’s Named Pipe on Windows seems to be a bigger challenge.
I couldn’t find docs for win32api anymore on Python’s doc website for win32api, which is referenced everywhere, so I guess somebody needs to give a hint or write a patch.
For now, Windows users of Connector/Python should use TCP to connect to MySQL.

How to install MySQL Connector/Python

Currently, MySQL Connector/Python is only available through Launchpad. Here’s a small how-to for installing it using the Bazaar bzr client tool. All you need is a machine with Python installed (v2.3 or higher, but not v3.x), and.. well, that’s it!

bzr checkout lp:~mysql/myconnpy/main myconnpy
cd myconnpy
python setup.py install

Please check it out. It’s not feature complete yet, and probably can use some code optimizations here and there. I’m looking forward to bug reports! Also, only works with MySQL 4.1 and above.

Here is a little script that shows how it works, save it in file test_myconn.py:

import mysql.connector

if __name__ == "__main__":
  db = mysql.connector.Connect(host="localhost",
    user="root",password="",database="test")
  cursor = db.cursor()
  cursor.execute("SHOW ENGINES")

  for row in cursor.fetchall():
    print row

  cursor.close()
  db.close()

Execute it like this and you should see the available storage engines:

shell> python test_myconn.py
[u'InnoDB', u'YES', u'Supports transactions, row-level locking, and foreign keys', u'YES', u'YES', u'YES']
[u'MRG_MYISAM', u'YES', u'Collection of identical MyISAM tables', u'NO', u'NO', u'NO']
[u'BLACKHOLE', u'YES', u'/dev/null storage engine (anything you write to it disappears)', u'NO', u'NO', u'NO']
[u'CSV', u'YES', u'CSV storage engine', u'NO', u'NO', u'NO']
[u'MEMORY', u'YES', u'Hash based, stored in memory, useful for temporary tables', u'NO', u'NO', u'NO']
[u'FEDERATED', u'NO', u'Federated MySQL storage engine', None, None, None]
[u'ARCHIVE', u'YES', u'Archive storage engine', u'NO', u'NO', u'NO']
[u'MyISAM', u'DEFAULT', u'Default engine as of MySQL 3.23 with great performance', u'NO', u'NO', u'NO']

Fixing iPhoto’s AlbumData.xml for importing into Google’s Picasa

Yesterday I gave Google’s Picasa again a try. Importing my iPhoto library I ran into the now infamous error message: “corrupted AlbumData.xml”. The Apple support website has some tips on how to fix this, but it’s too vague. Luckily there are smart people out there and I stumbled upon a good way in the Picasa help forums to debug your AlbumData.xml using TextWrangler.

  1. Install TextWrangler if you haven’t already.
  2. Open your iPhoto Library using Finder: right-click (Ctrl-Click) and select ‘Show Package Contents’. Copy the AlbumData.xml file to your desktop.
  3. Open the AlbumData.xml from on your Desktop using TextWrangler.
  4. From the Text-menu, choose ‘Zap Gremlins’.
  5. Deselect ‘Non-ASCII Characters’ and select ‘Replace with: •’.
  6. Wait for TextWrangler to finish the zapping! Can take a while.
  7. When done, search (Cmd-f) for occurrence of the • (Option-8)
  8. Open iPhoto and fix wherever you find a dot in the copy of AlbumData.xml

If you are lucky, you’ll find quickly the character that is bugging Picasa. I had only one of these Gremlins in the XML file.

So, I gave Picasa a try, but it failed importing captions of the pictures, only tags. I haven’t found a fix/workaround for that, so it’s a no-go for me still.