Skin support for BFG.
Project description
Overview
This package provides a framework to make files in a directory structure available as skin components (the term originates from the CMF package which provides comparable functionality on Zope 2).
There’s built-in integration with routes, views and components.
About
The package is written and maintained by Malthe Borch and Stefan Eletzhofer. Available as-is under the BSD license.
To contribute or get support for this package, please visit the #repoze channel on freenode irc or write to the repoze-dev mailinglist.
Usage
The package allows configuration using the ZCML language. The skin directive is defined in the meta.zcml file:
<include package="repoze.bfg.skins" file="meta.zcml" />
To configure all the included components (recommended), include the package instead:
<include package="repoze.bfg.skins" />
Application setup
Once you’ve included the repoze.bfg.skins ZCML, you may use the ZCML-directive <bfg:skins> to register a directory with templates and make them available as template components, e.g.::
<bfg:skins path="skins" />
The path parameter indicates a relative path which contains the skin object files.
The skins directive makes available skin components for use in library code. The default factory (see Factories) simply uses the relative path as the component name; some factories may strip off the file extension (this is the case for the page template factory).
To expose the contents of a skin directory as views, we can insert a view registration directive into the skins directive:
<bfg:skins path="skins"> <bfg:view /> </bfg:skins>
The view directive has no required attributes, but all the attributes which are applicable for the standalone directive [1] are available, except name which is defined by the component and view which is given by the skin object.
Routes integration
Every skin component corresponds to a relative path. We can configure a route to map a subpath to skin components for which a view is registered:
<route name="skins" path="/content/*subpath" factory="repoze.bfg.skins.RoutesTraverserFactory" />
This traverser will convert the subpath into a view name and let BFG render the view if possible.
View integration
Skin components are registered as named utilities. We can use the getUtility function to retrieve a skin component by name.
For convenience, the SkinObject class doubles as a descriptor which can be used as a class attribute; it uses a getUtility call when accessed:
class MyView(object): __call__ = SkinObject("document_view")
The weak binding to the skin object makes it easy to depend on skin components from library code without a hard dependency.
Factories
The skin objects are instances of the SkinObject base class. We may associate a custom factory for particular file extensions:
class MySkinObject(SkinObject): pass
We register the class as a named utility component:
<utility name=".my" component=".MySkinObject" provides="repoze.bfg.skins.interfaces.ISkinObjectFactory" />
Page template factory
Included with the package is a factory for Zope Page Templates (with the file extension “.pt”). The Chameleon rendering engine is used.
Page templates registered as skin objects will be called skin templates. Support is provided to locate other skin templates and include them as macros. This is made pluggable such that applications can add additional functionality.
This package provides a new expression skin: which will retrieve a skin object by name:
The skin object factory for page templates provide the macros attribute. The following snippet illustrates this:
<div tal:define="master skin: main_template" metal:use-macro="master.macros['main']" />
The route: expression maps to the route_url framework function:
<img tal:attributes=”src ${route: skins}/images/logo.png” />
See the repoze.bfg url documentation for more information on URL generation.
Automatic discovery and reload
When the global setting debug is set (to any non-trivial value), skin objects are discovered at run-time and files are automatically reloaded when changed.
Developer’s guide
This interactive narrative is written as a doctest.
You can run the tests by issuing the following command at the command-line prompt:
$ python setup.py test
In the course of the narrative we will demonstrate different setups. We have prepared a directory with skin files:
./tests/skins ./tests/skins/index.pt ./tests/skins/images/logo.png
We will use the ZCML configuration language to register this structure for use as skins. The following configure function loads in a ZCML configuration string.
>>> from repoze.bfg.skins import tests as testing
The ZCML-directive skins takes a path argument; we’ll provide a path which points to a directory within the testing harness.
>>> import os >>> path = os.path.join(testing.__path__[0], 'skins')>>> testing.configure(""" ... <configure xmlns="http://namespaces.repoze.org/bfg"> ... <include package="repoze.bfg.skins" /> ... <skins path="%s" /> ... </configure>""" % path)
Skin objects as components
After this bit of configuration, our skin objects are available as components.
>>> from zope.component import getUtility >>> from repoze.bfg.skins.interfaces import ISkinObject
The name of the component is the relative path.
>>> getUtility(ISkinObject, name="images/logo.png") <repoze.bfg.skins.models.SkinObject name="images/logo.png" at ...>
The page template factory strips off the file extension. The file “index.pt” becomes a skin template with the name “index”.
>>> getUtility(ISkinObject, name="index") <repoze.bfg.skins.models.SkinTemplate name="index" at ...>
Descriptor usage
The SkinObject class works as a descriptor. This is useful to tie user interface classes with skin files with a weak binding.
>>> from repoze.bfg.skins import SkinObject
Use it as a class attribute.
>>> class MyClass(object): ... index = SkinObject("index") ... logo = SkinObject("images/logo.png")
The property works on the class itself, and on instances.
>>> MyClass.index <repoze.bfg.skins.models.SkinTemplate name="index" at ...> >>> MyClass.logo <repoze.bfg.skins.models.SkinObject name="images/logo.png" at ...>
View registration
We can register views for skin objects by wrapping a view directive in the skins directive.
There are no required arguments to the view directive:
>>> testing.configure(""" ... <configure xmlns="http://namespaces.repoze.org/bfg"> ... <include package="repoze.bfg.skins" /> ... <skins path="%s"> ... <view /> ... </skins> ... </configure>""" % path)
The BFG framework function render_view_to_response lets us look up views by name and retrieve a response object for a given context and request.
>>> context = testing.DummyContext() >>> request = testing.DummyRequest("") >>> from repoze.bfg.view import render_view_to_response
Note in the example how the directory separator character has been replaced by an underscore.
>>> response = render_view_to_response( ... context, request, name="images_logo.png") >>> response.status '200 OK' >>> response.content_type 'image/png'
The page template view first renders the template before returning the response.
>>> response = render_view_to_response( ... context, request, name="index") >>> response.status '200 OK' >>> response.content_type 'text/html'
The response body contains the rendered page template:
>>> print response.body <html> <body> Hello, world! </body> </html>
Routes
Now that we have views registered, let’s configure a route.
>>> testing.configure(""" ... <configure xmlns="http://namespaces.repoze.org/bfg"> ... <include package="repoze.bfg.skins" /> ... <route ... name="test" ... path="/*subpath" ... factory="repoze.bfg.skins.RoutesTraverserFactory" ... /> ... </configure>""")
To try it out, we’ll configure a router to use the components we’ve set up.
>>> from repoze.bfg.router import Router >>> from zope.component import getSiteManager >>> router = Router(getSiteManager())
We need to set the root factory to the routes mapper.
>>> from zope.component import getUtility >>> from repoze.bfg.interfaces import IRoutesMapper >>> router.root_factory = getUtility(IRoutesMapper)
Our “test” route lets us pass in any valid skin path:
>>> testing.DummyRequest("/images/logo.png").get_response(router) <Response at ... 200 OK> >>> testing.DummyRequest("/index").get_response(router) <Response at ... 200 OK>
Templates
Included with the package is functionality to support interaction between templates registered as skin components.
An expression type skin is available for page templates to look up other skin components by name.
>>> from chameleon.zpt.template import PageTemplate >>> template = PageTemplate(""" ... <html tal:define="master skin: index" ... metal:use-macro="master.macros['main']"> ... <body metal:fill-slot="body"> ... <h1>Welcome</h1> ... <img src="${route: test}/images/logo.png" /> ... </body> ... </html>""")>>> print template.render(context=context, request=request) <html> <body> <h1>Welcome</h1> <img src="http://localhost/images/logo.png" /> </body> </html>>>> print MyClass.index.render() <html> <body> Hello, world! </body> </html>
Changelog
0.13 (2009-30-10)
Rewrite. Backwards-compatibility broken.
Migration path:
Skins registrartion directive renamed to <bfg:skins>.
To register views for skin objects, the <bfg:view> directive should be used inside a <bfg:skins> declaration. See documentation.
Previous users should consult documentation for more information.
Made compatible with repoze.bfg 1.1a4.
Disuse component.adapts (unuseable in any BFG app), to make compatible with repoze.bfg 1.1a6+.
0.12 (2009-02-12)
Added convenience method get_skin_template_view. [malthe]
The get_skin_template method now accepts an optional request_type parameter, which takes priority in adaptation. [malthe]
The provides parameter has been retired; instead, a class parameter may be provided. By default this is set to the SkinTemplate class; to register a view, simply set it to SkinTemplateView (full module path required). [malthe]
0.11 (2009-02-09)
View permission is now only registered if a view must be provided. [malthe]
Multiple interfaces may be specified as provides. [malthe]
0.10 (2009-01-28)
Added parameter content_type which will set the content type of the view response. [malthe]
Added macros attribute to the template object. [malthe]
0.9 (2008-12-05)
Updated signatures for skin template factory lookup functions. [malthe]
Added support for skin api methods. [malthe]
0.8 (2008-12-05)
Provide ISkinMacro unless provides is set; however, always provide ISkinTemplate. Meanwhile, the macro accessor looks only for skin templates registered for the ISkinMacro interface. [malthe]
0.7 (2008-12-04)
If provides is set, do not automatically provide the ISkinTemplate interface as well; this behavior made it difficult to program cascading rendering schemes. [malthe]
Keyword-arguments are now accepted by the utility methods for rendering skin templates using Python. [malthe]
Added security assertions to macro rendering function to prevent infinite loop if a template tries to render itself. [malthe]
0.6 (2008-12-03)
Do not register macro components separately, but make them available from the macro attribute of a skin template. [malthe]
0.5 (2008-12-03)
Added component lookup scheme for the bound skin template object which makes skin API components available using get_<name> where <name> is the component name. [malthe]
Restructured package and changed look up scheme for skin APIs and macros. A symbol template is now available to skin templates; from this object, methods get_api and get_macro can be used to look up skin APIs and macros, respectively. [malthe]
Added render_skin_template_to_response and render_skin_template methods for general template rendering. [fairwinds]
0.4 (2008-11-13)
Added name attribute to skin template interface. [malthe]
No longer provide repoze.bfg.interfaces.IView by default; the provides attribute may now be used to specify an additional interface which the skin templates will provide. [malthe]
0.3 (2008-10-29)
Fix performance issue where template objects would be instantiated at every call. [malthe]
Pass keyword arguments to skin template callable. [malthe]
Instantiate page template directly. [malthe]
0.2 (2008-10-03)
Templates located in subdirectories are now named by replacing the operating system path separator with a forward slash symbol (often this will be the same character); before a dot ‘.’ was used. [malthe]
Added Template API base class. [malthe]
Renamed IApi to ITemplateAPI. [malthe]
Template API components should adapt (context, request, template), where template is the skin template object (such an API might need to provide access to the template file itself, in order to get a path to resources local to the template). [malthe]
Added render method to skin template class to allow rendering to a string instead of to a WebOb response. [malthe]
Renamed package to repoze.bfg.skins [seletz]
Added logic to allow registering and acquiring template API components from templates. [malthe]
Changed the Skin Template View to be a class, and added a minimal interface ISkinTemplate to access the template path [seletz]
Fixed a bug where we did not tear down the tests correctly [seletz]
Fixed bug where the INewRequest event handler would call templates when checking for their existence [seletz]
0.1 (2008-09-25)
Initial release [malthe]
Added support to dynamically register templates if they are added to a registered template directory [seletz]
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file repoze.bfg.skins-0.13.tar.gz
.
File metadata
- Download URL: repoze.bfg.skins-0.13.tar.gz
- Upload date:
- Size: 20.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4f868450abefb5ae398c39735cd9c6e4ea7e9be575375fcbac9088652c24051f |
|
MD5 | 219008a868552aa6891b64518faa141f |
|
BLAKE2b-256 | a4749bd94edaf8e81c51c21db29241aab7a028897df06ef4d768a5f8399cc5e5 |