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
-~----------~----~----~----~------~----~------~--~---

Reply via email to