I started working with SQLObject like 2 weeks ago, went I started with
turbogears, since I was new some errors look really bad for me, and i
wasted some time checking them, and they end up behing stupid things
(like a typo). My 1st error in TG was a big stack trace just because I
put 'test', instead of 'text' in a FK call.
I don't think that 1 typo in the class should fail all the way down in the db.
So i decided to write this, it is a small function that checks if your model.py (in turbogears), or any other file that has classes that extend SQLObject will render a valid SQL structure, basically it parses the file with regexp, finds matches to references of classes, compares them and prints functions calls with errors, in a way that resembles python errors. And all this is necesary due to the work around of having strings as params to SQLObjects methods ('RelatedJoin','ForeignKey','MultipleJoin')
if you think this is good enough for SQLObject, then message me with some improvements and i'll fix them, or maybe someone can clean this up or just take the idea and do a rewrite.
I haven't test it extensible but i did with diferent file with at most 10 classes, with diferent errors, it even detects invalid identifiers in method class and i tested it on mysql (4.1.14), with TG 0.8a2 that comes with SQLObject 0.7.0
import re def process(filename=None): identifierPattern=r'([A-Za-z_]+[\w]*)' #a normal python identifier singleParameterPattern=r'\([\'"](.*)[\'"]\)' #a single string parametter enclosed in '' or "" classPattern=r'class[\W]+%s' % identifierPattern # class declarations functionNames=('RelatedJoin','ForeignKey','MultipleJoin' ) #SQLObject, functions to check functionPatterns=(re.compile(function+ singleParameterPattern) for function in functionNames) #re patters for all SQLObject functions #read the source (filename) f = file(filename,"rU") input = f.read() f.close() functionCalls= for pattern in functionPatterns: functionCalls.extend(re.findall(pattern,input ))#make one long list with all call to all SQLObject Funtions in the source classes=re.findall(classPattern,input) #get all class declarations on the soruce print classes list(set(functionCalls)) print functionCalls input=input.split( '\n')#split the source in lines, so we can tell the user the line number of the error output= for call in functionCalls: if call not in classes: for cont in range(len( input)):#sorry but i need the index number if call in input[cont]: output.append((cont+1,call)) if not output:# no errors found print "Ur code is bug free" return def sort(x,y): if x>y[ 0]: return 1 else: return -1 output.sort(cmp=sort) for error in output: print "Error, line %d, class %s not found" % error def main(): import sys process(sys.argv) if __name__ == '__main__': main()