TableOfContents(2)


General

What is Albatross

Albatross is a small and flexible toolkit for developing highly stateful web applications. The toolkit provides the following:

A primary design goal of Albatross is that it be small and easy to use and extend. Most of the toolkit is constructed from a collection of mixin classes. You are encouraged to look at the code and to think of new ways to combine the Albatross mixin classes with your own classes.

Object Craft developed Albatross because there was nothing available with the same capabilities which they could use for consulting work. For this reason the toolkit is important to Object Craft and so is actively maintained and developed.

What language is Albatross written in?

Albatross is written in Python, a powerful, but easy to learn, object-oriented scripting language. For more information on Python, go to http://www.python.org/

What license does Albatross use?

Albatross uses a Open Source BSD license that permits most uses. The Albatross 1.00 license is below:

Copyright (C) 2002, Object Craft P/L, Melbourne, Australia.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

    * Neither the name of Object Craft nor the names of its contributors may be
      used to endorse or promote products derived from this software without
      specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

I can't find an answer to my question here?

Ask us - send your question to albatross@object-craft.com.au.

Alternatively, you can join the Albatross-Users mailing list. For instructions on subscribing, go [https://www.object-craft.com.au/cgi-bin/mailman/listinfo/albatross-users HERE].

Is commercial support available?

Definitely! Contact enquiries@object-craft.com.au for more information.

Can you write my application for me?

Object Craft would be happy to talk to you about your requirements. Please contact enquiries@object-craft.com.au.

It is worth noting, however, that because Albatross is Open Source and written with ease of understanding in mind, any skilled python developer will also be able to help you.

What projects has Albatross been used in?

Among other things, Albatross has been used to:

Does Albatross have a mailing list or discussion group?

Yes - to subscribe, go to https://www.object-craft.com.au/cgi-bin/mailman/listinfo/albatross-users


Installation

Does Albatross work under Unix?

Of course!

Does Albatross work under Windows?

Yes.

What version of Python is required to run Albatross?

Albatross works with all versions of Python from version 2.3 onwards. It has not yet been ported to Python 3.

What other packages do I need to have before I can install Albatross?

You will probably want a web server, although it's possible to use the templating functionality outside a web server, and Albatross includes a stand-alone deployment mode that is suitable for limited use without a web server.

To rebuild the documentation, you will need: LATEX latex2html Python source - mkhowto and LATEX styles dia

We recommend you use the pre-formatted manuals available from http://www.object-craft.com.au/projects/albatross/.


Templates

Can I nest macros?

Yes, although you will need to explicitly pass any arguments through. For example:

   1     <al-macro name="sub">
   2         This is the submacro, its argument is:
   3         <al-usearg name="subarg" />
   4     </al-macro>
   5     <al-macro name="main">
   6         This is the main macro.
   7         <al-expand name="sub">
   8             <al-setarg name="subarg">
   9                 <al-usearg name="mainarg" />
  10             </al-setarg>
  11         </al-expand>
  12     </al-macro>
  13     <al-expand name="main">
  14         <al-setarg name="mainarg">
  15             Whatever
  16         </al-setarg>
  17     </al-expand>

What happens to attributes on Albatross tags that Albatross doesn't recognise?

Attributes that Albatross doesn't recognise are passed through to the generated HTML unchanged.

I need to internationalise my templates?

Dave suggested the following (untested) idea:

   1     class MyCtx(SimpleAppContext):
   2         def language_vary(self, name):
   3             language = self.request.get_header('Accept-Language')
   4             if language:
   5                 return os.path.join(string.split(language, ',')[0], name)
   6             return name
   7         def load_template(self, name):
   8             name = self.language_vary(name)
   9             return SimpleAppContext.load_template(name)
  10         def load_template_once(self, name):
  11             name = self.language_vary(name)
  12             return SimpleAppContext.load_template_once(name)


Application model

How do I capture the output from processing my templates?

You may want your template output to go somewhere other than stdout. If so, use ctx.push_content_trap() and ctx.pop_content_trap():

   1     ctx.push_content_trap()
   2     tmpl = ctx.load_template(filename)
   3     tmpl.to_html(ctx)
   4     ctx.flush_content()
   5     results = ctx.pop_content_trap()

Technically, calling push_content_trap() saves the current list off fragments on a stack and then clears the list. When you call pop_content_trap() the contents of the list and joined and returned and the previous fragment list is restored from the stack. This is used internally for arguments to macro expansion and sometimes for options to the select tag.

Can Albatross look after my logging?

Albatross doesn't help you with logging (yet), although traditionally stderr goes to the web server error log.

The easiest way to add logging support yourself would be to make your own subclass of one of the Context objects, and add your logging methods to this.

A simple example:

   1     class LogMixin:
   2         def log(self, s):
   3             sys.stderr.write('%s\n' % s)
   4             sys.stderr.flush()
   5     class AppContext(albatross.SimpleAppContext, LogMixin):
   6             ...
   7     ctx.log('log message')

Can I use the cgitb module with Albatross?

"cgitb" is a module that aids in the reporting of uncaught exceptions from within CGI scripts. It is distributed as a standard part of Python as of version 2.2. Because Albatross handles it's own exceptions, however, cgitb never gets a chance to report them.

Dave suggests overriding the handle_exception() method would work, although this is untested:

   1     import cgitb
   2     from albatross import SimpleApp
   3     class MyApp(SimpleApp):
   4         def handle_exception(self, req):
   5             cgitb.handler()

When are the page methods page_process, page_enter, page_leave, and page_display called?

For a page class called "blah", blah.page_enter() is called once after the previous page class calls ctx.set_page('blah'), and blah.page_display() is then called (and called each time the page is redisplayed - on reload, for example).

When the user submits some data, blah.page_process() is called. page_process() can act on the data, save it, or request the application to move to a new page (ctx.set_page()).

If the application remains on the "blah" page, blah.page_display() is called. If set_page() was called, blah.page_leave() is called, and process starts again with the new page class.

Note that you don't need to provide all four methods - if not provided, they default to sensible actions in each case.

In page_enter(), you would put one time initialisation (setting default values for form fields for example).

   1     def page_enter(ctx):
   2         ctx.locals.diagnostic = ''
   3         ctx.locals.whatever = load_whatever()
   4         ctx.add_session_vars('whatever')

In page_display(), you might initialise more form fields (ones derived from external data, maybe), for example:

   1     def page_display(ctx):
   2         ctx.locals.load_setting_name = ctx.locals.settings.get_current_name()
   3         return ctx.run_template('change_parameters.html')

In page_process(), you act on the user's form submission:

   1     def page_process(ctx):
   2         if ctx.req_equals('submit'):
   3             if ctx.locals.username == '':
   4                 ctx.locals.diagnostic = 'You must enter a username'
   5         else:
   6             ctx.locals.diagnostic = ''

In page_leave(), you might perform cleanup:

   1     def page_leave(ctx):
   2         ctx.remove_session_vars('whatever')