summaryrefslogtreecommitdiff
path: root/pypers/europython05/Quixote-2.0/doc
diff options
context:
space:
mode:
Diffstat (limited to 'pypers/europython05/Quixote-2.0/doc')
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/INSTALL.txt32
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/Makefile31
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/PTL.txt264
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/demo.txt221
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/form2conversion.txt358
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/multi-threaded.txt39
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/programming.txt157
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/session-mgmt.txt323
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/static-files.txt51
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/upgrading.txt324
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/web-server.txt258
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/web-services.txt169
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/widgets.txt524
-rwxr-xr-xpypers/europython05/Quixote-2.0/doc/win32.txt14
14 files changed, 2765 insertions, 0 deletions
diff --git a/pypers/europython05/Quixote-2.0/doc/INSTALL.txt b/pypers/europython05/Quixote-2.0/doc/INSTALL.txt
new file mode 100755
index 0000000..ccc18c8
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/INSTALL.txt
@@ -0,0 +1,32 @@
+Installing Quixote
+==================
+
+Quixote requires Python 2.3 or later.
+
+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:
+
+ python -c "import os, quixote; print os.path.dirname(quixote.__file__)"
+
+and then remove away the reported directory. (If the import fails, then
+you don't have an existing Quixote installation.)
+
+Now install the new version by running (in the distribution directory),
+
+ python setup.py install
+
+and you're done.
+
+Quick start
+===========
+
+In a terminal window, run server/simple_server.py.
+In a browser, open http://localhost:8080
+
+
+Upgrading a Quixote 1 application to Quixote 2.
+===============================================
+
+See upgrading.txt for details.
+
diff --git a/pypers/europython05/Quixote-2.0/doc/Makefile b/pypers/europython05/Quixote-2.0/doc/Makefile
new file mode 100755
index 0000000..b09d2f3
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/Makefile
@@ -0,0 +1,31 @@
+#
+# Makefile to convert Quixote docs to HTML
+#
+# $Id: Makefile 20217 2003-01-16 20:51:53Z akuchlin $
+#
+
+TXT_FILES = $(wildcard *.txt)
+HTML_FILES = $(filter-out ZPL%,$(TXT_FILES:%.txt=%.html))
+
+RST2HTML = /www/python/bin/rst2html
+RST2HTML_OPTS = -o us-ascii
+
+DEST_HOST = staging.mems-exchange.org
+DEST_DIR = /www/www-docroot/software/quixote/doc
+
+SS = default.css
+
+%.html: %.txt
+ $(RST2HTML) $(RST2HTML_OPTS) $< $@
+
+all: $(HTML_FILES)
+
+clean:
+ rm -f $(HTML_FILES)
+
+install:
+ rsync -vptgo *.html $(SS) $(DEST_HOST):$(DEST_DIR)
+
+local-install:
+ dir=`pwd` ; \
+ cd $(DEST_DIR) && ln -sf $$dir/*.html $$dir/$(SS) .
diff --git a/pypers/europython05/Quixote-2.0/doc/PTL.txt b/pypers/europython05/Quixote-2.0/doc/PTL.txt
new file mode 100755
index 0000000..c0e4b0f
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/PTL.txt
@@ -0,0 +1,264 @@
+PTL: Python Template Language
+=============================
+
+Introduction
+------------
+
+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.
+
+Specifically, a PTL template is designated by inserting a ``[plain]``
+or ``[html]`` modifier after the function name. The value of
+expressions inside templates are kept, not discarded. If the type is
+``[html]`` then non-literal strings are passed through a function that
+escapes HTML special characters.
+
+
+Plain text templates
+--------------------
+
+Here's a sample plain text template::
+
+ def foo [plain] (x, y = 5):
+ "This is a chunk of static text."
+ greeting = "hello world" # statement, no PTL output
+ print 'Input values:', x, y
+ z = x + y
+ """You can plug in variables like x (%s)
+ in a variety of ways.""" % x
+
+ "\n\n"
+ "Whitespace is important in generated text.\n"
+ "z = "; z
+ ", but y is "
+ y
+ "."
+
+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.
+
+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::
+
+ def foo [plain] (x, y = 5):
+ "This is a chunk of static text."
+ greeting = "hello world" # statement, no PTL output
+ print 'Input values:', x, y
+ z = x + y
+ """You can plug in variables like x (%s)
+ in a variety of ways.""" % x
+
+Calling this template with ``foo(1, 2)`` results in the following
+string::
+
+ This is a chunk of static text.You can plug in variables like x (1)
+ in a variety of ways.
+
+Normally when Python evaluates expressions inside functions, it just
+discards their values, but in a ``[plain]`` PTL template the value is
+converted to a string using ``str()`` and appended to the template's
+return value. There's a single exception to this rule: ``None`` 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 ``None``
+would require assigning their value to a variable. You'd have to write
+``dummy = list.sort()`` in PTL code, which would be strange and
+confusing.)
+
+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 ``...text.You can ...`` from the example. You'd
+have to add an extra space to one of the string literals to correct
+this.
+
+The assignment to the ``greeting`` local variable is a statement, not an
+expression, so it doesn't return a value and produces no output. The
+output from the ``print`` 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. ``print`` should never be used
+to generate output returned to the browser, only for adding debugging
+traces to a template.
+
+Inside templates, you can use all of Python's control-flow statements::
+
+ def numbers [plain] (n):
+ for i in range(n):
+ i
+ " " # PTL does not add any whitespace
+
+Calling ``numbers(5)`` will return the string ``"1 2 3 4 5 "``. You can
+also have conditional logic or exception blocks::
+
+ def international_hello [plain] (language):
+ if language == "english":
+ "hello"
+ elif language == "french":
+ "bonjour"
+ else:
+ raise ValueError, "I don't speak %s" % language
+
+
+HTML templates
+--------------
+
+Since PTL is usually used to generate HTML documents, an ``[html]``
+template type has been provided to make generating HTML easier.
+
+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 '<' and '&'. This leads to a class of
+security bugs called "cross-site scripting" 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).
+
+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).
+
+Here's how this feature works. PTL defines a class called
+``htmltext`` that represents a string that's already been HTML-escaped
+and can be safely sent to the client. The function ``htmlescape(string)``
+is used to escape data, and it always returns an ``htmltext``
+instance. It does nothing if the argument is already ``htmltext``.
+
+If a template function is declared ``[html]`` instead of ``[text]``
+then two things happen. First, all literal strings in the function
+become instances of ``htmltext`` instead of Python's ``str``. Second,
+the values of expressions are passed through ``htmlescape()`` instead
+of ``str()``.
+
+``htmltext`` type is like the ``str`` type except that operations
+combining strings and ``htmltext`` instances will result in the string
+being passed through ``htmlescape()``. For example::
+
+ >>> from quixote.html import htmltext
+ >>> htmltext('a') + 'b'
+ <htmltext 'ab'>
+ >>> 'a' + htmltext('b')
+ <htmltext 'ab'>
+ >>> htmltext('a%s') % 'b'
+ <htmltext 'ab'>
+ >>> response = 'green eggs & ham'
+ >>> htmltext('The response was: %s') % response
+ <htmltext 'The response was: green eggs &amp; ham'>
+
+Note that calling ``str()`` strips the ``htmltext`` type and should be
+avoided since it usually results in characters being escaped more than
+once. While ``htmltext`` behaves much like a regular string, it is
+sometimes necessary to insert a ``str()`` inside a template in order
+to obtain a genuine string. For example, the ``re`` module requires
+genuine strings. We have found that explicit calls to ``str()`` can
+often be avoided by splitting some code out of the template into a
+helper function written in regular Python.
+
+It is also recommended that the ``htmltext`` constructor be used as
+sparingly as possible. The reason is that when using the htmltext
+feature of PTL, explicit calls to ``htmltext`` become the most likely
+source of cross-site scripting holes. Calling ``htmltext`` is like
+saying "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."
+
+Note that literal strings in template functions declared with
+``[html]`` are htmltext instances, and therefore won't be escaped.
+You'll only need to use ``htmltext`` when HTML markup comes from
+outside the template. For example, if you want to include a file
+containing HTML::
+
+ def output_file [html] ():
+ '<html><body>' # does not get escaped
+ htmltext(open("myfile.html").read())
+ '</body></html>'
+
+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 ``HEAD`` element::
+
+ def meta_tags [html] (title, description):
+ '<title>%s</title>' % title
+ '<meta name="description" content="%s">\n' % description
+
+There are no calls to ``htmlescape()`` at all, but string literals
+such as ``<title>%s</title>`` have all be turned into ``htmltext``
+instances, so the string variables will be automatically escaped::
+
+ >>> t.meta_tags('Catalog', 'A catalog of our cool products')
+ <htmltext '<title>Catalog</title>
+ <meta name="description" content="A catalog of our cool products">\n'>
+ >>> t.meta_tags('Dissertation on <HEAD>',
+ ... 'Discusses the "LINK" and "META" tags')
+ <htmltext '<title>Dissertation on &lt;HEAD&gt;</title>
+ <meta name="description"
+ content="Discusses the &quot;LINK&quot; and &quot;META&quot; tags">\n'>
+ >>>
+
+Note how the title and description have had HTML-escaping applied to them.
+(The output has been manually pretty-printed to be more readable.)
+
+Once you start using ``htmltext`` in one of your templates, mixing
+plain and HTML templates is tricky because of ``htmltext``'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 ``str()`` to convert
+``htmltext`` instances to regular Python strings; just be sure the
+resulting string isn't HTML-escaped again.
+
+Two implementations of ``htmltext`` are provided, one written in pure
+Python and a second one implemented as a C extension. Both versions
+have seen production use.
+
+
+PTL modules
+-----------
+
+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 ``.pyc``. 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 ``enable_ptl()`` function::
+
+ from quixote import enable_ptl
+ enable_ptl()
+
+(Note: if you're using ZODB, always import ZODB *before* 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.)
+
+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 ``foo.ptl``, you could then write Python code that did
+this::
+
+ from foo import numbers
+ def f():
+ return numbers(10)
+
+You may want to keep this little function in your ``PYTHONSTARTUP``
+file::
+
+ def ptl():
+ try:
+ import ZODB
+ except ImportError:
+ pass
+ from quixote import enable_ptl
+ enable_ptl()
+
+This is useful if you want to interactively play with a PTL module.
+
diff --git a/pypers/europython05/Quixote-2.0/doc/demo.txt b/pypers/europython05/Quixote-2.0/doc/demo.txt
new file mode 100755
index 0000000..4272223
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/demo.txt
@@ -0,0 +1,221 @@
+Running the Quixote Demos
+=========================
+
+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.
+
+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 http://localhost:8080.
+
+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:
+
+ simple_server.py --factory quixote.demo.mini_demo.create_publisher
+
+or
+
+ simple_server.py --factory quixote.demo.altdemo.create_publisher
+
+
+
+Understanding the mini_demo
+---------------------------
+
+Start the mini demo by running the command:
+ simple_server.py --factory quixote.demo.mini_demo.create_publisher
+
+In a browser, load http://localhost:8080. In your browser, you should
+see "Welcome ..." page. In your terminal window, you will see a
+"localhost - - ..." line for each request. These are access log
+messages from the web server.
+
+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.
+
+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', ''].
+
+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.
+
+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
+http://localhost:8080/
+
+As mentioned above, the _q_translate() identifies a "designated"
+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'.
+
+When you click on the link on the top page, you get
+http://localhost:8080/hello. 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.
+
+Feeling bold? (Just kidding, this won't hurt at all.) Try opening
+http://localhost:8080/bogus. 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 "raise
+'ouch'" into the hello() method. Kill the demo server (Control-c) and
+start a new one with the same command as before. Now load the
+http://localhost:8080/hello 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
+"Internal Server Error" message instead of the full traceback. If you
+provide the value 'html', the browser displays a prettier version of
+the traceback.
+
+One more thing to try here. Replace your 'raise "ouch"' line in the hello() method with 'print "ouch"'. 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.
+
+
+Understanding the root demo
+---------------------------
+
+Start the root demo by running the command:
+ simple_server.py --factory quixote.demo.create_publisher
+
+In a browser, open http://localhost:8080 as before.
+Click around at will.
+
+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 "root.ptl". The suffix of "ptl" 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.
+
+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
+"[html]" between the function name and the parameter list. These
+functions are ptl templates. For details about PTL, see the PTL.txt
+file.
+
+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 ("favicon.ico",
+"favicon_ico") to designate "favicon_ico" as the attribute name
+corresponding the the "favicon.ico" URL component.
+
+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.
+
+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.
+
+The _q_lookup() method
+----------------------
+
+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.
+
+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 http://localhost:8080/extras/12/ to see how
+this behaves.
+
+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
+http://localhost:8080/extras/12 to yield the same page as
+http://localhost:8080/extras/12/. If given the path ['extras', '12'],
+the default _q_traverse() ends up *calling* 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__]
+
+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.
+
+The _q_resolve() method
+-----------------------
+
+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 *have* that attribute, the _q_resolve() method is called to
+"resolve" the trouble. Typically, the _q_resolve() imports or
+constructs what *should* 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.
+
+Forms
+-----
+
+You can't get very far writing web applications without writing forms.
+The root demo includes, at http://localhost:8080/extras/form, a page
+that demonstrates basic usage of the Form class and widgets defined in
+the quixote.form package.
+
+$Id: demo.txt 25695 2004-11-30 20:53:44Z dbinger $
diff --git a/pypers/europython05/Quixote-2.0/doc/form2conversion.txt b/pypers/europython05/Quixote-2.0/doc/form2conversion.txt
new file mode 100755
index 0000000..290db38
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/form2conversion.txt
@@ -0,0 +1,358 @@
+Converting form1 forms to use the form2 library
+===============================================
+
+Note:
+-----
+The packages names have changed in Quixote 2.
+
+Quixote form1 forms are now in the package quixote.form1.
+(In Quixote 1, they were in quixote.form.)
+
+Quixote form2 forms are now in the package quixote.form.
+(In Quixote 1, they were in quixote.form2.)
+
+
+Introduction
+------------
+
+These are some notes and examples for converting Quixote form1 forms,
+that is forms derived from ``quixote.form1.Form``, to the newer form2
+forms.
+
+Form2 forms are more flexible than their form1 counterparts in that they
+do not require you to use the ``Form`` 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 ``process``, ``render``,
+and ``action`` is desirable.
+
+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.
+
+The other end of the spectrum and normally the easiest way to port
+form1 forms to form2 is to use the ``compatibility`` module provided
+in the form2 package. The compatibility module's Form class provides
+much of the same highly structured machinery (via a ``handle`` master
+method) that the form1 framework uses.
+
+Converting form1 forms using using the compatibility module
+-----------------------------------------------------------
+
+Here's the short list of things to do to convert form1 forms to
+form2 using compatibility.
+
+ 1. Import the Form base class from ``quixote.form.compatibility``
+ rather than from quixote.form1.
+
+ 2. 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.
+
+ Form1 API::
+
+ self.error['widget_name'] = 'the error message'
+
+ Form2 API::
+
+ self.set_error('widget_name', 'the error message')
+
+ If you want to find out if the form already has errors, change
+ the form1 style of direct references to the ``self.errors``
+ dictionary to a call to the ``has_errors`` method.
+
+ Form1 API::
+
+ if not self.error:
+ do some more error checking...
+
+ Form2 API::
+
+ if not self.has_errors():
+ do some more error checking...
+
+ 3. Form2 select widgets no longer take ``allowed_values`` or
+ ``descriptions`` arguments. If you are adding type of form2 select
+ widget, you must provide the ``options`` 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::
+
+ options: [objects:any]
+ or
+ options: [(object:any, description:any)]
+ or
+ options: [(object:any, description:any, key:any)]
+
+ An easy way to construct options if you already have
+ allowed_values and descriptions is to use the built-in function
+ ``zip`` to define options::
+
+ options=zip(allowed_values, descriptions)
+
+ Note, however, that often it is simpler to to construct the
+ ``options`` list directly.
+
+ 4. 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 ``quixote.form.css``.
+
+
+Here's the longer list of things you may need to tweak in order for
+form2 compatibility forms to work with your form1 code.
+
+ * ``widget_type`` widget class attribute is gone. This means when
+ adding widgets other than widgets defined in ``quixote.form.widget``,
+ you must import the widget class into your module and pass the
+ widget class as the first argument to the ``add_widget`` method
+ rather than using the ``widget_type`` string.
+
+ * The ``action_url`` argument to the form's render method is now
+ a keyword argument.
+
+ * If you use ``OptionSelectWidget``, there is no longer a
+ ``get_current_option`` method. You can get the current value
+ in the normal way.
+
+ * ``ListWidget`` has been renamed to ``WidgetList``.
+
+ * There is no longer a ``CollapsibleListWidget`` class. If you need
+ this functionality, consider writing a 'deletable composite widget'
+ to wrap your ``WidgetList`` widgets in it::
+
+ 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)
+
+
+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:
+
+ * In your process method, you don't really need to get a ``form_data``
+ dictionary by calling ``Form.process`` to ensure your widgets are
+ parsed. Instead, the parsed value of any widget is easy to obtain
+ using the widget's ``get_value`` method or the form's
+ ``__getitem__`` method. So, instead of::
+
+ form_data = Form.process(self, request)
+ val = form_data['my_widget']
+
+ You can use::
+
+ val = self['my_widget']
+
+ If the widget may or may not be in the form, you can use ``get``::
+
+ val = self.get('my_widget')
+
+
+ * It's normally not necessary to provide the ``action_url`` argument
+ to the form's ``render`` method.
+
+ * 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 ``add`` (or ``add_widget`` in
+ the compatibility module) can be retrieved using the form's
+ ``get_widget`` method.
+
+
+Converting form1 forms to form2 by functional rewrite
+-----------------------------------------------------
+
+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.
+
+First the form1 form::
+
+ 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'] < 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) + '/')
+
+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::
+
+ 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'] < 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)
+
+
+As you can see in the example, the function still has all of the same
+parts of it's form1 equivalent.
+
+ 1. It determines if it's to create a new object or edit an existing one
+ 2. It adds submit buttons and widgets
+ 3. It has a function that knows how to render the form
+ 4. It has a function that knows how to do error processing on the form
+ 5. It has a function that knows how to register permanent changes to
+ objects when the form is submitted successfully.
+
+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.
+
+Form2 functional forms do not have the ``handle`` master-method that
+is called after the form is initialized. Instead, we deal with this
+functionality manually. Here are some things that the ``handle``
+portion of your form might need to implement illustrated in the
+order that often makes sense.
+
+ 1. Get the value of any submit buttons using ``form.get_submit``
+ 2. If the form has not been submitted yet, return ``render()``.
+ 3. See if the cancel button was pressed, if so return a redirect.
+ 4. Call your ``process`` 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.
+ 5. 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 ``get_submit`` is ``True`` in this case and if it is,
+ you want to clear any errors and re-render the form.
+ 6. If the form has not been submitted or if the form has errors,
+ you simply want to render the form.
+ 7. Check for your named submit buttons which you expect for
+ successful form posting e.g. ``add`` or ``update``. If one of
+ these is pressed, call you action inner function.
+ 8. Finally, return a redirect to the expected page following a
+ form submission.
+
+These steps are illustrated by the following snippet of code and to a
+large degree in the above functional form2 code example. Often this
+``handle`` 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 ``process`` function or the call to it::
+
+ 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)
diff --git a/pypers/europython05/Quixote-2.0/doc/multi-threaded.txt b/pypers/europython05/Quixote-2.0/doc/multi-threaded.txt
new file mode 100755
index 0000000..f3be1a5
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/multi-threaded.txt
@@ -0,0 +1,39 @@
+Multi-Threaded Quixote Applications
+===================================
+
+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.
+
+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::
+
+ 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())
+
+Using ThreadedPublisher, you now have one current request per thread,
+rather than one for the entire process.
+
+
+$Id: multi-threaded.txt 20217 2003-01-16 20:51:53Z akuchlin $
diff --git a/pypers/europython05/Quixote-2.0/doc/programming.txt b/pypers/europython05/Quixote-2.0/doc/programming.txt
new file mode 100755
index 0000000..d94adf7
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/programming.txt
@@ -0,0 +1,157 @@
+Quixote Programming Overview
+============================
+
+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:
+
+1) 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.
+
+2) 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.
+
+ The most important configuration parameters are:
+
+ ``ERROR_EMAIL``
+ e-mail address to which errors will be mailed
+ ``ERROR_LOG``
+ file to which errors will be logged
+
+ For development/debugging, you should also set ``DISPLAY_EXCEPTIONS``
+ true; the default value is false, to favor security over convenience.
+
+3) 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 ``root_directory``. Normally, the root_directory will be an
+ instance of the Directory class.
+
+
+Driver script
+-------------
+
+The driver script is the interface between your web server and Quixote's
+"publishing loop", which in turn is the gateway to your application
+code. Thus, there are two things that your Quixote driver script must
+do:
+
+* create a Quixote publisher -- that is, an instance of the Publisher
+ class provided by the quixote.publish module -- and customize it for
+ your application
+
+* 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).
+
+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.
+
+The most important application-specific customization done by the driver
+script is to set the root directory of your application.
+
+The quixote.servers package includes driver modules for cgi, fastcgi,
+scgi, medusa, twisted, and the simple_server. Each of these modules
+includes a ``run()`` 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 ``run()`` 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.)
+
+That's almost the simplest possible case -- there's no
+application-specific configuration info apart from the root directory.
+
+Getting the driver script to actually run is between you and your web
+server. See the web-server.txt document for help.
+
+
+Configuration file
+------------------
+
+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.
+
+Logging
+-------
+
+The publisher also accepts an optional ``logger`` keyword argument,
+that should, if provided, support the same methods as the
+default value, an instance of ``DefaultLogger``. Even if you
+use the default logger, you can still customize the behavior
+by setting configuration values for ``access_log``, ``error_log``, and/or
+``error_email``. These configuration variables are described
+more fully in config.py.
+
+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::
+
+ 127.0.0.1 - 2001-10-15 09:48:43
+ 2504 "GET /catalog/ HTTP/1.1"
+ 200 'Opera/6.0 (Linux; U)' 0.10sec
+
+This line consists of:
+
+* client IP address
+* current user (according to Quixote session management mechanism,
+ so this will be "-" unless you're using a session manager that
+ does authentication)
+* date and time of request in local timezone, as YYYY-MM-DD hh:mm:ss
+* process ID of the process serving the request (eg. your CGI/FastCGI
+ driver script)
+* the HTTP request line (request method, URI, and protocol)
+* response status code
+* HTTP user agent string (specifically, this is
+ ``repr(os.environ.get('HTTP_USER_AGENT', ''))``)
+* time to complete the request
+
+If no access log is configured (ie., ``ACCESS_LOG`` is ``None``), then
+Quixote will not do any access logging.
+
+The error log is used for three purposes:
+
+* application output to ``sys.stdout`` and ``sys.stderr`` goes to
+ Quixote's error log
+* application tracebacks will be written to Quixote's error log
+
+If no error log is configured (with ``ERROR_LOG``), 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.
+
+Having stdout redirected to the error log is useful for debugging. You
+can just sprinkle ``print`` statements into your application and the
+output will wind up in the error log.
+
+
+Application code
+----------------
+
+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.
+
+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.
+
+
diff --git a/pypers/europython05/Quixote-2.0/doc/session-mgmt.txt b/pypers/europython05/Quixote-2.0/doc/session-mgmt.txt
new file mode 100755
index 0000000..19df072
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/session-mgmt.txt
@@ -0,0 +1,323 @@
+Quixote Session Management
+==========================
+
+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 "session" for each user, ie. where all requests performed by
+that user are somehow tied together on the server.
+
+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.)
+
+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.
+
+In a nutshell, session management with Quixote works like this:
+
+* 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.
+
+* 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 ``QX_session`` 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. ::
+
+ Set-Cookie: QX_session="928F82A9B8FA92FD"
+
+ (You can instruct Quixote to specify the domain and path for
+ URLs to which this cookie should be sent.)
+
+* the user agent stores this cookie for future requests
+
+* the next time the user agent requests a resource that matches the
+ cookie's domain and path, it includes the ``QX_session`` cookie
+ previously generated by Quixote in the request headers, eg.::
+
+ Cookie: QX_session="928F82A9B8FA92FD"
+
+* 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.
+
+There are two caveats to keep in mind before proceeding, one major and
+one minor:
+
+* 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 "Session persistence" below for information.
+
+* 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.
+
+
+Session management demo
+-----------------------
+
+There's a simple demo of Quixote's session management in demo/altdemo.py.
+If the durus (http://www.mems-exchange.org/software/durus/) 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.
+
+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 ``user`` 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.
+
+Tracking the number of requests is a bit more interesting: from the
+DemoSession class in altdemo.py::
+
+ def __init__ (self, id):
+ Session.__init__(self, id)
+ self.num_requests = 0
+
+ def start_request (self):
+ Session.start_request(self)
+ self.num_requests += 1
+
+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 ``num_requests`` in the demo) or methods of the
+current Session instance.
+
+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::
+
+ if not get_user():
+ content += htmltext('<p>%s</p>' % href('login', 'login'))
+ else:
+ content += htmltext(
+ '<p>Hello, %s.</p>') % get_user()
+ content += htmltext('<p>%s</p>' % href('logout', 'logout'))
+
+
+Note that we must quote the user's name, because they are free to enter
+anything they please, including special HTML characters like ``&`` or
+``<``.
+
+Of course, ``session.user`` will never be set if we don't set it
+ourselves. The code that processes the login form is just this (from
+``login()`` in ``demo/altdemo.py``) ::
+
+ if get_field("name"):
+ session = get_session()
+ session.set_user(get_field("name")) # This is the important part.
+
+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 "user name". 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.
+
+
+Configuring the session cookie
+------------------------------
+
+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 ::
+
+ SESSION_COOKIE_NAME = "foo_session"
+
+and the second application might have ::
+
+ SESSION_COOKIE_NAME = "bar_session"
+
+Next, you can use ``SESSION_COOKIE_DOMAIN`` and ``SESSION_COOKIE_PATH``
+to set the cookie attributes that control which requests the cookie is
+included with. By default, these are both ``None``, which instructs
+Quixote to send the cookie without ``Domain`` or ``Path`` qualifiers.
+For example, if the client requests ``/foo/bar/`` 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 ::
+
+ Set-Cookie: QX_session="928F82A9B8FA92FD"
+
+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 ``/foo/bar/``.
+
+If you want to ensure that your session cookie is included with all
+requests to www.example.com, you should set ``SESSION_COOKIE_PATH`` in your
+config file::
+
+ SESSION_COOKIE_PATH = "/"
+
+which will cause Quixote to set the cookie like this::
+
+ Set-Cookie: QX_session="928F82A9B8FA92FD"; Path="/"
+
+which will instruct the browser to include that cookie with *all*
+requests to www.example.com.
+
+However, think carefully about what you set ``SESSION_COOKIE_PATH`` to
+-- eg. if you set it to "/", but all of your Quixote code is under "/q/"
+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.) ::
+
+ SESSION_COOKIE_PATH = "/q/"
+
+on such servers. The trailing slash is important; without it, your
+session cookies will be sent to URIs like ``/qux`` and ``/qix``, even if
+you don't control those URIs.
+
+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
+``SESSION_COOKIE_DOMAIN``:
+
+ SESSION_COOKIE_DOMAIN = ".example.com"
+
+Finally, note that the ``SESSION_COOKIE_*`` configuration variables
+*only* affect Quixote's session cookie; if you set your own cookies
+using the ``HTTPResponse.set_cookie()`` method, then the cookie sent to
+the client is completely determined by that ``set_cookie()`` call.
+
+See RFCs 2109 and 2965 for more information on the rules browsers are
+supposed to follow for including cookies with HTTP requests.
+
+
+Writing the session class
+-------------------------
+
+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:
+
+* initialize the attributes that will be used by your application
+
+* override the ``has_info()`` method, so the session manager knows when
+ it must save your session object
+
+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.
+
+For development/testing work, it's fine to say that your session objects
+should always be saved::
+
+ def has_info (self):
+ return 1
+
+The opposite extreme is to forget to override ``has_info()`` altogether,
+in which case session management most likely won't work: unless you
+tickle the Session object such that the base ``has_info()`` 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.
+
+In a real application, you need to think carefully about what data to
+store in your sessions, and how ``has_info()`` 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 ``robots.txt`` will
+come along and crawl your entire site, wreaking havoc on your Quixote
+application (or the database underlying it).
+
+
+Session persistence
+-------------------
+
+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.
+
+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.
+
+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.
+
+The second hook (two hooks, really) apply if you use a transactional
+persistence mechanism to provide your SessionManager's mapping. The
+``altdemo.py`` 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: ``forget_changes()`` and
+``commit_changes()``. ``forget_changes()`` is called by
+SessionPublisher whenever a request crashes, ie. whenever your
+application raises an exception other than PublishError.
+``commit_changes()`` 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.
+
+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::
+
+ import shelve
+ sessions = shelve.open("/tmp/quixote-sessions")
+ session_manager = SessionManager(session_mapping=sessions)
+
+If you use one of these relatively simple persistent mapping types,
+you'll also need to override ``is_dirty()`` in your Session class.
+That's in addition to overriding ``has_info()``, which determines if a
+session object is *ever* saved; ``is_dirty()`` is only called on
+sessions that have already been added to the session mapping, to see
+if they need to be "re-added". 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, ``is_dirty()`` 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
+``has_info()`` will work -- that just means that once the session has
+been written once, it will be re-written on every request.
+
+
diff --git a/pypers/europython05/Quixote-2.0/doc/static-files.txt b/pypers/europython05/Quixote-2.0/doc/static-files.txt
new file mode 100755
index 0000000..64254f4
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/static-files.txt
@@ -0,0 +1,51 @@
+Examples of serving static files
+================================
+
+The ``quixote.util`` module includes classes for making files and
+directories available as Quixote resources. Here are some examples.
+
+
+Publishing a Single File
+------------------------
+
+The ``StaticFile`` 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 ``mimetypes.guess_type()`` function.
+The default action is to not follow symbolic links, but this behaviour
+can be changed using the ``follow_symlinks`` parameter.
+
+The following example publishes a file with the URL ``.../stylesheet_css``::
+
+ # 'stylesheet_css' must be in the _q_exports list
+ _q_exports = [ ..., 'stylesheet_css', ...]
+
+ stylesheet_css = StaticFile(
+ "/htdocs/legacy_app/stylesheet.css",
+ follow_symlinks=1, mime_type="text/css")
+
+
+If you want the URL of the file to have a ``.css`` extension, you use
+the external to internal name mapping feature of ``_q_exports``. For
+example::
+
+ _q_exports = [ ..., ('stylesheet.css', 'stylesheet_css'), ...]
+
+
+
+Publishing a Directory
+----------------------
+
+Publishing a directory is similar. The ``StaticDirectory`` class
+makes a complete filesystem directory available. Again, the default
+behaviour is to not follow symlinks. You can also request that the
+``StaticDirectory`` object cache information about the files in
+memory so that it doesn't try to guess the MIME type on every hit.
+
+This example publishes the ``notes/`` directory::
+
+ _q_exports = [ ..., 'notes', ...]
+
+ notes = StaticDirectory("/htdocs/legacy_app/notes")
+
+
diff --git a/pypers/europython05/Quixote-2.0/doc/upgrading.txt b/pypers/europython05/Quixote-2.0/doc/upgrading.txt
new file mode 100755
index 0000000..4d002cb
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/upgrading.txt
@@ -0,0 +1,324 @@
+Upgrading code from older versions of Quixote
+=============================================
+
+This document lists backward-incompatible changes in Quixote, and
+explains how to update application code to work with the newer
+version.
+
+Changes from 1.0 to 2.0
+-------------------------
+
+Change any imports you have from quixote.form to be from quixote.form1.
+
+Change any imports you have from quixote.form2 to be from quixote.form.
+
+Replace calls to HTTPRequest.get_form_var() with calls to get_field().
+
+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.
+
+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
+"request" parameters with "self" parameters on the new methods. If
+you have a _q_resolve method, include Resolving in the bases of your
+new class.
+
+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.
+
+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.
+
+In every namespace with a _q_exports and a _q_index, either add "" to
+_q_exports or make sure that _q_lookup handles "" by returning the result
+of a call to _q_index.
+
+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.
+
+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().
+
+If your code depended on _q_access, include the AccessControlled with
+the bases of your Directory classes as needed.
+
+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.
+
+Quixote 1's secure_errors configuration variable is not present in Quixote 2.
+
+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
+'**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'.
+
+The SessionPublisher class is gone. Use the Publisher class instead.
+Also, the 'session_mgr' keyword has been renamed to 'session_manager'.
+
+
+Changes from 0.6.1 to 1.0
+-------------------------
+
+Sessions
+********
+
+A leading underscore was removed from the ``Session`` attributes
+``__remote_address``, ``__creation_time``, and ``__access_time``. If
+you have pickled ``Session`` 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.
+
+
+
+Changes from 0.6 to 0.6.1
+-------------------------
+
+``_q_exception_handler`` now called if exception while traversing
+*****************************************************************
+
+``_q_exception_handler`` hooks will now be called if an exception is
+raised during the traversal process. Quixote 0.6 had a bug that caused
+``_q_exception_handler`` hooks to only be called if an exception was
+raised after the traversal completed.
+
+
+
+Changes from 0.5 to 0.6
+-----------------------
+
+``_q_getname`` renamed to ``_q_lookup``
+***************************************
+
+The ``_q_getname`` special function was renamed to ``_q_lookup``,
+because that name gives a clearer impression of the function's
+purpose. In 0.6, ``_q_getname`` still works but will trigger a
+warning.
+
+
+Form Framework Changes
+**********************
+
+The ``quixote.form.form`` module was changed from a .ptl file to a .py
+file. You should delete or move the existing ``quixote/`` directory
+in ``site-packages`` before running ``setup.py``, or at least delete
+the old ``form.ptl`` and ``form.ptlc`` files.
+
+The widget and form classes in the ``quixote.form`` package now return
+``htmltext`` instances. Applications that use forms and widgets will
+likely have to be changed to use the ``[html]`` template type to avoid
+over-escaping of HTML special characters.
+
+Also, the constructor arguments to ``SelectWidget`` and its subclasses have
+changed. This only affects applications that use the form framework
+located in the ``quixote.form`` package.
+
+In Quixote 0.5, the ``SelectWidget`` constructor had this signature::
+
+ def __init__ (self, name, value=None,
+ allowed_values=None,
+ descriptions=None,
+ size=None,
+ sort=0):
+
+``allowed_values`` was the list of objects that the user could choose,
+and ``descriptions`` was a list of strings that would actually be
+shown to the user in the generated HTML.
+
+In Quixote 0.6, the signature has changed slightly::
+
+ def __init__ (self, name, value=None,
+ allowed_values=None,
+ descriptions=None,
+ options=None,
+ size=None,
+ sort=0):
+
+The ``quote`` argument is gone, and the ``options`` argument has been
+added. If an ``options`` argument is provided, ``allowed_values``
+and ``descriptions`` must not be supplied.
+
+The ``options`` argument, if present, must be a list of tuples with
+1,2, or 3 elements, of the form ``(value:any, description:any,
+key:string)``.
+
+ * ``value`` is the object that will be returned if the user chooses
+ this item, and must always be supplied.
+
+ * ``description`` 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 '&' will be converted to '&amp;'.
+ htmltext instances will be left as they are.
+
+ * If supplied, ``key`` will be used in the value attribute
+ of the option element (``<option value="...">``).
+ If not supplied, keys will be generated; ``value`` is checked for a
+ ``_p_oid`` attribute and if present, that string is used;
+ otherwise the description is used.
+
+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.
+
+
+File Upload Changes
+*******************
+
+Quixote 0.6 introduces new support for HTTP upload requests. Any HTTP
+request with a Content-Type of "multipart/form-data" -- 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.
+
+Whenever an HTTP request has a Content-Type of "multipart/form-data",
+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.
+
+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:
+
+``orig_filename``
+ the filename supplied by the browser.
+``base_filename``
+ a stripped-down version of orig_filename with unsafe characters removed.
+ This could be used when writing uploaded data to a permanent location.
+``tmp_filename``
+ the path of the temporary file containing the uploaded data for this field.
+
+Consult upload.txt for more information about handling file uploads.
+
+
+Refactored `Publisher` Class
+****************************
+
+Various methods in the `Publisher` class were rearranged. If your
+application subclasses Publisher, you may need to change your code
+accordingly.
+
+ * ``parse_request()`` no longer creates the HTTPRequest object;
+ instead a new method, ``create_request()``, handles this,
+ and can be overridden as required.
+
+ As a result, the method signature has changed from
+ ``parse_request(stdin, env)`` to ``parse_request(request)``.
+
+ * The ``Publisher.publish()`` method now catches exceptions raised
+ by ``parse_request()``.
+
+
+Changes from 0.4 to 0.5
+-----------------------
+
+Session Management Changes
+**************************
+
+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.
+
+
+Attribute renamings and pickled objects
++++++++++++++++++++++++++++++++++++++++
+
+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::
+
+ 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
+
+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::
+
+ 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 "__" 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
+
+It's not pretty, but it worked for us.
+
+
+Cookie domains and paths
+++++++++++++++++++++++++
+
+The session cookie config variables -- ``COOKIE_NAME``,
+``COOKIE_DOMAIN``, and ``COOKIE_PATH`` -- have been renamed to
+``SESSION_COOKIE_*`` for clarity.
+
+If you previously set the config variable ``COOKIE_DOMAIN`` to the name
+of your server, this is most likely no longer necessary -- it's now fine
+to leave ``SESSION_COOKIE_DOMAIN`` unset (ie. ``None``), 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.
+
+If you previously set ``COOKIE_PATH``, then you should probably preserve
+your setting as ``SESSION_COOKIE_PATH``. The default of ``None`` 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.
+
+If you previously set ``COOKIE_NAME``, change it to
+``SESSION_COOKIE_NAME``.
+
+
+
+
diff --git a/pypers/europython05/Quixote-2.0/doc/web-server.txt b/pypers/europython05/Quixote-2.0/doc/web-server.txt
new file mode 100755
index 0000000..2abfe21
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/web-server.txt
@@ -0,0 +1,258 @@
+Web Server Configuration for Quixote
+====================================
+
+For a simple Quixote installation, there are two things you have to get
+right:
+
+* installation of the Quixote modules to Python's library (the
+ trick here is that the ``quixote`` package must be visible to the user
+ that CGI scripts run as, not necessarily to you as an interactive
+ command-line user)
+
+* configuration of your web server to run Quixote driver scripts
+
+This document is concerned with the second of these.
+
+
+Which web servers?
+------------------
+
+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 ``PATH_INFO``), then you can
+run Quixote applications in the ideal manner, ie. with superfluous
+implementation details hidden from the user.
+
+
+Which operating systems?
+------------------------
+
+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.
+
+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.
+
+
+Basic CGI configuration
+-----------------------
+
+Throughout this document, I'm going to assume that:
+
+* CGI scripts live in the ``/www/cgi-bin`` directory of your web server,
+ and have the extension ``.cgi``
+
+* HTTP requests for ``/cgi-bin/foo.cgi`` will result in the execution
+ of ``/www/cgi-bin/foo.cgi`` (for various values of ``foo``)
+
+* if the web server is instructed to serve an executable file
+ ``bar.cgi``, the file is treated as a CGI script
+
+With Apache, these configuration directives will do the trick::
+
+ AddHandler cgi-script .cgi
+ ScriptAlias /cgi-bin/ /www/cgi-bin/
+
+Consult the Apache documentation for other ways of configuring CGI
+script execution.
+
+For other web servers, consult your server's documentation.
+
+
+Installing driver scripts
+-------------------------
+
+Given the above configuration, installing a Quixote driver script is the
+same as installing any other CGI script: copy it to ``/www/cgi-bin`` (or
+whatever). To install the Quixote demo's cgi driver script::
+
+ cp -p server/cgi_server.py /www/cgi-bin/demo.cgi
+
+(The ``-p`` option ensures that ``cp`` preserves the file mode, so that
+it remains executable.)
+
+
+URL rewriting
+-------------
+
+With the above configuration, users need to use URLs like ::
+
+ http://www.example.com/cgi-bin/demo.cgi
+
+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.
+
+In our view, it's preferable to give each Quixote application its own
+chunk of URL-space -- a "virtual directory" if you like. For example,
+you might want ::
+
+ http://www.example.com/qdemo
+
+to handle the Quixote demo.
+
+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.)
+
+To enable the rewrite engine, use the ::
+
+ RewriteEngine on
+
+directive. If you have virtual hosts, make sure to repeat this for each
+``<VirtualHost>`` section of your config file.
+
+The rewrite rule to use in this case is ::
+
+ RewriteRule ^/qdemo(/.*) /www/cgi-bin/demo.cgi$1 [last]
+
+This is *not* a redirect; this is all handled with one HTTP
+request/response cycle, and the user never sees ``/cgi-bin/demo.cgi`` in
+a URL.
+
+Note that requests for ``/qdemo/`` and ``/qdemo`` are *not* 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:
+``/qdemo`` doesn't match the regex, so ``demo.cgi`` is never invoked.)
+
+The solution for ``/qdemo`` is the same as if it corresponded to a
+directory in your document tree: redirect it to ``/qdemo/``. Apache
+(and, presumably, other web servers) does this automatically for "real"
+directories; however, ``/qdemo/`` is just a directory-like chunk of
+URL-space, so either you or Quixote have to take care of the redirect.
+
+It's almost certainly faster for you to take care of it in the web
+server's configuration. With Apache, simply insert this directive
+*before* the above rewrite rule::
+
+ RewriteRule ^/qdemo$ /qdemo/ [redirect=permanent]
+
+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 ``/qdemo`` URL is handled by
+Quixote. Change the rewrite rule to::
+
+ RewriteRule ^/qdemo(/.*)?$ /www/cgi-bin/demo.cgi$1 [last]
+
+Now a request for ``/qdemo`` will be handled by Quixote, and it will
+generate a redirect to ``/qdemo/``. If you're using a CGI driver
+script, this will be painfully slow, but it will work.
+
+For redirecting and rewriting URLs with other web servers, consult your
+server's documentation.
+
+
+Long-running processes
+----------------------
+
+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.
+
+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.
+
+
+mod_scgi configuration
+----------------------
+
+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.
+
+The SCGI code is available from http://www.mems-exchange.org/software/scgi/ .
+
+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 ``run()``
+function with arguments to run your application, on the port
+you choose. Here is an example::
+
+ #!/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)
+
+The following Apache directive will direct requests to an SCGI server
+running on port 3001::
+
+ <Location />
+ SCGIServer 127.0.0.1 3001
+ SCGIHandler On
+ </Location>
+
+[Note: the mod_scgi module for Apache 2 requires a colon, instead of a
+space, between the host and port on the SCGIServer line.]
+
+
+SCGI through CGI
+----------------
+
+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 ``-DPORT=3001`` (for example) to your compile command.
+
+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.
+
+
+FastCGI configuration
+---------------------
+
+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
+http://www.fastcgi.com/ for more information on FastCGI.)
+
+To use FastCGI with Apache, you'll need to download mod_fastcgi from
+http://www.fastcgi.com/ and add it to your Apache installation.
+
+Configuring a FastCGI driver script is best done after reading the fine
+documentation for mod_fastcgi at
+http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html
+
+However, if you just want to try it with the Quixote demo to see if it
+works, add this directive to your Apache configuration::
+
+ AddHandler fastcgi-script .fcgi
+
+and copy server/fastcgi_server.py to demo.fcgi. If you're using a URL
+rewrite to map requests for (eg.) ``/qdemo`` to
+``/www/cgi-bin/demo.cgi``, be sure to change the rewrite -- it should
+now point to ``/www/cgi-bin/demo.fcgi``.
+
+After the first access to ``demo.fcgi`` (or ``/qdemo/`` with the
+modified rewrite rule), the demo should be noticeably faster. You
+should also see a ``demo.fcgi`` process running if you do ``ps -le``
+(``ps -aux`` on BSD-ish systems, or maybe ``ps aux``). (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).
+
+
diff --git a/pypers/europython05/Quixote-2.0/doc/web-services.txt b/pypers/europython05/Quixote-2.0/doc/web-services.txt
new file mode 100755
index 0000000..c89125c
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/web-services.txt
@@ -0,0 +1,169 @@
+Implementing Web Services with Quixote
+======================================
+
+This document will show you how to implement Web services using
+Quixote.
+
+
+An XML-RPC Service
+------------------
+
+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
+http://www.pythonware.com/products/xmlrpc/, converts between Python's
+standard data types and the XML-RPC data types.
+
+============== =====================
+XML-RPC Type Python Type or Class
+-------------- ---------------------
+<int> int
+<double> float
+<string> string
+<array> list
+<struct> dict
+<boolean> xmlrpclib.Boolean
+<base64> xmlrpclib.Binary
+<dateTime> xmlrpclib.DateTime
+============== =====================
+
+
+Making XML-RPC Calls
+--------------------
+
+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. ::
+
+ >>> import xmlrpclib
+ >>> s = xmlrpclib.ServerProxy(
+ 'http://www.stuffeddog.com/speller/speller-rpc.cgi')
+
+Now you can simply make a call to the spell-checking service offered
+by this server::
+
+ >>> 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}]
+ >>>
+
+This call results in the following XML being sent::
+
+ <?xml version='1.0'?>
+ <methodCall>
+ <methodName>speller.spellCheck</methodName>
+ <params>
+ <param>
+ <value><string>my speling isnt gud</string></value>
+ </param>
+ <param>
+ <value><struct></struct></value>
+ </param>
+ </params>
+ </methodCall>
+
+
+Writing a Quixote Service
+-------------------------
+
+In the quixote.util module, Quixote provides a function,
+``xmlrpc(request, func)``, that processes the body of an XML-RPC
+request. ``request`` is the HTTPRequest object that Quixote passes to
+every function it invokes. ``func`` 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 ``xmlrpc()`` function will
+catch the exception and return a ``Fault`` to the remote caller.
+
+Here's an example of implementing a simple XML-RPC handler with a
+single method, ``get_time()``, that simply returns the current
+time. The first task is to expose a URL for accessing the service. ::
+
+ 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):
+ ...
+
+When the above code is placed in the __init__.py file for the Python
+package corresponding to your Quixote application, it exposes the URL
+``http://<hostname>/rpc`` as the access point for the XML-RPC service.
+
+Next, we need to fill in the contents of the ``rpc_process()``
+function::
+
+ 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, "Unknown XML-RPC method: %r" % meth
+
+``rpc_process()`` 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 ``rpc_process()`` will
+therefore usually be an ``if`` statement that checks the name of the
+method, and calls another function to do the actual work. In this case,
+``get_time()`` is very simple so the two lines of code it requires are
+simply included in the body of ``rpc_process()``.
+
+If the method name doesn't belong to a supported method, execution
+will fall through to the ``else`` clause, which will raise a
+RuntimeError exception. Quixote's ``xmlrpc()`` will catch this
+exception and report it to the caller as an XML-RPC fault, with the
+error code set to 1.
+
+As you add additional XML-RPC services, the ``if`` statement in
+``rpc_process()`` will grow more branches. You might be tempted to pass
+the method name to ``getattr()`` 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 ``if... elif... elif... else`` 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.
+
+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::
+
+ 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, "Unknown XML-RPC method: %r" % meth
+
+This approach works nicely when there are many methods and the
+``if...elif...else`` statement would be unworkably long.
+
+
+$Id: web-services.txt 25695 2004-11-30 20:53:44Z dbinger $
diff --git a/pypers/europython05/Quixote-2.0/doc/widgets.txt b/pypers/europython05/Quixote-2.0/doc/widgets.txt
new file mode 100755
index 0000000..0dc3597
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/widgets.txt
@@ -0,0 +1,524 @@
+Quixote Widget Classes
+======================
+
+[This is reference documentation. If you haven't yet read "Lesson 5:
+widgets" 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 *HTML: The Definitive
+Guide* by Chuck Musciano & Bill Kennedy (O'Reilly). I usually keep it
+within arm's reach.]
+
+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::
+
+ 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
+
+
+Widget: the base class
+----------------------
+
+Widget is the abstract base class for the widget hierarchy. It provides
+the following facilities:
+
+* widget name (``name`` attribute, ``set_name()`` method)
+* widget value (``value`` attribute, ``set_value()`` and ``clear()`` methods)
+* ``__str__()`` and ``__repr__()`` methods
+* some facilities for writing composite widget classes
+
+The Widget constructor signature is::
+
+ Widget(name : string, value : any = None)
+
+``name``
+ the name of the widget. For non-compound widgets (ie. everything in
+ the above class hierarchy), this will be used as the "name"
+ attribute for the main HTML tag that defines the form element.
+
+``value``
+ 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.
+
+
+Common widget methods
+---------------------
+
+The Widget base class also provides a couple of useful
+methods:
+
+``set_name(name:string)``
+ 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.
+
+``set_value(value:any)``
+ 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).
+
+``clear()``
+ clear the widget's current value. Equivalent to
+ ``widget.set_value(None)``.
+
+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:
+
+``render(request:HTTPRequest)`` : ``string``
+ return a chunk of HTML that implements the form element
+ corresponding to this widget.
+
+``parse(request:HTTPRequest)`` : ``any``
+ extract the form value for this widget from ``request.form``, 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 ``set_value()``.
+
+
+StringWidget
+------------
+
+Used for short, single-line string input with no validation (ie. any
+string will be accepted.) Generates an ``<input type="text">`` form
+element.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ StringWidget(name : string,
+ value : string = None,
+ size : int = None,
+ maxlength : int = None)
+
+``size``
+ used as the ``size`` attribute of the generated ``<input>`` tag;
+ controls the physical size of the input field.
+
+``maxlength``
+ used as the ``maxlength`` attribute; controls the maximum amount
+ of input.
+
+Examples
+~~~~~~~~
+::
+
+ >>> StringWidget("foo", value="hello").render(request)
+ '<input name="foo" type="text" value="hello">'
+
+ >>> StringWidget("foo", size=10, maxlength=20).render(request)
+ '<input name="foo" type="text" size="10" maxlength="20">'
+
+
+PasswordWidget
+--------------
+
+PasswordWidget is identical to StringWidget except for the type of the
+HTML form element: ``password`` instead of ``text``.
+
+
+TextWidget
+----------
+
+Used for multi-line text input. The value is a single string with
+newlines right where the browser supplied them. (``\r\n``, if present,
+is converted to ``\n``.) Generates a ``<textarea>`` form element.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ TextWidget(name : string,
+ value : string = None,
+ cols : int = None,
+ rows : int = None,
+ wrap : string = "physical")
+
+``cols``, ``rows``
+ number of columns/rows in the textarea
+``wrap``
+ controls how the browser wraps text and includes newlines in the
+ submitted form value; consult an HTML book for details.
+
+
+CheckboxWidget
+--------------
+
+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 ``parse()`` will always be 0 or 1 (but you shouldn't
+rely on that!). Generates an ``<input type="checkbox">`` form element.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ CheckboxWidget(name : string,
+ value : boolean = false)
+
+Examples
+~~~~~~~~
+::
+
+ >>> CheckboxWidget("foo", value=0).render(request)
+ '<input name="foo" type="checkbox" value="yes">'
+
+ >>> CheckboxWidget("foo", value="you bet").render(request)
+ '<input name="foo" type="checkbox" value="yes" checked>'
+
+
+RadiobuttonsWidget
+------------------
+
+Used for a *set* of related radiobuttons, ie. several ``<input
+type="radio">`` tags with the same name and different values. The set
+of values are supplied to the constructor as ``allowed_values``, which
+may be a list of any Python objects (not just strings). The current
+value must be either ``None`` (the default) or one of the values in
+``allowed_values``; if you supply a ``value`` not in ``allowed_values``,
+it will be ignored. ``parse()`` will return either ``None`` or one of
+the values in ``allowed_values``.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ RadiobuttonsWidget(name : string,
+ value : any = None,
+ allowed_values : [any] = None,
+ descriptions : [string] = map(str, allowed_values),
+ quote : boolean = true,
+ delim : string = "\n")
+
+``allowed_values``
+ specifies how many ``<input type="radio">`` tags to generate and the
+ values for each. Eg. ``allowed_values=["foo", "bar"]`` will result in
+ (roughly)::
+
+ <input type="radio" value="foo">
+ <input type="radio" value="bar">
+
+``descriptions``
+ the text that will actually be shown to the user in the web page
+ that includes this widget. Handy when the elements of
+ ``allowed_values`` are too terse, or don't have a meaningful
+ ``str()``, or you want to add some additional cues for the user. If
+ not supplied, ``map(str, allowed_values)`` is used, with the
+ exception that ``None`` in ``allowed_values`` becomes ``""`` (the
+ empty string) in ``descriptions``. If supplied, ``descriptions``
+ must be the same length as ``allowed_values``.
+
+``quote``
+ if true (the default), the elements of 'descriptions' will be
+ HTML-quoted (using ``quixote.html.html_quote()``) when the widget is
+ rendered. This is essential if you might have characters like
+ ``&`` or ``<`` in your descriptions. However, you'll want to set
+ ``quote`` to false if you are deliberately including HTML markup
+ in your descriptions.
+
+``delim``
+ the delimiter to separate the radiobuttons with when rendering
+ the whole widget. The default ensures that your HTML is readable
+ (by putting each ``<input>`` tag on a separate line), and that there
+ is horizontal whitespace between each radiobutton.
+
+Examples
+~~~~~~~~
+::
+
+ >>> colours = ["red", "green", "blue", "pink"]
+ >>> widget = RadiobuttonsWidget("foo", allowed_values=colours)
+ >>> print widget.render(request)
+ <input name="foo" type="radio" value="0">red</input>
+ <input name="foo" type="radio" value="1">green</input>
+ <input name="foo" type="radio" value="2">blue</input>
+ <input name="foo" type="radio" value="3">pink</input>
+
+(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 ``"1"`` to ``1`` and looking up ``allowed_values[1]``.)
+
+::
+
+ >>> values = [val1, val2, val3]
+ >>> descs = ["thing <b>1</b>",
+ "thing <b>2</b>",
+ "thing <b>3</b>"]
+ >>> widget = RadiobuttonsWidget("bar",
+ allowed_values=values,
+ descriptions=descs,
+ value=val3,
+ delim="<br>\n",
+ quote=0)
+ >>> print widget.render(request)
+ <input name="bar" type="radio" value="0">thing <b>1</b></input><br>
+ <input name="bar" type="radio" value="1">thing <b>2</b></input><br>
+ <input name="bar" type="radio" value="2" checked="checked">thing <b>3</b></input>
+
+
+SingleSelectWidget
+------------------
+
+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; ``parse()`` will return either
+``None`` or one of the values you supply to the constructor as
+``allowed_values``. Generates a ``<select>...</select>`` tag, with one
+``<option>`` tag for each element of ``allowed_values``.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ SingleSelectWidget(name : string,
+ value : any = None,
+ allowed_values : [any] = None,
+ descriptions : [string] = map(str, allowed_values),
+ quote : boolean = true,
+ size : int = None)
+
+``allowed_values``
+ determines the set of ``<option>`` tags that will go inside the
+ ``<select>`` tag; these can be any Python values (not just strings).
+ ``parse()`` will return either one of the ``allowed_values`` or ``None``.
+ If you supply a ``value`` that is not in ``allowed_values``, it
+ will be ignored.
+
+``descriptions``
+ (same as RadiobuttonsWidget above)
+
+``quote``
+ (same as RadiobuttonsWidget above)
+
+``size``
+ corresponds to the ``size`` attribute of the ``<select>`` tag: ask
+ the browser to show a select list with ``size`` items visible.
+ Not always respected by the browser; consult an HTML book.
+
+Examples
+~~~~~~~~
+::
+
+ >>> widget = SingleSelectWidget("foo",
+ allowed_values=["abc", 123, 5.5])
+ >>> print widget.render(request)
+ <select name="foo">
+ <option value="0">abc
+ <option value="1">123
+ <option value="2">5.5
+ </select>
+
+ >>> widget = SingleSelectWidget("bar",
+ value=val2,
+ allowed_values=[val1, val2, val3],
+ descriptions=["foo", "bar", "foo & bar"],
+ size=3)
+ >>> print widget.render(request)
+ <select name="bar" size="3">
+ <option value="0">foo
+ <option selected value="1">bar
+ <option value="2">foo &amp; bar
+ </select>
+
+
+MultipleSelectWidget
+--------------------
+
+Used to select multiple values from a list. Everything is just like
+SingleSelectWidget, except that ``value`` can be a list of objects
+selected from ``allowed_values`` (in which case every object in ``value``
+will initially be selected). Generates a ``<select multiple>...</select>``
+tag, with one ``<option>`` tag for each element of ``allowed_values``.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ MultipleSelectWidget(name : string,
+ value : any | [any] = None,
+ allowed_values : [any] = None,
+ descriptions : [string] = map(str, allowed_values),
+ quote : boolean = true,
+ size : int = None)
+
+
+SubmitButtonWidget
+------------------
+
+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.
+
+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.
+
+Also, SubmitButtonWidget is the only widget with an optional ``name``.
+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.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ SubmitButtonWidget(name : string = None,
+ value : string = None)
+
+``value``
+ the text that will be shown in the user's browser, *and* the
+ value that will be returned for this form element (widget)
+ if the user selects this submit button.
+
+Examples
+~~~~~~~~
+
+ >>> SubmitButtonWidget(value="Submit Form").render(request)
+ '<input type="submit" value="Submit Form">'
+
+
+HiddenWidget
+------------
+
+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 "sensitive" I mean "information
+which should not be revealed", rather than "security-related". If you
+wouldn't put it in a cookie or in email, don't put it in a hidden form
+element.)
+
+Constructor
+~~~~~~~~~~~
+::
+
+ HiddenWidget(name : string,
+ value : string)
+
+Examples
+~~~~~~~~
+::
+
+ >>> HiddenWidget("form_id", "2452345135").render(request)
+ '<input type="hidden" name="form_id" value="2452345135">'
+
+
+IntWidget
+---------
+
+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 ``int()`` can't convert to an integer,
+IntWidget's ``parse()`` 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.
+
+``IntWidget.parse()`` always returns an integer or ``None``.
+
+Constructor
+~~~~~~~~~~~
+::
+
+ IntWidget(name : string,
+ value : int = None,
+ size : int = None,
+ maxlength : int = None)
+
+Constructor arguments are as for StringWidget, except that ``value``
+must be an integer (or ``None``). Note that ``size`` and
+``maxlength`` have exactly the same meaning: they control the size of
+the input widget and the maximum number of characters of input.
+
+[Examples]
+
+ >>> IntWidget("num", value=37, size=5).render(request)
+ '<input type="string" name="num" value="37" size="5">'
+
+
+FloatWidget
+-----------
+
+FloatWidget is identical to IntWidget, except:
+
+* ``value`` must be a float
+* ``parse()`` returns a float or ``None``
+* ``parse()`` raises FormValueError if the string entered by the
+ user cannot be converted by Python's built-in ``float()`` function
+
+
+OptionSelectWidget
+------------------
+
+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.)
+
+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 "Canada",
+you'll ask them for a province and a postal code; if they select "United
+States", 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 ["How many states does Australia
+have again?"], and you're bound to get something wrong -- there are over
+200 countries in the world, after all.)
+
+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 ``submit``,
+since that masks the Javascript function called by OptionSelectWidget.
+
+
+$Id: widgets.txt 20217 2003-01-16 20:51:53Z akuchlin $
diff --git a/pypers/europython05/Quixote-2.0/doc/win32.txt b/pypers/europython05/Quixote-2.0/doc/win32.txt
new file mode 100755
index 0000000..9204f10
--- /dev/null
+++ b/pypers/europython05/Quixote-2.0/doc/win32.txt
@@ -0,0 +1,14 @@
+Compiling Quixote c extensions for Windows using the mingw compiler:
+
+The variable build_extensions in setup.py must be set to True (instead
+of "sys.platform != win32"). Then, Quixote can be installed through
+
+ python setup.py build_ext --compiler=mingw32 install
+
+The mingw compiler can be downloaded from
+http://www.bloodshed.net/dev/devcpp.html. Probably you need to list
+the bin directory (C:\Program files\Dev-Cpp\bin) in the PATH.
+
+To permit gcc to link against Python library, you also need a
+libpython2x.a file. Instructions for its creation are provided at
+http://sebsauvage.net/python/mingw.html.