.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % Copyright 2001 by Object Craft P/L, Melbourne, Australia.
.. % LICENCE - see LICENCE file distributed with this software for details.
.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. _mixin-ref:
*********************
Mixin Class Reference
*********************
Most of Albatross exists as a collection of plug compatible mixin classes which
you select from to define the way your application should behave and how it will
be deployed. Figure :ref:`fig-toolkit` shows the organisation of the component
types in the toolkit.
.. _fig-toolkit:
.. figure:: .build/figures/toolkit.*
:align: center
Toolkit Components
The divisions in the diagram represent conceptually different functional areas
within the toolkit.
Templating
This layer provides the Albatross templating functionality. Template classes
make use of the methods defined in the next layer down to access application
functionality and data.
Classes in this layer are defined in the :mod:`albatross.template` and
:mod:`albatross.tags` modules.
Template Execution
An execution context suitable for interpreting template files is constructed by
combining one mixin of each type from this layer.
Application Model
Execution contexts which subclass a :class:`PageMixin` class in addition to the
mixins from the above layer are suitable for use in Albatross applications. The
:class:`PageMixin` class controls how the application locates code and template
files for each page served by the application. The :class:`PickleSignMixin`
class is responsible for modifying pickles which are sent to the browser to
prevent or detect modification.
Your Application
In this layer you will typically create your own application and execution
context classes by subclassing a prepared application class.
For the most part Albatross applications are independent of the method by which
they are deployed. Depending upon which :class:`Request` class you choose from
this layer you can either deploy your application via CGI, ``mod_python``
(``_), FastCGI (``_) or as a
stand-alone python HTTP server.
Wherever possible the Albatross mixin classes use member names which begin with
double underscore to trigger Python name mangling. This protects your classes
from having member name clashes with private members of the mixin classes. Any
member names which are not mangled are intended to be accessed in your
application code.
.. _mixin-resource:
ResourceMixin Class
===================
Albatross only supplies one class for this function; the :class:`ResourceMixin`
class. This mixin manages application resources which which do not change
regardless of context. The resources managed are tag classes, HTML macros, and
HTML lookup tables.
The :class:`SimpleContext` execution context class subclasses the
:class:`ResourceMixin` class. During the constructor it registers all of the
standard Albatross tags. As HTML templates are executed the macros and lookup
tables in those templates are registered.
All standard Albatross application classes inherit from the :class:`Application`
class which in turn subclasses the :class:`ResourceMixin` class. During the
application class constructor all of the standard Albatross tags are registered.
The :class:`AppContext` class which is subclassed by all Albatross application
execution context classes proxies all HTML macro and lookup table methods and
directs them to the application object.
.. method:: ResourceMixin.__init__()
When you inherit from the :class:`ResourceMixin` class you must call this
constructor to initialise the internal variables.
.. method:: ResourceMixin.get_macro(name)
Returns the macro previously registered by the name in the *name* argument. If
no such macro exists ``None`` is returned.
.. method:: ResourceMixin.register_macro(name, macro)
Registers the HTML macro in the *macro* argument under the name in the *name*
argument.
.. method:: ResourceMixin.get_lookup(name)
Returns the lookup table previously registered by the name in the *name*
argument. If no such lookup exists ``None`` is returned.
.. method:: ResourceMixin.register_lookup(name, lookup)
Registers the HTML lookup table in the *lookup* argument under the name in the
*name* argument.
.. method:: ResourceMixin.discard_file_resources(filename)
Discards macros and lookups loaded from *filename*. This is called prior to
reloading a template.
.. method:: ResourceMixin.get_tagclass(name)
Returns the tag class in which the :attr:`name` member matches the name in the
*name* argument. If no such tag class exists ``None`` is returned.
.. method:: ResourceMixin.register_tagclasses(...)
Registers one or more tag classes indexing them by the value in the :attr:`name`
member of each class.
.. _mixin-execute:
ExecuteMixin Class
==================
Albatross only supplies one class for this function; the :class:`ExecuteMixin`
class. This mixin provides a "virtual machine" which is used to execute HTML
template files.
All standard Albatross execution context classes inherit from this class.
.. method:: ExecuteMixin.__init__()
When you inherit from the :class:`ExecuteMixin` class you must call this
constructor to initialise the internal variables.
.. method:: ExecuteMixin.get_macro_arg(name)
Retrieves a macro argument from the macro execution stack. The stack is
searched from the most recently pushed dictionary for an argument keyed by
*name*. If no argument is found a :exc:`MacroError` exception is raised.
.. method:: ExecuteMixin.push_macro_args(dict)
Pushes a dictionary of macro arguments onto the macro execution stack.
.. method:: ExecuteMixin.pop_macro_args()
Pops the most recently pushed dictionary of macro arguments from the macro
execution stack.
.. method:: ExecuteMixin.push_content_trap()
Saves accumulated content on the trap stack and then resets the content list.
.. method:: ExecuteMixin.pop_content_trap()
Joins all parts on the content list and returns the result. Sets the content
list to the value popped off the trap stack.
The content trap is useful for performing out-of-order execution of template
text. The ```` tag makes use of the content trap.
.. method:: ExecuteMixin.write_content(data)
Appends the content in *data* to the content list.
.. method:: ExecuteMixin.flush_content()
Does nothing if a content trap stack is in effect, otherwise it joins all parts
in the content list and sends it to the browser via the :meth:`send_content`
method. The content list is then reset via the :meth:`reset_content` method.
.. method:: ExecuteMixin.flush_html()
This is an alias for :meth:`flush_content`.
.. method:: ExecuteMixin.send_content(data)
Sends the content passed in the *data* argument to standard output. This is
overridden in the :class:`AppContext` class to redirect *data* to the
:meth:`write_content` method of the application referenced in the :attr:`app`
member.
.. method:: ExecuteMixin.reset_content()
Sets the content list to an empty list and clears the content trap stack.
.. _mixin-response:
ResponseMixin Class
===================
The :class:`ResponseMixin` class provides functionality to manage the delivery
of the application response to the browser. The class maintains headers in a
case insensitive ordered dictionary that ensures the headers are sent to the
browser in the same sequence as they are set (via :meth:`set_header` or
:meth:`add_header`).
The class automatically sends the headers to the browser when the first content
is sent. Any attempt to modify or send headers after they have been sent will
raise an :exc:`ApplicationError` exception.
All Albatross execution context classes except for :class:`SimpleContext`
inherit from this class.
.. method:: ResponseMixin.__init__()
When you inherit from the :class:`ResponseMixin` class you must call this
constructor to initialise the internal variables.
.. method:: ResponseMixin.get_header(name)
Returns a list of values of the *name* header from the internal store. If the
header does not exist then ``None`` is returned.
.. method:: ResponseMixin.set_header(name, value)
Sets the value of the *name* header to *value* in the internal store, replacing
any existing headers of the same name.
If headers have already been sent to the browser then an :exc:`ApplicationError`
exception will be raised.
.. method:: ResponseMixin.add_header(name, value)
Sets the value of the *name* header to *value* in the internal store, appending
the new header immediately after any existing headers of the same name.
If headers have already been sent to the browser then an :exc:`ApplicationError`
exception will be raised.
.. method:: ResponseMixin.del_header(name)
Removes the *name* header from the internal store.
If headers have already been sent to the browser then an :exc:`ApplicationError`
exception will be raised.
.. method:: ResponseMixin.write_headers()
Writes all headers in ascending sequence to the browser. Each header is sent
via the :class:`Request` object :meth:`write_header` method. At the end of
headers the :class:`Request` object :meth:`end_headers` method is called.
If headers have already been sent to the browser then an :exc:`ApplicationError`
exception will be raised.
.. method:: ResponseMixin.send_content(data)
Sends the content in *data* to the browser via the :class:`Request` object
:meth:`write_content` method.
If headers have not already been delivered to the browser then the
:meth:`write_headers` method is called before the *data* is written.
.. method:: ResponseMixin.send_redirect(loc)
If a cookie header has been set it is sent to the browser then the
:meth:`redirect` method of the :attr:`request` member is called and the result
is returned.
.. _mixin-template:
TemplateLoaderMixin Classes
===========================
This mixin is responsible for loading template files. Albatross supplies two
classes; :class:`TemplateLoaderMixin` and :class:`CachingTemplateLoaderMixin`.
.. _mixin-templ-loader:
TemplateLoaderMixin
-------------------
The :class:`TemplateLoaderMixin` class is a simplistic loader which performs no
caching.
.. method:: TemplateLoaderMixin.__init__(base_dir)
When you inherit from the :class:`TemplateLoaderMixin` class you must call the
constructor to define the root directory where template files will be loaded in
the *base_dir* argument.
.. method:: TemplateLoaderMixin.load_template(name)
Load and return the parsed template file specified in the *name* argument. The
path to the template file is constructed by performing ``os.path.join()`` on the
*base_dir* specified in the constructor and the *name* argument.
If there is an error reading the template a :exc:`TemplateLoadError` will be
raised.
The class remembers the names of all loaded templates.
.. method:: TemplateLoaderMixin.load_template_once(name)
Returns ``None`` if the template specified in the *name* argument has been
previously loaded. If not previously loaded it is loaded via the
:meth:`load_template` method and returned.
.. _mixin-templ-cache:
CachingTemplateLoaderMixin
--------------------------
The :class:`CachingTemplateLoaderMixin` class caches loaded templates to and
only reloads them if they have been modified since they were last loaded.
.. method:: CachingTemplateLoaderMixin.__init__(base_dir)
When you inherit from the :class:`CachingTemplateLoaderMixin` class you must
call the constructor to define the root directory where template files will be
loaded in the *base_dir* argument.
.. method:: CachingTemplateLoaderMixin.load_template(name)
Return the parsed template file specified in the *name* argument. The path to
the template file is constructed by performing ``os.path.join()`` on the
*base_dir* specified in the constructor and the *name* argument.
If there is an error reading the template a :exc:`TemplateLoadError` will be
raised.
If the template has been previously loaded it will only be reloaded if it has
been modified since last load.
.. method:: CachingTemplateLoaderMixin.load_template_once(name)
Call the :meth:`load_template` method and return the template if it is either
loaded for the first time or reloaded, else return ``None``.
.. _mixin-recorder:
RecorderMixin Classes
=====================
This mixin is passed form and input field recording messages as ````,
````, ````, and ```` tags are executed. Albatross
supplies two classes; :class:`StubRecorderMixin` and :class:`NameRecorderMixin`.
.. _mixin-rec-stub:
StubRecorderMixin
-----------------
The :class:`StubRecorderMixin` class ignores all form events.
.. method:: StubRecorderMixin.form_open()
Does nothing.
.. method:: StubRecorderMixin.form_close()
Does nothing.
.. method:: StubRecorderMixin.input_add(itype, name [, value ``= None``])
Does nothing.
.. method:: StubRecorderMixin.merge_request()
Merges request fields into ``ctx.locals``.
.. _mixin-rec-name:
NameRecorderMixin
-----------------
The :class:`NameRecorderMixin` class records details of all input fields used by
a form. When the form element is closed, a hidden field named ``__albform__``
containing these details is added to the form.
When processing a request, the :meth:`merge_request` method only merges fields
with ``ctx.locals`` when they match the details found in the submitted
``__albform__`` field.
.. method:: NameRecorderMixin.__init__()
When you inherit from the :class:`NameRecorderMixin` class you must call the
constructor.
.. method:: NameRecorderMixin.form_open()
Called when the ```` tag is opened.
.. method:: NameRecorderMixin.form_close()
Called just before the ```` tag is closed. A hidden field named
``__albform__`` is written to the output.
.. method:: NameRecorderMixin.input_add(itype, name [, value ``= None``] [, return_list ``= 0``])
Called when an ```` tag is executed. The *itype* argument contains
the ``type`` attribute from the input tag, *name* contains the ``name`` tag
attribute, and *value* contains the value of the input field if it is known and
relevant. The *return_list* argument indicates the presence of the ``list``
attribute on the input tag.
As fields are added to each form the value of the *return_list* argument is
checked against any previous setting of the argument for the same field name.
The argument value is also checked against whether or not there are multiple
instances of the field name. An detected discrepancy between the argument value
and actual fields will raise a :exc:`ApplicationError` exception.
.. method:: NameRecorderMixin.merge_request()
Retrieves the ``__albform__`` value from the browser request decodes it and then
merges the browser request into the local namespace accordingly.
If an input field has been flagged to return a list (via the ``list`` tag
attribute) then the method will create a list in ``ctx.locals`` for the field
regardless of the number of values sent by the browser. An empty list is
created when the field is missing from the browser request.
Request fields not listed in ``__albform__`` are ignored.
.. _mixin-namespace:
NamespaceMixin Class
====================
Albatross only supplies one class for this function; the :class:`NamespaceMixin`
class. This mixin provides a local and global namespace for evaluating
expressions embedded in HTML template files.
When the browser request is merged into the execution context the input field
values are written to the local namespace.
.. method:: NamespaceMixin.__init__()
When you inherit from the :class:`NamespaceMixin` class you must call the
constructor.
The global namespace for evaluating Python expressions in HTML templates is
initialised as an empty dictionary in the constructor.
.. attribute:: NamespaceMixin.locals
An empty object which is used for the local namespace for evaluating expressions
in HTML templates. It is initialised as an instance of an empty class in the
constructor to allow values to simply be assigned to attributes of this member.
Loading the session merges the session values into this member.
.. method:: NamespaceMixin.clear_locals()
Resets the :attr:`locals` member to an empty object.
.. method:: NamespaceMixin.set_globals(dict)
Sets the global namespace for evaluating expressions to the *dict* argument.
The :class:`SimpleContext` class constructor automatically sets this to the
globals of the function which invoked the :class:`SimpleContext` constructor.
The :meth:`run_template` and :meth:`run_template_once` methods of the
:class:`AppContext` calls this method to set global namespace to the globals of
the calling function.
.. method:: NamespaceMixin.eval_expr(expr)
Called by the template file interpreter to evaluate the embedded Python
expression in the *expr* argument.
.. method:: NamespaceMixin.set_value(name, value)
Sets the local namespace attribute named in the *name* argument to the value in
the *value* argument. If the *name* argument begins with an underscore the
method will raise a :exc:`SecurityError` exception.
This is used by the application :meth:`merge_request` method to merge individual
browser request fields into the local namespace.
There is a special "backdoor" identifier format which which directs browser
request fields to the :meth:`set_backdoor` method of :class:`ListIterator` and
:class:`TreeIterator` objects. The backdoor identifiers are generated by the
```` and ```` tags to implement sequence and tree browsing
requests.
The method implements a parser which can handle names of the form:
.. productionlist::
name: identifier \| list-backdoor \| tree-backdoor
identifier: identifier (("." identifier) \| ("[" number "]"))\*
list-backdoor: operation "," iter
tree-backdoor: operation "," iter "," alias
.. method:: NamespaceMixin.merge_vars(...)
This method merges request fields matching a prefix given in the argument list
to the local namespace (via the :meth:`set_value` method described above).
Normally, merging of request fields is automatic: either all request fields are
copied when :class:`StubRecorderMixin` is used, or fields listed in
``__albform__`` are copied when :class:`NameRecorderMixin` is used. However in
cases where :class:`NameRecorderMixin` is used and no ``__albform__`` field is
present, request merging does not occur, and this method is needed to allow the
application to explicitly request fields be merged.
.. method:: NamespaceMixin.make_alias(name)
Called to generate an alternate name for an object referenced in the ``alias``
attribute of an Albatross tag.
The method resolves the *name* argument up to the last "." and then calls the
:meth:`albatross_alias` method of the resolved object. The resolved object is
then entered into the local namespace and the session using the name returned by
:meth:`albatross_alias`.
The return value is a new name by combining the name returned by
:meth:`albatross_alias` with the part of the original name following and
including the last ".".
Refer to the ```` documentation in the :ref:`tag-input` section for an
explanation of why this method exists.
.. method:: NamespaceMixin.get_value(name)
Retrieves the value identified by the *name* argument from the local namespace.
If the named value does not exist then ``None`` is returned.
.. method:: NamespaceMixin.has_value(name)
Returns whether or not the value named in the *name* attribute exists in the
local namespace.
.. method:: NamespaceMixin.has_values(...)
Returns TRUE only if values named in the argument list exist in the local
namespace.
.. _mixin-ctxsession:
SessionContextMixin Classes
===========================
This mixin is used to manage the encoding and decoding of session data.
Albatross supplies a number of classes for use in the execution context;
:class:`StubSessionMixin`, :class:`SessionBase`,
:class:`HiddenFieldSessionMixin`, :class:`SessionServerContextMixin`, and
:class:`SessionFileContextMixin`. The :class:`SessionBase` class provides base
functionality for non-stub session classes.
Loading and storing of session data is usually performed by an application
mixin.
The :class:`SessionServerAppMixin` is designed to be used in the application
object.
.. _mixin-ses-stub:
StubSessionMixin
----------------
The :class:`StubSessionMixin` class ignores all session operations.
.. method:: StubSessionMixin.add_session_vars(...)
Does nothing.
.. method:: StubSessionMixin.del_session_vars(...)
Does nothing.
.. method:: StubSessionMixin.encode_session()
Does nothing.
.. method:: StubSessionMixin.load_session()
Does nothing.
.. method:: StubSessionMixin.save_session()
Does nothing.
.. method:: StubSessionMixin.remove_session()
Does nothing.
.. method:: StubSessionMixin.set_save_session(flag)
Does nothing.
.. method:: StubSessionMixin.should_save_session()
Returns ``0``.
.. _mixin-ses-base:
SessionBase
-----------
The :class:`SessionBase` class provides base session handling functionality
which is used by all standard Albatross execution context session mixin classes.
.. method:: SessionBase.__init__()
When you inherit from the :class:`SessionBase` class you must call this
constructor.
The class maintains a dictionary of all names from the execution context local
namespace which belong in the session. This dictionary is restored along with
the session when the session is decoded.
.. method:: SessionBase.add_session_vars(...)
Adds all listed names to the session dictionary. The named variables must exist
in the :attr:`locals` member or a :exc:`SessionError` will be raised.
The names can optionally be supplied as a list or tuple of names.
.. method:: SessionBase.default_session_var(name, value)
Adds a name to the session directory. Sets a value in the local namespace if the
name is not already in the local namespace.
.. method:: SessionBase.del_session_vars(...)
Deletes all listed names from the session dictionary.
The names can optionally be supplied as a list or tuple of names.
.. method:: SessionBase.session_vars()
Returns a list of the names that are currently in the session.
.. method:: SessionBase.remove_session()
Deletes all names from the session dictionary and clears all values from the
local namespace via the :meth:`clear_locals` method.
.. method:: SessionBase.decode_session(text)
Performs ``cPickle.loads()`` to retrieve a dictionary of session values. The
dictionary is merged into the session local namespace. Adds the keys of the
dictionary to the session dictionary.
Note that an import hook is used around the ``cPickle.loads()`` to redirect
requests to load page modules to the :meth:`app.load_page_module` method. This
allows the pickler to find classes which are defined in application page
modules. Whether a module is a page module is determined by calling the
:meth:`app.is_page_module` method, passing the module name.
.. method:: SessionBase.encode_session()
Builds a dictionary by extracting all local namespace values which are listed in
the session dictionary. A test pickle is performed on each value and any
unpickleable value is discarded and an error message is written to
``sys.stderr``.
The dictionary is then passed to ``cPickle.dumps()`` and the result is returned.
.. method:: SessionBase.set_save_session(flag)
Sets the flag which controls whether the session will be saved at the end of
request processing. By default the internal flag is ``TRUE`` which means the
session will be saved.
.. method:: SessionBase.should_save_session()
Returns the flag which controls whether the session will be saved at the end of
request processing.
.. _mixin-ses-field:
HiddenFieldSessionMixin
-----------------------
Saves session state to a hidden field named ``__albstate__`` at the end of every
form produced by ```` tags.
Inherits from the :class:`SessionBase` class so you must call the constructor if
you subclass this class.
.. method:: HiddenFieldSessionMixin.encode_session()
Extends the base class :meth:`encode_session` method to ``zlib.compress()`` and
``base64.encodestring()`` the result. This makes the session data suitable for
placing in a hidden field in the HTML.
.. method:: HiddenFieldSessionMixin.load_session()
This is called from the :class:`Application` class :meth:`load_session` method.
The session state is retrieved from the browser request, decoded and
decompressed then passed to the :meth:`decode_session` method.
.. method:: HiddenFieldSessionMixin.save_session()
This is called from the :class:`Application` class :meth:`save_session` method
at the end of the request processing sequence. The method does nothing because
the session state is saved in hidden fields in the HTML.
.. method:: HiddenFieldSessionMixin.form_close()
Called just before the ```` tag is closed. If the session is flagged
to be saved a hidden field named ``__albstate__`` is written to the output.
Note that this method is also present in the :class:`RecorderMixin`, so if you
inherit from the :class:`HiddenFieldSessionMixin` class you must define a
:meth:`form_close` method in the derived class which calls this method in both
of the super classes.
.. _mixin-ctx-sess:
SessionServerContextMixin
-------------------------
This class works in concert with the :class:`SessionServerAppMixin` application
mixin class to store session data in the Albatross session server. All
management of session data storage is performed by the application class.
Inherits from the :class:`SessionBase` class so you must call the constructor if
you subclass this class.
.. method:: SessionServerContextMixin.__init__()
When you inherit from the :class:`SessionServerContextMixin` class you must call
this constructor.
.. method:: SessionServerContextMixin.sesid()
Returns the session id.
.. method:: SessionServerContextMixin.load_session()
This is usually called from the :class:`Application` class :meth:`load_session`
method. Retrieves the session id and then either retrieves an existing session
or creates a new session via the application object.
If an existing session is retrieved it is passed to ``base64.decodestring()``
and ``zlib.decompress()`` then passed to the :meth:`decode_session` method
(inherited from the superclass). If an exception is raised during
:meth:`decode_session` then the session will be deleted from the server and a
new session will be created via the application object :meth:`new_session`
method.
.. method:: SessionServerContextMixin.save_session()
This is called from the :class:`Application` class :meth:`save_session` method
at the end of the request processing sequence. If the session save flag has
been cleared via the :meth:`set_save_session` method then the session is not
saved.
Before saving a session the method calls the superclass :meth:`encode_session`
then calls ``zlib.compress()`` and ``base64.encodestring()`` to convert the
session to plain text which is passed to the :meth:`put_session` application
method to save the session.
.. method:: SessionServerContextMixin.remove_session()
This is called from the :class:`Application` class :meth:`remove_session`
method. The method calls the superclass :meth:`remove_session` then calls the
:meth:`del_session` application method to remove the session at the server.
.. _mixin-ctx-file-sess:
SessionFileContextMixin
-----------------------
This class works in concert with the :class:`SessionFileAppMixin` application
mixin class to store session data in the local file-system. All management of
session data storage is performed by the application class.
Inherits from the :class:`SessionBase` class so you must call the constructor if
you subclass this class.
.. method:: SessionFileContextMixin.__init__()
When you inherit from the :class:`SessionFileContextMixin` class you must call
this constructor.
.. method:: SessionFileContextMixin.sesid()
Returns the session id.
.. method:: SessionFileContextMixin.load_session()
This is usually called from the :class:`Application` class :meth:`load_session`
method. Retrieves the session id and then either retrieves an existing session
or creates a new session via the application object.
If an existing session is retrieved it is passed to the :meth:`decode_session`
method (inherited from the superclass). If an exception is raised during
:meth:`decode_session` then the session will be deleted from the server and a
new session will be created via the application object :meth:`new_session`
method.
.. method:: SessionFileContextMixin.save_session()
This is called from the :class:`Application` class :meth:`save_session` method
at the end of the request processing sequence. If the session save flag has
been cleared via the :meth:`set_save_session` method then the session is not
saved.
Before saving a session the method calls the superclass :meth:`encode_session`
then calls the :meth:`put_session` application method to save the session.
.. method:: SessionFileContextMixin.remove_session()
This is called from the :class:`Application` class :meth:`remove_session`
method. The method calls the superclass :meth:`remove_session` then calls the
:meth:`del_session` application method to remove the session at the server.
.. _mixin-ctx-branching-sess:
BranchingSessionMixin
---------------------
A persistent problem with server-side sessions is the browser state getting out
of synchronisation with the application state. This occurs when the browser
"back" button is used, or when a form is reloaded (this is logically equivilent
to a "back" then a resubmission of the old form state).
One solution to this problem is to maintain a server-side session for each
interaction with the browser, rather than a single session per client that is
recycled for each interaction. A unique session identifier is stored in a hidden
form field, which allows us to retrieve the appropriate version of the session
on form submission (the hidden field value is rolled back with the browser state
when the "back" button is used, unlike a cookie). This class provides a drop-in
replacement for the :class:`SessionServerContextMixin` and implements this
session-per-interaction behaviour.
.. method:: BranchingSessionMixin.__init__()
When you inherit from the :class:`BranchingSessionMixin` class you must call
this constructor.
.. method:: BranchingSessionMixin.sesid()
Returns the session id.
.. method:: BranchingSessionMixin.load_session()
This is usually called from the :class:`Application` class :meth:`load_session`
method. Retrieves the session id and then either retrieves an existing session
or creates a new session via the application object.
If an existing session is retrieved it is passed to the :meth:`decode_session`
method (inherited from the superclass). If an exception is raised during
:meth:`decode_session` then the session will be deleted from the server and a
new session will be created via the application object :meth:`new_session`
method.
.. method:: BranchingSessionMixin.save_session()
This is called from the :class:`Application` class :meth:`save_session` method
at the end of the request processing sequence. If the session save flag has
been cleared via the :meth:`set_save_session` method then the session is not
saved.
Before saving a session the method calls the superclass :meth:`encode_session`
then calls the :meth:`put_session` application method to save the session.
.. method:: BranchingSessionMixin.remove_session()
This is called from the :class:`Application` class :meth:`remove_session`
method. The method calls the superclass :meth:`remove_session` then calls the
:meth:`del_session` application method to remove the session at the server.
.. method:: BranchingSessionMixin.form_close()
Called just before the ```` tag is closed. If the session is flagged
to be saved a hidden field named ``__albsessid__`` containing the session
identifier is written to the output.
Note that this method is also present in the :class:`RecorderMixin`, so if you
inherit from the :class:`BranchingSessionMixin` class you must define a
:meth:`form_close` method in the derived class which calls this method in both
of the super classes.
.. _mixin-appsession:
SessionAppMixin Classes
=======================
.. _mixin-app-sess:
SessionServerAppMixin
---------------------
The application mixin works in concert with the
:class:`SessionServerContextMixin` execution context method to store sessions in
the Albatross session server.
Whenever there are problems communicating with the session server the class
raises a :exc:`SessionServerError` exception, which is a subclass of
:exc:`SessionError`. Unless you have a reason to do otherwise, catch
:exc:`SessionError` rather than :exc:`SessionServerError`, as this allows other
Session classes to be substituted with minimal change.
.. method:: SessionServerAppMixin.__init__(appid [, server ``= 'localhost'``] [, port ``= 34343``] [, age ``= 1800``])
When you inherit from the :class:`SessionServerAppMixin` class you must call
this constructor.
The *appid* argument specifies the name of the cookie attribute which is used to
store the session id. This uniquely identifies the application at the web
server. Multiple applications can share sessions by defining the same value in
this argument.
The *server* and *port* arguments specify the location of the Albatross session
server. By using a session server you can have a number of web serving machines
which transparently share session data.
The *age* argument specifies how long (in seconds) an idle session will be
stored at the server before it is discarded.
A connection to the session server is established. The connection will be kept
open for the lifetime of the application object.
.. method:: SessionServerAppMixin.ses_appid()
Returns the *appid* argument which was passed to the constructor.
.. method:: SessionServerAppMixin.get_session(sesid)
Returns the session identified by *sesid* argument and the *appid* passed to the
constructor. If no such session exists ``None`` is returned.
.. method:: SessionServerAppMixin.new_session()
Returns a new session id for the *appid* passed to the constructor.
.. method:: SessionServerAppMixin.put_session(sesid, text)
Saves the *text* argument as session data for the session identified by *sesid*
argument and the *appid* passed to the constructor.
.. method:: SessionServerAppMixin.del_session(sesid)
Removes the session identified by *sesid* argument and the *appid* passed to the
constructor.
.. _mixin-app-file-sess:
SessionFileAppMixin
-------------------
The application mixin works in concert with the :class:`SessionFileContextMixin`
execution context method to store sessions in the local file-system.
Whenever there are problems reading or writing sessions from or to disk, the
class raises a :exc:`SessionFileError` exception, which is a subclass of
:exc:`SessionError`. Unless you have a reason to do otherwise, catch
:exc:`SessionError` rather than :exc:`SessionFileError`, as this allows other
Session classes to be substituted with minimal change.
.. method:: SessionFileAppMixin.__init__(appid , session_dir)
When you inherit from the :class:`SessionFileAppMixin` class you must call this
constructor.
The *appid* argument specifies the name of the cookie attribute which is used to
store the session id. This uniquely identifies the application at the web
server. Multiple applications can share sessions by defining the same value in
this argument.
The *session_dir* argument specifies the location on the local file-system in
which this application's sessions will be stored.
The directory should not be publicly readable, as the session file names are the
session id's (knowing a session id allows an attacker to steal that session).
Sessions recorded via this class are not automatically aged. An external process
will be required to clean orphaned sessions from the session directory (for
example, by removing any file that has not been accessed in the last two hours).
.. method:: SessionFileAppMixin.ses_appid()
Returns the *appid* argument which was passed to the constructor.
.. method:: SessionFileAppMixin.get_session(sesid)
Returns the session identified by *sesid* argument and the *appid* passed to the
constructor. If no such session exists ``None`` is returned.
.. method:: SessionFileAppMixin.new_session()
Returns a new session id for the *appid* passed to the constructor.
Note that if the *session_dir* passed to the constructor does not already exist,
this method will attempt to create it.
.. method:: SessionFileAppMixin.put_session(sesid, text)
Saves the *text* argument as session data for the session identified by *sesid*
argument and the *appid* passed to the constructor.
.. method:: SessionFileAppMixin.del_session(sesid)
Removes the session identified by *sesid* argument and the *appid* passed to the
constructor.
.. _mixin-sign:
PickleSignMixin Classes
=======================
This is mixed with the application class to sign or modify pickles before
sending them to the browser and to undo and check that modification on the
return trip. When processing modified pickles returned from the browser the
class discards pickles which do not pass the security check.
There is only one mixin supplied for this function; the :class:`PickleSignMixin`
class. Pickle strings are combined with the secret string which was passed to
the application constructor as the *secret* argument using the HMAC-SHA1
algorithm. The resulting signature is then prepended to the pickle. On the
return trip the HMAC-SHA1 sign is compared with the result of the signing
process on the pickle returned from the browser. If the two signs are not the
same, the pickle is discarded.
The process does not prevent users from seeing the contents of a pickle, rather
it provides an assurance of its authenticity.
The mixin has the following interface.
.. method:: PickleSignMixin.__init__(secret)
When you inherit from the :class:`PickleSignMixin` class you must call this
constructor.
The *secret* argument is the secret key which is combined with the pickle to
produces the HMAC-SHA1 signature.
.. method:: PickleSignMixin.pickle_sign(text)
Generates an HMAC-SHA1 signed copy of the *text* argument, using the *secret*
constructor argument as key.
.. method:: PickleSignMixin.pickle_unsign(text)
Compares the HMAC-SHA1 signature on the given *text*, and if valid, returns the
unsigned text. If the signature does not match, a :exc:`SecurityError` exception
is raised.
.. _mixin-page:
PageMixin Classes
=================
The choice of mixin for this functionality determines how Albatross will locate
the code to process the browser request and display the response for each page.
Albatross supplies three classes; :class:`PageModuleMixin`,
:class:`RandomPageModuleMixin`, and :class:`PageObjectMixin`.
.. _mixin-page-module:
PageModuleMixin
---------------
This class uses a separate Python module for each page in the application. This
scales very well at runtime because at most two modules will be loaded for each
request; one to process the browser request, and possibly another to display the
response. Page modules are cached for further efficiency. The class is
designed to be used where the application controls the sequence of pages seen in
a browser session so the start page is also specified in the constructor.
Application page modules are loaded from a base directory which is specified by
the constructor *base_dir* argument. The current application page is identified
by the path to the page module relative to the module base directory. Page
identifiers consist of an optional path component followed by a module name
without extension. For example ``"login"``, ``"user/list"``,
``"home-page/default"``.
Page modules are loaded into a dummy ``__alpage__`` namespace to avoid conflicts
with python modules, so loading ``"user/list"`` actually imports the module as
:mod:`__alpage__.user.list`.
To support pickling of instances defined in a page module, a dummy hierarchy of
modules needs to be created. In the :mod:`__alpage__.user.list` case mentioned
above, a temporary dummy module called :mod:`__alpage__.user` is registered.
This will be replaced by the real ``user`` module later if it is loaded.
Note also that the :class:`SessionBase` mixin uses an import hook while decoding
the session to redirects attempts to load page modules (those that being with
``__alpage__``) to the :meth:`load_page_module` method.
Page modules handled by this mixin have the following interface:
.. function:: page_enter(ctx [, ...])
:noindex:
If this function is present in the new page module it will be called whenever
your application code calls the execution context :meth:`set_page` method. For
application types which define a start page this method is called in the start
page when a new session is created.
The *ctx* argument contains the execution context. Any extra arguments which
are passed to the :func:`set_page` method are passed as optional extra arguments
to this function.
.. function:: page_leave(ctx)
:noindex:
If this function is present in the current page module it will be called
whenever your application code changes to another page by calling the execution
context :meth:`set_page` method.
The *ctx* argument contains the execution context.
.. function:: page_process(ctx)
:noindex:
If this function is present in the page module it will be called when the
application object executes the :meth:`process_request` method. This occurs if
the browser request was successfully validated.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. function:: page_display(ctx)
:noindex:
This is the only mandatory page module function. The application object calls
this function when it executes the :meth:`display_response` method as the final
step before saving the browser session.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
The :class:`PageModuleMixin` class has the following interface.
.. method:: PageModuleMixin.__init__(base_dir, start_page)
When you inherit from the :class:`PageModuleMixin` class you must call this
constructor.
The *base_dir* argument specifies the path of the root directory where page
modules are loaded from. When deploying your application as a CGI program you
can specify a relative path from the location of the application mainline.
Apache sets the current directory to root so when using ``mod_python``
deployment you will need to specify a path relative to the root.
The *start_page* argument is a page identifier which specifies the first page
that new browser session will see.
.. method:: PageModuleMixin.module_path()
Returns the *base_dir* which was passed to the constructor.
.. method:: PageModuleMixin.start_page()
Returns the *start_page* which was passed to the constructor.
.. method:: PageModuleMixin.load_page(ctx)
This method implements part of the standard application processing sequence. It
is called immediately after restoring the browser session. The *ctx* argument
is the execution context for the current browser request.
If no current page is defined in *ctx* then the method will invoke
:meth:`ctx.set_page` passing the page specified as the *start_page* argument to
the application constructor.
The actual page module load is performed via the :meth:`load_page_module`
method.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. method:: PageModuleMixin.load_page_module(ctx, name)
Loads the page module identified by the *name* argument and saves a reference to
the module in the :attr:`page` member.
.. method:: PageModuleMixin.page_enter(ctx, args)
Called when your application code calls the execution context :meth:`set_page`
method. The *ctx* argument is the execution context for the current browser
request. The *args* argument is a tuple which contains all optional extra
arguments which were passed to the :meth:`set_page` method.
The page module :func:`page_enter` function is called by this method.
.. method:: PageModuleMixin.page_leave(ctx)
Called before changing pages when your application code calls the execution
context :meth:`set_page` method. The *ctx* argument is the execution context
for the current browser request.
The page module :func:`page_leave` function is called by this method.
.. method:: PageModuleMixin.process_request(ctx)
This method implements part of the standard application processing sequence. It
is called if the browser request is successfully validated. The *ctx* argument
is the execution context for the current browser request.
The page module :func:`page_process` function is called by this method.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. method:: PageModuleMixin.display_response(ctx)
This method implements part of the standard application processing sequence. It
is called as the final stage just before the session is saved. The *ctx*
argument is the execution context for the current browser request.
The page module :func:`page_display` function is called by this method.
Refer to section the :ref:`app-model` section for an overview of the application
processing sequence.
.. _mixin-randpage-module:
RandomPageModuleMixin
---------------------
This class inherits from the :class:`PageModuleMixin` class. It redefines the
way in which page modules are selected.
Instead of the application calling the :meth:`set_page` execution context
method, the URL in the browser request controls which page module is loaded and
processed for each request.
Page module management is inherited from :class:`PageModuleMixin`. The
*base_dir* argument to the constructor determines the root directory where
modules are loaded from.
Page modules handled by this mixin have the following interface:
.. function:: page_enter(ctx)
:noindex:
If this function is present in the page module it will be called every time the
page module is used for a browser request.
The *ctx* argument contains the execution context.
.. function:: page_process(ctx)
:noindex:
If this function is present in the page module it will be called when the
application object executes the :meth:`process_request` method. This occurs if
the browser request was successfully validated.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. function:: page_display(ctx)
:noindex:
This is the only mandatory page module function. The application object calls
this function when it executes the :meth:`display_response` method as the final
step before saving the browser session.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
The :class:`RandomPageModuleMixin` class has the following interface.
.. method:: RandomPageModuleMixin.load_page(ctx)
This method implements part of the standard application processing sequence. It
is called immediately after restoring the browser session. The *ctx* argument
is the execution context for the current browser request.
The :meth:`get_page_from_uri` method is called to determine the identifier of
the page module that will be loaded. The identifier is then passed to the
:meth:`load_page_module` method (which is inherited from
:class:`PageModuleMixin`).
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. method:: RandomPageModuleMixin.get_page_from_uri(ctx, uri)
The method uses the :func:`urlparse` function from the standard Python
:func:`urlparse` module to extract the path component from both the *uri*
parameter and the value returned by the :meth:`base_url` method (which returns
the *base_url* argument to the application constructor).
The *path* component of the *base_url* is then used to split the *path*
component of the *uri*. Element one (first split to the right of *base_url*) of
the resulting string list is returned as the page identifier.
Override this method in your application if you wish to implement a your own
scheme for mapping the request onto a page identifier.
.. method:: RandomPageModuleMixin.load_badurl_template(ctx)
Called when your page template identified by the request URL does not exist.
The *ctx* argument is the execution context for the current browser request.
Override this method if you want to supply a different error page template.
.. method:: RandomPageModuleMixin.page_enter(ctx)
Called as soon as the page module has been loaded. The *ctx* argument is the
execution context for the current browser request.
The page module :func:`page_enter` function is called by this method if a page
module was located by the :meth:`load_page` method.
.. method:: RandomPageModuleMixin.process_request(ctx)
This method implements part of the standard application processing sequence. It
is called if the browser request is successfully validated. The *ctx* argument
is the execution context for the current browser request.
The page module :func:`page_process` function is called by this method if a page
module was located by the :meth:`load_page` method.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. method:: RandomPageModuleMixin.display_response(ctx)
This method implements part of the standard application processing sequence. It
is called as the final stage just before the session is saved. The *ctx*
argument is the execution context for the current browser request.
The page module :func:`page_display` function is called by this method if a page
module was located by the :meth:`load_page` method.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. _mixin-page-object:
PageObjectMixin
---------------
This class is intended for applications which do not require a separate Python
module for each page in the application. Page processing is performed by a set
of objects which the application registers with this class. The class is
designed to be used where the application controls the sequence of pages seen in
a browser session so the start page is specified in the constructor.
Application page objects must be registered before they can be used. Typically
you will register the page objects immediately after constructing your
application object. Since the current application page is identified by an
internal value, any hashable pickleable value can be used as an identifier.
Page objects handled by this mixin have the following interface:
.. method:: PageObject.page_enter(ctx [, ...])
:noindex:
If this method is present in the new page object it will be called whenever your
application code changes current the page by calling the execution context
:meth:`set_page` method. For application types which define a start page this
method is called in the start page when a new session is created.
The *ctx* argument contains the execution context. Any extra arguments which
are passed to the :func:`set_page` method are passed as optional extra arguments
to this method.
.. method:: PageObject.page_leave(ctx [, ...])
:noindex:
If this method is present in the old page object it will be called whenever your
application code changes current the page by calling the execution context
:meth:`set_page` method.
The *ctx* argument contains the execution context.
.. method:: PageObject.page_process(ctx)
:noindex:
If this method is present in the page object it will be called when the
application object executes the :meth:`process_request` method. This occurs if
the browser request was successfully validated.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. method:: PageObject.page_display(ctx)
:noindex:
This is the only mandatory page object function. The application object calls
this method when it executes the :meth:`display_response` method as the final
step before saving the browser session.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
The :class:`PageObjectMixin` class has the following interface.
.. method:: PageObjectMixin.__init__(start_page)
When you inherit from the :class:`PageObjectMixin` class you must call this
constructor.
The *start_page* argument is a page identifier which specifies the first page
that new browser session will see.
.. method:: PageObjectMixin.module_path()
Returns ``None``.
.. method:: PageObjectMixin.start_page()
Returns the *start_page* argument which was passed to the constructor.
.. method:: PageObjectMixin.register_page(name, obj)
You must call this method to register every page object in your application.
The *name* argument defines the page identifier which is used to select the page
object specified in the *obj* argument. All pages must be registered before
they can be used.
.. method:: PageObjectMixin.load_page(ctx)
This method implements part of the standard application processing sequence. It
is called immediately after restoring the browser session. The *ctx* argument
is the execution context for the current browser request.
If no current page is defined in *ctx* then the method will invoke
:meth:`ctx.set_page` passing the page specified as the *start_page* argument to
the application constructor.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. method:: PageObjectMixin.page_enter(ctx, args)
Called when your application code calls the execution context :meth:`set_page`
method. The *ctx* argument is the execution context for the current browser
request. The *args* argument is a tuple which contains all optional extra
arguments which were passed to the :meth:`set_page` method.
The page object :func:`page_enter` method is called by this method.
.. method:: PageObjectMixin.page_leave(ctx)
Called before changing pages when your application code calls the execution
context :meth:`set_page` method. The *ctx* argument is the execution context
for the current browser request.
The page object :func:`page_leave` method is called by this method.
.. method:: PageObjectMixin.process_request(ctx)
This method implements part of the standard application processing sequence. It
is called if the browser request is successfully validated. The *ctx* argument
is the execution context for the current browser request.
The page object :func:`page_process` method is called by this method.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. method:: PageObjectMixin.display_response(ctx)
This method implements part of the standard application processing sequence. It
is called as the final stage just before the session is saved. The *ctx*
argument is the execution context for the current browser request.
The page object :func:`page_display` method is called by this method.
Refer to the :ref:`app-model` section for an overview of the application
processing sequence.
.. _mixin-request:
Request Classes
===============
The choice of :class:`Request` class determines how you wish to deploy your
application. Albatross supplies a number of pre-built Request implementations
suited to various deployment methods. These include:
+--------------------------------+----------------------------+
| Deployment Method | Request Module |
+================================+============================+
| CGI | :mod:`albatross.cgiapp` |
+--------------------------------+----------------------------+
| mod_python | :mod:`albatross.apacheapp` |
+--------------------------------+----------------------------+
| FastCGI_python | :mod:`albatross.fcgiapp` |
+--------------------------------+----------------------------+
| Stand-alone Python HTTP server | :mod:`albatross.httpdapp` |
+--------------------------------+----------------------------+
You can also develop your own :class:`Request` class to deploy an Albatross
application in other ways.
All :class:`Request` classes implement the same interface. Much of this
interface can be supplied by the :class:`RequestBase` mixin.
.. method:: Request.has_field(name)
Returns ``TRUE`` if the field identified by the *name* argument is present in
the request.
.. method:: Request.field_value(name)
Return the value of the field identified by the *name* argument.
.. method:: Request.field_file(name)
Returns an object that contains the value of a file input field.
.. method:: Request.field_names()
Return a list of all all fields names in the request.
.. method:: Request.get_uri()
Return the URL which the browser used to perform the request.
.. method:: Request.get_servername()
Return the name of the server (Apache ServerName setting).
.. method:: Request.get_header(name)
Return the value of the HTTP header identified in the *name* argument.
.. method:: Request.write_header(name, value)
Add a header named *name* with the value *value* to the response. This method
should not be called once you have started sending content to the browser.
.. method:: Request.end_headers()
Signal to the Request object that header generation has finished and that you
are ready to start sending content.
.. method:: Request.redirect(loc)
Send a ``"301 Moved Permanently"`` response back to the browser.
.. method:: Request.write_content(data)
Send *data* as part of the request response.
.. method:: Request.set_status(status)
Sets the HTTP status code of the response. Defaults to 200. For deployment
methods based on the cgiapp module, this value is used to derive the ``Status:``
header. The apacheapp module uses it to set the :attr:`status` member of the
mod_python :class:`request` object.
.. method:: Request.status(num)
Return the saved value for the HTTP status code.
.. method:: Request.return_code()
Returns a value which should be returned from the :class:`Application` class
:meth:`run` method. For most deployment methods, this is ``None``, however the
``mod_python`` requires that ``mod_python.apache.OK`` be returned if
application emits any content. Your ``mod_python`` application should include
code such as this:
.. code-block:: python
from albatross.apacheapp import Request
...
def handler(req):
return app.run(Request(req))