Identity model problems while upgrading to TurboGears 1.0b2
If you have, like me, a TurboGears app, which was quickstarted with a TG version from before changeset 1603 was included, you might get bitten by the same problem, which hit me, when I tried to upgrade my TurboGears version from 1.0b1 to 1.0b2.
This changeset apparently changed the Identity model for SQLObject by adding a Visit class that replaces (wraps?) the former VisitIdentity class. Until TG 1.0b1, using only the old VisitIdentity class seemed to work fine and did not produce any warnings I noticed. The new beta relase of TurboGears, version 1.0b2, however, seems to have removed support for this and things will break.
This means, if you upgrade to the new TG version from the previous release 1.0b1 and then try to access you application, you will (in development mode) get a traceback like the following (shortened module pathnames for better readabilty):
File "cherrypy/_cphttptools.py", line 103, in _run
applyFilters('before_main')
File "cherrypy/filters/__init__.py", line 151, in applyFilters
method()
File "turbogears/visit/api.py", line 144, in before_main
visit= _manager.new_visit_with_key( visit_key )
File "turbogears/visit/sovisit.py", line 44, in new_visit_with_key
visit= visit_class( visit_key=visit_key,
expiry=datetime.now() + self.timeout )
File "sqlobject/declarative.py", line 94, in _wrapper
return fn(self, *args, **kwargs)
File "sqlobject/main.py", line 1214, in __init__
self._create(id, **kw)
File "sqlobject/main.py", line 1235, in _create
raise TypeError, "%s() did not get expected keyword argument %s" % \
(self.__class__.__name__, column.name)
TypeError: VisitIdentity() did not get expected keyword argument user_id
As you can see in the line for the module sovisit.py, TG tries to insert a new object into the identity visit class, VisitIdentity, which, as a look into your model.py module will confirm, does not have an expire attribute, but has a user_id attribute, which is missing from the constructor call.
So what's happening here? Let's quickstart a new TurboGears app with tg-admin quickstart, choose to use SQLObject and Identity and have a look at the generated model.py file. What's this? There's a new model class called Visit, which our old application's model does not have:
class Visit(SQLObject):
class sqlmeta:
table = "visit"
visit_key = StringCol(length=40, alternateID=True,
alternateMethodName="by_visit_key")
created = DateTimeCol(default=datetime.now)
expiry = DateTimeCol()
def lookup_visit(cls, visit_key):
try:
return cls.by_visit_key(visit_key)
except SQLObjectNotFound:
return None
lookup_visit = classmethod(lookup_visit)
Ok, this seems to be the class, that the call in sovisit.py was trying to instantiate. Why does it not get used? We'll find out, if we compare the app.cfg file of our old application with one generated for our new, quickstarted application:
Old app.cfg:
# Database class to use for visit tracking visit.soprovider.model = "myapp.model.VisitIdentity"
app.cfg from the new quickstarted app:
# Database class to use for visit tracking visit.soprovider.model = "mytest.model.Visit"
This is all the information we need to fix this issue. Here's what you have to do:
- Copy-and-paste the Visit class from the model.py file of a new quickstarted app into the model.py file of our old application.
- Stop your application
- Run tg-admin sql create from within your project directory.
- Edit the app.cfg file of your old application and change the option visit.soprovider.model to point to myapp.model.Visit instead of myapp.model.VisitIdentity.
- Restart your application.
Hope this helps!
Update (2006-12-12): I have since been informed that this issue has been discussed already on the TurboGears trunk mailing list. You can find the archived thread here.
Reader comments
There are no comments on this article yet. Add a comment now...