Remove generated HTML docs from the version control system.

This commit is contained in:
Neil Schemenauer 2012-01-02 13:49:37 -06:00
parent b799be7d7f
commit 5a2856c6d5
14 changed files with 1 additions and 2971 deletions

View File

@ -1,6 +1,5 @@
global-include *.py *.ptl
include *.txt MANIFEST.in TODO
include doc/*.txt doc/*.css doc/Makefile
recursive-include doc *.html
include doc/*.txt doc/*.css doc/*.html doc/Makefile
include demo/*.cgi demo/*.conf demo/*.sh
include src/*.c src/Makefile

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document">
<div class="section" id="installing-quixote">
<h1><a name="installing-quixote">Installing Quixote</a></h1>
<p>Quixote requires Python 2.3 or later.</p>
<p>If you have a previously installed quixote, we strongly recommend that
you remove it before installing a new one.
First, find out where your old Quixote installation is:</p>
<blockquote>
python -c &quot;import os, quixote; print os.path.dirname(quixote.__file__)&quot;</blockquote>
<p>and then remove away the reported directory. (If the import fails, then
you don't have an existing Quixote installation.)</p>
<p>Now install the new version by running (in the distribution directory),</p>
<blockquote>
python setup.py install</blockquote>
<p>and you're done.</p>
</div>
<div class="section" id="quick-start">
<h1><a name="quick-start">Quick start</a></h1>
<p>In a terminal window, run server/simple_server.py.
In a browser, open <a class="reference" href="http://localhost:8080">http://localhost:8080</a></p>
</div>
<div class="section" id="upgrading-a-quixote-1-application-to-quixote-2">
<h1><a name="upgrading-a-quixote-1-application-to-quixote-2">Upgrading a Quixote 1 application to Quixote 2.</a></h1>
<p>See upgrading.txt for details.</p>
</div>
</div>
</body>
</html>

View File

@ -1,255 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>PTL: Python Template Language</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="ptl-python-template-language">
<h1 class="title">PTL: Python Template Language</h1>
<div class="section" id="introduction">
<h1><a name="introduction">Introduction</a></h1>
<p>PTL is the templating language used by Quixote. Most web templating
languages embed a real programming language in HTML, but PTL inverts
this model by merely tweaking Python to make it easier to generate
HTML pages (or other forms of text). In other words, PTL is basically
Python with a novel way to specify function return values.</p>
<p>Specifically, a PTL template is designated by inserting a <tt class="literal"><span class="pre">[plain]</span></tt>
or <tt class="literal"><span class="pre">[html]</span></tt> modifier after the function name. The value of
expressions inside templates are kept, not discarded. If the type is
<tt class="literal"><span class="pre">[html]</span></tt> then non-literal strings are passed through a function that
escapes HTML special characters.</p>
</div>
<div class="section" id="plain-text-templates">
<h1><a name="plain-text-templates">Plain text templates</a></h1>
<p>Here's a sample plain text template:</p>
<pre class="literal-block">
def foo [plain] (x, y = 5):
&quot;This is a chunk of static text.&quot;
greeting = &quot;hello world&quot; # statement, no PTL output
print 'Input values:', x, y
z = x + y
&quot;&quot;&quot;You can plug in variables like x (%s)
in a variety of ways.&quot;&quot;&quot; % x
&quot;\n\n&quot;
&quot;Whitespace is important in generated text.\n&quot;
&quot;z = &quot;; z
&quot;, but y is &quot;
y
&quot;.&quot;
</pre>
<p>Obviously, templates can't have docstrings, but otherwise they follow
Python's syntactic rules: indentation indicates scoping, single-quoted
and triple-quoted strings can be used, the same rules for continuing
lines apply, and so forth. PTL also follows all the expected semantics
of normal Python code: so templates can have parameters, and the
parameters can have default values, be treated as keyword arguments,
etc.</p>
<p>The difference between a template and a regular Python function is that
inside a template the result of expressions are saved as the return
value of that template. Look at the first part of the example again:</p>
<pre class="literal-block">
def foo [plain] (x, y = 5):
&quot;This is a chunk of static text.&quot;
greeting = &quot;hello world&quot; # statement, no PTL output
print 'Input values:', x, y
z = x + y
&quot;&quot;&quot;You can plug in variables like x (%s)
in a variety of ways.&quot;&quot;&quot; % x
</pre>
<p>Calling this template with <tt class="literal"><span class="pre">foo(1,</span> <span class="pre">2)</span></tt> results in the following
string:</p>
<pre class="literal-block">
This is a chunk of static text.You can plug in variables like x (1)
in a variety of ways.
</pre>
<p>Normally when Python evaluates expressions inside functions, it just
discards their values, but in a <tt class="literal"><span class="pre">[plain]</span></tt> PTL template the value is
converted to a string using <tt class="literal"><span class="pre">str()</span></tt> and appended to the template's
return value. There's a single exception to this rule: <tt class="literal"><span class="pre">None</span></tt> is the
only value that's ever ignored, adding nothing to the output. (If this
weren't the case, calling methods or functions that return <tt class="literal"><span class="pre">None</span></tt>
would require assigning their value to a variable. You'd have to write
<tt class="literal"><span class="pre">dummy</span> <span class="pre">=</span> <span class="pre">list.sort()</span></tt> in PTL code, which would be strange and
confusing.)</p>
<p>The initial string in a template isn't treated as a docstring, but is
just incorporated in the generated output; therefore, templates can't
have docstrings. No whitespace is ever automatically added to the
output, resulting in <tt class="literal"><span class="pre">...text.You</span> <span class="pre">can</span> <span class="pre">...</span></tt> from the example. You'd
have to add an extra space to one of the string literals to correct
this.</p>
<p>The assignment to the <tt class="literal"><span class="pre">greeting</span></tt> local variable is a statement, not an
expression, so it doesn't return a value and produces no output. The
output from the <tt class="literal"><span class="pre">print</span></tt> statement will be printed as usual, but won't
go into the string generated by the template. Quixote directs standard
output into Quixote's debugging log; if you're using PTL on its own, you
should consider doing something similar. <tt class="literal"><span class="pre">print</span></tt> should never be used
to generate output returned to the browser, only for adding debugging
traces to a template.</p>
<p>Inside templates, you can use all of Python's control-flow statements:</p>
<pre class="literal-block">
def numbers [plain] (n):
for i in range(n):
i
&quot; &quot; # PTL does not add any whitespace
</pre>
<p>Calling <tt class="literal"><span class="pre">numbers(5)</span></tt> will return the string <tt class="literal"><span class="pre">&quot;1</span> <span class="pre">2</span> <span class="pre">3</span> <span class="pre">4</span> <span class="pre">5</span> <span class="pre">&quot;</span></tt>. You can
also have conditional logic or exception blocks:</p>
<pre class="literal-block">
def international_hello [plain] (language):
if language == &quot;english&quot;:
&quot;hello&quot;
elif language == &quot;french&quot;:
&quot;bonjour&quot;
else:
raise ValueError, &quot;I don't speak %s&quot; % language
</pre>
</div>
<div class="section" id="html-templates">
<h1><a name="html-templates">HTML templates</a></h1>
<p>Since PTL is usually used to generate HTML documents, an <tt class="literal"><span class="pre">[html]</span></tt>
template type has been provided to make generating HTML easier.</p>
<p>A common error when generating HTML is to grab data from the browser
or from a database and incorporate the contents without escaping
special characters such as '&lt;' and '&amp;'. This leads to a class of
security bugs called &quot;cross-site scripting&quot; bugs, where a hostile user
can insert arbitrary HTML in your site's output that can link to other
sites or contain JavaScript code that does something nasty (say,
popping up 10,000 browser windows).</p>
<p>Such bugs occur because it's easy to forget to HTML-escape a string,
and forgetting it in just one location is enough to open a hole. PTL
offers a solution to this problem by being able to escape strings
automatically when generating HTML output, at the cost of slightly
diminished performance (a few percent).</p>
<p>Here's how this feature works. PTL defines a class called
<tt class="literal"><span class="pre">htmltext</span></tt> that represents a string that's already been HTML-escaped
and can be safely sent to the client. The function <tt class="literal"><span class="pre">htmlescape(string)</span></tt>
is used to escape data, and it always returns an <tt class="literal"><span class="pre">htmltext</span></tt>
instance. It does nothing if the argument is already <tt class="literal"><span class="pre">htmltext</span></tt>.</p>
<p>If a template function is declared <tt class="literal"><span class="pre">[html]</span></tt> instead of <tt class="literal"><span class="pre">[text]</span></tt>
then two things happen. First, all literal strings in the function
become instances of <tt class="literal"><span class="pre">htmltext</span></tt> instead of Python's <tt class="literal"><span class="pre">str</span></tt>. Second,
the values of expressions are passed through <tt class="literal"><span class="pre">htmlescape()</span></tt> instead
of <tt class="literal"><span class="pre">str()</span></tt>.</p>
<p><tt class="literal"><span class="pre">htmltext</span></tt> type is like the <tt class="literal"><span class="pre">str</span></tt> type except that operations
combining strings and <tt class="literal"><span class="pre">htmltext</span></tt> instances will result in the string
being passed through <tt class="literal"><span class="pre">htmlescape()</span></tt>. For example:</p>
<pre class="literal-block">
&gt;&gt;&gt; from quixote.html import htmltext
&gt;&gt;&gt; htmltext('a') + 'b'
&lt;htmltext 'ab'&gt;
&gt;&gt;&gt; 'a' + htmltext('b')
&lt;htmltext 'ab'&gt;
&gt;&gt;&gt; htmltext('a%s') % 'b'
&lt;htmltext 'ab'&gt;
&gt;&gt;&gt; response = 'green eggs &amp; ham'
&gt;&gt;&gt; htmltext('The response was: %s') % response
&lt;htmltext 'The response was: green eggs &amp;amp; ham'&gt;
</pre>
<p>Note that calling <tt class="literal"><span class="pre">str()</span></tt> strips the <tt class="literal"><span class="pre">htmltext</span></tt> type and should be
avoided since it usually results in characters being escaped more than
once. While <tt class="literal"><span class="pre">htmltext</span></tt> behaves much like a regular string, it is
sometimes necessary to insert a <tt class="literal"><span class="pre">str()</span></tt> inside a template in order
to obtain a genuine string. For example, the <tt class="literal"><span class="pre">re</span></tt> module requires
genuine strings. We have found that explicit calls to <tt class="literal"><span class="pre">str()</span></tt> can
often be avoided by splitting some code out of the template into a
helper function written in regular Python.</p>
<p>It is also recommended that the <tt class="literal"><span class="pre">htmltext</span></tt> constructor be used as
sparingly as possible. The reason is that when using the htmltext
feature of PTL, explicit calls to <tt class="literal"><span class="pre">htmltext</span></tt> become the most likely
source of cross-site scripting holes. Calling <tt class="literal"><span class="pre">htmltext</span></tt> is like
saying &quot;I am absolutely sure this piece of data cannot contain malicious
HTML code injected by a user. Don't escape HTML special characters
because I want them.&quot;</p>
<p>Note that literal strings in template functions declared with
<tt class="literal"><span class="pre">[html]</span></tt> are htmltext instances, and therefore won't be escaped.
You'll only need to use <tt class="literal"><span class="pre">htmltext</span></tt> when HTML markup comes from
outside the template. For example, if you want to include a file
containing HTML:</p>
<pre class="literal-block">
def output_file [html] ():
'&lt;html&gt;&lt;body&gt;' # does not get escaped
htmltext(open(&quot;myfile.html&quot;).read())
'&lt;/body&gt;&lt;/html&gt;'
</pre>
<p>In the common case, templates won't be dealing with HTML markup from
external sources, so you can write straightforward code. Consider
this function to generate the contents of the <tt class="literal"><span class="pre">HEAD</span></tt> element:</p>
<pre class="literal-block">
def meta_tags [html] (title, description):
'&lt;title&gt;%s&lt;/title&gt;' % title
'&lt;meta name=&quot;description&quot; content=&quot;%s&quot;&gt;\n' % description
</pre>
<p>There are no calls to <tt class="literal"><span class="pre">htmlescape()</span></tt> at all, but string literals
such as <tt class="literal"><span class="pre">&lt;title&gt;%s&lt;/title&gt;</span></tt> have all be turned into <tt class="literal"><span class="pre">htmltext</span></tt>
instances, so the string variables will be automatically escaped:</p>
<pre class="literal-block">
&gt;&gt;&gt; t.meta_tags('Catalog', 'A catalog of our cool products')
&lt;htmltext '&lt;title&gt;Catalog&lt;/title&gt;
&lt;meta name=&quot;description&quot; content=&quot;A catalog of our cool products&quot;&gt;\n'&gt;
&gt;&gt;&gt; t.meta_tags('Dissertation on &lt;HEAD&gt;',
... 'Discusses the &quot;LINK&quot; and &quot;META&quot; tags')
&lt;htmltext '&lt;title&gt;Dissertation on &amp;lt;HEAD&amp;gt;&lt;/title&gt;
&lt;meta name=&quot;description&quot;
content=&quot;Discusses the &amp;quot;LINK&amp;quot; and &amp;quot;META&amp;quot; tags&quot;&gt;\n'&gt;
&gt;&gt;&gt;
</pre>
<p>Note how the title and description have had HTML-escaping applied to them.
(The output has been manually pretty-printed to be more readable.)</p>
<p>Once you start using <tt class="literal"><span class="pre">htmltext</span></tt> in one of your templates, mixing
plain and HTML templates is tricky because of <tt class="literal"><span class="pre">htmltext</span></tt>'s automatic
escaping; plain templates that generate HTML tags will be
double-escaped. One approach is to just use HTML templates throughout
your application. Alternatively you can use <tt class="literal"><span class="pre">str()</span></tt> to convert
<tt class="literal"><span class="pre">htmltext</span></tt> instances to regular Python strings; just be sure the
resulting string isn't HTML-escaped again.</p>
<p>Two implementations of <tt class="literal"><span class="pre">htmltext</span></tt> are provided, one written in pure
Python and a second one implemented as a C extension. Both versions
have seen production use.</p>
</div>
<div class="section" id="ptl-modules">
<h1><a name="ptl-modules">PTL modules</a></h1>
<p>PTL templates are kept in files with the extension .ptl. Like Python
files, they are byte-compiled on import, and the byte-code is written to
a compiled file with the extension <tt class="literal"><span class="pre">.pyc</span></tt>. Since vanilla Python
doesn't know anything about PTL, Quixote provides an import hook to let
you import PTL files just like regular Python modules. The standard way
to install this import hook is by calling the <tt class="literal"><span class="pre">enable_ptl()</span></tt> function:</p>
<pre class="literal-block">
from quixote import enable_ptl
enable_ptl()
</pre>
<p>(Note: if you're using ZODB, always import ZODB <em>before</em> installing the
PTL import hook. There's some interaction which causes importing the
TimeStamp module to fail when the PTL import hook is installed; we
haven't debugged the problem. A similar problem has been reported for
BioPython and win32com.client imports.)</p>
<p>Once the import hook is installed, PTL files can be imported as if they
were Python modules. If all the example templates shown here were put
into a file named <tt class="literal"><span class="pre">foo.ptl</span></tt>, you could then write Python code that did
this:</p>
<pre class="literal-block">
from foo import numbers
def f():
return numbers(10)
</pre>
<p>You may want to keep this little function in your <tt class="literal"><span class="pre">PYTHONSTARTUP</span></tt>
file:</p>
<pre class="literal-block">
def ptl():
try:
import ZODB
except ImportError:
pass
from quixote import enable_ptl
enable_ptl()
</pre>
<p>This is useful if you want to interactively play with a PTL module.</p>
</div>
</div>
</body>
</html>

View File

@ -1,206 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Running the Quixote Demos</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="running-the-quixote-demos">
<h1 class="title">Running the Quixote Demos</h1>
<p>Quixote comes with some demonstration applications in the demo directory.
After quixote is installed (see INSTALL.txt for instructions),
you can run the demos using the scripts located in the server directory.</p>
<p>Each server script is written for a specific method of connecting a
quixote publisher to a web server, and you will ultimately want to
choose the one that matches your needs. More information about the
different server scripts may be found in the scripts themselves and in
web-server.txt. To start, though, the easiest way to view the demos
is as follows: in a terminal window, run server/simple_server.py, and
in a browser, open <a class="reference" href="http://localhost:8080">http://localhost:8080</a>.</p>
<p>The simple_server.py script prints a usage message if you run it with
a '--help' command line argument. You can run different demos by
using the '--factory' option to identify a callable that creates the
publisher you want to use. In particular, you might try these demos:</p>
<blockquote>
simple_server.py --factory quixote.demo.mini_demo.create_publisher</blockquote>
<p>or</p>
<blockquote>
simple_server.py --factory quixote.demo.altdemo.create_publisher</blockquote>
<div class="section" id="understanding-the-mini-demo">
<h1><a name="understanding-the-mini-demo">Understanding the mini_demo</a></h1>
<dl>
<dt>Start the mini demo by running the command:</dt>
<dd>simple_server.py --factory quixote.demo.mini_demo.create_publisher</dd>
</dl>
<p>In a browser, load <a class="reference" href="http://localhost:8080">http://localhost:8080</a>. In your browser, you should
see &quot;Welcome ...&quot; page. In your terminal window, you will see a
&quot;localhost - - ...&quot; line for each request. These are access log
messages from the web server.</p>
<p>Look at the source code in demo/mini_demo.py. Near the bottom you
will find the create_publisher() function. The create_publisher()
function creates a Publisher instance whose root directory is an
instance of the RootDirectory class defined just above. When a
request arrives, the Publisher calls the _q_traverse() method on the
root directory. In this case, the RootDirectory is using the standard
_q_traverse() implementation, inherited from Directory.</p>
<p>Look, preferably in another window, at the source code for
_q_traverse() in directory.py. The path argument provided to
_q_traverse() is a list of string components of the path part of the
URL, obtained by splitting the request location at each '/' and
dropping the first element (which is always '') For example, if the
path part of the URL is '/', the path argument to _q_traverse() is
['']. If the path part of the URL is '/a', the path argument to
_q_traverse() is ['a']. If the path part of the URL is '/a/', the
path argument to _q_traverse() is ['a', ''].</p>
<p>Looking at the code of _q_traverse(), observe that it starts by
splitting off the first component of the path and calling
_q_translate() to see if there is a designated attribute name
corresponding to this component. For the '/' page, the component is
'', and _q_translate() returns the attribute name '_q_index'. The
_q_traverse() function goes on to lookup the _q_index method and
return the result of calling it.</p>
<p>Looking back at mini_demo.py, you can see that the RootDirectory class
includes a _q_index() method, and this method does return the HTML for
<a class="reference" href="http://localhost:8080/">http://localhost:8080/</a></p>
<p>As mentioned above, the _q_translate() identifies a &quot;designated&quot;
attribute name for a given component. The default implementation uses
self._q_exports to define this designation. In particular, if the
component is in self._q_exports, then it is returned as the attribute
name, except in the special case of '', which is translated to the
special attribute name '_q_index'.</p>
<p>When you click on the link on the top page, you get
<a class="reference" href="http://localhost:8080/hello">http://localhost:8080/hello</a>. In this case, the path argument to the
_q_traverse() call is ['hello'], and the return value is the result of
calling the hello() method.</p>
<p>Feeling bold? (Just kidding, this won't hurt at all.) Try opening
<a class="reference" href="http://localhost:8080/bogus">http://localhost:8080/bogus</a>. This is what happens when _q_traverse()
raises a TraversalError. A TraversalError is no big deal, but how
does quixote handle more exceptional exceptions? To see, you can
introduce one by editing mini_demo.py. Try inserting the line &quot;raise
'ouch'&quot; into the hello() method. Kill the demo server (Control-c) and
start a new one with the same command as before. Now load the
<a class="reference" href="http://localhost:8080/hello">http://localhost:8080/hello</a> page. You should see a plain text python
traceback followed by some information extracted from the HTTP
request. This information is always printed to the error log on an
exception. Here, it is also displayed in the browser because the
create_publisher() function made a publisher using the 'plain' value
for the display_exceptions keyword argument. If you omit that keyword
argument from the Publisher constructor, the browser will get an
&quot;Internal Server Error&quot; message instead of the full traceback. If you
provide the value 'html', the browser displays a prettier version of
the traceback.</p>
<p>One more thing to try here. Replace your 'raise &quot;ouch&quot;' line in the hello() method with 'print &quot;ouch&quot;'. If you restart the server and load the /hello page,
you will see that print statements go the the error log (in this case, your
terminal window). This can be useful.</p>
</div>
<div class="section" id="understanding-the-root-demo">
<h1><a name="understanding-the-root-demo">Understanding the root demo</a></h1>
<dl>
<dt>Start the root demo by running the command:</dt>
<dd>simple_server.py --factory quixote.demo.create_publisher</dd>
</dl>
<p>In a browser, open <a class="reference" href="http://localhost:8080">http://localhost:8080</a> as before.
Click around at will.</p>
<p>This is the default demo, but it is more complicated than the
mini_demo described above. The create_publisher() function in
quixote.demo.__init__.py creates a publisher whose root directory is
an instance of quixote.demo.root.RootDirectory. Note that the source
code is a file named &quot;root.ptl&quot;. The suffix of &quot;ptl&quot; indicates that
it is a PTL file, and the import must follow a call to
quixote.enable_ptl() or else the source file will not be found or
compiled. The quixote.demo.__init__.py file takes care of that.</p>
<p>Take a look at the source code in root.ptl. You will see code that
looks like regular python, except that some function definitions have
&quot;[html]&quot; between the function name and the parameter list. These
functions are ptl templates. For details about PTL, see the PTL.txt
file.</p>
<p>This RootDirectory class is similar to the one in mini_demo.py, in
that it has a _q_index() method and '' appears in the _q_exports list.
One new feature here is the presence of a tuple in the _q_exports
list. Most of the time, the elements of the _q_exports lists are just
strings that name attributes that should be available as URL
components. This pattern does not work, however, when the particular
URL component you want to use includes characters (like '.') that
can't appear in Python attribute names. To work around these cases,
the _q_exports list may contain tuples such as (&quot;favicon.ico&quot;,
&quot;favicon_ico&quot;) to designate &quot;favicon_ico&quot; as the attribute name
corresponding the the &quot;favicon.ico&quot; URL component.</p>
<p>Looking at the RootDirectoryMethods, including plain(), css() and
favon_ico(), you will see examples where, in addition to returning a
string containing the body of the HTTP response, the function also
makes side-effect modifications to the response object itself, to set
the content type and the expiration time for the response.
Most of the time, these direct modifications to the response are
not needed. When they are, though, the get_response() function
gives you direct access to the response instance.</p>
<p>The RootDirectory here also sets an 'extras' attribute to be an
instance of ExtraDirectory, imported from the quixote.demo.extras
module. Note that 'extras' also appears in the _q_exports list. This
is the ordinary way to extend your URL space through another '/'.
For example, the URL path '/extras/' will result in a call to
the ExtraDirectory instance's _q_index() method.</p>
</div>
<div class="section" id="the-q-lookup-method">
<h1><a name="the-q-lookup-method">The _q_lookup() method</a></h1>
<p>Now take a look at the ExtraDirectory class in extras.ptl. This class
exhibits some more advanced publishing features. If you look back at
the default _q_traverse() implementation (in directory.py), you will
see that the _q_traverse does not give up if _q_translate() returns
None, indicating that the path component has no designated
corresponding attribute name. In this case, _q_traverse() tries
calling self._q_lookup() to see if the object of interest can be found
in a different way. Note that _q_lookup() takes the component as an
argument and must return either (if there is more path to traverse) a
Directory instance, or else (if the component is the last in the path)
a callable or a string.</p>
<p>In this particular case, the ExtrasDirectory._q_lookup() call returns
an instance of IntegerUI (a subclass of Directory). The interest
here, unlike the ExtrasDirectory() instance itself, is created
on-the-fly during the traversal, especially for this particular
component. Try loading <a class="reference" href="http://localhost:8080/extras/12/">http://localhost:8080/extras/12/</a> to see how
this behaves.</p>
<p>Note that the correct URL to get to the IntegerUI(12)._q_index() call
ends with a '/'. This can sometimes be confusing to people who expect
<a class="reference" href="http://localhost:8080/extras/12">http://localhost:8080/extras/12</a> to yield the same page as
<a class="reference" href="http://localhost:8080/extras/12/">http://localhost:8080/extras/12/</a>. If given the path ['extras', '12'],
the default _q_traverse() ends up <em>calling</em> the instance of IntegerUI.
The Directory.__call__() (see directory.py) determines the result: if
no form values were submitted and adding a slash would produce a page,
the call returns the result of calling quixote.redirect(). The
redirect() call here causes the server to issue a permanent redirect
response to the path with the slash added. When this automatic
redirect is used, a message is printed to the error log. If the
conditions for a redirect are not met, the call falls back to raising
a TraversalError. [Note, if you don't like this redirect behavior,
override, replace, or delete Directory.__call__]</p>
<p>The _q_lookup() pattern is useful when you want to allow URL
components that you either don't know or don't want to list in
_q_exports ahead of time.</p>
</div>
<div class="section" id="the-q-resolve-method">
<h1><a name="the-q-resolve-method">The _q_resolve() method</a></h1>
<p>Note that the ExtraDirectory class inherits from Resolving (in
addition to Directory). The Resolving mixin modifies the
_q_traverse() so that, when a component has an attribute name
designated by _q_translate(), but the Directory instance does not
actually <em>have</em> that attribute, the _q_resolve() method is called to
&quot;resolve&quot; the trouble. Typically, the _q_resolve() imports or
constructs what <em>should</em> be the value of the designated attribute.
The modified _q_translate() sets the attribute value so that the
_q_resolve() won't be called again for the same attribute. The
_q_resolve() pattern is useful when you want to delay the work of
constructing the values for exported attributes.</p>
</div>
<div class="section" id="forms">
<h1><a name="forms">Forms</a></h1>
<p>You can't get very far writing web applications without writing forms.
The root demo includes, at <a class="reference" href="http://localhost:8080/extras/form">http://localhost:8080/extras/form</a>, a page
that demonstrates basic usage of the Form class and widgets defined in
the quixote.form package.</p>
</div>
</div>
</body>
</html>

View File

@ -1,377 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Converting form1 forms to use the form2 library</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="converting-form1-forms-to-use-the-form2-library">
<h1 class="title">Converting form1 forms to use the form2 library</h1>
<div class="section" id="note">
<h1><a name="note">Note:</a></h1>
<p>The packages names have changed in Quixote 2.</p>
<p>Quixote form1 forms are now in the package quixote.form1.
(In Quixote 1, they were in quixote.form.)</p>
<p>Quixote form2 forms are now in the package quixote.form.
(In Quixote 1, they were in quixote.form2.)</p>
</div>
<div class="section" id="introduction">
<h1><a name="introduction">Introduction</a></h1>
<p>These are some notes and examples for converting Quixote form1 forms,
that is forms derived from <tt class="literal"><span class="pre">quixote.form1.Form</span></tt>, to the newer form2
forms.</p>
<p>Form2 forms are more flexible than their form1 counterparts in that they
do not require you to use the <tt class="literal"><span class="pre">Form</span></tt> class as a base to get form
functionality as form1 forms did. Form2 forms can be instantiated
directly and then manipulated as instances. You may also continue to
use inheritance for your form2 classes to get form functionality,
particularly if the structured separation of <tt class="literal"><span class="pre">process</span></tt>, <tt class="literal"><span class="pre">render</span></tt>,
and <tt class="literal"><span class="pre">action</span></tt> is desirable.</p>
<p>There are many ways to get from form1 code ported to form2. At one
end of the spectrum is to rewrite the form class using a functional
programing style. This method is arguably best since the functional
style makes the flow of control clearer.</p>
<p>The other end of the spectrum and normally the easiest way to port
form1 forms to form2 is to use the <tt class="literal"><span class="pre">compatibility</span></tt> module provided
in the form2 package. The compatibility module's Form class provides
much of the same highly structured machinery (via a <tt class="literal"><span class="pre">handle</span></tt> master
method) that the form1 framework uses.</p>
</div>
<div class="section" id="converting-form1-forms-using-using-the-compatibility-module">
<h1><a name="converting-form1-forms-using-using-the-compatibility-module">Converting form1 forms using using the compatibility module</a></h1>
<p>Here's the short list of things to do to convert form1 forms to
form2 using compatibility.</p>
<blockquote>
<ol class="arabic">
<li><p class="first">Import the Form base class from <tt class="literal"><span class="pre">quixote.form.compatibility</span></tt>
rather than from quixote.form1.</p>
</li>
<li><p class="first">Getting and setting errors is slightly different. In your form's
process method, where errors are typically set, form2
has a new interface for marking a widget as having an error.</p>
<blockquote>
<p>Form1 API:</p>
<pre class="literal-block">
self.error['widget_name'] = 'the error message'
</pre>
<p>Form2 API:</p>
<pre class="literal-block">
self.set_error('widget_name', 'the error message')
</pre>
</blockquote>
<p>If you want to find out if the form already has errors, change
the form1 style of direct references to the <tt class="literal"><span class="pre">self.errors</span></tt>
dictionary to a call to the <tt class="literal"><span class="pre">has_errors</span></tt> method.</p>
<blockquote>
<p>Form1 API:</p>
<pre class="literal-block">
if not self.error:
do some more error checking...
</pre>
<p>Form2 API:</p>
<pre class="literal-block">
if not self.has_errors():
do some more error checking...
</pre>
</blockquote>
</li>
<li><p class="first">Form2 select widgets no longer take <tt class="literal"><span class="pre">allowed_values</span></tt> or
<tt class="literal"><span class="pre">descriptions</span></tt> arguments. If you are adding type of form2 select
widget, you must provide the <tt class="literal"><span class="pre">options</span></tt> argument instead. Options
are the way you define the list of things that are selectable and
what is returned when they are selected. the options list can be
specified in in one of three ways:</p>
<pre class="literal-block">
options: [objects:any]
or
options: [(object:any, description:any)]
or
options: [(object:any, description:any, key:any)]
</pre>
<p>An easy way to construct options if you already have
allowed_values and descriptions is to use the built-in function
<tt class="literal"><span class="pre">zip</span></tt> to define options:</p>
<pre class="literal-block">
options=zip(allowed_values, descriptions)
</pre>
</li>
</ol>
<blockquote>
Note, however, that often it is simpler to to construct the
<tt class="literal"><span class="pre">options</span></tt> list directly.</blockquote>
<ol class="arabic simple" start="4">
<li>You almost certainly want to include some kind of cascading style
sheet (since form2 forms render with minimal markup). There is a
basic set of CSS rules in <tt class="literal"><span class="pre">quixote.form.css</span></tt>.</li>
</ol>
</blockquote>
<p>Here's the longer list of things you may need to tweak in order for
form2 compatibility forms to work with your form1 code.</p>
<blockquote>
<ul>
<li><p class="first"><tt class="literal"><span class="pre">widget_type</span></tt> widget class attribute is gone. This means when
adding widgets other than widgets defined in <tt class="literal"><span class="pre">quixote.form.widget</span></tt>,
you must import the widget class into your module and pass the
widget class as the first argument to the <tt class="literal"><span class="pre">add_widget</span></tt> method
rather than using the <tt class="literal"><span class="pre">widget_type</span></tt> string.</p>
</li>
<li><p class="first">The <tt class="literal"><span class="pre">action_url</span></tt> argument to the form's render method is now
a keyword argument.</p>
</li>
<li><p class="first">If you use <tt class="literal"><span class="pre">OptionSelectWidget</span></tt>, there is no longer a
<tt class="literal"><span class="pre">get_current_option</span></tt> method. You can get the current value
in the normal way.</p>
</li>
<li><p class="first"><tt class="literal"><span class="pre">ListWidget</span></tt> has been renamed to <tt class="literal"><span class="pre">WidgetList</span></tt>.</p>
</li>
<li><p class="first">There is no longer a <tt class="literal"><span class="pre">CollapsibleListWidget</span></tt> class. If you need
this functionality, consider writing a 'deletable composite widget'
to wrap your <tt class="literal"><span class="pre">WidgetList</span></tt> widgets in it:</p>
<pre class="literal-block">
class DeletableWidget(CompositeWidget):
def __init__(self, name, value=None,
element_type=StringWidget,
element_kwargs={}, **kwargs):
CompositeWidget.__init__(self, name, value=value, **kwargs)
self.add(HiddenWidget, 'deleted', value='0')
if self.get('deleted') != '1':
self.add(element_type, 'element', value=value,
**element_kwargs)
self.add(SubmitWidget, 'delete', value='Delete')
if self.get('delete'):
self.get_widget('deleted').set_value('1')
def _parse(self, request):
if self.get('deleted') == '1':
self.value = None
else:
self.value = self.get('element')
def render(self):
if self.get('deleted') == '1':
return self.get_widget('deleted').render()
else:
return CompositeWidget.render(self)
</pre>
</li>
</ul>
</blockquote>
<p>Congratulations, now that you've gotten your form1 forms working in form2,
you may wish to simplify this code using some of the new features available
in form2 forms. Here's a list of things you may wish to consider:</p>
<blockquote>
<ul>
<li><p class="first">In your process method, you don't really need to get a <tt class="literal"><span class="pre">form_data</span></tt>
dictionary by calling <tt class="literal"><span class="pre">Form.process</span></tt> to ensure your widgets are
parsed. Instead, the parsed value of any widget is easy to obtain
using the widget's <tt class="literal"><span class="pre">get_value</span></tt> method or the form's
<tt class="literal"><span class="pre">__getitem__</span></tt> method. So, instead of:</p>
<pre class="literal-block">
form_data = Form.process(self, request)
val = form_data['my_widget']
</pre>
<p>You can use:</p>
<pre class="literal-block">
val = self['my_widget']
</pre>
<p>If the widget may or may not be in the form, you can use <tt class="literal"><span class="pre">get</span></tt>:</p>
<pre class="literal-block">
val = self.get('my_widget')
</pre>
</li>
<li><p class="first">It's normally not necessary to provide the <tt class="literal"><span class="pre">action_url</span></tt> argument
to the form's <tt class="literal"><span class="pre">render</span></tt> method.</p>
</li>
<li><p class="first">You don't need to save references to your widgets in your form
class. You may have a particular reason for wanting to do that,
but any widget added to the form using <tt class="literal"><span class="pre">add</span></tt> (or <tt class="literal"><span class="pre">add_widget</span></tt> in
the compatibility module) can be retrieved using the form's
<tt class="literal"><span class="pre">get_widget</span></tt> method.</p>
</li>
</ul>
</blockquote>
</div>
<div class="section" id="converting-form1-forms-to-form2-by-functional-rewrite">
<h1><a name="converting-form1-forms-to-form2-by-functional-rewrite">Converting form1 forms to form2 by functional rewrite</a></h1>
<p>The best way to get started on a functional version of a form2 rewrite
is to look at a trivial example form first written using the form1
inheritance model followed by it's form2 functional equivalent.</p>
<p>First the form1 form:</p>
<pre class="literal-block">
class MyForm1Form(Form):
def __init__(self, request, obj):
Form.__init__(self)
if obj is None:
self.obj = Obj()
self.add_submit_button('add', 'Add')
else:
self.obj = obj
self.add_submit_button('update', 'Update')
self.add_cancel_button('Cancel', request.get_path(1) + '/')
self.add_widget('single_select', 'obj_type',
title='Object Type',
value=self.obj.get_type(),
allowed_values=list(obj.VALID_TYPES),
descriptions=['type1', 'type2', 'type3'])
self.add_widget('float', 'cost',
title='Cost',
value=obj.get_cost())
def render [html] (self, request, action_url):
title = 'Obj %s: Edit Object' % self.obj
header(title)
Form.render(self, request, action_url)
footer(title)
def process(self, request):
form_data = Form.process(self, request)
if not self.error:
if form_data['cost'] is None:
self.error['cost'] = 'A cost is required.'
elif form_data['cost'] &lt; 0:
self.error['cost'] = 'The amount must be positive'
return form_data
def action(self, request, submit, form_data):
self.obj.set_type(form_data['obj_type'])
self.obj.set_cost(form_data['cost'])
if submit == 'add':
db = get_database()
db.add(self.obj)
else:
assert submit == 'update'
return request.redirect(request.get_path(1) + '/')
</pre>
<p>Here's the same form using form2 where the function operates on a Form
instance it keeps a reference to it as a local variable:</p>
<pre class="literal-block">
def obj_form(request, obj):
form = Form() # quixote.form.Form
if obj is None:
obj = Obj()
form.add_submit('add', 'Add')
else:
form.add_submit('update', 'Update')
form.add_submit('cancel', 'Cancel')
form.add_single_select('obj_type',
title='Object Type',
value=obj.get_type(),
options=zip(obj.VALID_TYPES,
['type1', 'type2', 'type3']))
form.add_float('cost',
title='Cost',
value=obj.get_cost(),
required=1)
def render [html] ():
title = 'Obj %s: Edit Object' % obj
header(title)
form.render()
footer(title)
def process():
if form['cost'] &lt; 0:
self.set_error('cost', 'The amount must be positive')
def action(submit):
obj.set_type(form['obj_type'])
obj.set_cost(form['cost'])
if submit == 'add':
db = get_database()
db.add(self.obj)
else:
assert submit == 'update'
exit_path = request.get_path(1) + '/'
submit = form.get_submit()
if submit == 'cancel':
return request.redirect(exit_path)
if not form.is_submitted() or form.has_errors():
return render()
process()
if form.has_errors():
return render()
action(submit)
return request.redirect(exit_path)
</pre>
<p>As you can see in the example, the function still has all of the same
parts of it's form1 equivalent.</p>
<blockquote>
<ol class="arabic simple">
<li>It determines if it's to create a new object or edit an existing one</li>
<li>It adds submit buttons and widgets</li>
<li>It has a function that knows how to render the form</li>
<li>It has a function that knows how to do error processing on the form</li>
<li>It has a function that knows how to register permanent changes to
objects when the form is submitted successfully.</li>
</ol>
</blockquote>
<p>In the form2 example, we have used inner functions to separate out these
parts. This, of course, is optional, but it does help readability once
the form gets more complicated and has the additional advantage of
mapping directly with it's form1 counterparts.</p>
<p>Form2 functional forms do not have the <tt class="literal"><span class="pre">handle</span></tt> master-method that
is called after the form is initialized. Instead, we deal with this
functionality manually. Here are some things that the <tt class="literal"><span class="pre">handle</span></tt>
portion of your form might need to implement illustrated in the
order that often makes sense.</p>
<blockquote>
<ol class="arabic simple">
<li>Get the value of any submit buttons using <tt class="literal"><span class="pre">form.get_submit</span></tt></li>
<li>If the form has not been submitted yet, return <tt class="literal"><span class="pre">render()</span></tt>.</li>
<li>See if the cancel button was pressed, if so return a redirect.</li>
<li>Call your <tt class="literal"><span class="pre">process</span></tt> inner function to do any widget-level error
checks. The form may already have set some errors, so you
may wish to check for that before trying additional error checks.</li>
<li>See if the form was submitted by an unknown submit button.
This will be the case if the form was submitted via a JavaScript
action, which is the case when an option select widget is selected.
The value of <tt class="literal"><span class="pre">get_submit</span></tt> is <tt class="literal"><span class="pre">True</span></tt> in this case and if it is,
you want to clear any errors and re-render the form.</li>
<li>If the form has not been submitted or if the form has errors,
you simply want to render the form.</li>
<li>Check for your named submit buttons which you expect for
successful form posting e.g. <tt class="literal"><span class="pre">add</span></tt> or <tt class="literal"><span class="pre">update</span></tt>. If one of
these is pressed, call you action inner function.</li>
<li>Finally, return a redirect to the expected page following a
form submission.</li>
</ol>
</blockquote>
<p>These steps are illustrated by the following snippet of code and to a
large degree in the above functional form2 code example. Often this
<tt class="literal"><span class="pre">handle</span></tt> block of code can be simplified. For example, if you do not
expect form submissions from unregistered submit buttons, you can
eliminate the test for that. Similarly, if your form does not do any
widget-specific error checking, there's no reason to have an error
checking <tt class="literal"><span class="pre">process</span></tt> function or the call to it:</p>
<pre class="literal-block">
exit_path = request.get_path(1) + '/'
submit = form.get_submit()
if not submit:
return render()
if submit == 'cancel':
return request.redirect(exit_path)
if submit == True:
form.clear_errors()
return render()
process()
if form.has_errors():
return render()
action(submit)
return request.redirect(exit_path)
</pre>
</div>
</div>
</body>
</html>

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Multi-Threaded Quixote Applications</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="multi-threaded-quixote-applications">
<h1 class="title">Multi-Threaded Quixote Applications</h1>
<p>Starting with Quixote 0.6, it's possible to write multi-threaded Quixote
applications. In previous versions, Quixote stored the current
HTTPRequest object in a global variable, meaning that processing
multiple requests in the same process simultaneously was impossible.</p>
<p>However, the Publisher class as shipped still can't handle multiple
simultaneous requests; you'll need to subclass Publisher to make it
re-entrant. Here's a starting point:</p>
<pre class="literal-block">
import thread
from quixote.publish import Publisher
[...]
class ThreadedPublisher (Publisher):
def __init__ (self, root_namespace, config=None):
Publisher.__init__(self, root_namespace, config)
self._request_dict = {}
def _set_request(self, request):
self._request_dict[thread.get_ident()] = request
def _clear_request(self):
try:
del self._request_dict[thread.get_ident()]
except KeyError:
pass
def get_request(self):
return self._request_dict.get(thread.get_ident())
</pre>
<p>Using ThreadedPublisher, you now have one current request per thread,
rather than one for the entire process.</p>
</div>
</body>
</html>

View File

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Quixote Programming Overview</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="quixote-programming-overview">
<h1 class="title">Quixote Programming Overview</h1>
<p>This document explains how a Quixote application is structured.
The demo.txt file should probably be read before you read this file.
There are three components to a Quixote application:</p>
<ol class="arabic">
<li><p class="first">A driver script, usually a CGI or FastCGI script. This is the
interface between your web server (eg., Apache) and the bulk of your
application code. The driver script is responsible for creating a
Quixote publisher customized for your application and invoking its
publishing loop.</p>
</li>
<li><p class="first">A configuration file. This file specifies various features of the
Publisher class, such as how errors are handled, the paths of
various log files, and various other things. Read through
quixote/config.py for the full list of configuration settings.</p>
<p>The most important configuration parameters are:</p>
<blockquote>
<dl>
<dt><tt class="literal"><span class="pre">ERROR_EMAIL</span></tt></dt>
<dd><p class="first last">e-mail address to which errors will be mailed</p>
</dd>
<dt><tt class="literal"><span class="pre">ERROR_LOG</span></tt></dt>
<dd><p class="first last">file to which errors will be logged</p>
</dd>
</dl>
</blockquote>
<p>For development/debugging, you should also set <tt class="literal"><span class="pre">DISPLAY_EXCEPTIONS</span></tt>
true; the default value is false, to favor security over convenience.</p>
</li>
<li><p class="first">Finally, the bulk of the code will be called through a call (by the
Publisher) to the _q_traverse() method of an instance designated as
the <tt class="literal"><span class="pre">root_directory</span></tt>. Normally, the root_directory will be an
instance of the Directory class.</p>
</li>
</ol>
<div class="section" id="driver-script">
<h1><a name="driver-script">Driver script</a></h1>
<p>The driver script is the interface between your web server and Quixote's
&quot;publishing loop&quot;, which in turn is the gateway to your application
code. Thus, there are two things that your Quixote driver script must
do:</p>
<ul class="simple">
<li>create a Quixote publisher -- that is, an instance of the Publisher
class provided by the quixote.publish module -- and customize it for
your application</li>
<li>invoke the publisher's process_request() method as needed to get
responses for one or more requests, writing the responses back
to the client(s).</li>
</ul>
<p>The publisher is responsible for translating URLs to Python objects and
calling the appropriate function, method, or PTL template to retrieve
the information and/or carry out the action requested by the URL.</p>
<p>The most important application-specific customization done by the driver
script is to set the root directory of your application.</p>
<p>The quixote.servers package includes driver modules for cgi, fastcgi,
scgi, medusa, twisted, and the simple_server. Each of these modules
includes a <tt class="literal"><span class="pre">run()</span></tt> function that you can use in a driver script that
provides a function to create the publisher that you want. For an example
of this pattern, see the __main__ part of demo/mini_demo.py. You could
run the mini_demo.py with scgi by using the <tt class="literal"><span class="pre">run()</span></tt> function imported
from quixote.server.scgi_server instead of the one from
quixote.server.simple_server. (You would also need your http server
set up to use the scgi server.)</p>
<p>That's almost the simplest possible case -- there's no
application-specific configuration info apart from the root directory.</p>
<p>Getting the driver script to actually run is between you and your web
server. See the web-server.txt document for help.</p>
</div>
<div class="section" id="configuration-file">
<h1><a name="configuration-file">Configuration file</a></h1>
<p>By default, the Publisher uses the configuration information from
quixote/config.py. You should never edit the default values in
quixote/config.py, because your edits will be lost if you upgrade to a
newer Quixote version. You should certainly read it, though, to
understand what all the configuration variables are. If you want to
customize any of the configuration variables, your driver script
should provide your customized Config instance as an argument to the
Publisher constructor.</p>
</div>
<div class="section" id="logging">
<h1><a name="logging">Logging</a></h1>
<p>The publisher also accepts an optional <tt class="literal"><span class="pre">logger</span></tt> keyword argument,
that should, if provided, support the same methods as the
default value, an instance of <tt class="literal"><span class="pre">DefaultLogger</span></tt>. Even if you
use the default logger, you can still customize the behavior
by setting configuration values for <tt class="literal"><span class="pre">access_log</span></tt>, <tt class="literal"><span class="pre">error_log</span></tt>, and/or
<tt class="literal"><span class="pre">error_email</span></tt>. These configuration variables are described
more fully in config.py.</p>
<p>Quixote writes one (rather long) line to the access log for each request
it handles; we have split that line up here to make it easier to read:</p>
<pre class="literal-block">
127.0.0.1 - 2001-10-15 09:48:43
2504 &quot;GET /catalog/ HTTP/1.1&quot;
200 'Opera/6.0 (Linux; U)' 0.10sec
</pre>
<p>This line consists of:</p>
<ul class="simple">
<li>client IP address</li>
<li>current user (according to Quixote session management mechanism,
so this will be &quot;-&quot; unless you're using a session manager that
does authentication)</li>
<li>date and time of request in local timezone, as YYYY-MM-DD hh:mm:ss</li>
<li>process ID of the process serving the request (eg. your CGI/FastCGI
driver script)</li>
<li>the HTTP request line (request method, URI, and protocol)</li>
<li>response status code</li>
<li>HTTP user agent string (specifically, this is
<tt class="literal"><span class="pre">repr(os.environ.get('HTTP_USER_AGENT',</span> <span class="pre">''))</span></tt>)</li>
<li>time to complete the request</li>
</ul>
<p>If no access log is configured (ie., <tt class="literal"><span class="pre">ACCESS_LOG</span></tt> is <tt class="literal"><span class="pre">None</span></tt>), then
Quixote will not do any access logging.</p>
<p>The error log is used for three purposes:</p>
<ul class="simple">
<li>application output to <tt class="literal"><span class="pre">sys.stdout</span></tt> and <tt class="literal"><span class="pre">sys.stderr</span></tt> goes to
Quixote's error log</li>
<li>application tracebacks will be written to Quixote's error log</li>
</ul>
<p>If no error log is configured (with <tt class="literal"><span class="pre">ERROR_LOG</span></tt>), then all output is
redirected to the stderr supplied to Quixote for this request by your
web server. At least for CGI/FastCGI scripts under Apache, this winds
up in Apache's error log.</p>
<p>Having stdout redirected to the error log is useful for debugging. You
can just sprinkle <tt class="literal"><span class="pre">print</span></tt> statements into your application and the
output will wind up in the error log.</p>
</div>
<div class="section" id="application-code">
<h1><a name="application-code">Application code</a></h1>
<p>Finally, we reach the most complicated part of a Quixote application.
However, thanks to Quixote's design, everything you've ever learned
about designing and writing Python code is applicable, so there are no
new hoops to jump through. You may, optionally, wish to use PTL,
which is simply Python with a novel way of generating function return
values -- see PTL.txt for details.</p>
<p>Quixote's Publisher constructs a request, splits the path into a list
of components, and calls the root directory's _q_traverse() method,
giving the component list as an argument. The _q_traverse() will either
return a value that will become the content of the HTTPResponse, or
else it may raise an Exception. Exceptions are caught by the Publisher
and handled as needed, depending on configuration variables and
whether or not the Exception is an instance of PublisherError.</p>
</div>
</div>
</body>
</html>

View File

@ -1,307 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Quixote Session Management</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="quixote-session-management">
<h1 class="title">Quixote Session Management</h1>
<p>HTTP was originally designed as a stateless protocol, meaning that every
request for a document or image was conducted in a separate TCP
connection, and that there was no way for a web server to tell if two
separate requests actually come from the same user. It's no longer
necessarily true that every request is conducted in a separate TCP
connection, but HTTP is still fundamentally stateless. However, there
are many applications where it is desirable or even essential to
establish a &quot;session&quot; for each user, ie. where all requests performed by
that user are somehow tied together on the server.</p>
<p>HTTP cookies were invented to address this requirement, and they are
still the best solution for establishing sessions on top of HTTP. Thus,
the session management mechanism that comes with Quixote is
cookie-based. (The most common alternative is to embed the session
identifier in the URL. Since Quixote views the URL as a fundamental
part of the web user interface, a URL-based session management scheme is
considered un-Quixotic.)</p>
<p>For further reading: the standard for cookies that is approximately
implemented by most current browsers is RFC 2109; the latest version of
the standard is RFC 2965.</p>
<p>In a nutshell, session management with Quixote works like this:</p>
<ul>
<li><p class="first">when a user-agent first requests a page from a Quixote application
that implements session management, Quixote creates a Session object
and generates a session ID (a random 64-bit number). The Session
object is attached to the current HTTPRequest object, so that
application code involved in processing this request has access to
the Session object. The get_session() function provides uniform
access to the current Session object.</p>
</li>
<li><p class="first">if, at the end of processing that request, the application code has
stored any information in the Session object, Quixote saves the
session in its SessionManager object for use by future requests and
sends a session cookie, called <tt class="literal"><span class="pre">QX_session</span></tt> by default, to the user.
The session cookie contains the session ID encoded as a hexadecimal
string, and is included in the response headers, eg.</p>
<pre class="literal-block">
Set-Cookie: QX_session=&quot;928F82A9B8FA92FD&quot;
</pre>
<p>(You can instruct Quixote to specify the domain and path for
URLs to which this cookie should be sent.)</p>
</li>
<li><p class="first">the user agent stores this cookie for future requests</p>
</li>
<li><p class="first">the next time the user agent requests a resource that matches the
cookie's domain and path, it includes the <tt class="literal"><span class="pre">QX_session</span></tt> cookie
previously generated by Quixote in the request headers, eg.:</p>
<pre class="literal-block">
Cookie: QX_session=&quot;928F82A9B8FA92FD&quot;
</pre>
</li>
<li><p class="first">while processing the request, Quixote decodes the session ID and
looks up the corresponding Session object in its SessionManager. If
there is no such session, the session cookie is bogus or
out-of-date, so Quixote raises SessionError; ultimately the user
gets an error page. Otherwise, the Session object is made
available, through the get_session() function, as the application
code processes the request.</p>
</li>
</ul>
<p>There are two caveats to keep in mind before proceeding, one major and
one minor:</p>
<ul class="simple">
<li>Quixote's standard Session and SessionManager class do not
implement any sort of persistence, meaning that all sessions
disappear when the process handling web requests terminates.
Thus, session management is completely useless with a plain
CGI driver script unless you add some persistence to the mix;
see &quot;Session persistence&quot; below for information.</li>
<li>Quixote never expires sessions; if you want user sessions to
be cleaned up after a period of inactivity, you will have to
write code to do it yourself.</li>
</ul>
<div class="section" id="session-management-demo">
<h1><a name="session-management-demo">Session management demo</a></h1>
<p>There's a simple demo of Quixote's session management in demo/altdemo.py.
If the durus (<a class="reference" href="http://www.mems-exchange.org/software/durus/">http://www.mems-exchange.org/software/durus/</a>) package is
installed, the demo uses a durus database to store sessions, so sessions
will be preserved, even if your are running it with plain cgi.</p>
<p>This particular application uses sessions to keep track of just two
things: the user's identity and the number of requests made in this
session. The first is addressed by Quixote's standard Session class --
every Session object has a <tt class="literal"><span class="pre">user</span></tt> attribute, which you can use for
anything you like. In the session demo, we simply store a string, the
user's name, which is entered by the user.</p>
<p>Tracking the number of requests is a bit more interesting: from the
DemoSession class in altdemo.py:</p>
<pre class="literal-block">
def __init__ (self, id):
Session.__init__(self, id)
self.num_requests = 0
def start_request (self):
Session.start_request(self)
self.num_requests += 1
</pre>
<p>When the session is created, we initialize the request counter; and
when we start processing each request, we increment it. Using the
session information in the application code is simple. If you want the
value of the user attribute of the current session, just call
get_user(). If you want some other attribute or method Use
get_session() to get the current Session if you need access to other
attributes (such as <tt class="literal"><span class="pre">num_requests</span></tt> in the demo) or methods of the
current Session instance.</p>
<p>Note that the Session class initializes the user attribute to None,
so get_user() will return None if no user has been identified for
this session. Application code can use this to change behavior,
as in the following:</p>
<pre class="literal-block">
if not get_user():
content += htmltext('&lt;p&gt;%s&lt;/p&gt;' % href('login', 'login'))
else:
content += htmltext(
'&lt;p&gt;Hello, %s.&lt;/p&gt;') % get_user()
content += htmltext('&lt;p&gt;%s&lt;/p&gt;' % href('logout', 'logout'))
</pre>
<p>Note that we must quote the user's name, because they are free to enter
anything they please, including special HTML characters like <tt class="literal"><span class="pre">&amp;</span></tt> or
<tt class="literal"><span class="pre">&lt;</span></tt>.</p>
<p>Of course, <tt class="literal"><span class="pre">session.user</span></tt> will never be set if we don't set it
ourselves. The code that processes the login form is just this (from
<tt class="literal"><span class="pre">login()</span></tt> in <tt class="literal"><span class="pre">demo/altdemo.py</span></tt>)</p>
<pre class="literal-block">
if get_field(&quot;name&quot;):
session = get_session()
session.set_user(get_field(&quot;name&quot;)) # This is the important part.
</pre>
<p>This is obviously a very simple application -- we're not doing any
verification of the user's input. We have no user database, no
passwords, and no limitations on what constitutes a &quot;user name&quot;. A real
application would have all of these, as well as a way for users to add
themselves to the user database -- ie. register with your web site.</p>
</div>
<div class="section" id="configuring-the-session-cookie">
<h1><a name="configuring-the-session-cookie">Configuring the session cookie</a></h1>
<p>Quixote allows you to configure several aspects of the session cookie
that it exchanges with clients. First, you can set the name of the
cookie; this is important if you have multiple independent Quixote
applications running on the same server. For example, the config file
for the first application might have</p>
<pre class="literal-block">
SESSION_COOKIE_NAME = &quot;foo_session&quot;
</pre>
<p>and the second application might have</p>
<pre class="literal-block">
SESSION_COOKIE_NAME = &quot;bar_session&quot;
</pre>
<p>Next, you can use <tt class="literal"><span class="pre">SESSION_COOKIE_DOMAIN</span></tt> and <tt class="literal"><span class="pre">SESSION_COOKIE_PATH</span></tt>
to set the cookie attributes that control which requests the cookie is
included with. By default, these are both <tt class="literal"><span class="pre">None</span></tt>, which instructs
Quixote to send the cookie without <tt class="literal"><span class="pre">Domain</span></tt> or <tt class="literal"><span class="pre">Path</span></tt> qualifiers.
For example, if the client requests <tt class="literal"><span class="pre">/foo/bar/</span></tt> from
www.example.com, and Quixote decides that it must set the session
cookie in the response to that request, then the server would send</p>
<pre class="literal-block">
Set-Cookie: QX_session=&quot;928F82A9B8FA92FD&quot;
</pre>
<p>in the response headers. Since no domain or path were specified with
that cookie, the browser will only include the cookie with requests to
www.example.com for URIs that start with <tt class="literal"><span class="pre">/foo/bar/</span></tt>.</p>
<p>If you want to ensure that your session cookie is included with all
requests to www.example.com, you should set <tt class="literal"><span class="pre">SESSION_COOKIE_PATH</span></tt> in your
config file:</p>
<pre class="literal-block">
SESSION_COOKIE_PATH = &quot;/&quot;
</pre>
<p>which will cause Quixote to set the cookie like this:</p>
<pre class="literal-block">
Set-Cookie: QX_session=&quot;928F82A9B8FA92FD&quot;; Path=&quot;/&quot;
</pre>
<p>which will instruct the browser to include that cookie with <em>all</em>
requests to www.example.com.</p>
<p>However, think carefully about what you set <tt class="literal"><span class="pre">SESSION_COOKIE_PATH</span></tt> to
-- eg. if you set it to &quot;/&quot;, but all of your Quixote code is under &quot;/q/&quot;
in your server's URL-space, then your user's session cookies could be
unnecessarily exposed. On shared servers where you don't control all of
the code, this is especially dangerous; be sure to use (eg.)</p>
<pre class="literal-block">
SESSION_COOKIE_PATH = &quot;/q/&quot;
</pre>
<p>on such servers. The trailing slash is important; without it, your
session cookies will be sent to URIs like <tt class="literal"><span class="pre">/qux</span></tt> and <tt class="literal"><span class="pre">/qix</span></tt>, even if
you don't control those URIs.</p>
<p>If you want to share the cookie across servers in your domain,
eg. www1.example.com and www2.example.com, you'll also need to set
<tt class="literal"><span class="pre">SESSION_COOKIE_DOMAIN</span></tt>:</p>
<blockquote>
SESSION_COOKIE_DOMAIN = &quot;.example.com&quot;</blockquote>
<p>Finally, note that the <tt class="literal"><span class="pre">SESSION_COOKIE_*</span></tt> configuration variables
<em>only</em> affect Quixote's session cookie; if you set your own cookies
using the <tt class="literal"><span class="pre">HTTPResponse.set_cookie()</span></tt> method, then the cookie sent to
the client is completely determined by that <tt class="literal"><span class="pre">set_cookie()</span></tt> call.</p>
<p>See RFCs 2109 and 2965 for more information on the rules browsers are
supposed to follow for including cookies with HTTP requests.</p>
</div>
<div class="section" id="writing-the-session-class">
<h1><a name="writing-the-session-class">Writing the session class</a></h1>
<p>You will almost certainly have to write a custom session class for your
application by subclassing Quixote's standard Session class. Every
custom session class has two essential responsibilities:</p>
<ul class="simple">
<li>initialize the attributes that will be used by your application</li>
<li>override the <tt class="literal"><span class="pre">has_info()</span></tt> method, so the session manager knows when
it must save your session object</li>
</ul>
<p>The first one is fairly obvious and just good practice. The second is
essential, and not at all obvious. The has_info() method exists because
SessionManager does not automatically hang on to all session objects;
this is a defense against clients that ignore cookies, making your
session manager create lots of session objects that are just used once.
As long as those session objects are not saved, the burden imposed by
these clients is not too bad -- at least they aren't sucking up your
memory, or bogging down the database that you save session data to.
Thus, the session manager uses has_info() to know if it should hang on
to a session object or not: if a session has information that must be
saved, the session manager saves it and sends a session cookie to the
client.</p>
<p>For development/testing work, it's fine to say that your session objects
should always be saved:</p>
<pre class="literal-block">
def has_info (self):
return 1
</pre>
<p>The opposite extreme is to forget to override <tt class="literal"><span class="pre">has_info()</span></tt> altogether,
in which case session management most likely won't work: unless you
tickle the Session object such that the base <tt class="literal"><span class="pre">has_info()</span></tt> method
returns true, the session manager won't save the sessions that it
creates, and Quixote will never drop a session cookie on the client.</p>
<p>In a real application, you need to think carefully about what data to
store in your sessions, and how <tt class="literal"><span class="pre">has_info()</span></tt> should react to the
presence of that data. If you try and track something about every
single visitor to your site, sooner or later one of those a
broken/malicious client that ignores cookies and <tt class="literal"><span class="pre">robots.txt</span></tt> will
come along and crawl your entire site, wreaking havoc on your Quixote
application (or the database underlying it).</p>
</div>
<div class="section" id="session-persistence">
<h1><a name="session-persistence">Session persistence</a></h1>
<p>Keeping session data across requests is all very nice, but in the real
world you want that data to survive across process termination. With
CGI, this is essential, since each process serves exactly one request
and then terminates. With other execution mechanisms, though, it's
still important -- you don't want to lose all your session data just
because your long-lived server process was restarted, or your server
machine was rebooted.</p>
<p>However, every application is different, so Quixote doesn't provide any
built-in mechanism for session persistence. Instead, it provides a
number of hooks, most in the SessionManager class, that let you plug in
your preferred persistence mechanism.</p>
<p>The first and most important hook is in the SessionManager
constructor: you can provide an alternate mapping object that
SessionManager will use to store session objects in. By default,
SessionManager uses an ordinary dictionary; if you provide a mapping
object that implements persistence, then your session data will
automatically persist across processes.</p>
<p>The second hook (two hooks, really) apply if you use a transactional
persistence mechanism to provide your SessionManager's mapping. The
<tt class="literal"><span class="pre">altdemo.py</span></tt> script does this with Durus, if the durus package is
installed, but you could also use ZODB or a relational database for
this purpose. The hooks make sure that session (and other) changes
get committed or aborted at the appropriate times. SessionManager
provides two methods for you to override: <tt class="literal"><span class="pre">forget_changes()</span></tt> and
<tt class="literal"><span class="pre">commit_changes()</span></tt>. <tt class="literal"><span class="pre">forget_changes()</span></tt> is called by
SessionPublisher whenever a request crashes, ie. whenever your
application raises an exception other than PublishError.
<tt class="literal"><span class="pre">commit_changes()</span></tt> is called for requests that complete
successfully, or that raise a PublishError exception. You'll have to
use your own SessionManager subclass if you need to take advantage of
these hooks for transactional session persistence.</p>
<p>The third available hook is the Session's is_dirty() method. This is
used when your mapping class uses a more primitive storage mechanism,
as, for example, the standard 'shelve' module, which provides a
mapping object on top of a DBM or Berkeley DB file:</p>
<pre class="literal-block">
import shelve
sessions = shelve.open(&quot;/tmp/quixote-sessions&quot;)
session_manager = SessionManager(session_mapping=sessions)
</pre>
<p>If you use one of these relatively simple persistent mapping types,
you'll also need to override <tt class="literal"><span class="pre">is_dirty()</span></tt> in your Session class.
That's in addition to overriding <tt class="literal"><span class="pre">has_info()</span></tt>, which determines if a
session object is <em>ever</em> saved; <tt class="literal"><span class="pre">is_dirty()</span></tt> is only called on
sessions that have already been added to the session mapping, to see
if they need to be &quot;re-added&quot;. The default implementation always
returns false, because once an object has been added to a normal
dictionary, there's no need to add it again. However, with simple
persistent mapping types like shelve, you need to store the object
again each time it changes. Thus, <tt class="literal"><span class="pre">is_dirty()</span></tt> should return true
if the session object needs to be re-written. For a simple, naive,
but inefficient implementation, making is_dirty an alias for
<tt class="literal"><span class="pre">has_info()</span></tt> will work -- that just means that once the session has
been written once, it will be re-written on every request.</p>
</div>
</div>
</body>
</html>

View File

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Examples of serving static files</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="examples-of-serving-static-files">
<h1 class="title">Examples of serving static files</h1>
<p>The <tt class="literal"><span class="pre">quixote.util</span></tt> module includes classes for making files and
directories available as Quixote resources. Here are some examples.</p>
<div class="section" id="publishing-a-single-file">
<h1><a name="publishing-a-single-file">Publishing a Single File</a></h1>
<p>The <tt class="literal"><span class="pre">StaticFile</span></tt> class makes an individual filesystem file (possibly
a symbolic link) available. You can also specify the MIME type and
encoding of the file; if you don't specify this, the MIME type will be
guessed using the standard Python <tt class="literal"><span class="pre">mimetypes.guess_type()</span></tt> function.
The default action is to not follow symbolic links, but this behaviour
can be changed using the <tt class="literal"><span class="pre">follow_symlinks</span></tt> parameter.</p>
<p>The following example publishes a file with the URL <tt class="literal"><span class="pre">.../stylesheet_css</span></tt>:</p>
<pre class="literal-block">
# 'stylesheet_css' must be in the _q_exports list
_q_exports = [ ..., 'stylesheet_css', ...]
stylesheet_css = StaticFile(
&quot;/htdocs/legacy_app/stylesheet.css&quot;,
follow_symlinks=1, mime_type=&quot;text/css&quot;)
</pre>
<p>If you want the URL of the file to have a <tt class="literal"><span class="pre">.css</span></tt> extension, you use
the external to internal name mapping feature of <tt class="literal"><span class="pre">_q_exports</span></tt>. For
example:</p>
<pre class="literal-block">
_q_exports = [ ..., ('stylesheet.css', 'stylesheet_css'), ...]
</pre>
</div>
<div class="section" id="publishing-a-directory">
<h1><a name="publishing-a-directory">Publishing a Directory</a></h1>
<p>Publishing a directory is similar. The <tt class="literal"><span class="pre">StaticDirectory</span></tt> class
makes a complete filesystem directory available. Again, the default
behaviour is to not follow symlinks. You can also request that the
<tt class="literal"><span class="pre">StaticDirectory</span></tt> object cache information about the files in
memory so that it doesn't try to guess the MIME type on every hit.</p>
<p>This example publishes the <tt class="literal"><span class="pre">notes/</span></tt> directory:</p>
<pre class="literal-block">
_q_exports = [ ..., 'notes', ...]
notes = StaticDirectory(&quot;/htdocs/legacy_app/notes&quot;)
</pre>
</div>
</div>
</body>
</html>

View File

@ -1,293 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Upgrading code from older versions of Quixote</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="upgrading-code-from-older-versions-of-quixote">
<h1 class="title">Upgrading code from older versions of Quixote</h1>
<p>This document lists backward-incompatible changes in Quixote, and
explains how to update application code to work with the newer
version.</p>
<div class="section" id="changes-from-1-0-to-2-0">
<h1><a name="changes-from-1-0-to-2-0">Changes from 1.0 to 2.0</a></h1>
<p>Change any imports you have from quixote.form to be from quixote.form1.</p>
<p>Change any imports you have from quixote.form2 to be from quixote.form.</p>
<p>Replace calls to HTTPRequest.get_form_var() with calls to get_field().</p>
<p>Define a create_publisher() function to get the publisher you need
and figure out how you want to connect it to web server.
See files in demo and server for examples. Note that publish1.py
contains a publisher that works more like the Quixote1 Publisher,
and does not require the changes listed below.</p>
<p>Make every namespace be an instance of quixote.directory.Directory.
Update namespaces that are modules (or in the init.py of a package) by
defining a new class in the module that inherits from Directory and
moving your _q_exports and _q_* functions onto the class. Replace
&quot;request&quot; parameters with &quot;self&quot; parameters on the new methods. If
you have a _q_resolve method, include Resolving in the bases of your
new class.</p>
<p>Remove request from calls to _q_ functions. If request, session,
user, path, or redirect is used in these new methods, replace as
needed with calls to get_request(), get_session(), get_user(),
get_path(), and/or redirect(), imported from quixote.</p>
<p>In every namespace that formerly traversed into a module, import the
new Directory class from the module and create an instance of the
Directory in a variable whose name is the name of the module.</p>
<p>In every namespace with a _q_exports and a _q_index, either add &quot;&quot; to
_q_exports or make sure that _q_lookup handles &quot;&quot; by returning the result
of a call to _q_index.</p>
<p>If your code depends on the Publisher's namespace_stack attribute,
try using quixote.util.get_directory_path() instead. If you need the
namespace stack after the traversal, override Directory._q_traverse()
to call get_directory_path() when the end of the path is reached, and
record the result somewhere for later reference.</p>
<p>If your code depends on _q_exception_handler, override the _q_traverse
on your root namespace or on your own Directory class to catch exceptions
and handle them the way you want. If you just want a general customization
for exception responses, you can change or override
Publisher.format_publish_error().</p>
<p>If your code depended on _q_access, include the AccessControlled with
the bases of your Directory classes as needed.</p>
<p>Provide imports as needed to htmltext, TemplateIO, get_field,
get_request, get_session, get_user, get_path, redirect, ?. You may
find dulcinea/bin/unknown.py useful for identifying missing imports.</p>
<p>Quixote 1's secure_errors configuration variable is not present in Quixote 2.</p>
<p>Form.__init__ no longer has name or attrs keywords. If your existing
code calls Form.__init__ with 'attrs=foo', you'll need to change it to
'<a href="#id1" name="id2"><span class="problematic" id="id2">**</span></a>foo'. Form instances no longer have a name attribute. If your code
looks for form.name, you can find it with form.attrs.get('name').
The Form.__init__ keyword parameter (and attribute) 'action_url' is now
named 'action'.</p>
<div class="system-message" id="id1">
<p class="system-message-title">System Message: <a name="id1">WARNING/2</a> (<tt>upgrading.txt</tt>, line 65); <em><a href="#id2">backlink</a></em></p>
Inline strong start-string without end-string.</div>
<p>The SessionPublisher class is gone. Use the Publisher class instead.
Also, the 'session_mgr' keyword has been renamed to 'session_manager'.</p>
</div>
<div class="section" id="changes-from-0-6-1-to-1-0">
<h1><a name="changes-from-0-6-1-to-1-0">Changes from 0.6.1 to 1.0</a></h1>
<div class="section" id="sessions">
<h2><a name="sessions">Sessions</a></h2>
<p>A leading underscore was removed from the <tt class="literal"><span class="pre">Session</span></tt> attributes
<tt class="literal"><span class="pre">__remote_address</span></tt>, <tt class="literal"><span class="pre">__creation_time</span></tt>, and <tt class="literal"><span class="pre">__access_time</span></tt>. If
you have pickled <tt class="literal"><span class="pre">Session</span></tt> objects you will need to upgrade them
somehow. Our preferred method is to write a script that unpickles each
object, renames the attributes and then re-pickles it.</p>
</div>
</div>
<div class="section" id="changes-from-0-6-to-0-6-1">
<h1><a name="changes-from-0-6-to-0-6-1">Changes from 0.6 to 0.6.1</a></h1>
<div class="section" id="q-exception-handler-now-called-if-exception-while-traversing">
<h2><a name="q-exception-handler-now-called-if-exception-while-traversing"><tt class="literal"><span class="pre">_q_exception_handler</span></tt> now called if exception while traversing</a></h2>
<p><tt class="literal"><span class="pre">_q_exception_handler</span></tt> hooks will now be called if an exception is
raised during the traversal process. Quixote 0.6 had a bug that caused
<tt class="literal"><span class="pre">_q_exception_handler</span></tt> hooks to only be called if an exception was
raised after the traversal completed.</p>
</div>
</div>
<div class="section" id="changes-from-0-5-to-0-6">
<h1><a name="changes-from-0-5-to-0-6">Changes from 0.5 to 0.6</a></h1>
<div class="section" id="q-getname-renamed-to-q-lookup">
<h2><a name="q-getname-renamed-to-q-lookup"><tt class="literal"><span class="pre">_q_getname</span></tt> renamed to <tt class="literal"><span class="pre">_q_lookup</span></tt></a></h2>
<p>The <tt class="literal"><span class="pre">_q_getname</span></tt> special function was renamed to <tt class="literal"><span class="pre">_q_lookup</span></tt>,
because that name gives a clearer impression of the function's
purpose. In 0.6, <tt class="literal"><span class="pre">_q_getname</span></tt> still works but will trigger a
warning.</p>
</div>
<div class="section" id="form-framework-changes">
<h2><a name="form-framework-changes">Form Framework Changes</a></h2>
<p>The <tt class="literal"><span class="pre">quixote.form.form</span></tt> module was changed from a .ptl file to a .py
file. You should delete or move the existing <tt class="literal"><span class="pre">quixote/</span></tt> directory
in <tt class="literal"><span class="pre">site-packages</span></tt> before running <tt class="literal"><span class="pre">setup.py</span></tt>, or at least delete
the old <tt class="literal"><span class="pre">form.ptl</span></tt> and <tt class="literal"><span class="pre">form.ptlc</span></tt> files.</p>
<p>The widget and form classes in the <tt class="literal"><span class="pre">quixote.form</span></tt> package now return
<tt class="literal"><span class="pre">htmltext</span></tt> instances. Applications that use forms and widgets will
likely have to be changed to use the <tt class="literal"><span class="pre">[html]</span></tt> template type to avoid
over-escaping of HTML special characters.</p>
<p>Also, the constructor arguments to <tt class="literal"><span class="pre">SelectWidget</span></tt> and its subclasses have
changed. This only affects applications that use the form framework
located in the <tt class="literal"><span class="pre">quixote.form</span></tt> package.</p>
<p>In Quixote 0.5, the <tt class="literal"><span class="pre">SelectWidget</span></tt> constructor had this signature:</p>
<pre class="literal-block">
def __init__ (self, name, value=None,
allowed_values=None,
descriptions=None,
size=None,
sort=0):
</pre>
<p><tt class="literal"><span class="pre">allowed_values</span></tt> was the list of objects that the user could choose,
and <tt class="literal"><span class="pre">descriptions</span></tt> was a list of strings that would actually be
shown to the user in the generated HTML.</p>
<p>In Quixote 0.6, the signature has changed slightly:</p>
<pre class="literal-block">
def __init__ (self, name, value=None,
allowed_values=None,
descriptions=None,
options=None,
size=None,
sort=0):
</pre>
<p>The <tt class="literal"><span class="pre">quote</span></tt> argument is gone, and the <tt class="literal"><span class="pre">options</span></tt> argument has been
added. If an <tt class="literal"><span class="pre">options</span></tt> argument is provided, <tt class="literal"><span class="pre">allowed_values</span></tt>
and <tt class="literal"><span class="pre">descriptions</span></tt> must not be supplied.</p>
<p>The <tt class="literal"><span class="pre">options</span></tt> argument, if present, must be a list of tuples with
1,2, or 3 elements, of the form <tt class="literal"><span class="pre">(value:any,</span> <span class="pre">description:any,</span>
<span class="pre">key:string)</span></tt>.</p>
<blockquote>
<ul class="simple">
<li><tt class="literal"><span class="pre">value</span></tt> is the object that will be returned if the user chooses
this item, and must always be supplied.</li>
<li><tt class="literal"><span class="pre">description</span></tt> is a string or htmltext instance which will be
shown to the user in the generated HTML. It will be passed
through the htmlescape() functions, so for an ordinary string
special characters such as '&amp;' will be converted to '&amp;amp;'.
htmltext instances will be left as they are.</li>
<li>If supplied, <tt class="literal"><span class="pre">key</span></tt> will be used in the value attribute
of the option element (<tt class="literal"><span class="pre">&lt;option</span> <span class="pre">value=&quot;...&quot;&gt;</span></tt>).
If not supplied, keys will be generated; <tt class="literal"><span class="pre">value</span></tt> is checked for a
<tt class="literal"><span class="pre">_p_oid</span></tt> attribute and if present, that string is used;
otherwise the description is used.</li>
</ul>
</blockquote>
<p>In the common case, most applications won't have to change anything,
though the ordering of selection items may change due to the
difference in how keys are generated.</p>
</div>
<div class="section" id="file-upload-changes">
<h2><a name="file-upload-changes">File Upload Changes</a></h2>
<p>Quixote 0.6 introduces new support for HTTP upload requests. Any HTTP
request with a Content-Type of &quot;multipart/form-data&quot; -- which is
generally only used for uploads -- is now represented by
HTTPUploadRequest, a subclass of HTTPRequest, and the uploaded files
themselves are represented by Upload objects.</p>
<p>Whenever an HTTP request has a Content-Type of &quot;multipart/form-data&quot;,
an instance of HTTPUploadRequest is created instead of HTTPRequest.
Some of the fields in the request are presumably uploaded files and
might be quite large, so HTTPUploadRequest will read all of the fields
supplied in the request body and write them out to temporary files;
the temporary files are written in the directory specified by the
UPLOAD_DIR configuration variable.</p>
<p>Once the temporary files have been written, the HTTPUploadRequest
object is passed to a function or PTL template, just like an ordinary
request. The difference between HTTPRequest and HTTPUploadRequest
is that all of the form variables are represented as Upload objects.
Upload objects have three attributes:</p>
<dl>
<dt><tt class="literal"><span class="pre">orig_filename</span></tt></dt>
<dd>the filename supplied by the browser.</dd>
<dt><tt class="literal"><span class="pre">base_filename</span></tt></dt>
<dd>a stripped-down version of orig_filename with unsafe characters removed.
This could be used when writing uploaded data to a permanent location.</dd>
<dt><tt class="literal"><span class="pre">tmp_filename</span></tt></dt>
<dd>the path of the temporary file containing the uploaded data for this field.</dd>
</dl>
<p>Consult upload.txt for more information about handling file uploads.</p>
</div>
<div class="section" id="refactored-publisher-class">
<h2><a name="refactored-publisher-class">Refactored <cite>Publisher</cite> Class</a></h2>
<p>Various methods in the <cite>Publisher</cite> class were rearranged. If your
application subclasses Publisher, you may need to change your code
accordingly.</p>
<blockquote>
<ul>
<li><p class="first"><tt class="literal"><span class="pre">parse_request()</span></tt> no longer creates the HTTPRequest object;
instead a new method, <tt class="literal"><span class="pre">create_request()</span></tt>, handles this,
and can be overridden as required.</p>
<p>As a result, the method signature has changed from
<tt class="literal"><span class="pre">parse_request(stdin,</span> <span class="pre">env)</span></tt> to <tt class="literal"><span class="pre">parse_request(request)</span></tt>.</p>
</li>
<li><p class="first">The <tt class="literal"><span class="pre">Publisher.publish()</span></tt> method now catches exceptions raised
by <tt class="literal"><span class="pre">parse_request()</span></tt>.</p>
</li>
</ul>
</blockquote>
</div>
</div>
<div class="section" id="changes-from-0-4-to-0-5">
<h1><a name="changes-from-0-4-to-0-5">Changes from 0.4 to 0.5</a></h1>
<div class="section" id="session-management-changes">
<h2><a name="session-management-changes">Session Management Changes</a></h2>
<p>The Quixote session management interface underwent lots of change and
cleanup with Quixote 0.5. It was previously undocumented (apart from
docstrings in the code), so we thought that this was a good opportunity
to clean up the interface. Nevertheless, those brave souls who got
session management working just by reading the code are in for a bit of
suffering; this brief note should help clarify things. The definitive
documentation for session management is session-mgmt.txt -- you should
start there.</p>
<div class="section" id="attribute-renamings-and-pickled-objects">
<h3><a name="attribute-renamings-and-pickled-objects">Attribute renamings and pickled objects</a></h3>
<p>Most attributes of the standard Session class were made private in order
to reduce collisions with subclasses. The downside is that pickled
Session objects will break. You might want to (temporarily) modify
session.py and add this method to Session:</p>
<pre class="literal-block">
def __setstate__ (self, dict):
# Update for attribute renamings made in rev. 1.51.2.3
# (between Quixote 0.4.7 and 0.5).
self.__dict__.update(dict)
if hasattr(self, 'remote_address'):
self.__remote_address = self.remote_address
del self.remote_address
if hasattr(self, 'creation_time'):
self.__creation_time = self.creation_time
del self.creation_time
if hasattr(self, 'access_time'):
self.__access_time = self.access_time
del self.access_time
if hasattr(self, 'form_tokens'):
self._form_tokens = self.form_tokens
del self.form_tokens
</pre>
<p>However, if your sessions were pickled via ZODB, this may not work. (It
didn't work for us.) In that case, you'll have to add something like
this to your class that inherits from both ZODB's Persistent and
Quixote's Session:</p>
<pre class="literal-block">
def __setstate__ (self, dict):
# Blechhh! This doesn't work if I put it in Quixote's
# session.py, so I have to second-guess how Python
# treats &quot;__&quot; attribute names.
self.__dict__.update(dict)
if hasattr(self, 'remote_address'):
self._Session__remote_address = self.remote_address
del self.remote_address
if hasattr(self, 'creation_time'):
self._Session__creation_time = self.creation_time
del self.creation_time
if hasattr(self, 'access_time'):
self._Session__access_time = self.access_time
del self.access_time
if hasattr(self, 'form_tokens'):
self._form_tokens = self.form_tokens
del self.form_tokens
</pre>
<p>It's not pretty, but it worked for us.</p>
</div>
<div class="section" id="cookie-domains-and-paths">
<h3><a name="cookie-domains-and-paths">Cookie domains and paths</a></h3>
<p>The session cookie config variables -- <tt class="literal"><span class="pre">COOKIE_NAME</span></tt>,
<tt class="literal"><span class="pre">COOKIE_DOMAIN</span></tt>, and <tt class="literal"><span class="pre">COOKIE_PATH</span></tt> -- have been renamed to
<tt class="literal"><span class="pre">SESSION_COOKIE_*</span></tt> for clarity.</p>
<p>If you previously set the config variable <tt class="literal"><span class="pre">COOKIE_DOMAIN</span></tt> to the name
of your server, this is most likely no longer necessary -- it's now fine
to leave <tt class="literal"><span class="pre">SESSION_COOKIE_DOMAIN</span></tt> unset (ie. <tt class="literal"><span class="pre">None</span></tt>), which
ultimately means browsers will only include the session cookie in
requests to the same server that sent it to them in the first place.</p>
<p>If you previously set <tt class="literal"><span class="pre">COOKIE_PATH</span></tt>, then you should probably preserve
your setting as <tt class="literal"><span class="pre">SESSION_COOKIE_PATH</span></tt>. The default of <tt class="literal"><span class="pre">None</span></tt> means
that browsers will only send session cookies with requests for URIs
under the URI that originally resulted in the session cookie being sent.
See session-mgmt.txt and RFCs 2109 and 2965.</p>
<p>If you previously set <tt class="literal"><span class="pre">COOKIE_NAME</span></tt>, change it to
<tt class="literal"><span class="pre">SESSION_COOKIE_NAME</span></tt>.</p>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,229 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Web Server Configuration for Quixote</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="web-server-configuration-for-quixote">
<h1 class="title">Web Server Configuration for Quixote</h1>
<p>For a simple Quixote installation, there are two things you have to get
right:</p>
<ul class="simple">
<li>installation of the Quixote modules to Python's library (the
trick here is that the <tt class="literal"><span class="pre">quixote</span></tt> package must be visible to the user
that CGI scripts run as, not necessarily to you as an interactive
command-line user)</li>
<li>configuration of your web server to run Quixote driver scripts</li>
</ul>
<p>This document is concerned with the second of these.</p>
<div class="section" id="which-web-servers">
<h1><a name="which-web-servers">Which web servers?</a></h1>
<p>We are only familiar with Apache, and we develop Quixote for use under
Apache. However, Quixote doesn't rely on any Apache-specific tricks;
if you can execute CGI scripts, then you can run Quixote applications
(although they'll run a lot faster with mod_scgi or FastCGI). If you
can redirect arbitrary URLs to a CGI script and preserve parts of the
URL as an add-on to the script name (with <tt class="literal"><span class="pre">PATH_INFO</span></tt>), then you can
run Quixote applications in the ideal manner, ie. with superfluous
implementation details hidden from the user.</p>
</div>
<div class="section" id="which-operating-systems">
<h1><a name="which-operating-systems">Which operating systems?</a></h1>
<p>We are mainly familiar with Unix, and develop and deploy Quixote under
Linux. However, we've had several reports of people using Quixote under
Windows, more-or-less successfully. There are still a few Unix-isms in
the code, but they are being rooted out in favor of portability.</p>
<p>Remember that your system is only as secure as its weakest link.
Quixote can't help you write secure web applications on an inherently
insecure operating system.</p>
</div>
<div class="section" id="basic-cgi-configuration">
<h1><a name="basic-cgi-configuration">Basic CGI configuration</a></h1>
<p>Throughout this document, I'm going to assume that:</p>
<ul class="simple">
<li>CGI scripts live in the <tt class="literal"><span class="pre">/www/cgi-bin</span></tt> directory of your web server,
and have the extension <tt class="literal"><span class="pre">.cgi</span></tt></li>
<li>HTTP requests for <tt class="literal"><span class="pre">/cgi-bin/foo.cgi</span></tt> will result in the execution
of <tt class="literal"><span class="pre">/www/cgi-bin/foo.cgi</span></tt> (for various values of <tt class="literal"><span class="pre">foo</span></tt>)</li>
<li>if the web server is instructed to serve an executable file
<tt class="literal"><span class="pre">bar.cgi</span></tt>, the file is treated as a CGI script</li>
</ul>
<p>With Apache, these configuration directives will do the trick:</p>
<pre class="literal-block">
AddHandler cgi-script .cgi
ScriptAlias /cgi-bin/ /www/cgi-bin/
</pre>
<p>Consult the Apache documentation for other ways of configuring CGI
script execution.</p>
<p>For other web servers, consult your server's documentation.</p>
</div>
<div class="section" id="installing-driver-scripts">
<h1><a name="installing-driver-scripts">Installing driver scripts</a></h1>
<p>Given the above configuration, installing a Quixote driver script is the
same as installing any other CGI script: copy it to <tt class="literal"><span class="pre">/www/cgi-bin</span></tt> (or
whatever). To install the Quixote demo's cgi driver script:</p>
<pre class="literal-block">
cp -p server/cgi_server.py /www/cgi-bin/demo.cgi
</pre>
<p>(The <tt class="literal"><span class="pre">-p</span></tt> option ensures that <tt class="literal"><span class="pre">cp</span></tt> preserves the file mode, so that
it remains executable.)</p>
</div>
<div class="section" id="url-rewriting">
<h1><a name="url-rewriting">URL rewriting</a></h1>
<p>With the above configuration, users need to use URLs like</p>
<pre class="literal-block">
http://www.example.com/cgi-bin/demo.cgi
</pre>
<p>to access the Quixote demo (or other Quixote applications installed in
the same way). This works, but it's ugly and unnecessarily exposes
implementation details.</p>
<p>In our view, it's preferable to give each Quixote application its own
chunk of URL-space -- a &quot;virtual directory&quot; if you like. For example,
you might want</p>
<pre class="literal-block">
http://www.example.com/qdemo
</pre>
<p>to handle the Quixote demo.</p>
<p>With Apache, this is quite easy, as long as mod_rewrite is compiled,
loaded, and enabled. (Building and loading Apache modules is beyond the
scope of this document; consult the Apache documentation.)</p>
<p>To enable the rewrite engine, use the</p>
<pre class="literal-block">
RewriteEngine on
</pre>
<p>directive. If you have virtual hosts, make sure to repeat this for each
<tt class="literal"><span class="pre">&lt;VirtualHost&gt;</span></tt> section of your config file.</p>
<p>The rewrite rule to use in this case is</p>
<pre class="literal-block">
RewriteRule ^/qdemo(/.*) /www/cgi-bin/demo.cgi$1 [last]
</pre>
<p>This is <em>not</em> a redirect; this is all handled with one HTTP
request/response cycle, and the user never sees <tt class="literal"><span class="pre">/cgi-bin/demo.cgi</span></tt> in
a URL.</p>
<p>Note that requests for <tt class="literal"><span class="pre">/qdemo/</span></tt> and <tt class="literal"><span class="pre">/qdemo</span></tt> are <em>not</em> the same; in
particular, with the above rewrite rule, the former will succeed and the
latter will not. (Look at the regex again if you don't believe me:
<tt class="literal"><span class="pre">/qdemo</span></tt> doesn't match the regex, so <tt class="literal"><span class="pre">demo.cgi</span></tt> is never invoked.)</p>
<p>The solution for <tt class="literal"><span class="pre">/qdemo</span></tt> is the same as if it corresponded to a
directory in your document tree: redirect it to <tt class="literal"><span class="pre">/qdemo/</span></tt>. Apache
(and, presumably, other web servers) does this automatically for &quot;real&quot;
directories; however, <tt class="literal"><span class="pre">/qdemo/</span></tt> is just a directory-like chunk of
URL-space, so either you or Quixote have to take care of the redirect.</p>
<p>It's almost certainly faster for you to take care of it in the web
server's configuration. With Apache, simply insert this directive
<em>before</em> the above rewrite rule:</p>
<pre class="literal-block">
RewriteRule ^/qdemo$ /qdemo/ [redirect=permanent]
</pre>
<p>If, for some reason, you are unwilling or unable to instruct your web
server to perform this redirection, Quixote will do it for you.
However, you have to make sure that the <tt class="literal"><span class="pre">/qdemo</span></tt> URL is handled by
Quixote. Change the rewrite rule to:</p>
<pre class="literal-block">
RewriteRule ^/qdemo(/.*)?$ /www/cgi-bin/demo.cgi$1 [last]
</pre>
<p>Now a request for <tt class="literal"><span class="pre">/qdemo</span></tt> will be handled by Quixote, and it will
generate a redirect to <tt class="literal"><span class="pre">/qdemo/</span></tt>. If you're using a CGI driver
script, this will be painfully slow, but it will work.</p>
<p>For redirecting and rewriting URLs with other web servers, consult your
server's documentation.</p>
</div>
<div class="section" id="long-running-processes">
<h1><a name="long-running-processes">Long-running processes</a></h1>
<p>For serious web applications, CGI is unacceptably slow. For a CGI-based
Quixote application, you have to start a Python interpreter, load the
Quixote modules, and load your application's modules before you can
start working. For sophisticated, database-backed applications, you'll
probably have to open a new database connection as well for every hit.</p>
<p>Small wonder so many high-performance alternatives to CGI exist. (The
main advantages of CGI are that it is widely supported and easy to
develop with. Even for large Quixote applications, running in CGI mode
is nice in development because you don't have to kill a long-running
driver script every time the code changes.) Quixote includes support
for mod_scgi and FastCGI.</p>
</div>
<div class="section" id="mod-scgi-configuration">
<h1><a name="mod-scgi-configuration">mod_scgi configuration</a></h1>
<p>SCGI is a CGI replacement written by Neil Schemenauer, one of
Quixote's developers, and is similar to FastCGI but is designed to be
easier to implement. mod_scgi simply forwards requests to an
already-running SCGI server on a different TCP port, and doesn't try
to start or stop processes, leaving that up to the SCGI server.</p>
<p>The SCGI code is available from <a class="reference" href="http://www.mems-exchange.org/software/scgi/">http://www.mems-exchange.org/software/scgi/</a> .</p>
<p>The quixote.server.scgi_server module is a script that
publishes the demo quixote application via SCGI. You can use
it for your application by importing it and calling the <tt class="literal"><span class="pre">run()</span></tt>
function with arguments to run your application, on the port
you choose. Here is an example:</p>
<pre class="literal-block">
#!/usr/bin/python
from quixote.server.scgi_server import run
from quixote.publish import Publisher
from mymodule import MyRootDirectory
def create_my_publisher():
return Publisher(MyRootDirectory())
run(create_my_publisher, port=3001)
</pre>
<p>The following Apache directive will direct requests to an SCGI server
running on port 3001:</p>
<pre class="literal-block">
&lt;Location /&gt;
SCGIServer 127.0.0.1 3001
SCGIHandler On
&lt;/Location&gt;
</pre>
<p>[Note: the mod_scgi module for Apache 2 requires a colon, instead of a
space, between the host and port on the SCGIServer line.]</p>
</div>
<div class="section" id="scgi-through-cgi">
<h1><a name="scgi-through-cgi">SCGI through CGI</a></h1>
<p>Recent releases of the scgi package include cgi2scgi.c, a small program
that offers an extremely convenient way to take advantage of SCGI using
Apache or any web server that supports CGI. To use it, compile the
cgi2scgi.c and install the compiled program as usual for your
webserver. The default SCGI port is 3000, but you can change that
by adding <tt class="literal"><span class="pre">-DPORT=3001</span></tt> (for example) to your compile command.</p>
<p>Although this method requires a new process to be launched for each
request, the process is small and fast, so the performance is
acceptable for many applications.</p>
</div>
<div class="section" id="fastcgi-configuration">
<h1><a name="fastcgi-configuration">FastCGI configuration</a></h1>
<p>If your web server supports FastCGI, you can significantly speed up your
Quixote applications with a simple change to your configuration. You
don't have to change your code at all (unless it makes assumptions about
how many requests are handled by each process). (See
<a class="reference" href="http://www.fastcgi.com/">http://www.fastcgi.com/</a> for more information on FastCGI.)</p>
<p>To use FastCGI with Apache, you'll need to download mod_fastcgi from
<a class="reference" href="http://www.fastcgi.com/">http://www.fastcgi.com/</a> and add it to your Apache installation.</p>
<p>Configuring a FastCGI driver script is best done after reading the fine
documentation for mod_fastcgi at
<a class="reference" href="http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html">http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html</a></p>
<p>However, if you just want to try it with the Quixote demo to see if it
works, add this directive to your Apache configuration:</p>
<pre class="literal-block">
AddHandler fastcgi-script .fcgi
</pre>
<p>and copy server/fastcgi_server.py to demo.fcgi. If you're using a URL
rewrite to map requests for (eg.) <tt class="literal"><span class="pre">/qdemo</span></tt> to
<tt class="literal"><span class="pre">/www/cgi-bin/demo.cgi</span></tt>, be sure to change the rewrite -- it should
now point to <tt class="literal"><span class="pre">/www/cgi-bin/demo.fcgi</span></tt>.</p>
<p>After the first access to <tt class="literal"><span class="pre">demo.fcgi</span></tt> (or <tt class="literal"><span class="pre">/qdemo/</span></tt> with the
modified rewrite rule), the demo should be noticeably faster. You
should also see a <tt class="literal"><span class="pre">demo.fcgi</span></tt> process running if you do <tt class="literal"><span class="pre">ps</span> <span class="pre">-le</span></tt>
(<tt class="literal"><span class="pre">ps</span> <span class="pre">-aux</span></tt> on BSD-ish systems, or maybe <tt class="literal"><span class="pre">ps</span> <span class="pre">aux</span></tt>). (On my 800 MHz
Athlon machine, there are slight but perceptible delays navigating the
Quixote demo in CGI mode. In FastCGI mode, the delay between pages is
no longer perceptible -- navigation is instantaneous.) The larger your
application is, the more code it loads, and the more work it does at
startup, the bigger a win FastCGI will be for you (in comparison to CGI).</p>
</div>
</div>
</body>
</html>

View File

@ -1,190 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Implementing Web Services with Quixote</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="implementing-web-services-with-quixote">
<h1 class="title">Implementing Web Services with Quixote</h1>
<p>This document will show you how to implement Web services using
Quixote.</p>
<div class="section" id="an-xml-rpc-service">
<h1><a name="an-xml-rpc-service">An XML-RPC Service</a></h1>
<p>XML-RPC is the simplest protocol commonly used to expose a Web
service. In XML-RPC, there are a few basic data types such as
integers, floats, strings, and dates, and a few aggregate types such
as arrays and structs. The xmlrpclib module, part of the Python 2.2
standard library and available separately from
<a class="reference" href="http://www.pythonware.com/products/xmlrpc/">http://www.pythonware.com/products/xmlrpc/</a>, converts between Python's
standard data types and the XML-RPC data types.</p>
<table class="table" frame="border" rules="all">
<colgroup>
<col width="40%" />
<col width="60%" />
</colgroup>
<tbody valign="top">
<tr><td>XML-RPC Type</td>
<td>Python Type or Class</td>
</tr>
<tr><td>&lt;int&gt;</td>
<td>int</td>
</tr>
<tr><td>&lt;double&gt;</td>
<td>float</td>
</tr>
<tr><td>&lt;string&gt;</td>
<td>string</td>
</tr>
<tr><td>&lt;array&gt;</td>
<td>list</td>
</tr>
<tr><td>&lt;struct&gt;</td>
<td>dict</td>
</tr>
<tr><td>&lt;boolean&gt;</td>
<td>xmlrpclib.Boolean</td>
</tr>
<tr><td>&lt;base64&gt;</td>
<td>xmlrpclib.Binary</td>
</tr>
<tr><td>&lt;dateTime&gt;</td>
<td>xmlrpclib.DateTime</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="making-xml-rpc-calls">
<h1><a name="making-xml-rpc-calls">Making XML-RPC Calls</a></h1>
<p>Making an XML-RPC call using xmlrpclib is easy. An XML-RPC server
lives at a particular URL, so the first step is to create an
xmlrpclib.ServerProxy object pointing at that URL.</p>
<pre class="literal-block">
&gt;&gt;&gt; import xmlrpclib
&gt;&gt;&gt; s = xmlrpclib.ServerProxy(
'http://www.stuffeddog.com/speller/speller-rpc.cgi')
</pre>
<p>Now you can simply make a call to the spell-checking service offered
by this server:</p>
<pre class="literal-block">
&gt;&gt;&gt; s.speller.spellCheck('my speling isnt gud', {})
[{'word': 'speling', 'suggestions': ['apeling', 'spelding',
'spelling', 'sperling', 'spewing', 'spiling'], 'location': 4},
{'word': 'isnt', 'suggestions': [``isn't'', 'ist'], 'location': 12}]
&gt;&gt;&gt;
</pre>
<p>This call results in the following XML being sent:</p>
<pre class="literal-block">
&lt;?xml version='1.0'?&gt;
&lt;methodCall&gt;
&lt;methodName&gt;speller.spellCheck&lt;/methodName&gt;
&lt;params&gt;
&lt;param&gt;
&lt;value&gt;&lt;string&gt;my speling isnt gud&lt;/string&gt;&lt;/value&gt;
&lt;/param&gt;
&lt;param&gt;
&lt;value&gt;&lt;struct&gt;&lt;/struct&gt;&lt;/value&gt;
&lt;/param&gt;
&lt;/params&gt;
&lt;/methodCall&gt;
</pre>
</div>
<div class="section" id="writing-a-quixote-service">
<h1><a name="writing-a-quixote-service">Writing a Quixote Service</a></h1>
<p>In the quixote.util module, Quixote provides a function,
<tt class="literal"><span class="pre">xmlrpc(request,</span> <span class="pre">func)</span></tt>, that processes the body of an XML-RPC
request. <tt class="literal"><span class="pre">request</span></tt> is the HTTPRequest object that Quixote passes to
every function it invokes. <tt class="literal"><span class="pre">func</span></tt> is a user-supplied function that
receives the name of the XML-RPC method being called and a tuple
containing the method's parameters. If there's a bug in the function
you supply and it raises an exception, the <tt class="literal"><span class="pre">xmlrpc()</span></tt> function will
catch the exception and return a <tt class="literal"><span class="pre">Fault</span></tt> to the remote caller.</p>
<p>Here's an example of implementing a simple XML-RPC handler with a
single method, <tt class="literal"><span class="pre">get_time()</span></tt>, that simply returns the current
time. The first task is to expose a URL for accessing the service.</p>
<pre class="literal-block">
from quixote.directory import Directory
from quixote.util import xmlrpc
from quixote import get_request
class RPCDirectory(Directory):
_q_exports = ['rpc']
def rpc (self):
return xmlrpc(get_request(), rpc_process)
def rpc_process (meth, params):
...
</pre>
<p>When the above code is placed in the __init__.py file for the Python
package corresponding to your Quixote application, it exposes the URL
<tt class="literal"><span class="pre">http://&lt;hostname&gt;/rpc</span></tt> as the access point for the XML-RPC service.</p>
<p>Next, we need to fill in the contents of the <tt class="literal"><span class="pre">rpc_process()</span></tt>
function:</p>
<pre class="literal-block">
import time
def rpc_process (meth, params):
if meth == 'get_time':
# params is ignored
now = time.gmtime(time.time())
return xmlrpclib.DateTime(now)
else:
raise RuntimeError, &quot;Unknown XML-RPC method: %r&quot; % meth
</pre>
<p><tt class="literal"><span class="pre">rpc_process()</span></tt> receives the method name and the parameters, and its
job is to run the right code for the method, returning a result that
will be marshalled into XML-RPC. The body of <tt class="literal"><span class="pre">rpc_process()</span></tt> will
therefore usually be an <tt class="literal"><span class="pre">if</span></tt> statement that checks the name of the
method, and calls another function to do the actual work. In this case,
<tt class="literal"><span class="pre">get_time()</span></tt> is very simple so the two lines of code it requires are
simply included in the body of <tt class="literal"><span class="pre">rpc_process()</span></tt>.</p>
<p>If the method name doesn't belong to a supported method, execution
will fall through to the <tt class="literal"><span class="pre">else</span></tt> clause, which will raise a
RuntimeError exception. Quixote's <tt class="literal"><span class="pre">xmlrpc()</span></tt> will catch this
exception and report it to the caller as an XML-RPC fault, with the
error code set to 1.</p>
<p>As you add additional XML-RPC services, the <tt class="literal"><span class="pre">if</span></tt> statement in
<tt class="literal"><span class="pre">rpc_process()</span></tt> will grow more branches. You might be tempted to pass
the method name to <tt class="literal"><span class="pre">getattr()</span></tt> to select a method from a module or
class. That would work, too, and avoids having a continually growing
set of branches, but you should be careful with this and be sure that
there are no private methods that a remote caller could access. I
generally prefer to have the <tt class="literal"><span class="pre">if...</span> <span class="pre">elif...</span> <span class="pre">elif...</span> <span class="pre">else</span></tt> blocks, for
three reasons: 1) adding another branch isn't much work, 2) it's
explicit about the supported method names, and 3) there won't be any
security holes in doing so.</p>
<p>An alternative approach is to have a dictionary mapping method names
to the corresponding functions and restrict the legal method names
to the keys of this dictionary:</p>
<pre class="literal-block">
def echo (*params):
# Just returns the parameters it's passed
return params
def get_time ():
now = time.gmtime(time.time())
return xmlrpclib.DateTime(now)
methods = {'echo' : echo,
'get_time' : get_time}
def rpc_process (meth, params):
func = methods.get[meth]
if methods.has_key(meth):
# params is ignored
now = time.gmtime(time.time())
return xmlrpclib.DateTime(now)
else:
raise RuntimeError, &quot;Unknown XML-RPC method: %r&quot; % meth
</pre>
<p>This approach works nicely when there are many methods and the
<tt class="literal"><span class="pre">if...elif...else</span></tt> statement would be unworkably long.</p>
</div>
</div>
</body>
</html>

View File

@ -1,502 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" />
<title>Quixote Widget Classes</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="quixote-widget-classes">
<h1 class="title">Quixote Widget Classes</h1>
<p>[This is reference documentation. If you haven't yet read &quot;Lesson 5:
widgets&quot; of demo.txt, you should go and do so now. This document also
assumes you have a good understanding of HTML forms and form elements.
If not, you could do worse than pick up a copy of <em>HTML: The Definitive
Guide</em> by Chuck Musciano &amp; Bill Kennedy (O'Reilly). I usually keep it
within arm's reach.]</p>
<p>Web forms are built out of form elements: string input, select lists,
checkboxes, submit buttons, and so forth. Quixote provides a family of
classes for handling these form elements, or widgets, in the
quixote.form.widget module. The class hierarchy is:</p>
<pre class="literal-block">
Widget [A]
|
+--StringWidget
| |
| +--PasswordWidget
| |
| +--NumberWidget [*] [A]
| |
| +-FloatWidget [*]
| +-IntWidget [*]
|
+--TextWidget
|
+--CheckboxWidget
|
+--SelectWidget [A]
| |
| +--SingleSelectWidget
| | |
| | +-RadiobuttonsWidget
| | |
| | +-OptionSelectWidget [*]
| |
| +--MultipleSelectWidget
|
+--SubmitButtonWidget
|
+--HiddenWidget
|
+--ListWidget [*]
[*] Widget classes that do not correspond exactly with a particular
HTML form element
[A] Abstract classes
</pre>
<div class="section" id="widget-the-base-class">
<h1><a name="widget-the-base-class">Widget: the base class</a></h1>
<p>Widget is the abstract base class for the widget hierarchy. It provides
the following facilities:</p>
<ul class="simple">
<li>widget name (<tt class="literal"><span class="pre">name</span></tt> attribute, <tt class="literal"><span class="pre">set_name()</span></tt> method)</li>
<li>widget value (<tt class="literal"><span class="pre">value</span></tt> attribute, <tt class="literal"><span class="pre">set_value()</span></tt> and <tt class="literal"><span class="pre">clear()</span></tt> methods)</li>
<li><tt class="literal"><span class="pre">__str__()</span></tt> and <tt class="literal"><span class="pre">__repr__()</span></tt> methods</li>
<li>some facilities for writing composite widget classes</li>
</ul>
<p>The Widget constructor signature is:</p>
<pre class="literal-block">
Widget(name : string, value : any = None)
</pre>
<dl>
<dt><tt class="literal"><span class="pre">name</span></tt></dt>
<dd>the name of the widget. For non-compound widgets (ie. everything in
the above class hierarchy), this will be used as the &quot;name&quot;
attribute for the main HTML tag that defines the form element.</dd>
<dt><tt class="literal"><span class="pre">value</span></tt></dt>
<dd>the current value of the form element. The type of 'value' depends
on the widget class. Most widget classes support only a single
type, eg. StringWidget always deals with strings and IntWidget with
integers. The SelectWidget classes are different; see the
descriptions below for details.</dd>
</dl>
</div>
<div class="section" id="common-widget-methods">
<h1><a name="common-widget-methods">Common widget methods</a></h1>
<p>The Widget base class also provides a couple of useful
methods:</p>
<dl>
<dt><tt class="literal"><span class="pre">set_name(name:string)</span></tt></dt>
<dd>use this to change the widget name supplied to the constructor.
Unless you know what you're doing, you should do this before
rendering or parsing the widget.</dd>
<dt><tt class="literal"><span class="pre">set_value(value:any)</span></tt></dt>
<dd>use this to set the widget value; this is the same as supplying
a value to the constructor (and the same type rules apply, ie.
the type of 'value' depends on the widget class).</dd>
<dt><tt class="literal"><span class="pre">clear()</span></tt></dt>
<dd>clear the widget's current value. Equivalent to
<tt class="literal"><span class="pre">widget.set_value(None)</span></tt>.</dd>
</dl>
<p>The following two methods will be used on every widget object you
create; if you write your own widget classes, you will almost certainly
have to define both of these:</p>
<dl>
<dt><tt class="literal"><span class="pre">render(request:HTTPRequest)</span></tt> <span class="classifier-delimiter">:</span> <span class="classifier"><tt class="literal"><span class="pre">string</span></tt></span></dt>
<dd>return a chunk of HTML that implements the form element
corresponding to this widget.</dd>
<dt><tt class="literal"><span class="pre">parse(request:HTTPRequest)</span></tt> <span class="classifier-delimiter">:</span> <span class="classifier"><tt class="literal"><span class="pre">any</span></tt></span></dt>
<dd>extract the form value for this widget from <tt class="literal"><span class="pre">request.form</span></tt>, parse it
according to the rules for this widget class, and return the
resulting value. The return value depends on the widget class, and
will be of the same type as the value passed to the constructor
and/or <tt class="literal"><span class="pre">set_value()</span></tt>.</dd>
</dl>
</div>
<div class="section" id="stringwidget">
<h1><a name="stringwidget">StringWidget</a></h1>
<p>Used for short, single-line string input with no validation (ie. any
string will be accepted.) Generates an <tt class="literal"><span class="pre">&lt;input</span> <span class="pre">type=&quot;text&quot;&gt;</span></tt> form
element.</p>
<div class="section" id="constructor">
<h2><a name="constructor">Constructor</a></h2>
<pre class="literal-block">
StringWidget(name : string,
value : string = None,
size : int = None,
maxlength : int = None)
</pre>
<dl>
<dt><tt class="literal"><span class="pre">size</span></tt></dt>
<dd>used as the <tt class="literal"><span class="pre">size</span></tt> attribute of the generated <tt class="literal"><span class="pre">&lt;input&gt;</span></tt> tag;
controls the physical size of the input field.</dd>
<dt><tt class="literal"><span class="pre">maxlength</span></tt></dt>
<dd>used as the <tt class="literal"><span class="pre">maxlength</span></tt> attribute; controls the maximum amount
of input.</dd>
</dl>
</div>
<div class="section" id="examples">
<h2><a name="examples">Examples</a></h2>
<pre class="literal-block">
&gt;&gt;&gt; StringWidget(&quot;foo&quot;, value=&quot;hello&quot;).render(request)
'&lt;input name=&quot;foo&quot; type=&quot;text&quot; value=&quot;hello&quot;&gt;'
&gt;&gt;&gt; StringWidget(&quot;foo&quot;, size=10, maxlength=20).render(request)
'&lt;input name=&quot;foo&quot; type=&quot;text&quot; size=&quot;10&quot; maxlength=&quot;20&quot;&gt;'
</pre>
</div>
</div>
<div class="section" id="passwordwidget">
<h1><a name="passwordwidget">PasswordWidget</a></h1>
<p>PasswordWidget is identical to StringWidget except for the type of the
HTML form element: <tt class="literal"><span class="pre">password</span></tt> instead of <tt class="literal"><span class="pre">text</span></tt>.</p>
</div>
<div class="section" id="textwidget">
<h1><a name="textwidget">TextWidget</a></h1>
<p>Used for multi-line text input. The value is a single string with
newlines right where the browser supplied them. (<tt class="literal"><span class="pre">\r\n</span></tt>, if present,
is converted to <tt class="literal"><span class="pre">\n</span></tt>.) Generates a <tt class="literal"><span class="pre">&lt;textarea&gt;</span></tt> form element.</p>
<div class="section" id="id1">
<h2><a name="id1">Constructor</a></h2>
<pre class="literal-block">
TextWidget(name : string,
value : string = None,
cols : int = None,
rows : int = None,
wrap : string = &quot;physical&quot;)
</pre>
<dl>
<dt><tt class="literal"><span class="pre">cols</span></tt>, <tt class="literal"><span class="pre">rows</span></tt></dt>
<dd>number of columns/rows in the textarea</dd>
<dt><tt class="literal"><span class="pre">wrap</span></tt></dt>
<dd>controls how the browser wraps text and includes newlines in the
submitted form value; consult an HTML book for details.</dd>
</dl>
</div>
</div>
<div class="section" id="checkboxwidget">
<h1><a name="checkboxwidget">CheckboxWidget</a></h1>
<p>Used for single boolean (on/off) value. The value you supply can be
anything, since Python has a boolean interpretation for all values; the
value returned by <tt class="literal"><span class="pre">parse()</span></tt> will always be 0 or 1 (but you shouldn't
rely on that!). Generates an <tt class="literal"><span class="pre">&lt;input</span> <span class="pre">type=&quot;checkbox&quot;&gt;</span></tt> form element.</p>
<div class="section" id="id2">
<h2><a name="id2">Constructor</a></h2>
<pre class="literal-block">
CheckboxWidget(name : string,
value : boolean = false)
</pre>
</div>
<div class="section" id="id3">
<h2><a name="id3">Examples</a></h2>
<pre class="literal-block">
&gt;&gt;&gt; CheckboxWidget(&quot;foo&quot;, value=0).render(request)
'&lt;input name=&quot;foo&quot; type=&quot;checkbox&quot; value=&quot;yes&quot;&gt;'
&gt;&gt;&gt; CheckboxWidget(&quot;foo&quot;, value=&quot;you bet&quot;).render(request)
'&lt;input name=&quot;foo&quot; type=&quot;checkbox&quot; value=&quot;yes&quot; checked&gt;'
</pre>
</div>
</div>
<div class="section" id="radiobuttonswidget">
<h1><a name="radiobuttonswidget">RadiobuttonsWidget</a></h1>
<p>Used for a <em>set</em> of related radiobuttons, ie. several <tt class="literal"><span class="pre">&lt;input</span>
<span class="pre">type=&quot;radio&quot;&gt;</span></tt> tags with the same name and different values. The set
of values are supplied to the constructor as <tt class="literal"><span class="pre">allowed_values</span></tt>, which
may be a list of any Python objects (not just strings). The current
value must be either <tt class="literal"><span class="pre">None</span></tt> (the default) or one of the values in
<tt class="literal"><span class="pre">allowed_values</span></tt>; if you supply a <tt class="literal"><span class="pre">value</span></tt> not in <tt class="literal"><span class="pre">allowed_values</span></tt>,
it will be ignored. <tt class="literal"><span class="pre">parse()</span></tt> will return either <tt class="literal"><span class="pre">None</span></tt> or one of
the values in <tt class="literal"><span class="pre">allowed_values</span></tt>.</p>
<div class="section" id="id4">
<h2><a name="id4">Constructor</a></h2>
<pre class="literal-block">
RadiobuttonsWidget(name : string,
value : any = None,
allowed_values : [any] = None,
descriptions : [string] = map(str, allowed_values),
quote : boolean = true,
delim : string = &quot;\n&quot;)
</pre>
<dl>
<dt><tt class="literal"><span class="pre">allowed_values</span></tt></dt>
<dd><p class="first">specifies how many <tt class="literal"><span class="pre">&lt;input</span> <span class="pre">type=&quot;radio&quot;&gt;</span></tt> tags to generate and the
values for each. Eg. <tt class="literal"><span class="pre">allowed_values=[&quot;foo&quot;,</span> <span class="pre">&quot;bar&quot;]</span></tt> will result in
(roughly):</p>
<pre class="last literal-block">
&lt;input type=&quot;radio&quot; value=&quot;foo&quot;&gt;
&lt;input type=&quot;radio&quot; value=&quot;bar&quot;&gt;
</pre>
</dd>
<dt><tt class="literal"><span class="pre">descriptions</span></tt></dt>
<dd>the text that will actually be shown to the user in the web page
that includes this widget. Handy when the elements of
<tt class="literal"><span class="pre">allowed_values</span></tt> are too terse, or don't have a meaningful
<tt class="literal"><span class="pre">str()</span></tt>, or you want to add some additional cues for the user. If
not supplied, <tt class="literal"><span class="pre">map(str,</span> <span class="pre">allowed_values)</span></tt> is used, with the
exception that <tt class="literal"><span class="pre">None</span></tt> in <tt class="literal"><span class="pre">allowed_values</span></tt> becomes <tt class="literal"><span class="pre">&quot;&quot;</span></tt> (the
empty string) in <tt class="literal"><span class="pre">descriptions</span></tt>. If supplied, <tt class="literal"><span class="pre">descriptions</span></tt>
must be the same length as <tt class="literal"><span class="pre">allowed_values</span></tt>.</dd>
<dt><tt class="literal"><span class="pre">quote</span></tt></dt>
<dd>if true (the default), the elements of 'descriptions' will be
HTML-quoted (using <tt class="literal"><span class="pre">quixote.html.html_quote()</span></tt>) when the widget is
rendered. This is essential if you might have characters like
<tt class="literal"><span class="pre">&amp;</span></tt> or <tt class="literal"><span class="pre">&lt;</span></tt> in your descriptions. However, you'll want to set
<tt class="literal"><span class="pre">quote</span></tt> to false if you are deliberately including HTML markup
in your descriptions.</dd>
<dt><tt class="literal"><span class="pre">delim</span></tt></dt>
<dd>the delimiter to separate the radiobuttons with when rendering
the whole widget. The default ensures that your HTML is readable
(by putting each <tt class="literal"><span class="pre">&lt;input&gt;</span></tt> tag on a separate line), and that there
is horizontal whitespace between each radiobutton.</dd>
</dl>
</div>
<div class="section" id="id5">
<h2><a name="id5">Examples</a></h2>
<pre class="literal-block">
&gt;&gt;&gt; colours = [&quot;red&quot;, &quot;green&quot;, &quot;blue&quot;, &quot;pink&quot;]
&gt;&gt;&gt; widget = RadiobuttonsWidget(&quot;foo&quot;, allowed_values=colours)
&gt;&gt;&gt; print widget.render(request)
&lt;input name=&quot;foo&quot; type=&quot;radio&quot; value=&quot;0&quot;&gt;red&lt;/input&gt;
&lt;input name=&quot;foo&quot; type=&quot;radio&quot; value=&quot;1&quot;&gt;green&lt;/input&gt;
&lt;input name=&quot;foo&quot; type=&quot;radio&quot; value=&quot;2&quot;&gt;blue&lt;/input&gt;
&lt;input name=&quot;foo&quot; type=&quot;radio&quot; value=&quot;3&quot;&gt;pink&lt;/input&gt;
</pre>
<p>(Note that the actual form values, ie. what the browser returns to the
server, are always stringified indices into the 'allowed_values' list.
This is irrelevant to you, since SingleSelectWidget takes care of
converting <tt class="literal"><span class="pre">&quot;1&quot;</span></tt> to <tt class="literal"><span class="pre">1</span></tt> and looking up <tt class="literal"><span class="pre">allowed_values[1]</span></tt>.)</p>
<pre class="literal-block">
&gt;&gt;&gt; values = [val1, val2, val3]
&gt;&gt;&gt; descs = [&quot;thing &lt;b&gt;1&lt;/b&gt;&quot;,
&quot;thing &lt;b&gt;2&lt;/b&gt;&quot;,
&quot;thing &lt;b&gt;3&lt;/b&gt;&quot;]
&gt;&gt;&gt; widget = RadiobuttonsWidget(&quot;bar&quot;,
allowed_values=values,
descriptions=descs,
value=val3,
delim=&quot;&lt;br&gt;\n&quot;,
quote=0)
&gt;&gt;&gt; print widget.render(request)
&lt;input name=&quot;bar&quot; type=&quot;radio&quot; value=&quot;0&quot;&gt;thing &lt;b&gt;1&lt;/b&gt;&lt;/input&gt;&lt;br&gt;
&lt;input name=&quot;bar&quot; type=&quot;radio&quot; value=&quot;1&quot;&gt;thing &lt;b&gt;2&lt;/b&gt;&lt;/input&gt;&lt;br&gt;
&lt;input name=&quot;bar&quot; type=&quot;radio&quot; value=&quot;2&quot; checked=&quot;checked&quot;&gt;thing &lt;b&gt;3&lt;/b&gt;&lt;/input&gt;
</pre>
</div>
</div>
<div class="section" id="singleselectwidget">
<h1><a name="singleselectwidget">SingleSelectWidget</a></h1>
<p>Used to select a single value from a list that's too long or ungainly
for a set of radiobuttons. (Most browsers implement this as a scrolling
list; UNIX versions of Netscape 4.x and earlier used a pop-up menu.)
The value can be any Python object; <tt class="literal"><span class="pre">parse()</span></tt> will return either
<tt class="literal"><span class="pre">None</span></tt> or one of the values you supply to the constructor as
<tt class="literal"><span class="pre">allowed_values</span></tt>. Generates a <tt class="literal"><span class="pre">&lt;select&gt;...&lt;/select&gt;</span></tt> tag, with one
<tt class="literal"><span class="pre">&lt;option&gt;</span></tt> tag for each element of <tt class="literal"><span class="pre">allowed_values</span></tt>.</p>
<div class="section" id="id6">
<h2><a name="id6">Constructor</a></h2>
<pre class="literal-block">
SingleSelectWidget(name : string,
value : any = None,
allowed_values : [any] = None,
descriptions : [string] = map(str, allowed_values),
quote : boolean = true,
size : int = None)
</pre>
<dl>
<dt><tt class="literal"><span class="pre">allowed_values</span></tt></dt>
<dd>determines the set of <tt class="literal"><span class="pre">&lt;option&gt;</span></tt> tags that will go inside the
<tt class="literal"><span class="pre">&lt;select&gt;</span></tt> tag; these can be any Python values (not just strings).
<tt class="literal"><span class="pre">parse()</span></tt> will return either one of the <tt class="literal"><span class="pre">allowed_values</span></tt> or <tt class="literal"><span class="pre">None</span></tt>.
If you supply a <tt class="literal"><span class="pre">value</span></tt> that is not in <tt class="literal"><span class="pre">allowed_values</span></tt>, it
will be ignored.</dd>
<dt><tt class="literal"><span class="pre">descriptions</span></tt></dt>
<dd>(same as RadiobuttonsWidget above)</dd>
<dt><tt class="literal"><span class="pre">quote</span></tt></dt>
<dd>(same as RadiobuttonsWidget above)</dd>
<dt><tt class="literal"><span class="pre">size</span></tt></dt>
<dd>corresponds to the <tt class="literal"><span class="pre">size</span></tt> attribute of the <tt class="literal"><span class="pre">&lt;select&gt;</span></tt> tag: ask
the browser to show a select list with <tt class="literal"><span class="pre">size</span></tt> items visible.
Not always respected by the browser; consult an HTML book.</dd>
</dl>
</div>
<div class="section" id="id7">
<h2><a name="id7">Examples</a></h2>
<pre class="literal-block">
&gt;&gt;&gt; widget = SingleSelectWidget(&quot;foo&quot;,
allowed_values=[&quot;abc&quot;, 123, 5.5])
&gt;&gt;&gt; print widget.render(request)
&lt;select name=&quot;foo&quot;&gt;
&lt;option value=&quot;0&quot;&gt;abc
&lt;option value=&quot;1&quot;&gt;123
&lt;option value=&quot;2&quot;&gt;5.5
&lt;/select&gt;
&gt;&gt;&gt; widget = SingleSelectWidget(&quot;bar&quot;,
value=val2,
allowed_values=[val1, val2, val3],
descriptions=[&quot;foo&quot;, &quot;bar&quot;, &quot;foo &amp; bar&quot;],
size=3)
&gt;&gt;&gt; print widget.render(request)
&lt;select name=&quot;bar&quot; size=&quot;3&quot;&gt;
&lt;option value=&quot;0&quot;&gt;foo
&lt;option selected value=&quot;1&quot;&gt;bar
&lt;option value=&quot;2&quot;&gt;foo &amp;amp; bar
&lt;/select&gt;
</pre>
</div>
</div>
<div class="section" id="multipleselectwidget">
<h1><a name="multipleselectwidget">MultipleSelectWidget</a></h1>
<p>Used to select multiple values from a list. Everything is just like
SingleSelectWidget, except that <tt class="literal"><span class="pre">value</span></tt> can be a list of objects
selected from <tt class="literal"><span class="pre">allowed_values</span></tt> (in which case every object in <tt class="literal"><span class="pre">value</span></tt>
will initially be selected). Generates a <tt class="literal"><span class="pre">&lt;select</span> <span class="pre">multiple&gt;...&lt;/select&gt;</span></tt>
tag, with one <tt class="literal"><span class="pre">&lt;option&gt;</span></tt> tag for each element of <tt class="literal"><span class="pre">allowed_values</span></tt>.</p>
<div class="section" id="id8">
<h2><a name="id8">Constructor</a></h2>
<pre class="literal-block">
MultipleSelectWidget(name : string,
value : any | [any] = None,
allowed_values : [any] = None,
descriptions : [string] = map(str, allowed_values),
quote : boolean = true,
size : int = None)
</pre>
</div>
</div>
<div class="section" id="submitbuttonwidget">
<h1><a name="submitbuttonwidget">SubmitButtonWidget</a></h1>
<p>Used for generating submit buttons. Note that HTML submit buttons are
rather weird, and Quixote preserves this weirdness -- the Widget classes
are meant to be a fairly thin wrapper around HTML form elements, after
all.</p>
<p>In particular, the widget value for a submit button controls two things:
what the user sees in their browser (the text in the button) and what
the browser returns as the value for that form element. You can't
control the two separately, as you can with radiobuttons or selection
widgets.</p>
<p>Also, SubmitButtonWidget is the only widget with an optional <tt class="literal"><span class="pre">name</span></tt>.
In many simple forms, all you care about is the fact that the form was
submitted -- which submit button the user used doesn't matter.</p>
<div class="section" id="id9">
<h2><a name="id9">Constructor</a></h2>
<pre class="literal-block">
SubmitButtonWidget(name : string = None,
value : string = None)
</pre>
<dl>
<dt><tt class="literal"><span class="pre">value</span></tt></dt>
<dd>the text that will be shown in the user's browser, <em>and</em> the
value that will be returned for this form element (widget)
if the user selects this submit button.</dd>
</dl>
</div>
<div class="section" id="id10">
<h2><a name="id10">Examples</a></h2>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; SubmitButtonWidget(value=&quot;Submit Form&quot;).render(request)
'&lt;input type=&quot;submit&quot; value=&quot;Submit Form&quot;&gt;'
</pre>
</blockquote>
</div>
</div>
<div class="section" id="hiddenwidget">
<h1><a name="hiddenwidget">HiddenWidget</a></h1>
<p>Used to generate HTML hidden widgets, which can be useful for carrying
around non-sensitive application state. (The Quixote form framework
uses hidden widgets for form tokens as a measure against cross-site
request forgery [CSRF] attacks. So by &quot;sensitive&quot; I mean &quot;information
which should not be revealed&quot;, rather than &quot;security-related&quot;. If you
wouldn't put it in a cookie or in email, don't put it in a hidden form
element.)</p>
<div class="section" id="id11">
<h2><a name="id11">Constructor</a></h2>
<pre class="literal-block">
HiddenWidget(name : string,
value : string)
</pre>
</div>
<div class="section" id="id12">
<h2><a name="id12">Examples</a></h2>
<pre class="literal-block">
&gt;&gt;&gt; HiddenWidget(&quot;form_id&quot;, &quot;2452345135&quot;).render(request)
'&lt;input type=&quot;hidden&quot; name=&quot;form_id&quot; value=&quot;2452345135&quot;&gt;'
</pre>
</div>
</div>
<div class="section" id="intwidget">
<h1><a name="intwidget">IntWidget</a></h1>
<p>The first derived widget class: this is a subclass of StringWidget
specifically for entering integer values. As such, this is the first
widget class we've covered that can reject certain user input. (The
selection widgets all have to validate their input in case of broken or
malicious clients, but they just drop bogus values.) If the user enters
a string that Python's built-in <tt class="literal"><span class="pre">int()</span></tt> can't convert to an integer,
IntWidget's <tt class="literal"><span class="pre">parse()</span></tt> method raises FormValueError (also defined in
the quixote.form.widget module). This exception is handled by Quixote's
form framework, but if you're using widget objects on their own, you'll
have to handle it yourself.</p>
<p><tt class="literal"><span class="pre">IntWidget.parse()</span></tt> always returns an integer or <tt class="literal"><span class="pre">None</span></tt>.</p>
<div class="section" id="id13">
<h2><a name="id13">Constructor</a></h2>
<pre class="literal-block">
IntWidget(name : string,
value : int = None,
size : int = None,
maxlength : int = None)
</pre>
<p>Constructor arguments are as for StringWidget, except that <tt class="literal"><span class="pre">value</span></tt>
must be an integer (or <tt class="literal"><span class="pre">None</span></tt>). Note that <tt class="literal"><span class="pre">size</span></tt> and
<tt class="literal"><span class="pre">maxlength</span></tt> have exactly the same meaning: they control the size of
the input widget and the maximum number of characters of input.</p>
<p>[Examples]</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; IntWidget(&quot;num&quot;, value=37, size=5).render(request)
'&lt;input type=&quot;string&quot; name=&quot;num&quot; value=&quot;37&quot; size=&quot;5&quot;&gt;'
</pre>
</blockquote>
</div>
</div>
<div class="section" id="floatwidget">
<h1><a name="floatwidget">FloatWidget</a></h1>
<p>FloatWidget is identical to IntWidget, except:</p>
<ul class="simple">
<li><tt class="literal"><span class="pre">value</span></tt> must be a float</li>
<li><tt class="literal"><span class="pre">parse()</span></tt> returns a float or <tt class="literal"><span class="pre">None</span></tt></li>
<li><tt class="literal"><span class="pre">parse()</span></tt> raises FormValueError if the string entered by the
user cannot be converted by Python's built-in <tt class="literal"><span class="pre">float()</span></tt> function</li>
</ul>
</div>
<div class="section" id="optionselectwidget">
<h1><a name="optionselectwidget">OptionSelectWidget</a></h1>
<p>OptionSelectWidget is simply a SingleSelectWidget that uses a bit of
Javascript to automatically submit the current form as soon as the user
selects a value. This is useful for very simple one-element forms where
you don't want to bother with a submit button, or for very complex forms
where you need to revamp the user interface based on a user's selection.
Your form-processing code could then detect that style of form
submission, and regenerate a slightly different form for the user. (Or
you could treat it as a full-blown form submission, if the only widget
of interest is the OptionSelectWidget.)</p>
<p>For example, if you're asking a user for their address, some of the
details will vary depending on which country they're in. You might make
the country widget an OptionSelectWidget: if the user selects &quot;Canada&quot;,
you'll ask them for a province and a postal code; if they select &quot;United
States&quot;, you ask for a state and a zip code; and so forth. (I don't
really recommend a user interface that works this way: you'll spend way
too much time getting the details right [&quot;How many states does Australia
have again?&quot;], and you're bound to get something wrong -- there are over
200 countries in the world, after all.)</p>
<p>Be warned that since OptionSelectWidget relies on Javascript to work,
using it makes immediately makes your application less portable and more
fragile. One thing to avoid: form elements with a name of <tt class="literal"><span class="pre">submit</span></tt>,
since that masks the Javascript function called by OptionSelectWidget.</p>
</div>
</div>
</body>
</html>

View File

@ -1,315 +0,0 @@
<?xml version="1.0" encoding="us-ascii" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
<title>WSGI and Quixote</title>
<style type="text/css">
/*
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $
:Revision: $Revision: 4224 $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin-left: 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left {
clear: left }
img.align-right {
clear: right }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font-family: serif ;
font-size: 100% }
pre.literal-block, pre.doctest-block {
margin-left: 2em ;
margin-right: 2em ;
background-color: #eeeeee }
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
tt.docutils {
background-color: #eeeeee }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="wsgi-and-quixote">
<h1 class="title">WSGI and Quixote</h1>
<p>&quot;WSGI&quot; stands for the Python Web Server Gateway Interface, defined in
<a class="reference" href="http://www.python.org/dev/peps/pep-0333/">PEP 333</a>.</p>
<p>The function <tt class="docutils literal"><span class="pre">quixote.get_wsgi_app()</span></tt> returns a WSGI application
object for the current publisher instance.</p>
<p>This WSGI application ties into the publisher at the <tt class="docutils literal"><span class="pre">process_request</span></tt>
method, and bypasses the <tt class="docutils literal"><span class="pre">process</span></tt> method completely.</p>
<div class="section">
<h1><a id="an-example" name="an-example">An Example</a></h1>
<p>For example, you can use the <tt class="docutils literal"><span class="pre">wsgiref</span></tt> module (included with
Python 2.5 and later) to serve a Quixote application.</p>
<pre class="literal-block">
your_app.create_publisher()
wsgi_app = quixote.get_wsgi_app()
from wsgiref.simple_server import make_server
make_server('', 8000, wsgi_app)
</pre>
</div>
</div>
</body>
</html>