Fearing I'd never actually getting around to making a neutral theme to put into my web log project, Gibe, I've now just bundled the BloggingPro theme by DesignDisease into the base release.

I've also bundled the tags plugin for an improved default experience.

And I've removed the custom Google search keyed to my domain.  You know, in case someone actually would like to use it on _their_ site and not mine...

Next release will have "pages" - just generic pages that aren't web log entries, so I can stop maintaining stuff in HTML manually.

And, hopefully, I'll be able to optionally support postmarkup for the editing of posts and pages.  Especially pages - custom postmarkup tags being defined in plugins would be very cool!

And then begins the descent into madness that is creating a from-scratch CMS system for Pylons (maybe using a TurboGears 2 template for Pylons), using the lessons learned from Gibe.  It is going to be called Mazarine (after the Mazarine Blue butterfly).

After converting 70+% of a project at work from Django to TurboGears over a week and a bit, and starting at rewriting an existing TurboGears project of mine to Pylons, quite a few things have interested me about the exercises.

Standard disclaimer about this just being my personal feelings and not some scientific test applies.  I've used TurboGears (90% own projects) a lot longer than I've used Django and Pylons, and I've used Django (50% work projects) a little bit more than I've used Pylons (only own projects so far).  I also prefer tea to coffee, tcsh to bash, and winter to summer.

... 

As Kevin points out, TurboGears 1.0.2 has been released.  A whole bunch of fixes and changes as one expects for a stable release, including support for Python 2.5, with contributions from some 20+ people.  This, the same day (ie, yesterday) I hear, yet again, how "nobody is going to support TurboGears 1.0".  Ah, the misinformation - one has to wonder why people feel the need to create it.  I've met too many trusting people who've believed a lot of it, and it's quite depressing.

I've moved TGOpenIDLogin onto Google Code so that the source code repository is accessible and other people can work on it.  I've also created a TGOpenIDLogin discussion group, in case someone actually ends up using it and wants to know some things about it.

(TGOpenIDLogin is a TurboGears module that you can use to add OpenID logins to your TurboGears application without too much fuss.  A previous post has information on how to use it.)

After much poking, cajoling, and downright finger pointing and laughing by Bryn and a bunch of other "friends", I now have Gibe, the little project saving my sanity from the tedium of burn-out and under-stimulation, in a publically accessible place for more people to do more finger pointing and laughing.

Gibe is just your standard web log software - people can log in and add posts, other people can read the posts and make comments on them, and there's anti-spam (using akismet) and there's also a bit of a beginnings of a plugin architecture there for people who want to expand it beyond what it does now.

 

Part of the magic of TurboGears Widgets (and carried on in ToscaWidgets) is that you have a bundle of resources that come along with the widget object you add to your page.  Generally, this is a couple of JavaScript files, some CSS files, and some images.  This is certainly the case if you're using a Widget as part of creating a theme for a TurboGears application.

The resources are registered as a static directory in the framework (in TG, accessible as /tg_widgets/%(resource_name)s/ - usually resource_name is the module name), and you can then use JSLink and CSSLink and friends to provide the correct URL when referencing those resources.  pkg_resources is used to provide the base path for the resources, thus allowing resources enclosed in .egg files to be found.

The widgets.py file for a TurboGears Widget generally contains this by default:

resource_dir = pkg_resources.resource_filename("tgsociable",
                                         "static")
widgets.register_static_directory("tgsociable", resource_dir)

Having the request go through the framework - through an interpreter at all, can slow things down quite a bit.  It's not so much a throughput issue as a latency issue - it takes longer to actually start sending the data for the resources.  As you can imagine, the .egg file format isn't as fast as reading from the filesystem either.

Return visitors may notice a slight difference today.  For the first time ever, I'm running a web site theme that someone else created.  While it's obviously better than my attempts, that's not why it's here (and who knows how long it'll stay).  I'm testing out the theme support in Gibe, my web log engine, which ended up not being particularly hard to do at all, thanks to the way TurboGears' expose decorator works, and a simple decorator of my own.

So far, I've been looking at modifying existing pages in Gibe (my still as-yet-unreleased TurboGears blog application) - adding widgets to post pages, dynamically adding the comment field and handling it for different comment formats, and adding additional fields at blog entry create/edit-time and handling these fields to add tagging (or whatever).  Adding new pages (or replacing the default ones) is pretty much necessary - for example, to add a page where there is a list of all pages with a particular tag.

I use Routes for dispatching incoming URLs to functions in Gibe.  It's not the default dispatcher in TurboGears, but it's pretty easy to set up (there's a TurboGears/Routes integration recipe on the TurboGears wiki).

Why go through the bother?

It makes adding new pages easy - no matter how complicated the URL structure is and where the dynamic portions are.  It also makes it easy to pass through the dynamic portions, and also to pass through defaults if the dynamic portions don't exist.   The killer function is named routes, which allows me to look up where something is (ie, generate the URL for it), and not hard-code the link to where the page is.  That means that I can totally change the URL structure of the site without changing any code.

In terms of dynamicism, the worst cases I've explained so far in Gibe are the little comment format hack to allow the use of Postmarkup instead of HTML in comments, and the adding of little trivial plugins to add visual widgets at the top and bottom of blog entries.  Certainly not rocket science.  And, well, neither is this...

My next task was to look at how one could add additional fields to the blog entry create/edit screen - to allow plugins to ask for additional information like tags, geographical location, your mood, what you're currently listening to, and other vain things that nobody really cares about (I mean, it's a blog, it's not like it's useful...).

I used tags as my test case, since that is at least something I can see some value in, and it's something that's already around except for the actual entry of the tags.  Until now, I've been manually typing in things like:

INSERT INTO post_tag
    SELECT 625 AS post_id, tag_id FROM tag
        WHERE name IN
            ('gibe', 'python', 'code','amatomu',
            'blogs','me','tgsociable');

The last time I was talking code (I mean, besides the little example usage snippet when I was announcing TGOpenIDLogin, in between my reporting back about the GeekDinner, the Western Cape Linux User Group  meeting, the Cape Town Python User Group meeting, and so forth), I was showing how I converted the Wordpress Sociable plugin to a TurboGears widget (innovatively named TGSociable).

The ultimate purpose of this was to make a plugin for Gibe (my little weblog engine) which would add the sociable icons with the correct URLs to blog entry pages, without having to put anything sociable-specific in the code.

When writing the comment format "plugin system" so that Gibe could use something other than the built-in TinyMCE, I used pkg_resources to create an "entry point" so that other packages could provide functionality to Gibe, and Gibe would know about them without anything but installing the package.

So, I started with the near-simplest possible Plugin class:

class Plugin(object):
    def post_top_widgets(self, post, widgets, context):
        # widgets to put above the post
        pass