Myghty Documentation
Version: 1.2 Last Updated: 07/07/10 12:55:17
View: Paged  |  One Page

This section describes some options that can be applied to Myghty components which affect how the request object deals with their output. The request object supports the capturing of component output in a buffer which is flushed upon completion to provide simple and flexible component output behavior, or sending the output directly to the underlying output stream to provide faster perceived response time. This option is known as autoflush. Post-processing functions can be attached to the final output of a component at the top-level or callable component level, allowing user-defined text operations on the output, known as filtering. Autoflushing and filtering have some dependencies on each other, so they are described together.

As a convenient alternative to filtering, common text-escaping functions applicable to a web application environment, plus support for user-defined escape functions, are provided under the functionality of escapes, described at the end of the section.

The Autoflush Option

The autoflush option controls whether the output of a component is sent to the underlying output stream as it is produced, or if it is first captured in a buffer which is then sent in one chunk at the end of the request's lifecycle. This is significant in a web context, as it affects "perceived performance", which means the response time of an unbuffered page is nearly immediate, even though the time it takes to finish might be the same as that of a buffered page.

While the autoflush option can improve perceived performance, there are also increased complexities with an autoflushed, i.e. unbuffered page. HTTP headers, including hard redirects, must be sent before any content is written, else the response will have already begun and any new headers will simply be displayed with the page's content. A soft redirect, not being dependent on HTTP headers, will still function, but it's output also may be corrupted via any preceding output. Error messages also will appear inline with already existing content rather than on a page of their own.

The option can be set for an entire application, for a set of files or directories via autohandlers/inherited superpages, for an individual page, or even an individual method or subcomponent within a page. Within all of those scopes, the flag can be set at a more specific level and will override the more general level.

With no configuration, the parameter defaults to False, meaning that component output is captured in a buffer, which is flushed at the end of the request or subcomponent's execution. This produces the simplest behavior and is fine for most applications.

But, here you are and you want to turn autoflush on. To set it across an entire application, specify autoflush=True to the Interpreter or HTTPHandler being used. Or to configure via http.conf with mod_python:

PythonOption MyghtyAutoflush True

When autoflush is true for an entire application, no buffer is placed between the output of a component and the underlying request output stream. The flag can be overridden back to False within directories and pages via the use of the autoflush flag within the %flags section of the page. To set the value of autoflush for a particular directory, place an autohandler file at the base of the directory as such:

<%flags>autoflush=False</%flags>
% m.call_next()

The Myghty request will run the autohandler which then calls the inherited page via the m.call_next() call. The autoflush flag indicates that buffering should be enabled for the execution of this page, overriding the per-application setting of True.

The ultimate autoflush flag that is used for a page is the innermost occuring flag within the templates that comprise the wrapper chain. If no autoflush flag is present, the next enclosing template is used, and if no template contains an autoflush flag, the application setting is used. Even though an autohandler executes before the page that it encloses, the Myghty request figures out what the autoflush behavior should be before executing any components so that it takes the proper effect.

So any page can control its own autoflush behavior as follows:

<%flags>autoflush=False</%flags>
<html>
    <head>
    ...
</html>
Setting Autoflush in Subcomponents

Subcomponent or methods can determine their autoflush behavior as follows:

<%def mycomp>
<%flags>autoflush=False</%flags>
    ... stuff ...
</%def>

There is one limitation to the autoflush flag when used in a subcomponent. If autoflush is set to True on a subcomponent, within a request that has autoflush set to False, the component will send its unfiltered data directly to the output stream of its parent; however since the overall request is not autoflushing and is instead capturing its content in a buffer of its own, the content is still stored in a buffer, which does not get sent to the client until the request is complete. Note that this limitation does not exist the other way around; if an overall request is autoflushing, and a subcomponent sets autoflush to False, that subcomponent's output will be buffered, until the subcomponent completes its execution. This is significant for a subcomponent whos output is being processed by a <%filter> section. More on this later.

back to section top
Non-Buffered with Autohandlers

What happens when a page in an autoflush=True environment interacts with one or more autohandlers or inherited superpages? The superpage will execute first, output whatever content it has before it calls the subpage, and then will call m.call_next() to pass control to the subpage. If the subpage then wants to play with HTTP headers and/or perform redirects, it's out of luck:

autohandler - autoflush enabled
<%flags>autoflush=True</%flags>
<html>
    <head></head>
    <body>
% m.call_next()
    </body>
</html>
page.myt - wants to send a redirect
<%python scope="init">
    m.send_redirect("page2.myt", hard=True)
</%python>

The above example will fail! Since the autohandler executes and prints the top HTML tags to the underlying output stream, by the time page.myt tries to send its redirect, the HTTP headers have already been written and you'll basically get a broken HTML page. What to do? Either page.myt needs to specify that it is not an autoflushing page, or it can detach itself from its inherited parent.

Solution One - Turn Autoflush On:

page.myt
<%flags>autoflush=False</%flags>
<%python scope="init">
    m.send_redirect("page2.myt", hard=True)
</%python>

This is the most general-purpose method, which just disables autoflush for just that one page.

Solution Two - Inherit from None

page.myt
<%flags>inherit=None</%flags>
<%python scope="init">
    m.send_redirect("page2.myt", hard=True)
</%python>

This method is appropriate for a page that never needs to output any content, i.e. it always will be performing a redirect. The autohandler here is not inherited, so never even gets called. This saves you the processing time of the autohandler setting up buffers and producing content. Of course, if there are autohandlers that are performing operations that this subpage depends upon, then you must be sure to inherit from those pages, possibly through the use of "alternate" autohandlers that inherit only from the desired pages.

back to section top
Filtering

Filtering means that the output stream of a component is sent through a text processing function which modifies the content before it is passed on to the ultimate output stream. Typical usages of text filtering are modifying entity references, trimming whitespace, converting plain-text to HTML, and lots of other things. For the general purpose per-component filter, Myghty supplies the <%filter> tag.

The <%filter> Tag

%filter describes a filtering function that is applied to the final output of a component. This is more common on subcomponents or methods but works within the scope of any top-level component as well. The Python code within the %filter section provides the body of the to be used; the heading of the function is generated within the compiled component and not normally seen. The filter function is provided with one argument f which contains the content to be filtered; the function processes content and returns the new value.

Example:

<%filter>
import re
return re.sub(r"turkey", "penguin", f)
</%filter>

dang those flyin turkeys !

will produce:

dang those flyin penguins !
back to section top
Escaping Content in a Filter Section

Myghty has some built in escaping functions, described in the next section Escaping Content. While these functions are easy enough to use within substitutions or any other Python code, you can of course use them within a filter section as well.

This is a component that HTML escapes its output, i.e. replaces the special characters &, <, and > with entity reference encoding:

<%def bodytext>
    <%filter>
        return m.apply_escapes(f, 'h')
    </%filter>

    # ... component output
</%def>
back to section top
Filtering Behavior with Autoflush Enabled

The usual case when a %filter section is used is that all m.write() statements, both explicit and implicit, send their content to a buffer. Upon completion of the component's execution, the buffer's content is passed through the function defined in the %filter section. However when autoflush is enabled, the extra buffer is not used and the filtering function is attached directly to each call to m.write(). For regular blocks of HTML, the entire block is sent inside of one big write() statement, but each python substitution or other code call splits it up, resulting in another call to write().

Since a non-autoflushing component is more predictable for filtering purposes than an autoflushing component, it is often useful to have autoflush disabled for a component that uses a %filter section. As stated in the autoflush section, autoflushing behavior can be changed per component, per page or for the whole application, and is the default value as well. There is also another configuration option can be overridden for all filter components by the setting "dont_auto_flush_filters" - see the section Index of Configuration Parameters for more information.

back to section top
Filtering Whitespace - the Trim Flag

A common need for components is to trim off the whitespace at the beginning and/or the end of a component output. It is convenient to define subcomponents and methods on multiple lines, but this inherently includes newlines in the output of that component, since Myghty sees the blank lines in the source. But lots of times the ultimate output of a component needs to not have any surrounding whitespace, such as a component that outputs a hyperlink. While a regular %filter section can be used for this, Myghty provides the trim flag, as so:

for more information, click <&makelink, a="here", p=4.3, xg="foo" &>.

<%def makelink trim="both">
<%args>
    p
    xg
    a
</%args>

<%doc>note this component has a lot of whitespace in it</%doc>
<A href="http://foo.myt?xg=<% xg %>&p=<% p | u %>"><% a %></a>

</%def>

Output:

for more information, click <A href="http://foo.myt?xg=foo&p=4.3">here</a>.

trim supports the three options left, right, or both, trimming whitespace on the left, right and both sides of component output, respectively.

back to section top
Escaping Content

Escaping usually refers to a kind of filtering that converts the characters in a string into encoded values that can be safely passed through other character-parsing systems without them interfering.

Myghty provides built in support for HTML and URL escaping (also called URL encoding), and has plans for entity-reference escaping. User-defined escape functions can be added to an application as well.

Escaping Substitutions

Substitutions, first introduced in Substitutions, can include escape flags, specified by the following notation:

 
    <% "i am an argument" | u %>

The above example will URL encode the embedded string. The two escape flags included with Myghty are "u" for url encoding, and "h" for HTML encoding. Entity reference encoding is in the works.

Multiple escape flags are separated by a comma:

 
    <% "multiple escapes" | h, u %>

Which will HTML and URL escape the given string.

back to section top
Programmatic Escaping

The HTML and URL-encoded escaping functions described above are easy enough to use programmatically as well. The request object provides the escaping functions via the apply_escapes() method for this purpose. This method uses the same flags as an escaped substitution, the defaults being "h" for HTML escaping and "u" for URL encoding.

In this example, a component receives the argument "text" and displays it in a textarea, where HTML escaping is required:

<%args>
    text
</%args>
<%python>
    # HTML escape the given text
    text = m.apply_escapes(text, 'h')
</%python>

<textarea><% text %></textarea>

The first argument to apply_escapes() is the text to be escaped, and the second is a list of escape flags. Since strings are lists in Python, multiple flags can be specified either in a single string as in "hu" or as a regular list such as ['h', 'u'].

back to section top
Custom Escape Flags

You can add your own escape flags to your application via the escapes configuration parameter. escapes is in the form of a dictionary, with the key names being the single-character escaping token and the values being function pointers to escaping functions.

In this example, an escape flag 'p' is added which provides the ability to convert the word "turkey" into "penguin":

escapes = {
    'p':re.sub('turkey', 'penguin', f)
}
back to section top
Default Escape Flags

Default escaping can be configured via the configuration parameter default_escape_flags (PythonOption MyghtyDefaultEscapeFlags). The format of this parameter is a list of escape flag characters. This applies the given flags to all substitutions in an application.

When default escaping is used, the special flag "n" can be specified in the substitution to disable the default escape flags for that substitution.

back to section top
Previous: Special Templates | Next: Session