Archive for the ‘TurboGears’ Category

Beep My Stuff enters public Beta

Thursday, April 2nd, 2009

Beep My Stuff

Beep My Stuff


After a rather long period in closed beta I've opened Beep My Stuff to a public beta.

Beep My Stuff is a web site that makes it FREE and easy to create an online library of your Books, Movies, Video Games and Music. Check it out, all feedback is much appreciated.

It's built with Turbogears, SQLAlchemy, Genshi and countless other python modules. It's all sitting on Python, FreeBSD and PostgreSQL.

Just wanted to say thanks to all the pythonista's out there that helped me get this far :)

Mutlipart file upload in Turbogears 1.0.x

Monday, March 16th, 2009

When uploading files to Beep My Stuff using SWFUpload I was getting this error:

data = self._sock.recv(self._rbufsize)
timeout: timed out

Uploading files to a TG1.0.x app is easy unless you want to do something nice like use SWFUpload to allow multiple files to be selected for upload.

The reason for this is that Flash has interpreted RFC 2046 one way and they python libraries/CherryPy interpret it another. Fortunately this is fixed in Turbogears 1.1+ but I am using 1.08 at the moment for Beep My Stuff so I needed a fix.

There is a patch in CherryPy that can be used to fix the problem and Chris Arndt has created a patch for TG1.1. You can easily apply the same code to your TG1.0x app to fix this problem as well.

Visit here and copy the contents of safemutlipart.py into a file in your project. Then you need to install the filter when Turbogears is starting up. Something like this will do the trick:

#force the multipart filter to be installed.
def install_safemutlipartfilter():
    from cherrypy import root
    root._cp_filters.extend([SafeMultipartFilter()])
 
def install_multipart_filter():
    from turbogears.startup import call_on_startup
    log.info("Installing multipart filter")
    call_on_startup.append(install_safemutlipartfilter)

Note that the code in SafeMultiPartFilter needs a config change to turn it on so add

safempfilter.on = True

to your app.cfg

hope that helps :)

SQLAlchemy-Migrate upgrade scripts in a transaction

Sunday, July 27th, 2008

SQLAlchemy Migrate is a really good tool for managing database upgrades for SQLAlchemy centric projects. I've been using it for 6 months on New Metal Army and I haven't had a screwed website upgrade yet!

For those that don't know SQLAlchemy-migrate allows you to version control database changes and easily upgrade and downgrade a database. Basically you write a python script with two functions: upgrade and downgrade. You test the script against the database, commit it to the SQLAlchemy-migrate version repository (not to be confused with your source control mechanism). Finally you upgrade your development database.

When it the time comes to deploy the new application you simply ask sqlalchemy-migrate to upgrade your database to the current version. sqlalchemy-migrate reads the current version of your schema from the database (via a custom table it inserts) and proceeds to upgrade your schema by running each upgrade script in turn.

Often you want your upgrades and downgrades to run within a transaction. Not because you expect them to fail but because while writing them you don't wont to leave the database partially upgraded or downgraded if your script fails. To do this I wrote a transaction decorator. Here is a template for an upgrade script:

  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3.  
  4. from datetime import datetime
  5. from sqlalchemy import *
  6. from migrate import *
  7. from migrate.changeset import *
  8.  
  9. metadata = MetaData(migrate_engine)
  10.  
  11. def transaction(f, *args, **kwargs):
  12. def wrapper(*args, **kwargs):
  13. connection = migrate_engine.connect()
  14. transaction = connection.begin()
  15. try:
  16. result = f(*args, **kwargs)
  17. transaction.commit()
  18. return result
  19. except:
  20. transaction.rollback()
  21. raise
  22. finally:
  23. connection.close()
  24.  
  25. wrapper.__name__ = f.__name__
  26. wrapper.__dict__ = f.__dict__
  27. wrapper.__doc__ = f.__doc__
  28. return wrapper
  29.  
  30. @transaction
  31. def upgrade():
  32. pass
  33.  
  34. @transaction
  35. def downgrade():
  36. pass
  37.  

I fill in the upgrade and downgrade functions and I'm done :)

I include the decorator in every script as it's good practice to make your scripts as independent as possible. If you imported it from a module you may improve it in the future and inadvertently break your old downgrade scripts.

I hope this helps you version control your database schema and data.