Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style type="text/css"><!--
body {
font-family: arial,helvetica;
}
#sidebar table {
}
#sidebar td {
background-color: #eeeeff;
}
#sidebar p {
margin: 0;
padding: 0;
}
#sidebar div {
margin: 0px;
margin-bottom: 5px;
padding-left: 0.5em;
padding-right: 0.5em;
width: 100%;
}
#sidebar h2 {
font-family: sans-serif;
margin: 0px;
width: 100%;
font-size: 150%;
background-color: #6622cc;
color: white;
text-align: center;
}
#sidebar h3 {
margin: 0px;
font-size: 130%;
}
#sidebar ul a {
font-style: bold;
}
#sidebar ul {
margin: 0;
padding: 0;
list-style-type: none;
}
.code {
border: 2px dotted;
font-family: Courier,monospace;
font-size: 90%;
background-color: #E0E0E0;
margin-left: 10;
margin-right: 10;
padding-left: 10;
padding-right: 10;
padding-top: 0;
padding-bottom: 10;
}
a { text-decoration: none; color: #0000cc }
a:hover { text-decoration: underline; color: #0000cc; }
--></style>
<title>Spyce - Python Server Pages (PSP)</title>
<meta NAME="LANGUAGE" CONTENT="en-US">
<meta NAME="RATING" CONTENT="GENERAL">
<meta NAME="ROBOTS" CONTENT="ALL">
<meta name="abstract" content="Spyce is a server-side language that supports simple and efficient Python-based dynamic HTML generation. Those who like Python and are familiar with JSP, or PHP, or ASP, should have a look at Spyce.">
<meta name="description" content="Spyce - Python Server Pages: a server-side language that supports simple and efficient Python-based dynamic HTML generation.">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta HTTP-EQUIV="Refresh" CONTENT="1800">
<meta HTTP-EQUIV="Revisit-After" CONTENT="15 days">
<link rel="icon" href="spycefav.ico" type="image/x-icon">
<link rel="shortcut icon" href="spycefav.ico" type="image/x-icon">
</head>
<body bgcolor="#ffffff">
<table border=0 cellspacing=0 cellpadding=0 width="100%"><tr><td valign=top>
<!-- index -->
<div style="text-align:center">
<a href="http://spyce.sourceforge.net"><img src="/spyce.gif" border=0 alt="spyce" width=58 height=70></a>
</div>
<table id=sidebar width=250px>
<tr><td>
<h2>Download</h2>
<div>
<h3>Spyce 2.1</h3>
<center style="font-size: small">
<a href=/docs/whats-new-2-1.html>what's new</a>
<a href=http://svn.sourceforge.net/svnroot/spyce/branches/spyce-2.1/CHANGES>changelog</a>
<a href=/docs/license.html>license</a>
</center>
<center><a href=/docs/get.html><b>DOWNLOAD</b></a></center>
</div>
<h2>Community</h2>
<div>
<b>Discussion list signup</b>:
<FORM name=list1 Method=POST ACTION="https://lists.sourceforge.net/lists/subscribe/spyce-users">
<INPUT type="Text" name="email" size="30" value=""> <a href="javascript:document.list1.submit()">Go</a>
</FORM>
<b>Announcement list signup</b>:
<FORM name=list2 Method=POST ACTION="https://lists.sourceforge.net/lists/subscribe/spyce-announce">
<INPUT type="Text" name="email" size="30" value=""> <a href="javascript:document.list2.submit()">Go</a>
</FORM>
</div>
<h2>Documentation</h2>
<div>
<ul>
<li><a href=/docs/doc-intro.html>introduction</a>
<li><a href=/docs/doc-lang.html>language</a>
<li><a href=/docs/doc-runtime.html>runtime</a>
<li><a href=/docs/doc-mod.html>modules</a>
<li><a href=/docs/doc-tag.html>tags</a>
<li><a href=/docs/doc-conf.html>install</a>
<li><a href=/docs/eg.html>examples list</a>
</div>
<h2>Other</h2>
<div>
<ul>
<li><a href=http://sourceforge.net/projects/spyce>Sourceforge project</a>
<li><a href=/docs/mail.html>"Spyce Powered"</a>
<li><a href=/docs/links.html>Resources</a>
<li><a href=http://spyced.blogspot.com/>Spyced blog</a>
</ul>
</div>
</td></tr>
</table>
</td>
<td> </td>
<td width="100%" valign=top>
<!-- page title -->
<table border=0 width="100%"><tr>
<td align=right nowrap valign=bottom>
<a href=/index.html>home</a>
<a href=/docs/doc.html>documentation</a>
<a href=/docs/get.html>download</a>
</td>
<td align=right nowrap valign=bottom width=1>
<img alt="Spyce logo" src="/spyce2.png">
</td>
</tr></table>
<br><br>
<b><font face="arial, helvetica" size="+1"><big>Documentation</big></font></b><br clear=all>
<hr>
<!-- body -->
<center>
<big><b>Spyce - Python Server Pages (PSP) <br>
<big>User Documentation</big></b></big><p>
Release 2.1<p>
</center>
<center><b>
[ <a href="doc.html">Multi-Page Format</a> ]
</b></center>
<p>
<font color="#ee0000"><b>TABLE OF CONTENTS</b><br></font>
<ul>
<li>1. <a href="#intro">Introduction</a></li>
<ul>
<li>1.1. <a href="#intro_rationale">Rationale / competitive analysis</a></li>
<li>1.2. <a href="#intro_design">Design Goals</a></li>
</ul>
<li>2. <a href="#lang">Language</a></li>
<ul>
<li>2.1. <a href="#lang_string">Plain HTML and Active Tags</a></li>
<li>2.2. <a href="#lang_comment">Spyce Comments</a></li>
<li>2.3. <a href="#lang_directive">Spyce Directives</a></li>
<li>2.4. <a href="#lang_stmt">Python Statements</a></li>
<li>2.5. <a href="#lang_chunk">Python Chunks</a></li>
<li>2.6. <a href="#lang_chunkc">Python Class Chunks</a></li>
<li>2.7. <a href="#lang_expr">Python Expressions</a></li>
<li>2.8. <a href="#lang_lambda">Spyce Lambdas</a></li>
<li>2.9. <a href="#lang_asp">ASP/JSP syntax</a></li>
</ul>
<li>3. <a href="#runtime">Runtime</a></li>
<ul>
<li>3.1. <a href="#runtime_except">Exceptions</a></li>
<li>3.2. <a href="#runtime_transform">Code Transformation</a></li>
<li>3.3. <a href="#runtime_web">Dynamic Content</a></li>
<li>3.4. <a href="#runtime_static">Static Content</a></li>
<li>3.5. <a href="#runtime_cmdline">Command line</a></li>
<li>3.6. <a href="#runtime_common">Configuration</a></li>
<li>3.7. <a href="#runtime_util">Server utilities</a></li>
<ul>
<li>3.7.1. <a href="#runtime_util_scheduler">The Spyce scheduler</a></li>
<li>3.7.2. <a href="#runtime_util_su">spyceUtil</a></li>
</ul>
<li>3.8. <a href="#mod">Modules</a></li>
<ul>
<li>3.8.1. <a href="#mod_db">DB (implicit)</a></li>
<li>3.8.2. <a href="#mod_request">Request (implicit)</a></li>
<li>3.8.3. <a href="#mod_response">Response (implicit)</a></li>
<li>3.8.4. <a href="#mod_redirect">Redirect</a></li>
<li>3.8.5. <a href="#mod_cookie">Cookie</a></li>
<li>3.8.6. <a href="#mod_session">Session</a></li>
<li>3.8.7. <a href="#mod_pool">Pool</a></li>
<li>3.8.8. <a href="#mod_transform">Transform</a></li>
<li>3.8.9. <a href="#mod_compress">Compress</a></li>
<li>3.8.10. <a href="#mod_include">Include</a></li>
<li>3.8.11. <a href="#mod_internal">Internal modules</a></li>
<ul>
</ul>
<li>3.8.12. <a href="#mod_new">Writing Modules</a></li>
</ul>
<li>3.9. <a href="#tag">Tags</a></li>
<ul>
<li>3.9.1. <a href="#tag_core">Core</a></li>
<li>3.9.2. <a href="#tag_form">Form</a></li>
<li>3.9.3. <a href="#tag_handlers">Active Handlers</a></li>
<li>3.9.4. <a href="#tag_new2">Writing Tag Libraries</a></li>
<li>3.9.5. <a href="#tag_new">Writing Tag Libraries the hard way</a></li>
</ul>
<li>3.10. <a href="#conf">Installation</a></li>
<ul>
<li>3.10.1. <a href="#conf_overview">Overview</a></li>
<li>3.10.2. <a href="#conf_proxy">Web Server</a></li>
<li>3.10.3. <a href="#conf_source">CGI/FastCGI installation</a></li>
<li>3.10.4. <a href="#conf_modpython">Mod_Python</a></li>
<li>3.10.5. <a href="#conf_windows">Notes for Windows</a></li>
<li>3.10.6. <a href="#conf_rpm">Notes on RPM installation</a></li>
<li>3.10.7. <a href="#conf_apache">Notes on Apache integration</a></li>
<li>3.10.8. <a href="#conf_next">Starting your first project</a></li>
</ul>
<li>3.11. <a href="#runtime_prog">Programmatic Interface</a></li>
<ul>
<li>3.11.1. <a href="#runtime_prog_basicUsage">Basic usage</a></li>
<li>3.11.1. <a href="#runtime_prog_passingParameters">Passing parameters</a></li>
<li>3.11.1. <a href="#runtime_prog_requestAndResponse">Customized Request/Response classes</a></li>
<li>3.11.1. <a href="#runtime_prog_example">Example</a></li>
</ul>
</ul>
<li>4. <a href="#add">Addenda</a></li>
<ul>
<li>4.1. <a href="#add_perf">Performance</a></li>
<li>4.2. <a href="#add_history">History</a></li>
</ul>
</ul>
<hr>
<p><big><a name="intro"></a><b>1. <font color=#ee0000>INTRODUCTION</font></b></big><p>
This document aims to be the authoritative source of
information about Spyce, usable as a comprehensive refence, a user guide and a
tutorial. It should be at least skimmed from beginning to end,
so you have at least an idea of the functionality available and can refer
back for more details as needed. <p>
Spyce is a server-side language that supports elegant and
efficient Python-based dynamic HTML generation.
Spyce allows embedding Python in pages similar to how JSP embeds Java,
but Spyce is far more than a JSP clone. Out of the box, Spyce provides
development as rapid as other modern frameworks like Rails, but with an
cohesive design rather than a morass of special cases.
<p>
Spyce's modular design makes it very flexible
and extensible. It can also be used as a command-line utility for static text
pre-processing or as a web-server proxy.
<p>
Spyce's <a
href="#add_perf">performance</a> is comparable to the
other solutions in its class. <p>
<b>Note:</b> This manual assumes a knowledge of Python and focusses
exclusively on Spyce. If you do not already know Python, it is easy to
learn via this short <a
href="http://www.python.org/doc/current/tut/tut.html">tutorial</a>, and has
extensive <a href="http://www.python.org/doc/current/">documentation</a>.<p>
<big><a name="intro_rationale"></a><b>1.1. <font color=#ee0000>Rationale / competitive analysis</font></b></big><p>
<i>This section is somewhat dated. We plan to update it soon.</i>
<p>
A natural question to ask is why one would choose Spyce over JSP, ASP, PHP,
or any of the other HTML scripting languages that
perform a similar function. We compare Spyce with an array of exising tools:
<ul>
<li><i><b>Java Server Pages, JSP,</b></i> is a widely popular, effective and
well-supported solution based on Java Servlet technology. Spyce differs from
JSP in that it embeds Python code among the HTML, thus providing a number of
advantages over Java.
<ul>
<li>Python is a high-level scripting language,
where rapid prototyping is syntactically easier to perform.
<li>There is no need for a separate "expression langauge" in Spyce;
Python is well-suited for both larger modules and active tag scripting.
<li>Python
is interpreted and latently typed, which can be advantageous for
prototyping, especially in avoiding unnecessary binary incompatibility of
classes for minor changes.
<li>Spyce code is of first-order in the Spyce
language, unlike JSP, which allows you to create useful Spyce lambda
functions.
<li>Creating new active tags and modules is simpler in
Spyce than in JSP.
<li>Spyce is better-integrated than JSP; to get similar functionality
in JSP, you have to add JSF (Java Server Faces) and Tiles, or
equivalents.
</ul>
<p>
</li>
<li><i><b>PHP</b></i> is another popular webserver module for dynamic
content generation. The PHP interpreter engine and the language itself were
explicitly designed for the task of dynamic HTML generation, while Python is
a general-purpose scripting language.
<ul>
<li>Spyce leverages from the extensive
development effort in Python: since any Python library can be imported and
reused, Spyce does not need to rebuild many of the core function libraries
that have been implemented by the PHP project.
<li>Use of Python
often simplifies integration of Spyce with existing system environments.
<li>Spyce code is also first-order in the Spyce language and Spyce supports
active tags.
<li>Spyce is modular in its design, allowing
users to easily extend its base functinality with add-on modules.
<li>The Spyce engine can be run from the command-line, which allows
Spyce to be used as an HTML preprocessor.
</ul>
Spyce,
like PHP, can run entirely within the process space of a webserver or via
CGI (as well as other web server adapters), and has been benchmarked to be
competitive in <a href="#add_perf">performance</a>. </li> <p>
<li><i><b>ASP.NET</b></i> is a Microsoft technology
popular with Microsoft Internet Information Server (IIS) users. Visual
Basic .NET and C# are both popular implementation languages.
<ul>
<li>Spyce provides the power of the ASP.NET "component" development style
without trying to pretend that web applications live in a stateful,
event-driven environment. This is a leaky abstraction that causes
ASP.NET to have a steep learning curve while the user learns
where the rough edges are.
<li>ASP.NET is not well-supported outside the IIS environment. Spyce can
currently run as a standalone or proxy server, under mod_python (Apache),
or under CGI and <a
href="http://www.fastcgi.com">FastCGI</a>, which are
supported in the majority of web server environments. Adapters have also
been written for Xitami, Coil, Cheetah -- other web servers and frameworks.
<li>Spyce is open-source, and free.
</ul>
</li>
<p>
<li><i><b>WebWare with Python Server Pages, PSP,</b></i> is another
Python-based open-source development. PSP is similar in design to the Spyce
language, and shares many of the same benefits. Some important differences
include
<ul>
<li>Spyce supports both
Python chunks (indented Python) as well as PSP-style statements (braced
Python).
<li>Spyce supports active tags and component-based development
<li>Spyce code is first-order in the Spyce language
</ul>
PSP is also an integral part of
WebWare, an application-server framework similar to Tomcat Java-based
application server of the Apache Jakarta project. Spyce is to WebWare as JSP
is to Tomcat. Spyce is far simpler to install and run than WebWare (in the
author's humble opinion), and does not involve notions such as application
contexts. It aims to do only one thing well: provide a preprocessor and
runtime engine for the dynamic generation of HTML using embedded Python.
</li> <p>
<li><i><b>Zope</b></i> is an object-oriented open-source application server,
specializing in "content management, portals, and custom applications." Zope
is the most mature Python web application development environment, but
to a large degree suffers from
<a href=http://en.wikipedia.org/wiki/Second-system_effect>second-system syndrome</a>.
In the author's opinion, Zope is to a large degree responsible for the
<a href=http://www.python.org/moin/WebProgramming>large number of python
web environments</a>: a few years ago, it was de rigeur for talented programmers
to try Zope, realize it was a mess, and go off to write their own framework.
<p>
Zope provides a scripting language called DHTML and can call
extensions written in Perl or Python. Spyce embeds Python directly in the
HTML, and only Python. It is an HTML-embedded language, not an application
server. </li> <p>
</ul>
Spyce strikes a unique balance between power and simplicity.
Many users have said that this
is "exactly what they have been waiting for". Hopefully, this is the correct
point in the design space for your project as well.
<p>
<big><a name="intro_design"></a><b>1.2. <font color=#ee0000>Design Goals</font></b></big><p>
As a Spyce user, it helps to understand the broad design goals of this tool.
Spyce is designed to be:
<ul>
<li><b>Minimalist:</b> The philosophy behind the design of Spyce is only
to include features that particularly enhance its functionality over the
wealth that is already available from within Python. One can readily import
and use Python modules for many functions, and there is no need to recode
large bodies of functionality. </li> <p>
<li><b>Powerful:</b> Spyce aims to free the programmer from as much
"plumbing"-style drudgery as possible through features such as
<a href="#tag_handlers">Active Handlers</a>
and reusable <a href="#tag">Active Tags</a>.</li><p>
<li><b>Modular:</b> Spyce is built to be extended with
<a href="#mod">Spyce modules</a> and
<a href="#tag">Active Tags</a>
that provide additional functionality over the core engine
capabilities and standard Python modules. New features in the core engine
and language are rationalised against the option of creating a new module or
a new tag library. Standard Spyce modules and tag libraries are those that
are considered useful in a general setting and are included in the default
Spyce distribution. Users and third-parties are encouraged to develop their
own Spyce modules. </li> <p>
<li><b>Intuitive:</b> Obey user expectations. Part of this is avoiding
special cases.</li> <p>
<li><b>Convenient:</b> Using Spyce should be made as efficient as possible.
This, for example, is the reason behind the choice of <font
face=courier>[[</font> as delimeters over alternatives such as <font
face=courier><?</font> (php) and <font face=courier><%</font> (jsp).
(However, ASP/JSP-style delimeters are also supported, so if you're
used to that style and like it, feel free to continue using it with Spyce.)
Functions and
modules are also designed with as many defaults as possible.
There are no XML configuration files in Spyce.
</li> <p>
<li><b>Single-purpose:</b> To be the best, most versatile, wildly-popular
Python-based dynamic HTML engine. Nothing more; nothing less. </li> <p>
<li><b>Fast:</b> <a href="#add_perf">Performance</a> is
important. It is expected that Spyce will perform comparably with any other
dynamic, scripting solutions available.
</li> <p>
</ul> <p>
Now, let's start using Spyce... <p>
<p><big><a name="lang"></a><b>2. <font color=#ee0000>LANGUAGE</font></b></big><p>
The basic structure of a Spyce script is an HTML file with embeddings. There
are six types of possible embeddings among the plain HTML text:
<ul>
<li><font face=courier><b><</b><a href="#lang_string">taglib:name</a> attr1=val1 ...<b>></b></font>
<br><i>Active tags may include presentation and action code.</i>
<li><font face=courier><b>[[--</b> <a href="#lang_comment">Spyce comment</a> <b>--]]</b></font>
<br><i>Enclosed code is elided from the compiled Spyce class.</i>
<li><font face=courier><b>[[\</b> <a href="#lang_chunk">Python chunk</a> <b>]]</b></font>
<br><i>Embed python in your code.</i>
<li><font face=courier><b>[[!</b> <a href="#lang_chunkc">Python class chunk</a> <b>]]</b></font>
<br><i>Like chunks, but at the class level rather than the spyceProcess method.</i>
<li><font face=courier><b>[[</b> <a href="#lang_stmt">Python statement(s)</a> <b>]]</b></font>
<br><i>Like chunks, but may include braces to indicate that the block should continue after the ]].</i>
<li><font face=courier><b>[[=</b> <a href="#lang_expr">Python expression</a> <b>]]</b></font>
<br><i>Output the result of evaluating the given expression.</i>
<li><font face=courier><b>[[.</b> <a href="#lang_directive">Spyce directive</a> <b>]]</b></font>
<br><i>Pass options to the Spyce compiler.</i>
<li><font face=courier><b>[[spy</b> <a href="#lang_lambda">lambda</a> <b>]]</b></font>
<br><i>Allows dynamic compilation of Spyce code to a python function.</i>
</ul>
Each Spyce tag type has a
unique beginning delimeter, namely <font face=courier><b>[[</b></font>, <font
face=courier><b>[[\</b></font>, <font face=courier><b>[[=</b></font>, <font
face=courier><b>[[.</b></font> or <font face=courier><b>[[--</b></font>. All
tags end with <font face=courier><b>]]</b></font>, except comment tags, which
end with <font face=courier><b>--]]</b></font>.
<p>
Since
<font face=courier><b>[[</b></font> and
<font face=courier><b>]]</b></font>
are special Spyce delimeters, one would escape them as
<font face=courier><b>\[[</b></font> and
<font face=courier><b>\]]</b></font>
for use in HTML text. They can not be escaped within Python code, but the
string expressions
<font face=courier><b>("["*2)</b></font> and
<font face=courier><b>("]"*2)</b></font>, or equivalent expressions,
can be used instead, or the brackets can be conveniently separated with a
space in the case of list or slicing expressions. <p>
<big><a name="lang_string"></a><b>2.1. <font color=#ee0000>Plain HTML and Active Tags</font></b></big><p>
Static plain HTML strings are printed as they are encountered. Depending on
the <a href="#lang_directive">compacting</a> mode of the
Spyce compiler, some whitespace may be eliminated. The Spyce <a
href="#mod_transform">transform</a> module, for example, may
further pre-processes this string, by inserting transformations into the
output pipe. This is useful, for example, for dynamic compression of the
script result. <p>
The Spyce language supports <a href="">tag libraries</a>.
Once a tag library is imported under some name, <i>mytags</i>, then all static
HTML tags of the form <font
face=courier><<i>mytags</i>:foo ... ></font> become "active".
That is, code from the tag library is executed at that point in the document.
Tags can control their output, conditionally skip or loop the execution of
their bodies, and can interact with other active tags in the document. They
are similar, in spirit and functionality, to JSP tags. Tag libraries and <a
href="">modules</a> (discussed later) can both
considerably reduce the amount of code on a Spyce page, and increase code
reuse and modularity. <p>
<big><a name="lang_comment"></a><b>2.2. <font color=#ee0000>Spyce Comments</font></b></big><p>
<b>Syntax: <font face=courier>[[-- comment --]]</font></b> <p>
Spyce comments are ignored, and do not produce any output, meaning that they
will not appear at the browser even in the HTML source. The first line of a
Spyce file, if it begins with the characters <b>#!</b>, is also considered a
comment, by Unix scripting convention. Spyce comments do <i>not</i> nest. <p>
<big><a name="lang_directive"></a><b>2.3. <font color=#ee0000>Spyce Directives</font></b></big><p>
<b>Syntax: <font face=courier>[[. directive ]]</font></b>
<p>
Spyce directives directly affect the operation of the Spyce compiler. There
is a limited set of directives, listed and explained below:
<ul>
<li><b><font face=courier>
[[.<b>compact</b> mode=<i>mode</i>]] </font>:</b><br>
Spyce can output the static HTML strings in various modes of compaction,
which can both save bandwidth and improve download times without visibly
affecting the output. Compaction of static HTML strings is performed once
when the input Spyce file is compiled, and there is no additional run-time
overhead beyond that. Dynamically generated content from Python code tags
and expressions is not compacted nor altered in any way. Spyce can operate
in one of the compaction modes listed below. One can use the <b>compact</b>
tag to change the compaction mode from that point in the file forwards. <p>
<ul>
<li><b>off</b>: No compaction is performed. Every space and newline in the
static HTML strings is preserved. </li> <p>
<li><b>space</b>: Space compaction involves reducing any consecutive runs
of spaces or tabs down to a single space. Any spaces or tabs at the
beginning of a line are eliminated. These transformations will not affect
HTML output, barring the <pre> tag, but can considerably reduce the
size of the emitted text. </li> <p>
<li><b>line</b>: Line compaction eliminates any (invisible) trailing
whitespace at the end of lines. More significantly it improves the indented
presentation of HTML, by ignoring any lines that do not contain any static
text or expression tags. Namely, it removes all the whitespace, including
the line break, surrounding the code or directives on that line. This
compaction method usually "does the right thing", and produces nice HTML
without requiring tricky indentation tricks by the developer. It is,
therefore, the <b>initial</b> compaction mode. </li><p>
<li><b>full</b>: Full compaction applies both space and line compaction. If
the optional mode attribute is omitted, full compaction mode is the
<b>default</b> value assumed. </li><p>
</ul>
</li><p>
<li><b><font face=courier>
[[.<b>import</b> name=<i>name</i> from=<i>file</i> as=<i>name</i> args=<i>arguments</i>]] </font>:</b><br>
The import directive loads and defines a Spyce module into the global
context. (The <font face=courier>[[.module ... ]]</font>directive
is synonymous.) A Spyce <a href="#mod">module</a> is a
Python file, written specifically to interact with Spyce. The <b>name</b>
parameter is required, specifying the name of the Python class to load. The
<b>file</b> parameter is optional, specifying the file where the named class
is to be found. If omitted, file will equal <font
face=courier><i>name</i>.py</font>. The file path can be absolute or
relative. Relative paths are scanned in the Spyce home, user-configurable <a
href="#runtime_common">server path</a> directories and current
script directory, in that order. Users are encouraged to name or prefix their
modules uniquely so as not to be masked by system modules or tag libraries.
The <b>as</b> parameter is optional, and specifies the name under which the
module will be installed in the global context. If omitted, this parameter
defaults to the name parameter. Lastly, the optional <b>args</b> parameter
provides arguments to be passed to the module initialization function. All
Spyce modules are <b>start()</b>ed before Spyce processing begins,
<b>init()</b>ed at the point where the directive is placed in the code, and
<b>finish()</b>ed after Spyce processing terminates. It is convention to
place modules at, or near, the very top of the file unless the location of
initialization is relevant for the functioning of the specific module. <p>
<b><font face=courier>
[[.<b>import</b> names="<i>name1,name2,...</i>"]] </font>:</b><br>
An alternative syntax allows convenient loading of multiple Spyce modules.
One can not specify non-standard module file locations, nor rename the
modules using this syntax. </li><p>
<li><b><font face=courier>
[[.<b>taglib</b> name=<i>name</i> from=<i>file</i> as=<i>name</i>]] </font>:</b><br>
The taglib directive loads a Spyce tag library. A Spyce <a
href="#tag">tag library</a> is a Python file, written
specifically to interact with Spyce. The <b>name</b> parameter specifies
the name of the Python class to load if using a 1.x-style taglib;
otherwise it is ignored. The <b>file</b> parameter is
optional, specifying the file where the named class is to be found. If
omitted, file will equal <font face=courier><i>name</i>.py</font>. The file
path can be absolute or relative. Relative paths are scanned in the Spyce
home, user-configurable <a href="#runtime_common">server
path</a> directories and current script directory, in that order. Users are
encouraged to name or prefix their tag libraries uniquely so as not to be
masked by system tag libraries and modules. The <b>as</b> parameter is
optional, and specifies the unique tag prefix that will be used to identify
the tags from this library. If omitted, this parameter defaults to the name
parameter. It is convention to place tag library directives at, or near, the
very top of the file. The tags only become active after the point of the tag
library directive. <p>
Also note that the configuration parameter <i>globaltags</i> allows you
to set up tag libraries globally, freeing you from having to specify the
taglib directive on each page that uses a tag. By default, globaltags
installs core under the spy: prefix, and form under the f: prefix.
(Tag libraries specified in globaltags are only loaded if the Spyce compiler
determines they are actually used on the page, so there is no performance
difference between globaltags and manually setting up taglib for each page.)
<p>There are some additional directives that are only legal when
<a href="#tag_new2">defining an active tag library</a>.
</ul> <p>
It is important to note that Spyce directives are processed at <i>compile</i>
time, not during the execution of the script, much like directives in C, and
other languages. In other words, they are processed as the Python code for the
Spyce script is being produced, not as it is being executed. Consequently, it
is not possible to include runtime values as parameters to the various
directives.<p>
<big><a name="lang_stmt"></a><b>2.4. <font color=#ee0000>Python Statements</font></b></big><p>
<b>Syntax: <font face=courier>[[ statement(s) ]]</font></b> <p>
The contents of a code tag is one or more Python statements. The statements
are executed when the page is emitted. There will be no output unless the
statements themselves generate output. <p>
The statements are separated with semi-colons or new lines, as in regular
Python scripts. However, unlike regular Python code, Python statements <i>do
<b>not</b> nest based on their level of indentation</i>. This is because
indenting code properly in the middle of HTML is difficult on the developer.
To alleviate this problem, Spyce supports a slightly modifed Python syntax:
proper nesting of Spyce statements is achieved using begin- and end-braces:
<font face=courier><b>{</b></font> and <font face=courier><b>}</b></font>,
respectively. These <b>MUST</b> be used, because the compiler regenerates the
correct indentation based on these markers alone. Even single-statement blocks
of code must be wrapped with begin and end braces. (If you prefer to use
Python-like indentation, read about <a
href="#lang_chunk">chunks</a>). <p>
The following Spyce code, from the <font face=courier>Hello World!</font>
example above: <p>
<table align=center border=0><tr><td>
<font face=courier>
<b><pre>
[[ for i in range(10): <font color=red>{</font> ]]
[[=i]]
[[ <font color=red>}</font> ]]
</pre></b>
</font>
</td></tr></table>
<p>
produces the following indented Python code:<p>
<table align=center border=0><tr><td>
<font face=courier>
<b><pre>
for i in range(10):
response.writeStatic(' ')
response.writeExpr(i)
response.writeStatic('\n')
</pre></b>
</font>
</td></tr></table>
<p>
Without the braces, the code produced would be unindented and, in this case,
also invalid: <p>
<table align=center border=0><tr><td>
<font face=courier>
<b><pre>
for i in range(10):
response.writeStatic(' ')
response.writeExpr(i)
response.writeStatic('\n')
</pre></b>
</font>
</td></tr></table>
<p>
Note how the indentation of the expression does not affect the indentation of
the Python code that is produced; it merely changes the number of spaces in
the <font face=courier>writeStatic</font> string. Also note that unbalanced
open and close braces within a single tag are allowed, as in the example
above, and they modify the indentation level outside the code tag. However,
the braces must be balanced across an entire file. Remember: inside the <font
face=courier>[[ ... ]]</font> delimiters, <b>braces are always
required</b> to change the indentation level. <p>
<big><a name="lang_chunk"></a><b>2.5. <font color=#ee0000>Python Chunks</font></b></big><p>
<b>Syntax: <font face=courier>[[\ Python chunk ]]</font></b>
<p>
There are many Python users that experience anguish, disgust or dismay upon
reading the previous section: "Braces!? Give me real, indented Python!". These
intendation zealots will be more comfortable using Python chunks, which is why
Spyce supports them. Feel free to use Spyce statements or chunks
inter-changeably, as the need arises.<p>
A Python chunk is straight Python code, and the <i>internal</i> indentation is
preserved. The entire block is merely outdented (or indented) as a whole, such
that the first non-empty line of the block matches the indentation level of
the context into which the chunk was placed. Thus, a Python chunk can not
affect the indentation level outside its scope, but internal indentation is
fully respected, relative to the first line of code, and braces (<font
face=courier>{</font>, <font face=courier>}</font>) are not required, nor
expected for anything but Python dictionaries. Since the first line of code is
used as an indentation reference, it is recommended that the start delimeter
of the tag (i.e. the <font face=courier>[[\</font>) be placed on its own
line, above the code chunk, as shown in the following example: <p>
<table align=center border=0><tr><td>
<font face=courier>
<b><pre>[[\
def printHello(num):
for i in range(num):
response.write('hello<br>')
printHello(5)
]]</pre></b>
</font>
</td></tr></table>
<p>
Naturally, one should <i>not</i> use braces here for purposes of indentation,
only for Python dictionaries. Additional braces will merely generate Python
syntax errors in the context of chunks. To recap: a Python statement tag
should contain braced Python; A Python chunk tag should contain regular
indented Python. <p>
<big><a name="lang_chunkc"></a><b>2.6. <font color=#ee0000>Python Class Chunks</font></b></big><p>
<b>Syntax: <font face=courier>[[! Python class chunk ]]</font></b>
<p>
Behind the scenes, your Spyce files are compiled into a class called <font
face=courier>spyceImpl</font>. Your Spyce script runs in a method of this class
called <font face=courier>spyceProcess</font>. Class chunks allow you to
specify code to be placed inside the class, but outside the main method,
analogously to the "<%!" token in JSP code. (If you would like to
see your Spyce file in compiled Python form, use the following command-line:
<font face=courier><b>spyce.py -c myfile.spy</b></font>.) <p>
<p>
This is primarily useful when defining active
handlers without using a separate .py file: <a href="#tag_handlers">active handlers</a> are the first
thing that the spyceProcess calls, even before any "python chunks."
For a handler callback to be visible at this stage, it needs to be defined
at the class level. Class chunks to the rescue:
<p>
<table border=1 align=center>
<tr><td align=left bgcolor="#cccccc">
<font face="arial, helvetica" size="-1"><b>examples/handlerintro.spy</b></font>
</td></tr><tr><td>
<font face=courier>
<pre style='font-family: courier,monospace; font-size: small'><font color="#000000"><b><font color="#0000CC">[[!
def calculate(self, api, x, y):
self.result = x * y
]]</font>
<font color="#229922"><spy:parent title="Active Handler example" /></font>
<font color="#229922"><f:form></font>
<font color="#229922"><f:text name="x:float" default="2" label="first value" /></font>
<font color="#229922"><f:text name="y:float" default="3" label="second value" /></font>
<font color="#229922"><f:submit handler="self.calculate" value="Multiply" /></font>
<font color="#229922"></f:form></font>
<p>
Result: <font color="#CC0000">[[= hasattr(self, 'result') and self.result or '(no result yet)' ]]</font>
</p>
</b></font></pre>
</font>
</td></tr><tr><td align=right bgcolor="#cccccc">
<font face="arial, helvetica" size="-1">
<b><a href="/docs/examples/handlerintro.spy">Run this code</a></b>
</font>
</td></tr></table>
<p>
<big><a name="lang_expr"></a><b>2.7. <font color=#ee0000>Python Expressions</font></b></big><p>
<b>Syntax: <font face=courier>[[= expression ]]</font></b>
<p>
The contents of an expression tag is a Python expression. The result of that
expression evaluation is printed using the its string representation.
The Python object None is special cased to output as the empty string
just as it is in the Python interactive shell. This is almost always
more convenient when working with HTML. (If you really want a literal
string 'None' emitted instead, use response.write in a statement or chunk.)
<p>
The Spyce <a href="#mod_transform">transform</a> module, can
pre-processes this result, to assist with mundane tasks such as ensuring that
the string is properly HTML-encoded, or formatted. <p>
<big><a name="lang_lambda"></a><b>2.8. <font color=#ee0000>Spyce Lambdas</font></b></big><p>
<b>Syntax: <font face=courier>[[spy <i>[params]</i> : <i>spyce lambda code</i> ]]</font></b>
<br>
<b>or: <font face=courier>[[spy! <i>[params]</i> : <i>spyce lambda code</i> ]]</font></b>
<p>
A nice feature of Spyce is that Spyce scripts are first-class members of the
language. In other words, you can create a Spyce lambda (or function) in any
of the Spyce Python elements (statements, chunks and expressions). These can
then be invoked like regular Python functions, stored in variables for later
use, or be passed around as paramaters. This feature is often very useful for
templating (example shown below), and can also be used to implement more
esoteric processing functionality, such as internationalization, multi-modal
component frameworks and other kinds of polymorphic renderers. <p>
It is instructive to understand how these functions are generated. The <font
face="courier">[[spy ... : ... ]]</font> syntax is first
translated during compilation into a call to the define() function of the <a
href="#mod_lambda">spylambda</a> module. At runtime, this
call compiles the Spyce code at the point of its definition, and returns a
function. While the invocation of a Spyce lambda is reasonably efficient, it
is certainly not as fast as a regular Python function invocation. The
spycelambda can be memoized (explained in the <a
href="#mod_lambda">spylambda</a> module section) by using
the <font face=courier>[[spy! ... : ... ]]</font>
syntax. However, even with this optimization one should take care to use
Python lambdas and functions when the overhead of Spyce parsing and invocation
is not needed. <p>
Note that Spyce lambdas do not currently support nested variable scoping, nor
default parameters. The global execution context (specifically, Spyce modules)
of the Spyce lambda is defined at the point of its execution. <p>
<table border=1 align=center>
<tr><td align=left bgcolor="#cccccc">
<font face="arial, helvetica" size="-1"><b>examples/spylambda.spy</b></font>
</td></tr><tr><td>
<font face=courier>
<pre style='font-family: courier,monospace; font-size: small'><font color="#000000"><b><font color="#0000CC">[[\
# table template
table = <font color="#000000"><b>[[spy! title, data:
<table>
<tr>
<font color="#0000CC">[[for cell in title: {]]</font>
<td><b><font color="#CC0000">[[=cell]]</font></b></td>
<font color="#0000CC">[[}]]</font>
</tr>
<font color="#0000CC">[[for row in data: {]]</font>
<tr>
<font color="#0000CC">[[for cell in row: {]]</font>
<td><font color="#CC0000">[[=cell]]</font></td>
<font color="#0000CC">[[}]]</font>
</tr>
<font color="#0000CC">[[}]]</font>
</table>
]]</b></font>
# table information
title = ['Country', 'Size', 'Population', 'GDP per capita']
data = [
[ 'USA', '9,158,960', '280,562,489', '$36,300' ],
[ 'Canada', '9,220,970', '31,902,268', '$27,700' ],
[ 'Mexico', '1,923,040', '103,400,165', '$9,000' ],
]
]]</font>
<font color="#ff7448">[[-- emit web page --]]</font>
<html><body>
<font color="#0000CC">[[ table(title, data) ]]</font>
</body></html>
</b></font></pre>
</font>
</td></tr><tr><td align=right bgcolor="#cccccc">
<font face="arial, helvetica" size="-1">
<b><a href="/docs/examples/spylambda.spy">Run this code</a></b>
</font>
</td></tr></table>
<p>
<big><a name="lang_asp"></a><b>2.9. <font color=#ee0000>ASP/JSP syntax</font></b></big><p>
Finally, due to popular demand, because of current editor support and people
who actually enjoy pains in their wrists, the Spyce engine will respect
ASP/JSP-like delimeters. In other words, it will also recognize the following
syntax:
<ul>
<li><font face=courier><b><%--</b> <a href="#lang_comment">Spyce comment</a> <b>--%></b></font></li>
<li><font face=courier><b><%@</b> <a href="#lang_directive">Spyce directive</a> <b>%></b></font></li>
<li><font face=courier><b><%</b> <a href="#lang_stmt">Python statement(s)</a> <b>%></b></font></li>
<li><font face=courier><b><%\</b> <a href="#lang_chunk">Python chunk</a> <b>%></b></font></li>
<li><font face=courier><b><%!</b> <a href="#lang_chunkc">Python class chunk</a> <b>%></b></font></li>
<li><font face=courier><b><%=</b> <a href="#lang_expr">Python expression</a> <b>%></b></font></li>
<li><font face=courier><b><%spy</b> [parameters] <b>:</b> <a href="#lang_lambda">spyce lambda code</a> <b>%></b></font></li>
</ul>
The two sets of delimeters may be used interchangeably within the same file,
though for the sake of consistency this is not recommended.
<p><big><a name="runtime"></a><b>3. <font color=#ee0000>RUNTIME</font></b></big><p>
Having covered the Spyce language syntax, we now move to describing the
runtime processing. Each time a request comes in, the cache of compiled Spyce
files is checked for the compiled version of the requisite Spyce file. If one
is not found, the Spyce file is quickly read, transformed, compiled and cached
for future use. <p>
The compiled Spyce is initialized, then processed, then finalized. The
initialization consists of initializing all the Spyce modules. The Spyce file
is executed top-down, until the end is reached or an exception is thrown,
whichever comes first. The finalization step then finalizes each module in
reverse order of initialization, and any buffered output is automatically
flushed. <p>
<big><a name="runtime_except"></a><b>3.1. <font color=#ee0000>Exceptions</font></b></big><p>
The Spyce file is executed top-down, until the end of the file is reached, a
valued is <font face="courier">return</font>ed, or an exception is thrown,
whichever comes first. If the code terminates via an unhandled exception, then
it is caught by the Spyce engine. Depending on the exception type, different
actions are taken:
<ul>
<li><b>spyceDone</b> can be raised at any time to stop the Spyce processing
(without error) at that point. It is often used to stop further output, as
in the example below that emits a binary image file. The spyceDone
exception, however, is more useful for modules writers. In regular Spyce
code one could simply issue a <font face="courier">return</font> statement,