Adam, thanks for sharing that! I think I'll use that concept in the CMS I'm working on. After a quick glance though: in the 'init' method for ThoughtMail, shouldn't that say "if theme:" instead of "if not theme:" ??? Perhaps I read the code the wrong way?
thanks again! -ian On Nov 18, 10:30 pm, "Adam Jones" <[EMAIL PROTECTED]> wrote: > Well, came up with something kind of useful that I thought I would > share with the groups. One of the hidden gems of TG is that it is > actually almost ridiculously easy to make your applications extensible. > Plugins, Themes, Extensions, entire new site components, you name it TG > probably has an easy way to make it happen. (and that easy way probably > uses setuptools to do the dirty work.) > > Here, let's take a look at an easy way to make your application > themeable. Although you can get a lot done with just CSS, I am going to > be showing how to replace templates to accomplish theming as it is more > useful. I'll be linking to useful resources if I am covering anything > that might not be immediately easy to grasp. All of these examples come > from a webmail project I am working on (currently dubbed ThoughtMail). > > The first thing we are going to do is make a change to our setup.py > file that declares (and fills) an entry point for themes. (for more > info see the first section of:http://docs.turbogears.org/1.0/CommandPlugins) > > Here is a sample entry point: > > """ > [thoughtmail.themes] > default = thoughtmail.themepackages:Default > """ > > Briefly what we are doing here is declaring a name (thoughtmail.themes) > that we will use later to have setuptools look for code that is > available to use. We are also informing setuptools that the "Default" > class in the "thoughtmail.themepackages" module should be included in > the list for "thoughtmail.themes" and named "default". > > Now we are just a quick package registration (python setup.py develop) > away from getting started. > > Since I don't want to keep a list of every template name, lets cheat a > bit. In the themepackages.py file we'll build our Default class so all > it does is put the appropriate namespace on the name it is given. Here > is what it looks like: > > class Default: > desc = "Default theme for ThoughtMail" # This is not required by > setuptools, but is useful. > def __getattr__(self, item): > """ > Overload getattr so calls to Default().attr return > "kid:thoughtmail.templates.default.attr" > """ > if item[0]=='_': > return item > return "kid:thoughtmail.templates.default." + item > > So a call to Default().index will return > "kid:thoughtmail.templates.default.index". > > This is only half the equation though, as we still need to allow our > users to select a theme. One way of solving that is to rely on a > combination of our previously defined entry points and the TurboGears > config system. When it is started ThoughtMail will look for a > thoughtmail.theme config item grab a list of available themes through > setuptools, and use the match if it is found. Here is the code that > does that: > > import turbogears.config > import pkg_resources > class ThoughtMail: > def __init__(self): > get = turbogears.config.get > # look for any provided theme libraries, if none are given use > the default > theme = get("thoughtmail.theme",None) > if not theme: > for entrypoint in > pkg_resources.iter_entry_points("thoughtmail.themes"): > if entrypoint.name == theme: > my = entrypoint.load() > else: > my = > pkg_resources.load_entry_point('thoughtmail','thoughtmail.themes','default') > self.theme = my() > > Here's the important bits: > We are using turbogears.config.get to retrieve the value (if any) of > thoughtmail.theme from our application's config files. Then, if we > found a match the relevant class is imported and set to the wonderfully > descriptive (but usefully short) name 'my'. The above mentioned > 'Default' theme is used if we can't find anything else. > > Now that that is done we are just about home free. Since I am storing > this information as a member variable of the ThoughtMail class, it will > normally be invisible to @expose. One way around this is to set the > template in the returned dictionary through the 'tg_template' key. Here > is a sample index using this method. > > @expose() > def index(self): > return dict(data="foo", tg_template=self.templates.index) > > Now the template for the index page will be set as though you had used > @expose to directly reference the template library for the theme you > are using. This is kind of messy though, and I would hate to add this > tg_template key to each of my methods, so lets cheat, again. > > def tdict(self, name, **kw): > """ > Create a dictionary with the given args and a tg_template key set > to 'name' > """ > return dict(tg_template=name).update(kw) > > Now we can change our index to make it a little shorter: > > @expose() > def index(self): > return tdict(self.templates.index, data="foo") > > You can possibly get something shorter as well, if you want to spend > the effort writing a custom decorator. > > Writing a new theme package now becomes a matter of creating an egg > containing your theme files, classes that point to those files, and > some entry_point listings that point to those classes. > > That is pretty much it. A smattering of little bits of code in a few > places and all someone has to do is install a theme library and set a > config variable to change the look of your application. The nice part > about this solution is that, since it is all done at runtime, it is > pretty easy to allow for per-user themes as well. > > Although the above code only deals with themes; plugins and extensions > are conceptually similar. You define an entry point and find a way to > choose a specific item out of the list for that entry point, and it is > pretty much strait Python classes from there. > > Hope you enjoyed it, > > -Adam --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "TurboGears" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/turbogears?hl=en -~----------~----~----~----~------~----~------~--~---

