home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / spyce / *.* / doc.spy < prev    next >
Encoding:
Text File  |  2004-05-18  |  182.3 KB  |  3,994 lines

  1. [[.compact]]
  2. [[.import names="include,stdout,transform,toc"]]
  3. [[ include.spyce('inc/head.spi', {'pagename': 'Documentation', 'page': 'doc.html'}) ]]
  4. [[.include file="inc/static.spi"]]
  5.  
  6. [[\
  7. import verchk, re, os, string, sys
  8. import spyceModule, spyce
  9.  
  10. def escapeHTMLandCode(html):
  11.   import re
  12.   html = re.sub(r'\<', '<', html)
  13.   html = re.sub(r'\>', '>', html)
  14.   html = re.sub(r'\[\+', '['*2, html)
  15.   html = re.sub(r'\+\]', ']'*2, html)
  16.   return html
  17.  
  18. # single and multipage
  19. sectionbegin = 1
  20. try:
  21.   singlepage  # does it exist?
  22.   multipage = 0
  23. except: multipage = 1
  24.  
  25. # table of contents functions
  26. def genTOClink(tag, multipage=multipage):
  27.   import os.path
  28.   if multipage:
  29.     filename = os.path.splitext(os.path.basename(request.filename()))[0]
  30.     if tag=='root': return "%s.html" % filename
  31.     else: return "%s-%s.html" % (filename, tag)
  32.   else: return '#%s' % tag
  33.  
  34. def getNumData(tag):
  35.   import string
  36.   data = None
  37.   num = ''
  38.   if tag:
  39.     data = str(toc.getData(tag))
  40.     num = toc.getNumbering(tag)
  41.     if num: num = string.join(map(str, num),'.')
  42.   return num, data
  43.  
  44. def getLink(tag, genTOClink=genTOClink, getNumData=getNumData):
  45.   num, data = getNumData(tag)
  46.   if tag:
  47.     if num: return '<a href="%s">%s - %s</a>' % (genTOClink(tag), num, data)
  48.     else: return '<a href="%s">%s</a>' % (genTOClink(tag), data)
  49.   else: return 'None'
  50.  
  51. def emitLocation(tag, getLink=getLink):
  52.   next = getLink(toc.getNextTag(tag))
  53.   prev = getLink(toc.getPrevTag(tag))
  54.   up = getLink(toc.getParentTag(tag))
  55.   print '''
  56. <table width="100%s" align=center><tr>
  57.     <td align=left width="33%s" nowrap><font face="arial, helvetica" size="-1"><b>Prev:</b> %s</font></td>
  58.     <td align=center width="33%s" nowrap><font face="arial, helvetica" size="-1"><b>Up:</b> %s</font></td>
  59.     <td align=right width="33%s" nowrap><font face="arial, helvetica" size="-1"><b>Next:</b> %s</font></td>
  60. </tr></table>''' % ('%', '%', prev, '%', up, '%', next)
  61.  
  62. def emitChildren(tag, getLink=getLink):
  63.   nodes = toc.getChildrenTags(tag)
  64.   if not nodes: return
  65.   links = map(getLink, nodes)
  66.   print '<p>'
  67.   print '<b>Sub-sections:</b>'
  68.   print '<ul>'
  69.   for l in links:
  70.     print '<li>%s</li>' % l
  71.   print '</ul>'
  72.  
  73. def emitHeader(tag, emitLocation=emitLocation, genTOClink=genTOClink):
  74.   tag2 = toc.getTag()
  75.   pagename, page = 'Documentation', 'doc.html'
  76.   while tag2:
  77.     titles = {
  78.       'intro': ('Introduction', 'intro'),
  79.       'lang': ('Language', 'lang'),
  80.       'runtime': ('Runtime', 'runtime'),
  81.       'mod': ('Modules', 'mod'),
  82.       'tag': ('Tags', 'tag'),
  83.       'conf': ('Install', 'conf'),
  84.       'add_perf': ('Performance', None),
  85.       'add_history': ('History', None),
  86.       'add_related': ('Related', None),
  87.     }
  88.     if titles.has_key(tag2):
  89.       pagename = pagename+' - '+titles[tag2][0]
  90.       if titles[tag2][1]:
  91.         page = 'doc-'+titles[tag2][1]+'.html'
  92.       break
  93.     tag2 = toc.getParentTag(tag2)
  94.   context = {
  95.     'pagename': pagename, 
  96.     'page': page,
  97.     'nexturl': genTOClink(toc.getNextTag(tag)),
  98.     'prevurl': genTOClink(toc.getPrevTag(tag)),
  99.     'contentsurl': 'doc.html',
  100.   }
  101.   include.spyce('inc/head.spi', context)
  102.   emitLocation(tag)
  103.   print '<hr>'
  104.  
  105. def emitFooter(tag, emitLocation=emitLocation, emitChildren=emitChildren):
  106.   print '<hr>'
  107.   emitLocation(tag)
  108.   emitChildren(tag)
  109.   include.spyce('inc/tail.spi')
  110.  
  111.  
  112. def toc_tocPush(depth, tag, numbering, data):
  113.   print '<ul>\n'
  114.  
  115. def toc_tocPop(depth, tag, numbering, data):
  116.   print '</ul>\n'
  117.  
  118. def toc_tocStart(depth, tag, numbering, data, genTOClink=genTOClink):
  119.   if depth==1:
  120.     print '<li>%s <a href="%s">%s</a></li>\n' % (
  121.       reduce(lambda s, i: '%s%d.' % (s, i), numbering, ''),
  122.       genTOClink(tag),
  123.       data)
  124.   if depth==2:
  125.     print '<li>%s <a href="%s">%s</a></li>\n' % (
  126.       reduce(lambda s, i: '%s%d.' % (s, i), numbering, ''),
  127.       genTOClink(tag),
  128.       data)
  129.   if depth==3:
  130.     print '<li>%s <a href="%s">%s</a></li>\n' % (
  131.       reduce(lambda s, i: '%s%d.' % (s, i), numbering, ''),
  132.       genTOClink(tag),
  133.       data)
  134.  
  135. def toc_docStart(depth, tag, numbering, data, multipage=multipage, genTOClink=genTOClink, emitHeader=emitHeader):
  136.   import string
  137.   if multipage:
  138.     stdout.push(genTOClink(tag))
  139.     emitHeader(tag)
  140.   if depth==1:
  141.     print '<p><big><a name="%s"></a><b>%s <font color=#ee0000>%s</font></b></big><p>\n' % (
  142.       tag,
  143.       reduce(lambda s, i: '%s%d.' % (s, i), numbering, ''),
  144.       string.upper(data))
  145.   if depth==2:
  146.     print '<big><a name="%s"></a><b>%s <font color=#ee0000>%s</font></b></big><p>\n' % (
  147.       tag,
  148.       reduce(lambda s, i: '%s%d.' % (s, i), numbering, ''),
  149.       data)
  150.   if depth==3:
  151.     print '<big><a name="%s"></a><b>%s <font color=#ee0000><i>%s</i></font></b></big><p>\n' % (
  152.       tag,
  153.       reduce(lambda s, i: '%s%d.' % (s, i), numbering, ''),
  154.       data)
  155.  
  156. def toc_docEnd(depth, tag, numbering, data, multipage=multipage, emitFooter=emitFooter):
  157.   if multipage:
  158.     emitFooter(tag)
  159.     stdout.pop()
  160.  
  161. toc.setTOC_PUSH(toc_tocPush)
  162. toc.setTOC_POP(toc_tocPop)
  163. toc.setTOC_ENTRY(toc_tocStart)
  164. toc.setDOC_START(toc_docStart)
  165. toc.setDOC_END(toc_docEnd)
  166. ]]
  167.  
  168.  
  169. [[toc.anchor("Table of Contents")]]
  170.  
  171. <center>
  172.   <big><b>Spyce - Python Server Pages (PSP) <br>
  173.     <big>User Documentation</big></b></big><p>
  174.   <b>Rimon Barr</b><p>
  175.   Release [[=spyce.__version__]]<p>
  176. </center>
  177.  
  178. <center><b>
  179. [[ if multipage: { ]]
  180.   [ <a href="doc-single.html">Single-Page Format</a> ]
  181. [[ } else: { ]]
  182.   [ <a href="doc.html">Multi-Page Format</a> ]
  183. [[ } ]]
  184. </b></center>
  185. <p>
  186.  
  187. <font color="#ee0000"><b>TABLE OF CONTENTS</b><br></font>
  188. [[toc.showTOC()]]
  189. [[\
  190. if not multipage:
  191.   print '<hr>'
  192. ]]
  193.  
  194. [[toc.b("Introduction", "intro")]]
  195.  
  196. This document aims to be the only necessary and authoritative source of
  197. information about spyce, usable as a comprehensive refence, a user guide and a
  198. tutorial all-in-one. It should be read at least once from end to end. <p>
  199.  
  200. [[ import spyce ]]
  201. [[=spyce.__doc__]]<p>
  202.  
  203. Like JSP, PHP, ASP and other similar HTML scripting languages it allows the
  204. generation of dynamic content via embedded programming logic, and does not
  205. attempt to provide an encompassing application framework. Just as JSP uses
  206. Java, PHP uses a Perl-like language and ASP most commonly uses Visual Basic,
  207. Spyce embeds Python. Its <a
  208.   href="[[=genTOClink('add_perf')]]">performance</a> is comparable to the
  209. other solutions in its class. <p>
  210.  
  211. [[toc.b("Rationale", "intro_rationale")]]
  212.  
  213. A natural question to ask is why one would choose Spyce, over JSP, ASP, PHP
  214. and a handful of other popular HTML scripting languages or technologies that
  215. perform a similar function. We compare Spyce with an array of exising tools
  216. (chosen for their interesting points of comparison, not <a
  217.   href="[[=genTOClink('add_related')]]">completeness</a>):
  218.  
  219. <ul>
  220.  
  221.   <li><i><b>Java Server Pages, JSP,</b></i> is a widely popular, effective and
  222.   well-supported solution based on Java Servlet technology. Spyce differs from
  223.   JSP in that it embeds Python code among the HTML, thus providing a number of
  224.   advantages over Java. First, Python is a high-level scripting language,
  225.   where rapid prototyping is syntactically easier to perform. Second, Python
  226.   is interpreted and latently typed, which can be advantageous for
  227.   prototyping, especially in avoiding unnecessary binary incompatibility of
  228.   classes for minor changes. Third, Spyce code is of first-order in the Spyce
  229.   language, unlike JSP, which allows you to create useful Spyce lambda
  230.   functions. And, lastly, creating new active tags and modules is simpler in
  231.   Spyce than in JSP. Like Java, Python is portable.</li> <p>
  232.  
  233.   <li><i><b>PHP</b></i> is another popular webserver module for dynamic
  234.   content generation. The PHP interpreter engine and the language itself were
  235.   explicitly designed for the task of dynamic HTML generation, while Python is
  236.   a general-purpose scripting language. Spyce borrows from the extensive
  237.   development effort in Python: since any Python library can be imported and
  238.   reused, Spyce does not need to rebuild many of the core function libraries
  239.   that have been implemented by the PHP project. Moreover, the use of Python
  240.   often simplifies integration of Spyce with existing system environments.
  241.   Spyce code is also first-order in the Spyce language and Spyce supports
  242.   active tags, unlike PHP. Lastly, Spyce is modular in its design, allowing
  243.   users to easily extend its base functinality with add-on modules. Spyce,
  244.   like PHP, can run entirely within the process space of a webserver or via
  245.   CGI (as well as other web server adapters), and has been benchmarked to be
  246.   competitive in <a href="[[=genTOClink('add_perf')]]">performance</a>. In
  247.   addition, the Spyce engine can be run from the command-line, which allows
  248.   Spyce to be used as an HTML preprocessor. </li> <p>
  249.  
  250.   <li><i><b>Active Server Pages, ASP,</b></i> is a Microsoft technology
  251.   popular with Microsoft Internet Information Server (IIS) users. The default
  252.   and most common language embedding is Visual Basic. Stated briefly, the
  253.   author strongly prefers the language design and syntax of Python over VB.
  254.   Secondly, ASP is not well-supported outside the IIS environment. Spyce can
  255.   currently run under mod_python (Apache), as well as under CGI and <a
  256.   href="http://www.fastcgi.com">FastCGI</a>, or as a proxy server, which is
  257.   supported in the majority of web server environments. Adapters have also
  258.   been written for Xitami, Coil, Cheetah -- other web servers and frameworks.
  259.   Lastly, Spyce is open-source, and free. </li> <p>
  260.  
  261.   <li><i><b>WebWare with Python Server Pages, PSP,</b></i> is a recent
  262.   Python-based open-source development. PSP is similar in design to the Spyce
  263.   language, and shares many of the same benefits. However, Spyce supports both
  264.   Python chunks (indented Python) as well as PSP-style statements (braced
  265.   Python). Spyce code is also first-order in the Spyce language, as discussed
  266.   above, and supports active tags, unlike PSP. PSP is also an integral part of
  267.   WebWare, an application-server framework similar to Tomcat Java-based
  268.   application server of the Apache Jakarta project. Spyce is to WebWare as JSP
  269.   is to Tomcat. Spyce is far simpler to install and run than WebWare (in the
  270.   author's humble opinion), and does not involve notions such as application
  271.   contexts. It aims to do only one thing well: provide a preprocessor and
  272.   runtime engine for the dynamic generation of HTML using embedded Python.
  273.   </li> <p>
  274.  
  275.   <li><i><b>Zope</b></i> is an object-oriented open-source application server,
  276.   specializing in "content management, portals, and custom applications." It
  277.   is more mature than WebWare, but also attacks a much larger problem than
  278.   Spyce. Zope provides a scripting language called DHTML and can call
  279.   extensions written in Perl or Python. Spyce embeds Python directly in the
  280.   HTML, and only Python. It is an HTML-embedded language, not an application
  281.   server. </li> <p>
  282.  
  283. </ul>
  284.  
  285. In summary, the most popular of these solutions seem to be the solutions (JSP,
  286. PHP and ASP) that focus on the smaller problem of embedding a language within
  287. HTML. Spyce embeds Python in HTML, and no more. Many users have said that this
  288. is "exactly what they have been waiting for". Hopefully, this is the correct
  289. point in the design space for your project as well. You really just have to
  290. try it and see whether it suits your needs. <p>
  291.  
  292. [[toc.n('Design Goals', 'intro_design')]]
  293.  
  294. As a Spyce user, it helps to understand the broad design goals of this tool.
  295. Spyce is designed to be:
  296.  
  297. <ul>
  298.   
  299.   <li><b>Feature poor:</b> The philosophy behind the design of Spyce is only
  300.   to include features that particularly enhance its functionality over the
  301.   wealth that is already available from within Python. One can readily import
  302.   and use Python modules for many functions, and there is no need to recode
  303.   large bodies of functionality. </li> <p>
  304.  
  305.   <li><b>Small:</b> There is an active push keep Spyce small, especially the
  306.   core engine. The engine currently stands at 5000 lines of code -- tiny
  307.   compared to PHP or Zope, etc. The standard modules comprise another
  308.   2000 lines. </li> <p>
  309.  
  310.   <li><b>Modular:</b> Spyce is built to be extended with Spyce modules and
  311.   active tags that provide additional functionality over the core engine
  312.   capabilities and standard Python modules. New features in the core engine
  313.   and language are rationalised against the option of creating a new module or
  314.   a new tag library. Standard Spyce modules and tag libraries are those that
  315.   are considered useful in a general setting and are included in the default
  316.   Spyce distribution. Users and third-parties are encouraged to develop their
  317.   own Spyce modules. </li> <p>
  318.  
  319.   <li><b>Intuitive:</b> Obey user expectations. </li> <p>
  320.  
  321.   <li><b>Convenient:</b> Using Spyce should be made as efficient as possible.
  322.   This, for example, is the reason behind the choice of <font
  323.     face=courier>\[[</font> as delimeters over alternatives such as <font
  324.     face=courier><?</font> (php) and <font face=courier><%</font> (jsp).
  325.   Note that ASP/JSP-style delimeters are supported as well! Functions and
  326.   modules are also designed with as many defaults as possible.
  327.   </li> <p>
  328.  
  329.   <li><b>Single-purpose:</b> To be the best, most versatile, wildly-popular
  330.   Python-based dynamic HTML engine. Nothing more; nothing less. </li> <p>
  331.  
  332.   <li><b>Fast:</b> <a href="[[=genTOClink('add_perf')]]">Performance</a> is
  333.   important. It is expected that Spyce will perform comparably with any other
  334.   dynamic, scripting solutions available. Of paramount importance, however, is
  335.   clean design and syntax, and high degree of modularity and usability. The
  336.   philosophy is to build and tweak only when necessary and only for
  337.   significant performance gains, tested empirically.</li> <p>
  338.  
  339. </ul> <p>
  340.  
  341. Now, let's start using Spyce... <p>
  342.  
  343. [[toc.n('Getting Started', 'intro_started')]]
  344.  
  345. After <a href="[[=genTOClink('conf')]]">installing</a> Spyce, you are ready to
  346. write your first Spyce page. Start by editing a file called <b>hello.spy</b>
  347. in some web-published directory (a directory served by your webserver, and
  348. where <b>.spy</b> files will be handled correctly). Enter the following Spyce
  349. code:<p>
  350.  
  351. [[includeCode('examples/hello.spy') ]]<p>
  352.  
  353. <b>Note:</b> This manual assumes a knowledge of Python and focusses
  354. exclusively on Spyce. If you do not already know Python, it is easiest to
  355. learn via this short <a
  356.   href="http://www.python.org/doc/current/tut/tut.html">tutorial</a>, and has
  357. extensive <a href="http://www.python.org/doc/current/">documentation</a>.<p>
  358.  
  359. Save the file, and execute: <p>
  360.  
  361. <table border=0 align=center><tr><td>
  362. <font face=courier>
  363.   <pre>spyce hello.spy</pre>
  364. </font>
  365. </td></tr></table><p>
  366.  
  367. The output should be:<p>
  368.  
  369. [[.compact mode=off]]
  370. <table border=0 align=center><tr><td>
  371. <font face=courier>
  372. <b><pre>[[=escapeHTMLandCode('''
  373.   <html><body>
  374.     Hello world!
  375.       0  
  376.       1  
  377.       2  
  378.       3  
  379.       4  
  380.       5  
  381.       6  
  382.       7  
  383.       8  
  384.       9 
  385.   </body></html>''')]]</pre></b>
  386. </font>
  387. </td></tr></table><p>
  388. [[.compact]]
  389.  
  390. You might want to see this inside a browser! For this, you need a Spyce
  391. enabled web server. Spyce can integrate into a number of web environments, but
  392. the easiest for the purposes of "getting started" is the built-in Spyce web
  393. server. You can run it by typing:<p>
  394.  
  395. <table border=0 align=center><tr><td>
  396. <font face=courier>
  397.   <pre>spyce -l -p port root</pre>
  398. </font>
  399. </td></tr></table><p>
  400.  
  401. Replace <b>port</b> with some other port number, or omit the <b>-p</b> switch
  402. and assume the default, which is port 80. Replace <b>root</b> with the root
  403. document directory; the default is the current directory. All web requests are
  404. served relative to the server's root document directory. <p>
  405.  
  406. Windows users should note that there is no command called <font
  407. face=courier>spyce</font> installed on their system. They should execute,
  408. instead: <p>
  409.  
  410. <table border=0 align=center><tr><td>
  411. <font face=courier>
  412.   <pre>C:\python_directory\python.exe C:\spyce_directory\spyce.py ...</pre>
  413. </font>
  414. </td></tr></table><p>
  415.  
  416. Now, if you fire up your browser, and browse to:<p>
  417.  
  418. <table border=0 align=center><tr><td>
  419. <font face=courier>
  420.   <pre>http://your.domain:8080/some_path/hello.spy</pre>
  421. </font>
  422. </td></tr></table><p>
  423.  
  424. then you will see the file: <font face=courier>root/some_path/hello.spy</font>
  425. and the output should be:<p>
  426.  
  427. [[.compact mode=off]]
  428. <table border=0 align=center><tr><td>
  429. <font face=courier>
  430. <b><pre>
  431.   Hello world! 0  1  2  3  4  5  6  7  8  9
  432. </pre></b>
  433. </font>
  434. </td></tr></table><p>
  435. [[.compact]]
  436.  
  437. If you are curious, you can see the Python source code of the compiled Spyce
  438. script. It sometimes helps to understand the transformation that is taking
  439. place. Execute: <p>
  440.  
  441. <table border=0 align=center><tr><td>
  442. <font face=courier>
  443.   <pre>spyce -c hello.spy</pre>
  444. </font>
  445. </td></tr></table><p>
  446.  
  447. That's all folks! You have just written your first Spyce script. Having
  448. performed the obligatory <font face=courier>Hello world!</font> ritual, we now
  449. describe the Spyce language more systematically. <p>
  450.  
  451. [[toc.e()]]
  452.  
  453. [[toc.n('Language', 'lang')]]
  454.  
  455. The basic structure of a Spyce script is an HTML file with embeddings. There
  456. are six types of possible embeddings among the plain HTML text: 
  457.  
  458. <ul>
  459.   <li><font face=courier><b><</b><a href="[[=genTOClink('lang_string')]]">taglib:name</a> attr1=val1 ...<b>></b></font></li>
  460.   <li><font face=courier><b>\[[--</b> <a href="[[=genTOClink('lang_comment')]]">Spyce comment</a>      <b>--\]]</b></font></li>
  461.   <li><font face=courier><b>\[[.</b>  <a href="[[=genTOClink('lang_directive')]]">Spyce directive</a>      <b>\]]</b></font></li>
  462.   <li><font face=courier><b>\[[</b>   <a href="[[=genTOClink('lang_stmt')]]">Python statement(s)</a>  <b>\]]</b></font></li>
  463.   <li><font face=courier><b>\[[\</b>  <a href="[[=genTOClink('lang_chunk')]]">Python chunk</a>         <b>\]]</b></font></li>
  464.   <li><font face=courier><b>\[[=</b>  <a href="[[=genTOClink('lang_expr')]]">Python expression</a>    <b>\]]</b></font></li>
  465. </ul>
  466.  
  467. The majority of HTML strings are written out to the browser, verbatim.
  468. However, the Spyce language also supports "active" HTML <i>tags</i> via <a
  469. href="[[=genTOClink('tag')]]">tag libraries</a>, in the sense that they can
  470. execute custom code. Spyce <i>comments</i> are elided. The Spyce
  471. <i>directives</i> affect the interpreter behaviour. Python <i>statements</i>
  472. and <i>chunks</i> are executed. Finally, Python <i>expressions</i> are
  473. evaluated and the result is emitted to the browser. Each Spyce tag type has a
  474. unique beginning delimeter, namely <font face=courier><b>\[[</b></font>, <font
  475. face=courier><b>\[[\</b></font>, <font face=courier><b>\[[=</b></font>, <font
  476. face=courier><b>\[[.</b></font> or <font face=courier><b>\[[--</b></font>. All
  477. tags end with <font face=courier><b>\]]</b></font>, except comment tags, which
  478. end with <font face=courier><b>--\]]</b></font>.<p>
  479.  
  480. Since 
  481. <font face=courier><b>\[[</b></font> and
  482. <font face=courier><b>\]]</b></font>
  483. are special Spyce delimeters, one would escape them as
  484. <font face=courier><b>\\[[</b></font> and
  485. <font face=courier><b>\\]]</b></font> 
  486. for use in HTML text. They can not be escaped within Python code, but the
  487. string expressions
  488. <font face=courier><b>("["*2)</b></font> and
  489. <font face=courier><b>("]"*2)</b></font>, or equivalent expressions,
  490. can be used instead, or the brackets can be conveniently separated with a
  491. space in the case of list or slicing expressions. <p>
  492.  
  493. In addition, Spyce scripts are first-class members of the Spyce language: you
  494. can create a <a href="[[=genTOClink('lang_lambda')]]">Spyce <i>lambda</i></a>
  495. out of a Spyce string using the syntax below, in any of the Spyce Python
  496. elements (statements, chunks and expressions). A Spyce lambda can be invoked
  497. like a regular Python function, and its execution context (i.e. modules) is
  498. that of its caller. Spyce lambdas do not currently support nested variable
  499. scoping, nor default parameters, which Python users may be accustomed to.
  500.  
  501. <ul>
  502.  
  503.   <li><font face=courier><b>\[[spy</b> [parameters] <b>:</b> <a href="[[=genTOClink('lang_lambda')]]">spyce lambda code</a> <b>\]]</b></font></li>
  504.  
  505. </ul> <p>
  506.  
  507. Note that braces in "<font face=courier>[parameters]</font>" above indicate
  508. that a Spyce lambda may have zero or more parameters. Consider the parameter
  509. list of a Spyce lambda to be the same as the parameter list of a Python lambda
  510. definition. <p>
  511.  
  512. [[toc.b('Plain HTML and Active Tags', 'lang_string')]]
  513.  
  514. Static plain HTML strings are printed as they are encountered. Depending on
  515. the <a href="[[=genTOClink('lang_directive')]]">compacting</a> mode of the
  516. Spyce interpreter, some whitespace may be eliminated. The Spyce <a
  517. href="[[=genTOClink('mod_transform')]]">transform</a> module, for example, may
  518. further pre-processes this string, by inserting transformations into the
  519. output pipe. This is useful, for example, for dynamic compression of the
  520. script result. <p>
  521.  
  522. The Spyce language supports <a href="[[genTOClink('tag')]]">tag libraries</a>.
  523. Once a tag library is imported under some name, <i>mytags</i>, then all static
  524. HTML tags of the form <font
  525. face=courier><<i>mytags</i>:foo ... ></font> become "active".
  526. That is, code from the tag library is executed at that point in the document.
  527. Tags can control their output, conditionally skip or loop the execution of
  528. their bodies, and can interact with other active tags in the document. They
  529. are similar, in spirit and functionality, to JSP tags. Tag libraries and <a
  530. href="[[genTOClink('mod')]]">modules</a> (discussed later) can both
  531. considerably reduce the amount of code on a Spyce page, and increase code
  532. reuse and modularity. <p>
  533.  
  534. [[toc.n('Spyce Comments', 'lang_comment')]]
  535.  
  536. <b>Syntax: <font face=courier>\[[-- comment --\]]</font></b> <p>
  537.  
  538. Spyce comments are ignored, and do not produce any output, meaning that they
  539. will not appear at the browser even in the HTML source. The first line of a
  540. Spyce file, if it begins with the characters <b>#!</b>, is also considered a
  541. comment, by Unix scripting convention. Spyce comments do <i>not</i> nest. <p>
  542.  
  543. [[toc.n('Spyce Directives', 'lang_directive')]]
  544.  
  545. <b>Syntax: <font face=courier>\[[. directive \]]</font></b>
  546. <p>
  547.  
  548. Spyce directives directly affect the operation of the Spyce interpreter. There
  549. is a limited set of directives, listed and explained below:
  550.  
  551. <ul>
  552.   
  553.   <li><b><font face=courier>
  554.   \[[.<b>include</b> file=<i>file</i>\]] </font>:</b><br>
  555.  
  556.   Upon encountering this tag the Spyce compiler will insert the file
  557.   referenced, treating its contents as if it had been typed inline. Statically
  558.   included files are not checked for updates. Only an update to the primary
  559.   file will invalidate the cache. For dynamic includes, please refer to the <a
  560.   href="[[=genTOClink('mod_include')]]">include</a> module. Developers should
  561.   also consider creating custom Python or <a
  562.   href="[[=genTOClink('mod_new')]]">Spyce modules</a>, when the included file
  563.   is primarily code, since there is no need to involve the Spyce compiler to
  564.   convert primarily Python code to... Python code! </li> <p>
  565.  
  566.   <li><b><font face=courier>
  567.   \[[.<b>compact</b> mode=<i>mode</i>\]] </font>:</b><br>
  568.  
  569.   Spyce can output the static HTML strings in various modes of compaction,
  570.   which can both save bandwidth and improve download times without visibly
  571.   affecting the output. Compaction of static HTML strings is performed once
  572.   when the input Spyce file is compiled, and there is no additional run-time
  573.   overhead beyond that. Dynamically generated content from Python code tags
  574.   and expressions is not compacted nor altered in any way. Spyce can operate
  575.   in one of the compaction modes listed below. One can use the <b>compact</b>
  576.   tag to change the compaction mode from that point in the file forwards. <p>
  577.  
  578.   <ul>
  579.  
  580.     <li><b>off</b>: No compaction is performed. Every space and newline in the
  581.     static HTML strings is preserved. </li> <p>
  582.     
  583.     <li><b>space</b>: Space compaction involves reducing any consecutive runs
  584.     of spaces or tabs down to a single space. Any spaces or tabs at the
  585.     beginning of a line are eliminated. These transformations will not affect
  586.     HTML output, barring the <pre> tag, but can considerably reduce the
  587.     size of the emitted text. </li> <p>
  588.  
  589.     <li><b>line</b>: Line compaction eliminates any (invisible) trailing
  590.     whitespace at the end of lines. More significantly it improves the indented
  591.     presentation of HTML, by ignoring any lines that do not contain any static
  592.     text or expression tags. Namely, it removes all the whitespace, including
  593.     the line break, surrounding the code or directives on that line. This
  594.     compaction method usually "does the right thing", and produces nice HTML
  595.     without requiring tricky indentation tricks by the developer. It is,
  596.     therefore, the <b>initial</b> compaction mode. </li><p>
  597.  
  598.     <li><b>full</b>: Full compaction applies both space and line compaction. If
  599.     the optional mode attribute is omitted, full compaction mode is the
  600.     <b>default</b> value assumed. </li><p>
  601.  
  602.   </ul>
  603.   </li><p>
  604.  
  605.   <li><b><font face=courier> 
  606.   \[[.<b>import</b> name=<i>name</i> from=<i>file</i> as=<i>name</i> args=<i>arguments</i>\]] </font>:</b><br>
  607.  
  608.   The import directive loads and defines a Spyce module into the global
  609.   context. (The <font face=courier>\[[.module ... \]]</font>directive
  610.   is synonymous.) A Spyce <a href="[[=genTOClink('mod')]]">module</a> is a
  611.   Python file, written specifically to interact with Spyce. The <b>name</b>
  612.   parameter is required, specifying the name of the Python class to load. The
  613.   <b>file</b> parameter is optional, specifying the file where the named class
  614.   is to be found. If omitted, file will equal <font
  615.   face=courier><i>name</i>.py</font>. The file path can be absolute or
  616.   relative. Relative paths are scanned in the Spyce home, user-configurable <a
  617.   href="[[=genTOClink('runtime_common')]]">server path</a> directories and current
  618.   script directory, in that order. Users are encouraged to name or prefix their
  619.   modules uniquely so as not to be masked by system modules or tag libraries.
  620.   The <b>as</b> parameter is optional, and specifies the name under which the
  621.   module will be installed in the global context. If omitted, this parameter
  622.   defaults to the name parameter. Lastly, the optional <b>args</b> parameter
  623.   provides arguments to be passed to the module initialization function. All
  624.   Spyce modules are <b>start()</b>ed before Spyce processing begins,
  625.   <b>init()</b>ed at the point where the directive is placed in the code, and
  626.   <b>finish()</b>ed after Spyce processing terminates. It is convention to
  627.   place modules at, or near, the very top of the file unless the location of
  628.   initialization is relevant for the functioning of the specific module. <p>
  629.  
  630.   <b><font face=courier>
  631.   \[[.<b>import</b> names="<i>name1,name2,...</i>"\]] </font>:</b><br>
  632.  
  633.   An alternative syntax allows convenient loading of multiple Spyce modules.
  634.   One can not specify non-standard module file locations, nor rename the
  635.   modules using this syntax. </li><p>
  636.  
  637.   <li><b><font face=courier> 
  638.   \[[.<b>taglib</b> name=<i>name</i> from=<i>file</i> as=<i>name</i>\]] </font>:</b><br>
  639.  
  640.   The taglib directive loads a Spyce tag library. A Spyce <a
  641.   href="[[=genTOClink('tag')]]">tag library</a> is a Python file, written
  642.   specifically to interact with Spyce. The <b>name</b> parameter is required,
  643.   specifying the name of the Python class to load. The <b>file</b> parameter is
  644.   optional, specifying the file where the named class is to be found. If
  645.   omitted, file will equal <font face=courier><i>name</i>.py</font>. The file
  646.   path can be absolute or relative. Relative paths are scanned in the Spyce
  647.   home, user-configurable <a href="[[=genTOClink('runtime_common')]]">server
  648.   path</a> directories and current script directory, in that order. Users are
  649.   encouraged to name or prefix their tag libraries uniquely so as not to be
  650.   masked by system tag libraries and modules. The <b>as</b> parameter is
  651.   optional, and specifies the unique tag prefix that will be used to identify
  652.   the tags from this library. If omitted, this parameter defaults to the name
  653.   parameter. It is convention to place tag library directives at, or near, the
  654.   very top of the file. The tags only become active after the point of the tag
  655.   library directive. <p>
  656.   
  657.   <b><font face=courier>
  658.   \[[.<b>taglib</b> names="<i>name1,name2,...</i>"\]] </font>:</b><br>
  659.  
  660.   An alternative syntax allows convenient loading of multiple Spyce tag
  661.   libraries. One can not specify non-standard tag library locations, nor
  662.   specify a prefix of the tag libraries using this syntax. </li><p>
  663.  
  664. </ul> <p>
  665.  
  666. It is important to note that Spyce directives are processed at <i>compile</i>
  667. time, not during the execution of the script, much like directives in C, and
  668. other languages. In other words, they are processed as the Python code for the
  669. Spyce script is being produced, not as it is being executed. Consequently, it
  670. is not possible to include runtime values as parameters to the various
  671. directives.<p>
  672.  
  673. [[toc.n('Python Statements', 'lang_stmt')]]
  674.  
  675. <b>Syntax: <font face=courier>\[[ statement(s) \]]</font></b> <p>
  676.  
  677. The contents of a code tag is one or more Python statements. The statements
  678. are executed when the page is emitted. There will be no output unless the
  679. statements themselves generate output. <p>
  680.  
  681. The statements are separated with semi-colons or new lines, as in regular
  682. Python scripts. However, unlike regular Python code, Python statements <i>do
  683. <b>not</b> nest based on their level of indentation</i>. This is because
  684. indenting code properly in the middle of HTML is difficult on the developer.
  685. To alleviate this problem, Spyce supports a slightly modifed Python syntax:
  686. proper nesting of Spyce statements is achieved using begin- and end-braces:
  687. <font face=courier><b>{</b></font> and <font face=courier><b>}</b></font>,
  688. respectively. These <b>MUST</b> be used, because the compiler regenerates the
  689. correct indentation based on these markers alone. Even single-statement blocks
  690. of code must be wrapped with begin and end braces. (If you prefer to use
  691. Python-like indentation, read about <a
  692. href="[[=genTOClink('lang_chunk')]]">chunks</a>). <p>
  693.  
  694. The following Spyce code, from the <font face=courier>Hello World!</font>
  695. example above: <p>
  696.  
  697. [[.compact mode=off]]
  698. <table align=center border=0><tr><td>
  699. <font face=courier>
  700. <b><pre>
  701.   \[[ for i in range(10): <font color=red>{</font> \]]
  702.     \[[=i\]]
  703.   \[[ <font color=red>}</font> \]]
  704. </pre></b>
  705. </font>
  706. </td></tr></table>
  707. [[.compact]]<p>
  708.  
  709. produces the following indented Python code:<p>
  710.  
  711. [[.compact mode=off]]
  712. <table align=center border=0><tr><td>
  713. <font face=courier>
  714. <b><pre>
  715.   for i in range(10):
  716.     response.writeStatic('  ')
  717.     response.writeExpr(i)
  718.     response.writeStatic('\n')
  719. </pre></b>
  720. </font>
  721. </td></tr></table>
  722. [[.compact]]<p>
  723.  
  724. Without the braces, the code produced would be unindented and, in this case,
  725. also invalid: <p>
  726.  
  727. [[.compact mode=off]]
  728. <table align=center border=0><tr><td>
  729. <font face=courier>
  730. <b><pre>
  731.   for i in range(10):
  732.   response.writeStatic('  ')
  733.   response.writeExpr(i)
  734.   response.writeStatic('\n')
  735. </pre></b>
  736. </font>
  737. </td></tr></table>
  738. [[.compact]]<p>
  739.  
  740. Note how the indentation of the expression does not affect the indentation of
  741. the Python code that is produced; it merely changes the number of spaces in
  742. the <font face=courier>writeStatic</font> string. Also note that unbalanced
  743. open and close braces within a single tag are allowed, as in the example
  744. above, and they modify the indentation level outside the code tag. However,
  745. the braces must be balanced across an entire file. Remember: inside the <font
  746.   face=courier>\[[ ... \]]</font> delimiters, <b>braces are always
  747.   required</b> to change the indentation level. <p>
  748.  
  749. [[toc.n('Python Chunks', 'lang_chunk')]]
  750.  
  751. <b>Syntax: <font face=courier>\[[\ Python chunk \]]</font></b>
  752. <p>
  753.  
  754. There are many Python users that experience anguish, disgust or dismay upon
  755. reading the previous section: "Braces!? Give me real, indented Python!". These
  756. intendation zealots will be more comfortable using Python chunks, which is why
  757. Spyce supports them. Feel free to use Spyce statements or chunks
  758. inter-changeably, as the need arises.<p>
  759.  
  760. A Python chunk is straight Python code, and the <i>internal</i> indentation is
  761. preserved. The entire block is merely outdented (or indented) as a whole, such
  762. that the first non-empty line of the block matches the indentation level of
  763. the context into which the chunk was placed. Thus, a Python chunk can not
  764. affect the indentation level outside its scope, but internal indentation is
  765. fully respected, relative to the first line of code, and braces (<font
  766. face=courier>{</font>, <font face=courier>}</font>) are not required, nor
  767. expected for anything but Python dictionaries. Since the first line of code is
  768. used as an indentation reference, it is recommended that the start delimeter
  769. of the tag (i.e. the <font face=courier>\[[\</font>) be placed on its own
  770. line, above the code chunk, as shown in the following example: <p>
  771.  
  772. [[.compact mode=off]]
  773. <table align=center border=0><tr><td>
  774. <font face=courier>
  775. <b><pre>\[[\
  776.     def printHello(num):
  777.       for i in range(num):
  778.         response.write('hello<br>')
  779.  
  780.     printHello(5)
  781. \]]</pre></b>
  782. </font>
  783. </td></tr></table>
  784. [[.compact]]
  785. <p>
  786.  
  787. Naturally, one should <i>not</i> use braces here for purposes of indentation,
  788. only for Python dictionaries. Additional braces will merely generate Python
  789. syntax errors in the context of chunks. To recap: a Python statement tag
  790. should contain braced Python; A Python chunk tag should contain regular
  791. indented Python. <p>
  792.  
  793. [[toc.n('Python Expressions', 'lang_expr')]]
  794.  
  795. <b>Syntax: <font face=courier>\[[= expression \]]</font></b>
  796. <p>
  797.  
  798. The contents of an expression tag is a Python expression. The result of that
  799. expression evaluation is printed using the its string representation. The
  800. Spyce <a href="[[=genTOClink('mod_transform')]]">transform</a> module, can
  801. pre-processes this result, to assist with mundane tasks such as ensuring that
  802. the string is properly HTML-encoded, or formatted. <p>
  803.  
  804. [[toc.n('Spyce Lambdas', 'lang_lambda')]]
  805.  
  806. <b>Syntax: <font face=courier>\[[spy <i>[params]</i> : <i>spyce lambda code</i> \]]</font></b>
  807. <br>
  808. <b>or: <font face=courier>\[[spy! <i>[params]</i> : <i>spyce lambda code</i> \]]</font></b>
  809. <p>
  810.  
  811. A nice feature of Spyce is that Spyce scripts are first-class members of the
  812. language. In other words, you can create a Spyce lambda (or function) in any
  813. of the Spyce Python elements (statements, chunks and expressions). These can
  814. then be invoked like regular Python functions, stored in variables for later
  815. use, or be passed around as paramaters. This feature is often very useful for
  816. templating (example shown below), and can also be used to implement more
  817. esoteric processing functionality, such as internationalization, multi-modal
  818. component frameworks and other kinds of polymorphic renderers. <p>
  819.  
  820. It is instructive to understand how these functions are generated. The <font
  821. face="courier">\[[spy ... : ... \]]</font> syntax is first
  822. translated during compilation into a call to the define() function of the <a
  823. href="[[=genTOClink('mod_lambda')]]">spylambda</a> module. At runtime, this
  824. call compiles the Spyce code at the point of its definition, and returns a
  825. function. While the invocation of a Spyce lambda is reasonably efficient, it
  826. is certainly not as fast as a regular Python function invocation. The
  827. spycelambda can be memoized (explained in the <a
  828. href="[[=genTOClink('mod_lambda')]]">spylambda</a> module section) by using
  829. the <font face=courier>\[[spy! ... : ... \]]</font>
  830. syntax. However, even with this optimization one should take care to use
  831. Python lambdas and functions when the overhead of Spyce parsing and invocation
  832. is not needed. <p>
  833.  
  834. Note that Spyce lambdas do not currently support nested variable scoping, nor
  835. default parameters. The global execution context (specifically, Spyce modules)
  836. of the Spyce lambda is defined at the point of its execution. <p>
  837.  
  838. [[includeCode('examples/spylambda.spy') ]] <p> 
  839.  
  840. [[toc.n('ASP/JSP syntax', 'lang_asp') ]]
  841.  
  842. Finally, due to popular demand, because of current editor support and people
  843. who actually enjoy pains in their wrists, the Spyce engine will respect
  844. ASP/JSP-like delimeters. In other words, it will also recognize the following
  845. syntax:
  846.  
  847. <ul>
  848.   <li><font face=courier><b><%--</b> <a href="[[=genTOClink('lang_comment')]]">Spyce comment</a>      <b>--%></b></font></li>
  849.   <li><font face=courier><b><%@</b>  <a href="[[=genTOClink('lang_directive')]]">Spyce directive</a>      <b>%></b></font></li>
  850.   <li><font face=courier><b><%</b>   <a href="[[=genTOClink('lang_stmt')]]">Python statement(s)</a>  <b>%></b></font></li>
  851.   <li><font face=courier><b><%\</b>  <a href="[[=genTOClink('lang_chunk')]]">Python chunk</a>         <b>%></b></font></li>
  852.   <li><font face=courier><b><%=</b>  <a href="[[=genTOClink('lang_expr')]]">Python expression</a>    <b>%></b></font></li>
  853.   <li><font face=courier><b><%spy</b> [parameters] <b>:</b> <a href="[[=genTOClink('lang_lambda')]]">spyce lambda code</a> <b>%></b></font></li>
  854. </ul>
  855.  
  856. The two sets of delimeters may be used interchangeably within the same file,
  857. though this is not recommended.
  858.  
  859. [[toc.e()]]
  860.  
  861. [[toc.n('Runtime', 'runtime')]]
  862.  
  863. Having covered the Spyce language syntax, we now move to describing the
  864. runtime processing. Each time a request comes in, the cache of compiled Spyce
  865. files is checked for the compiled version of the requisite Spyce file. If one
  866. is not found, the Spyce file is quickly read, transformed, compiled and cached
  867. for future use. <p>
  868.  
  869. The compiled Spyce is initialized, then processed, then finalized. The
  870. initialization consists of initializing all the Spyce modules. The Spyce file
  871. is executed top-down, until the end is reached or an exception is thrown,
  872. whichever comes first. The finalization step then finalizes each module in
  873. reverse order of initialization, and any buffered output is automatically
  874. flushed. <p>
  875.  
  876. [[toc.b('Exceptions', 'runtime_except')]]
  877.  
  878. The Spyce file is executed top-down, until the end of the file is reached, a
  879. valued is <font face="courier">return</font>ed, or an exception is thrown,
  880. whichever comes first. If the code terminates via an unhandled exception, then
  881. it is caught by the Spyce engine. Depending on the exception type, different
  882. actions are taken:
  883.  
  884. <ul>
  885.  
  886.   <li><b>spyceDone</b> can be raised at any time to stop the Spyce processing
  887.   (without error) at that point. It is often used to stop further output, as
  888.   in the example below that emits a binary image file. The spyceDone
  889.   exception, however, is more useful for modules writers. In regular Spyce
  890.   code one could simply issue a <font face="courier">return</font> statement,
  891.   with the same effect. </li> <p>
  892.  
  893.   <li><b>spyceRedirect</b> is used by the <a
  894.   href="[[=genTOClink('mod_redirect')]]">redirect</a> module. It causes the
  895.   Spyce engine to immediately redirect the request to another Spyce file
  896.   <i>internally</i>. Internally means that we do not send back a redirect to
  897.   the browser, but merely clear the output buffer and start processing a new
  898.   script. </li> <p>
  899.  
  900.   <li><b>All other exceptions</b> that occur at runtime will be processed via
  901.   the Spyce <a href="[[=genTOClink('mod_error')]]">error</a> module. This
  902.   module will emit a default error message, unless the user has installed some
  903.   other error handler. </li> <p>
  904.  
  905. </ul><p>
  906.  
  907. Note that non-runtime exceptions, such as exceptions caused by compile errors,
  908. missing files, access restrictions and the like, are handled by the server.
  909. The default <a href="[[=genTOClink('runtime_common')]]">server error handler</a>
  910. can be configured via the server configuration file. <p>
  911.  
  912. [[includeCode('examples/gif.spy') ]]
  913. <p>
  914.  
  915. [[toc.n('Code Transformation', 'runtime_transform')]]
  916.  
  917. While the minutia of the code transformation that produces Python code from
  918. the Spyce sources is of no interest to the casual user, it has some slight,
  919. but important, ramifications on certain aspects of the Python language
  920. semantics when used inside a Spyce file. <p>
  921.  
  922. The result of the Spyce compilation is some Python code, wherein the majority
  923. of the Spyce code actually resides in a single function called
  924. <b>spyceProcess</b>. If you are curious to see the result of a Spyce
  925. compilation, execute: <font face=courier>"spyce -c".</font>  <p>
  926.  
  927. It follows from the compilation transformation that:
  928.  
  929. <ul>
  930.   
  931.   <li>Any functions defined within the Spyce file are actually nested
  932.   functions within the spyceProcess function. </li> <p>
  933.  
  934.   <li>The use of <b>global</b> variables within Spyce code is not supported,
  935.   but also not needed. If nested scoping is available (Python versions
  936.   >2.1) then these variables will simply be available. If not, then you
  937.   will need to pass variables into functions as default parameters, and will
  938.   not be able to update them by value (standard Python limitations). It is
  939.   good practice to store constants and other globals in a single class, or to
  940.   to place them in a single, included file, or both. </li> <p>
  941.   
  942.   <li><p>The global Spyce namespace is reserved for special variables, such as
  943.   Spyce and Python modules. While the use of the keyword <font
  944.     face=courier>global</font> is not explicitly checked, it will pollute this
  945.   space and may result in unexpected behaviour or runtime errors. </li> <p>
  946.  
  947.   <li>The lifetime of variables is the duration of a request. Variables with
  948.   lifetimes longer than a single request can be stored using the <a
  949.   href="[[=genTOClink('mod_pool')]]">pool</a> module. </li> <p>
  950.  
  951. </ul> <p>
  952.  
  953. [[toc.n('Dynamic Content', 'runtime_web')]]
  954.  
  955. The most common use of Spyce is to serve dynamic HTML content, but it should
  956. be noted that Spyce can be used as a general purpose text engine. It can be
  957. used to generate XML, text and other output, as easily as HTML. In fact, the
  958. engine can also be used to generate dynamic binary data, such as images, PDF
  959. files, etc., if needed. <p>
  960.  
  961. The Spyce engine can be <a href="[[=genTOClink('conf')]]">installed</a>
  962. in a number of different configurations that can produce dynamic output.
  963. The first three options exhibit high performance; the CGI approach is
  964. slowest, since a new engine must be created for each request:
  965.  
  966. <ul>
  967.  
  968.   <li><b>mod_python</b>: Apache module that runs a Python interpreter
  969.   in-process </li> <p>
  970.  
  971.   <li><b>FCGI</b>: A CGI-like method that does not incur the large
  972.   process startup overhead on each request </li> <p>
  973.  
  974.   <li><b>webserver</b>: The engine can operate as a proxy webserver,
  975.   serving requests redirected to it by a primary server. It can also
  976.   operate as a primary server, although this webserver is extremely
  977.   feature poor. </li> <p>
  978.  
  979.   <li><b>CGI</b>: Spyce can interoperate with any webserver that
  980.   supports CGI. The CGI-mode, while the slowest alternative, is
  981.   especially convenient during the development of Python modules,
  982.   ensuring that modules always get reloaded. Another alternative is to
  983.   use the <a href="[[=genTOClink('runtime_common_debug')]]">debug</a>
  984.   configuration switch. </li><p>
  985.  
  986.   <li><b>Others</b>: Spyce abstracts its operating environment using a thin
  987.   indirection layer. Spyce users have written small Spyce adapters for the
  988.   Xitami webserver and also to integrate with the Coil framework. Writing your
  989.   own adapter, should the need arise, is therefore a realistic possibility.
  990.   </li><p>
  991.  
  992. </ul>
  993.  
  994. [[toc.n('Static Content', 'runtime_static')]]
  995.  
  996. A nice feature of Spyce is that it can be invoked both from within a web
  997. server to process a web request dynamically and also from the command-line.
  998. The processing engine itself is the same in both cases. The command-line
  999. option is actually just a modified CGI client, and is often used to
  1000. pre-process static content, such as this manual. <p>
  1001.  
  1002. Some remarks regarding command-line execution specifics are in order. The
  1003. request and response objects for a command-line request are connected to
  1004. standard input and output, as expected. A minimal CGI-like environment is
  1005. created among the other shell environment variables. Header and cookie lookups
  1006. will return None and the engine will accept input on stdin for POST
  1007. information, if requested. There is also no compiler cache, since the process
  1008. memory is lost at the end of every execution. <p>
  1009.  
  1010. Most commonly, Spyce is invoked from the command-line to generate static .html
  1011. ouput. Spyce then becomes a rather handy and powerful .html preprocessing
  1012. tool. It was used on this documentation to produce the consistent headers and
  1013. footers, to include and highlight the example code snippets, etc...<p>
  1014.  
  1015. The following makefile rule comes in handy:<p>
  1016.  
  1017. [[.compact mode=off]]
  1018. <table align=center border=0><tr><td><font face=courier>
  1019. <b><pre>
  1020.   %.html: %.spy
  1021.     spyce -o $@ $<
  1022. </pre></b>
  1023. [[.compact]]
  1024. </font></td></tr></table><p>
  1025.  
  1026. [[toc.n('Command line', 'runtime_cmdline')]]
  1027.  
  1028. The full command-line syntax is:<p>
  1029.  
  1030. [[.compact mode=off]]
  1031. <table align=center border=0><tr><td>
  1032. <font face=courier size=-1>
  1033. <b><pre>[[ 
  1034.   import spyceCmd, cStringIO
  1035.   buf = cStringIO.StringIO()
  1036.   spyceCmd.showUsage(buf)
  1037.   response.write(escapeHTMLandCode(buf.getvalue()))
  1038. ]]</pre></b>
  1039. </font>
  1040. </td></tr></table>
  1041. [[.compact]] <p>
  1042.  
  1043. [[toc.n('Configuration', 'runtime_common')]]
  1044.  
  1045.  
  1046. Since there are a variety of very different <a
  1047. href="[[=genTOClink('conf')]]">installation</a> alternatives for the Spyce
  1048. engine, effort has been invested in consolidating all the various runtime
  1049. configuration options. By default, the Spyce engine will search for a file
  1050. called <b>spyce.conf</b> in its installation directory. An alternative file
  1051. location may be specified via the <b>--conf</b> command-line option. However,
  1052. the engine will operate just fine without any configuration file, using its
  1053. built-in default values. In general, command-line options supercede
  1054. configuration file options which, in turn, supercede built-in configuration
  1055. defaults. The options specified in the Spyce configuration file are
  1056. server-level configuration options (as opposed to file-level options). An
  1057. example configuration file is provided, called <b>spyce.conf.eg</b>. <p>
  1058.  
  1059. The general format of a Spyce file is that of a Windows .ini file. Sections
  1060. are denoted inside braces (i.e. [section]), and options with values are
  1061. specified on independent lines separated by a colon (i.e. option: value).
  1062. Comment lines begin with either a semicolon ';' or a hash '#'. An example of
  1063. an extensive Spyce file (i.e. with all options specified) is shown, with the
  1064. individual options described below.
  1065.  
  1066. [[toc.b('Example configuration', 'runtime_common_sample')]]
  1067.  
  1068. <table border=0 align=center><tr><td>
  1069.   <font face=courier size=-1>
  1070.     [[.compact mode=off]]
  1071.     <pre><b>[[=transform.html_encode(include.dump('../spyce.conf.eg'))]]</b></pre>
  1072.     [[.compact]]
  1073.   </font>
  1074. </td></tr></table>
  1075. <p>
  1076.  
  1077. [[toc.n('path', 'runtime_common_path')]]
  1078.  
  1079. The <b>path</b> option specifies additional module and import directories
  1080. searched by the Spyce engine. Specifically, the Spyce path (the path searched
  1081. to resolve <font face=courier>\[[.import\]]</font> directives) is the Spyce
  1082. home modules directory, plus the directories specified here, plus the
  1083. directory of the current Spyce file. The directories specified here are also
  1084. added to the sys.path, so that import statements search these directories as
  1085. well. The format for this option is a colon-separated (or semicolon-separated,
  1086. depending on your operating system) list of directories. If path is omitted
  1087. from the configuration file, the engine will check for a <font
  1088.   face=courier>SPYCE_PATH</font> variable in the process environment, and use
  1089. that. Failing this, the default is an empty string. <p>
  1090.  
  1091. [[toc.n('import', 'runtime_common_import')]]
  1092.  
  1093. The <b>import</b> option specifies <i>Python</i> modules (not Spyce modules)
  1094. that should be loaded (i.e. imported) at server startup. This can be useful to
  1095. perform initialization at server startup. Using the <a
  1096.   href="[[=genTOClink('mod_pool')]]">pool</a> module is prefered for storing
  1097. long-lived values. The string for this option is a comma-separated list of
  1098. Python module names. In CGI-mode, the Spyce engine is restarted on each
  1099. request, so these modules will be loaded on each request. For other
  1100. configurations, the import is performed once. To use this module, you will
  1101. still need to import the module in your Spyce modules or Spyce files, but it
  1102. will be taken from the Python module cache. <p>
  1103.  
  1104. [[toc.n('error', 'runtime_common_error')]]
  1105.  
  1106. The <b>error</b> option specifies an error handling function to call for
  1107. server-level errors. Server-level errors include: <b>spyce.spyceNotFound</b>,
  1108. <b>spyce.spyceForbidden</b>, <b>spyce.spyceSyntaxError</b> and
  1109. <b>spyce.pythonSyntaxError</b>. The string should be of the format
  1110. "module:function", and the module should be on the server path. The function
  1111. is invoked as <b>function(server, request, response, error)</b> to
  1112. generate the error output. The default is "error:serverHandler". Please look
  1113. at the serverHandler function in the error module, if you are considering
  1114. writing your own server error handler. File-level (or request-level) errors
  1115. are handled using the <a href="[[=genTOClink('mod_error')]]">error</a> module.
  1116. <p>
  1117.  
  1118. [[toc.n('pageerror', 'runtime_common_pageerror')]]
  1119.  
  1120. The <b>pageerror</b> option specifies the default page-level error handler
  1121. used by the error module. Page-level errors include all runtime errors that
  1122. occur during the processing of a Spyce script (i.e. after the compilation
  1123. phase has completed successfully). This option can take one of two forms: 1)
  1124. "string:<b>module</b>:<b>variable</b>", where string is a literal,
  1125. <b>module</b> specifies a module in the server path and <b>variable</b> is the
  1126. name of a variable containing the default error template Spyce string; or 2)
  1127. "file:<b>filename</b>", where file is a literal and <b>filename</b> is the
  1128. name of the Spyce file to use as the default error template. The default value
  1129. for this option is "string:error:defaultErrorTemplate". Please refer to this
  1130. string in the error module to see how to define your own page-level error
  1131. handlers.
  1132.  
  1133. [[toc.n('concurrency', 'runtime_common_concurrency')]]
  1134.  
  1135. The <b>concurrency</b> option specifies the concurrency mode that the engine
  1136. will operate in. The Spyce engine can process requests serially (i.e.
  1137. non-concurrently or one-at-a-time), or in parallel using either process-level
  1138. (forking) or thread-level (threading) concurrency. Note that this option
  1139. affects the request processing parallelism of a <i>single</i> engine. Request
  1140. processing parallelism may also be acheived by running multiple instances of
  1141. the engine, and this choice is independent of the follow discussion. <p>
  1142.  
  1143. The "one shot" Spyce configurations, namely CGI-based or command-line
  1144. execution, are unaffected by the concurrency option, since the server only
  1145. processes one request per Spyce engine invocation. <p>
  1146.  
  1147. The FastCGI configuration does not currently support parallel request
  1148. processing due to a limitation of the FastCGI interface code (not anything
  1149. inherent to the core of the Spyce engine). This will be remedied in the
  1150. future. <p>
  1151.  
  1152. The mod_python configuration does not support parallel request processing
  1153. within a single engine, since it is not supported by the mod_python interface.
  1154. In fact, many mod_python compilations do not even allow threading in the
  1155. Python interpretter. However, mod_python configurations run one Spyce engine
  1156. per Apache child, and achieve request processing parallelism in this way. <p>
  1157.  
  1158. Lastly, the Spyce engine can be run in webserver mode. This mode is affected
  1159. by the concurrency mode. The webserver runs in serial mode by default. It can
  1160. fork a new process for each request. Alternatively, it can spawn a new thread
  1161. for each request, if threading is supported by the Python interpretter. <p>
  1162.  
  1163. The possible values for the <b>concurrency</b> option are 'thread' (or
  1164. 'threading') and 'fork' (or 'forking'). Any other value results in a serial
  1165. execution, which is also the default. <p>
  1166.  
  1167. [[toc.n('cache', 'runtime_common_cache')]]
  1168.  
  1169. The <b>cache</b> option allows the user to select the underlying Spyce caching
  1170. implementation used. The format of the string for this option is
  1171. "<b>type:info</b>", where the <b>type</b> specifies the cache type, and the
  1172. optional <b>info</b> parameter is passed on to the cache implementation for
  1173. initialization. Spyce currently supports the following cache implementations:
  1174.  
  1175. <ul>
  1176.  
  1177.   <li><b>memory</b>: This is the default cache type, which uses an in-memory
  1178.   dictionary to store the compiled Spyces. It takes no parameters.</li> <p>
  1179.  
  1180.   <li><b>file</b>: The file-based cache type will serialize the compiled
  1181.   Spyces and store them in a given directory. The info parameter should be the
  1182.   <b>directory</b> location. </li> <p>
  1183.  
  1184. </ul> <p>
  1185.  
  1186. [[toc.n('debug', 'runtime_common_debug')]]
  1187.  
  1188. The <b>debug</b> option specifies whether the engine will run in debug mode.
  1189. Debug mode currently only affects the caching of Spyce files and Spyce
  1190. modules. Namely, Spyce files are always recompiled and Spyce modules are not
  1191. cached (are reloaded on each request) in debug mode, which is useful for
  1192. module developers. <b>This switch should not be used in a production
  1193.   environment</b>, because compilation will slow things down considerably! The
  1194. default value for this option is off. The values '0', 'false', and 'off'
  1195. represent production mode (as does leaving out the debug option entirely),
  1196. while any other value for this option turns debugging on. <p>
  1197.  
  1198. Alternatively, one could decide to perform development under CGI mode.
  1199. This ensures that a newly loaded Spyce engine is used on every request.
  1200. <p>
  1201.  
  1202. [[toc.n('globals', 'runtime_common_globals')]]
  1203.  
  1204. The <b>globals</b> section is also entirely optional. Any "key: expr" pair
  1205. will be stored in a hashtable, h, as h[key]=eval(expr). In other words, the
  1206. expression is evaluated first, and the result is stored in the hashtable using
  1207. the given key. This hashtable is accessible as <b>self.wrapper.server.globals</b>
  1208. within any Spyce module, or as <b>pool.globals</b> within any Spyce file (with
  1209. the pool module loaded). <p>
  1210.  
  1211. [[toc.n('www', 'runtime_common_www')]]
  1212.  
  1213. The <b>www</b> section defines values for the built-in Spyce webserver. <p>
  1214.  
  1215. The <b>root</b> option defines the root directory from which all requests are
  1216. served. By default, this is the current directory. It may be overridden on the
  1217. command-line. <p>
  1218.  
  1219. The <b>port</b> option defines the port at which the web server will listen.
  1220. By default, this is port 80, the regular HTTP port. It may be overridden using
  1221. the <b>-p</b> command-line switch. <p>
  1222.  
  1223. The <b>mime</b> option is a comma-separated list of files that define
  1224. mime-types for common file extensions. The files should be in the standard
  1225. Apache format. By default, the Spyce engine will read a file called
  1226. <b>spyce.mime</b> in from the installation directory. <p>
  1227.  
  1228. The <b>ext_</b> and <b>ext_<i>foo</i></b> (where <b><i>foo</i></b> can be
  1229. replaced by any extension) define the handler mapping. The legitimate values
  1230. are: <b>spyce</b> and <b>dump</b>. The spyce handler processes the file at the
  1231. requested path as a spyce script. The dump handler transfers the file at the
  1232. requested path verbatim, using the appropriate "Content-type" header, if it is
  1233. known. <b>ext_foo</b> option defines a mapping for a file that ends with
  1234. <b>foo</b>. The <b>ext_</b> option defines the default handler. By default,
  1235. all files ending with <b>.spy</b> are processed by the spyce handler, and all
  1236. other files are processed using the dump handler. Other handlers may readily
  1237. be added to the Spyce webserver, but it is never intended to be a fully
  1238. featured web server. <p>
  1239.  
  1240. [[toc.e()]]
  1241.  
  1242. [[toc.n('Programmatic Interface', 'runtime_prog')]]
  1243.  
  1244. It is also possible to embed Spyce into another program. All you need is to
  1245. run or <a href="http://www.python.org/doc/current/ext/embedding.html">embed
  1246. </a> a Python interpretter. Although other entry points into the engine code
  1247. as possible, the most convenient entry points are in <b>spyce.py</b>:
  1248.  
  1249. <ul>
  1250.  
  1251.   <li> <b>spyceFileHandler</b>( request, response, filename, [sig], [args], [kwargs], [config_file] ) <br>
  1252.  
  1253.   <i>explanation forthcoming; read the code for now, or send an email</i>
  1254.   
  1255.   </li> <p>
  1256.  
  1257.   <li> <b>spyceStringHandler</b>( request, response, code, [sig], [args], [kwargs], [config_file] ) <br>
  1258.   
  1259.   <i>explanation forthcoming; read the code for now, or send an email</i>
  1260.  
  1261.   </li> <p>
  1262.  
  1263. </ul> <p>
  1264.  
  1265. [[toc.e()]]
  1266.  
  1267. [[toc.n('Modules', 'mod')]]
  1268.  
  1269. The Spyce language, as described above, is simple and small. The Spyce
  1270. compiler merely embeds the power of Python using special Spyce tags. Most
  1271. functionality is provided at runtime through Spyce modules and Python modules.
  1272. A suite of standard Spyce modules is included with the Spyce distribution. The
  1273. standard Python modules are included in the Python distribution. You, of
  1274. course, may also write <a href="[[=genTOClink('mod_new')]]">new Spyce
  1275.   modules</a> and Python modules, or use code <a
  1276.   href="http://spyce.sourceforge.net/contrib/index.html">contributed</a>
  1277. (sourceforge link) by others to extend the base functionality available in
  1278. Spyce. <p>
  1279.  
  1280. It is important, from the outset, to define what a Spyce module is, and is
  1281. not. Specifically, it is important to differentiate a Spyce module from a
  1282. Python module. A Python module is a file with Python code, usually with a
  1283. common theme, and not necessarily related to Spyce. In contrast, a Spyce
  1284. module is a file with Python code that is written in a specific way to
  1285. interact directly with the Spyce runtime engine. A Spyce module may access the
  1286. internal request and response structures, require per-request startup and
  1287. tear-down callbacks from the engine, build on the existing standard modules,
  1288. or alter the behaviour of the runtime engine in some way, whereas a Python
  1289. module does not. <p> 
  1290.  
  1291. Both can be imported and used with equal ease at runtime. Spyce modules are
  1292. imported using the Spyce <a href="[[=genTOClink('lang_directive')]]"><font
  1293.     face=courier>\[[.import\]]</font></a> directive. Python modules are
  1294. imported using Python <font face=courier>import</font> keyword. Remember that
  1295. modules need to have the same read permissions as regular files that you
  1296. expect the web server to read. <p>
  1297.  
  1298. Once included, a module may be accessed anywhere in the Spyce code as a global
  1299. variable, just like Python modules. Spyce modules are objects. They provide
  1300. methods and fields. One uses them as regular Python objects. Modules are
  1301. <b>start</b>()ed before pre-Spyce processing, and <b>finish</b>()ed post-Spyce
  1302. processing. They are <b>init</b>()ialized with optional arguments during Spyce
  1303. processing at the point of the Spyce directive. <p>
  1304.  
  1305. Modules may be renamed from their defaults using the <b>as</b> attribute,
  1306. though this is discouraged in most cases. Doing this may cause unexpected
  1307. behaviour. The <b>session</b> module, for example, may expect to find or
  1308. otherwise load a module named <b>cookie</b> in the Spyce environment, if
  1309. cookies are chosen for session management; the <b>taglib</b> module expects to
  1310. find the standard <b>stdout</b> module to capture the output of tag body
  1311. processing; the <b>stdout</b> and <b>filter</b> modules interact very closely
  1312. with the <b>response</b> module; etc. In other words, you should rename
  1313. modules only if you have read their implementations and know what you are
  1314. doing. <p>
  1315.  
  1316. The following standard Spyce modules are loaded implictly into the spyce
  1317. environment, because they are required for Spyce operation: <b>request</b>,
  1318. <b>response</b>, <b>error</b>, <b>stdout</b>, <b>spylambda</b> and
  1319. <b>taglib</b>. The latter two are loaded only if Spyce lambdas and active tags
  1320. are used in the script, respectively. Of the standard Python modules, only the
  1321. __builtins__ module is imported, along with a number of Spyce exceptions from
  1322. the spyceException module. <p>
  1323.  
  1324. Below, we document each individual standard Spyce module, and then describe
  1325. how one would write <a href="[[=genTOClink('mod_new')]]">new</a> Spyce
  1326. modules. <p>
  1327.  
  1328. [[toc.b('Request', 'mod_request')]]
  1329.  
  1330. The request module is loaded implicitly into every Spyce environment. It
  1331. provides the following methods:
  1332.  
  1333. <ul>
  1334.  
  1335.   <li><b>uri</b>( [component] ): <br> Returns the request URI, or some
  1336.   component thereof. If the optional <b>component</b> parameter is specified,
  1337.   it should be one of the following strings:
  1338.  
  1339.   <font face=courier>'scheme'</font>, 
  1340.   <font face=courier>'location'</font>, 
  1341.   <font face=courier>'path'</font>, 
  1342.   <font face=courier>'parameters'</font>, 
  1343.   <font face=courier>'query'</font> or 
  1344.   <font face=courier>'fragment'</font>.
  1345.  
  1346.   </li><p>
  1347.  
  1348.   <li><b>method</b>(): <br> Returns request method type (GET, POST,
  1349.   ...)</li><p>
  1350.  
  1351.   <li><b>query</b>(): <br> Returns the request query string</li><p>
  1352.  
  1353.   <li><b>get</b>( [name], [default], [ignoreCase] ): <br> Returns request GET
  1354.   information. If <b>name</b> is specified then a single list of values is
  1355.   returned if the parameter exists, or <b>default</b>, which defaults to None,
  1356.   if the parameter does not exist. Parameters without values are skipped,
  1357.   though empty string values are allowed. If name is omitted, then a
  1358.   dictionary of lists is returned. If <b>ignoreCase</b> is true, then the
  1359.   above behaviour is performed in a case insensitive manner (all parameters
  1360.   are treated as lowercase). </li><p>
  1361.  
  1362.   <li><b>get1</b>( [name], [default], [ignoreCase] ): <br> Returns request GET
  1363.   information, similarly to (though slightly differently from) the function
  1364.   above. If <b>name</b> is specified then a single string is returned if the
  1365.   parameter exists, or <b>default</b>, which default to None, if the parameter
  1366.   does not exist. If there is more than one value for a parameter, then only
  1367.   one is returned. Parameters without values are skipped, though empty string
  1368.   values are allowed. If name is omitted, then a dictionary of strings is
  1369.   returned. If the optional <b>ignoreCase</b> flag is true, then the above
  1370.   behaviour is performed in a case insensitive manner (all parameters are
  1371.   treated as lowercase). </li><p>
  1372.   
  1373.   <li><b>post</b>( [name], [default], [ignoreCase] ): <br> Returns request
  1374.   POST information. If <b>name</b> is specified then a single list of values
  1375.   is returned if the parameter exists, or <b>default</b>, which defaults to
  1376.   None, if the parameter does not exist. Parameters without values are
  1377.   skipped, though empty string values are allowed. If name is omitted, then a
  1378.   dictionary of lists is returned. If <b>ignoreCase</b> is true, then the
  1379.   above behaviour is performed in a case insensitive manner (all parameters
  1380.   are treated as lowercase). This function understands form information
  1381.   encoded either as 'application/x-www-form-urlencoded' or
  1382.   'multipart/form-data'. Uploaded file parameters are not included in this
  1383.   dictionary; they can be accessed via the file method. </li><p>
  1384.   
  1385.   <li><b>post1</b>( [name], [default], [ignoreCase] ): <br> Returns request
  1386.   POST information, similarly to (though slightly differently from) the
  1387.   function above. If <b>name</b> is specified then a single string is returned
  1388.   if the parameter exists, or <b>default</b>, which defaults to None, if the
  1389.   parameter does not exist. If there is more than one value for a parameter,
  1390.   then only one is returned. Parameters without values are skipped, though
  1391.   empty string values are allowed. If name is omitted, then a dictionary of
  1392.   strings is returned. If the optional <b>ignoreCase</b> flag is true, then
  1393.   the above behaviour is performed in a case insensitive manner (all
  1394.   parameters are treated as lowercase). This function understands form
  1395.   information encoded either as 'application/x-www-form-urlencoded' or
  1396.   'multipart/form-data'. Uploaded file parameters are not included in this
  1397.   dictionary; they can be accessed via the file method. </li><p>
  1398.   
  1399.   <li><b>file</b>( [name], [ignoreCase] ): <br> Returns files POSTed in the
  1400.   request. If <b>name</b> is specified then a single cgi.FieldStorage class is
  1401.   returned if such a file parameter exists, otherwise None. If name is
  1402.   omitted, then a dictionary of file entries is returned. If the optional
  1403.   <b>ignoreCase</b> flag is true, then the above behaviour is performed in a
  1404.   case insensitive manner (all parameters are treated as lowercase). The
  1405.   interesting fields of the FieldStorage class are: <p>
  1406.  
  1407.   <ul>
  1408.  
  1409.     <li><b>name:</b> the field name, if specified; otherwise None</li>
  1410.  
  1411.     <li><b>filename:</b> the filename, if specified; otherwise None; this is
  1412.     the client-side filename, not the filename in which the content is stored
  1413.     - a temporary file you don't deal with
  1414.  
  1415.     <li><b>value:</b> the value as a string; for file uploads, this
  1416.     transparently reads the file every time you request the value
  1417.  
  1418.     <li><b>file:</b> the file(-like) object from which you can read the data;
  1419.     None if the data is stored a simple string
  1420.  
  1421.     <li><b>type:</b> the content-type, or None if not specified
  1422.  
  1423.     <li><b>type_options:</b> dictionary of options specified on the
  1424.     content-type line
  1425.  
  1426.     <li><b>disposition:</b> content-disposition, or None if not specified
  1427.  
  1428.     <li><b>disposition_options:</b> dictionary of corresponding options
  1429.  
  1430.     <li><b>headers:</b> a dictionary(-like) object (sometimes rfc822.Message
  1431.     or a subclass thereof) containing *all* headers
  1432.  
  1433.   </ul><p>
  1434.  
  1435.   <li><b>__getitem__</b>( key ): <br> The request module can be used as a
  1436.   dictionary: i.e. request['foo']. This method first calls the get1() method,
  1437.   then the post1() method and lastly the file() method trying to find the
  1438.   first non-None value to return. If no value is found, then this method
  1439.   returns None. Note: Throwing an exception seemed too strong a semantics, and
  1440.   so this is a break from Python. One can also iterate over the request
  1441.   object, as if over a dictionary of field names in the get1 and post1
  1442.   dictionaries. In the case of overlap, the get1() dictionary takes
  1443.   precedence. </li><p>
  1444.  
  1445.   <li><b>getpost</b>( [name], [default], [ignoreCase] ): <br> Using given
  1446.   parameters, return get() result if not None, otherwise return post() result
  1447.   if not None, otherwise <b>default</b>. </li><p>
  1448.  
  1449.   <li><b>getpost1</b>( [name], [default], [ignoreCase] ): <br> Using given
  1450.   parameters, return get1() result if not None, otherwise return post1()
  1451.   result if not None, otherwise <b>default</b>. </li><p>
  1452.  
  1453.   <li><b>postget</b>( [name], [default], [ignoreCase] ): <br> Using given
  1454.   parameters, return post() result if not None, otherwise return get() result
  1455.   if not None, otherwise <b>default</b>. </li><p>
  1456.  
  1457.   <li><b>postget1</b>( [name], [default], [ignoreCase] ): <br> Using given
  1458.   parameters, return post1() result if not None, otherwise return get1()
  1459.   result if not None, otherwise <b>default</b>. </li><p>
  1460.  
  1461.   <li><b>env</b>( [name], [default] ): <br> Returns a dictionary with CGI-like
  1462.   environment information of this request. If <b>name</b> is specified then a
  1463.   single entry is returned if the parameter exists, otherwise <b>default</b>,
  1464.   which defaults to None, if omitted. </li><p>
  1465.   
  1466.   <li><b>getHeader</b>( [type] ): <br> Return a specific header sent by the
  1467.   browser. If optional <b>type</b> is omitted, a dictionary of all headers is
  1468.   returned.</li><p>
  1469.  
  1470.   <li><b>filename</b>( [path] ): <br> Return the Spyce filename of the request
  1471.   currently being processed. If an optional <b>path</b> parameter is provided,
  1472.   then that path is made relative to the Spyce filename of the request
  1473.   currently being processed. </li><p>
  1474.  
  1475.   <li><b>default</b>( value, value2 ): <br> (convenience method) Return
  1476.   <b>value</b> if it is not None, otherwise return <b>value2</b>. </li><p>
  1477.  
  1478. </ul>
  1479.  
  1480. Dynamic web pages frequently need to access GET and POST information sent by
  1481. the browser. Here is an example that shows this is done.<br>
  1482.  
  1483. [[includeCode('examples/getpost.spy') ]]
  1484. <p>
  1485.  
  1486. The example below presents the results of all the method calls list above. Run
  1487. it to understand the information available. <p>
  1488.  
  1489. [[includeCode('examples/request.spy') ]]
  1490. <p>
  1491.  
  1492. A more complicated form... <p>
  1493.  
  1494. [[includeCode('examples/form.spy') ]]
  1495. <p>
  1496.  
  1497. Lastly, the following example shows how to deal with uploaded files. <p>
  1498.  
  1499. [[includeCode('examples/fileupload.spy') ]] <p>
  1500.  
  1501. [[toc.n('Response', 'mod_response')]]
  1502.  
  1503. Like the request module, the response module is also loaded implicitly by every
  1504. Spyce. It provides the following methods:
  1505.  
  1506. <ul>
  1507.  
  1508.   <li><b>write</b>( string ): <br> Sends a <b>string</b> to the client. All
  1509.   writes are buffered by default and sent at the end of Spyce processing to
  1510.   allow appending headers, setting cookies and exception handling. Note that
  1511.   using the <font face="courier">print</font> statement is often easier, and
  1512.   <a href="[[=genTOClink('mod_stdout')]]">stdout</a> is implicitly redirected
  1513.   to the browser. </li> <p>
  1514.  
  1515.   <li><b>writeln</b>( string ): <br> Sends a <b>string</b> to the client, and
  1516.   appends a newline. </li><p>
  1517.  
  1518.   <li><b>writeStatic</b>( string ): <br> All static HTML <b>strings</b> are
  1519.   emitted to the client via this method, which (by default) simply calls
  1520.   write(). This method is <i>not</i> commonly invoked by the user. </li><p>
  1521.  
  1522.   <li><b>writeExpr</b>( object ): <br> All expression results are emitted to
  1523.   the client via this method, which (by default) calls write() with the str()
  1524.   of the result <b>object</b>. This method is <i>not</i> commonly invoked by
  1525.   the user. </li><p>
  1526.  
  1527.   <li><b>clear</b>( ): Clears the output buffer. </li> <p>
  1528.  
  1529.   <li><b>flush</b>( ): Sends buffered output to the client immediately. This
  1530.   is a blocking call, and can incur a performance hit.</li> <p>
  1531.  
  1532.   <li><b>setContentType</b>( contentType ): <br> Sets the MIME <b>content
  1533.     type</b> of the response. </li> <p>
  1534.  
  1535.   <li><b>setReturnCode</b>( code ): <br> Set the HTTP return code for this
  1536.   response. This <b>return code</b> may be overriden if an error occurs or by
  1537.   functions in other modules (such as redirects). </li> <p>
  1538.  
  1539.   <li><b>addHeader</b>( type, data, [replace] ): <br> Adds the header line
  1540.   "<font face=courier>type: data</font>" to the outgoing response. The
  1541.   optional <b>replace</b> flag determines whether any previous headers of the
  1542.   same type are first removed. </li><p>
  1543.  
  1544.   <li><b>unbuffer</b>(): <br> Turns off buffering on the output stream. In
  1545.   other words, each write is followed by a flush(). An unbuffered output
  1546.   stream should be used only when sending large amounts of data (ie. file
  1547.   transfers) that would take up server memory unnecessarily, and involve
  1548.   consistently large writes. Note that using an unbuffered response stream
  1549.   will not allow the output to be cleared if an exception occurs. It will also
  1550.   immediately send any headers. </li><p>
  1551.  
  1552.   <li><b>isCancelled</b>(): <br> Returns true if it has been detected that the
  1553.   client is no longer connected. This flag will turn on, and remain on, after
  1554.   the first client output failure. However, the detection is best-effort, and
  1555.   may never turn on in certain configurations (such as CGI) due to buffering.
  1556.   </li><p>
  1557.  
  1558.   <li><b>timestamp</b>( [thetime] ):<br> Timestamps the response with an HTTP
  1559.   <font face=courier>Date:</font> header, using the optional <b>thetime</b>
  1560.   parameter, which may be either be the number of seconds since the epoch
  1561.   (see Python <a
  1562.   href="http://www.python.org/doc/current/lib/module-time.html">time</a>
  1563.   module), or a properly formatted HTTP date string. If thetime is omitted,
  1564.   the current time is used. </li> <p>
  1565.  
  1566.   <li><b>expires</b>( [thetime] ):<br> Sets the expiration time of the
  1567.   response with an HTTP <font face=courier>Expires:</font> header, using the
  1568.   optional <b>thetime</b> parameter, which may be either the number of seconds
  1569.   since the epoch (see Python <a
  1570.   href="http://www.python.org/doc/current/lib/module-time.html">time</a>
  1571.   module), or a properly formatted HTTP date string. If thetime is omitted,
  1572.   the current time is used. </li> <p>
  1573.  
  1574.   <li><b>expiresRel</b>( [secs] ):<br> Sets the expiration time of the
  1575.   response <i>relative to the current time</i> with an HTTP <font
  1576.   face=courier>Expires:</font> header. The optional <b>secs</b> (which may
  1577.   also be negative) indicates the number of seconds to add to the current time
  1578.   to compute the expiration time. If secs is omitted, it defaults to zero.
  1579.   </li> <p>
  1580.  
  1581.   <li><b>lastModified</b>( [thetime] ):<br> Sets the last modification time of
  1582.   the response with an HTTP <font face=courier>Last-Modified:</font> header,
  1583.   using the optional <b>thetime</b> parameter, which can be either the number
  1584.   of seconds since the epoch (see Python <a
  1585.   href="http://www.python.org/doc/current/lib/module-time.html">time</a>
  1586.   module), or a properly formatted HTTP date string, or None indicating the
  1587.   current time. If thetime is omitted, this function will default to the last
  1588.   modification time of the Spyce file for this request, and raise an exception
  1589.   if this time can not be determined. Note that, as per the HTTP
  1590.   specification, you should not set a last modification time that is beyond
  1591.   the response timestamp.</li> <p>
  1592.  
  1593.   <li><b>uncacheable</b>():<br> Sets the HTTP/1.1 <font
  1594.   face=courier>Cache-Control:</font> and HTTP/1.0 <font
  1595.   face=courier>Pragma:</font> headers to inform clients and proxies that this
  1596.   content should not be cached. </li> <p>
  1597.  
  1598. </ul>
  1599.  
  1600. The methods are self-explanatory. One of the more interesting things that one could do is 
  1601. to emit non-HTML content types. The example below emits the Spyce logo as a GIF.<p>
  1602.  
  1603. [[includeCode('examples/gif.spy') ]] <p>
  1604.  
  1605. [[toc.n('Error', 'mod_error')]]
  1606.  
  1607. The error module is implicitly loaded and provides error-handling
  1608. functionality. An error is any <a
  1609. href="[[=genTOClink('runtime_except')]]">unhandled runtime exception</a> that
  1610. occurs <b>during Spyce processing</b>. This mechanism does not include
  1611. exceptions that are not related to Spyce processing (i.e. server-related
  1612. exceptions), that can be caused before or after Spyce processing by invalid
  1613. syntax, missing files and file access restrictions. To install a server-level
  1614. error handler use a <a href="[[=genTOClink('runtime_common')]]">configuration
  1615. file</a>. The default page-level error handler can also be modified in the <a
  1616. href="[[=genTOClink('runtime_common')]]">configuration file</a>. This module
  1617. allows the user to install page-level error handling code, overriding the
  1618. default page-level handler, by using one of the following functions: <p>
  1619.  
  1620. <ul>
  1621.  
  1622.   <li><b>setStringHandler</b>( string ): <br> Installs a function that will
  1623.   processes the given <b>string</b>, as Spyce code, for error handling.
  1624.   </li><p>
  1625.  
  1626.   <li><b>setFileHandler</b>( file ): <br> Installs a function that will
  1627.   processes the given <b>file</b> for error handling. </li><p>
  1628.  
  1629.   <li><b>setHandler</b>( fn ): <br> Installs the <b>fn</b> function for error
  1630.   handling. The function is passed one parameter, a reference to the error
  1631.   module. From this, all the error information as well as references to other
  1632.   modules and Spyce objects can be accessed.</li><p>
  1633.  
  1634. </ul>
  1635.  
  1636. The error module provides the following information about an error: <p>
  1637.  
  1638. <ul>
  1639.  
  1640.   <li><b>isError</b>(): <br> Returns whether an error is being handled.
  1641.   </li><p>
  1642.  
  1643.   <li><b>getMessage</b>(): <br> Return the error message; the string of the
  1644.   object that was raised, or None if there is no current error. </li><p>
  1645.  
  1646.   <li><b>getType</b>(): <br> Return the error type; the type of the object
  1647.   that was raised, or None if there is no current error. </li><p>
  1648.  
  1649.   <li><b>getFile</b>(): <br> Return the file where the error was raised, or
  1650.   None if there is no current error. </li><p>
  1651.  
  1652.   <li><b>getTraceback</b>(): <br> Return the stack trace as an array of
  1653.   tuples, or None if there is no current error. Each tuple entry is of the
  1654.   form: (file, line numbers, function name, code context).</li><p>
  1655.  
  1656.   <li><b>getString</b>(): <br> Return the string of the entire error (the
  1657.   string representation of the message, type, location and stack trace), or
  1658.   None if there is no current error. </li><p>
  1659.  
  1660. </ul>
  1661.  
  1662. The default error handling function uses the following string handler:
  1663.  
  1664. [[\
  1665.   template = response._api.spyceModule('defaultErrorTemplate', 'error.py')
  1666. ]]
  1667. <table border=0 align=center><tr><td>
  1668. <pre>[[=include.spycecode(string=template)]]</pre>
  1669. </td></tr></table>
  1670. <p>
  1671.  
  1672. The example below shows the error module in use. Error handling can often be
  1673. used to send emails notifying webmasters of problems, as this example shows.
  1674. <p>
  1675.  
  1676. [[includeCode('examples/error.spy')]]
  1677. <p>
  1678.  
  1679. [[includeCode('examples/error.spi', run=0)]]
  1680. <p>
  1681.  
  1682. This mechanism is not a subsititute for proper exception handling within the
  1683. code itself, and should not be abused. It does, however, serve as a useful
  1684. catch-all for bugs that slip through the cracks. <p>
  1685.  
  1686. [[toc.n('Stdout', 'mod_stdout')]]
  1687.  
  1688. The stdout module is loaded implicitly and redirects Python's <font
  1689. face=courier>sys.stdout</font> (in a thread-safe manner) to the appropriate
  1690. response object for the duration of Spyce processing. This allows one to use
  1691. <font face=courier>print</font>, without having to write <font
  1692. face=courier>print >> response, ...</font>. The stdout
  1693. module provides a variable <font face=courier>stdout.stdout</font>, which
  1694. refers to the original stream, but is unlikely to be needed. It may also be
  1695. useful to know that <font face=courier>sys.stderr</font> is, under many
  1696. configurations, connected to the webserver error log. <p>
  1697.  
  1698. In addition, the stdout module provides the following functions for capturing
  1699. or redirecting output:
  1700.  
  1701. <ul>
  1702.  
  1703.   <li><b>push</b>( [filename] ): <br> Begin capturing output. Namely, the current
  1704.   output stream is pushed onto the stack and replaced with a memory buffer. An
  1705.   optional <b>filename</b> may be associated with this operation (see pop()
  1706.   method below). </li> <p>
  1707.   
  1708.   <li><b>pop</b>(): <br> Close current output buffer, and return the captured
  1709.   output as a string. If a filename was associated with the push(), then the
  1710.   string will also be written to that file. </li> <p>
  1711.  
  1712.   <li><b>capture</b>(f, [*args], [**kwargs] ): <br> Push the current stream,
  1713.   call the given function <b>f</b> with any supplied arguments <b>*args</b>
  1714.   and keyword arguments <b>**kwargs</b>, and then pop it back. Capture returns
  1715.   a tuple (r,s), where r is the result returned by f and s is a string of its
  1716.   output. </li> <p>
  1717.  
  1718. </ul> <p>
  1719.  
  1720. The example below show how the module is used: 
  1721.  
  1722. [[includeCode('examples/stdout.spy')]]
  1723. <p>
  1724.  
  1725. [[toc.n('Spylambda', 'mod_lambda')]]
  1726.  
  1727. The spylambda module is loaded implicitly and allows the definition of
  1728. functions based on Spyce scripts. The spylambda module provides the following
  1729. methods:
  1730.  
  1731. <ul>
  1732.  
  1733.   <li><b>define</b>( args, code, [memoize] ): <br> Returns a function that
  1734.   accepts the given <b>args</b> and executes the Spyce script defined by the
  1735.   <b>code</b> parameter. Note that the code is compiled immediately and that
  1736.   <font face=courier>spyce.spyceSyntaxError</font> or <font
  1737.   face=courier>spyce.spycePythonError</font> exceptions can be thrown for
  1738.   invalid code arguments. The optional <b>memoize</b> parameter sets whether
  1739.   the spyce can or can not be memoized, with the default being false.
  1740.   Memoizing a function means capturing the result and output and caching them,
  1741.   keyed on the function parameters. Later, if a function is called again with
  1742.   the same parameters, the cached information is returned, if it exists, and
  1743.   the function may not actually be called. Thus, you should only memoize
  1744.   functions that are truly functional, i.e. they do not have side-effects:
  1745.   they only return a value and output data to the response object, and their
  1746.   behaviour depends exclusively on their parameters. If you memoize code that
  1747.   does have side-effects, those side-effects may not occur on every
  1748.   invocation. </li> <p>
  1749.  
  1750.   <li><b>__call__</b>( args, code, _spyceCache ): <br> This is an alias to the
  1751.   define function. Because of the special method name, the spylambda module
  1752.   object can be <a
  1753.   href="http://www.python.org/doc/current/ref/callable-types.html">called as
  1754.   if it were a function</a>. </li> <p>
  1755.  
  1756. </ul>
  1757.  
  1758. This function is not frequently called directly from Spyce code, because
  1759. writing the Spyce code argument in a manner that does not conflict with the
  1760. Spyce tag delimiters is cumbersome. Rather the <a
  1761.   href="[[=genTOClink('lang_lambda')]]">Spyce lambda</a> syntax is used and
  1762. translated into this function call at compilation time, as in the example
  1763. below. <p>
  1764.  
  1765. [[includeCode('examples/spylambda.spy') ]] <p> 
  1766.  
  1767. It often useful to use the spylambda module directly from other Spyce modules
  1768. that may need to perform significant amounts of output. Rather than calling
  1769. <font face="courier">print</font> repeatedly, it is more convenient to invoke
  1770. a Spyce, as in the example below. Though highly simplified, this example also
  1771. shows how Spyce lambdas can be used to easily build a complex rendering
  1772. environment. <p>
  1773.  
  1774. [[includeCode('examples/myPortal.spy') ]] <p> 
  1775.  
  1776. [[includeCode('examples/myPortal.py', run=0) ]] <p> 
  1777.  
  1778. [[toc.n('Taglib', 'mod_taglib')]]
  1779.  
  1780. The taglib module is loaded implicitly and supports the active tags
  1781. functionality at runtime. It is expected that the casual user will not have
  1782. much use for this module, and will only call its functions indirectly by
  1783. importing tag libraries and using active tags. Primarily, this is because the
  1784. methods interoperate very tightly and require a very strict calling sequence,
  1785. which is generated by the Spyce compiler for each active tag it encounters.
  1786. Nevertheless, for completeness, the taglib module provides the following
  1787. methods:
  1788.  
  1789. <ul>
  1790.  
  1791.   <li><b>context</b>: This field is a dictionary that serves as the context in
  1792.   which tags operate. Tags can store variables and evaluate expressions within
  1793.   this context. The tag context contains references to all the loaded modules.
  1794.   Thus, it is valid to refer to something like <font
  1795.   face=courier>request.query()</font> in a tag expression. However, it is not
  1796.   valid to change any module variable references. While this will not cause
  1797.   any harm, the user should expect that these new values can be reset by the
  1798.   runtime at any time. </li> <p>
  1799.  
  1800.   <li><b>load</b>( libname, [libfrom], [libas] ): <br> Loads a tag library
  1801.   class named <b>libname</b> from a file called <b>libfrom</b> in the search
  1802.   path, and installed it under the tag prefix <b>libas</b>. The default for
  1803.   libfrom is <font face=courier><i>libname</i>.py</font>. The default for
  1804.   libas is <font face=courier><i>libname</i></font>. Once installed, a library
  1805.   name is its unique tag prefix. </li> <p>
  1806.  
  1807.   <li><b>unload</b>( libname ): <br> Unload a tag library that is installed
  1808.   under the <b>libname</b> prefix. This is usually performed only at the end
  1809.   of a request. </li> <p>
  1810.  
  1811.   <li><b>tagPush</b>( libname, tagname, pair ): <br> Push a new tag object for
  1812.   a <b>libname</b>:<b>tagname</b> tag onto the tag stack. The <b>pair</b>
  1813.   parameter is a flag indicating whether this is a singleton or a paired tag.
  1814.   </li> <p>
  1815.  
  1816.   <li><b>tagPop</b>(): <br> Pop the current tag from the tag stack. </li> <p>
  1817.  
  1818.   <li><b>getTag</b>(): <br> Return the current tag object. </li> <p>
  1819.  
  1820.   <li><b>outPush</b>(): <br> Begin capturing the current output stream. This
  1821.   is usually called by the tagBegin method. </li> <p>
  1822.  
  1823.   <li><b>outPopCond</b>(): <br> End capturing the current output stream, and
  1824.   return the captured contents. It will only "pop" once, even if called
  1825.   multiple times for the same tag. This method is usually called by either the
  1826.   tagEnd(), tagCatch, or tagPop() methods. </li> <p>
  1827.  
  1828.   <li><b>tagBegin</b>( attrs ): <br> This method sets the tag output and
  1829.   variable environment, and then calls the tag's <b>begin()</b> method with
  1830.   the given <b>attrs</b> tag attribute dictionary. This method returns a flag,
  1831.   and the tag body must be processed if and only if this flag is true. </li>
  1832.   <p>
  1833.   
  1834.   <li><b>tagBody</b>(): <br> This method sets the tag output and variable
  1835.   environment, and then calls the tag's <b>body()</b> method with the captured
  1836.   output of the body processing. If this method returns true, then the
  1837.   processing of the body must be repeated. </li> <p>
  1838.  
  1839.   <li><b>tagEnd</b>(): <br> This method sets the tag output and variable
  1840.   environment, and then calls the tag's <b>end()</b> method. This method must
  1841.   be called if the tagBegin() method completes successfully in order to
  1842.   preserve tag semantics. </li> <p>
  1843.  
  1844.   <li><b>tagCatch</b>(): <br> This method should be called if any of the
  1845.   tagBegin, tagBody or tagEnd methods raise an exception. It calls the tag's
  1846.   <b>catch()</b> method with the current exception. </li> <p>
  1847.  
  1848. </ul> <p>
  1849.  
  1850. As stated previously, it is expected that the user will not call these methods
  1851. directly, but rather simply use the active tag functionality that this module
  1852. supports. Spyce comes with various standard <a
  1853. href="[[=genTOClink('tag')]]">tag libraries</a>. The following example shows a
  1854. few simple ones in use:
  1855.  
  1856. [[includeCode('examples/tag.spy') ]] <p> 
  1857.  
  1858. [[toc.n('Include', 'mod_include')]]
  1859.  
  1860. Many websites carry a theme across their various pages, which is often
  1861. achieved by including a common header or footer. The include module provides
  1862. exactly this functionality, and more. For example, it can also be used to
  1863. define dynamic site-wide constants, and other similar globals that can not
  1864. otherwise be initialized with static include directives (due to their dynamic
  1865. nature). For example, language specific constants may be selected dynamically
  1866. from the required language include file, based on a GET or POST language
  1867. parameter or, better yet, from the Accept-Language request header. This module
  1868. also provides other functions that are similar in nature. For example, it can
  1869. currently pretty print Spyce code. In the future, it will be able to generate
  1870. the Spyce and Spyce Powered logo, and possibly other similar trinkets. <p>
  1871.  
  1872. <ul>
  1873.  
  1874.   <li><b>spyce</b>( file, [context] ): <br> Dynamically includes the specified
  1875.   <b>file</b>, and processes it as Spyce code. The return value is that of the
  1876.   included Spyce file. One can optionally provide a <b>context</b> value to
  1877.   the included file. If omitted, the value defaults to None. All currently
  1878.   imported modules are passed along into the included file without
  1879.   re-initialization. However, for each explicit <font
  1880.   face=courier>\[[.import \]]</font> tag in the included file, a new
  1881.   module is initialized and also finalized up at the end of processing. The
  1882.   include module provides three fields for use inside included files: <p>
  1883.  
  1884.   <ul>
  1885.  
  1886.     <li>include.<b>context</b>: This field stores the value passed in at the
  1887.     point of inclusion. Note that if the value is one that is passed by
  1888.     reference (as is the case with object, list, and dictionary types), then
  1889.     the context may be used to pass information back to the including file, in
  1890.     addition to the return value. </li> <p>
  1891.  
  1892.     <li>include.<b>vars</b>: If the include context is of type dictionary,
  1893.     then the vars field is initialized, otherwise it is None. The vars field
  1894.     provides attribute-based access to the context dictionary, merely for
  1895.     convenience. In other words, <font face=courier>self.vars.x</font> is
  1896.     equivalent to <font face=courier>self.context['x']</font>. </li> <p>
  1897.  
  1898.     <li>include.<b>fromFile</b>: stores the name of the file name from which
  1899.     this file was included. </li><p>
  1900.  
  1901.   </ul> 
  1902.   
  1903.   Note that either the locals() or globals() dictionaries may be passed in as
  1904.   include contexts. However, be advised that due to Python optimizations of
  1905.   local variable access, any updates to the locals() dictionary may not be
  1906.   reflected in the local namespace under all circumstances and all versions of
  1907.   Python. In fact, this is the reason why the context has been made explicit,
  1908.   and does not simply grab the locals() dictionary. It may, however, safely be
  1909.   used for read access. With respect to the globals() dictionary, it is not
  1910.   advised to <a href="[[=genTOClink('runtime_transform')]]">pollute</a> this
  1911.   namespace. </li><p>
  1912.  
  1913.   <li><b>dump</b>( file, [binary] ): <br> Contents of the <b>file</b> are
  1914.   returned. If the <b>binary</b> parameter is true, the file is opened in
  1915.   binary mode. By default, text mode is used. </li><p>
  1916.  
  1917.   <li><b>spycecode</b>( file ): <br> Contents of the <b>file</b> are returned
  1918.   as HTML formatted Spyce code. </li><p>
  1919.  
  1920. </ul>
  1921.  
  1922. The example below (taken from this documentation file), uses a common header
  1923. template only requiring two context variables to change the title and the
  1924. highlighted link:<br>
  1925.  
  1926. [[.compact mode=off]]
  1927. <table align=center border=0><tr><td>
  1928. <font face=courier>
  1929. <b><pre>  \[[.import name=include\]]
  1930.   \[[include.spyce('inc/head.spi', 
  1931.       {'pagename': 'Documentation', 
  1932.        'page': 'manual.html'}) \]]</pre></b>
  1933. </font>
  1934. </td></tr></table><p>
  1935. [[.compact]]
  1936.  
  1937. In <b>head.spi</b>, we use this information to set the title:<p>
  1938.  
  1939. [[.compact mode=off]]
  1940. <table align=center border=0><tr><td>
  1941. <font face=courier>
  1942. <b><pre>
  1943.   \[[.import name=include\]]
  1944.   [[=escapeHTMLandCode("<title>[+=include.context['pagename'] +]</title>") ]]
  1945. </pre></b>
  1946. </font>
  1947. </td></tr></table><p>
  1948. [[.compact]]
  1949.  
  1950. By convention, included files are given the extension <b>.spi</b>.<p>
  1951.  
  1952. Below we contrast the difference between static and dynamic includes. A
  1953. dynamic include is included on each request; a static include is inserted at
  1954. compile time. A static include runs in the same context, while a dynamic
  1955. include has a separate context.<p>
  1956.  
  1957. [[includeCode('examples/include.spy') ]]<p>
  1958. [[includeCode('examples/include.spi', run=0) ]]<p>
  1959. [[includeCode('examples/includestatic.spy') ]]<p>
  1960. [[includeCode('examples/includestatic.spi', run=0) ]]<p>
  1961.  
  1962. [[toc.n('Transform', 'mod_transform')]]
  1963.  
  1964. The transform module contains useful text transformation functions, commonly
  1965. used during web-page generation. <p>
  1966.  
  1967. <ul>
  1968.  
  1969.   <li><b>html_encode</b>( string, [also] ): <br> Returns a HTML-encoded
  1970.   <b>string</b>, with special characters replaced by entity references as
  1971.   defined in the HTML 3.2 and 4 specifications. The optional <b>also</b>
  1972.   parameter can be used to encode additional characters. </li><p>
  1973.   
  1974.   <li><b>url_encode</b>( string, ): <br> Returns an URL-encoded <b>string</b>,
  1975.   with special characters replaced with %XX equivalents as defined by the URI
  1976.   RFC document. </li><p>
  1977.  
  1978. </ul>
  1979.  
  1980. The transform module also be used to intercept and insert intermediate
  1981. processing steps when <b>response.writeStatic()</b>,
  1982. <b>response.writeExpr()</b> and <b>response.write()</b> are called to emit
  1983. static html, expressions and dynamic content, respectively. It can be useful,
  1984. for example, to automatically ensure that expressions never produce output
  1985. that is HTML-unsafe, in other words strings that contain characters such as
  1986. [[=transform.html_encode('''&, < and >''')]]. Many interesting processing
  1987. functions can be defined. By default, the transform module leaves all output
  1988. untouched. These processing functions, called filters, can be inserted via the
  1989. following module functions: <p>
  1990.  
  1991. <ul>
  1992.  
  1993.   <li><b>static</b>( [ fn ] ): <br> Defines the processing performed on all
  1994.   static HTML strings from this point forwards. The <b>fn</b> parameter is
  1995.   explained below.</li><p>
  1996.  
  1997.   <li><b>expr</b>( [ fn ] ): <br> Defines the processing performed on all the
  1998.   results of all expression tags from this point forwards. The <b>fn</b>
  1999.   parameter is explained below.</li><p>
  2000.  
  2001.   <li><b>dynamic</b>( [ fn ] ): <br> Defines the processing performed on all
  2002.   dynamic content generated, i.e. content generated using response.write in the
  2003.   code tags. The <b>fn</b> parameter is explained below. </li><p>
  2004.  
  2005. </ul>
  2006. <p>
  2007.  
  2008. Each of the functions above take a single, optional parameter, which specifies
  2009. the processing to be performed. The parameter can be one of the following
  2010. types:
  2011.  
  2012. <ul>
  2013.  
  2014.   <li><b>None</b>: <br> If the paramter is None, or omitted, then no processing
  2015.   is performed other converting the output to a string. </li><p>
  2016.  
  2017.   <li><b>Function</b>: <br> If a parameter of function type is specified, then
  2018.   that function is called to process the output. The output can be any Python
  2019.   type, and the output may be any Python type. The result is then converted
  2020.   into a string for output. The first parameter to a filter will always be the
  2021.   object to be processed for output. However, the function should be properly
  2022.   defined so as to possibly accept other parameters. The details of how to
  2023.   define filters are explained below. </li><p>
  2024.   
  2025.   <li><b>String</b>: <br> If a paramter of string type is specified, then the
  2026.   string should be of the following format: <font
  2027.     face=courier>"file:name"</font>, where <b>file</b> is the location where
  2028.   the function is defined and <b>name</b> is the name of the filter. The file
  2029.   component is optional, and is searched for using the standard module-finding
  2030.   rules. If only the function name is specified, then the default location
  2031.   (inside the transform module itself) is used, where the standard Spyce
  2032.   filters reside. The standard Spyce filters are described below. </li><p>
  2033.   
  2034.   <li><b>List</b> / <b>Tuple</b>: <br> If a parameter of list or tuple type is
  2035.   specified, its elements should be functions, strings, lists or
  2036.   tuples. The compound filter is recursively defined as
  2037.   <font face=courier>f=fn(...f2(f1())...)</font>, for the parameter
  2038.   <font face=courier>(f1,f2,...,fn)</font>.
  2039.   </li><p>
  2040.  
  2041. </ul>
  2042. <p>
  2043.  
  2044. Having explained how to install filters, we now list the standard Spyce
  2045. filters and show how they are used:
  2046.  
  2047. <ul>
  2048.  
  2049.   <li><b>ignore_none</b>( o ): <br> Emits any input <b>o</b> except for None,
  2050.   which is converted into an empty string. </li><p>
  2051.  
  2052.   <li><b>truncate</b>( o, [maxlen] ): <br> If <b>maxlen</b> is specified,
  2053.   then only the first maxlen characters of input <b>o</b> are returned,
  2054.   otherwise the entire original. </li><p>
  2055.  
  2056.   <li><b>html_encode</b>( o, [also] ): <br> Converts any '&', '<' and
  2057.   '>' characters of input <b>o</b> into HTML entities for safe inclusion in
  2058.   among HTML. The optional <b>also</b> parameter can specify, additional
  2059.   characters that should be entity encoded.</li><p>
  2060.  
  2061.   <li><b>url_encode</b>( o ): <br> Converts input <b>o</b> into a URL-encoded
  2062.   string. </li><p>
  2063.  
  2064.   <li><b>nb_space</b>( o ): <br> Replaces all spaces in input <b>o</b> with
  2065.   "&nbsp;". </li><p>
  2066.  
  2067.   <li><b>silence</b>( o ): <br> Outputs nothing. </li><p>
  2068.  
  2069. </ul>
  2070. <p>
  2071.  
  2072. The optional parameters to some of these filters can be passed to the various
  2073. write functions as <b>named parameters</b>. They can also be specified in an
  2074. expression tag, as in the following example. (One should simply imagine that
  2075. the entire expression tag is replaced with a call to response.writeExpr).
  2076.  
  2077. <table align=center border=0><tr><td><font face=courier>
  2078. [[.compact mode=off]]
  2079. <b><pre>\[[.import name=transform\]]
  2080. \[[ transform.expr(("truncate", "html_encode")) \]]
  2081. \[[='This is an unsafe (< > &) string... '*100, <font color=#ff0000>maxlen=500</font>\]] </pre></b>
  2082. [[.compact]]
  2083. </font></td></tr></table>
  2084. <p>
  2085.  
  2086. In the example above, the unsafe string is repeated 100 times. It is then
  2087. passed through a <font face=courier>truncate</font> filter that will accept
  2088. only the first 500 characters. It is then passed through the <font
  2089.   face=courier>html_encode</font> filter that will convert the unsafe
  2090. characters into their safe, equivalent HTML entities. The resulting string is
  2091. emitted.<p>
  2092.  
  2093. The parameters (specified by their names) are simply accepted by the
  2094. appropriate write method (writeExpr() in the case above) and passed along to
  2095. the installed filter. Note that in the case of compound filters, the
  2096. parameters are passed to <b>ALL</b> the functions. The html_encode filter is
  2097. written to ignore the maxlen parameter, and does not fail. <p>
  2098.  
  2099. For those who would like to write their own filters, looking at the definition
  2100. of the truncate filter will help. The other standard filters are in <font
  2101.   face="courier">modules/transform.py</font>.
  2102.  
  2103. <table align=center border=0><tr><td><font face=courier>
  2104. [[.compact mode=off]]
  2105. <b><pre>def truncate(o, maxlen=None, **kwargs):</pre></b>
  2106. [[.compact]]
  2107. </font></td></tr></table>
  2108. <p>
  2109.  
  2110. When writing a filter, any function will do, but it is strongly advised to
  2111. follow the model above. The important points are:
  2112.  
  2113. <ul>
  2114.  
  2115.   <li>The input o can be of <b>any type</b>, not only a string.</li>
  2116.  
  2117.   <li>The function <b>result</b> does not have to be string either. It is
  2118.   automatically stringified at the end.</li>
  2119.  
  2120.   <li>The function can accept <b>parameters</b> that modify its behaviour, such
  2121.   as maxlen, above.</li>
  2122.   
  2123.   <li>It is recommended to provide convenient user <b>defaults</b> for all
  2124.   parameters.</li>
  2125.  
  2126.   <li>The last parameter should be <b>**kwargs</b> so that unneeded parameters
  2127.   are quietly passed along.</li>
  2128.  
  2129. </ul>
  2130. <p>
  2131.  
  2132. Lastly, one can retrieve filters. This can be useful when creating new
  2133. functions that depend on existing filters, but can not be compounded using the
  2134. tuple syntax above. For example, one might use one filter or another
  2135. conditionally. For whatever purpose, the following module function is provided
  2136. to retreive standard Spyce filters, if needed: <p>
  2137.  
  2138. <ul>
  2139.  
  2140.   <li><b>create</b>( [ fn ] ): <br> Returns a filter. The <b>fn</b> parameter
  2141.   can be of type None, function, string, list or tuple and is handled as in
  2142.   the installation functions discussed above. </li><p>
  2143.  
  2144. </ul>
  2145.  
  2146. The transform module is flexible, but not complicated to use. The example
  2147. below is <i>not</i> examplary of typical use. Rather it highlights some of the
  2148. flexibility, so that users can think about creative uses.<p>
  2149.  
  2150. [[includeCode('examples/transform.spy') ]] <p>
  2151.  
  2152. [[toc.n('Redirect', 'mod_redirect')]]
  2153.  
  2154. The redirect module allows requests to be redirected to different pages, by
  2155. providing the following methods:
  2156.  
  2157. <ul>
  2158.  
  2159.   <li><b>internal</b>( file ): <br> Performs an internal redirect. All
  2160.   processing on the current page ends, the output buffer is cleared and
  2161.   processing continues at the named <b>file</b>. The browser URI remains
  2162.   unchanged, and does not realise that a redirect has even occurred during
  2163.   processing. </li><p>
  2164.  
  2165.   <li><b>external</b>( uri, [permanent] ): <br> Performs an external redirect
  2166.   using the HTTP Location header to a new <b>uri</b>. Processing of the
  2167.   current file continues, but the content is ignored (ie. the buffer is
  2168.   cleared at the end). The status of the document is set to 301 MOVED
  2169.   PERMANENTLY or 302 MOVED TEMPORARILY, depending on the <b>permanent</b>
  2170.   boolean parameter, which defaults to false or temporary. The redirect
  2171.   document is sent to the browser, which requests the new relative uri.
  2172.   </li><p>
  2173.  
  2174.   <li><b>externalRefresh</b>( uri, [seconds] ): <br> Performs an external
  2175.   redirect using the HTTP Refresh header a new <b>uri</b>. Processing of the
  2176.   current file continues, and will be displayed on the browser as a regular
  2177.   document. Unless interrupted by the user, the browser will request the new
  2178.   URL after the specified number of <b>seconds</b>, which defaults to zero if
  2179.   omitted. Many websites use this functionality to show some page, while a
  2180.   file is being downloaded. To do this, one would show the page using Spyce,
  2181.   and redirect with an externalRefresh to the download URI. Remember to set
  2182.   the <font face=courier>Content-Type</font> on the target download file page
  2183.   to be something that the browser can not display, only download. </li><p>
  2184.  
  2185. </ul>
  2186.  
  2187. The example below, shows the possible redirects in use:<p>
  2188.  
  2189. [[includeCode('examples/redirect.spy') ]] <p>
  2190.  
  2191. [[toc.n('Cookie', 'mod_cookie')]]
  2192.  
  2193. This module provides cookie functionality. Its methods are:
  2194.  
  2195. <ul>
  2196.  
  2197.   <li><b>get</b>( [key] ): <br> Return a specific cookie string sent by the
  2198.   browser. If the optional cookie <b>key</b> is omitted, a dictionary of all
  2199.   cookies is returned. The cookie module may also be accessed as an
  2200.   associative array to achieve the same result as calling: namely, <font
  2201.     face=courier>cookie['foo']</font> and <font
  2202.     face=courier>cookie.get('foo')</font> are equivalent. </li><p>
  2203.  
  2204.   <li><b>set</b>( key, value, [expire], [domain], [path], [secure] ): <br>
  2205.   Sends a cookie to the browser. The cookie will be sent back on
  2206.   <i>subsequent</i> requests and can be retreived using the get function. The
  2207.   <b>key</b> and <b>value</b> parameters are required; the rest are optional.
  2208.   The <b>expire</b> parameter determines how long this cookie information will
  2209.   remain valid. It is specified in seconds from the current time. If expire is
  2210.   omitted, no expiration value will be provided along with the cookie header,
  2211.   meaning that the cookie will expire when the browser is closed. The
  2212.   <b>domain</b> and <b>path</b> parameters specify when the cookie will get
  2213.   sent; it will be restricted to certain document paths at certain domains,
  2214.   based on the cookie standard. If these are omitted, then path and/or domain
  2215.   information will not be sent in the cookie header. Lastly, the <b>secure</b>
  2216.   parameter, which defaults to false if omitted, determines whether the cookie
  2217.   information can be sent over an HTTP connection, or only via HTTPS. </li><p>
  2218.  
  2219.   <li><b>delete</b>( key ): <br> Send a cookie delete header to the browser to
  2220.   delete the <b>key</b> cookie. The same may be achieved by: <font
  2221.     face=courier>del cookie[key]</font>. </li><p>
  2222.  
  2223. </ul>
  2224.  
  2225. The example below shows to manage browser cookies.<p>
  2226.  
  2227. [[includeCode('examples/cookie.spy') ]] <p>
  2228.  
  2229. [[toc.n('Session', 'mod_session')]]
  2230.  
  2231. Sessions allow information to be efficiently passed from one request to the
  2232. next via some browser mechanism: get, post or cookie. The potentially large or
  2233. sensitive information is stored at the server, and only a short identifier is
  2234. sent to the client. Sessions are often used to create sequences of pages that
  2235. represent an application flow. This module manages session state. All session
  2236. state has an expiration time and is automatically garbage collected.
  2237.  
  2238. <ul>
  2239.  
  2240.   <li><b>setHandler</b>( type, [ params ] ): <br> Selects the session handler.
  2241.   This method must be called before invoking other session functions. The
  2242.   <b>type</b> specifies the handler, and the <b>param(s)</b> is (are) passed
  2243.   to the initialiser of the chosen handler. The type parameter is a string of
  2244.   the format: <font face=courier>"file:class"</font>, where <b>file</b> is the
  2245.   location where the session handler is defined and <b>class</b> is the name
  2246.   of the session handler. The file name component is optional, and is searched
  2247.   for using the standard module-finding rules. If only the class name is
  2248.   specified, then the default location is used: inside the session module
  2249.   itself, where the standard Spyce session handlers reside. <p>
  2250.  
  2251.   The standard Spyce session handlers are listed below, along with the
  2252.   parameters they take. If you would like to implement your own, custom
  2253.   session handler, there are two ways to do so. First, you can have a look at
  2254.   <font face=courier>modules/session.py</font> and define your subclass of the
  2255.   <font face=courier>sessionHandler</font> class. One would do this when
  2256.   defining a general-purpose session handler, and if you do go to this
  2257.   trouble, please email it in as a <a
  2258.   href="http://spyce.sourceforge.net/contrib/index.html">contribution</a>.
  2259.   Alternatively, you can simply use the <b>session_user</b> handler, also
  2260.   defined below, to your own install callback functions. The majority of users
  2261.   should be satisfied with the basic session handlers provided. <p>
  2262.  
  2263.   <ul>
  2264.  
  2265.     <li>setHandler( <b>'session_dir'</b>, directory ): <br> Uses inidividual
  2266.     files in the specified <b>directory</b> to store session information.
  2267.     </li><p>
  2268.  
  2269.     <li>setHandler( <b>'session_gdbm'</b>, file ): <br> Uses the gdbm library
  2270.     to create and manage the session information inside the specified
  2271.     <b>file</b>. </li><p>
  2272.  
  2273.     <li>setHandler( <b>'session_bsddb'</b>, file ): <br> Uses the BSD database
  2274.     library to create and manage the session information inside the specified
  2275.     <b>file</b>. </li><p>
  2276.  
  2277.     <li>setHandler( <b>'session_user'</b>, getf, setf, delf, idsf, info ):
  2278.     <br> Uses user-provided functions to create and manage session
  2279.     information. The parameters are as follows:
  2280.  
  2281.     <ul>
  2282.  
  2283.       <li><b>getf</b>: A function that will be called to get session state, as
  2284.       follows: <font face=courier>getf(info, id)</font>, where
  2285.       <b>info</b> is the parameter given to setHandler above, and <b>id</b> is
  2286.       the session identifier. This function should ensure that the session has
  2287.       not expired. If an expired session is found, it must be automatically
  2288.       deleted. Note that a delete may never be called on an object, so it is
  2289.       imperative for getf() to delete objects when expiration is detected. If
  2290.       the session has expired, or if the session does not exist, this function
  2291.       should return None, otherwise the session information. </li>
  2292.  
  2293.       <li><b>setf</b>: A function that will be called to set or create session
  2294.       state, as follows: <font
  2295.       face=courier>setf(info, state, expire, serverID, id)</font>,
  2296.       where <b>info</b> is the parameter given to setHandler above,
  2297.       <b>state</b> is the actual session information to be preserved,
  2298.       <b>expire</b> is the number of seconds after which this information will
  2299.       be invalidated, <b>serverID</b> is a unique identifier for this server
  2300.       that can be used to avoid race conditions between two Spyce engines
  2301.       generating new session identifiers, and <b>id</b> is the optional
  2302.       session identifier. If an identifier is provided, that session should be
  2303.       updated, otherwise (namely, in the case when id is set to None), a new
  2304.       session identifier should be generated. This function returns the (new
  2305.       or old) session identifier. </li>
  2306.  
  2307.       <li><b>delf</b>: A function that will be called to set delete a session,
  2308.       as follows: <font face=courier>delf(info, id)</font>, where
  2309.       <b>info</b> is the parameter given to the setHandler above and <b>id</b>
  2310.       is the session identifier of the session to be invalidated. </li>
  2311.  
  2312.       <li><b>idsf</b>: A function that will be called to get all the session
  2313.       identifiers, as follows: <font face=courier>idsf(info)</font>, where
  2314.       <b>info</b> is the parameter given to the setHandler above. This
  2315.       function should return ALL session identifiers, even those that have
  2316.       expired and are to be deleted. Among other purposes, this function is
  2317.       used to automatically clean up session state periodically, by performing
  2318.       a getf() on all sessions. (Remember that according to the semantics
  2319.       defined for getf(), it will delete any expired sessions.) </li>
  2320.  
  2321.       <li><b>info</b>: At the very least, this is a key that uniquely
  2322.       identifies this session handler. The info variable may also contain any
  2323.       other additional information. It is passed back as-is to each of the
  2324.       session callback functions, as described previously. </li>
  2325.  
  2326.     </ul> <p>
  2327.   
  2328.   </ul>
  2329.   <p>
  2330.   
  2331.  
  2332.   <li><b>get</b>( id ): <br> Returns the object stored under the given
  2333.   <b>id</b>. If the id does not exist, or was previously used but has expired,
  2334.   then None is returned. As with the cookie module, the session module may be
  2335.   treated as an associative array when retrieving session information.
  2336.   </li><p>
  2337.  
  2338.   <li><b>set</b>( data, expire, [id] ): <br> Stores the <b>data</b> object
  2339.   under the given <b>id</b>. If id is omitted, then a unique one is generated.
  2340.   On success, an id is returned, otherwise an exception raised. The
  2341.   <b>expire</b> field specifies the number of seconds that the session
  2342.   information is valid for. </li><p>
  2343.  
  2344.   <li><b>delete</b>( id ): <br> Deletes the session stored under the given
  2345.   <b>id</b>. Note that sessions are automatically deleted upon expiration, so
  2346.   this method need only be used when immediate invalidation is desired. As
  2347.   with the cookie module, the session module may be treated as an associative
  2348.   array when removing session information. </li><p>
  2349.  
  2350.   <li><b>autoSession</b>( expire, [method], [name] ): <br> This function can
  2351.   remove most of the code associated with session management, by doing it
  2352.   automatically. Namely, it automatically retrieves the session information
  2353.   and resaves it at the end of the request, using the <b>auto</b>,
  2354.   <b>autoID</b>, <b>autoName</b> and <b>autoMethod</b> fields (explained
  2355.   below). The <b>expire</b> parameters acts as before, to specify how long the
  2356.   session information remains valid. The <b>method</b> and <b>name</b>
  2357.   parameters instruct the session module how to find the session identifier.
  2358.   Method can be one of <font face=courier>'get'</font>, <font
  2359.   face=courier>'post'</font>, or <font face=courier>'cookie'</font>, which is
  2360.   the default. The name parameter, under which the session id is stored,
  2361.   defaults to 'spyceSession'. If the lookup is unable to find a session id for
  2362.   this request a new session is created. At the end of the request, the
  2363.   session information is automatically saved, and a cookie automatically
  2364.   generated if the 'cookie' method was chosen. For the 'get' and 'post'
  2365.   methods the user is required to encode the <b>autoID</b> (session id) inside
  2366.   all form targets and urls that are generated. </li><p>
  2367.  
  2368.   <li><b>auto</b>: <br> The field containing the actual session information,
  2369.   when automatic session management is used. Set it to whatever you like, as
  2370.   long as it can be serialized. Its initial value, for a new session, is None.
  2371.   </li><p>
  2372.  
  2373.   <li><b>autoID</b>: <br> The session identifier, when automatiic session
  2374.   management is used. </li><p>
  2375.  
  2376.   <li><b>autoName</b>: <br> The variable named used to identify the cookie or
  2377.   the parameter in the get or post requests containing the session identifier,
  2378.   when automatic session management is used.</li><p>
  2379.  
  2380.   <li><b>autoMethod</b>: <br> The method used ('cookie', 'post' or 'get') to
  2381.   load and save the session identifier, when automatic session management is
  2382.   used.</li><p>
  2383.  
  2384. </ul>
  2385.  
  2386. The example below shows how a session can be used to count the number of times
  2387. the same open browser visited our page. The session ID is stored in a cookie
  2388. that expires when the browser is closed. Note that the session module
  2389. automatically loads the cookie module if not already loaded and is needed.<p>
  2390.  
  2391. [[includeCode('examples/session.spy')]]
  2392. <p>
  2393.  
  2394. The next example highlights the convenience of using autoSession. By default,
  2395. the session identifier is stored using a cookie named 'spyceSession'.<p>
  2396.  
  2397.  
  2398. [[includeCode('examples/autosession.spy')]]
  2399. <p>
  2400.  
  2401. If cookies are not desired, the automatic session identifier
  2402. <font face=courier>session.autoID</font> can also be transmitted via a browser
  2403. post, as shown:<p>
  2404.  
  2405. [[includeCode('examples/autosessionpost.spy')]] <p>
  2406.  
  2407. Finally, one can easily define some new session handling mechanism using
  2408. callback functions, as this last example shows:
  2409.  
  2410. [[includeCode('examples/mysession.spy')]] <p>
  2411.  
  2412.  
  2413. [[toc.n('Pool', 'mod_pool')]]
  2414.  
  2415. The pool module provides support for server-pooled variables. That is support
  2416. for variables whose lifetime begins when declared, and ends when explicitly
  2417. deleted or when the server dies. These variables are often useful for storing
  2418. persistent database connections and other information that may be expensive to
  2419. compute at each request. Another interesting use of pool variables is to store
  2420. file- or memory-based lock objects for concurrency control. A pooled variable
  2421. can hold any Python value. <p>
  2422.  
  2423. The pool module may be accessed as a regular dictionary, supporting the usual
  2424. <font face=courier>get</font>, <font face=courier>set</font>, <font
  2425.   face=courier>delete</font>, <font face=courier>has_key</font>, <font
  2426.   face=courier>keys</font>, <font face=courier>values</font> and <font
  2427.   face=courier>clear</font> operations. Note that the pool is shared across all
  2428. Spyce files. If file-specific variables are desired, simply include the
  2429. filename in the pool variables name as a tuple [i.e. (filename, variable)], or
  2430. in some other form. <p>
  2431.  
  2432. The pool module also provides access to any server variables that are set in
  2433. the Spyce engine <a href="[[=genTOClink('runtime_common')]]">configuration
  2434.   file</a>. A hashtable of these variables is available as <b>pool.server</b>.
  2435.  
  2436. The example below shows how the module is used:<p>
  2437.  
  2438. [[includeCode('examples/pool.spy')]] <p>
  2439.  
  2440. [[toc.n('Template', 'mod_template')]]
  2441.  
  2442. In general, a template is useful for separating form from function. Or, in
  2443. other words, one would like web page designers to play with one file, and
  2444. programmers to play with another, so that they don't step on each other's
  2445. toes. A templating engine then puts the two pieces (template and data)
  2446. together to create the final output. The Spyce language internally provides <a
  2447.   href="[[=genTOClink('lang_lambda')]]">Spyce lambdas</a>, which can be very
  2448. useful for templating purposes. This module provides hooks to various external
  2449. templating engines. <p>
  2450.  
  2451. Spyce interacts with the rather powerful <a
  2452.   href="http://www.cheetahtemplate.org">Cheetah</a> Python-based templating
  2453. engine. The Cheetah engine is not included with the Spyce distribution, some
  2454. recommended installation instructions are provided below. The Cheetah engine
  2455. is invoked as follows:<p>
  2456.  
  2457. <ul>
  2458.  
  2459.   <li><b>cheetah</b>( file, [lookup] ): <br> Calling this function will invoke
  2460.   the Cheetah engine to compile (and cache) the template <b>file</b> provided.
  2461.   The engine then "runs" the template and fills in the appropriate data from
  2462.   the <b>lookup</b> dictionary, or list of dictionaries. If the lookup is
  2463.   omitted, the convenient default is to use the local and global variables
  2464.   from the current context. The template is filled and the resulting string is
  2465.   returned. </li><p>
  2466.  
  2467. </ul><p>
  2468.  
  2469. To install Cheetah (instructions correct as of version 0.9.15a1), follow the
  2470. following steps:
  2471.  
  2472. <ul>
  2473.  
  2474.   <li>Download the latest Cheetah engine from their <a
  2475.     href="http://www.cheetahtemplate.org">website</a>.</li>
  2476.  
  2477.   <li>Extract the files from the gzipped tarball into some directory</li>
  2478.  
  2479.   <li>Switch to root user</li>
  2480.  
  2481.   <li>In that directory type:
  2482.   <font face=courier>python setup.py install</font></li>
  2483.  
  2484.   <li>Now, change directory to:
  2485.   <font face=courier>/usr/lib/python2.2/site-packages/</font></li>
  2486.  
  2487.   <li>Type in:
  2488.   <font face=courier>chmod -R a+r Cheetah*</font></li>
  2489.  
  2490.   <li>Type in:
  2491.   <font face=courier>chmod a+x `find Cheetah -type d`</font></li>
  2492.  
  2493. </ul>
  2494. <p>
  2495.  
  2496. In general, that the Python path must simply include the Cheetah installation
  2497. directory and Spyce will find it. If not, you will see an import error. At
  2498. this time, the Cheetah engine requires Python version 2.0 or higher.<p>
  2499.  
  2500. Support for other templating engines will be added as needed. An example of
  2501. how templates are used is shown below, with the template files appended
  2502. thereafter.<p>
  2503.  
  2504. [[includeCode('examples/template.spy')]] <p>
  2505.  
  2506. [[includeCode('examples/template.tmpl')]] <p>
  2507.  
  2508. [[toc.n('Compress', 'mod_compress')]]
  2509.  
  2510. The compress module supports dynamic compression of Spyce output, and can save
  2511. bandwidth in addition to static <a
  2512.   href="[[=genTOClink('lang_directive')]]">compaction</a>. The different forms
  2513. of compression supported are described below.
  2514.  
  2515. <ul>
  2516.  
  2517.   <li><b>spaces</b>( [ boolean ] ): <br> Controls dynamic space compression.
  2518.   Dynamic space compression will eliminate consecutive whitespaces (spaces,
  2519.   newlines and tabs) in the output stream, each time it is flushed. The optional
  2520.   <b>boolean</b> parameter defaults to true. <p>
  2521.  
  2522.   <li><b>gzip</b>( [ level ] ): <br> Applies gzip compression to the Spyce
  2523.   output stream, but only if the browser can support gzip content encoding. Note
  2524.   that this function will fail if the output stream has already been flushed,
  2525.   and should generally only be used with buffered output streams. The optional
  2526.   <b>level</b> parameter specifies the compression level, between 1 and 9
  2527.   inclusive. A value of zero disables compression. If level is omitted, the
  2528.   default gzip compression level is used. This function will automatically check
  2529.   the request's <i>Accept-Encoding</i> header, and set the response's
  2530.   <i>Content-Encoding</i> header. <p>
  2531.   
  2532. </ul>
  2533.  
  2534. The example below shows the compression module in use.<p>
  2535.  
  2536. [[includeCode('examples/compress.spy')]]
  2537. <p>
  2538.  
  2539. Note that the compression functions need not be called at the beginning of the
  2540. input, but before the output stream is flushed. Also, to really see what is
  2541. going on, you should telnet to your web server, and provide something like the
  2542. following request.
  2543.  
  2544. [[.compact mode=off]]
  2545. <table border=0 align=center cellspacing=0 cellpadding=0><tr><td>
  2546. <font face=courier>
  2547. <b><pre>GET /spyce/examples/compress.spy HTTP/1.1
  2548. Accept-Encoding: gzip</pre></b>
  2549. </font>
  2550. </td></tr></table>
  2551. [[.compact]] <p>
  2552.  
  2553. [[toc.n('Automaton', 'mod_automaton')]]
  2554.  
  2555. <i>The current release of the automaton module is preliminary and is still in
  2556. flux.</i> The automaton module provides support for state machine-based
  2557. application design, which is often useful when designing websites with
  2558. application flows. The state machine is a directed, labelled graph. It has
  2559. states (nodes with names), and transitions (directed edges with names). One of
  2560. the states is defined to be a <b>begin</b> state for the machine. Every state
  2561. has a <b>send</b> function, a <b>receive</b> function and a set of outgoing
  2562. edges.<p>
  2563.  
  2564. The basic idea behind the operation of the automaton module is as follows: The
  2565. application is at some state when a request comes in. The receive function for
  2566. that state is invoked to process the input from the browser. Based on this
  2567. input the receive function returns some edge label, which takes the
  2568. application from the current state to its new state. The send function of this
  2569. new state is invoked to emit the appropriate application page. The data that
  2570. returns from this page will be processed by the corresponding receive
  2571. function, and so on. All you need to remember between requests is which state
  2572. the application is in, which can be done via get or post, or via cookies using
  2573. the cookie module. Better yet (to keep application states private and on the
  2574. server for security reasons), one can store the state label in the session
  2575. using the session module. <p>
  2576.  
  2577. A state machine can be defined programmatically using the following functions:
  2578.  
  2579. <ul>
  2580.  
  2581.   <li><b>state</b>( name, send, recv ): <br> Add a new state labelled
  2582.   <b>name</b> with associated <b>send</b> and <b>recv</b> functions. </li><p>
  2583.  
  2584.   <li><b>transition</b>( state1, name, state2 ): <br> Add a new edge labelled
  2585.   <b>name</b> from <b>state1</b> to <b>state2</b>. There is always a
  2586.   self-referencing edge with the label None, but this can be overidden.
  2587.   </li><p>
  2588.  
  2589.   <li><b>begin</b>( state ): <br> Define a given state to be the begin state.
  2590.   </li><p>
  2591.  
  2592.   <li><b>define</b>( sm, begin ): <br> Define an entire automaton <b>sm</b>
  2593.   all at once, where sm is a hashtable. The keys are the states and the values
  2594.   are triplets with a send function, a receive function and an edge hashtable.
  2595.   The edge hashtable has names of the edges as keys and the target states as
  2596.   values. The <b>begin</b> state is given. </li><p>
  2597.  
  2598. </ul>
  2599. <p>
  2600.  
  2601. To step through the state machine transitions, you call:
  2602.  
  2603. <ul>
  2604.  
  2605.   <li><b>step</b>( [state] ): <br> If <b>state</b> is specified, then call the
  2606.   receive function of that state. The receive function returns an edge label,
  2607.   which points to the new state. If no state is specified, just set the new
  2608.   state to the begin state of the automaton. Then, call the send function of
  2609.   the new state. Note that the send function is responsible for encoding its
  2610.   own state label, for use on the subsequent client request. </li><p>
  2611.  
  2612. </ul>
  2613. <p>
  2614.  
  2615. Future releases of this module may add support for different types of send and
  2616. receive handlers. For example, it is probably useful to be able to internally
  2617. redirect to various Spyce pages for send processing, rather than inline
  2618. functions. It may also be possible to pass information among the different
  2619. functions, which could be useful, for example, in handling error messages
  2620. during form processing. It may also be useful to define a sequence of states,
  2621. where previous and next are implicit edges.<p>
  2622.  
  2623. The following examples, shows the above in action:<p>
  2624.  
  2625. [[includeCode('examples/automaton.spy')]]
  2626. <p>
  2627.  
  2628. [[toc.n('TOC', 'mod_toc')]]
  2629.  
  2630. The TOC module provides support for constructing a table contents for a
  2631. lengthy document, such as this user documentation. The primary task of the TOC
  2632. module is to maintain a document tree, and initiate callbacks at the
  2633. appropriate points in the document. Note that this module may automatically
  2634. force a secondary processing of the Spyce file to resolve forward references.
  2635. <p>
  2636.  
  2637. The module provides the following methods to segment the document:
  2638.  
  2639. <ul>
  2640.  
  2641.   <li><b>begin</b>( data, [tag] ): <br> Increase the nesting level and add a
  2642.   new section. The <b>data</b> is stored in the document tree, and used for
  2643.   callbacks (see later). An optional <b>tag</b> may be associated with the
  2644.   node, otherwise one will automatically be generated. The function <b>b</b>()
  2645.   is equivalent. </li><p>
  2646.   
  2647.   <li><b>next</b>( data, [tag] ): <br> Add a new section at the same nesting
  2648.   level. The <b>data</b> is stored in the document tree, and used for
  2649.   callbacks (see later). An optional <b>tag</b> may be associated with the
  2650.   node, or one will be automatically generated. The function <b>n</b>() is
  2651.   equivalent.</li><p>
  2652.  
  2653.   <li><b>end</b>(): <br> Decrease the nesting level. The function <b>e</b>()
  2654.   is equivalent.</li><p>
  2655.  
  2656.   <li><b>anchor</b>( data, [tag] ): <br> Set <b>data</b> and optionally the
  2657.   <b>tag</b> associated with the root of the document tree. If the tag is
  2658.   omitted, it defaults to the string <i>'root'</i>. </li><p>
  2659.  
  2660.   <li><b>level</b>( depth, data, [tag] ): <br> Start a new section at given
  2661.   <b>depth</b> with given <b>data</b> and optional <b>tag</b>. The necessary
  2662.   begin(), next() and end() calls are automatically made, based on the current
  2663.   document depth, so both types of calls can be inter-mixed. </li> <p>
  2664.  
  2665.   <li><b>l1</b>( data, [tag] ): <br> Start a level 1 section. This
  2666.   function merely calls <b>level</b>(1, <b>data</b>, <b>tag</b>).
  2667.   The functions, <b>l2</b>()...<b>l9</b>() are similarly defined. </li> <p>
  2668.  
  2669. </ul> <p>
  2670.  
  2671. The following methods provide access to document information:
  2672.  
  2673. <ul>
  2674.  
  2675.   <li><b>getTag</b>(): <br> Return the tag of the current document section.
  2676.   </li><p>
  2677.  
  2678.   <li><b>getNumbering</b>( [tag] ) <br> Return the numbering of some section
  2679.   of the document identified by the given <b>tag</b>. If the tag is omitted,
  2680.   the current document section is assumed. The numbering is an array of
  2681.   numbers. This function may return 'None' on the first pass through a
  2682.   document. </li><p>
  2683.  
  2684.   <li><b>getData</b>( [tag] ) <br> Return the data associated with some
  2685.   section of the document identified by the given <b>tag</b>. If the tag is
  2686.   omitted, the current document section is assumed. This function may return
  2687.   'None' on the first pass through a document. </li><p>
  2688.  
  2689.   <li><b>getDepth</b>( [tag] ) <br> Return the depth of some section of the
  2690.   document identified by the given <b>tag</b>. If the tag is omitted, the
  2691.   current document section is assumed. This function may return 'None' on the 
  2692.   first pass through a document. </li><p>
  2693.  
  2694.   <li><b>getNextTag</b>( [tag] ) <br> Return the tag of the section following
  2695.   some section of the document identified by the given <b>tag</b>. If the tag
  2696.   is omitted, the current document section is assumed. If this is the last
  2697.   section of the document, then this function will return 'None'. This
  2698.   function may return 'None' on the first pass through a document. </li><p>
  2699.  
  2700.   <li><b>getPrevTag</b>( [tag] ) <br> Return the tag of the section before
  2701.   some section of the document identified by the given <b>tag</b>. If the tag
  2702.   is omitted, the current document section is assumed. If this is the first
  2703.   section of the document, then this function will return 'None'. This
  2704.   function may return 'None' on the first pass through a document. </li><p>
  2705.  
  2706.   <li><b>getParentTag</b>( [tag] ) <br> Return the tag of the section above
  2707.   (or containing) some section of the document identified by the given
  2708.   <b>tag</b>. If the tag is omitted, the current document section is assumed.
  2709.   If this is the top-most section of the document, then this function will
  2710.   return 'None'. This function may return 'None' on the first pass through a
  2711.   document. </li><p>
  2712.  
  2713.   <li><b>getChildrenTags</b>( [tag] ) <br> Return a list (possibly empty) of
  2714.   tags of the sections directly contained within some section of the document
  2715.   identified by the given <b>tag</b>. If the tag is omitted, the current
  2716.   document section is assumed. This function may return a shorter list than
  2717.   anticipated or 'None', on the first pass through a document.
  2718.   
  2719. </ul> <p>
  2720.  
  2721. The TOC modules can make callbacks to handlers that format the document
  2722. correctly. The handlers should be defined and registered before the first
  2723. section break in the document. The following functions register handlers:
  2724.  
  2725. <ul>
  2726.  
  2727.   <li><b>setDOC_PUSH</b>( f ): <br> Register a function <b>f</b> to be called
  2728.   when the nesting depth of the document increases. </li><p>
  2729.  
  2730.   <li><b>setDOC_POP</b>( f ): <br> Register a function <b>f</b> to be called
  2731.   when the nesting depth of the document decreases. </li><p>
  2732.  
  2733.   <li><b>setDOC_START</b>( f ): <br> Register a funtion <b>f</b> to be called
  2734.   at the beginning of a section. </li><p>
  2735.  
  2736.   <li><b>setDOC_END</b>( f ): <br> Register a function <b>f</b> to be called
  2737.   at the end of a section. </li><p>
  2738.  
  2739.   <li><b>setTOC_PUSH</b>( f ): <br> Register a function <b>f</b> to be called
  2740.   when the nesting depth of the table of contents increases. </li><p>
  2741.  
  2742.   <li><b>setTOC_POP</b>( f ): <br> Register a function <b>f</b> to be called
  2743.   when the nesting depth of the table of contents decreases. </li><p>
  2744.  
  2745.   <li><b>setTOC_ENTRY</b>( f ): <br> Register a function <b>f</b> to be called
  2746.   for each table of contents entry. </li><p>
  2747.  
  2748. </ul><p>
  2749.  
  2750. Each callback function should be of the form: <center> <b>f</b>(depth,
  2751. tag, numbering, data), </center> where: <b>depth</b> is the nesting depth,
  2752. <b>tag</b> is the associated tag, <b>numbering</b> is the position array, and
  2753. <b>data</b> is the associated data of the section for which the callback was
  2754. made.<p>
  2755.  
  2756. The <i>DOC</i> callbacks are made as the sections are encountered. The
  2757. <i>TOC</i> callbacks are made while printing the table of contents. If the
  2758. modules detects that forward references exist in the document, the document
  2759. will be processed twice, and only the second output will be sent. Note that
  2760. buffering MUST be turned on for this to function correctly. <p>
  2761.  
  2762. To display a table of contents, define the appropriate TOC callback functions
  2763. and call:
  2764.  
  2765. <ul>
  2766.  
  2767.   <li><b>showTOC</b>(): Display the table of contents.
  2768.   
  2769. </ul>
  2770.  
  2771. For an example of how to use the TOC module, please refer to the source Spyce
  2772. file of this documentation. <p>
  2773.  
  2774. [[--includeCode('examples/automaton.spy')--]]
  2775. <p>
  2776.  
  2777. [[toc.n('Writing Modules', 'mod_new')]]
  2778.  
  2779. Writing your own Spyce modules is simple. Let us begin with a basic example
  2780. called myModule. It is a module that implements one function named foo().
  2781.  
  2782. [[includeCode('examples/myModule.py', run=0)]]
  2783. <p>
  2784.  
  2785. Saving this code in <font face=courier>myModule.py</font> in the same
  2786. directory as the Spyce script, or somewhere on the module path, we could use
  2787. it as expected: <p>
  2788.  
  2789. <table align=center border=0><tr><td><font face=courier>
  2790. [[.compact mode=off]]
  2791. <b><pre>\[[.import name=myModule\]]
  2792. \[[ myModule.foo() \]]
  2793. </pre></b>
  2794. [[.compact]]
  2795. </font></td></tr></table>
  2796. <p>
  2797.  
  2798. A Spyce module can be any Python class that derives from
  2799. <b>spyceModule.spyceModule</b>. Do not override the <b> __init__(...)</b>
  2800. method because it is inherited from spyceModule and has an fixed signature
  2801. that is expected by the Spyce engine's module loader. The inherited method
  2802. accepts a Spyce API object, a <a
  2803. href="http://www.python.org/doc/current/lib/module-Bastion.html">Bastion</a>
  2804. of <b>spyce.spyceWrapper</b>, an internal engine object, and stores it in
  2805. <b>self._api</b>. This is the building block for all the functionality that
  2806. any module provides. The available API methods of the wrapper are (listed in
  2807. spyceModule.spyceModuleAPI): 
  2808.  
  2809. <ul>
  2810.  
  2811.   [[ for api in spyceModule.spyceModuleAPI: { ]]
  2812.  
  2813.   <li> <b>[[=api]]</b>: [[=eval('spyce.spyceWrapper.%s.__doc__'%api)]]</li>
  2814.  
  2815.   [[ } ]]
  2816.  
  2817. </ul> <p>
  2818.  
  2819. For convenience, one can sub-class the <b>spyceModulePlus</b> class instead of
  2820. the regular <b>spyceModule</b>. The spyceModulePlus defines a
  2821. <b>self.modules</b> field, which can be used to acquire references to other
  2822. modules loaded into the Spyce environment. The <i>response</i> module, for
  2823. instance, would be referenced as <i>self.modules.response</i>. Modules are
  2824. loaded on demand, if necessary. The spyceModulePlus also contains a
  2825. <b>self.globals</b> field, which is a reference to the Spyce global namespace
  2826. dictionary, though this should rarely be needed. <p>
  2827.  
  2828. <b>Note:</b> It is not expected that many module writers will need the entire
  2829. API functionality. In fact, the vast majority of modules will use a small
  2830. portion of the API, if at all. Many of these functions are included for just
  2831. one of the standard Spyce modules that needs to perform some esoteric
  2832. function. <p>
  2833.  
  2834. Three Spyce module methods, <b>start()</b>, <b>init([args])</b> and
  2835. <b>finish(error)</b> are special in that they are automatically called by the
  2836. runtime during Spyce request startup, processing and cleanup, respectively.
  2837. The modules are started in the order in which module directives appear in the
  2838. file, before processing begins. The implicitly loaded modules are always
  2839. loaded first. The init method is called during Spyce processing at the
  2840. location of the module directive in the file, with the optional args attribute
  2841. is passed as the arguments of this call. Finally, after Spyce processing is
  2842. complete, the modules are finalized in reverse order. If there is an unhandled
  2843. exception, it will be wrapped in a spyce.spyceException object and passed as
  2844. the first parameter to finish(). During successful completion of Spyce
  2845. processing (i.e. without exception), the error parameter is None. The default
  2846. inherited start, init and finish methods from spyceModule are noops. <p>
  2847.  
  2848. <b>Note 2:</b> When writing a Spyce module, consider carefully why you are
  2849. selecting a Spyce module over a regular Python module. If it is just code,
  2850. that does not interact with the Spyce engine, then a regular Python <font
  2851. face=courier>import</font> instead of an Spyce <font
  2852. face=courier>\[[.import\]]</font> can just as easily bring in the necessary
  2853. code, and is preferred. In other words, choose a Spyce module only when there
  2854. is a need for per-request initialization or for one of the engine APIs. <p>
  2855.  
  2856. Module writers are encouraged to look at the existing standard modules as
  2857. examples and the definitions of the core Spyce objects in <font
  2858.   face=courier>spyce.py</font> as well. If you write or use a novel Spyce
  2859. module that you think is of general use, please email your <a
  2860.   href="http://spyce.sourceforge.net/contrib/index.html">contribution</a>, or
  2861. a link to it. Also, please keep in mind that the standard modules are designed
  2862. with the goal of being minimalist. Much functionality is readily available
  2863. using the Python language libraries. If you think that they should be
  2864. expanded, also please send a note. <p>
  2865.  
  2866. [[toc.e()]]
  2867.  
  2868. [[toc.n('Tags', 'tag')]]
  2869.  
  2870. The previous chapter discussed the Spyce module facility, the standard Spyce
  2871. modules and how users can create their own modules to extend Spyce. Spyce
  2872. functionality can also be extended via active tags, which are defined in tag
  2873. libraries. This chapter describes what Spyce active tags are, and how they are
  2874. used. We then describe each of the standard active tag libraries and, finally,
  2875. how to define <a href="[[=genTOClink('tag_new')]]">new tags libraries</a>. <p>
  2876.  
  2877. It is important, from the outset, to define what an active tag actually does.
  2878. A few illustrative examples may help. The examples below all use tags that are
  2879. defined in the <a href="[[=genTOClink('tag_core')]]">core tag library</a>,
  2880. that has been installed under the <b>spy</b> prefix, as follows: <p>
  2881.  
  2882. [[.compact mode=off]]
  2883. <table border=0 align=center><tr><td>
  2884. <font size="-1"><font face=courier>
  2885. <b><pre>[[=escapeHTMLandCode('''
  2886.   %s.taglib name=core as=spy %s
  2887. ''' % ('['*2, ']'*2) )]]</pre></b>
  2888. </font></font>
  2889. </td></tr></table><p>
  2890. [[.compact]]
  2891.  
  2892. <ul>
  2893.  
  2894.   <li><font face=courier><spy:print val="=2+2"/></font> <br> Rather
  2895.   than emitting itself as plain text, this tag will output <font
  2896.   face=courier>4</font>. </li> <p>
  2897.  
  2898.   <li><font face=courier><spy:let var="foo" val="bar"/></font> <br> This
  2899.   tag will assign the constant string value <font face=courier>bar</font> to a
  2900.   variable named <b>foo</b> in the tag context, which will then be available
  2901.   to other tags that follow later in the document. </li> <p>
  2902.  
  2903.   <li><font face=courier> <spy:for items="=range(5)"> <br>
  2904.     <spy:print value="=foo"/> <br> </spy:for> </font>
  2905.   <br> As expected, these tags will print the value of <b>foo</b>, set to
  2906.   <font face=courier>bar</font> above, 5 times. </li> <p>
  2907.  
  2908. </ul>
  2909.  
  2910. Note that the same output could have been achieved in many different ways, and
  2911. entirely without active tags. The manner in which you choose to organize your
  2912. script or application, and when you choose active tags over other
  2913. alternatives, is a matter of personal preference. Notice also that active tags
  2914. entirely control their output and what they do with their attributes and the
  2915. result of processing their bodies (in fact, whether the body of the tag is
  2916. even processed). Tags can even supply additional syntax constraints on their
  2917. attributes that will be enforced at compile-time. Most commonly a tag could
  2918. require that certain attributes exist, and possibly that it be used only as a
  2919. single or only as a paired (open and close) tag. Unlike early versions of
  2920. HTML, active tags must be strictly balanced, and this will be enforced by the
  2921. Spyce compiler. <p>
  2922.  
  2923. Below, each individual standard Spyce tag library is documented, followed by a
  2924. description of how one would write a <a href="[[=genTOClink('tag_new')]]">new
  2925. active tag library</a>. The following general information will be useful for
  2926. reading that material.
  2927.  
  2928. <ul>
  2929.  
  2930.   <li>Active tags are installed using the <font
  2931.   face=courier>\[[.taglib\]]</font> <a
  2932.   href="[[=genTOClink('lang_directive')]]">directive</a>, under some prefix.
  2933.   Active tags are of the format <font
  2934.   face=courier><pre:name ... ></font>, where <b>pre</b> is the
  2935.   prefix under which the tag library was installed, and <b>name</b> is defined
  2936.   by the tag library. In the following tag library documentation, the prefix
  2937.   is omitted from the syntax. </li>
  2938.  
  2939.   <li>Tags store variables and evaluated expression within a separate tag
  2940.   context. This tag context dictionary is available via <b>taglib.context</b>
  2941.   (i.e. the context field of the <a
  2942.   href="[[=genTOClink('mod_taglib')]]">taglib module</a>). The tag context
  2943.   contains references to all the loaded modules. Thus, it is valid to refer to
  2944.   something like <font face=courier>request.query()</font> in a tag
  2945.   expression. However, it is not valid to change any module variable
  2946.   references. While this will not cause any harm, the user should expect that
  2947.   these new values can be reset at any time. </li>
  2948.  
  2949.   <li>The following notation is used in the documentation of the tag libraries
  2950.   below:
  2951.  
  2952.   <ul>
  2953.  
  2954.     <li> <name .../> : The tag should be used as a singleton. </li>
  2955.  
  2956.     <li> <name ... > ... </name> : The tag should be used as an
  2957.     open-close pair. </li>
  2958.  
  2959.     <li> [ x ] : The attribute is optional. Attributes not enclosed in
  2960.     brackets are required. </li>
  2961.  
  2962.     <li> foo|<u>bar</u> : indicates that an attribute may be one of two
  2963.     constant strings. The underlined value is the default. </li>
  2964.  
  2965.     <li> <i>string</i> : an arbitrary string constant </li>
  2966.  
  2967.     <li> <i>expression</i> : may be a string constant, and may be of the form
  2968.     <font face=courier>'=expr'</font>, where <font face=courier>expr</font> is
  2969.     a Python expression that will be evaluated in the tag context. </li>
  2970.  
  2971.   </ul>
  2972.  
  2973. </ul> <p>
  2974.  
  2975. [[toc.b('Core', 'tag_core')]]
  2976.  
  2977. The core active tag library is modelled after some of the functionality that
  2978. exists in Java's <a href=http://java.sun.com/products/jsp/jstl/>JSTL</a>. It
  2979. is still in the preliminary design stages, and more tags are expected.
  2980. Currently, it provides the following active tags: <p>
  2981.  
  2982. <ul>
  2983.  
  2984.   <li><font face=courier><<b>print</b> val=<i>expression</i>
  2985.   [encode=false|<u>html</u>|url] [default=<i>expression</i>] /></font>
  2986.   <br> Outputs the value of the <b>val</b> expression. If there is an error
  2987.   and a <b>default</b> is provided, the default will be evaluated instead. The
  2988.   output may be encoded to be HTML- or URL-safe, depending on the
  2989.   <b>encode</b> attribute. </li> <p>
  2990.  
  2991.   <li><font face=courier><<b>let</b> var=<i>string</i>
  2992.   val=<i>expression</i> /></font> <br> Sets the variable <b>var</b> to
  2993.   the value <b>val</b> in the tag context. </li> <p>
  2994.  
  2995.   <li><font face=courier><<b>let</b> var=<i>string</i>
  2996.   val=<i>expression</i>> ... </<b>let</b>></font> <br> Same as above,
  2997.   except that the scope of the variable is that of the tag body, and the value
  2998.   of the variable, if it existed prior to the start tag, is restored after the
  2999.   end tag. </li> <p>
  3000.  
  3001.   <li><font face=courier><<b>unlet</b> var=<i>string</i> /></font>
  3002.   <br> Unset (i.e. delete) the variable <b>var</b> in the tag context. </li>
  3003.   <p>
  3004.  
  3005.   <li><font face=courier><<b>if</b> test=<i>expression</i>> ...
  3006.   </<b>if</b>></font> <br> Evaluate <b>test</b> and conditionally
  3007.   process body of tag. </li> <p>
  3008.  
  3009.   <li><font face=courier><<b>for</b> items=<i>expression</i>
  3010.   [var=<i>string</i>] [counter=<i>string</i>]> ...
  3011.   </<b>for</b>></font> <br> Iterate through a tuple or list of
  3012.   <b>items</b> and process the body each time. The current item can optionally
  3013.   be stored in variable named by <b>var</b>, and the current iteration number
  3014.   (starting at zero) can optionally be stored in a variable named by
  3015.   <b>counter</b>. </li> <p>
  3016.  
  3017. </ul> <p>
  3018.  
  3019. [[toc.n('Form', 'tag_form')]]
  3020.  
  3021. The form active tag library is designed to simplify the generation of forms.
  3022. The tags in this library closely follow the names of HTML form tags. The active
  3023. tags automatically look up the appropriate data values or defaults. In time,
  3024. more tags will be added for server-side verification. 
  3025.  
  3026. <ul>
  3027.  
  3028.   <li><font face=courier><<b>form</b>
  3029.   [method=<i>expr</i>] [action=<i>expr</i>] [value=<i>expr</i>] [default=<i>expr</i>] ...> </<b>form</b>></font>
  3030.   <br> Begin a new form. The <b>method</b> parameter is optional and defaults
  3031.   to 'GET'. The <b>action</b> is evaluated in the tag context. Both parameters
  3032.   are emitted. The <b>value</b> parameter is a dictionary of values, which
  3033.   overrides any submitted form values. The <b>default</b> parameter is a
  3034.   dictionary of values that is overridden by any submitted values. </li> <p>
  3035.  
  3036.   <li><font face=courier><<b>submit</b>
  3037.   [name=<i>expr</i>] [value=<i>expr</i>] ... /></font>
  3038.   <br> Create a submit button. The <b>name</b> and <b>value</b> parameters are
  3039.   evaluated within the tag context and emitted. </li> <p>
  3040.  
  3041.   <li><font face=courier><<b>hidden</b>
  3042.   name=<i>expr</i> [value=<i>expr</i>] [default=<i>expr</i>] .../></font>
  3043.   <br> Create a hidden form field. The <b>name</b> parameter is evaluated and
  3044.   emitted. Both the <b>value</b> and <b>default</b> optional parameters are
  3045.   expressions and are evaluated. The value emitted is, in order of decreasing
  3046.   priority: local tag value, form tag value, value in submitted request
  3047.   dictionary, local tag default, form tag default. We search this list for the
  3048.   first non-None value. </li> <p>
  3049.  
  3050.   <li><font face=courier><<b>text</b>
  3051.   name=<i>expr</i> [value=<i>expr</i>] [default=<i>expr</i>] [size=<i>expr</i>] [maxlength=<i>expr</i>] .../></font>
  3052.   <br> Create a form text field. The <b>name</b> parameter is evaluated and
  3053.   emitted. Both the <b>value</b> and <b>default</b> optional parameters are
  3054.   expressions and are evaluated. The value emitted is, in order of decreasing
  3055.   priority: local tag value, form tag value, value in submitted request
  3056.   dictionary, local tag default, form tag default. We search this list for the
  3057.   first non-None value. The <b>size</b> and <b>maxlength</b> optional
  3058.   parameters are evaluated and emitted. </li> <p>
  3059.  
  3060.   <li><font face=courier><<b>password</b>
  3061.   name=<i>expr</i> [value=<i>expr</i>] [default=<i>expr</i>] [size=<i>expr</i>] [maxlength=<i>expr</i>] .../></font>
  3062.   <br> Create a form password field. Parameters are the same as for <b>text</b>
  3063.   fields, explained above. </li> <p>
  3064.  
  3065.   <li><font face=courier><<b>textarea</b>
  3066.   name=<i>expr</i> [value=<i>expr</i>] [rows=<i>expr</i>] [cols=<i>expr</i>] ...>default</<b>textarea</b>></font>
  3067.   <br> Create a form textarea field. The <b>name</b> parameter is evaluated and
  3068.   emitted. The <b>value</b> optional parameter is evaluated. A <b>default</b>
  3069.   may be provided in the body of the tag. The value emitted is, in order of
  3070.   decreasing priority: local tag value, form tag value, value in submitted
  3071.   request dictionary, local tag default, form tag default. We search this list
  3072.   for the first non-None value. The <b>rows</b> and <b>cols</b> optional
  3073.   parameters are evaluated and emitted. </li> <p>
  3074.  
  3075.   <li><font face=courier><<b>radio</b>
  3076.   name=<i>expr</i> value=<i>expr</i> [checked] [default] .../></font>
  3077.   <br> Create a form radio-box. The <b>name</b> and <b>value</b> parameters are
  3078.   evaluated and emitted. A <b>checked</b> and <b>default</b> flags affect
  3079.   whether this box is checked. The box is checked based on the following
  3080.   values, in decreasing order of priority: local tag value, form tag value,
  3081.   value in submitted request dictionary, local tag default, form tag default.
  3082.   We search this list for the first non-None value. </li> <p>
  3083.  
  3084.   <li><font face=courier><<b>checkbox</b>
  3085.   name=<i>expr</i> value=<i>expr</i> [checked] [default] .../></font>
  3086.   <br> Create a form check-box. Parameters are the same as for <b>radio</b>
  3087.   fields, explained above. </li> <p>
  3088.  
  3089.   <li><font face=courier><<b>select</b>
  3090.   name=<i>expr</i> [value=<i>expr</i>] [default=<i>expr</i>] [multiple] [size=<i>expr</i>] ...>...</<b>select</b>></font>
  3091.   <br> Create a form select block. The <b>name</b> parameter and the optional
  3092.   <b>size</b> parameters are evaluated and emitted. The <b>value</b> and
  3093.   <b>default</b> optional parameters are evaluated and serve to select the
  3094.   nested option fields. The <b>multiple</b> flag sets whether multiple
  3095.   selections are allowed. </li><p>
  3096.  
  3097.   <li><font face=courier><<b>option</b>
  3098.   [text=<i>expr</i>] [value=<i>expr</i>] [selected] [default] .../></font>
  3099.   <br> <font face=courier><<b>option</b>
  3100.   [value=<i>expr</i>] [selected] [default] ...>text</<b>option</b>></font>
  3101.   <br> Create a form selection option. This tag must be nested within a
  3102.   <b>select</b> tag. The <b>text</b> optional parameter is evaluated and
  3103.   emitted in the body of the tag. It can also be provided in the body of the
  3104.   tag, as per the HTML standard. The optional <b>value</b> parameter is
  3105.   evaluated and emitted. The <b>selected</b> and <b>default</b> flags determine
  3106.   which options are selected. The options is selected based on the following
  3107.   values, in decreasing order of priority: local tag value, select tag value,
  3108.   form tag value, value in submitted request dictionary, local tag default,
  3109.   select tag default, form tag default. We search this list for the first
  3110.   non-None value. </li> <p>
  3111.  
  3112. </ul> <p>
  3113.  
  3114.  
  3115.  
  3116.  
  3117. [[toc.n('Writing Tag Libraries', 'tag_new')]]
  3118.  
  3119. Creating your own active tags is quite easy and this section explains how. You
  3120. may want to create your own active tags for a number of reasons. More advanced
  3121. uses of tags include database querying, separation of business logic, or
  3122. component rendering. On the other hand, you might consider creating simpler
  3123. task-specific tag libraries. For example, if you do not wish to rely on
  3124. style-sheets you could easily define your own custom tags to perform the
  3125. formatting in a consistent manner at the server. Another convenient use for
  3126. tags is to automatically fill forms with session data. These are only a few of
  3127. the uses for tags. As you will see, writing a Spyce active tag is <i>far</i>
  3128. simpler than writing a JSP tag.<p>
  3129.  
  3130. We begin with a basic example: <p>
  3131.  
  3132. [[includeCode('examples/myTaglib.py', run=0)]] <p>
  3133.  
  3134. Saving this code in <font face=courier>myTaglib.py</font>, in the same
  3135. directory as your script or anywhere else in the search path, one could then
  3136. use the <b>foo</b> active tag (defined above), as follows: <p>
  3137.  
  3138. [[includeCode('examples/tag.spy')]] <p>
  3139.  
  3140. An active tag library can be any Python class that derives from
  3141. <b>spyceTag.spyceTagLibrary</b>. The interesting aspects of this class
  3142. definition to implementors are: <p>
  3143.  
  3144. <ul>
  3145.  
  3146.   <li><b>tags</b>: <br> This field is usually all that requires redefinition.
  3147.   It should be a list of the <i>classes</i> (as opposed to instances) of the
  3148.   active tags. </li> <p>
  3149.  
  3150.   <li><b>start</b>(): <br> This methd is invoked by the engine upon loading
  3151.   the library. The inherited method is a noop. </li> <p>
  3152.  
  3153.   <li><b>finish</b>(): <br> This method is invoked by the engine upon
  3154.   unloading the library after a request. The inherited method is a noop. </li>
  3155.   <p>
  3156.  
  3157. </ul>
  3158.  
  3159. Each active tag can be any Python class that derives from
  3160. <b>spyceTag.spyceTag</b>. The interesting aspects of the class definition for
  3161. tag implementors are: <p>
  3162.  
  3163. <ul>
  3164.  
  3165.   <li><b>name</b>: <br> This field MUST be overidden to indicate the name of
  3166.   the tag that this class defines. </li> <p>
  3167.  
  3168.   <li><b>buffer</b>: <br> This flag indicates whether the processing of the
  3169.   body of the tag should be performed with the current output stream
  3170.   (unbuffered) or with a new, buffered output stream. Buffering is useful for
  3171.   tags that may want to transform, or otherwise use, the output of processing
  3172.   their own bodies, before it is sent to the client. The inherited default is
  3173.   false. </li> <p>
  3174.  
  3175.   <li><b>conditional</b>: <br> This flag indicates whether this tag may
  3176.   conditionally control the execution of its body. If true, then the begin()
  3177.   method of the tag must return true to process the tag body, or false to skip
  3178.   it. If the flag is set to false, then return value of the begin() method is
  3179.   ignored, and the body executed (unless an exception is triggered). Some
  3180.   tags, such as the <font face=courier>core:if</font> tag, require this
  3181.   functionality, and will set the flag true. Many other kinds of tags do not,
  3182.   thus saving a level of indentation (which is unfortunately limited in Python
  3183.   -- hence the need for this switch). The inherited default is false. </li>
  3184.   <p>
  3185.  
  3186.   <li><b>loops</b>: <br> This flag indicates whether this tag may want to loop
  3187.   over the execution of its body. If true, then the body() method of the tag
  3188.   must return true to repeat the body processing, or false to move on to the
  3189.   end() of the tag. If the flag is set to false, then the return value of the
  3190.   body() method is ignored, and the body is not looped. Some tags, such as the
  3191.   <font face="courier">core:for</font> tag, require this functionality, and
  3192.   will set the flag true. Many other kinds of tags do not, thus saving a level
  3193.   of indentation. The inherited default is false. </li> <p>
  3194.  
  3195.   <li><b>catches</b>: <br> This flag indicates whether this tag may want to
  3196.   catch any exceptions that occur during the execution of its body. If true,
  3197.   then the catch() method of the tag will be invoked on exception. If the flag
  3198.   is false, the exception will continue to propagate beyond this point. Some
  3199.   tags, such as the <font face="courier">core:catch</font>, require this
  3200.   functionality, and will set the flag true. Many other kinds of tags do not,
  3201.   thus saving a level of indentation. The inherited default is false. </li>
  3202.   <p>
  3203.  
  3204.   <li><b>mustend</b>: <br> This flag indicates whether this tag wants the
  3205.   end() method to get called, if the begin() completes successfully, <i>no
  3206.   matter what</i>. In other words, the call to end() is placed in the finally
  3207.   of try-finally block which begins just after the begin(). This is useful for
  3208.   tag cleanup, such as in the <font face="courier">core:let</font> tag, which
  3209.   sets this flag to true in order to ensure that variables are removed from
  3210.   the tag context. However, many other tags do not perform anything in the
  3211.   end() of their tag, or perhaps perform operations that are not important in
  3212.   the case of an exception. Such tags do not require this functionaliy, thus
  3213.   saving a level of indentation. The inherited default is false. </li> <p>
  3214.   
  3215.   <li><b>syntax</b>(): <br> This method is invoked at compile time to perform
  3216.   any additional tag-specific syntax checks. The inherited method returns
  3217.   None, which means that there are no syntax errors. If a syntax error is
  3218.   detected, this function should return a string with a helpful message about
  3219.   the problem. Alternatively, one could raise an
  3220.   <b>spyceTagSyntaxException</b>. </li> <p>
  3221.  
  3222.   <li><b>begin</b>( ... ): <br> This method is invoked when the corresponding
  3223.   start tag is encountered in the document. All the attributes of the tag are
  3224.   passed in by name. This method may return a boolean flag. If
  3225.   <b>conditional</b> is set to true (see above), then this flag indicates
  3226.   whether the body of the tag should be processed (true), or skipped (false).
  3227.   The inherited method performs no operation, except to return true. </li> <p>
  3228.  
  3229.   <li><b>body</b>( contents ): <br> This method is invoked when the body of
  3230.   the tag has <i>completed</i> processing. It will be called also for a
  3231.   singleton, which we assume simply has an empty body. However, it will not be
  3232.   called if the begin() method has chosen to skip body processing entirely. If
  3233.   the tag sets <b>buffer</b> to true for capturing the body processing output
  3234.   (see above), then the string output of the body processing has been captured
  3235.   and stored in <b>contents</b>. It is the responsibility of this method to
  3236.   emit something, if necessary. If the tag does not buffer then
  3237.   <b>contents</b> will be None, and any output has already been written to the
  3238.   enclosing scope. If the <b>loops</b> flag is set to true, then this method
  3239.   is expected to return a boolean flag. If the flag is true, then the body
  3240.   will be processed again, followed by another invocation of this method. And
  3241.   again, and again, until false is received. The inherited tag method performs
  3242.   nothing and returns false. </li> <p>
  3243.  
  3244.   <li><b>end</b>(): <br> This method is invoked when the corresponding end tag
  3245.   is encountered. For a singleton tag, we assume that the end tag immediately
  3246.   follows the begin, and still invoke this method. If the <b>mustend</b> flag
  3247.   has been set to true, then the runtime engine semantics ensure that if the
  3248.   begin method terminates successfully, this method <i>will</i> get called,
  3249.   even in the case of an exception during body processing. The inherited
  3250.   method is a noop. </li> <p>
  3251.  
  3252.   <li><b>catch</b>( ex ): <br> If the <b>catches</b> flag has been set to
  3253.   true, then if any exception occurs in the begin(), body() or end() methods
  3254.   or from within the body processing, this method will be invoked. The
  3255.   parameter <b>ex</b> holds the value that was thrown. The inherited method
  3256.   simply re-raises the exception. </li> <p>
  3257.  
  3258.   <li><b>getPrefix</b>(): <br> Return the prefix under which this tag library
  3259.   was installed. </li> <p>
  3260.  
  3261.   <li><b>getAttributes</b>(): <br> Return a dictionary of tag attributes.
  3262.   </li> <p>
  3263.  
  3264.   <li><b>getPaired</b>(): <br> Return true if this is a paired (open and
  3265.   close) tag, or false if it is a singleton. </li> <p>
  3266.  
  3267.   <li><b>getParent</b>( [name] ): <br> Return the object of the direct parent
  3268.   tag, or None if this is the root active tag. Plain (inactive) tags do not
  3269.   have objects associated with them in this hierarchy. If the optional
  3270.   <b>name</b> parameter is provided, then we search up the tree for an active
  3271.   tag of the same library and with the given name. If such a tag can not be
  3272.   found, then return None. </li> <p>
  3273.  
  3274.   <li><b>getOut</b>(): <br> Return the (possibly buffered) output stream that
  3275.   this tag should write to. </li> <p>
  3276.  
  3277.   <li><b>getContext</b>(): <br> Return the tag context dictionary, where all
  3278.   tags variables are kept and expression are evaluated. The context contains
  3279.   references to each of the loaded Spyce modules. These variables may used to
  3280.   access module functionality, but they should not be deleted or modified.
  3281.   </li> <p>
  3282.  
  3283.   <li><b>getBuffered</b>(): <br> Returns true if the tag output stream is a
  3284.   local buffer, or false if the output is connected to the enlosing scope.
  3285.   </li> <p>
  3286.  
  3287. </ul>
  3288.  
  3289. For convenience, tag implementors may wish to derive their implementations
  3290. from <b>spyceTagPlus</b>, which provides some useful additional methods:
  3291.  
  3292. <ul>
  3293.  
  3294.   <li><b>contextSet</b>( name, (exists,value) ): <br> Accepts a variable
  3295.   <b>name</b> and a tuple containing an <b>exists</b> flag and a <b>value</b>.
  3296.   If the flag is true, then the variable is assigned the value within the tag
  3297.   context. If the flag is false, the variable is deleted from the context
  3298.   dictionary. This function returns the previous state of this variable, as
  3299.   per contextGet(). </li> <p>
  3300.  
  3301.   <li><b>contextGet</b>( name ): <br> Returns the current state of the
  3302.   variable <b>name</b> in the tag context. The state is a tuple containing a
  3303.   flag whether the variable is defined and its value. </li> <p>
  3304.  
  3305.   <li><b>contextEval</b>( expr ): <br> Evaluates a string <b>expr</b> as
  3306.   follows. If the string begins with an '=', then the rest of the string is
  3307.   treated as a Python expression. This is expression is evaluated within the
  3308.   tag context dictionary, and the result is returned. Otherwise, the parameter
  3309.   is treated as a string constant and returned as-is. </li> <p>
  3310.  
  3311.   <li><b>contextGetModule</b>( name ): <br> Return a reference to a module
  3312.   from the tag context. The module is loaded, if necessary. </li> <p>
  3313.  
  3314.   <li><b>syntaxExist</b>( [must]* ): <br> Ensure that the list of attributes
  3315.   given in <b>must</b> are all defined in the attributes of this tag.
  3316.   Otherwise, a spyceTagSyntaxException is thrown. </li> <p>
  3317.  
  3318.   <li><b>syntaxExistOr</b>( [mustgroups]* ): <br> Ensure that at least one of
  3319.   the lists of attributes specified in <b>mustgroups</b> satisfies
  3320.   syntaxExist(). Otherwise, a spyceTagSyntaxException is thrown. </li> <p>
  3321.  
  3322.   <li><b>syntaxExistOrEx</b>( [mustgroups]* ): <br> Ensure that exactly one of
  3323.   the lists of attributes specified in <b>mustgroups</b> satisfies
  3324.   syntaxExist(). Otherwise, a spyceTagSyntaxException is thrown. </li> <p>
  3325.  
  3326.   <li><b>syntaxNonEmpty</b>( [names]* ): <br> Ensure that if the attributes
  3327.   listed in <b>names</b> exist, then each of them does not contain an empty
  3328.   string value. Otherwise, a spyceTagSyntaxException is thrown. Note that the
  3329.   actual existence of a tag is checked by syntaxExists(), and that this method
  3330.   only checks that a tag is non-empty. Specifically, there is no exception
  3331.   raised from this method, if the attribute does not exist. </li> <p>
  3332.  
  3333.   <li><b>syntaxValidSet</b>( name, validSet ): <br> Ensure that the value of
  3334.   the attribute <b>name</b>, if it exists, is one of the values in the set
  3335.   <b>validSet</b>. Otherwise, a spyceTagSyntaxException is raised. </li> <p>
  3336.  
  3337.   <li><b>syntaxPairOnly</b>(): <br> Ensure that this tag is a paired tag.
  3338.   Otherwise, a spyceTagSyntaxException is thrown. </li> <p>
  3339.  
  3340.   <li><b>syntaxSingleOnly</b>(): <br> Ensure that this tag is a singleton tag.
  3341.   Otherwise, a spyceTagSyntaxException is thrown. </li> <p>
  3342.  
  3343. </ul>
  3344.  
  3345. Despite the length of this description, most tags are trivial to write, as
  3346. shown in the initial example. The easiest way to start is by having at a look
  3347. at various implemented tag libraries, such as <font
  3348. face=courier>tags/core.py</font>. The more curious reader is welcome to look
  3349. at the tag library internals in <font face=courier>spyceTag.py</font> and
  3350. <font face=courier>modules/taglib.py</font>. The tag semantics are ensured by
  3351. the Spyce compiler (see <font face=courier>spyceCompile.py</font>), though it
  3352. is likely easier simply to look at the generated Python code using the <font
  3353. face=courier>"spyce -c"</font> command-line facility. <p>
  3354.  
  3355. [[toc.e()]]
  3356.  
  3357. [[toc.n('Installation', 'conf')]]
  3358.  
  3359. Spyce can be installed and used in many configurations. Hopefully, one of the
  3360. ones below will suit your needs. If not, feel free to email the lists asking
  3361. for assistance in using a different setup. If you have successfully set up
  3362. Spyce by some other method, please email me the details so that I can post
  3363. them for others. Lastly, if you had troubles following these instructions,
  3364. please send an email with suggestions on how to improve them. <p>
  3365.  
  3366. [[toc.b('Overview', 'conf_overview')]]
  3367.  
  3368. Spyce supports a variety of installation methods (automated versus manual),
  3369. webserver adapters (FastCGI, mod_python, proxy, CGI and command-line) and
  3370. operating system environments (Linux and Windows), which require separate
  3371. discussion and configuration-specific tweaks. These specifics are kept to an
  3372. absolute minimum, however, and, wherever possible, the configuration of the
  3373. Spyce engine is performed through a common configuration file. <p>
  3374.  
  3375. The supported adapters are:
  3376.  
  3377. <ul>
  3378.  
  3379.   <li> <b>Fast CGI:</b>The default Spyce integration with Apache is acheived
  3380.   via <a href="http://www.fastcgi.com">FastCGI</a>, a CGI-like interface that
  3381.   is relatively fast, because it does not incur the large process startup
  3382.   overhead on each request. </li> <p>
  3383.  
  3384.   <li> <b>mod_python:</b> If you really must have the fastest Spyce
  3385.   implementation (see the <a
  3386.     href="[[=genTOClink('add_perf')]]">performance</a> numbers), it is
  3387.   currently through an Apache module called <a
  3388.     href="http://www.modpython.org">mod_python</a>. Spyce has been tested with
  3389.   mod_python version 2.7.6 (and version 3.0.3 with apache 2.0.37). You can try 
  3390.   to find some mod_python rpms <a
  3391.     href="http://www.rpmfind.net/linux/rpm2html/search.php?query=mod_python">here</a>,
  3392.   but in general one must compile mod_python from sources. The reason for this
  3393.   is because mod_python links with the Python library it finds on your system
  3394.   at compile time. Thus, even if you have the correct Python version installed
  3395.   on your system, mod_python will be using the Python library version on the
  3396.   system where it was compiled. Also, note that mod_python (or rather Apache)
  3397.   needs a Python that has been compiled without threading, so you may need to
  3398.   recompile Python as well for this reason. The process is not very difficult
  3399.   (just the usual: <i>./configure; make; make install</i> dance), but
  3400.   hopefully someone will suggest a better route in time. In any case, make
  3401.   sure you can first get mod_python running on your system, if that is that is
  3402.   your chosen Apache integration route. </li> <p>
  3403.  
  3404.   <li> <b>Web server:</b> Another fast alternative is to serve Spyce files via
  3405.   a proxy. This involves running Spyce in web-server mode, and configuring the
  3406.   main web server to forward the appropriate requests. The built-in Spyce web
  3407.   server can also be used to serve requests directly, but this is highly
  3408.   discouraged for production environments. </li> <p>
  3409.  
  3410.   <li> <b>CGI:</b> Failing these alternatives you can always process requests
  3411.   via regular CGI, but this alternative is the slowest option and is intended
  3412.   primarily for those who do not have much control over their web environments.
  3413.   </li> <p>
  3414.  
  3415.   <li> <b>Command line:</b> Lastly, one can use Spyce as a command-line tool
  3416.   for pre-processing Spyce pages and creating static HTML files. </li> <p>
  3417.  
  3418. </ul>
  3419.  
  3420. Users have written a number of additional Spyce adapters, including an adapter
  3421. for the Xitami extension protocol and an adapter for the Coil framework. <p>
  3422.  
  3423. [[toc.n('Requirements', 'conf_req')]]
  3424.  
  3425. Spyce (the core engine and all the standard modules) currently requires
  3426. <b>Python version [[=verchk.REQUIRED]] or greater</b>, and <b>Apache version
  3427. 1.3.x or greater</b>. <p>
  3428.  
  3429. However, Spyce is developed and tested mostly with <b>Python version
  3430. 2.2.x</b>, and using <b>Apache version 2.0.x</b>. <p>
  3431.  
  3432. Spyce currently does <i>not</i> require thread support. Spyce uses no
  3433. version-specific Apache features. It is highly recommended that you use
  3434. <b>Python version 2.1 or higher</b>, because certain common operations can be
  3435. difficult without the new nested scoping functionality. <p>
  3436.  
  3437. If you find a bug, please let me know! <p>
  3438.  
  3439. [[toc.n('Installation Methods', 'conf_methods')]]
  3440.  
  3441. Spyce can be installed in a variety of ways:
  3442.  
  3443. <ul>
  3444.  
  3445.   <li> <a href="[[=genTOClink('conf_rpm')]]">Automated installation via RPM</a>
  3446.   </li> <p>
  3447.  
  3448.   <li> <a href="[[=genTOClink('conf_win')]]">Automated installation via Windows
  3449.     installer</a> </li> <p>
  3450.  
  3451.   <li> <a href="[[=genTOClink('conf_source')]]">Manual installation</a> </li>
  3452.   <p>
  3453.  
  3454. </ul>
  3455.  
  3456. <p>
  3457.  
  3458. [[toc.b('Automated installation - RPM', 'conf_rpm')]]
  3459.  
  3460. The easiest way to install Spyce on Linux is via RPM. Download the file from
  3461. the link above and, as root user on your system, type in the following
  3462. command: (If you upgrading Spyce, it is recommended to uninstall the previous
  3463. version using <b>rpm -e spyce</b>, and then install a fresh copy, as opposed
  3464. to using the <b>rpm -U</b> option.) <p>
  3465.  
  3466. <font face=courier>
  3467. [[.compact mode=off]]
  3468. <pre>
  3469.   <b>rpm -i spyce-[[=spyce.__version__]]-[[=release]].rpm</b>
  3470. </pre>
  3471. [[.compact]]
  3472. </font>
  3473. <p>
  3474.  
  3475. This will:
  3476.  
  3477. <ul>
  3478.  
  3479.   <li>Install the Spyce engine</li>
  3480.   <li>Install the web-based and command-line Spyce processors</li>
  3481.   <li>Configure Apache to process .spy files via fast cgi, if installed or regular cgi otherwise
  3482.   <li>Restart the server</li>
  3483.   <li>Install the Spyce documentation under <a href="http://localhost/spyce">http://localhost/spyce</a></li>
  3484.  
  3485. </ul>
  3486.  
  3487. Note that the default Apache installation does not come with FastCGI
  3488. configured. Thus, you will be running Spyce via CGI, which is slow. If you
  3489. install FastCGI, you will get a considerable performance boost. Alternatively,
  3490. you could configure the mod_python adapter, or use the proxy server, for a
  3491. similar performance boost. <p>
  3492.  
  3493. <b>Note to Redhat users:</b> Spyce should install without a hitch on RedHat
  3494. 8.0 machines and up. Redhat (up until version 8.0) still used Python version
  3495. 1.5, as many standard scripts depended on it. If you want to run Spyce with
  3496. some of the newer Python2 rpms, you will need to change top line of the <font
  3497. face=courier>run_spyceCmd.py</font>, <font
  3498. face=courier>run_spyceCGI.py</font>, <font
  3499. face=courier>run_spyceModpy.py</font> and <font face=courier>verchk.py</font>
  3500. scripts, or reconfigure your path so that the default python is the version
  3501. that you want. <p>
  3502.  
  3503. <b>Note to Mandrake users:</b> Users have reported this distribution to have no
  3504. problems with the RPM. <p>
  3505.  
  3506. [[toc.n('Automated installation - Windows executable', 'conf_win')]]
  3507.  
  3508. On Windows platforms, the easiest method to install Spyce is via the executable
  3509. installer. Python is required on the system prior to installation. It is also
  3510. recommended to install the ActivePython distribution, as Spyce will
  3511. automatically detect and use various Windows-specific features. It is advised
  3512. to install Apache before Spyce, so that the Spyce installer can automatically
  3513. modify the configuration file. You will need to install FastCGI or mod_python
  3514. separately. Otherwise, Spyce will function via CGI. <p>
  3515.  
  3516. The Windows installer installs the Spyce engine in a user-specified directory,
  3517. copies and compiles the Spyce documentation, configures Apache, registers an
  3518. uninstaller and also registers the .spy file types with the shell for easy
  3519. compilation. Don't forget to check the Apache configuration file, and
  3520. <b>restart Apache</b>. If you have any problems with the installer please send
  3521. an email. <p>
  3522.  
  3523. [[toc.n('Manual installation', 'conf_source')]]
  3524.  
  3525. One could also install Spyce manually from the source tarball (using
  3526. FastCGI), as follows:
  3527.  
  3528. <ul>
  3529.  
  3530.   <li>Ensure that you have Apache and FastCGI installed and functioning.</li>
  3531.  
  3532.   <li><b>Extract</b> the source tarball into some directory.</li>
  3533.  
  3534.   <li>Execute <font face=courier><b>make</b></font> in this directory to compile the
  3535.   python modules and build the documentation.</li>
  3536.  
  3537.   <li>(Optional) As <b>root user</b>, execute "<font face=courier><b>make
  3538.       install</b></font>", to install spyce into <font
  3539.     face=courier><b>/usr/share/spyce</b></font>.</li>
  3540.  
  3541.   <li>Create a link to the command-line executable: <br> "<font
  3542.     face=courier><b>ln -sf /usr/share/spyce/run_spyceCmd.py /usr/bin/spyce</b></font>"
  3543.   <br> or wherever you have chosen to install it. </li>
  3544.  
  3545.   <li>Create a link to the documentation in /usr/share/doc: <br> "<font
  3546.     face=courier><b>ln -sf /usr/share/spyce/docs/ /usr/share/doc/spyce</b></font>"
  3547.   <br> or wherever you have chosen to install it. </li>
  3548.  
  3549.   <li>Add the following lines to your <font face=courier><b>/etc/httpd/conf/httpd.conf</b></font> 
  3550.   file, and replace the <font color=red><b>XXX</b></font> with the appropriate
  3551.   path.
  3552.   <br>
  3553.   <font face=courier size=-1>
  3554.     [[.compact mode=off]]
  3555.     <pre>[[=re.sub('XXX', '<font color=red><b>XXX</b></font>', transform.html_encode(include.dump('../spyceApache.conf')))]]</pre>
  3556.     [[.compact]]
  3557.   </font></li>
  3558.  
  3559.   <li>If you are installing on Windows, please also read follow the following
  3560.   <a href="[[=genTOClink('conf_windows')]]">instructions</a>. </li>
  3561.  
  3562.   <li><b>Restart Apache</b>, and you should be set.</li>
  3563.  
  3564. </ul>
  3565.  
  3566. Test the installation by browsing:
  3567. <font face=courier>
  3568. [[.compact mode=off]]
  3569. <pre>
  3570.   <a href="http://localhost/spyce/examples/hello.spy">http://localhost/spyce/examples/hello.spy</a>
  3571. </pre>
  3572. [[.compact]]
  3573. </font>
  3574. <p>
  3575.  
  3576. <b>Alternative CGI configuration:</b>
  3577.  
  3578. The alternative CGI configuration directs the webserver to execute the Spyce
  3579. file itself, not the Spyce engine. The Spyce file should have execute
  3580. permissions for the web server, and the first line should be:<p>
  3581.  
  3582. [[.compact mode=off]]
  3583. <font face=courier>
  3584. <pre>
  3585.   #! /usr/bin/python /home/username/spyce/run_spyceCGI.py
  3586. </pre>
  3587. </font>
  3588. [[.compact]]
  3589.  
  3590. Then add the following line to the <font face=courier>httpd.conf</font>, or to
  3591. the <font face=courier>.htaccess</font> file in the same directory.
  3592.  
  3593. [[.compact mode=off]]
  3594. <font face=courier>
  3595. <pre>
  3596.   AddHandler cgi-script spy
  3597. </pre>
  3598. </font>
  3599. [[.compact]]
  3600.  
  3601. And ensure that the directory itself has the <b>ExecCGI</b> option enabled.<p>
  3602.  
  3603. Please refer to the Apache documentation, specifically
  3604. <a href="http://httpd.apache.org/docs/mod/core.html#options">ExecCGI option</a>,
  3605. <a href="http://httpd.apache.org/docs/mod/core.html#directory">Directory</a>,
  3606. <a href="http://httpd.apache.org/docs/mod/core.html#location">Location</a>,
  3607. <a href="http://httpd.apache.org/docs/mod/core.html#allowoverride">AllowOverride</a> and
  3608. <a href="http://httpd.apache.org/docs/howto/cgi.html">Apache CGI documentation</a>,
  3609. for more information on how to get a standard CGI setup working. <p>
  3610.  
  3611. [[toc.e()]]
  3612.  
  3613. [[toc.n('Configuration Specifics', 'conf_spec')]]
  3614.  
  3615. While the default configuration above should suffice many users, it is often
  3616. the case that you would like to use Spyce under a different adapter or in a
  3617. different way. The following notes should be helpful, but should not be
  3618. considered complete. Many other configurations are possible, and if you come
  3619. across one that you find useful, please let me know. <p>
  3620.  
  3621. [[toc.b('Mod_Python', 'conf_modpython')]]
  3622.  
  3623. The mod_python webserver integration route is the fastest currently available.
  3624. Try this option if you really need more speed, or if you simply can not get
  3625. FastCGI to work. Before you try to install Spyce, first get mod_python to work!
  3626. You may have to compile from sources, and possibly do the same for Python. (See
  3627. the documentation at: <a href="http://www.modpython.org">mod_python</a>.) You
  3628. might be able to find some useful python rpms <a
  3629.   href="http://www.rpmfind.net/linux/rpm2html/search.php?query=python">here</a>
  3630. and mod_python rpms <a
  3631.   href="http://www.rpmfind.net/linux/rpm2html/search.php?query=mod_python">here</a>.
  3632. Windows versions of mod_python are available as well. <p>
  3633.  
  3634. To use Spyce via mod_python:
  3635.  
  3636. <ul>
  3637.  
  3638.   <li><a href="[[=genTOClink('conf_methods')]]">Install Spyce</a>. </li> <p>
  3639.  
  3640.   <li>Then, edit the httpd.conf to comment the cgi parts of the inserted Spyce
  3641.   configuration lines and uncomment the mod_python parts. </li> <p>
  3642.  
  3643.   <li>Restart Apache</li> <p>
  3644.  
  3645. </ul>
  3646.  
  3647.  
  3648. [[toc.n('Web Server', 'conf_proxy')]]
  3649.  
  3650. Yet another alternative for running Spyce, it to run it as a web-server either
  3651. serving the web as a proxy server or as a primary. The Spyce web server is
  3652. exceptionally feature poor, thus using it as a proxy behind a real web server
  3653. is advised. Moreover, using it as the primary web server in a production is
  3654. highly discouraged. The Spyce web server configuration is defined in a section
  3655. of the <a href="[[=genTOClink('runtime_common')]]">runtime configuration</a>
  3656. file. To run it as a proxy server behind Apache, following these instructions:
  3657.  
  3658. <ul>
  3659.  
  3660.   <li><a href="[[=genTOClink('conf_methods')]]">Install Spyce</a>. </li> <p>
  3661.  
  3662.   <li>Then, uncomment the lines in the httpd.conf to comment the cgi parts and
  3663.   uncomment the proxy parts. </li> <p>
  3664.  
  3665.   <li>Start the Spyce web server. The command-line syntax for starting the
  3666.   server is: <br> <b><font face=courier>spyce -l [-p port] [<root>]</font><b> </li>
  3667.  
  3668.   <li>Restart Apache</li> <p>
  3669.  
  3670. </ul>
  3671.  
  3672. [[toc.n('Windows', 'conf_windows')]]
  3673.  
  3674. If you are installing Spyce <a
  3675.   href="[[=genTOClink('conf_source')]]">manually</a> on Windows, remember to
  3676. add the following line to Apache's httpd.conf: <p>
  3677.  
  3678. [[.compact mode=off]]
  3679. <font face=courier>
  3680. <b><pre>
  3681.   ScriptInterpreterSource registry
  3682. </pre></b>
  3683. </font>
  3684. [[.compact]]<p>
  3685.  
  3686. This assumes that Python has registered itself with the Windows registry to
  3687. run .py files. Otherwise, you can also omit this line, but make sure that the
  3688. first line of the <font face=courier>run_spyceCGI.py</font> file points to a
  3689. valid Python executable, as in:
  3690.  
  3691. [[.compact mode=off]]
  3692. <font face=courier>
  3693. <b><pre>
  3694.   #! c:/progs/python/python.exe
  3695. </pre></b>
  3696. </font>
  3697. [[.compact]]<p>
  3698.  
  3699. If you are running using IIS on Windows, you can take a look at 
  3700. <a href="http://starship.python.net/crew/aaron_watters/pws.html">how to 
  3701.   configure IIS or PWS for Python/CGI scripts</a>. <p>
  3702.  
  3703. The basics for getting IIS to work with Spyce are:
  3704.  
  3705. <ul>
  3706.  
  3707.   <li> Start the IIS administration console. You get to it from the <b>Control
  3708.   Panel</b>. Click on <b>Administrative Tools</b>, and then <b>Internet
  3709.   Services Manager</b>. </li>
  3710.  
  3711.   <li> Drill down to your <b>Default Web Site</b>. Right click and select
  3712.   <b>Properties</b>. </li>
  3713.  
  3714.   <li> Select the <b>Home Directory</b> tab, and click on the
  3715.   <b>Configuration...</b> button near the bottom right. </li>
  3716.  
  3717.   <li> Add an application mapping. On the <b>executable</b> line you should
  3718.   type the equivalent of: <br> <b><font
  3719.   face=courier>"c:\program files\python22\python.exe" "c:\program files\spyce\spyceCGI.py"</font></b>.
  3720.   <br> Set the <b>extension</b> to <b><font face=courier>.spy</font></b>, or
  3721.   whatever you like. <br> Limit the <b>Verbs</b> to <b><font
  3722.   face="courier">GET,POST</font></b>. <br> Select the <b>Script engine</b> and
  3723.   <b>Check that file exists</b> check-boxes. </li>
  3724.  
  3725.   <li>Click <b>OK</b> twice. Make sure to propagate these properties to all
  3726.   sub-nodes. That is, click <b>Select All</b> and then <b>OK</b> once more.
  3727.   </li>
  3728.  
  3729.   <li> You should now be able to browse .spy files within your website. Note,
  3730.   that this is a very slow mechanism, since it utilizes CGI and restarts the
  3731.   Spyce engine on each request. </li>
  3732.  
  3733.   <li> Using the Spyce proxy web server or installing FastCGI are much
  3734.   advised for the vast majority of environments. </li>
  3735.  
  3736. </ul>
  3737.  
  3738. [[toc.e()]]
  3739.  
  3740. [[toc.e()]]
  3741.  
  3742. [[toc.n('Addenda', 'add')]]
  3743.  
  3744. List of appendices:
  3745.  
  3746. <ul>
  3747.  
  3748.   <li><a href="[[=genTOClink('add_perf')]]">Performance</a> - Some throughput
  3749.   micro-benchmarks</li><p>
  3750.  
  3751.   <li><a href="[[=genTOClink('add_history')]]">History</a> - The brief history
  3752.   of Spyce</li><p>
  3753.  
  3754.   <li><a href="[[=genTOClink('add_related')]]">Related work</a> - Links to
  3755.   other related projects online</li><p>
  3756.  
  3757. </ul>
  3758.  
  3759. [[toc.b('Performance', 'add_perf')]]
  3760.  
  3761. Although flexibility usually outweighs raw performance in the choice of
  3762. technology, it is nice to know that the technology that you have chosen is not
  3763. a resource hog, and can scale to large production sites. The current Spyce
  3764. implementation is comparable to its cousin technologies: JSP, PHP and ASP. We
  3765. ran a micro-benchmark using <b>hello.spy</b> and equivalents. All benchmark
  3766. files are available in the <font face=courier>misc/benchmark</font>
  3767. directory.<p>
  3768.  
  3769. [[includeCode('examples/hello.spy')]]
  3770. <p>
  3771.  
  3772. Spyce was measured under CGI, FCGI, mod_python and proxy configurations. For
  3773. calibration the static HTML, CGI-C, CGI-Python and FCGI-Python tests were
  3774. performed. In the case of CGI-C, the request is handled by a compiled C
  3775. program with the appropriate printf statements. In the case of CGI-Python, we
  3776. have an executable Python script with the appropriate print statements.
  3777. FCGI-Python is a similar script that is FCGI enabled. ASP was measured on a
  3778. different machine, only to satisfy curiosity; those results are omitted. <p>
  3779.  
  3780. <table border=1 align=center>
  3781.   <tr>
  3782.     <td bgcolor="#cccccc"><font face="arial, helvetica" size="-1">Configuration</font></td>
  3783.     <td bgcolor="#cccccc"><font face="arial, helvetica" size="-1">Hello world!</font></td>
  3784.   </tr>
  3785.   <tr>
  3786.     <td><font face="arial, helvetica" size="-1"><b>Spyce-modpython</b></font></td>
  3787.     <td align=right><font face="arial, helvetica" size="-1"><b>250</b></font></td>
  3788.   </tr>
  3789.   <tr>
  3790.     <td><font face="arial, helvetica" size="-1">modpython publisher</font></td>
  3791.     <td align=right><font face="arial, helvetica" size="-1">300</font></td>
  3792.   </tr>
  3793.   <tr>
  3794.     <td><font face="arial, helvetica" size="-1"><b>Spyce-proxy</b></font></td>
  3795.     <td align=right><font face="arial, helvetica" size="-1"><b>200</b></font></td>
  3796.   </tr>
  3797.   <tr>
  3798.     <td><font face="arial, helvetica" size="-1">JSP</font></td>
  3799.     <td align=right><font face="arial, helvetica" size="-1">100</font></td>
  3800.   </tr>
  3801.   <tr>
  3802.     <td><font face="arial, helvetica" size="-1">PHP</font></td>
  3803.     <td align=right><font face="arial, helvetica" size="-1">450</font></td>
  3804.   </tr>
  3805.   <tr>
  3806.     <td><font face="arial, helvetica" size="-1"><b>Spyce-FCGI</b></font></td>
  3807.     <td align=right><font face="arial, helvetica" size="-1"><b>100</b></font></td>
  3808.   </tr>
  3809.   <tr>
  3810.     <td><font face="arial, helvetica" size="-1">Python-FCGI</font></td>
  3811.     <td align=right><font face="arial, helvetica" size="-1">140</font></td>
  3812.   </tr>
  3813.   <tr>
  3814.     <td><font face="arial, helvetica" size="-1"><b>Spyce-CGI</b></font></td>
  3815.     <td align=right><font face="arial, helvetica" size="-1"><b>8</b></font></td>
  3816.   </tr>
  3817.   <tr>
  3818.     <td><font face="arial, helvetica" size="-1">Python-CGI</font></td>
  3819.     <td align=right><font face="arial, helvetica" size="-1">25</font></td>
  3820.   </tr>
  3821.   <tr>
  3822.     <td><font face="arial, helvetica" size="-1">C-CGI</font></td>
  3823.     <td align=right><font face="arial, helvetica" size="-1">180</font></td>
  3824.   </tr>
  3825.   <tr>
  3826.     <td><font face="arial, helvetica" size="-1">Static HTML</font></td>
  3827.     <td align=right><font face="arial, helvetica" size="-1">1500</font></td>
  3828.   </tr>
  3829. </table>
  3830. <p>
  3831.  
  3832. The throughput results (shown above in requests per second) were measured on a
  3833. Intel PIII 700MHz, with 128 MB of RAM and a 512 KB cache
  3834. running RedHat Linux 7.2 (2.4.7-10 kernel), Apache 1.3.22 and
  3835. Python 2.2 using loopback (http://localhost/...) requests. Since each of
  3836. the script languages requires an initial compilation phase (of which JSP seems
  3837. the longest), the server was warmed up with 100 requests before executing
  3838. 1000 measured requests with a concurrency level of 3, using the
  3839. ab (Apache benchmark) tool. Figures are rounded to the nearest
  3840. 25 requests/second. <p>
  3841.  
  3842. <b>Conclusion:</b> Both the mod_python and FCGI version can handle large
  3843. websites, as the Spyce engine and cache persist between requests. The CGI
  3844. version takes a hit in recompiling Spyce files on every request. This may be
  3845. alleviated using a disk-based Spyce cache (as opposed to the current
  3846. memory-based implementation). <p>
  3847.  
  3848. [[toc.n('History', 'add_history')]]
  3849.  
  3850. The initial idea for a Python-based HTML scripting language came in May 1999,
  3851. a few months after I had first learned of Python, while working with JSP on
  3852. some website. The idea was pretty basic and I felt that someone was bound to
  3853. implement it sooner or later, so I waited. But, nobody stepped up to the task,
  3854. and the idea remained little more than a design in my head for two and a half
  3855. years. In early 2002, after having successfully used Python extensively for
  3856. various other tasks and gaining experience with the language, I began to
  3857. revisit my thoughts on a Python-based HTML scripting language, and by late
  3858. May 2002 the beta of version 1.0 was released. <p>
  3859.  
  3860. <b>Version 1.0</b> had support for standard features like get and post,
  3861. cookies, session management, etc. Development was still on-going, but Spyce
  3862. was mature and being used on live systems. Support of various features was
  3863. enhanced for about a week or two, and then a new design idea popped into my
  3864. head. <b>Version 1.1</b> was the first modular release of Spyce. Lots of
  3865. prior functionality was shipped out of the core engine and into standard
  3866. modules. Many, many new modules and features were added. Spyce popularity rose
  3867. to the top percentile of SourceForge projects and the user base grew.
  3868. <b>Version 1.2</b> represented a greatly matured release of Spyce. Spyce
  3869. got a totally revamped website and documentation, and development continued.
  3870. <b>Version 1.3</b> introduced active tags. More performance work, more
  3871. modules, etc. Development continues... <p>
  3872.  
  3873. For more detail, please refer to the <a
  3874.   href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/spyce/spyce/CHANGES?rev=HEAD">change
  3875.   log</a>. As always, user feedback is welcome and appreciated. <p>
  3876.  
  3877. [[toc.n('Related Work', 'add_related')]]
  3878.  
  3879. Links to websites and projects that are related in some way to Spyce (listed
  3880. alphabetically).
  3881.  
  3882. <ul>
  3883.  
  3884.   <li>Albatross - 
  3885.   <a href="http://www.object-craft.com.au/projects/albatross/">http://www.object-craft.com.au/projects/albatross</a></li>
  3886.  
  3887.   <li>Apache -
  3888.   <a href="http://www.apache.org/">http://www.apache.org</a></li>
  3889.  
  3890.   <li>ASPy - 
  3891.   <a href="http://archive.dstc.edu.au/aspy/">http://archive.dstc.edu.au/aspy</a></li>
  3892.  
  3893.   <li> Castalian -
  3894.   <a href="http://www.kryogenix.org/code/castalian/">http://www.kryogenix.org/code/castalian/</a></li>
  3895.  
  3896.   <li>Cheetah - 
  3897.   <a href="http://www.cheetahtemplate.org">http://www.cheetahtemplate.org</a>
  3898.  
  3899.   <li>CherryPy -
  3900.   <a href="http://www.cherrypy.org">http://www.cherrypy.org</a>
  3901.  
  3902.   <li>Empy - 
  3903.   <a href="http://www.alcyone.com/pyos/empy/">http://www.alcyone.com/pyos/empy/</a></li>
  3904.  
  3905.   <li>Fenster - 
  3906.   <a href="http://fenster.sourceforge.net/">http://fenster.sourceforge.net</a></li>
  3907.  
  3908.   <li>Jaguar - 
  3909.   <a href="http://jaguar.sourceforge.net/">http://jaguar.sourceforge.net</a></li>
  3910.  
  3911.   <li>Java Server Pages, JSP - 
  3912.   <a href="http://java.sun.com/products/jsp/">http://java.sun.com/products/jsp</a></li>
  3913.  
  3914.   <li>JonPy - 
  3915.   <a href="http://jonpy.sourceforge.net/">http://jonpy.sourceforge.net</a></li>
  3916.  
  3917.   <li>Open Directory Project, ODP - 
  3918.   <a href="http://dmoz.org/Computers/Programming/Languages/Python/Modules/WWW/">http://dmoz.org/.../Python/Modules/WWW/
  3919. </a></li>
  3920.  
  3921.   <li>PHP - 
  3922.   <a href="http://www.php.net">http://www.php.net</a></li>
  3923.  
  3924.   <li>Poor Man's Zope, PMZ -
  3925.   <a href="http://pmz.sourceforge.net/">http://pmz.sourceforge.net</a></li>
  3926.  
  3927.   <li>PSP -
  3928.   <a href="http://www.ciobriefings.com/psp/">http://www.ciobriefings.com/psp</a></li>
  3929.  
  3930.   <li>PyHP -
  3931.   <a href="http://www.ccraig.org/software/pyhp">http://www.ccraig.org/software/pyhp</a></li>
  3932.  
  3933.   <li>PyML - 
  3934.   <a href="http://www.pyml.org">http://www.pyml.org</a></li>
  3935.  
  3936.   <li>PyServ -
  3937.   <a href="http://pyserv.sourceforge.net/">http://pyserv.sourceforge.net</a></li>
  3938.  
  3939.   <li>Python -
  3940.   <a href="http://www.python.org/">http://www.python.org</a></li>
  3941.  
  3942.   <li>Python Pages -
  3943.   <a href="http://www.embl-heidelberg.de/~chenna/pythonpages/">http://www.embl-heidelberg.de/~chenna/pythonpages</a></li>
  3944.  
  3945.   <li>Python Web Frameworks -
  3946.   <a href="http://www.boddie.org.uk/python/web_frameworks.html">http://www.boddie.org.uk/python/web_frameworks.html</a></li>
  3947.  
  3948.   <li>PyWX - 
  3949.   <a href="http://pywx.idyll.org">http://pywx.idyll.org</a></li>
  3950.  
  3951.   <li>mod_python -
  3952.   <a href="http://www.modpython.org/">http://www.modpython.org</a></li>
  3953.  
  3954.   <li>Quixote - 
  3955.   <a href="http://www.mems-exchange.org/software/quixote/">http://www.mems-exchange.org/software/quixote/</a></li>
  3956.  
  3957.   <li>Roadkill - 
  3958.   <a href="http://roadkill.sourceforge.net/">http://roadkill.sourceforge.net/</a></li>
  3959.  
  3960.   <li>Sixth Dev - 
  3961.   <a href="http://www.sixthdev.com/">http://www.sixthdev.com</a></li>
  3962.  
  3963.   <li>Skunkweb - 
  3964.   <a href="http://skunkweb.sourceforge.net">http://skunkweb.sourceforge.net</a></li>
  3965.  
  3966.   <li>Snakelets -
  3967.   <a href="http://snakelets.sourceforge.net/">http://snakelets.sourceforge.net</a></li>
  3968.  
  3969.   <li>Twisted Matrix - 
  3970.   <a href="http://www.twistedmatrix.com/">http://www.twistedmatrix.com</a></li>
  3971.  
  3972.   <li>Velocity -
  3973.   <a href="http://jakarta.apache.org/velocity/">http://jakarta.apache.org/velocity</a></li>
  3974.  
  3975.   <li>Wasp -
  3976.   <a href="http://www.execulink.com/~robin1/wasp/readme.html">http://www.execulink.com/~robin1/wasp/readme.html</a></li>
  3977.  
  3978.   <li>Webmacro -
  3979.   <a href="http://www.webmacro.org/">http://www.webmacro.org</a></li>
  3980.  
  3981.   <li>Webware - 
  3982.   <a href="http://webware.sourceforge.net/">http://webware.sourceforge.net</a></li>
  3983.  
  3984.   <li>Zope -
  3985.   <a href="http://www.zope.org/">http://www.zope.org</a></li>
  3986.  
  3987. </ul> <p>
  3988.  
  3989. [[toc.e()]]
  3990.  
  3991. [[toc.e()]]
  3992.  
  3993. [[include.spyce('inc/tail.spi') ]]
  3994.