| Home | Trees | Indices | Help |
|
|---|
|
|
A web-widget library.
wehjit is a Python library for for building XHTML widgets for web applications and web pages. It encapsulates the XHTML (a Genshi XML template), CSS, and JavaScript for each widget into a plugin. For detailed Genshi documentation, see:
http://genshi.edgewall.org/
Widgets are Python classes. All widgets need to either directly or indirectly subclass from wehjit.Widget. For example, this is what a simple widget class looks like:
>>> from wehjit import Widget >>> class HelloWorld(Widget): ... xml = """ ... <p xmlns:py="http://genshi.edgewall.org/"> ... Hello, world! ... </p> ... """ ... >>> hello_world = HelloWorld() >>> print hello_world.render() <p> Hello, world! </p>
Widgets that subclass from wehjit.Container can contain other widgets. Child widgets are incrementally added using a simple container API similar to a traditional toolkit like GTK+ or Qt. For example:
>>> class Section(Container): ... xml = """ ... <div xmlns:py="http://genshi.edgewall.org/"> ... <stuff py:for="child in children" py:replace="child.generate()" /> ... </div> ... """ ... >>> section = Section() >>> section.add(hello_world) >>> print section.render() <div> <p> Hello, world! </p> </div>
Note that the <stuff> tag is not rendered above because of the Genshi py:replace directive.
wehjit has four special Python descriptor classes (Static, Dynamic, StaticProp, and DynamicProp) that allow you to easily extend the variables provided to the Genshi template. For example, let's try a more sophisticated parent/child setup:
>>> from wehjit import Dynamic >>> class H1Section(Container): ... xml = """ ... <div xmlns:py="http://genshi.edgewall.org/"> ... <h1 py:content="label" /> ... <div py:for="child in children" py:replace="child.generate()" /> ... </div> ... """ ... label = Dynamic('label') ... >>> class Paragraph(Widget): ... xml = """ ... <p xmlns:py="http://genshi.edgewall.org/" py:content="content" /> ... """ ... content = Dynamic('content', default='I am fine.') ... >>> h1section = H1Section(label='A classic "Hello World"') >>> p1 = Paragraph(content='Hello world.') >>> p2 = Paragraph(content='How are you?') >>> h1section.add(p1, p2) # Can add multiple children in a single call >>> h1section.add(Paragraph()) # And call call add() multiple times >>> print h1section.render() <div> <h1>A classic "Hello World"</h1> <p>Hello world.</p><p>How are you?</p><p>I am fine.</p> </div>
The parent/child relationships can easily be visualized using the Widget.print_tree() method. For example:
>>> import sys >>> h1section.add(section) >>> h1section.print_tree(sys.stdout) H1Section(id=None, name=None) Paragraph(id=None, name=None) Paragraph(id=None, name=None) Paragraph(id=None, name=None) Section(id=None, name=None) HelloWorld(id=None, name=None)
Widgets also happen to be plugins. A Collection is used to group a set of widget plugins together into a namespace. The wehjit.plugins sub-package includes a large number of widget plugins which are registered in the pre-defined Collection instance at wehjit.builtins. For example:
>>> from wehjit import builtins >>> builtins Collection('builtins') >>> h1 = builtins.H1(label='Hello again, world.') >>> print h1.render() <h1 class="H1">Hello again, world.</h1>
wehjit.builtins is already frozen (meaning no further plugins can be registered); however, you can create as many independent Collection instances as you like. For example:
>>> from wehjit import Collection >>> my_widgets = Collection('My custom widgets') >>> my_widgets Collection('My custom widgets') >>> my_widgets.register(HelloWorld) >>> my_widgets.HelloWorld is HelloWorld True >>> hello_world = my_widgets.HelloWorld() >>> print hello_world.render() <p> Hello, world! </p>
Often times you'll want to use the built-in widgets as your starting point, and then register additional widgets or even override some built-in widgets. The Collection.register_builtins() method registers all the built-in widgets into your Collection instance (which always start empty). For example:
>>> hasattr(my_widgets, 'H1') False >>> my_widgets.register_builtins() >>> hasattr(my_widgets, 'H1') True >>> print my_widgets.H1(label='this is a builtin', id='eg.1').render() <h1 class="H1" id="eg.1">this is a builtin</h1>
You can also override a built-in. When overriding a plugin (built-in or otherwise), it's generally a good idea to subclass from the plugin you are overriding so that the subclass inherits the parent's state-descriptor attributes. For example:
>>> my_widgets.H1 is builtins.H1 True >>> class H1(my_widgets.H1): ... xml = """ ... <h1 ... xmlns:py="http://genshi.edgewall.org/" ... class="${klass}" ... id="${id}" ... py:content="label.upper()" ... /> ... """ ... >>> my_widgets.register(H1, override=True) >>> my_widgets.H1 is builtins.H1 False >>> print my_widgets.H1(label='this will be uppercase', id='eg.2').render() <h1 class="H1" id="eg.2">THIS WILL BE UPPERCASE</h1>
Notice how a Collection allows your page-generating code to use my_widgets.H1 independent of whether it happens to be the built-in wehjit.plugins.page.H1 implementation or your custom H1 plugin.
When overriding plugins, you must always do so explicitly using override=True, otherwise wehjit.errors.OverrideError will be raised. For example:
>>> class Menu(my_widgets.Menu): ... pass ... >>> my_widgets.register(Menu) Traceback (most recent call last): ... OverrideError: unexpected override of <class 'wehjit.plugins.page.Menu'> with <class 'wehjit.Menu'>
An Application combines a Collection with other configuration information (like the base URL of the application and the assets). For example:
>>> from wehjit import Application >>> my_app = Application(url='/my-app/', widgets=my_widgets) >>> my_app Application(url='/my-app/')
Application.new() creates a new widget instance using a plugin from the Collection passed to Application.__init__() (in this case, my_widgets). For example:
>>> h1 = my_app.new('H1', label='still uppercase') >>> print h1.render() <h1 class="H1">STILL UPPERCASE</h1>
Application.new() keeps track of all the widget plugins that have been used at least once, available via Application.plugins(). For example:
>>> list(my_app.plugins()) [<class 'wehjit.H1'>] >>> my_app.new('View') View(id=None, name=None) >>> list(my_app.plugins()) [<class 'wehjit.H1'>, <class 'wehjit.plugins.page.View'>]
Application.new() also keeps track of all the wehjit.Page instances that have been created, available via Application.pages(). For example:
>>> welcome = my_app.new('Page', id='welcome') >>> list(my_app.pages()) [Page(id='welcome')] >>> my_app.new('Page', id='another') Page(id='another') >>> list(my_app.pages()) [Page(id='welcome'), Page(id='another')]
So that all widget instances receive a reference to the specific Application, Collection, and assets that you're working from, your page generation code should only create widget instances using Application.new(). This is especially important because some containers will automatically create child widgets by themselves calling Application.new(). For example:
>>> fancy = my_app.new('PageApp', id='fancy:page') >>> fancy.print_tree(sys.stdout) PageApp(id='fancy:page') Form(id='form') TopBar(id='topbar', name=None) MenuSet(id='menuset', name=None) Menu(id='menu', name=None) Actions(id='actions', name=None) View(id='view', name=None) H1(id='h1', name=None)
Of course, fancy will now also be in Application.pages():
>>> list(my_app.pages()) [Page(id='welcome'), Page(id='another'), PageApp(id='fancy:page')]
Similar to Widget.print_tree(), Application.print_tree() allows you to visualize the entire page and widget hierarchy. For example:
>>> my_app.print_tree(sys.stdout) Application(url='/my-app/') Page(id='welcome') Page(id='another') PageApp(id='fancy:page') Form(id='form') TopBar(id='topbar', name=None) MenuSet(id='menuset', name=None) Menu(id='menu', name=None) Actions(id='actions', name=None) View(id='view', name=None) H1(id='h1', name=None)
Version: 0.1.1
|
|||
| |||
|
|||
|
|||
|
|||
staticdir =
|
|||
__package__ =
|
|||
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed Sep 30 19:42:04 2009 | http://epydoc.sourceforge.net |