1
2
3 """
4 This module can be used to generate python source code. It has an interface
5 similar to the "new" module.
6
7 """
8
9 import sys, os
10 import string
11
12 BANGLINE = "#!/usr/bin/env python\n"
13
15 return string.join(map(str, tup), ", ")
16
17
18
19
20
21 -def genClass(klassname, parents, attribs=None, doc=None, methods=None):
22 """genClass(name, parents, [attribs, [doc, [methods]]])
23 Return a string of Python source code defineing a class object.
24 Where:
25 name = class name (string)
26 parents = tuple of parent class objects or strings.
27 attribs = class-global attributes to define, contained in a dictionary.
28 doc = a doc string (optional)
29 methods = list of methods strings.
30 """
31 s = []
32 if parents:
33 s.append( "class %s(%s):" % (klassname, _tuplestr(parents)) )
34 else:
35 s.append( "class %s:" % (klassname) )
36 if doc:
37 s.append('\t"""%s"""' % doc)
38 if attribs:
39 for key, val in attribs.items():
40 s.append( "\t%s = %r" % (key, val) )
41 if methods is not None:
42 s.extend(map(str, list(methods)))
43 if len(s) == 1:
44 s.append("\tpass")
45 s.append("\n")
46 return string.join(s, "\n")
47
48 -def genFunc(funcname, params, body=None, globals=None, doc=None):
61
62 -def genMethod(funcname, params, body=None, globals=None, doc=None):
63 s = []
64 s.append( "def %s(self, %s):" % (funcname, _tuplestr(params)) )
65 if doc:
66 s.append('\t"""%s"""' % doc)
67 if globals is not None:
68 s.append("\tglobal %s" % _tuplestr(globals))
69 if body is None:
70 s.append("\tpass")
71 elif type(body) is str:
72 s.extend( map(lambda l: "\t%s"%l, string.split(body, "\n")) )
73 elif type(body) is list or type(body) is tuple:
74 s.extend( map(lambda l: "\t%s"%l, body) )
75 else:
76 raise TypeError, "invalid type for body text"
77 s.append("\n")
78
79 return string.join(map(lambda l: "\t%s"%l, s), "\n")
80
85
87 if type(module) is type(sys):
88 module = module.__name__
89 if obj:
90 if type(obj) is tuple or type(obj) is list:
91 obj = _tuplestr(obj)
92 return "%sfrom %s import %s\n" % ("\t"*indent, module, obj)
93 else:
94 return "%simport %s\n" % ("\t"*indent, module)
95
96
97
99 """SourceGen(outfile, [bangline])
100 An instance of this SourceGen class is a factory for generating python
101 source code, by writing to a file object.
102
103 """
104 - def __init__(self, outfile, bangline=None):
105 self.outfile = outfile
106 bangline = bangline or BANGLINE
107 self.outfile.write(bangline)
108
109 - def genClass(self, klassname, parents=None, attribs=None, doc=None, methods=None):
111
112 - def genFunc(self, funcname, params, attribs=None, doc=None):
113 self.outfile.write( genFunc(funcname, params, attribs, doc) )
114
115 - def genMethod(self, funcname, params, body=None, globals=None, doc=None):
116 self.outfile.write( genMethod(funcname, params, body, globals, doc) )
117
120
123
125 self.outfile.write("\n")
126
129
133
134
135
136
138 if type(outfile) is str:
139 outfile = open(outfile, "w")
140 return SourceGen(outfile)
141
142
144 if type(outfile) is str:
145 outfile = open(outfile, "w")
146 return SourceFile(outfile, bangline)
147
148
149
165
166
168 - def __init__(self, funcname, params=None, body=None, globals=None, doc=None):
169 self.name = funcname
170 self.params = params or ()
171 self.body = body
172 self.globals = globals
173 self.doc = doc
174
176 return genMethod(self.name, self.params, self.body, self.globals, self.doc)
177
178
180 - def __init__(self, klassname, parents=None, attributes=None, doc=None, methods=None):
188
189 - def add_method(self, funcname, params, body=None, globals=None, doc=None):
190 mh = MethodHolder(funcname, params, body, globals, doc)
191 self.methods.append(mh)
192 return mh
193
196 set_attribute = add_attribute
201
202
203
205 - def __init__(self, fo=None, bangline=None):
206 print "Writing to", fo
207 self.fo = fo
208 self.elements = []
209 self.docstring = None
210 self.bangline = bangline or BANGLINE
212 s = [self.bangline]
213 if self.docstring:
214 s.append('"""\n%s\n"""\n\n' % (self.docstring))
215 s.extend(map(str, self.elements))
216 return "\n".join(s)
217
219 self.docstring = docstring
226
227 - def add_function(self, funcname, params, attribs=None, doc=None):
231
232 - def add_class(self, klassname, parents, attributes=None, doc=None, methods=None):
236
239
240 - def write(self, fo=None):
241 fo = fo or self.fo
242 fo.write(str(self))
244 filename = filename or self.filename
245 if filename:
246 fo = open(filename, "w")
247 self.write(fo)
248 else:
249 raise ValueError, "SourceFile: no filename given to write to!"
250
251
252
253 if __name__ == "__main__":
256 print "generated classes"
257 print "-----------------"
258 print genComment(__doc__)
259 print genClass("test1", (), {})
260 print genClass("test2", ("sub1",), {})
261 print genClass("test3", ("sub1","sub2"), {})
262 print genClass("test4", (SUBCLASS,), {})
263 print genClass("test5", (), {"attr1": 1})
264 print genClass("test6", (), {}, "One docstring")
265 print genClass("test7", (), {"attr1": 1}, "another docstring")
266
267 print "Holder classes"
268 print "--------------"
269 print genImport(sys.modules[__name__])
270 print genImport(sys)
271 print genImport(sys, "open")
272 ch = ClassHolder("holdclass", ("sub1",))
273 print ch
274 print "--------------"
275 ch.add_method("holdmethod1", ("param1",))
276 print ch
277 print "--------------"
278 ch.add_method("holdmethod2", ("hm2p1",), "print 'body code'", doc="Some docstring")
279 print ch
280 print "--------------"
281 ch.doc = "Documentation for holdclass."
282 print ch
283 print "--------------"
284 sf = SourceFile()
285 sf.add_doc("Testing the generator.")
286 sf.add_import(sys)
287 sf.append(ch)
288 sf.write(sys.stdout)
289