1 2"""A bunch of utility functions for the PSP generator. 3 4(c) Copyright by Jay Love, 2000 (mailto:jsliv@jslove.org) 5 6Permission to use, copy, modify, and distribute this software and its 7documentation for any purpose and without fee or royalty is hereby granted, 8provided that the above copyright notice appear in all copies and that 9both that copyright notice and this permission notice appear in 10supporting documentation or portions thereof, including modifications, 11that you make. 12 13This software is based in part on work done by the Jakarta group. 14""" 15 16# PSP Error classes 17 18class PSPParserException(Exception): 19 """PSP parser error.""" 20 21 22# Various utility functions 23 24def removeQuotes(s): 25 return s.replace(r'%\\>', '%>') 26 27 28def isExpression(s): 29 """Check whether this is a PSP expression.""" 30 return s.startswith('<%=') and s.endswith('%>') 31 32 33def getExpr(s): 34 """Get the content of a PSP expression.""" 35 if s.startswith('<%=') and s.endswith('%>'): 36 return s[3:-2] 37 else: 38 return '' 39 40 41def checkAttributes(tagType, attrs, validAttrs): 42 """Check for mandatory and optional atributes.""" 43 attrs = set(attrs) 44 mandatoryAttrs = validAttrs[0] 45 for attr in mandatoryAttrs: # mandatory 46 try: 47 attrs.remove(attr) 48 except KeyError: 49 raise PSPParserException('%s: Mandatory attribute %s missing' 50 % (tagType, attr)) 51 optionalAttrs = validAttrs[1] 52 for attr in attrs: 53 if attr not in optionalAttrs: 54 raise PSPParserException('%s: Invalid attribute %s' 55 % (tagType, attr)) 56 57 58def splitLines(text, keepends=False): 59 """Split text into lines.""" 60 return text.splitlines(keepends) 61 62 63def startsNewBlock(line): 64 """Determine whether a code line starts a new block. 65 66 Added by Christoph Zwerschke. 67 """ 68 line = line.strip() 69 if line.startswith('#'): 70 return False 71 try: 72 compile(line, '<string>', 'exec') 73 except SyntaxError: 74 try: 75 compile(line + '\n pass', '<string>', 'exec') 76 except Exception: 77 pass 78 else: 79 return True 80 else: 81 return False 82 return line.endswith(':') 83 84 85def normalizeIndentation(pySource): 86 """Take a code block that may be too indented, and move it all to the left. 87 88 See PSPUtilsTest for examples. 89 90 First written by Winston Wolff; improved version by Christoph Zwerschke. 91 """ 92 lines = splitLines(pySource, True) 93 minIndent = None 94 indents = [] 95 for line in lines: 96 strippedLine = line.lstrip(' \t') 97 indent = len(line) - len(strippedLine) 98 indents.append(len(line) - len(strippedLine)) 99 if strippedLine.lstrip('\r\n') and not strippedLine.startswith('#'): 100 if minIndent is None or indent < minIndent: 101 minIndent = indent 102 if not minIndent: 103 break 104 if minIndent: 105 pySource = ''.join([line[min(minIndent, indent):] 106 for line, indent in zip(lines, indents)]) 107 return pySource 108