Add usage type/id as a public API property of virSecret
[libvirt-python/ericb.git] / generator.py
blobad9c54423b3a6b2958eea57dfc33f539869c8601
1 #!/usr/bin/python -u
3 # generate python wrappers from the XML API description
6 functions = {}
7 enums = {} # { enumType: { enumConstant: enumValue } }
9 import os
10 import sys
11 import string
12 import re
14 if __name__ == "__main__":
15 # launched as a script
16 srcPref = os.path.dirname(sys.argv[0])
17 else:
18 # imported
19 srcPref = os.path.dirname(__file__)
21 #######################################################################
23 # That part if purely the API acquisition phase from the
24 # libvirt API description
26 #######################################################################
27 import os
28 import xmllib
29 try:
30 import sgmlop
31 except ImportError:
32 sgmlop = None # accelerator not available
34 debug = 0
36 if sgmlop:
37 class FastParser:
38 """sgmlop based XML parser. this is typically 15x faster
39 than SlowParser..."""
41 def __init__(self, target):
43 # setup callbacks
44 self.finish_starttag = target.start
45 self.finish_endtag = target.end
46 self.handle_data = target.data
48 # activate parser
49 self.parser = sgmlop.XMLParser()
50 self.parser.register(self)
51 self.feed = self.parser.feed
52 self.entity = {
53 "amp": "&", "gt": ">", "lt": "<",
54 "apos": "'", "quot": '"'
57 def close(self):
58 try:
59 self.parser.close()
60 finally:
61 self.parser = self.feed = None # nuke circular reference
63 def handle_entityref(self, entity):
64 # <string> entity
65 try:
66 self.handle_data(self.entity[entity])
67 except KeyError:
68 self.handle_data("&%s;" % entity)
70 else:
71 FastParser = None
74 class SlowParser(xmllib.XMLParser):
75 """slow but safe standard parser, based on the XML parser in
76 Python's standard library."""
78 def __init__(self, target):
79 self.unknown_starttag = target.start
80 self.handle_data = target.data
81 self.unknown_endtag = target.end
82 xmllib.XMLParser.__init__(self)
84 def getparser(target = None):
85 # get the fastest available parser, and attach it to an
86 # unmarshalling object. return both objects.
87 if target is None:
88 target = docParser()
89 if FastParser:
90 return FastParser(target), target
91 return SlowParser(target), target
93 class docParser:
94 def __init__(self):
95 self._methodname = None
96 self._data = []
97 self.in_function = 0
99 def close(self):
100 if debug:
101 print "close"
103 def getmethodname(self):
104 return self._methodname
106 def data(self, text):
107 if debug:
108 print "data %s" % text
109 self._data.append(text)
111 def start(self, tag, attrs):
112 if debug:
113 print "start %s, %s" % (tag, attrs)
114 if tag == 'function':
115 self._data = []
116 self.in_function = 1
117 self.function = None
118 self.function_cond = None
119 self.function_args = []
120 self.function_descr = None
121 self.function_return = None
122 self.function_file = None
123 if attrs.has_key('name'):
124 self.function = attrs['name']
125 if attrs.has_key('file'):
126 self.function_file = attrs['file']
127 elif tag == 'cond':
128 self._data = []
129 elif tag == 'info':
130 self._data = []
131 elif tag == 'arg':
132 if self.in_function == 1:
133 self.function_arg_name = None
134 self.function_arg_type = None
135 self.function_arg_info = None
136 if attrs.has_key('name'):
137 self.function_arg_name = attrs['name']
138 if self.function_arg_name == 'from':
139 self.function_arg_name = 'frm'
140 if attrs.has_key('type'):
141 self.function_arg_type = attrs['type']
142 if attrs.has_key('info'):
143 self.function_arg_info = attrs['info']
144 elif tag == 'return':
145 if self.in_function == 1:
146 self.function_return_type = None
147 self.function_return_info = None
148 self.function_return_field = None
149 if attrs.has_key('type'):
150 self.function_return_type = attrs['type']
151 if attrs.has_key('info'):
152 self.function_return_info = attrs['info']
153 if attrs.has_key('field'):
154 self.function_return_field = attrs['field']
155 elif tag == 'enum':
156 enum(attrs['type'],attrs['name'],attrs['value'])
158 def end(self, tag):
159 if debug:
160 print "end %s" % tag
161 if tag == 'function':
162 if self.function != None:
163 function(self.function, self.function_descr,
164 self.function_return, self.function_args,
165 self.function_file, self.function_cond)
166 self.in_function = 0
167 elif tag == 'arg':
168 if self.in_function == 1:
169 self.function_args.append([self.function_arg_name,
170 self.function_arg_type,
171 self.function_arg_info])
172 elif tag == 'return':
173 if self.in_function == 1:
174 self.function_return = [self.function_return_type,
175 self.function_return_info,
176 self.function_return_field]
177 elif tag == 'info':
178 str = ''
179 for c in self._data:
180 str = str + c
181 if self.in_function == 1:
182 self.function_descr = str
183 elif tag == 'cond':
184 str = ''
185 for c in self._data:
186 str = str + c
187 if self.in_function == 1:
188 self.function_cond = str
191 def function(name, desc, ret, args, file, cond):
192 functions[name] = (desc, ret, args, file, cond)
194 def enum(type, name, value):
195 if not enums.has_key(type):
196 enums[type] = {}
197 enums[type][name] = value
199 #######################################################################
201 # Some filtering rukes to drop functions/types which should not
202 # be exposed as-is on the Python interface
204 #######################################################################
206 functions_failed = []
207 functions_skipped = [
208 "virConnectListDomains"
211 skipped_modules = {
214 skipped_types = {
215 # 'int *': "usually a return type",
216 'virConnectDomainEventCallback': "No function types in python",
217 'virEventAddHandleFunc': "No function types in python",
220 #######################################################################
222 # Table of remapping to/from the python type or class to the C
223 # counterpart.
225 #######################################################################
227 py_types = {
228 'void': (None, None, None, None),
229 'int': ('i', None, "int", "int"),
230 'long': ('l', None, "long", "long"),
231 'double': ('d', None, "double", "double"),
232 'unsigned int': ('i', None, "int", "int"),
233 'unsigned long': ('l', None, "long", "long"),
234 'unsigned long long': ('l', None, "longlong", "long long"),
235 'unsigned char *': ('z', None, "charPtr", "char *"),
236 'char *': ('z', None, "charPtr", "char *"),
237 'const char *': ('z', None, "charPtrConst", "const char *"),
239 'virDomainPtr': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
240 'const virDomainPtr': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
241 'virDomain *': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
242 'const virDomain *': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
244 'virNetworkPtr': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
245 'const virNetworkPtr': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
246 'virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
247 'const virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
249 'virInterfacePtr': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
250 'const virInterfacePtr': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
251 'virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
252 'const virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
254 'virStoragePoolPtr': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
255 'const virStoragePoolPtr': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
256 'virStoragePool *': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
257 'const virStoragePool *': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
259 'virStorageVolPtr': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
260 'const virStorageVolPtr': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
261 'virStorageVol *': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
262 'const virStorageVol *': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
264 'virConnectPtr': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
265 'const virConnectPtr': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
266 'virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
267 'const virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
269 'virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
270 'const virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
271 'virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
272 'const virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
274 'virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
275 'const virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
276 'virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
277 'const virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
280 py_return_types = {
283 unknown_types = {}
285 foreign_encoding_args = (
288 #######################################################################
290 # This part writes the C <-> Python stubs libvirt2-py.[ch] and
291 # the table libxml2-export.c to add when registrering the Python module
293 #######################################################################
295 # Class methods which are written by hand in libvir.c but the Python-level
296 # code is still automatically generated (so they are not in skip_function()).
297 skip_impl = (
298 'virConnectListDomainsID',
299 'virConnectListDefinedDomains',
300 'virConnectListNetworks',
301 'virConnectListDefinedNetworks',
302 'virConnectListInterfaces',
303 'virConnectListDefinedInterfaces',
304 'virConnectListSecrets',
305 'virConnectListStoragePools',
306 'virConnectListDefinedStoragePools',
307 'virConnectListStorageVols',
308 'virConnectListDefinedStorageVols',
309 'virConnGetLastError',
310 'virGetLastError',
311 'virDomainGetInfo',
312 'virNodeGetInfo',
313 'virDomainGetUUID',
314 'virDomainGetUUIDString',
315 'virDomainLookupByUUID',
316 'virNetworkGetUUID',
317 'virNetworkGetUUIDString',
318 'virNetworkLookupByUUID',
319 'virDomainGetAutostart',
320 'virNetworkGetAutostart',
321 'virDomainBlockStats',
322 'virDomainInterfaceStats',
323 'virNodeGetCellsFreeMemory',
324 'virDomainGetSchedulerType',
325 'virDomainGetSchedulerParameters',
326 'virDomainSetSchedulerParameters',
327 'virDomainGetVcpus',
328 'virDomainPinVcpu',
329 'virSecretGetValue',
330 'virSecretSetValue',
331 'virSecretGetUUID',
332 'virSecretGetUUIDString',
333 'virSecretLookupByUUID',
334 'virStoragePoolGetUUID',
335 'virStoragePoolGetUUIDString',
336 'virStoragePoolLookupByUUID',
337 'virStoragePoolGetInfo',
338 'virStorageVolGetInfo',
339 'virStoragePoolGetAutostart',
340 'virStoragePoolListVolumes',
341 'virDomainBlockPeek',
342 'virDomainMemoryPeek',
343 'virEventRegisterImpl',
344 'virNodeListDevices',
345 'virNodeDeviceListCaps',
349 # These are functions which the generator skips completly - no python
350 # or C code is generated. Generally should not be used for any more
351 # functions than those already listed
352 skip_function = (
353 'virConnectListDomains', # Python API is called virConectListDomainsID for unknown reasons
354 'virConnSetErrorFunc', # Not used in Python API XXX is this a bug ?
355 'virResetError', # Not used in Python API XXX is this a bug ?
356 'virConnectGetVersion', # Not used in Python API XXX is this a bug ?
357 'virGetVersion', # Python C code is manually written
358 'virSetErrorFunc', # Python API is called virRegisterErrorHandler for unknown reasons
359 'virConnCopyLastError', # Python API is called virConnGetLastError instead
360 'virCopyLastError', # Python API is called virGetLastError instead
361 'virConnectOpenAuth', # Python C code is manually written
362 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C
363 'virDomainGetSecurityLabel', # Needs investigation...
364 'virNodeGetSecurityModel', # Needs investigation...
365 'virConnectDomainEventRegister', # overridden in virConnect.py
366 'virConnectDomainEventDeregister', # overridden in virConnect.py
367 'virSaveLastError', # We have our own python error wrapper
368 'virFreeError', # Only needed if we use virSaveLastError
372 def print_function_wrapper(name, output, export, include):
373 global py_types
374 global unknown_types
375 global functions
376 global skipped_modules
378 try:
379 (desc, ret, args, file, cond) = functions[name]
380 except:
381 print "failed to get function %s infos"
382 return
384 if skipped_modules.has_key(file):
385 return 0
386 if name in skip_function:
387 return 0
388 if name in skip_impl:
389 # Don't delete the function entry in the caller.
390 return 1
392 c_call = "";
393 format=""
394 format_args=""
395 c_args=""
396 c_return=""
397 c_convert=""
398 num_bufs=0
399 for arg in args:
400 # This should be correct
401 if arg[1][0:6] == "const ":
402 arg[1] = arg[1][6:]
403 c_args = c_args + " %s %s;\n" % (arg[1], arg[0])
404 if py_types.has_key(arg[1]):
405 (f, t, n, c) = py_types[arg[1]]
406 if (f == 'z') and (name in foreign_encoding_args) and (num_bufs == 0):
407 f = 't#'
408 if f != None:
409 format = format + f
410 if t != None:
411 format_args = format_args + ", &pyobj_%s" % (arg[0])
412 c_args = c_args + " PyObject *pyobj_%s;\n" % (arg[0])
413 c_convert = c_convert + \
414 " %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
415 arg[1], t, arg[0]);
416 else:
417 format_args = format_args + ", &%s" % (arg[0])
418 if f == 't#':
419 format_args = format_args + ", &py_buffsize%d" % num_bufs
420 c_args = c_args + " int py_buffsize%d;\n" % num_bufs
421 num_bufs = num_bufs + 1
422 if c_call != "":
423 c_call = c_call + ", ";
424 c_call = c_call + "%s" % (arg[0])
425 else:
426 if skipped_types.has_key(arg[1]):
427 return 0
428 if unknown_types.has_key(arg[1]):
429 lst = unknown_types[arg[1]]
430 lst.append(name)
431 else:
432 unknown_types[arg[1]] = [name]
433 return -1
434 if format != "":
435 format = format + ":%s" % (name)
437 if ret[0] == 'void':
438 if file == "python_accessor":
439 if args[1][1] == "char *":
440 c_call = "\n free(%s->%s);\n" % (
441 args[0][0], args[1][0], args[0][0], args[1][0])
442 c_call = c_call + " %s->%s = (%s)strdup((const xmlChar *)%s);\n" % (args[0][0],
443 args[1][0], args[1][1], args[1][0])
444 else:
445 c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0],
446 args[1][0])
447 else:
448 c_call = "\n %s(%s);\n" % (name, c_call);
449 ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n"
450 elif py_types.has_key(ret[0]):
451 (f, t, n, c) = py_types[ret[0]]
452 c_return = " %s c_retval;\n" % (ret[0])
453 if file == "python_accessor" and ret[2] != None:
454 c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2])
455 else:
456 c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
457 ret_convert = " py_retval = libvirt_%sWrap((%s) c_retval);\n" % (n,c)
458 ret_convert = ret_convert + " return(py_retval);\n"
459 elif py_return_types.has_key(ret[0]):
460 (f, t, n, c) = py_return_types[ret[0]]
461 c_return = " %s c_retval;\n" % (ret[0])
462 c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
463 ret_convert = " py_retval = libvirt_%sWrap((%s) c_retval);\n" % (n,c)
464 ret_convert = ret_convert + " return(py_retval);\n"
465 else:
466 if skipped_types.has_key(ret[0]):
467 return 0
468 if unknown_types.has_key(ret[0]):
469 lst = unknown_types[ret[0]]
470 lst.append(name)
471 else:
472 unknown_types[ret[0]] = [name]
473 return -1
475 if cond != None and cond != "":
476 include.write("#if %s\n" % cond)
477 export.write("#if %s\n" % cond)
478 output.write("#if %s\n" % cond)
480 include.write("PyObject * ")
481 include.write("libvirt_%s(PyObject *self, PyObject *args);\n" % (name));
483 export.write(" { (char *)\"%s\", libvirt_%s, METH_VARARGS, NULL },\n" %
484 (name, name))
486 if file == "python":
487 # Those have been manually generated
488 if cond != None and cond != "":
489 include.write("#endif\n");
490 export.write("#endif\n");
491 output.write("#endif\n");
492 return 1
493 if file == "python_accessor" and ret[0] != "void" and ret[2] is None:
494 # Those have been manually generated
495 if cond != None and cond != "":
496 include.write("#endif\n");
497 export.write("#endif\n");
498 output.write("#endif\n");
499 return 1
501 output.write("PyObject *\n")
502 output.write("libvirt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
503 output.write(" PyObject *args")
504 if format == "":
505 output.write(" ATTRIBUTE_UNUSED")
506 output.write(") {\n")
507 if ret[0] != 'void':
508 output.write(" PyObject *py_retval;\n")
509 if c_return != "":
510 output.write(c_return)
511 if c_args != "":
512 output.write(c_args)
513 if format != "":
514 output.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
515 (format, format_args))
516 output.write(" return(NULL);\n")
517 if c_convert != "":
518 output.write(c_convert)
520 output.write("LIBVIRT_BEGIN_ALLOW_THREADS;\n");
521 output.write(c_call);
522 output.write("LIBVIRT_END_ALLOW_THREADS;\n");
523 output.write(ret_convert)
524 output.write("}\n\n")
525 if cond != None and cond != "":
526 include.write("#endif /* %s */\n" % cond)
527 export.write("#endif /* %s */\n" % cond)
528 output.write("#endif /* %s */\n" % cond)
529 return 1
531 def buildStubs():
532 global py_types
533 global py_return_types
534 global unknown_types
536 try:
537 f = open(os.path.join(srcPref,"libvirt-api.xml"))
538 data = f.read()
539 (parser, target) = getparser()
540 parser.feed(data)
541 parser.close()
542 except IOError, msg:
543 try:
544 f = open(os.path.join(srcPref,"..","docs","libvirt-api.xml"))
545 data = f.read()
546 (parser, target) = getparser()
547 parser.feed(data)
548 parser.close()
549 except IOError, msg:
550 print file, ":", msg
551 sys.exit(1)
553 n = len(functions.keys())
554 print "Found %d functions in libvirt-api.xml" % (n)
556 py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
557 try:
558 f = open(os.path.join(srcPref,"libvirt-python-api.xml"))
559 data = f.read()
560 (parser, target) = getparser()
561 parser.feed(data)
562 parser.close()
563 except IOError, msg:
564 print file, ":", msg
567 print "Found %d functions in libvirt-python-api.xml" % (
568 len(functions.keys()) - n)
569 nb_wrap = 0
570 failed = 0
571 skipped = 0
573 include = open("libvirt-py.h", "w")
574 include.write("/* Generated */\n\n")
575 export = open("libvirt-export.c", "w")
576 export.write("/* Generated */\n\n")
577 wrapper = open("libvirt-py.c", "w")
578 wrapper.write("/* Generated */\n\n")
579 wrapper.write("#include <Python.h>\n")
580 wrapper.write("#include <libvirt/libvirt.h>\n")
581 wrapper.write("#include \"libvirt_wrap.h\"\n")
582 wrapper.write("#include \"libvirt-py.h\"\n\n")
583 for function in functions.keys():
584 ret = print_function_wrapper(function, wrapper, export, include)
585 if ret < 0:
586 failed = failed + 1
587 functions_failed.append(function)
588 del functions[function]
589 if ret == 0:
590 skipped = skipped + 1
591 functions_skipped.append(function)
592 del functions[function]
593 if ret == 1:
594 nb_wrap = nb_wrap + 1
595 include.close()
596 export.close()
597 wrapper.close()
599 print "Generated %d wrapper functions" % nb_wrap
601 print "Missing type converters: "
602 for type in unknown_types.keys():
603 print "%s:%d " % (type, len(unknown_types[type])),
604 print
606 for f in functions_failed:
607 print "ERROR: failed %s" % f
609 if failed > 0:
610 return -1
611 return 0
613 #######################################################################
615 # This part writes part of the Python front-end classes based on
616 # mapping rules between types and classes and also based on function
617 # renaming to get consistent function names at the Python level
619 #######################################################################
622 # The type automatically remapped to generated classes
624 classes_type = {
625 "virDomainPtr": ("._o", "virDomain(self,_obj=%s)", "virDomain"),
626 "virDomain *": ("._o", "virDomain(self, _obj=%s)", "virDomain"),
627 "virNetworkPtr": ("._o", "virNetwork(self, _obj=%s)", "virNetwork"),
628 "virNetwork *": ("._o", "virNetwork(self, _obj=%s)", "virNetwork"),
629 "virInterfacePtr": ("._o", "virInterface(self, _obj=%s)", "virInterface"),
630 "virInterface *": ("._o", "virInterface(self, _obj=%s)", "virInterface"),
631 "virStoragePoolPtr": ("._o", "virStoragePool(self, _obj=%s)", "virStoragePool"),
632 "virStoragePool *": ("._o", "virStoragePool(self, _obj=%s)", "virStoragePool"),
633 "virStorageVolPtr": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"),
634 "virStorageVol *": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"),
635 "virNodeDevicePtr": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"),
636 "virNodeDevice *": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"),
637 "virSecretPtr": ("._o", "virSecret(self, _obj=%s)", "virSecret"),
638 "virSecret *": ("._o", "virSecret(self, _obj=%s)", "virSecret"),
639 "virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"),
640 "virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"),
643 converter_type = {
646 primary_classes = ["virDomain", "virNetwork", "virInterface",
647 "virStoragePool", "virStorageVol",
648 "virConnect", "virNodeDevice", "virSecret" ]
650 classes_ancestor = {
652 classes_destructors = {
653 "virDomain": "virDomainFree",
654 "virNetwork": "virNetworkFree",
655 "virInterface": "virInterfaceFree",
656 "virStoragePool": "virStoragePoolFree",
657 "virStorageVol": "virStorageVolFree",
658 "virNodeDevice" : "virNodeDeviceFree",
659 "virSecret": "virSecretFree"
662 functions_noexcept = {
663 'virDomainGetID': True,
664 'virDomainGetName': True,
665 'virNetworkGetName': True,
666 'virInterfaceGetName': True,
667 'virStoragePoolGetName': True,
668 'virStorageVolGetName': True,
669 'virStorageVolGetkey': True,
670 'virNodeDeviceGetName': True,
671 'virNodeDeviceGetParent': True,
672 'virSecretGetUsageType': True,
673 'virSecretGetUsageID': True,
676 reference_keepers = {
679 function_classes = {}
681 function_classes["None"] = []
683 function_post = {}
685 # Functions returning an integral type which need special rules to
686 # check for errors and raise exceptions.
687 functions_int_exception_test = {
688 'virDomainGetMaxMemory': "%s == 0",
690 functions_int_default_test = "%s == -1"
692 def is_integral_type (name):
693 return not re.search ("^(unsigned)? ?(int|long)$", name) is None
695 # Functions returning lists which need special rules to check for errors
696 # and raise exceptions.
697 functions_list_exception_test = {
699 functions_list_default_test = "%s is None"
701 def is_list_type (name):
702 whitelist = [ "virDomainBlockStats",
703 "virDomainInterfaceStats" ]
705 return name[-1:] == "*" or name in whitelist
707 def nameFixup(name, classe, type, file):
708 # avoid a desastrous clash
709 listname = classe + "List"
710 ll = len(listname)
711 l = len(classe)
712 if name[0:l] == listname:
713 func = name[l:]
714 func = string.lower(func[0:1]) + func[1:]
715 elif name[0:16] == "virNetworkDefine":
716 func = name[3:]
717 func = string.lower(func[0:1]) + func[1:]
718 elif name[0:19] == "virNetworkCreateXML":
719 func = name[3:]
720 func = string.lower(func[0:1]) + func[1:]
721 elif name[0:16] == "virNetworkLookup":
722 func = name[3:]
723 func = string.lower(func[0:1]) + func[1:]
724 elif name[0:18] == "virInterfaceDefine":
725 func = name[3:]
726 func = string.lower(func[0:1]) + func[1:]
727 elif name[0:21] == "virInterfaceCreateXML":
728 func = name[3:]
729 func = string.lower(func[0:1]) + func[1:]
730 elif name[0:18] == "virInterfaceLookup":
731 func = name[3:]
732 func = string.lower(func[0:1]) + func[1:]
733 elif name[0:15] == "virSecretDefine":
734 func = name[3:]
735 func = string.lower(func[0:1]) + func[1:]
736 elif name[0:15] == "virSecretLookup":
737 func = name[3:]
738 func = string.lower(func[0:1]) + func[1:]
739 elif name[0:20] == "virStoragePoolDefine":
740 func = name[3:]
741 func = string.lower(func[0:1]) + func[1:]
742 elif name[0:23] == "virStoragePoolCreateXML":
743 func = name[3:]
744 func = string.lower(func[0:1]) + func[1:]
745 elif name[0:20] == "virStoragePoolLookup":
746 func = name[3:]
747 func = string.lower(func[0:1]) + func[1:]
748 elif name[0:19] == "virStorageVolDefine":
749 func = name[3:]
750 func = string.lower(func[0:1]) + func[1:]
751 elif name[0:19] == "virStorageVolLookup":
752 func = name[3:]
753 func = string.lower(func[0:1]) + func[1:]
754 elif name[0:12] == "virDomainGet":
755 func = name[12:]
756 func = string.lower(func[0:1]) + func[1:]
757 elif name[0:9] == "virDomain":
758 func = name[9:]
759 func = string.lower(func[0:1]) + func[1:]
760 elif name[0:13] == "virNetworkGet":
761 func = name[13:]
762 func = string.lower(func[0:1]) + func[1:]
763 elif name[0:10] == "virNetwork":
764 func = name[10:]
765 func = string.lower(func[0:1]) + func[1:]
766 elif name[0:15] == "virInterfaceGet":
767 func = name[13:]
768 func = string.lower(func[0:1]) + func[1:]
769 elif name[0:12] == "virInterface":
770 func = name[10:]
771 func = string.lower(func[0:1]) + func[1:]
772 elif name[0:12] == 'virSecretGet':
773 func = name[12:]
774 func = string.lower(func[0:1]) + func[1:]
775 elif name[0:9] == 'virSecret':
776 func = name[9:]
777 func = string.lower(func[0:1]) + func[1:]
778 elif name[0:17] == "virStoragePoolGet":
779 func = name[17:]
780 func = string.lower(func[0:1]) + func[1:]
781 elif name[0:14] == "virStoragePool":
782 func = name[14:]
783 func = string.lower(func[0:1]) + func[1:]
784 elif name[0:16] == "virStorageVolGet":
785 func = name[16:]
786 func = string.lower(func[0:1]) + func[1:]
787 elif name[0:13] == "virStorageVol":
788 func = name[13:]
789 func = string.lower(func[0:1]) + func[1:]
790 elif name[0:13] == "virNodeDevice":
791 if name[13:16] == "Get":
792 func = string.lower(name[16]) + name[17:]
793 elif name[13:19] == "Lookup" or name[13:] == "Create":
794 func = string.lower(name[3]) + name[4:]
795 else:
796 func = string.lower(name[13]) + name[14:]
797 elif name[0:7] == "virNode":
798 func = name[7:]
799 func = string.lower(func[0:1]) + func[1:]
800 elif name[0:10] == "virConnect":
801 func = name[10:]
802 func = string.lower(func[0:1]) + func[1:]
803 elif name[0:3] == "xml":
804 func = name[3:]
805 func = string.lower(func[0:1]) + func[1:]
806 else:
807 func = name
808 if func == "iD":
809 func = "ID"
810 if func == "uUID":
811 func = "UUID"
812 if func == "uUIDString":
813 func = "UUIDString"
814 if func == "oSType":
815 func = "OSType"
816 if func == "xMLDesc":
817 func = "XMLDesc"
818 return func
821 def functionCompare(info1, info2):
822 (index1, func1, name1, ret1, args1, file1) = info1
823 (index2, func2, name2, ret2, args2, file2) = info2
824 if file1 == file2:
825 if func1 < func2:
826 return -1
827 if func1 > func2:
828 return 1
829 if file1 == "python_accessor":
830 return -1
831 if file2 == "python_accessor":
832 return 1
833 if file1 < file2:
834 return -1
835 if file1 > file2:
836 return 1
837 return 0
839 def writeDoc(name, args, indent, output):
840 if functions[name][0] is None or functions[name][0] == "":
841 return
842 val = functions[name][0]
843 val = string.replace(val, "NULL", "None");
844 output.write(indent)
845 output.write('"""')
846 while len(val) > 60:
847 if val[0] == " ":
848 val = val[1:]
849 continue
850 str = val[0:60]
851 i = string.rfind(str, " ");
852 if i < 0:
853 i = 60
854 str = val[0:i]
855 val = val[i:]
856 output.write(str)
857 output.write('\n ');
858 output.write(indent)
859 output.write(val);
860 output.write(' """\n')
862 def buildWrappers():
863 global ctypes
864 global py_types
865 global py_return_types
866 global unknown_types
867 global functions
868 global function_classes
869 global classes_type
870 global classes_list
871 global converter_type
872 global primary_classes
873 global converter_type
874 global classes_ancestor
875 global converter_type
876 global primary_classes
877 global classes_ancestor
878 global classes_destructors
879 global functions_noexcept
881 for type in classes_type.keys():
882 function_classes[classes_type[type][2]] = []
885 # Build the list of C types to look for ordered to start
886 # with primary classes
888 ctypes = []
889 classes_list = []
890 ctypes_processed = {}
891 classes_processed = {}
892 for classe in primary_classes:
893 classes_list.append(classe)
894 classes_processed[classe] = ()
895 for type in classes_type.keys():
896 tinfo = classes_type[type]
897 if tinfo[2] == classe:
898 ctypes.append(type)
899 ctypes_processed[type] = ()
900 for type in classes_type.keys():
901 if ctypes_processed.has_key(type):
902 continue
903 tinfo = classes_type[type]
904 if not classes_processed.has_key(tinfo[2]):
905 classes_list.append(tinfo[2])
906 classes_processed[tinfo[2]] = ()
908 ctypes.append(type)
909 ctypes_processed[type] = ()
911 for name in functions.keys():
912 found = 0;
913 (desc, ret, args, file, cond) = functions[name]
914 for type in ctypes:
915 classe = classes_type[type][2]
917 if name[0:3] == "vir" and len(args) >= 1 and args[0][1] == type:
918 found = 1
919 func = nameFixup(name, classe, type, file)
920 info = (0, func, name, ret, args, file)
921 function_classes[classe].append(info)
922 elif name[0:3] == "vir" and len(args) >= 2 and args[1][1] == type \
923 and file != "python_accessor":
924 found = 1
925 func = nameFixup(name, classe, type, file)
926 info = (1, func, name, ret, args, file)
927 function_classes[classe].append(info)
928 if found == 1:
929 continue
930 func = nameFixup(name, "None", file, file)
931 info = (0, func, name, ret, args, file)
932 function_classes['None'].append(info)
934 classes = open("libvirtclass.py", "w")
936 txt = open("libvirtclass.txt", "w")
937 txt.write(" Generated Classes for libvir-python\n\n")
939 txt.write("#\n# Global functions of the module\n#\n\n")
940 if function_classes.has_key("None"):
941 flist = function_classes["None"]
942 flist.sort(functionCompare)
943 oldfile = ""
944 for info in flist:
945 (index, func, name, ret, args, file) = info
946 if file != oldfile:
947 classes.write("#\n# Functions from module %s\n#\n\n" % file)
948 txt.write("\n# functions from module %s\n" % file)
949 oldfile = file
950 classes.write("def %s(" % func)
951 txt.write("%s()\n" % func);
952 n = 0
953 for arg in args:
954 if n != 0:
955 classes.write(", ")
956 classes.write("%s" % arg[0])
957 n = n + 1
958 classes.write("):\n")
959 writeDoc(name, args, ' ', classes);
961 for arg in args:
962 if classes_type.has_key(arg[1]):
963 classes.write(" if %s is None: %s__o = None\n" %
964 (arg[0], arg[0]))
965 classes.write(" else: %s__o = %s%s\n" %
966 (arg[0], arg[0], classes_type[arg[1]][0]))
967 if ret[0] != "void":
968 classes.write(" ret = ");
969 else:
970 classes.write(" ");
971 classes.write("libvirtmod.%s(" % name)
972 n = 0
973 for arg in args:
974 if n != 0:
975 classes.write(", ");
976 classes.write("%s" % arg[0])
977 if classes_type.has_key(arg[1]):
978 classes.write("__o");
979 n = n + 1
980 classes.write(")\n");
982 if ret[0] != "void":
983 if classes_type.has_key(ret[0]):
985 # Raise an exception
987 if functions_noexcept.has_key(name):
988 classes.write(" if ret is None:return None\n");
989 else:
990 classes.write(
991 " if ret is None:raise libvirtError('%s() failed')\n" %
992 (name))
994 classes.write(" return ");
995 classes.write(classes_type[ret[0]][1] % ("ret"));
996 classes.write("\n");
998 # For functions returning an integral type there are
999 # several things that we can do, depending on the
1000 # contents of functions_int_*:
1001 elif is_integral_type (ret[0]):
1002 if not functions_noexcept.has_key (name):
1003 if functions_int_exception_test.has_key (name):
1004 test = functions_int_exception_test[name]
1005 else:
1006 test = functions_int_default_test
1007 classes.write ((" if " + test +
1008 ": raise libvirtError ('%s() failed')\n") %
1009 ("ret", name))
1010 classes.write(" return ret\n")
1012 elif is_list_type (ret[0]):
1013 if not functions_noexcept.has_key (name):
1014 if functions_list_exception_test.has_key (name):
1015 test = functions_list_exception_test[name]
1016 else:
1017 test = functions_list_default_test
1018 classes.write ((" if " + test +
1019 ": raise libvirtError ('%s() failed')\n") %
1020 ("ret", name))
1021 classes.write(" return ret\n")
1023 else:
1024 classes.write(" return ret\n")
1026 classes.write("\n");
1028 txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
1029 for classname in classes_list:
1030 if classname == "None":
1031 pass
1032 else:
1033 if classes_ancestor.has_key(classname):
1034 txt.write("\n\nClass %s(%s)\n" % (classname,
1035 classes_ancestor[classname]))
1036 classes.write("class %s(%s):\n" % (classname,
1037 classes_ancestor[classname]))
1038 classes.write(" def __init__(self, _obj=None):\n")
1039 if reference_keepers.has_key(classname):
1040 rlist = reference_keepers[classname]
1041 for ref in rlist:
1042 classes.write(" self.%s = None\n" % ref[1])
1043 classes.write(" self._o = _obj\n")
1044 classes.write(" %s.__init__(self, _obj=_obj)\n\n" % (
1045 classes_ancestor[classname]))
1046 else:
1047 txt.write("Class %s()\n" % (classname))
1048 classes.write("class %s:\n" % (classname))
1049 if classname in [ "virDomain", "virNetwork", "virInterface", "virStoragePool", "virStorageVol", "virNodeDevice", "virSecret" ]:
1050 classes.write(" def __init__(self, conn, _obj=None):\n")
1051 else:
1052 classes.write(" def __init__(self, _obj=None):\n")
1053 if reference_keepers.has_key(classname):
1054 list = reference_keepers[classname]
1055 for ref in list:
1056 classes.write(" self.%s = None\n" % ref[1])
1057 if classname in [ "virDomain", "virNetwork", "virInterface", "virNodeDevice", "virSecret" ]:
1058 classes.write(" self._conn = conn\n")
1059 elif classname in [ "virStorageVol", "virStoragePool" ]:
1060 classes.write(" self._conn = conn\n" + \
1061 " if not isinstance(conn, virConnect):\n" + \
1062 " self._conn = conn._conn\n")
1063 classes.write(" if _obj != None:self._o = _obj;return\n")
1064 classes.write(" self._o = None\n\n");
1065 destruct=None
1066 if classes_destructors.has_key(classname):
1067 classes.write(" def __del__(self):\n")
1068 classes.write(" if self._o != None:\n")
1069 classes.write(" libvirtmod.%s(self._o)\n" %
1070 classes_destructors[classname]);
1071 classes.write(" self._o = None\n\n");
1072 destruct=classes_destructors[classname]
1073 flist = function_classes[classname]
1074 flist.sort(functionCompare)
1075 oldfile = ""
1076 for info in flist:
1077 (index, func, name, ret, args, file) = info
1079 # Do not provide as method the destructors for the class
1080 # to avoid double free
1082 if name == destruct:
1083 continue;
1084 if file != oldfile:
1085 if file == "python_accessor":
1086 classes.write(" # accessors for %s\n" % (classname))
1087 txt.write(" # accessors\n")
1088 else:
1089 classes.write(" #\n")
1090 classes.write(" # %s functions from module %s\n" % (
1091 classname, file))
1092 txt.write("\n # functions from module %s\n" % file)
1093 classes.write(" #\n\n")
1094 oldfile = file
1095 classes.write(" def %s(self" % func)
1096 txt.write(" %s()\n" % func);
1097 n = 0
1098 for arg in args:
1099 if n != index:
1100 classes.write(", %s" % arg[0])
1101 n = n + 1
1102 classes.write("):\n")
1103 writeDoc(name, args, ' ', classes);
1104 n = 0
1105 for arg in args:
1106 if classes_type.has_key(arg[1]):
1107 if n != index:
1108 classes.write(" if %s is None: %s__o = None\n" %
1109 (arg[0], arg[0]))
1110 classes.write(" else: %s__o = %s%s\n" %
1111 (arg[0], arg[0], classes_type[arg[1]][0]))
1112 n = n + 1
1113 if ret[0] != "void":
1114 classes.write(" ret = ");
1115 else:
1116 classes.write(" ");
1117 classes.write("libvirtmod.%s(" % name)
1118 n = 0
1119 for arg in args:
1120 if n != 0:
1121 classes.write(", ");
1122 if n != index:
1123 classes.write("%s" % arg[0])
1124 if classes_type.has_key(arg[1]):
1125 classes.write("__o");
1126 else:
1127 classes.write("self");
1128 if classes_type.has_key(arg[1]):
1129 classes.write(classes_type[arg[1]][0])
1130 n = n + 1
1131 classes.write(")\n");
1133 if name == "virConnectClose":
1134 classes.write(" self._o = None\n")
1136 # For functions returning object types:
1137 if ret[0] != "void":
1138 if classes_type.has_key(ret[0]):
1140 # Raise an exception
1142 if functions_noexcept.has_key(name):
1143 classes.write(
1144 " if ret is None:return None\n");
1145 else:
1146 if classname == "virConnect":
1147 classes.write(
1148 " if ret is None:raise libvirtError('%s() failed', conn=self)\n" %
1149 (name))
1150 elif classname == "virDomain":
1151 classes.write(
1152 " if ret is None:raise libvirtError('%s() failed', dom=self)\n" %
1153 (name))
1154 elif classname == "virNetwork":
1155 classes.write(
1156 " if ret is None:raise libvirtError('%s() failed', net=self)\n" %
1157 (name))
1158 elif classname == "virInterface":
1159 classes.write(
1160 " if ret is None:raise libvirtError('%s() failed', net=self)\n" %
1161 (name))
1162 elif classname == "virStoragePool":
1163 classes.write(
1164 " if ret is None:raise libvirtError('%s() failed', pool=self)\n" %
1165 (name))
1166 elif classname == "virStorageVol":
1167 classes.write(
1168 " if ret is None:raise libvirtError('%s() failed', vol=self)\n" %
1169 (name))
1170 else:
1171 classes.write(
1172 " if ret is None:raise libvirtError('%s() failed')\n" %
1173 (name))
1176 # generate the returned class wrapper for the object
1178 classes.write(" __tmp = ");
1179 classes.write(classes_type[ret[0]][1] % ("ret"));
1180 classes.write("\n");
1183 # Sometime one need to keep references of the source
1184 # class in the returned class object.
1185 # See reference_keepers for the list
1187 tclass = classes_type[ret[0]][2]
1188 if reference_keepers.has_key(tclass):
1189 list = reference_keepers[tclass]
1190 for pref in list:
1191 if pref[0] == classname:
1192 classes.write(" __tmp.%s = self\n" %
1193 pref[1])
1195 # Post-processing - just before we return.
1196 if function_post.has_key(name):
1197 classes.write(" %s\n" %
1198 (function_post[name]));
1201 # return the class
1203 classes.write(" return __tmp\n");
1204 elif converter_type.has_key(ret[0]):
1206 # Raise an exception
1208 if functions_noexcept.has_key(name):
1209 classes.write(
1210 " if ret is None:return None");
1212 # Post-processing - just before we return.
1213 if function_post.has_key(name):
1214 classes.write(" %s\n" %
1215 (function_post[name]));
1217 classes.write(" return ");
1218 classes.write(converter_type[ret[0]] % ("ret"));
1219 classes.write("\n");
1221 # For functions returning an integral type there
1222 # are several things that we can do, depending on
1223 # the contents of functions_int_*:
1224 elif is_integral_type (ret[0]):
1225 if not functions_noexcept.has_key (name):
1226 if functions_int_exception_test.has_key (name):
1227 test = functions_int_exception_test[name]
1228 else:
1229 test = functions_int_default_test
1230 if classname == "virConnect":
1231 classes.write ((" if " + test +
1232 ": raise libvirtError ('%s() failed', conn=self)\n") %
1233 ("ret", name))
1234 elif classname == "virDomain":
1235 classes.write ((" if " + test +
1236 ": raise libvirtError ('%s() failed', dom=self)\n") %
1237 ("ret", name))
1238 elif classname == "virNetwork":
1239 classes.write ((" if " + test +
1240 ": raise libvirtError ('%s() failed', net=self)\n") %
1241 ("ret", name))
1242 elif classname == "virInterface":
1243 classes.write ((" if " + test +
1244 ": raise libvirtError ('%s() failed', net=self)\n") %
1245 ("ret", name))
1246 elif classname == "virStoragePool":
1247 classes.write ((" if " + test +
1248 ": raise libvirtError ('%s() failed', pool=self)\n") %
1249 ("ret", name))
1250 elif classname == "virStorageVol":
1251 classes.write ((" if " + test +
1252 ": raise libvirtError ('%s() failed', vol=self)\n") %
1253 ("ret", name))
1254 else:
1255 classes.write ((" if " + test +
1256 ": raise libvirtError ('%s() failed')\n") %
1257 ("ret", name))
1259 # Post-processing - just before we return.
1260 if function_post.has_key(name):
1261 classes.write(" %s\n" %
1262 (function_post[name]));
1264 classes.write (" return ret\n")
1266 elif is_list_type (ret[0]):
1267 if not functions_noexcept.has_key (name):
1268 if functions_list_exception_test.has_key (name):
1269 test = functions_list_exception_test[name]
1270 else:
1271 test = functions_list_default_test
1272 if classname == "virConnect":
1273 classes.write ((" if " + test +
1274 ": raise libvirtError ('%s() failed', conn=self)\n") %
1275 ("ret", name))
1276 elif classname == "virDomain":
1277 classes.write ((" if " + test +
1278 ": raise libvirtError ('%s() failed', dom=self)\n") %
1279 ("ret", name))
1280 elif classname == "virNetwork":
1281 classes.write ((" if " + test +
1282 ": raise libvirtError ('%s() failed', net=self)\n") %
1283 ("ret", name))
1284 elif classname == "virInterface":
1285 classes.write ((" if " + test +
1286 ": raise libvirtError ('%s() failed', net=self)\n") %
1287 ("ret", name))
1288 elif classname == "virStoragePool":
1289 classes.write ((" if " + test +
1290 ": raise libvirtError ('%s() failed', pool=self)\n") %
1291 ("ret", name))
1292 elif classname == "virStorageVol":
1293 classes.write ((" if " + test +
1294 ": raise libvirtError ('%s() failed', vol=self)\n") %
1295 ("ret", name))
1296 else:
1297 classes.write ((" if " + test +
1298 ": raise libvirtError ('%s() failed')\n") %
1299 ("ret", name))
1301 # Post-processing - just before we return.
1302 if function_post.has_key(name):
1303 classes.write(" %s\n" %
1304 (function_post[name]));
1306 classes.write (" return ret\n")
1308 else:
1309 # Post-processing - just before we return.
1310 if function_post.has_key(name):
1311 classes.write(" %s\n" %
1312 (function_post[name]));
1314 classes.write(" return ret\n");
1316 classes.write("\n");
1317 # Append "<classname>.py" to class def, iff it exists
1318 try:
1319 extra = open(classname + ".py", "r")
1320 classes.write (" #\n")
1321 classes.write (" # %s methods from %s.py (hand coded)\n" % (classname,classname))
1322 classes.write (" #\n")
1323 classes.writelines(extra.readlines())
1324 extra.close()
1325 except:
1326 pass
1329 # Generate enum constants
1331 for type,enum in enums.items():
1332 classes.write("# %s\n" % type)
1333 items = enum.items()
1334 items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1])))
1335 for name,value in items:
1336 classes.write("%s = %s\n" % (name,value))
1337 classes.write("\n");
1339 if len(functions_skipped) != 0:
1340 txt.write("\nFunctions skipped:\n")
1341 for function in functions_skipped:
1342 txt.write(" %s\n" % function)
1343 if len(functions_failed) != 0:
1344 txt.write("\nFunctions failed:\n")
1345 for function in functions_failed:
1346 txt.write(" %s\n" % function)
1347 txt.close()
1348 classes.close()
1350 if buildStubs() < 0:
1351 sys.exit(1)
1352 buildWrappers()
1353 sys.exit(0)