The most significant change in TurboGears 2 is the decision to work very, very closely with Pylons. We’ve basically built a copy of the TurboGears 1.x API on top of Pylons/paste which allows our two communities to work together on everything from internationalization to database connection pooling.
Another significant change is that we’ve removed the tg-admin wrapper and started explicitly using paster for administrative commands to match what Pylons was doing. We’ve re-implemented the old tg-admin commands as paster commands; for example, “tg-admin quickstart” is replaced by “paster quickstart”.
Lots of questions have been asked about why we’ve decided to create TurboGears 2 the way we did, so let’s try to answer them as best we can.
Well, there are a lot of changes, but perhaps not as many as it looks like from the description. We were able to keep the controller API very similar to TurboGears 1, and Genshi copied the Kid API, so while we chose new components, we didn’t really change the way Controllers and Templates look very much at all. Sure, there are some minor changes here and there, but one member of the TurboGears 2 training class at PyCon said “I didn’t notice a lot that was new in terms of how you put a TurboGears application together.”
Well, Pylons is committed to being officially template engine agnostic, ORM agnostic, etc. On the other hand TurboGears is committed to providing a “Full-Stack” for web development. So, the two communities have different, but compatible priorities. If you think about it Pylons provides a great set of tools for building a full-stack framework, and people had been asking for a full-stack Pylons implementation for a long time. And TurboGears 2 provides that.
There are a lot of benefits to having a full-stack. You can build form helpers which do all sorts of interesting things (introspect model objects to make web-based forms, automatically display form errors, etc) because you can make some assumptions about what tools will be available and what will be used. In particular, you can start building pluggable website components much more easily, because you are building on a known set of tools.
This is something we really struggled with. CherryPy 3 is a huge improvement over CherryPy 2, providing a much richer programming experience, and huge performance gains. But TurboGears 1 was very tightly coupled to the config system of CherryPy 2, which was entirely rewritten in CherrPy 3. We tried to make a backwards compatible TG based on CherryPy 3, but discovered that it was significantly more difficult than we had expected.
At the same time there was a push to make TurboGears 2 more WSGI based, and to take advantage of things like Routes middleware, and to generally take advantage of the Pylons/WSGI revolution. We discovered that Pylons had a lot of the same code as TurboGears (both of us had Buffet implementations, both of us had SQLObject wrappers that did the same thing, etc)
Well, Genshi is an intentional re-implementation of Kid, with an almost identical API. But internally it’s simpler, faster, and provides better error messages. The inclusion of a couple of new features – includes and full x-path support – also make it significantly more flexible.
Genshi has also developed a larger, more active community than Kid, and is being used in lots of places outside of TurboGears so, unlike Kid, it’s not at all likely to have to be taken over and maintained by the TG core developers.
SQLAlchemy is arguably the best ORM available for Python. Some have even proclaimed it the best ORM in any language. The fact is, writing your own ORM is hard, and if we were to spend time doing that, we’d have no time to glue together everything that makes TG great. Previously, TurboGears used SQLObject, which implements the ActiveRecord pattern, whereas SQLAlchemy utilizes the Data Mapper Pattern. We feel that the Data Mapper Pattern is more flexible for the longevity of a project, in that it gives you direct access to the Table Objects, allowing you to map the Related Objects around it. For those who want everything summed up in a single mapping class, SQLAlchemy provides a Declarative form of Object definition which implements ActiveRecord, while still giving you access to your tables.
A concrete example of the flexibility of SQLAlchemy vs. SQLObject is that it is very hard to have a user data type in SQLObject that has a key based in part on foreign key fields of another object. So while (for example) account transaction objects never exist independently of account objects, it was very hard to build a data model embodying this fact in SQLObject. This is not true of SQLAlchemy.
Design decisions aside, SA has an active community, and has a well-maintained codebase that is also well documented. This makes it a perfect choice for us because while we love giving you documentation, there is no way we could provide the detail required to do Object Relational Mapping justice.
- Cache system
- Error report: interactive tracebacks through the web, custom error pages, and email alerts
- API Document generator through Sphinx
- could pass status code to flash message
- support crud interface generator
Areas of compatibility:
- Like TurboGears 1.1, TurboGears 2 supports Python 2.4 and above.
- TurboGears 1.x and TurboGears 2.1.5 can both be installed on the same machine. They are different packages with different namespaces. Right now there are no dependency conflicts. But using virtualenv is highly recommended to eliminate the possibility of future dependency conflicts.
- Object dispatch is implemented in TurboGears 2.1.5, so you can use arguments and keywords in functions the same way you did in TurboGears 1.x.
- Expose and error handling decorators are implemented in TurboGears 2.1.5, you can use decorators just like TurboGears 1.x.
Use paster command instead of the old tg-admin command.
For example you now type paster quickstart rather than tg-admin quickstart to start a project.
Here’s a full list of the old command line tools and their new equivalents
- tg-admin quickstart —> paster quickstart
- tg-admin info —> paster tginfo
- tg-admin toolbox –> paster toolbox
- tg-admin shell –> paster shell
- tg-admin sql create –> paster setup-app development.ini
Both controllers.py and model.py have been replaced by the controllers and model folders. In other words they are now Python packages, in just the way they were in TurboGears 1 if you used the ‘–template tgbig’ option with quickstart.
- your root controller is not in controllers.py -> it has moved to controllers/root.py
- model.py -> model/__init__.py
- myproject_dev.cfg -> development.ini With a whole new structure based on paste.deploy
- app.cfg –> config/environment.py and to a lesser extent config/middleware.py
- import turbogears -> import tg
- turbogears.config.get(‘sqlalchemy.dburi’) -> pylons.config[‘sqlalchemy.url’]
- pylons.tmpl_context provides a request local place to stick stuff
- pylons.request provides the rough equivalent of cherrypy.request
- pylons.response provides the equivalent of cherrypy.response