Author: chrisz
Date: Sat Jun 20 17:41:03 2009
New Revision: 7975
Added:
Webware/trunk/PSP/Tests/FixPath.py (contents, props changed)
Webware/trunk/PSP/Tests/TestBraceConverter.py (contents, props changed)
Webware/trunk/PSP/Tests/TestCompiler.py
- copied, changed from r7973, /Webware/trunk/PSP/Tests/CompileTest.py
Webware/trunk/PSP/Tests/TestContext.py (contents, props changed)
Webware/trunk/PSP/Tests/TestUtils.py
- copied, changed from r7973, /Webware/trunk/PSP/Tests/PSPUtilsTest.py
Removed:
Webware/trunk/PSP/Tests/CompileTest.py
Webware/trunk/PSP/Tests/PSPUtilsTest.py
Modified:
Webware/trunk/AllTests.py
Webware/trunk/DocSupport/ClassList.py
Webware/trunk/DocSupport/PySummary.config
Webware/trunk/DocSupport/PySummary.py
Webware/trunk/DocSupport/autotoc.py
Webware/trunk/DocSupport/buildhtml.py
Webware/trunk/MiscUtils/PickleCache.py
Webware/trunk/MiscUtils/Tests/TestDataTable.py
Webware/trunk/MiscUtils/Tests/TestDictForArgs.py
Webware/trunk/PSP/BraceConverter.py
Webware/trunk/PSP/Context.py
Webware/trunk/PSP/Docs/RelNotes-X.Y.phtml
Webware/trunk/PSP/Docs/UsersGuide.phtml
Webware/trunk/PSP/Examples/APSPinclude.html
Webware/trunk/PSP/Examples/APSPinclude.psp
Webware/trunk/PSP/Examples/PSPTests-Braces.psp
Webware/trunk/PSP/Examples/PSPTests.psp
Webware/trunk/PSP/Examples/View.py
Webware/trunk/PSP/Examples/my_include.psp
Webware/trunk/PSP/Generators.py
Webware/trunk/PSP/PSPCompiler.py
Webware/trunk/PSP/PSPPage.py
Webware/trunk/PSP/PSPParser.py
Webware/trunk/PSP/PSPServletFactory.py
Webware/trunk/PSP/PSPUtils.py
Webware/trunk/PSP/ParseEventHandler.py
Webware/trunk/PSP/Properties.py
Webware/trunk/PSP/ServletWriter.py
Webware/trunk/PSP/StreamReader.py
Webware/trunk/PSP/cl_psp.py
Webware/trunk/WebKit/Tests/twill/PSP.twill
Webware/trunk/install.py
Log:
Some clean-up, optimization and improvements of PSP.
Modified: Webware/trunk/AllTests.py
==============================================================================
--- Webware/trunk/AllTests.py (original)
+++ Webware/trunk/AllTests.py Sat Jun 20 17:41:03 2009
@@ -32,8 +32,10 @@
'TaskKit.Tests.Test.makeTestSuite',
- 'PSP.Tests.PSPUtilsTest',
- 'PSP.Tests.CompileTest',
+ 'PSP.Tests.TestContext',
+ 'PSP.Tests.TestUtils',
+ 'PSP.Tests.TestBraceConverter',
+ 'PSP.Tests.TestCompiler',
'UserKit.Tests.ExampleTest',
'UserKit.Tests.Test',
Modified: Webware/trunk/DocSupport/ClassList.py
==============================================================================
--- Webware/trunk/DocSupport/ClassList.py (original)
+++ Webware/trunk/DocSupport/ClassList.py Sat Jun 20 17:41:03 2009
@@ -140,7 +140,7 @@
def roots(self):
roots = []
for klass in self._klasses.values():
- if len(klass._bases) == 0:
+ if not klass._bases:
roots.append(klass)
return roots
@@ -150,7 +150,7 @@
for klass in roots:
klass.printList(file=file)
- def printForWeb(self, hierarchic=0, file=sys.stdout):
+ def printForWeb(self, hierarchic=False, file=sys.stdout):
if isinstance(file, basestring):
file = open(file, 'w')
closeFile = True
Modified: Webware/trunk/DocSupport/PySummary.config
==============================================================================
--- Webware/trunk/DocSupport/PySummary.config (original)
+++ Webware/trunk/DocSupport/PySummary.config Sat Jun 20 17:41:03 2009
@@ -1,6 +1,6 @@
{
'html': {
- 'tabSubstitute': ' '*4, # eg, 4 spaces per tab
+ 'tabSubstitute': ' ', # 4 spaces
'file': ('''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -36,7 +36,7 @@
},
'text': {
- 'tabSubstitute': ' '*4, # eg, 4 spaces per tab
+ 'tabSubstitute': ' ', # 4 spaces
'file': ('', ''),
'class': ('\n', ''),
'def': ('', ''),
Modified: Webware/trunk/DocSupport/PySummary.py
==============================================================================
--- Webware/trunk/DocSupport/PySummary.py (original)
+++ Webware/trunk/DocSupport/PySummary.py Sat Jun 20 17:41:03 2009
@@ -92,8 +92,8 @@
if self._lines:
for line in self._lines:
type = line.type()
- if line.text()[:1].lstrip() \
- and settings[type][0][:1] == '\n':
+ if (line.text()[:1].lstrip()
+ and settings[type][0][:1] == '\n'):
res.append('\n')
res.append(settings[type][0])
if span:
Modified: Webware/trunk/DocSupport/autotoc.py
==============================================================================
--- Webware/trunk/DocSupport/autotoc.py (original)
+++ Webware/trunk/DocSupport/autotoc.py Sat Jun 20 17:41:03 2009
@@ -173,7 +173,7 @@
mindepth = 6
headings = []
names = {}
- names_created = 0
+ names_created = False
depths = {}
group = self._heading_pattern.groupindex
for heading_found in headings_found:
@@ -192,7 +192,7 @@
title = heading_found[group['title'] - 1]
name = heading_found[group['name'] - 1]
if name:
- name_created = 0
+ name_created = False
else: # no name given
name = self._make_name(title) # create one
if names.has_key(name): # make sure it is unique
@@ -203,7 +203,7 @@
names[name] = n
else:
names[name] = 1
- names_created = name_created = 1
+ names_created = name_created = True
heading = Heading(depth, title, name)
heading._pattern = heading_found[group['pattern'] - 1]
heading._name_created = name_created
Modified: Webware/trunk/DocSupport/buildhtml.py
==============================================================================
--- Webware/trunk/DocSupport/buildhtml.py (original)
+++ Webware/trunk/DocSupport/buildhtml.py Sat Jun 20 17:41:03 2009
@@ -1,6 +1,5 @@
#!/usr/bin/env python
-# $Id: buildhtml.py 5019 2007-03-12 21:48:30Z wiemann $
# Author: David Goodger <goodger@...>
# Copyright: This module has been placed in the public domain.
@@ -53,7 +52,7 @@
(('Recursively scan subdirectories for files to process. '
'This is the default.',
['--recurse'],
- {'action': 'store_true', 'default': 1,
+ {'action': 'store_true', 'default': True,
'validator': frontend.validate_boolean}),
('Do not scan subdirectories for files to process.',
['--local'], {'dest': 'recurse', 'action': 'store_false'}),
@@ -132,12 +131,12 @@
"""
for name, publisher in self.publishers.items():
option_parser = OptionParser(
- components=publisher.components, read_config_files=1,
+ components=publisher.components, read_config_files=True,
usage=usage, description=description)
publisher.option_parser = option_parser
publisher.setting_defaults = option_parser.get_default_values()
frontend.make_paths_absolute(publisher.setting_defaults.__dict__,
- option_parser.relative_path_settings)
+ option_parser.relative_path_settings)
publisher.config_settings = (
option_parser.get_standard_config_settings())
self.settings_spec = self.publishers[''].option_parser.parse_args(
@@ -165,7 +164,7 @@
settings.update(self.settings_spec.__dict__, publisher.option_parser)
return settings
- def run(self, directory=None, recurse=1):
+ def run(self, directory=None, recurse=True):
recurse = recurse and self.initial_settings.recurse
if directory:
self.directories = [directory]
@@ -193,12 +192,10 @@
if fnmatch(names[i], pattern):
# Modify in place!
del names[i]
- prune = False
for name in names:
if name.endswith('.txt'):
- prune = self.process_txt(directory, name)
- if prune:
- break
+ if self.process_txt(directory, name):
+ break # prune
if not recurse:
del names[:]
@@ -209,8 +206,8 @@
publisher = '.txt'
settings = self.get_settings(publisher, directory)
pub_struct = self.publishers[publisher]
- if settings.prune and (directory in settings.prune):
- return 1
+ if settings.prune and directory in settings.prune:
+ return True
settings._source = os.path.normpath(os.path.join(directory, name))
settings._destination = settings._source[:-4]+'.html'
if not self.initial_settings.silent:
@@ -225,7 +222,7 @@
settings=settings)
except ApplicationError, error:
print >>sys.stderr, (' Error (%s): %s'
- % (error.__class__.__name__, error))
+ % (error.__class__.__name__, error))
if __name__ == "__main__":
Modified: Webware/trunk/MiscUtils/PickleCache.py
==============================================================================
--- Webware/trunk/MiscUtils/PickleCache.py (original)
+++ Webware/trunk/MiscUtils/PickleCache.py Sat Jun 20 17:41:03 2009
@@ -58,7 +58,7 @@
from pickle import load, dump
-class PickleCache:
+class PickleCache(object):
"""Simple abstract base class for PickleCacheReader and PickleCacheWriter."""
_verbose = verbose
@@ -119,8 +119,8 @@
print 'EOFError - not loading'
shouldDeletePickle = True
except Exception, exc:
- print 'WARNING: %s: %s: %s' % (
- self.__class__.__name__, exc.__class__, exc)
+ print 'WARNING: %s: %s: %s' % (self.__class__.__name__,
+ exc.__class__.__name__, exc)
shouldDeletePickle = True
else:
file.close()
@@ -158,10 +158,10 @@
if v:
print 'Attempting to remove pickle cache file.'
os.remove(picklePath)
- except OSError, e:
+ except OSError, exc:
if v:
print 'Failed to remove: %s: %s' % (
- e.__class__.__name__, e)
+ exc.__class__.__name__, exc)
if v:
print 'Done reading data.'
Modified: Webware/trunk/MiscUtils/Tests/TestDataTable.py
==============================================================================
--- Webware/trunk/MiscUtils/Tests/TestDataTable.py (original)
+++ Webware/trunk/MiscUtils/Tests/TestDataTable.py Sat Jun 20 17:41:03 2009
@@ -22,7 +22,7 @@
i = 0
while i < len(dt):
match = data[i]
- self.assertEquals(dt[i].asList(), match,
+ self.assertEqual(dt[i].asList(), match,
'For element %d, I expected "%s" but got "%s"'
% (i, match, dt[i].asList()))
i += 1
Modified: Webware/trunk/MiscUtils/Tests/TestDictForArgs.py
==============================================================================
--- Webware/trunk/MiscUtils/Tests/TestDictForArgs.py (original)
+++ Webware/trunk/MiscUtils/Tests/TestDictForArgs.py Sat Jun 20 17:41:03 2009
@@ -48,7 +48,7 @@
# print repr(input)
# sys.stdout.flush()
result = DictForArgs(input)
- self.assertEquals(result, output,
+ self.assertEqual(result, output,
'Expecting: %s\nGot: %s\n' % (repr(output), repr(result)))
def testNegatives(self):
Modified: Webware/trunk/PSP/BraceConverter.py
==============================================================================
--- Webware/trunk/PSP/BraceConverter.py (original)
+++ Webware/trunk/PSP/BraceConverter.py Sat Jun 20 17:41:03 2009
@@ -1,25 +1,27 @@
"""BraceConverter.py
- Contributed 2000-09-04 by Dave Wallace (dwallace@...)
+Contributed 2000-09-04 by Dave Wallace (dwallace@...)
- Converts Brace-blocked Python into normal indented Python.
- Brace-blocked Python is non-indentation aware and blocks are delimited by ':{' and '}' pairs.
-
- Thus:
- for x in range(10) :{
- if x%2 :{ print x } else :{ print z }
- }
-
- Becomes (roughly, barring some spurious newlines):
- for x in range(10) :
- if x%2 :
- print x
- else :
- print z
+Converts Brace-blocked Python into normal indented Python.
+Brace-blocked Python is non-indentation aware and blocks are
+delimited by ':{' and '}' pairs.
+
+Thus:
+ for x in range(10) :{
+ if x%2 :{ print x } else :{ print z }
+ }
- This implementation is fed a line at a time via parseLine(), outputs to
- a PSPServletWriter, and tracks the current quotation and block levels internally.
+Becomes (roughly, barring some spurious newlines):
+ for x in range(10) :
+ if x%2 :
+ print x
+ else :
+ print z
+
+This implementation is fed a line at a time via parseLine(),
+outputs to a PSPServletWriter, and tracks the current quotation
+and block levels internally.
"""
@@ -33,7 +35,7 @@
COLONBRACE = re.compile(":\s*{\s*([^\s].*)?$")
def __init__(self):
- self.inquote = 0
+ self.inquote = False
self.dictlevel = 0
def parseLine(self, line, writer):
@@ -74,7 +76,7 @@
self.openBlock(writer)
elif ch == '#':
writer.printChars(self.line)
- self.line = ""
+ self.line = ''
else:
# should never get here
raise Exception()
@@ -85,34 +87,34 @@
"""Open a new block."""
match = self.COLONBRACE.match(self.line)
if match and not self.dictlevel:
- writer.printChars(":")
+ writer.printChars(':')
writer.pushIndent()
if match.group(1):
# text follows :{, if its a comment leave it on the same line
# else start a new line and leave the text for processing
if match.group(1)[0] == '#':
- writer.printChars(" " + match.group(1))
- self.line = ""
+ writer.printChars(' ' + match.group(1))
+ self.line = ''
else:
writer.printChars('\n')
writer.printIndent()
self.line = match.group(1)
else:
- self.line = ""
+ self.line = ''
else:
- writer.printChars(":")
+ writer.printChars(':')
self.line = self.line[1:]
def openBrace(self, writer):
"""Open brace encountered."""
- writer.printChars("{")
+ writer.printChars('{')
self.line = self.line[1:]
self.dictlevel += 1
def closeBrace(self, writer):
"""Close brace encountered."""
if self.dictlevel:
- writer.printChars("}")
+ writer.printChars('}')
self.line = self.line[1:]
self.dictlevel -= 1
else:
@@ -130,10 +132,10 @@
"""
pos = self.line.find(self.quotechars)
- if pos == -1:
+ if pos < 0:
writer.printChars(self.line)
- self.line = ""
- elif (pos > 0) and self.line[pos-1] == '\\':
+ self.line = ''
+ elif pos > 0 and self.line[pos-1] == '\\':
pos += 1
writer.printChars(self.line[:pos])
self.line = self.line[pos:]
@@ -142,11 +144,11 @@
pos += len(self.quotechars)
writer.printChars(self.line[:pos])
self.line = self.line[pos:]
- self.inquote = 0
+ self.inquote = False
def handleQuote(self, quote, writer):
- "Check and handle if current pos is a single or triple quote."""
- self.inquote = 1
+ """Check and handle if current pos is a single or triple quote."""
+ self.inquote = True
triple = quote*3
if self.line[0:3] == triple:
self.quotechars = triple
@@ -156,41 +158,3 @@
self.quotechars = quote
writer.printChars(quote)
self.line = self.line[1:]
-
-
-## Testing ##
-
-if __name__ == "__main__":
- from ServletWriter import ServletWriter
-
-
- class DummyWriter(ServletWriter):
- """For stand alone testing."""
-
- def __init__(self):
- self._filehandle = sys.stdout
- self._tabcnt = 0
- self._blockcount = 0 # a hack to handle nested blocks of Python code
- self._indentSpaces = ServletWriter._spaces
- self._useTabs = 0
- self._useBraces = 0
- self._indent = ' '
- self._userIndent = ServletWriter._emptyString
-
- test = r'''
- for x in range(10): { q = {
- 'test': x
- }
- print x
- }
-
- for x in range(10): { q= {'test': x}; print x} else: { print "\"done\"" #""}{
- x = { 'test1': {'sub2': {'subsub1': 2}} # yee ha
- }
- } print "all done"
-
- '''
- p = BraceConverter()
- dw = DummyWriter()
- for line in test.split('\n'):
- p.parseLine(line, dw)
Modified: Webware/trunk/PSP/Context.py
==============================================================================
--- Webware/trunk/PSP/Context.py (original)
+++ Webware/trunk/PSP/Context.py Sat Jun 20 17:41:03 2009
@@ -1,35 +1,26 @@
"""Utility class for keeping track of the context.
- A utility class that holds information about the file we are parsing
- and the environment we are doing it in.
+A utility class that holds information about the file we are parsing
+and the environment we are doing it in.
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
import os
-from ParseEventHandler import *
-class PSPContext:
+class PSPContext(object):
"""PSPContext is an abstract base class for Context classes.
Holds all the common stuff that various parts of the compilation
@@ -38,9 +29,6 @@
"""
- def __init__(self):
- raise NotImplementedError
-
def getClassPath(self):
raise NotImplementedError
@@ -62,6 +50,7 @@
"""Return the class name including package prefixes.
Won't use this for now.
+
"""
raise NotImplementedError
@@ -73,19 +62,19 @@
"""Return the encoding of the file that we are generating."""
raise NotImplementedError
- def setPSPReader(self):
+ def setPSPReader(self, reader):
"""Set the PSPReader for this context."""
raise NotImplementedError
- def setServletWriter(self):
+ def setServletWriter(self, writer):
"""Set the PSPWriter instance for this context."""
raise NotImplementedError
- def setPythonFileName(self):
+ def setPythonFileName(self, name):
"""Set the name of the .py file to generate."""
raise NotImplementedError
- def setPythonFileEncoding(self):
+ def setPythonFileEncoding(self, encoding):
"""Set the encoding of the .py file to generate."""
raise NotImplementedError
@@ -99,8 +88,8 @@
"""
- def __init__(self, pspfile, trans=None):
- # self._transactrion = trans # I don't think I need this
+ def __init__(self, pspfile):
+ PSPContext.__init__(self)
self._baseUri, self._pspfile = os.path.split(pspfile)
self._fullpath = pspfile
self._pyFileEncoding = None
@@ -126,9 +115,7 @@
return os.path.split(self._pyFileName)[0]
def getServletClassName(self):
- """Return the class name of the servlet being generated.
-
- """
+ """Return the class name of the servlet being generated."""
return self._className
def getFullClassName(self):
Modified: Webware/trunk/PSP/Docs/RelNotes-X.Y.phtml
==============================================================================
--- Webware/trunk/PSP/Docs/RelNotes-X.Y.phtml (original)
+++ Webware/trunk/PSP/Docs/RelNotes-X.Y.phtml Sat Jun 20 17:41:03 2009
@@ -19,7 +19,7 @@
<a name="Improvements"></a><h2>Improvements and Refinements</h2>
<ul>
- <li>...</li>
+ <li>The parser has been optimized and checks for invalid attributes now.</li>
</ul>
<a name="Security"></a><h2>Security</h2>
Modified: Webware/trunk/PSP/Docs/UsersGuide.phtml
==============================================================================
--- Webware/trunk/PSP/Docs/UsersGuide.phtml (original)
+++ Webware/trunk/PSP/Docs/UsersGuide.phtml Sat Jun 20 17:41:03 2009
@@ -336,7 +336,7 @@
The <i>isThreadSafe</i> attribute of <i>page</i> tells the PSP parser whether the class it is producing
can be utilized by multiple threads simultaneously. This is analogous to the isThreadSafe function in WebKit servlets.</p>
-<p><b>Example:</b> <span class="py"><%@ page threadSafe="yes"%></span></p>
+<p><b>Example:</b> <span class="py"><%@ page isThreadSafe="yes"%></span></p>
<p>valid values are "yes" and "no". The default is "no".</p></li>
Modified: Webware/trunk/PSP/Examples/APSPinclude.html
==============================================================================
--- Webware/trunk/PSP/Examples/APSPinclude.html (original)
+++ Webware/trunk/PSP/Examples/APSPinclude.html Sat Jun 20 17:41:03 2009
@@ -1,6 +1,6 @@
<hr>
-<p style="color:red">This is a HTML file that is dynamically inserted.</p>
+<p style="color:red">This is an HTML file that is dynamically inserted.</p>
<hr>
Modified: Webware/trunk/PSP/Examples/APSPinclude.psp
==============================================================================
--- Webware/trunk/PSP/Examples/APSPinclude.psp (original)
+++ Webware/trunk/PSP/Examples/APSPinclude.psp Sat Jun 20 17:41:03 2009
@@ -1,5 +1,5 @@
<%@ page imports="time"%>
-<p style="color:purple"><%= time.ctime(time.time()) %></p>
+<p style="color:purple"><%= time.ctime() %></p>
<hr>
Modified: Webware/trunk/PSP/Examples/PSPTests-Braces.psp
==============================================================================
--- Webware/trunk/PSP/Examples/PSPTests-Braces.psp (original)
+++ Webware/trunk/PSP/Examples/PSPTests-Braces.psp Sat Jun 20 17:41:03 2009
@@ -134,4 +134,4 @@
<p><b>That's all, folks.</b></p>
-<p><%= time.ctime(time.time())%></p>
+<p><%= time.ctime()%></p>
Modified: Webware/trunk/PSP/Examples/PSPTests.psp
==============================================================================
--- Webware/trunk/PSP/Examples/PSPTests.psp (original)
+++ Webware/trunk/PSP/Examples/PSPTests.psp Sat Jun 20 17:41:03 2009
@@ -131,4 +131,4 @@
<p><b>That's all, folks.</b></p>
-<p><%= time.ctime(time.time())%></p>
+<p><%= time.ctime()%></p>
Modified: Webware/trunk/PSP/Examples/View.py
==============================================================================
--- Webware/trunk/PSP/Examples/View.py (original)
+++ Webware/trunk/PSP/Examples/View.py Sat Jun 20 17:41:03 2009
@@ -1,5 +1,6 @@
import os
-from PSP.Examples.PSPExamplePage import PSPExamplePage
+
+from PSPExamplePage import PSPExamplePage
class View(PSPExamplePage):
@@ -24,7 +25,7 @@
filename = self.request().serverSidePath(basename)
if not os.path.exists(filename):
self.write('<p style="color:red">'
- 'No such file %r exists</p>' % basename)
+ 'No such file %r exists</p>' % basename)
return
text = open(filename).read()
text = self.htmlEncode(text)
Modified: Webware/trunk/PSP/Examples/my_include.psp
==============================================================================
--- Webware/trunk/PSP/Examples/my_include.psp (original)
+++ Webware/trunk/PSP/Examples/my_include.psp Sat Jun 20 17:41:03 2009
@@ -1,4 +1,4 @@
<p>Hello from included file!<p>
<%@page imports="time" %>
-<p><%= time.ctime(time.time()) %></p>
+<p><%= time.ctime() %></p>
Modified: Webware/trunk/PSP/Generators.py
==============================================================================
--- Webware/trunk/PSP/Generators.py (original)
+++ Webware/trunk/PSP/Generators.py Sat Jun 20 17:41:03 2009
@@ -1,44 +1,36 @@
"""Generate Python code from PSP templates.
- This module holds the classes that generate the Python code resulting
- from the PSP template file. As the parser encounters PSP elements,
- it creates a new Generator object for that type of element.
- Each of these elements is put into a list maintained by the
- ParseEventHandler object. When it comes time to output the source code,
- each generator is called in turn to create its source.
-
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+This module holds the classes that generate the Python code resulting
+from the PSP template file. As the parser encounters PSP elements,
+it creates a new Generator object for that type of element.
+Each of these elements is put into a list maintained by the
+ParseEventHandler object. When it comes time to output the source code,
+each generator is called in turn to create its source.
+
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
import os
+
import PSPUtils, BraceConverter
-# These are global so that the ParseEventHandler and this module agree:
+# This is global so that the ParseEventHandler and this module agree:
ResponseObject = 'res'
-AwakeCreated = 0
-class GenericGenerator:
- """ Base class for the generators """
+class GenericGenerator(object):
+ """Base class for all the generators"""
def __init__(self, ctxt=None):
self._ctxt = ctxt
@@ -58,7 +50,8 @@
GenericGenerator.__init__(self)
def generate(self, writer, phase=None):
- writer.println('res.write(_formatter(' + PSPUtils.removeQuotes(self.chars) + '))')
+ writer.println('res.write(_formatter(%s))'
+ % PSPUtils.removeQuotes(self.chars))
class CharDataGenerator(GenericGenerator):
@@ -74,9 +67,11 @@
self.chars = chars
def generate(self, writer, phase=None):
- # Quote any existing backslash so generated Python will not interpret it when running.
+ # Quote any existing backslash so generated Python will not
+ # interpret it when running.
self.chars = self.chars.replace('\\', r'\\')
- # Quote any single quotes so it does not get confused with our triple-quotes:
+ # Quote any single quotes so it does not get confused with
+ # our triple-quotes:
self.chars = self.chars.replace('"', r'\"')
self.generateChunk(writer)
@@ -108,15 +103,15 @@
bc.parseLine(line, writer)
return
# Check for whitespace at the beginning and if less than 2 spaces, remove:
- if self.chars[:1] == ' ' and self.chars[:2] != ' ':
+ if self.chars.startswith(' ') and not self.chars.startswith(' '):
self.chars = self.chars.lstrip()
lines = PSPUtils.splitLines(PSPUtils.removeQuotes(self.chars))
if not lines:
- return # ignore empty tag
+ return # ignore any empty tag
# userIndent check
- if len(lines[-1]) > 0 and lines[-1][-1] == '$':
+ if lines[-1].endswith('$'):
lastline = lines[-1] = lines[-1][:-1]
- if lastline == '':
+ if not lastline:
lastline = lines[-2] # handle endscript marker on its own line
count = 0
while lastline[count].isspace():
@@ -130,12 +125,11 @@
writer.printList(lines)
writer.printChars('\n')
# Check for a block:
- # lastline = string.splitfields(PSPUtils.removeQuotes(self.chars), '\n')[-1]
commentstart = lastline.find('#') # @@ this fails if '#' part of string
- if commentstart > 0:
+ if commentstart >= 0:
lastline = lastline[:commentstart]
blockcheck = lastline.rstrip()
- if len(blockcheck) > 0 and blockcheck[-1] == ':':
+ if blockcheck.endswith(':'):
writer.pushIndent()
writer.println()
writer._blockcount = writer._blockcount+1
@@ -213,16 +207,12 @@
writer.printChars('(')
# self.attrs['params']
writer.printChars('self')
- if self.attrs.has_key('params') and self.attrs['params'] != '':
+ if 'params' in self.attrs and self.attrs['params']:
writer.printChars(', ')
writer.printChars(self.attrs['params'])
writer.printChars('):\n')
if self.attrs['name'] == 'awake':
- # This is hacky, need better method, but it works.
- # @@ Maybe I should require a standard parent and do the intPSP call in that awake?
- global AwakeCreated
- AwakeCreated = 1
- # Below indented on 6/1/00, was outside if block:
+ writer._awakeCreated = True
writer.pushIndent()
writer.println('self.initPSP()\n')
writer.popIndent()
@@ -258,14 +248,9 @@
"""
- # _theFunction = """
- # __pspincludepath = self.transaction().request().urlPathDir() + "%s"
- # self.transaction().application().includeURL(self.transaction(), __pspincludepath)
- # """
- _theFunction = """
-__pspincludepath = "%s"
-self.transaction().application().includeURL(self.transaction(), __pspincludepath)
-"""
+ _theFunction = ('__pspincludepath = "%s"\n'
+ 'self.transaction().application().includeURL('
+ 'self.transaction(), __pspincludepath)')
def __init__(self, attrs, param, ctxt):
GenericGenerator.__init__(self, ctxt)
@@ -275,7 +260,7 @@
self.url = attrs.get('path')
if self.url is None:
- raise AttributeError, 'No path attribute in include'
+ raise AttributeError('No path attribute in include')
self.scriptgen = ScriptGenerator(self._theFunction % self.url, None)
@@ -301,28 +286,28 @@
self.page = attrs.get('file')
if not self.page:
- raise AttributeError, 'No file attribute in include'
+ raise AttributeError('No file attribute in include')
thepath = self._ctxt.resolveRelativeURI(self.page)
if not os.path.exists(thepath):
print self.page
- raise IOError, 'Invalid included file %r' % thepath
+ raise IOError('Invalid included file %r' % thepath)
self.page = thepath
self.static = str(attrs.get('static')).lower() in ('true', 'yes', '1')
if not self.static:
self.scriptgen = ScriptGenerator("self.__includeFile('%s')"
- % thepath.replace('\\', '\\\\'), None)
+ % thepath.replace('\\', '\\\\'), None)
def generate(self, writer, phase=None):
# JSP does this in the servlet. I'm doing it here because
# I have triple quotes. Note: res.write statements inflate
# the size of the resulting classfile when it is cached.
# Cut down on those by using a single res.write on the whole
- # file, after escaping any triple-double quotes."""
+ # file, after escaping any triple-double quotes.
if self.static:
data = open(self.page).read()
data = data.replace('"""', r'\"""')
- writer.println('res.write("""'+data+'""")')
+ writer.println('res.write("""' + data + '""")')
writer.println()
else:
self.scriptgen.generate(writer, phase)
Modified: Webware/trunk/PSP/PSPCompiler.py
==============================================================================
--- Webware/trunk/PSP/PSPCompiler.py (original)
+++ Webware/trunk/PSP/PSPCompiler.py Sat Jun 20 17:41:03 2009
@@ -1,24 +1,16 @@
"""A simple little module that organizes the actual page generation.
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
Modified: Webware/trunk/PSP/PSPPage.py
==============================================================================
--- Webware/trunk/PSP/PSPPage.py (original)
+++ Webware/trunk/PSP/PSPPage.py Sat Jun 20 17:41:03 2009
@@ -13,8 +13,6 @@
class PSPPage(Page):
def __init__(self):
- # self._parent = str(self.__class__.__bases__[0]).split('.')[1]
- # print self._parent
self._parent = Page
self._parent.__init__(self)
Modified: Webware/trunk/PSP/PSPParser.py
==============================================================================
--- Webware/trunk/PSP/PSPParser.py (original)
+++ Webware/trunk/PSP/PSPParser.py Sat Jun 20 17:41:03 2009
@@ -1,69 +1,66 @@
"""The PSP parser.
- This module handles the actual reading of the characters in the source
- PSP file and checking it for valid psp tokens. When it finds one,
- it calls ParseEventHandler with the characters it found.
-
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+This module handles the actual reading of the characters in the source
+PSP file and checking it for valid psp tokens. When it finds one,
+it calls ParseEventHandler with the characters it found.
+
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
-from Generators import *
-
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
-class PSPParserException(Exception):
- pass
+from PSPUtils import checkAttributes, PSPParserException
+
+
+checklist = []
+def checker(method):
+ """Decorator for adding a method to the checklist."""
+ checklist.append(method)
+ return method
-class PSPParser:
+
+class PSPParser(object):
"""The main PSP parser class.
The PSPParser class does the actual sniffing through the input file
looking for anything we're interested in. Basically, it starts by
looking at the code looking for a '<' symbol. It looks at the code by
- working with a PSPReader object, which handle the current location in
- the code. When it finds one, it calls a list of functions, the xxxChecks,
+ working with a PSPReader object, which handles the current location in
+ the code. When it finds one, it calls a list of checker methods,
asking each if it recognizes the characters as its kind of input.
- When the check functions look at the characters, if they want it,
+ When the checker methods look at the characters, if they want it,
they go ahead and gobble it up and set up to create it in the servlet
- when the time comes. When they return, they return true if they accept
+ when the time comes. When they return, they return true if they accept
the character, and the PSPReader object cursor is positioned past the
- end of the block that the check function accepted.
+ end of the block that the checker method accepted.
"""
- checklist = []
+ checklist = checklist # global list of checker methods
def __init__(self, ctxt):
self._reader = ctxt.getReader()
self._writer = ctxt.getServletWriter()
self._handler = None
- self.cout = StringIO() # This is where we dump straight HTML code that none of the checks want
- self.tmplStart = 0 # marks the start of HTML code
- self.tmplStop = 0 #marks the end of HTML code
- self.currentFile = self._reader.Mark().getFile()
+ self.cout = StringIO() # for dumping HTML that none of the check wants
+ self.tmplStart = None # marks the start of HTML code
+ self.tmplStop = None # marks the end of HTML code
+ self.currentFile = self._reader.mark().getFile()
def setEventHandler(self, handler):
"""Set the handler this parser will use when it finds PSP code."""
@@ -78,279 +75,220 @@
"""
data = self.cout.getvalue()
self.cout.close()
- if len(data) > 0: # make sure there's something there
+ if data: # make sure there's something there
self._handler.handleCharData(start, stop, data)
self.cout = StringIO()
+ @checker
def commentCheck(self, handler, reader):
"""Comments just get eaten."""
- OPEN_COMMENT = '<%--'
- CLOSE_COMMENT = '--%>'
- if reader.Matches(OPEN_COMMENT):
- reader.Advance(len(OPEN_COMMENT))
- if reader.skipUntil(CLOSE_COMMENT) is None:
- raise PSPParserException, 'Comment not terminated'
+ if reader.matches('<%--'):
+ reader.advance(4)
+ if reader.skipUntil('--%>') is None:
+ raise PSPParserException('Comment not terminated')
self.flushCharData(self.tmplStart, self.tmplStop)
- return 1
- return 0
-
- checklist.append(commentCheck) # add this checker to the list that the parse function will call
+ return True
+ return False
+ @checker
def checkExpression(self, handler, reader):
- """Look for "expressions" and handle them"""
- OPEN_EXPR = '<%='
- CLOSE_EXPR = '%>'
- end_open = None
- attrs = None
- if not reader.Matches(OPEN_EXPR):
- return 0
- reader.Advance(len(OPEN_EXPR)) # eat the opening tag
- if end_open is not None:
- attrs = reader.parseTagAttributes()
- reader.skipSpaces()
- if not reader.matches(end_open):
- raise PSPParserException, 'Expression not terminated'
- reader.Advance(len(end_open))
- reader.skipSpaces()
- # below not implemented
- # PSPUtil.checkAttrs('Expression', attrs, validAttrs)
+ """Look for "expressions" and handle them."""
+ if not reader.matches('<%='):
+ return False
+ reader.advance(3) # eat the opening tag
reader.peekChar()
reader.skipSpaces()
- start = reader.Mark()
- stop = reader.skipUntil(CLOSE_EXPR)
+ start = reader.mark()
+ stop = reader.skipUntil('%>')
if stop is None:
- raise PSPParserException, 'Expression not terminated'
+ raise PSPParserException('Expression not terminated')
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
- handler.handleExpression(start, stop, attrs)
- return 1
-
- checklist.append(checkExpression)
+ handler.handleExpression(start, stop, None)
+ return True
+ @checker
def checkDirective(self, handler, reader):
- """Check for directives. I support two right now, page and include."""
- validDirectives = ['page', 'include']
- OPEN_DIRECTIVE = r'<%@'
- CLOSE_DIRECTIVE = r'%>'
- if not reader.Matches(OPEN_DIRECTIVE):
- return 0
- start = reader.Mark()
- reader.Advance(len(OPEN_DIRECTIVE))
- match = None
+ """Check for directives; for now we support only page and include."""
+ if not reader.matches('<%@'):
+ return False
+ start = reader.mark()
+ reader.advance(3)
reader.skipSpaces()
- for i in validDirectives:
- if reader.Matches(i):
- match = i
+ for directive in ('page', 'include', 'taglib'):
+ if reader.matches(directive):
+ match = directive
break
- if match is None:
- raise PSPParserException, 'Invalid Directive'
- reader.Advance(len(match))
+ else:
+ raise PSPParserException('Invalid directive')
+ reader.advance(len(match))
# parse the directive attr:val pair dictionary
attrs = reader.parseTagAttributes()
- # not checking for validity yet
- # if match == 'page':
- # PSPUtils.checkAttributes('Page Directive', attrs, pageDvalidAttrs)
- # elif match == 'include':
- # PSPUtils.checkAttributes('Include Directive', attrs, includeDvalidAttrs)
- # elif match == 'taglib':
- # raise NotImplementedError
- # match close
+ if match == 'page':
+ checkAttributes('Page directive', attrs, ([], set([
+ 'imports', 'extends', 'method',
+ 'isThreadSafe', 'isInstanceSafe',
+ 'indentType', 'indentSpaces',
+ 'gobbleWhitespace', 'formatter'])))
+ elif match == 'include':
+ checkAttributes('Include directive', attrs, (['file'], []))
+ else:
+ raise PSPParserException('%s directive not implemented' % match)
reader.skipSpaces() # skip to where we expect a close tag
- close = CLOSE_DIRECTIVE
- if not reader.Matches(close):
- raise PSPParserException, 'Directive not terminated'
+ if reader.matches('%>'):
+ reader.advance(2) # advance past it
else:
- reader.Advance(len(close)) #advance past it
- stop = reader.Mark()
+ raise PSPParserException('Directive not terminated')
+ stop = reader.mark()
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
handler.handleDirective(match, start, stop, attrs)
- return 1
-
- checklist.append(checkDirective)
+ return True
+ @checker
def checkEndBlock(self, handler, reader):
- OPEN_SCRIPT = '<%'
- CLOSE_SCRIPT = '%>'
- CLOSE_SCRIPT2 = '$%>'
- CENTER_SCRIPT = 'end'
- start = reader.Mark()
- if reader.Matches(OPEN_SCRIPT):
- reader.Advance(len(OPEN_SCRIPT))
+ """Check for the end of a block."""
+ start = reader.mark()
+ if reader.matches('<%'):
+ reader.advance(2)
reader.skipSpaces()
- if reader.Matches(CENTER_SCRIPT):
- reader.Advance(len(CENTER_SCRIPT))
+ if reader.matches('end'):
+ reader.advance(3)
reader.skipSpaces()
- if reader.Matches(CLOSE_SCRIPT):
- reader.Advance(len(CLOSE_SCRIPT))
+ if reader.matches('%>'):
+ reader.advance(2)
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
handler.handleEndBlock()
- return 1
- if reader.Matches(CLOSE_SCRIPT2):
- reader.Advance(len(CLOSE_SCRIPT2))
+ return True
+ if reader.matches('$%>'):
+ reader.advance(3)
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
handler.handleEndBlock()
- print ">>>>Putting a $ at the end of an end tag does nothing, I Say"
- return 1
+ print 'INFO: A $ at the end of an end tag does nothing.'
+ return True
# that wasn't it
reader.reset(start)
- return 0
-
- checklist.append(checkEndBlock)
+ return False
+ @checker
def checkScript(self, handler, reader):
"""The main thing we're after. Check for embedded scripts."""
- OPEN_SCRIPT = '<%'
- CLOSE_SCRIPT = '%>'
- attrs = None
- end_open = None
- if not reader.Matches(OPEN_SCRIPT):
- return 0
- open = OPEN_SCRIPT
- close = CLOSE_SCRIPT
- validAttributes = ('name', 'params')
- reader.Advance(len(open)) # matches advances it
- if end_open is not None:
- attrs = reader.parseTagAttributes()
- reader.skipSpaces()
- if not reader.Matches(end_open):
- raise PSPParserException, 'Script not terminated'
- reader.Advance(len(end_open))
- reader.skipSpaces()
- PSPUtils.checkAttributes('Script', attrs, validAttributes)
- # reader.skipSpaces() # don't skip as spaces may be significant, leave this for the generator
- start = reader.Mark()
+ if not reader.matches('<%'):
+ return False
+ reader.advance(2)
+ # don't skip as spaces may be significant; leave this for the generator
+ start = reader.mark()
try:
- stop = reader.skipUntil(close)
+ stop = reader.skipUntil('%>')
except EOFError:
raise EOFError("Reached EOF while looking for ending script tag")
if stop is None:
- raise PSPParserException, 'Script not terminated'
+ raise PSPParserException('Script not terminated')
handler.setTemplateInfo(self.tmplStart, self.tmplStop)
- handler.handleScript(start, stop, attrs)
- return 1
-
- checklist.append(checkScript)
+ handler.handleScript(start, stop, None)
+ return True
+ @checker
def checkScriptFile(self, handler, reader):
"""Check for file level code.
- Check for Python code that should go in the beginning of the generated module.
+ Check for Python code that should go to the top of the generated module.
<psp:file>
- import xyz
- print 'hi Mome!'
- def foo(): return 'foo'
+ import xyz
+ print 'hi Mome!'
+ def foo(): return 'foo'
</psp:file>
"""
- OPEN_SCRIPT = '<psp:file>'
- CLOSE_SCRIPT = '</psp:file>'
- attrs = None
- if reader.Matches(OPEN_SCRIPT):
- reader.Advance(len(OPEN_SCRIPT))
- start = reader.Mark()
- try:
- stop = reader.skipUntil(CLOSE_SCRIPT)
- if stop is None:
- raise PSPParserException, 'Script not terminated in %s block' % OPEN_SCRIPT
- except EOFError:
- raise EOFError("Reached EOF while looking for ending script tag (%s)" % CLOSE_SCRIPT)
- handler.setTemplateInfo(self.tmplStart, self.tmplStop)
- handler.handleScriptFile(start, stop, attrs)
- return 1
- return 0
-
- checklist.append(checkScriptFile)
+ if not reader.matches('<psp:file>'):
+ return False
+ reader.advance(10)
+ start = reader.mark()
+ try:
+ stop = reader.skipUntil('</psp:file>')
+ if stop is None:
+ raise PSPParserException(
+ 'Script not terminated in <psp:file> block')
+ except EOFError:
+ raise EOFError('Reached EOF while looking for ending'
+ ' script tag </psp:file>')
+ handler.setTemplateInfo(self.tmplStart, self.tmplStop)
+ handler.handleScriptFile(start, stop, None)
+ return True
+ @checker
def checkScriptClass(self, handler, reader):
"""Check for class level code.
Check for Python code that should go in the class definition.
<psp:class>
- def foo(self):
- return self.dosomething()
+ def foo(self):
+ return self.dosomething()
</psp:class>
"""
- OPEN_SCRIPT = '<psp:class>'
- CLOSE_SCRIPT = '</psp:class>'
- attrs = None
- if reader.Matches(OPEN_SCRIPT):
- reader.Advance(len(OPEN_SCRIPT))
- start = reader.Mark()
- try:
- stop = reader.skipUntil(CLOSE_SCRIPT)
- if stop is None:
- raise PSPParserException, 'Script not terminated in %s block' % OPEN_SCRIPT
- except EOFError:
- raise EOFError("Reached EOF while looking for ending script tag (%s)" % CLOSE_SCRIPT)
- handler.setTemplateInfo(self.tmplStart, self.tmplStop)
- handler.handleScriptClass(start, stop, attrs)
- return 1
- return 0
-
- checklist.append(checkScriptClass)
+ if not reader.matches('<psp:class>'):
+ return False
+ reader.advance(11)
+ start = reader.mark()
+ try:
+ stop = reader.skipUntil('</psp:class>')
+ if stop is None:
+ raise PSPParserException(
+ 'Script not terminated in <psp:class> block')
+ except EOFError:
+ raise EOFError('Reached EOF while looking for ending'
+ ' script tag </psp:class>')
+ handler.setTemplateInfo(self.tmplStart, self.tmplStop)
+ handler.handleScriptClass(start, stop, None)
+ return True
+ @checker
def checkMethod(self, handler, reader):
"""Check for class methods defined in the page.
- I only support one format for these,
+ We only support one format for these,
<psp:method name="xxx" params="xxx,xxx">
- Then the function BODY, then <psp:method>.
+ Then the function body, then </psp:method>.
"""
- OPEN_METHOD = '<psp:method'
- # CLOSE_METHOD = '/>'
- CLOSE_METHOD_2 = '</psp:method>'
- CLOSE_METHOD_3 = '>'
- attrs = None
- # validAttributes = ('name', 'params')
- if reader.Matches(OPEN_METHOD):
- start = reader.Mark()
- reader.Advance(len(OPEN_METHOD))
- attrs = reader.parseTagAttributes()
- # PSPUtils.checkAttributes('method', attrs, validAttributes)
- reader.skipSpaces()
- if not reader.Matches(CLOSE_METHOD_3):
- raise PSPParserException, 'Expected method declaration close'
- reader.Advance(len(CLOSE_METHOD_3))
- stop = reader.Mark()
- handler.setTemplateInfo(self.tmplStart, self.tmplStop)
- handler.handleMethod(start, stop, attrs)
- start = stop
- # skip past the close marker, return the point before the close marker
- stop = reader.skipUntil(CLOSE_METHOD_2)
- handler.handleMethodEnd(start, stop, attrs)
- return 1
- return 0
-
- checklist.append(checkMethod)
+ if not reader.matches('<psp:method'):
+ return False
+ start = reader.mark()
+ reader.advance(11)
+ attrs = reader.parseTagAttributes()
+ checkAttributes('method', attrs, (['name'], ['params']))
+ reader.skipSpaces()
+ if not reader.matches('>'):
+ raise PSPParserException('Expected method declaration close')
+ reader.advance(1)
+ stop = reader.mark()
+ handler.setTemplateInfo(self.tmplStart, self.tmplStop)
+ handler.handleMethod(start, stop, attrs)
+ start = stop
+ # skip past the close marker, return the point before the close marker
+ stop = reader.skipUntil('</psp:method>')
+ handler.handleMethodEnd(start, stop, attrs)
+ return True
+ @checker
def checkInclude(self, handler, reader):
"""Check for inserting another pages output in this spot."""
- OPEN_INCLUDE = '<psp:include'
- # CLOSE_INCLUDE_NO_BODY = "/>"
- CLOSE_INCLUDE_BODY = ">"
- # CLOSE_INCLUDE = "</psp:include>"
- # OPEN_INDIVIDUAL_PARAM = "<psp:param"
- # CLOSE_INDIVIDUAL_PARAM = "/>"
- if reader.Matches(OPEN_INCLUDE):
- param = {}
- reader.Advance(len(OPEN_INCLUDE))
- reader.skipSpaces()
- attrs = reader.parseTagAttributes()
- #PSPUtils.checkTagAttributes()....
- reader.skipSpaces()
- if not reader.Matches(CLOSE_INCLUDE_BODY):
- raise PSPParserException, 'Include bodies not implemented'
- reader.Advance(len(CLOSE_INCLUDE_BODY))
- handler.setTemplateInfo(self.tmplStart, self.tmplStop)
- handler.handleInclude(attrs, param)
- return 1
- return 0
-
- checklist.append(checkInclude)
+ if not reader.matches('<psp:include'):
+ return False
+ reader.advance(12)
+ reader.skipSpaces()
+ attrs = reader.parseTagAttributes()
+ checkAttributes('include', attrs, (['path'], []))
+ reader.skipSpaces()
+ if not reader.matches('>'):
+ raise PSPParserException('Include bodies not implemented')
+ reader.advance(1)
+ handler.setTemplateInfo(self.tmplStart, self.tmplStop)
+ handler.handleInclude(attrs, None)
+ return True
+ @checker
def checkInsert(self, handler, reader):
"""Check for straight character dumps.
@@ -359,59 +297,44 @@
JSP can pull it from another server, servlet, JSP page, etc.
"""
- OPEN_INSERT = '<psp:insert'
- # CLOSE_INSERT_NO_BODY = "/>"
- CLOSE_INSERT_BODY = ">"
- # CLOSE_INSERT = "</psp:insert>"
- # OPEN_INDIVIDUAL_PARAM = "<psp:param"
- # CLOSE_INDIVIDUAL_PARAM = "/>"
- if reader.Matches(OPEN_INSERT):
- param = {}
- reader.Advance(len(OPEN_INSERT))
- reader.skipSpaces()
- attrs = reader.parseTagAttributes()
- # PSPUtils.checkTagAttributes()....
- reader.skipSpaces()
- if not reader.Matches(CLOSE_INSERT_BODY):
- raise PSPParserException, 'Insert bodies not implemented'
- reader.Advance(len(CLOSE_INSERT_BODY))
- handler.setTemplateInfo(self.tmplStart, self.tmplStop)
- handler.handleInsert(attrs, param)
- return 1
- return 0
-
- checklist.append(checkInsert)
+ if not reader.matches('<psp:insert'):
+ return False
+ reader.advance(11)
+ reader.skipSpaces()
+ attrs = reader.parseTagAttributes()
+ checkAttributes('insert', attrs, (['file'], []))
+ reader.skipSpaces()
+ if not reader.matches('>'):
+ raise PSPParserException('Insert bodies not implemented')
+ reader.advance(1)
+ handler.setTemplateInfo(self.tmplStart, self.tmplStop)
+ handler.handleInsert(attrs, None)
+ return True
- def parse(self, until=None, accept=None):
+ def parse(self, until=None):
"""Parse the PSP file."""
- noPspElement = 0
reader = self._reader
handler = self._handler
+ noPspElement = False
while reader.hasMoreInput():
- # This is for XML style blocks, which I'm not handling yet
- if until is not None and reader.Matches(until):
+ # This is for XML style blocks, which we're not handling yet:
+ if until and reader.matches(until):
return
- # If the file the reader is working on has changed due to a push or pop,
- # flush any char data from the old file
- if not reader.Mark().getFile() == self.currentFile:
+ # If the file the reader is working on has changed due to
+ # a push or pop, flush any char data from the old file:
+ if reader.mark().getFile() != self.currentFile:
self.flushCharData(self.tmplStart, self.tmplStop)
- self.currentFile = reader.Mark().getFile()
- self.tmplStart = reader.Mark()
- # in JSP, this is an array of valid tag type to check for,
- # I'm not using it now, # and I don't think JSP does either
- if accept:
- pass
- accepted = 0
+ self.currentFile = reader.mark().getFile()
+ self.tmplStart = reader.mark()
for checkfunc in self.checklist:
if checkfunc(self, handler, reader):
- accepted = 1
- noPspElement = 0
+ noPspElement = False
break
- if not accepted:
+ else:
if not noPspElement:
- self.tmplStart = reader.Mark()
- noPspElement = 1
- st = reader.nextContent() # skip till the next possible tag
- self.tmplStop = reader.Mark() # mark the end of HTML data
- self.cout.write(st) # write out the raw HTML data
- self.flushCharData(self.tmplStart, self.tmplStop) #dump remaining raw HTML
+ self.tmplStart = reader.mark()
+ noPspElement = True
+ s = reader.nextContent() # skip till the next possible tag
+ self.tmplStop = reader.mark() # mark the end of HTML data
+ self.cout.write(s) # write out the raw HTML data
+ self.flushCharData(self.tmplStart, self.tmplStop) # dump the rest
Modified: Webware/trunk/PSP/PSPServletFactory.py
==============================================================================
--- Webware/trunk/PSP/PSPServletFactory.py (original)
+++ Webware/trunk/PSP/PSPServletFactory.py Sat Jun 20 17:41:03 2009
@@ -1,37 +1,28 @@
"""This module handles requests from the application for PSP pages.
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
"""
-import os, sys
+import os
+import sys
from glob import glob
+from string import digits, letters
+
from WebKit.ServletFactory import ServletFactory
from PSP import Context, PSPCompiler
class PSPServletFactory(ServletFactory):
- """Servlet Factory for PSP files.
-
- Very sloppy. Need to come back and do a serious cleanup.
-
- """
+ """Servlet Factory for PSP files."""
def __init__(self, application):
ServletFactory.__init__(self, application)
@@ -39,14 +30,13 @@
sys.path.append(self._cacheDir)
self._cacheClassFiles = self._cacheClasses
t = ['_'] * 256
- from string import digits, letters
for c in digits + letters:
t[ord(c)] = c
self._classNameTrans = ''.join(t)
setting = application.setting
self._extensions = setting('ExtensionsForPSP', ['.psp'])
self._fileEncoding = setting('PSPFileEncoding', None)
- if setting('ClearPSPCacheOnStart', 0):
+ if setting('ClearPSPCacheOnStart', False):
self.clearFileCache()
def uniqueness(self):
@@ -88,9 +78,9 @@
"""
module = self.importAsPackage(transaction, filename)
- assert module.__dict__.has_key(classname), \
- 'Cannot find expected class named %s in %s.' \
- % (repr(classname), repr(filename))
+ assert classname in module.__dict__, (
+ 'Cannot find expected class named %r in %r.'
+ % (classname, filename))
theClass = getattr(module, classname)
return theClass
@@ -98,9 +88,9 @@
classname = self.computeClassName(path)
classfile = os.path.join(self._cacheDir, classname + ".py")
mtime = os.path.getmtime(path)
- if not os.path.exists(classfile) \
- or os.path.getmtime(classfile) != mtime:
- context = Context.PSPCLContext(path, transaction)
+ if (not os.path.exists(classfile)
+ or os.path.getmtime(classfile) != mtime):
+ context = Context.PSPCLContext(path)
context.setClassName(classname)
context.setPythonFileName(classfile)
context.setPythonFileEncoding(self._fileEncoding)
Modified: Webware/trunk/PSP/PSPUtils.py
==============================================================================
--- Webware/trunk/PSP/PSPUtils.py (original)
+++ Webware/trunk/PSP/PSPUtils.py Sat Jun 20 17:41:03 2009
@@ -1,124 +1,113 @@
"""A bunch of utility functions for the PSP generator.
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
+# PSP Error classes
+
+class PSPParserException(Exception):
+ """PSP parser error."""
+
# Various utility functions
-def removeQuotes(st):
- return st.replace("%\\\\>", "%>")
+def removeQuotes(s):
+ return s.replace(r'%\\>', '%>')
+
-def isExpression(st):
+def isExpression(s):
"""Check whether this is a PSP expression."""
- OPEN_EXPR = '<%='
- CLOSE_EXPR = '%>'
- if st.startswith(OPEN_EXPR) and st.endswith(CLOSE_EXPR):
- return 1
- return 1
+ if s.startswith('<%=') and s.endswith('%>'):
+ return True
+ else:
+ return False
+
-def getExpr(st):
+def getExpr(s):
"""Get the content of a PSP expression."""
- OPEN_EXPR = '<%='
- CLOSE_EXPR = '%>'
- if st.startswith(OPEN_EXPR) and st.endswith(CLOSE_EXPR):
- return st[len(OPEN_EXPR):-len(CLOSE_EXPR)]
+ if s.startswith('<%=') and s.endswith('%>'):
+ return s[3:-2]
else:
return ''
-def checkAttributes(tagtype, attrs, validAttrs):
- """Missing check for mandatory atributes."""
- pass #see line 186 in JSPUtils.java
-def splitLines(text, keepends=0):
+def checkAttributes(tagType, attrs, validAttrs):
+ """Check for mandatory and optional atributes."""
+ attrs = set(attrs)
+ mandatoryAttrs = validAttrs[0]
+ for attr in mandatoryAttrs: # mandatory
+ try:
+ attrs.remove(attr)
+ except KeyError:
+ raise PSPParserException('%s: Mandatory attribute %s missing'
+ % (tagType, attr))
+ optionalAttrs = validAttrs[1]
+ for attr in attrs:
+ if attr not in optionalAttrs:
+ raise PSPParserException('%s: Invalid attribute %s'
+ % (tagType, attr))
+
+
+def splitLines(text, keepends=False):
"""Split text into lines."""
return text.splitlines(keepends)
-def startsNewBlock(line):
- """Determine whether line starts a new block.
- Utility function for normalizeIndentation
+def startsNewBlock(line):
+ """Determine whether a code line starts a new block.
Added by Christoph Zwerschke.
"""
+ line = line.strip()
if line.startswith('#'):
- return 0
+ return False
try:
compile(line, '<string>', 'exec')
- return 0
except SyntaxError:
try:
compile(line + '\n pass', '<string>', 'exec')
- return 1
except Exception:
pass
+ else:
+ return True
else:
- pass
+ return False
return line.endswith(':')
+
def normalizeIndentation(pySource):
- """Take a block of code that may be too indented, and move it all to the left.
+ """Take a code block that may be too indented, and move it all to the left.
See PSPUtilsTest for examples.
- First written by Winston Wolff.
- Improved version by Christoph Zwerschke.
+ First written by Winston Wolff; improved version by Christoph Zwerschke.
"""
- lines = splitLines(pySource, 1)
- # Find out which kind of line feeds are used:
- crlf = ''
- line0 = lines.pop(0)
- while line0 and line0[-1] in '\r\n':
- crlf += line0[-1]
- line0 = line0[:-1]
- # The first line may be stripped completely:
- strippedLines = []
- charsToStrip = None
- # Find the least indentation of the remaining lines:
+ lines = splitLines(pySource, True)
+ minIndent = None
+ indents = []
for line in lines:
- line = line.rstrip()
- strippedLines.append(line)
- if charsToStrip == 0:
- continue
- if line != '':
- s = line.lstrip()
- if s[0] != '#':
- i = len(line) - len(s)
- if charsToStrip is None or i < charsToStrip:
- charsToStrip = i
- if charsToStrip is not None:
- # If there is code on the first line, strip one column less:
- if line0 and line0[0] != '#' and charsToStrip != 0:
- charsToStrip -= 1
- # Strip off the first indent characters from each line:
- if charsToStrip != 0:
- lines = []
- for line in strippedLines:
- line = line[:charsToStrip].lstrip() + line[charsToStrip:]
- lines.append(line)
- strippedLines = lines
- # Write lines back out:
- strippedLines.insert(0, line0)
- pySource = crlf.join(strippedLines)
+ strippedLine = line.lstrip(' \t')
+ indent = len(line) - len(strippedLine)
+ indents.append(len(line) - len(strippedLine))
+ if strippedLine.lstrip('\r\n') and not strippedLine.startswith('#'):
+ if minIndent is None or indent < minIndent:
+ minIndent = indent
+ if not minIndent:
+ break
+ if minIndent:
+ pySource = ''.join([line[min(minIndent, indent):]
+ for line, indent in zip(lines, indents)])
return pySource
Modified: Webware/trunk/PSP/ParseEventHandler.py
==============================================================================
--- Webware/trunk/PSP/ParseEventHandler.py (original)
+++ Webware/trunk/PSP/ParseEventHandler.py Sat Jun 20 17:41:03 2009
@@ -1,33 +1,26 @@
"""Event handler for parsing PSP tokens.
- This module is called when the Parser encounters psp tokens.
- It creates a generator to handle the PSP token. When the PSP
- source file is fully parsed, this module calls all of the
- generators in turn to output their source code.
-
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+This module is called when the Parser encounters psp tokens.
+It creates a generator to handle the PSP token. When the PSP
+source file is fully parsed, this module calls all of the
+generators in turn to output their source code.
+
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
import time
+
from Generators import * # ResponseObject, plus all the *Generator functions.
@@ -36,21 +29,21 @@
It implements the handling of all the parsing elements.
Note: This files JSP cousin is called ParseEventListener,
- I don\'t know why, but Handler seemed more appropriate to me.
+ I don't know why, but Handler seemed more appropriate to me.
"""
aspace = ' '
- defaults = {
- 'BASE_CLASS':' WebKit.Page',
- 'BASE_METHOD': 'writeHTML',
- 'imports': {'filename': 'classes'},
- 'threadSafe': 'no',
- 'instanceSafe': 'yes',
- 'indent': int(4),
- 'gobbleWhitespace': 1,
- 'formatter': 'str'
- }
+ defaults = dict(
+ BASE_CLASS = 'WebKit.Page',
+ BASE_METHOD = 'writeHTML',
+ imports = dict(filename='classes'),
+ threadSafe = 'no',
+ instanceSafe = 'yes',
+ indent = 4,
+ gobbleWhitespace = True,
+ formatter = 'str'
+ )
def __init__(self, ctxt, parser):
self._ctxt = ctxt
@@ -79,14 +72,14 @@
def handleCharData(self, start, stop, chars):
"""Flush character data into a CharGen."""
- if chars != '':
+ if chars:
gen = CharDataGenerator(chars)
self.addGenerator(gen)
def handleComment(self, start, stop):
"""Comments get swallowed into nothing."""
self._parser.flushCharData(self.tmplStart, self.tmplStop)
- return #just eats the comment
+ return # just eats the comment
def handleInclude(self, attrs, param):
"""This is for includes of the form <psp:include ...>
@@ -111,14 +104,14 @@
def importHandler(self, imports, start, stop):
importlist = imports.split(',')
- for i in importlist:
- if i.find(':') != -1:
- module, symbol = i.split(':')[:2]
+ for imp in importlist:
+ if ':' in imp:
+ module, symbol = imp.split(':', 1)
self._importedSymbols.append(symbol.strip())
implist = "from " + module + " import " + symbol
self._imports.append(implist)
else:
- self._imports.append('import ' + i.strip())
+ self._imports.append('import ' + imp.strip())
def extendsHandler(self, bc, start, stop):
"""Extends is a page directive.
@@ -129,7 +122,7 @@
The default base class is PSPPage. PSPPage inherits from Page.py.
"""
- self._baseClasses = map(lambda s: s.strip(), bc.split(','))
+ self._baseClasses = [s.strip() for s in bc.split(',')]
def mainMethodHandler(self, method, start, stop):
"""BaseMethod is a page directive.
@@ -142,7 +135,7 @@
"""
self._baseMethod = method
- def threadSafeHandler(self, bool, start, stop):
+ def threadSafeHandler(self, value, start, stop):
"""Handle isThreadSage.
isThreadSafe is a page directive.
@@ -151,9 +144,9 @@
Page.py, isn't thread safe.
"""
- self._threadSafe = bool
+ self._threadSafe = value
- def instanceSafeHandler(self, bool, start, stop):
+ def instanceSafeHandler(self, value, start, stop):
"""Handle isInstanceSafe.
isInstanceSafe tells the Servlet engine whether it is safe
@@ -163,12 +156,12 @@
Saying "no" here hurts performance.
"""
- self._instanceSafe = bool
+ self._instanceSafe = value
def indentTypeHandler(self, type, start, stop):
"""Declare whether tabs are used to indent source code."""
type = type.lower()
- if type != "tabs" and type != "spaces" and type != "braces":
+ if type not in ('tabs', 'spaces', 'braces'):
raise TypeError('Invalid Indentation Type')
self._writer.setIndentType(type)
@@ -179,8 +172,8 @@
def gobbleWhitespaceHandler(self, value, start, stop):
"""Declare whether whitespace between script tags are gobble up."""
- if value.lower() == "no" or value == "0":
- self._gobbleWhitespace = 0
+ if value.lower() in ('no', 'false', '0'):
+ self._gobbleWhitespace = False
def formatterHandler(self, value, start, stop):
"""Set an alternate formatter function to use instead of str()."""
@@ -204,29 +197,20 @@
self._parser.flushCharData(self.tmplStart, self.tmplStop)
# big switch
if directive == 'page':
- e = attrs.keys()
- for i in e:
- if self.directiveHandlers.has_key(i):
- self.directiveHandlers[i](self, attrs[i], start, stop)
+ for h in attrs:
+ if h in self.directiveHandlers:
+ self.directiveHandlers[h](self, attrs[h], start, stop)
else:
- print i
- raise ValueError, 'No page directive handler'
+ raise ValueError('No page directive handler: %s' % h)
elif directive == 'include':
+ filename = attrs['file']
+ encoding = attrs.get('encoding', None)
try:
- filenm = attrs['file']
- encoding = attrs['encoding']
- except KeyError:
- if filenm is not None:
- encoding = None
- else:
- raise KeyError
- try:
- self._reader.pushFile(filenm, encoding)
+ self._reader.pushFile(filename, encoding)
except IOError:
- raise IOError, 'PSP include file not found'
+ raise IOError('PSP include file not found: %s' % filename)
else:
- print directive
- raise ValueError, 'Invalid directive'
+ raise ValueError('Invalid directive: %s' % directive)
def handleScript(self, start, stop, attrs):
"""Handle scripting elements"""
@@ -269,15 +253,16 @@
pass
def endProcessing(self):
+ encoding = self._ctxt.getPythonFileEncoding()
+ if encoding:
+ # add encoding as a hint for both Python (PEP263) and editors
+ self._writer.println('# -*- coding: %s -*-' % encoding)
self._writer.println('# Generated automatically by PSP compiler on %s'
- % time.asctime(time.localtime(time.time())))
- enc = self._ctxt.getPythonFileEncoding()
- if enc:
- self._writer.println('# -*- coding: %s -*-' % enc)
+ % time.asctime(time.localtime(time.time())))
self._writer.println()
self.generateHeader()
self.generateAll('psp:file')
- self.generateDeclarations() # I'll overwrite this later when I can handle extends
+ self.generateDeclarations() # overwrite this when we can handle extends
self.generateInitPSP()
self.generateAll('psp:class')
self.generateAll('Declarations')
@@ -296,22 +281,15 @@
self.tmplStop = stop
def generateHeader(self):
- for i in self._imports:
- self._writer.println(i)
- # self._writer.println('try:\n')
- # self._writer.pushIndent()
- # self._writer.println('from ' + self._baseClass + ' import ' + self._baseClass + '\n')
+ for imp in self._imports:
+ self._writer.println(imp)
self._writer.println('import WebKit')
self._writer.println('from WebKit import Page')
for baseClass in self._baseClasses:
- if baseClass.find('.') < 0 and baseClass not in self._importedSymbols:
+ if '.' not in baseClass and baseClass not in self._importedSymbols:
self._writer.println('import ' + baseClass)
- # self._writer.popIndent()
- # self._writer.println('except ImportError:\n')
- # self._writer.pushIndent()
- # self._writer.println('pass\n')
- # self._writer.popIndent()
- self._writer.println("__orig_file__ = %r" % self._ctxt.getFullPspFileName())
+ self._writer.println("__orig_file__ = %r"
+ % self._ctxt.getFullPspFileName())
def generateDeclarations(self):
# The PSP "extends" directive allows you to use a shortcut
@@ -324,10 +302,12 @@
self._writer.println('import types')
self._writer.println('_baseClasses = []')
for baseClass in self._baseClasses:
- className = baseClass.split('.')[-1]
- self._writer.println('if isinstance(%s, types.ModuleType):' % baseClass)
+ className = baseClass.rsplit('.', 1)[-1]
+ self._writer.println(
+ 'if isinstance(%s, types.ModuleType):' % baseClass)
self._writer.pushIndent()
- self._writer.println('_baseClasses.append(%s.%s)' % (baseClass, className))
+ self._writer.println(
+ '_baseClasses.append(%s.%s)' % (baseClass, className))
self._writer.popIndent()
self._writer.println('else:')
self._writer.pushIndent()
@@ -343,26 +323,25 @@
self._writer.printChars(',')
self._writer.printChars('_baseClasses[%d]' % i)
self._writer.printChars('):')
- # self._writer.printChars('(' + self._baseClass + '):')
self._writer.printChars('\n')
self._writer.pushIndent()
- self._writer.println('def canBeThreaded(self):') # I Hope to take this out soon!
+ self._writer.println('def canBeThreaded(self):') # sadly, still needed
self._writer.pushIndent()
- if self._threadSafe.lower() == 'no':
- self._writer.println('return 0')
+ if self._threadSafe.lower() in ('no', 'false', '0'):
+ self._writer.println('return False')
else:
- self._writer.println('return 1')
+ self._writer.println('return True')
self._writer.popIndent()
self._writer.println()
- self._writer.println('def canBeReused(self):') # I Hope to take this out soon!
+ self._writer.println('def canBeReused(self):') # sadly, still needed
self._writer.pushIndent()
- if self._instanceSafe.lower() == 'no':
- self._writer.println('return 0')
+ if self._instanceSafe.lower() in ('no', 'false', '0'):
+ self._writer.println('return False')
else:
- self._writer.println('return 1')
+ self._writer.println('return True')
self._writer.popIndent()
self._writer.println()
- if not AwakeCreated:
+ if not self._writer._awakeCreated:
self._writer.println('def awake(self, trans):')
self._writer.pushIndent()
self._writer.println('for baseclass in self.__class__.__bases__:')
@@ -392,37 +371,35 @@
self._writer.println()
def generateMainMethod(self):
- # Write the output method that the user requested in with
- # <%@ page method="WriteHTML"%>
+ # Write the output method requested with <%@ page method=... %>
self._writer.printIndent()
- self._writer.printChars('def %s(self, transaction=None):\n' % self._baseMethod)
+ self._writer.printChars(
+ 'def %s(self, transaction=None):\n' % self._baseMethod)
self._writer.pushIndent()
self._writer.println('"""I take a WebKit.Transaction object."""')
self._writer.println('trans = self._transaction')
self._writer.println(ResponseObject + ' = trans.response()')
self._writer.println('req = trans.request()')
self._writer.println('self._%s(%s, req, trans)\n'
- % (self._baseMethod, ResponseObject))
+ % (self._baseMethod, ResponseObject))
# Put the real output code in a function that doesn't need
# a 'transaction' for unit tests.
self._writer.popIndent()
self._writer.println('def _%s(self, %s, req=None, trans=None):'
- % (self._baseMethod, ResponseObject))
+ % (self._baseMethod, ResponseObject))
self._writer.pushIndent()
- self._writer.println('"""I take a file-like object. I am useful for unit testing."""')
+ self._writer.println(
+ '"""I take a file-like object. I am useful for unit testing."""')
self._writer.println('_formatter = %s' % self._formatter)
- # self._writer.println('app = trans.application()')
def generateFooter(self):
- # Can't decide if this is in the class or outside.
- # Guess I'll know when I'm done"""
self._writer.popIndent()
self._writer.println('##footer')
def generateAll(self, phase):
- for i in self._gens:
- if i.phase == phase:
- i.generate(self._writer)
+ for gen in self._gens:
+ if gen.phase == phase:
+ gen.generate(self._writer)
def optimizeCharData(self):
"""Optimize the CharData.
@@ -435,10 +412,9 @@
gens = self._gens
count = 0
gencount = len(gens)
-
while count < gencount-1:
- if isinstance(gens[count], CharDataGenerator) \
- and isinstance(gens[count+1], CharDataGenerator):
+ if (isinstance(gens[count], CharDataGenerator)
+ and isinstance(gens[count+1], CharDataGenerator)):
gens[count].mergeData(gens[count+1])
gens.remove(gens[count+1])
gencount -= 1
@@ -455,18 +431,18 @@
a if/else, try/except etc.
"""
- debug = 0
+ debug = False
gens = self._gens
sideClasses = (ScriptGenerator, EndBlockGenerator)
count = 1
gencount = len(gens)
if debug:
- for i in gens:
- print "Generator type = %s" % i.__class__
+ for gen in gens:
+ print "Generator type = %s" % gen.__class__
while count < gencount - 1:
- if isinstance(gens[count], CharDataGenerator) \
- and gens[count+1].__class__ in sideClasses \
- and gens[count-1].__class__ in sideClasses:
+ if (isinstance(gens[count], CharDataGenerator)
+ and gens[count+1].__class__ in sideClasses
+ and gens[count-1].__class__ in sideClasses):
if checkForTextHavingOnlyGivenChars(gens[count].chars):
gens.remove(gens[count])
gencount -= 1
@@ -485,5 +461,6 @@
else:
for char in text:
if char not in ws:
- return 0
- return 1
+ return False
+ else:
+ return True
Modified: Webware/trunk/PSP/Properties.py
==============================================================================
--- Webware/trunk/PSP/Properties.py (original)
+++ Webware/trunk/PSP/Properties.py Sat Jun 20 17:41:03 2009
@@ -11,10 +11,10 @@
synopsis = """A Python Server Page (or PSP) is an HTML document with interspersed Python instructions that are interpreted as a template to generate dynamic content. PSP is analogous to PHP, Microsoft's ASP and Sun's JSP. PSP sits on top of (and requires) WebKit and therefore benefits from its features."""
WebKitConfig = {
- 'examplePages': [
- 'Hello',
- 'Braces',
- 'PSPTests',
- 'PSPTests-Braces',
- ]
+ 'examplePages': [
+ 'Hello',
+ 'Braces',
+ 'PSPTests',
+ 'PSPTests-Braces',
+ ]
}
Modified: Webware/trunk/PSP/ServletWriter.py
==============================================================================
--- Webware/trunk/PSP/ServletWriter.py (original)
+++ Webware/trunk/PSP/ServletWriter.py Sat Jun 20 17:41:03 2009
@@ -1,34 +1,24 @@
"""This module holds the actual file writer class.
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
import os
from tempfile import mkstemp
-from Context import *
-
-class ServletWriter:
+class ServletWriter(object):
"""This file creates the servlet source code.
Well, it writes it out to a file at least.
@@ -46,31 +36,32 @@
self._tabcnt = 0
self._blockcount = 0 # a hack to handle nested blocks of python code
self._indentSpaces = self._spaces
- self._useTabs = 0
- self._useBraces = 0
+ self._useTabs = False
+ self._useBraces = False
self._indent = ' '
self._userIndent = self._emptyString
+ self._awakeCreated = False # means that awake() needs to be generated
def setIndentSpaces(self, amt):
- self._indentSpaces = ' '*amt
+ self._indentSpaces = ' ' * amt
self.setIndention()
def setIndention(self):
if self._useTabs:
self._indent = '\t'
else:
- self._indent = self._indentSpaces # ' '*self._indentSpaces
+ self._indent = self._indentSpaces
def setIndentType(self, type):
if type == 'tabs':
- self._useTabs = 1
+ self._useTabs = True
self.setIndention()
elif type == 'spaces':
- self._useTabs = 0
+ self._useTabs = False
self.setIndention()
elif type == 'braces':
- self._useTabs = 0
- self._useBraces = 1
+ self._useTabs = False
+ self._useBraces = True
self.setIndention()
def close(self):
@@ -103,46 +94,45 @@
self.println('## from ' + str(start))
self.println('## from ' + str(stop))
if chars:
- sp = chars.split('\n')
- for i in sp:
+ lines = chars.split('\n')
+ for line in lines:
self._filehandle.write(self.indent(''))
self._filehandle.write('##')
- self._filehandle.write(i)
+ self._filehandle.write(line)
def quoteString(self, s):
"""Escape the string."""
if s is None:
- return 'None'
# this probably won't work, I'll be back for this
- return 'r'+s
+ return 'None'
+ return 'r' + s
- def indent(self, st):
+ def indent(self, s):
"""Indent the string."""
- # added userIndent 6/18/00
- if self._tabcnt > 0:
- return self._userIndent + self._indent*self._tabcnt + st
- return st
+ if self._userIndent or self._tabcnt > 0:
+ return self._userIndent + self._indent*self._tabcnt + s
+ return s
def println(self, line=None):
"""Print with indentation and a newline if none supplied."""
if line:
self._filehandle.write(self.indent(line))
+ if not line.endswith('\n'):
+ self._filehandle.write('\n')
else:
self._filehandle.write(self.indent('\n'))
- if line and line[:-1] != '\n':
- self._filehandle.write('\n')
- def printChars(self, st):
+ def printChars(self, s):
"""Just prints what its given."""
- self._filehandle.write(st)
+ self._filehandle.write(s)
- def printMultiLn(self, st):
+ def printMultiLn(self, s):
raise NotImplementedError
def printList(self, strlist):
"""Prints a list of strings with indentation and a newline."""
- for i in strlist:
- self.printChars(self.indent(i))
+ for line in strlist:
+ self.printChars(self.indent(line))
self.printChars('\n')
def printIndent(self):
Modified: Webware/trunk/PSP/StreamReader.py
==============================================================================
--- Webware/trunk/PSP/StreamReader.py (original)
+++ Webware/trunk/PSP/StreamReader.py Sat Jun 20 17:41:03 2009
@@ -1,85 +1,67 @@
"""This module co-ordinates the reading of the source file.
- It maintains the current position of the parser in the source file.
+It maintains the current position of the parser in the source file.
- (c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
+(c) Copyright by Jay Love, 2000 (mailto:jsliv@...)
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee or royalty is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation or portions thereof, including modifications,
+that you make.
- This software is based in part on work done by the Jakarta group.
+This software is based in part on work done by the Jakarta group.
"""
-from Context import *
-
-import copy
+from copy import copy
import os
+from PSPUtils import PSPParserException
+
-class Mark:
+class Mark(object):
"""The Mark class marks a point in an input stream."""
- def __init__(self, reader, fileid=None, stream=None, inBaseDir=None, encoding=None):
+ def __init__(self, reader,
+ fileId=None, stream=None, inBaseDir=None, encoding=None):
if isinstance(reader, StreamReader):
self.reader = reader
- self.fileid = fileid
+ self.fileId = fileId
self.includeStack = []
self.cursor = 0
self.stream = stream
self.baseDir = inBaseDir
self.encoding = encoding
else:
- self = copy.copy(reader)
- # I think the includeStack will be copied correctly,
- # but check here for problems: raise Error('clone include stack')
- # JSP has an equals function, but I don't think I need that,
- # because of using copy, but maybe I do.
-
- def getFile(self):
- return self.reader.getFile(self.fileid)
+ self = copy(reader)
def __str__(self):
- return self.getFile() + '(' + str(self.line) + str(self.col) + ')'
+ return '%s(%d)' % (self.getFile(), self.cursor)
- def __repr__(self):
- return self.getFile() + '(' + str(self.col) + ')'
+ def getFile(self):
+ return self.reader.getFile(self.fileId)
- def pushStream(self, infileid, inStream, inBaseDir, inEncoding):
- self.includeStack.append((self.cursor, self.fileid, self.baseDir, self.encoding, self.stream))
+ def pushStream(self, inFileId, inStream, inBaseDir, inEncoding):
+ self.includeStack.append((self.cursor, self.fileId, self.baseDir,
+ self.encoding, self.stream))
self.cursor = 0
- self.fileid = infileid
+ self.fileId = inFileId
+ self.stream = inStream
self.baseDir = inBaseDir
self.encoding = inEncoding
- self.stream = inStream
def popStream(self):
- if len(self.includeStack) == 0:
- return 0 # false
- list = self.includeStack[len(self.includeStack)-1]
- del self.includeStack[len(self.includeStack)-1]
- self.cursor = list[0]
- self.fileid = list[1]
- self.baseDir = list[2]
- self.encoding = list[3]
- self.stream = list[4]
- return 1 # true
+ if not self.includeStack:
+ return False
+ (self.cursor, self.fileId, self.baseDir,
+ self.encoding, self.stream) = self.includeStack.pop()
+ return True
-class StreamReader:
+class StreamReader(object):
"""This class handles the PSP source file.
It provides the characters to the other parts of the system.
@@ -90,7 +72,6 @@
def __init__(self, filename, ctxt):
self._pspfile = filename
self._ctxt = ctxt
- self._filehandle = None
self.sourcefiles = []
self.current = None
self.master = None
@@ -98,45 +79,34 @@
def init(self):
self.pushFile(self._ctxt.getFullPspFileName())
- def registerSourceFile(self, file):
- self.sourcefiles.append(file)
+ def registerSourceFile(self, filepath):
+ self.sourcefiles.append(filepath)
return len(self.sourcefiles) - 1
- def pushFile(self, file, encoding=None):
- assert type(file) == type('')
- # if type(file) != type(''):
- # we've got an open file handle - don't think this case exists
- # Don't know what this master stuff is, but until I do, implement it.
- # Oh, it's the original file.
+ def pushFile(self, filepath, encoding=None):
+ assert isinstance(filepath, basestring)
if self.master is None:
parent = None
- self.master = file
+ self.master = filepath
else:
parent = os.path.split(self.master)[0]
- isAbsolute = os.path.isabs(file)
+ isAbsolute = os.path.isabs(filepath)
if parent is not None and not isAbsolute:
- file = os.path.join(parent, file)
- fileid = self.registerSourceFile(file)
- handle = open(file, 'r')
+ filepath = os.path.join(parent, filepath)
+ fileId = self.registerSourceFile(filepath)
+ handle = open(filepath, 'rU')
stream = handle.read()
handle.seek(0, 0)
- lines = handle.readlines()
- z = 0
- for i in lines:
- lines[z] = i.replace('\r\n', '\n').replace('\r', '\n')
- z += 1
- stream = ''.join(lines)
-
if self.current is None:
- self.current = Mark(self, fileid, stream,
- self._ctxt.getBaseUri(), encoding)
+ self.current = Mark(self, fileId, stream,
+ self._ctxt.getBaseUri(), encoding)
else:
- self.current.pushStream(fileid, stream,
- self._ctxt.getBaseUri(), encoding) # don't use yet
+ self.current.pushStream(fileId, stream,
+ self._ctxt.getBaseUri(), encoding) # don't use yet
def popFile(self):
if self.current is None:
- return 0
+ return None
return self.current.popStream()
def getFile(self, i):
@@ -148,39 +118,39 @@
self.sourcefiles.append(filename)
return len(self.sourcefiles)
- def Mark(self):
- return copy.copy(self.current)
+ def mark(self):
+ return copy(self.current)
- def skipUntil(self, st):
+ def skipUntil(self, s):
"""Greedy search.
Return the point before the string, but move reader past it.
"""
- pt = self.current.stream.find(st, self.current.cursor)
- if pt == -1:
+ new_cursor = self.current.stream.find(s, self.current.cursor)
+ if new_cursor < 0:
self.current.cursor = len(self.current.stream)
if self.hasMoreInput():
- self.popFile() # @@ Should I do this here? 6/1/00
- self.skipUntil(st)
+ self.popFile()
+ self.skipUntil(s)
else:
raise EOFError
else:
- self.current.cursor = pt
- ret = self.Mark()
- self.current.cursor += len(st)
- return ret
+ self.current.cursor = new_cursor
+ mark = self.mark()
+ self.current.cursor += len(s)
+ return mark
def reset(self, mark):
self.current = mark
- def Matches(self, st):
- if st == self.current.stream[
- self.current.cursor:self.current.cursor+len(st)]:
- return 1
- return 0
+ def matches(self, s):
+ if s == self.current.stream[
+ self.current.cursor:self.current.cursor+len(s)]:
+ return True
+ return False
- def Advance(self, length):
+ def advance(self, length):
"""Advance length characters"""
if length + self.current.cursor <= len(self.current.stream):
self.current.cursor += length
@@ -188,45 +158,42 @@
prog = len(self.current.stream) - self.current.cursor
self.current.cursor = len(self.current.stream)
if self.hasMoreInput():
- self.Advance(length-prog)
+ self.advance(length - prog)
else:
raise EOFError()
def nextChar(self):
- if self.hasMoreInput() == 0:
+ if not self.hasMoreInput():
return -1
- ch = self.current.stream[self.current.cursor]
- self.Advance(1)
- return ch
+ c = self.current.stream[self.current.cursor]
+ self.advance(1)
+ return c
def isSpace(self):
"""No advancing."""
- return self.current.stream[self.current.cursor] == ' ' \
- or self.current.stream[self.current.cursor] == '\n'
+ return self.current.stream[self.current.cursor] in (' ', '\n')
def isDelimiter(self):
if not self.isSpace():
- ch = self.peekChar()
+ c = self.peekChar()
# Look for single character work delimiter:
- if ch == '=' or ch == '\"' or ch == "'" or ch == '/':
- return 1
+ if c in ('=', '"', "'", '/'):
+ return True
# Look for end of comment or basic end tag:
- if ch == '-':
- mark = self.Mark()
- ch = self.nextChar()
- ch2 = self.nextChar()
- if ch == '>' or (ch == '-' and ch2 == '>'):
- self.reset(mark)
- return 1
- else:
+ if c == '-':
+ mark = self.mark()
+ c = self.nextChar()
+ try:
+ return c == '>' or (c == '-' and self.nextChar() == '>')
+ finally:
self.reset(mark)
- return 0
else:
- return 1
+ return True
def peekChar(self, cnt=1):
if self.hasMoreInput():
- return self.current.stream[self.current.cursor:self.current.cursor+cnt]
+ return self.current.stream[
+ self.current.cursor:self.current.cursor+cnt]
raise EOFError
def skipSpaces(self):
@@ -237,100 +204,97 @@
return i
def getChars(self, start, stop):
- oldcurr = self.Mark()
+ mark = self.mark()
self.reset(start)
chars = self.current.stream[start.cursor:stop.cursor]
- self.reset(oldcurr)
+ self.reset(mark)
return chars
def hasMoreInput(self):
if self.current.cursor >= len(self.current.stream):
while self.popFile():
if self.current.cursor < len(self.current.stream) :
- return 1
- return 0
- return 1
+ return True
+ return False
+ return True
def nextContent(self):
"""Find next < char."""
cur_cursor = self.current.cursor
self.current.cursor += 1
- pt = self.current.stream.find('<', self.current.cursor)
- if pt == -1:
- self.current.cursor = len(self.current.stream)
- else:
- self.current.cursor = pt
- return self.current.stream[cur_cursor:self.current.cursor]
+ new_cursor = self.current.stream.find('<', self.current.cursor)
+ if new_cursor < 0:
+ new_cursor = len(self.current.stream)
+ self.current.cursor = new_cursor
+ return self.current.stream[cur_cursor:new_cursor]
def parseTagAttributes(self):
"""Parse the attributes at the beginning of a tag."""
values = {}
while 1:
self.skipSpaces()
- ch = self.peekChar()
- if ch == '>':
+ c = self.peekChar()
+ if c == '>':
return values
- if ch == '-':
- mark = self.Mark()
+ if c == '-':
+ mark = self.mark()
self.nextChar()
try:
if self.nextChar() == '-' and self.nextChar() == '>':
return values
finally:
self.reset(mark)
- elif ch == '%':
- mark = self.Mark()
+ elif c == '%':
+ mark = self.mark()
self.nextChar()
try:
- ts = self.peekChar()
- if ts == '>':
- self.reset(mark)
+ if self.peekChar() == '>':
return values
finally:
self.reset(mark)
- if ch is None:
+ elif not c:
break
self.parseAttributeValue(values)
- raise ValueError, 'PSP Error - unterminated attribute'
+ raise PSPParserException('Unterminated attribute')
- def parseAttributeValue(self, valuedict):
+ def parseAttributeValue(self, valueDict):
self.skipSpaces()
name = self.parseToken(0)
self.skipSpaces()
if self.peekChar() != '=':
- raise ValueError, 'PSP Error - no attribute value'
+ raise PSPParserException('No attribute value')
self.nextChar()
self.skipSpaces()
value = self.parseToken(1)
self.skipSpaces()
- valuedict[name] = value
+ valueDict[name] = value
def parseToken(self, quoted):
# This may not be quite right:
buffer = []
self.skipSpaces()
- ch = self.peekChar()
+ c = self.peekChar()
if quoted:
- if ch == '\"' or ch == "\'":
- endquote = ch
- ch = self.nextChar()
- ch = self.peekChar()
- while ch is not None and ch != endquote:
- ch = self.nextChar()
- if ch == '\\':
- ch = self.nextChar()
- buffer.append(ch)
- ch = self.peekChar()
- if ch is None:
- raise ValueError, 'PSP Error - unterminated attribute value'
+ if c in ('"', "'"):
+ endquote = c
+ self.nextChar()
+ c = self.peekChar()
+ while c is not None and c != endquote:
+ c = self.nextChar()
+ if c == '\\':
+ c = self.nextChar()
+ buffer.append(c)
+ c = self.peekChar()
+ if c is None:
+ raise PSPParserException('Unterminated attribute value')
self.nextChar()
else:
if not self.isDelimiter():
while not self.isDelimiter():
- ch = self.nextChar()
- if ch == '\\':
- ch = self.peekChar()
- if ch == '\"' or ch == "'" or ch == '>' or ch == '%':
- ch = self.nextChar()
- buffer.append(ch)
+ c = self.nextChar()
+ if c == '\\':
+ c = self.peekChar()
+ if c in ('"', "'", '>', '%'):
+ c = self.nextChar()
+ buffer.append(c)
return ''.join(buffer)
Added: Webware/trunk/PSP/Tests/FixPath.py
==============================================================================
--- (empty file)
+++ Webware/trunk/PSP/Tests/FixPath.py Sat Jun 20 17:41:03 2009
@@ -0,0 +1,16 @@
+"""Fix the Python path to start with our Webware parent directory.
+
+Merely importing this module fixes the path.
+
+Doing this _guarantees_ that we're testing our local classes and not some other
+installation. For those of us who have multiple instances of Webware present,
+this is critical. For those who do not, this doesn't hurt anything.
+
+"""
+
+import sys
+from os.path import abspath, dirname
+
+webwarePath = dirname(dirname(dirname(abspath(__file__))))
+if sys.path[0] != webwarePath:
+ sys.path.insert(0, webwarePath)
Added: Webware/trunk/PSP/Tests/TestBraceConverter.py
==============================================================================
--- (empty file)
+++ Webware/trunk/PSP/Tests/TestBraceConverter.py Sat Jun 20 17:41:03 2009
@@ -0,0 +1,95 @@
+"""Automated tests for the PSP BraceConverter
+
+Contributed 2000-09-04 by Dave Wallace
+
+"""
+
+import sys
+import unittest
+from StringIO import StringIO
+
+import FixPath
+from PSP.BraceConverter import BraceConverter
+from PSP.ServletWriter import ServletWriter
+
+
+class DummyWriter(ServletWriter):
+ """Dummy writer for testing."""
+
+ def __init__(self):
+ self._filehandle = StringIO()
+ self._tabcnt = 3 # base indentation of our test examples
+ self._blockcount = 0
+ self._indentSpaces = ServletWriter._spaces
+ self._useTabs = False
+ self._useBraces = False
+ self._indent = ' '
+ self._userIndent = ServletWriter._emptyString
+
+ def getOutput(self):
+ return self._filehandle.getvalue()
+
+ def close(self):
+ self._filehandle.close()
+
+
+class TestBraceConverter(unittest.TestCase):
+
+ def trim(self, text):
+ return '\n'.join(filter(None, map(str.rstrip, text.splitlines())))
+
+ def assertParses(self, input, expected):
+ dummyWriter = DummyWriter()
+ braceConverter = BraceConverter()
+ for line in input.splitlines():
+ braceConverter.parseLine(line, dummyWriter)
+ output = dummyWriter.getOutput()
+ dummyWriter.close()
+ output, expected = map(self.trim, (output, expected))
+ self.assertEqual(output, expected,
+ '\n\nOutput:\n%s\n\nExpected:\n%s\n' % (output, expected))
+
+ def testSimple(self):
+ self.assertParses('''
+ if a == b: { return True } else: { return False }
+ ''', '''
+ if a == b:
+ return True
+ else:
+ return False
+ ''')
+
+ def testDict(self):
+ self.assertParses('''
+ for x in range(10): { q = {
+ 'test': x
+ }
+ print x
+ }
+ ''', '''
+ for x in range(10):
+ q = {
+ 'test': x
+ }
+ print x
+ ''')
+
+ def testNestedDict(self):
+ self.assertParses(r'''
+ if x: { q = {'test': x}; print x} else: { print "\"done\"" #""}{
+ x = { 'test1': {'sub2': {'subsub1': 2}} # yee ha
+ }
+ } print "all done"
+ ''', r'''
+ if x:
+ q = {'test': x}; print x
+ else:
+ print "\"done\"" #""}{
+ x = { 'test1': {'sub2': {'subsub1': 2}} # yee ha
+ }
+ print "all done"
+ ''')
+
+
+if __name__ == '__main__':
+ unittest.main()
Copied: Webware/trunk/PSP/Tests/TestCompiler.py (from r7973, /Webware/trunk/PSP/Tests/CompileTest.py)
==============================================================================
--- /Webware/trunk/PSP/Tests/CompileTest.py (original)
+++ Webware/trunk/PSP/Tests/TestCompiler.py Sat Jun 20 17:41:03 2009
@@ -1,22 +1,6 @@
-"""
- Automated tests for PSP Kit
-
- (c) Copyright by Winston Wolff, 2004 http://www.stratolab.com
+"""Automated tests for PSPCompiler
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+(c) Copyright by Winston Wolff, 2004 http://www.stratolab.com
"""
@@ -34,24 +18,25 @@
_log = logging.getLogger(__name__)
# Turn off debug messages, and delete temporary scripts after test:
-DEBUG = 0
+DEBUG = False
if DEBUG:
logging.basicConfig()
_log.setLevel(logging.DEBUG)
-class CompileTest(unittest.TestCase):
+class TestCompiler(unittest.TestCase):
def compileString(self, pspSource, classname):
- '''Compile a string to an object.
+ """Compile a string to an object.
Takes a string, compiles it, imports the Python file, and returns you
the Python class object.
classname = some string so that each file is unique per test case.
- '''
+
+ """
# write string to temporary file
- moduleName = "tmp_CompileTest_" + classname
+ moduleName = "tmp_TestCompiler_" + classname
tmpInName = moduleName + ".psp"
tmpOutName = moduleName + ".py"
_log.debug('Writing PSP source to: "%s"', tmpInName)
@@ -90,44 +75,46 @@
return output
def testExpression(self):
- output = self.compileAndRun('two plus three is: <%= 2+3 %>', 'testExpression')
- self.assertEquals("two plus three is: 5", output)
+ output = self.compileAndRun(
+ 'two plus three is: <%= 2+3 %>', 'testExpression')
+ self.assertEqual("two plus three is: 5", output)
def testScript(self):
- output = self.compileAndRun('one plus two is: <% res.write(str(1+2)) %>', 'testScript')
- self.assertEquals("one plus two is: 3", output)
+ output = self.compileAndRun(
+ 'one plus two is: <% res.write(str(1+2)) %>', 'testScript')
+ self.assertEqual("one plus two is: 3", output)
def testScript_NewLines(self):
psp = '''\nthree plus two is: \n<%\nres.write(str(3+2)) \n%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun(psp, 'testScript_NewLines')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
psp = '''\nthree plus two is: \n<%\n res.write(str(3+2)) \n%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun(psp, 'testScript_NewLines')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
def testScript_Returns(self):
psp = '''\rthree plus two is: \r<%\rres.write(str(3+2)) \r%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun(psp, 'testScript_Returns')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
psp = '''\rthree plus two is: \r<%\r res.write(str(3+2)) \r%>'''
expect = '''\nthree plus two is: \n5'''
output = self.compileAndRun(psp, 'testScript_Returns')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
def testScript_If(self):
psp = '''PSP is <% if 1: %>Good<% end %>'''
expect = '''PSP is Good'''
output = self.compileAndRun(psp, 'testScript_If')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
def testScript_IfElse(self):
psp = '''JSP is <% if 0: %>Good<% end %><% else: %>Bad<% end %>'''
expect = '''JSP is Bad'''
output = self.compileAndRun(psp, 'testScript_IfElse')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
def testScript_Blocks(self):
psp = '''
@@ -143,7 +130,7 @@
2<br/>
'''
output = self.compileAndRun(psp, 'testScript_Blocks')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
def testScript_Braces(self):
psp = '''\
@@ -160,7 +147,7 @@
2<br/>
'''
output = self.compileAndRun(psp, 'testScript_Braces')
- self.assertEquals(output, expect)
+ self.assertEqual(output, expect)
def testPspMethod(self):
psp = '''
@@ -170,26 +157,26 @@
7 plus 8 = <%= self.add(7,8) %>
'''
output = self.compileAndRun(psp, 'testPspMethod').strip()
- self.assertEquals("7 plus 8 = 15", output)
+ self.assertEqual("7 plus 8 = 15", output)
def testPspFile(self):
psp = '''
<psp:file>
- def square(a):
- return a*a
+ def square(a):
+ return a*a
</psp:file>
7^2 = <%= square(7) %>
'''
output = self.compileAndRun(psp, 'testPspFile').strip()
- self.assertEquals("7^2 = 49", output)
+ self.assertEqual("7^2 = 49", output)
def testPspClass(self):
psp = '''
<psp:class>
- def square(self, a):
- return a*a
+ def square(self, a):
+ return a*a
</psp:class>
4^2 = <%= self.square(4) %>
'''
output = self.compileAndRun(psp, 'testPspClass').strip()
- self.assertEquals("4^2 = 16", output)
+ self.assertEqual("4^2 = 16", output)
Added: Webware/trunk/PSP/Tests/TestContext.py
==============================================================================
--- (empty file)
+++ Webware/trunk/PSP/Tests/TestContext.py Sat Jun 20 17:41:03 2009
@@ -0,0 +1,47 @@
+"""Automated tests for the PSP Context"""
+
+import os
+import unittest
+
+import FixPath
+from PSP.Context import PSPCLContext
+
+
+
+class TestCLContext(unittest.TestCase):
+
+ def testInit(self):
+ pspfile = '/files/PSP/ContextTest.psp'.replace('/', os.sep)
+ clc = PSPCLContext(pspfile)
+ self.assertEqual(clc.getFullPspFileName(), pspfile)
+ self.assertEqual(clc.getPspFileName(), 'ContextTest.psp')
+ self.assertEqual(clc.getBaseUri(), '/files/PSP'.replace('/', os.sep))
+
+ def testPythonFileEncodin(self):
+ clc = PSPCLContext('test.psp')
+ self.assertEqual(clc.getPythonFileEncoding(), None)
+ clc.setPythonFileEncoding('latin-1')
+ self.assertEqual(clc.getPythonFileEncoding(), 'latin-1')
+
+ def testResolveRelativeURI(self):
+ pspfile = '/files/PSP/Test1.psp'.replace('/', os.sep)
+ clc = PSPCLContext(pspfile)
+ uri = clc.resolveRelativeURI('Test2.psp')
+ self.assertEqual(uri, '/files/PSP/Test2.psp'.replace('/', os.sep))
+ pspfile = '/files3/PSP3/Test3.psp'.replace('/', os.sep)
+ self.assertEqual(clc.resolveRelativeURI(uri), uri)
+
+ def testPSPReader(self):
+ reader = object()
+ clc = PSPCLContext('test.psp')
+ clc.setPSPReader(reader)
+ self.assertEqual(clc.getReader(), reader)
+
+ def testClassName(self):
+ clc = PSPCLContext('test.psp')
+ clc.setClassName('ContextTestClass')
+ self.assertEqual(clc.getServletClassName(), 'ContextTestClass')
+
+
+if __name__ == '__main__':
+ unittest.main()
Copied: Webware/trunk/PSP/Tests/TestUtils.py (from r7973, /Webware/trunk/PSP/Tests/PSPUtilsTest.py)
==============================================================================
--- /Webware/trunk/PSP/Tests/PSPUtilsTest.py (original)
+++ Webware/trunk/PSP/Tests/TestUtils.py Sat Jun 20 17:41:03 2009
@@ -1,65 +1,86 @@
-"""
- Automated tests for PSPUtils
-
- (c) Copyright by Winston Wolff, 2004 http://www.stratolab.com
+"""Automated tests for PSPUtils
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee or royalty is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation or portions thereof, including modifications,
- that you make.
-
- THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
- INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+(c) Copyright by Winston Wolff, 2004 http://www.stratolab.com
"""
import unittest
+
+import FixPath
from PSP import PSPUtils
-if 0:
- import doctest
- def suite():
- """Combine our unittest with our doctests."""
- result = unittest.TestSuite()
- result.addTest(doctest.DocTestSuite(PSPUtils))
- result.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(PSPUtilsTest))
- return result
+class TestUtils(unittest.TestCase):
+ def testRemoveQuotes(self):
+ self.assertEqual(PSPUtils.removeQuotes(
+ r'html <% psp %\\> html'), 'html <% psp %> html')
+
+ def testIsExpression(self):
+ self.assertEqual(PSPUtils.isExpression('<%= bla'), False)
+ self.assertEqual(PSPUtils.isExpression('bla %>'), False)
+ self.assertEqual(PSPUtils.isExpression('<%= bla %>'), True)
+ self.assertEqual(PSPUtils.isExpression('bla <%= bla %>'), False)
+ self.assertEqual(PSPUtils.isExpression('<%= bla %> bla'), False)
+
+ def testGetExpr(self):
+ self.assertEqual(PSPUtils.getExpr('<%= bla'), '')
+ self.assertEqual(PSPUtils.getExpr('bla %>'), '')
+ self.assertEqual(PSPUtils.getExpr('<%= bla %>'), ' bla ')
+ self.assertEqual(PSPUtils.getExpr('bla <%= bla %>'), '')
+ self.assertEqual(PSPUtils.getExpr('<%= bla %> bla'), '')
-class PSPUtilsTest(unittest.TestCase):
+ def testSplitLines(self):
+ self.assertEqual(PSPUtils.splitLines(
+ 'foo\nbar\n'), ['foo', 'bar'])
+ self.assertEqual(PSPUtils.splitLines(
+ 'foo\rbar\r'), ['foo', 'bar'])
+ self.assertEqual(PSPUtils.splitLines(
+ 'foo\rbar\n', True), ['foo\r', 'bar\n'])
+
+ def testStartsNewBlock(self):
+ startsNewBlock = PSPUtils.startsNewBlock
+ self.assertEqual(startsNewBlock('x = 1'), False)
+ self.assertEqual(startsNewBlock('if x == 1:'), True)
+ self.assertEqual(startsNewBlock('x = 1 # bla:'), False)
+ self.assertEqual(startsNewBlock('if x == 1: # bla'), True)
+ self.assertEqual(startsNewBlock('if x == 1: bla'), False)
+ self.assertEqual(startsNewBlock('x = "if x == 1:" # bla:'), False)
+
+ def testCheckAttributes(self):
+ checkAttributes = PSPUtils.checkAttributes
+ for attrs in (dict(man=1), dict(man=1, opt=1)):
+ checkAttributes('test', attrs, (['man'], ['opt']))
+ PSPParserException = PSPUtils.PSPParserException
+ for attrs in (dict(), dict(opt=1), dict(man=1, noopt=1)):
+ self.assertRaises(PSPParserException, checkAttributes,
+ 'test', attrs, (['man'], ['opt']))
+ self.assertRaises(PSPParserException, checkAttributes,
+ 'test', dict(opt=1), (['man1', 'man2'], []))
+ self.assertRaises(PSPParserException, checkAttributes,
+ 'test', dict(man=1), ([], ['opt1', 'opt2']))
def testNormalizeIndentation(self):
+ normalizeIndentation = PSPUtils.normalizeIndentation
before = """
def add(a,b):
return a+b"""
- expected = \
-"""
+ expected = """
def add(a,b):
return a+b"""
-
- self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
+ self.assertEqual(normalizeIndentation(before), expected)
# Comments should be ignored for the unindentation
before = """
# Will comments throw off the indentation?
def add(a,b):
return a+b"""
- expected = \
-"""
+ expected = """
# Will comments throw off the indentation?
def add(a,b):
return a+b"""
-
- self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
+ self.assertEqual(normalizeIndentation(before), expected)
# Will blank lines cause a problem?
before = """
@@ -68,26 +89,24 @@
def add(a,b):
return a+b"""
- expected = \
-"""
+ expected = """
# Will blank lines cause a problem?
def add(a,b):
return a+b"""
+ self.assertEqual(normalizeIndentation(before), expected)
- self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
+ # Tab chars OK?
+ before = '\tdef add(a,b):\n\t\treturn a+b'
+ expected = 'def add(a,b):\n\treturn a+b'
+ self.assertEqual(normalizeIndentation(before), expected)
# Different line endings OK?
before = '#line endings\r def add(a,b):\r \r return a+b'
expected = '#line endings\rdef add(a,b):\r\rreturn a+b'
+ self.assertEqual(normalizeIndentation(before), expected)
- self.assertEquals(PSPUtils.normalizeIndentation(before), expected)
-
- def testSplitLines(self):
-
- text = 'one\rtwo\rthree'
- self.assertEquals(3, len(PSPUtils.splitLines(text)))
- text = 'one\ntwo\nthree'
- self.assertEquals(3, len(PSPUtils.splitLines(text)))
+if __name__ == '__main__':
+ unittest.main()
Modified: Webware/trunk/PSP/cl_psp.py
==============================================================================
--- Webware/trunk/PSP/cl_psp.py (original)
+++ Webware/trunk/PSP/cl_psp.py Sat Jun 20 17:41:03 2009
@@ -3,13 +3,12 @@
from Context import PSPCLContext
from PSPCompiler import Compiler
-from ServletWriter import ServletWriter
# Move this to a class like JPS?
def PSPCompile(*args):
pspfilename = args[0]
- fil, ext= os.path.basename(pspfilename).split('.')
+ fil, ext = os.path.splitext(os.path.basename(pspfilename))
classname = fil + '_' + ext
pythonfilename = classname + '.py'
context = PSPCLContext(pspfilename)
Modified: Webware/trunk/WebKit/Tests/twill/PSP.twill
==============================================================================
--- Webware/trunk/WebKit/Tests/twill/PSP.twill (original)
+++ Webware/trunk/WebKit/Tests/twill/PSP.twill Sat Jun 20 17:41:03 2009
@@ -38,7 +38,7 @@
notfind 'test page uses <a href="Braces"><b>braces</b></a>'
find "<p>Hello from included file!<p>"
find "<p>\w{3} \w{3} ( |\d)\d \d{2}:\d{2}:\d{2} \d{4}</p>"
-find 'This is a HTML file that is dynamically inserted.'
+find 'This is an HTML file that is dynamically inserted.'
find '<p style="color:purple">\w{3} \w{3} ( |\d)\d \d{2}:\d{2}:\d{2} \d{4}</p>'
find "<ul><li>Outer loop: 1"
find "<li>Inner loop: 2"
@@ -57,7 +57,7 @@
find 'test page uses <a href="Braces"><b>braces</b></a>'
find "<p>Hello from included file!<p>"
find "<p>\w{3} \w{3} ( |\d)\d \d{2}:\d{2}:\d{2} \d{4}</p>"
-find 'This is a HTML file that is dynamically inserted.'
+find 'This is an HTML file that is dynamically inserted.'
find '<p style="color:purple">\w{3} \w{3} ( |\d)\d \d{2}:\d{2}:\d{2} \d{4}</p>'
find "<ul><li>Outer loop: 1"
find "<li>Inner loop: 2"
Modified: Webware/trunk/install.py
==============================================================================
--- Webware/trunk/install.py (original)
+++ Webware/trunk/install.py Sat Jun 20 17:41:03 2009
@@ -5,9 +5,9 @@
Webware for Python installer
FUTURE
- * Look for an install.py in each component directory and run it
- (there's not a strong need right now).
- * Use distutils or setuptools instead of our own plugin concept.
+ * Look for an install.py in each component directory and run it
+ (there's not a strong need right now).
+ * Use distutils or setuptools instead of our own plugin concept.
"""
@@ -67,7 +67,8 @@
## Running the installation ##
- def run(self, verbose=0, passprompt=1, defaultpass='', keepdocs=0):
+ def run(self, verbose=False,
+ passprompt=True, defaultpass='', keepdocs=False):
self._verbose = verbose
self.printMsg = verbose and self._printMsg or self._nop
log = []
@@ -129,7 +130,7 @@
'but Webware may not perform as expected.\n'
'Do you wish to continue with the installation? [yes/no] ')
return response[:1].upper() == "Y"
- return 1
+ return True
def checkThreading(self):
try:
@@ -142,7 +143,7 @@
'interpreter that has threading enabled.\n'
'Do you wish to continue with the installation? [yes/no] ')
return response[:1].upper() == "Y"
- return 1
+ return True
def detectComponents(self):
print
@@ -151,7 +152,7 @@
and os.path.isdir(dir), os.listdir(os.curdir))
dirNames.sort()
self._maxCompLen = max(map(len, dirNames))
- oldPyVersion = 0
+ oldPyVersion = False
column = 0
for dirName in dirNames:
propName = dirName + '/Properties.py'
@@ -166,7 +167,7 @@
if key not in comp:
comp[key] = self._props[key]
if sys.version_info[:3] < comp['requiredPyVersion']:
- oldPyVersion += 1
+ oldPyVersion = True
print 'no*',
else:
self._comps.append(comp)
@@ -336,7 +337,7 @@
open(targetName, 'w').write(result)
def createPySummary(self, filename, dir):
- """Create a HTML module summary."""
+ """Create an HTML module summary."""
from DocSupport.PySummary import PySummary
module = os.path.splitext(os.path.basename(filename))[0]
targetName = '%s/%s.html' % (dir, module)
@@ -348,7 +349,7 @@
open(targetName, 'w').write(html)
def createPyDocs(self, filename, dir):
- """Create a HTML module documentation using pydoc."""
+ """Create an HTML module documentation using pydoc."""
import pydoc
package, module = os.path.split(filename)
module = os.path.splitext(module)[0]
@@ -375,7 +376,7 @@
self.printMsg(msg)
def createFileList(self, filesDir, docsDir):
- """Create a HTML list of the source files."""
+ """Create an HTML list of the source files."""
from DocSupport.FileList import FileList
name = filesDir.replace('/', '.')
self.printMsg('Creating file list of %s...' % name)
@@ -392,7 +393,7 @@
os.chdir(saveDir)
def createClassList(self, filesDir, docsDir):
- """Create a HTML class hierarchy listing of the source files."""
+ """Create an HTML class hierarchy listing of the source files."""
from DocSupport.ClassList import ClassList
name = filesDir.replace('/', '.')
self.printMsg('Creating class list of %s...' % name)
@@ -404,38 +405,38 @@
classlist.readFiles(subDir + '*.py')
targetName = docsDir + '/ClassList.html'
self.printMsg('Creating %s...' % targetName)
- classlist.printForWeb(0, '../' + targetName)
+ classlist.printForWeb(False, '../' + targetName)
targetName = docsDir + '/ClassHierarchy.html'
self.printMsg('Creating %s...' % targetName)
- classlist.printForWeb(1, '../' + targetName)
+ classlist.printForWeb(True, '../' + targetName)
finally:
os.chdir(saveDir)
def createComponentIndex(self):
- """Create a HTML component index of Webware itself."""
+ """Create an HTML component index of Webware itself."""
print 'Creating ComponentIndex.html...'
ht = ["<% header('Webware Documentation', 'titlebar',"
- " 'ComponentIndex.css') %>"]
+ " 'ComponentIndex.css') %>"]
wr = ht.append
wr('<p>Don\'t know where to start? '
- 'Try <a href="../WebKit/Docs/index.html">WebKit</a>.</p>')
+ 'Try <a href="../WebKit/Docs/index.html">WebKit</a>.</p>')
wr('<table align="center" border="0" '
- 'cellpadding="2" cellspacing="2" width="100%">')
+ 'cellpadding="2" cellspacing="2" width="100%">')
wr('<tr class="ComponentHeadings">'
- '<th>Component</th><th>Status</th><th>Ver</th>'
- '<th>Py</th><th>Summary</th></tr>')
+ '<th>Component</th><th>Status</th><th>Ver</th>'
+ '<th>Py</th><th>Summary</th></tr>')
row = 0
for comp in self._comps:
comp['nameAsLink'] = ('<a href='
- '"../%(dirname)s/Docs/index.html">%(name)s</a>' % comp)
+ '"../%(dirname)s/Docs/index.html">%(name)s</a>' % comp)
comp['indexRow'] = row + 1
wr('<tr valign="top" class="ComponentRow%(indexRow)i">'
- '<td class="NameVersionCell">'
- '<span class="Name">%(nameAsLink)s</span></td>'
- '<td>%(status)s</td>'
- '<td><span class="Version">%(versionString)s</span></td>'
- '<td>%(requiredPyVersionString)s</td>'
- '<td>%(synopsis)s</td></tr>' % comp)
+ '<td class="NameVersionCell">'
+ '<span class="Name">%(nameAsLink)s</span></td>'
+ '<td>%(status)s</td>'
+ '<td><span class="Version">%(versionString)s</span></td>'
+ '<td>%(requiredPyVersionString)s</td>'
+ '<td>%(synopsis)s</td></tr>' % comp)
row = 1 - row
wr('</table>')
wr("<% footer() %>")
@@ -455,7 +456,7 @@
for comp in self._comps:
comp['webwareVersion'] = self._props['version']
comp['webwareVersionString'] = self._props['versionString']
- # Create 'htDocs' as a HTML fragment corresponding to comp['docs']
+ # Create 'htDocs' as an HTML fragment corresponding to comp['docs']
ht = []
for doc in comp['docs']:
ht.append(link % (doc['file'], doc['name']))
@@ -470,7 +471,7 @@
item = {'dirname': os.path.basename(filename)}
filename = item['dirname']
ver = filename[
- filename.rfind('-') + 1 : filename.rfind('.')]
+ filename.rfind('-') + 1 : filename.rfind('.')]
item['name'] = ver
if ver == 'X.Y':
item['ver'] = ver.split('.')
@@ -508,12 +509,12 @@
docsDirs.append(docsDir)
for docsDir in docsDirs:
initFile = docsDir + '/__init__.py'
- if not os.path.exists(initFile) or 1:
+ if not os.path.exists(initFile):
open(initFile, 'w').write(
- '# this can be browsed as a Webware context\n')
+ '# this can be browsed as a Webware context\n')
# Copy favicon to the default context
open('WebKit/Examples/favicon.ico', 'wb').write(
- open('Docs/favicon.ico', 'rb').read())
+ open('Docs/favicon.ico', 'rb').read())
def backupConfigs(self):
"""Copy *.config to *.config.default, if they don't already exist.
@@ -563,14 +564,14 @@
t = 'WebKit/webkit'
open(t, 'wb').write(open(s, 'rb').read())
- def compileModules(self, force=0):
+ def compileModules(self, force=False):
"""Compile modules in all installed componentes."""
from compileall import compile_dir
print
print 'Byte compiling all modules...'
for comp in self._comps:
dir = comp['dirname']
- compile_dir(dir, force=force, quiet=1)
+ compile_dir(dir, force=force, quiet=True)
def fixPermissions(self):
if os.name == 'posix':
@@ -627,17 +628,17 @@
return template.split('\n<!-- page content -->\n', 1)
def processHtmlDocFile(self, htmlFile):
- """Process a HTML file."""
+ """Process an HTML file."""
txtFile = os.path.splitext(htmlFile)[0] + '.txt'
if os.path.exists(txtFile):
# A text file with the same name exists:
page = open(htmlFile).read()
- if page.find('<meta name="generator" content="Docutils') > 0 \
- and page.find('<h1 class="title">') > 0:
+ if ('<meta name="generator" content="Docutils' in page
+ and '<h1 class="title">' in page):
# This has obvisouly been created with Docutils; modify it
# to match style, header and footer of all the other docs.
page = page.replace('<h1 class="title">',
- '<h1 class="header">')
+ '<h1 class="header">')
page = page.replace('</body>\n</html>', self._htFooter)
self.printMsg('Modifying %s...' % htmlFile)
open(htmlFile, 'w').write(page)
@@ -701,28 +702,28 @@
if __name__ == '__main__':
import getopt
- verbose = 0
+ verbose = False
passprompt = defaultpass = keepdocs = None
try:
opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose",
- "no-password-prompt", "set-password=", "keep-templates"])
+ "no-password-prompt", "set-password=", "keep-templates"])
except getopt.GetoptError:
printHelp()
else:
for o, a in opts:
if o in ("-v", "--verbose"):
- verbose = 1
+ verbose = True
elif o == "--no-password-prompt":
- passprompt = 0
+ passprompt = False
elif o == "--set-password":
defaultpass = a
elif o == '--keep-templates':
- keepdocs = 1
+ keepdocs = True
elif o in ("-h", "--help", "h", "help"):
printHelp()
sys.exit(0)
if passprompt is None and defaultpass is None:
- passprompt = 1
+ passprompt = True
Installer().run(verbose=verbose, passprompt=passprompt,
defaultpass=defaultpass, keepdocs=keepdocs)
|