1#!/usr/bin/python -u 2# 3# generate python wrappers from the XML API description 4# 5 6functions = {} 7enums = {} # { enumType: { enumConstant: enumValue } } 8 9import os 10import sys 11import string 12 13if __name__ == "__main__": 14 # launched as a script 15 srcPref = os.path.dirname(sys.argv[0]) 16else: 17 # imported 18 srcPref = os.path.dirname(__file__) 19 20####################################################################### 21# 22# That part if purely the API acquisition phase from the 23# XML API description 24# 25####################################################################### 26import os 27import xmllib 28try: 29 import sgmlop 30except ImportError: 31 sgmlop = None # accelerator not available 32 33debug = 0 34 35if sgmlop: 36 class FastParser: 37 """sgmlop based XML parser. this is typically 15x faster 38 than SlowParser...""" 39 40 def __init__(self, target): 41 42 # setup callbacks 43 self.finish_starttag = target.start 44 self.finish_endtag = target.end 45 self.handle_data = target.data 46 47 # activate parser 48 self.parser = sgmlop.XMLParser() 49 self.parser.register(self) 50 self.feed = self.parser.feed 51 self.entity = { 52 "amp": "&", "gt": ">", "lt": "<", 53 "apos": "'", "quot": '"' 54 } 55 56 def close(self): 57 try: 58 self.parser.close() 59 finally: 60 self.parser = self.feed = None # nuke circular reference 61 62 def handle_entityref(self, entity): 63 # <string> entity 64 try: 65 self.handle_data(self.entity[entity]) 66 except KeyError: 67 self.handle_data("&%s;" % entity) 68 69else: 70 FastParser = None 71 72 73class SlowParser(xmllib.XMLParser): 74 """slow but safe standard parser, based on the XML parser in 75 Python's standard library.""" 76 77 def __init__(self, target): 78 self.unknown_starttag = target.start 79 self.handle_data = target.data 80 self.unknown_endtag = target.end 81 xmllib.XMLParser.__init__(self) 82 83def getparser(target = None): 84 # get the fastest available parser, and attach it to an 85 # unmarshalling object. return both objects. 86 if target is None: 87 target = docParser() 88 if FastParser: 89 return FastParser(target), target 90 return SlowParser(target), target 91 92class docParser: 93 def __init__(self): 94 self._methodname = None 95 self._data = [] 96 self.in_function = 0 97 98 def close(self): 99 if debug: 100 print "close" 101 102 def getmethodname(self): 103 return self._methodname 104 105 def data(self, text): 106 if debug: 107 print "data %s" % text 108 self._data.append(text) 109 110 def start(self, tag, attrs): 111 if debug: 112 print "start %s, %s" % (tag, attrs) 113 if tag == 'function': 114 self._data = [] 115 self.in_function = 1 116 self.function = None 117 self.function_cond = None 118 self.function_args = [] 119 self.function_descr = None 120 self.function_return = None 121 self.function_file = None 122 if attrs.has_key('name'): 123 self.function = attrs['name'] 124 if attrs.has_key('file'): 125 self.function_file = attrs['file'] 126 elif tag == 'cond': 127 self._data = [] 128 elif tag == 'info': 129 self._data = [] 130 elif tag == 'arg': 131 if self.in_function == 1: 132 self.function_arg_name = None 133 self.function_arg_type = None 134 self.function_arg_info = None 135 if attrs.has_key('name'): 136 self.function_arg_name = attrs['name'] 137 if attrs.has_key('type'): 138 self.function_arg_type = attrs['type'] 139 if attrs.has_key('info'): 140 self.function_arg_info = attrs['info'] 141 elif tag == 'return': 142 if self.in_function == 1: 143 self.function_return_type = None 144 self.function_return_info = None 145 self.function_return_field = None 146 if attrs.has_key('type'): 147 self.function_return_type = attrs['type'] 148 if attrs.has_key('info'): 149 self.function_return_info = attrs['info'] 150 if attrs.has_key('field'): 151 self.function_return_field = attrs['field'] 152 elif tag == 'enum': 153 enum(attrs['type'],attrs['name'],attrs['value']) 154 155 def end(self, tag): 156 if debug: 157 print "end %s" % tag 158 if tag == 'function': 159 if self.function != None: 160 function(self.function, self.function_descr, 161 self.function_return, self.function_args, 162 self.function_file, self.function_cond) 163 self.in_function = 0 164 elif tag == 'arg': 165 if self.in_function == 1: 166 self.function_args.append([self.function_arg_name, 167 self.function_arg_type, 168 self.function_arg_info]) 169 elif tag == 'return': 170 if self.in_function == 1: 171 self.function_return = [self.function_return_type, 172 self.function_return_info, 173 self.function_return_field] 174 elif tag == 'info': 175 str = '' 176 for c in self._data: 177 str = str + c 178 if self.in_function == 1: 179 self.function_descr = str 180 elif tag == 'cond': 181 str = '' 182 for c in self._data: 183 str = str + c 184 if self.in_function == 1: 185 self.function_cond = str 186 187 188def function(name, desc, ret, args, file, cond): 189 functions[name] = (desc, ret, args, file, cond) 190 191def enum(type, name, value): 192 if not enums.has_key(type): 193 enums[type] = {} 194 enums[type][name] = value 195 196####################################################################### 197# 198# Some filtering rukes to drop functions/types which should not 199# be exposed as-is on the Python interface 200# 201####################################################################### 202 203skipped_modules = { 204 'xmlmemory': None, 205 'DOCBparser': None, 206 'SAX': None, 207 'hash': None, 208 'list': None, 209 'threads': None, 210# 'xpointer': None, 211} 212skipped_types = { 213 'int *': "usually a return type", 214 'xmlSAXHandlerPtr': "not the proper interface for SAX", 215 'htmlSAXHandlerPtr': "not the proper interface for SAX", 216 'xmlRMutexPtr': "thread specific, skipped", 217 'xmlMutexPtr': "thread specific, skipped", 218 'xmlGlobalStatePtr': "thread specific, skipped", 219 'xmlListPtr': "internal representation not suitable for python", 220 'xmlBufferPtr': "internal representation not suitable for python", 221 'FILE *': None, 222} 223 224####################################################################### 225# 226# Table of remapping to/from the python type or class to the C 227# counterpart. 228# 229####################################################################### 230 231py_types = { 232 'void': (None, None, None, None), 233 'int': ('i', None, "int", "int"), 234 'long': ('l', None, "long", "long"), 235 'double': ('d', None, "double", "double"), 236 'unsigned int': ('i', None, "int", "int"), 237 'xmlChar': ('c', None, "int", "int"), 238 'unsigned char *': ('z', None, "charPtr", "char *"), 239 'char *': ('z', None, "charPtr", "char *"), 240 'const char *': ('z', None, "charPtrConst", "const char *"), 241 'xmlChar *': ('z', None, "xmlCharPtr", "xmlChar *"), 242 'const xmlChar *': ('z', None, "xmlCharPtrConst", "const xmlChar *"), 243 'xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 244 'const xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 245 'xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 246 'const xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 247 'xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 248 'const xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 249 'xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 250 'const xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 251 'xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 252 'const xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 253 'xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 254 'const xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 255 'xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 256 'const xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 257 'xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 258 'const xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 259 'xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 260 'const xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 261 'xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 262 'const xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 263 'xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 264 'const xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 265 'xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 266 'const xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 267 'xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 268 'const xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 269 'xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 270 'const xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 271 'xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 272 'const xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 273 'xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 274 'const xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 275 'htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 276 'const htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 277 'htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 278 'const htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 279 'htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 280 'const htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 281 'htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 282 'const htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 283 'xmlXPathContextPtr': ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"), 284 'xmlXPathContext *': ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"), 285 'xmlXPathParserContextPtr': ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr"), 286 'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 287 'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 288 'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 289 'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 290 'xmlValidCtxtPtr': ('O', "ValidCtxt", "xmlValidCtxtPtr", "xmlValidCtxtPtr"), 291 'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"), 292 'FILE *': ('O', "File", "FILEPtr", "FILE *"), 293 'xmlURIPtr': ('O', "URI", "xmlURIPtr", "xmlURIPtr"), 294 'xmlErrorPtr': ('O', "Error", "xmlErrorPtr", "xmlErrorPtr"), 295 'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"), 296 'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"), 297 'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"), 298 'xmlTextReaderLocatorPtr': ('O', "xmlTextReaderLocator", "xmlTextReaderLocatorPtr", "xmlTextReaderLocatorPtr"), 299 'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"), 300 'xmlRelaxNGPtr': ('O', "relaxNgSchema", "xmlRelaxNGPtr", "xmlRelaxNGPtr"), 301 'xmlRelaxNGParserCtxtPtr': ('O', "relaxNgParserCtxt", "xmlRelaxNGParserCtxtPtr", "xmlRelaxNGParserCtxtPtr"), 302 'xmlRelaxNGValidCtxtPtr': ('O', "relaxNgValidCtxt", "xmlRelaxNGValidCtxtPtr", "xmlRelaxNGValidCtxtPtr"), 303 'xmlSchemaPtr': ('O', "Schema", "xmlSchemaPtr", "xmlSchemaPtr"), 304 'xmlSchemaParserCtxtPtr': ('O', "SchemaParserCtxt", "xmlSchemaParserCtxtPtr", "xmlSchemaParserCtxtPtr"), 305 'xmlSchemaValidCtxtPtr': ('O', "SchemaValidCtxt", "xmlSchemaValidCtxtPtr", "xmlSchemaValidCtxtPtr"), 306} 307 308py_return_types = { 309 'xmlXPathObjectPtr': ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"), 310} 311 312unknown_types = {} 313 314foreign_encoding_args = ( 315 'htmlCreateMemoryParserCtxt', 316 'htmlCtxtReadMemory', 317 'htmlParseChunk', 318 'htmlReadMemory', 319 'xmlCreateMemoryParserCtxt', 320 'xmlCtxtReadMemory', 321 'xmlCtxtResetPush', 322 'xmlParseChunk', 323 'xmlParseMemory', 324 'xmlReadMemory', 325 'xmlRecoverMemory', 326) 327 328####################################################################### 329# 330# This part writes the C <-> Python stubs libxml2-py.[ch] and 331# the table libxml2-export.c to add when registrering the Python module 332# 333####################################################################### 334 335# Class methods which are written by hand in libxml.c but the Python-level 336# code is still automatically generated (so they are not in skip_function()). 337skip_impl = ( 338 'xmlSaveFileTo', 339 'xmlSaveFormatFileTo', 340) 341 342def skip_function(name): 343 if name[0:12] == "xmlXPathWrap": 344 return 1 345 if name == "xmlFreeParserCtxt": 346 return 1 347 if name == "xmlCleanupParser": 348 return 1 349 if name == "xmlFreeTextReader": 350 return 1 351# if name[0:11] == "xmlXPathNew": 352# return 1 353 # the next function is defined in libxml.c 354 if name == "xmlRelaxNGFreeValidCtxt": 355 return 1 356 if name == "xmlFreeValidCtxt": 357 return 1 358 if name == "xmlSchemaFreeValidCtxt": 359 return 1 360 361# 362# Those are skipped because the Const version is used of the bindings 363# instead. 364# 365 if name == "xmlTextReaderBaseUri": 366 return 1 367 if name == "xmlTextReaderLocalName": 368 return 1 369 if name == "xmlTextReaderName": 370 return 1 371 if name == "xmlTextReaderNamespaceUri": 372 return 1 373 if name == "xmlTextReaderPrefix": 374 return 1 375 if name == "xmlTextReaderXmlLang": 376 return 1 377 if name == "xmlTextReaderValue": 378 return 1 379 if name == "xmlOutputBufferClose": # handled by by the superclass 380 return 1 381 if name == "xmlOutputBufferFlush": # handled by by the superclass 382 return 1 383 if name == "xmlErrMemory": 384 return 1 385 386 if name == "xmlValidBuildContentModel": 387 return 1 388 if name == "xmlValidateElementDecl": 389 return 1 390 if name == "xmlValidateAttributeDecl": 391 return 1 392 393 return 0 394 395def print_function_wrapper(name, output, export, include): 396 global py_types 397 global unknown_types 398 global functions 399 global skipped_modules 400 401 try: 402 (desc, ret, args, file, cond) = functions[name] 403 except: 404 print "failed to get function %s infos" 405 return 406 407 if skipped_modules.has_key(file): 408 return 0 409 if skip_function(name) == 1: 410 return 0 411 if name in skip_impl: 412 # Don't delete the function entry in the caller. 413 return 1 414 415 c_call = ""; 416 format="" 417 format_args="" 418 c_args="" 419 c_return="" 420 c_convert="" 421 num_bufs=0 422 for arg in args: 423 # This should be correct 424 if arg[1][0:6] == "const ": 425 arg[1] = arg[1][6:] 426 c_args = c_args + " %s %s;\n" % (arg[1], arg[0]) 427 if py_types.has_key(arg[1]): 428 (f, t, n, c) = py_types[arg[1]] 429 if (f == 'z') and (name in foreign_encoding_args) and (num_bufs == 0): 430 f = 't#' 431 if f != None: 432 format = format + f 433 if t != None: 434 format_args = format_args + ", &pyobj_%s" % (arg[0]) 435 c_args = c_args + " PyObject *pyobj_%s;\n" % (arg[0]) 436 c_convert = c_convert + \ 437 " %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0], 438 arg[1], t, arg[0]); 439 else: 440 format_args = format_args + ", &%s" % (arg[0]) 441 if f == 't#': 442 format_args = format_args + ", &py_buffsize%d" % num_bufs 443 c_args = c_args + " int py_buffsize%d;\n" % num_bufs 444 num_bufs = num_bufs + 1 445 if c_call != "": 446 c_call = c_call + ", "; 447 c_call = c_call + "%s" % (arg[0]) 448 else: 449 if skipped_types.has_key(arg[1]): 450 return 0 451 if unknown_types.has_key(arg[1]): 452 lst = unknown_types[arg[1]] 453 lst.append(name) 454 else: 455 unknown_types[arg[1]] = [name] 456 return -1 457 if format != "": 458 format = format + ":%s" % (name) 459 460 if ret[0] == 'void': 461 if file == "python_accessor": 462 if args[1][1] == "char *" or args[1][1] == "xmlChar *": 463 c_call = "\n if (%s->%s != NULL) xmlFree(%s->%s);\n" % ( 464 args[0][0], args[1][0], args[0][0], args[1][0]) 465 c_call = c_call + " %s->%s = (%s)xmlStrdup((const xmlChar *)%s);\n" % (args[0][0], 466 args[1][0], args[1][1], args[1][0]) 467 else: 468 c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0], 469 args[1][0]) 470 else: 471 c_call = "\n %s(%s);\n" % (name, c_call); 472 ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n" 473 elif py_types.has_key(ret[0]): 474 (f, t, n, c) = py_types[ret[0]] 475 c_return = " %s c_retval;\n" % (ret[0]) 476 if file == "python_accessor" and ret[2] != None: 477 c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2]) 478 else: 479 c_call = "\n c_retval = %s(%s);\n" % (name, c_call); 480 ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c) 481 ret_convert = ret_convert + " return(py_retval);\n" 482 elif py_return_types.has_key(ret[0]): 483 (f, t, n, c) = py_return_types[ret[0]] 484 c_return = " %s c_retval;\n" % (ret[0]) 485 c_call = "\n c_retval = %s(%s);\n" % (name, c_call); 486 ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c) 487 ret_convert = ret_convert + " return(py_retval);\n" 488 else: 489 if skipped_types.has_key(ret[0]): 490 return 0 491 if unknown_types.has_key(ret[0]): 492 lst = unknown_types[ret[0]] 493 lst.append(name) 494 else: 495 unknown_types[ret[0]] = [name] 496 return -1 497 498 if cond != None and cond != "": 499 include.write("#if %s\n" % cond) 500 export.write("#if %s\n" % cond) 501 output.write("#if %s\n" % cond) 502 503 include.write("PyObject * ") 504 include.write("libxml_%s(PyObject *self, PyObject *args);\n" % (name)); 505 506 export.write(" { (char *)\"%s\", libxml_%s, METH_VARARGS, NULL },\n" % 507 (name, name)) 508 509 if file == "python": 510 # Those have been manually generated 511 if cond != None and cond != "": 512 include.write("#endif\n"); 513 export.write("#endif\n"); 514 output.write("#endif\n"); 515 return 1 516 if file == "python_accessor" and ret[0] != "void" and ret[2] is None: 517 # Those have been manually generated 518 if cond != None and cond != "": 519 include.write("#endif\n"); 520 export.write("#endif\n"); 521 output.write("#endif\n"); 522 return 1 523 524 output.write("PyObject *\n") 525 output.write("libxml_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) 526 output.write(" PyObject *args") 527 if format == "": 528 output.write(" ATTRIBUTE_UNUSED") 529 output.write(") {\n") 530 if ret[0] != 'void': 531 output.write(" PyObject *py_retval;\n") 532 if c_return != "": 533 output.write(c_return) 534 if c_args != "": 535 output.write(c_args) 536 if format != "": 537 output.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" % 538 (format, format_args)) 539 output.write(" return(NULL);\n") 540 if c_convert != "": 541 output.write(c_convert) 542 543 output.write(c_call) 544 output.write(ret_convert) 545 output.write("}\n\n") 546 if cond != None and cond != "": 547 include.write("#endif /* %s */\n" % cond) 548 export.write("#endif /* %s */\n" % cond) 549 output.write("#endif /* %s */\n" % cond) 550 return 1 551 552def buildStubs(): 553 global py_types 554 global py_return_types 555 global unknown_types 556 557 try: 558 f = open(os.path.join(srcPref,"libxml2-api.xml")) 559 data = f.read() 560 (parser, target) = getparser() 561 parser.feed(data) 562 parser.close() 563 except IOError, msg: 564 try: 565 f = open(os.path.join(srcPref,"..","doc","libxml2-api.xml")) 566 data = f.read() 567 (parser, target) = getparser() 568 parser.feed(data) 569 parser.close() 570 except IOError, msg: 571 print file, ":", msg 572 sys.exit(1) 573 574 n = len(functions.keys()) 575 print "Found %d functions in libxml2-api.xml" % (n) 576 577 py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject") 578 try: 579 f = open(os.path.join(srcPref,"libxml2-python-api.xml")) 580 data = f.read() 581 (parser, target) = getparser() 582 parser.feed(data) 583 parser.close() 584 except IOError, msg: 585 print file, ":", msg 586 587 588 print "Found %d functions in libxml2-python-api.xml" % ( 589 len(functions.keys()) - n) 590 nb_wrap = 0 591 failed = 0 592 skipped = 0 593 594 include = open("libxml2-py.h", "w") 595 include.write("/* Generated */\n\n") 596 export = open("libxml2-export.c", "w") 597 export.write("/* Generated */\n\n") 598 wrapper = open("libxml2-py.c", "w") 599 wrapper.write("/* Generated */\n\n") 600 wrapper.write("#include <Python.h>\n") 601 wrapper.write("#include <libxml/xmlversion.h>\n") 602 wrapper.write("#include <libxml/tree.h>\n") 603 wrapper.write("#include <libxml/xmlschemastypes.h>\n") 604 wrapper.write("#include \"libxml_wrap.h\"\n") 605 wrapper.write("#include \"libxml2-py.h\"\n\n") 606 for function in functions.keys(): 607 ret = print_function_wrapper(function, wrapper, export, include) 608 if ret < 0: 609 failed = failed + 1 610 del functions[function] 611 if ret == 0: 612 skipped = skipped + 1 613 del functions[function] 614 if ret == 1: 615 nb_wrap = nb_wrap + 1 616 include.close() 617 export.close() 618 wrapper.close() 619 620 print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap, 621 failed, skipped); 622 print "Missing type converters: " 623 for type in unknown_types.keys(): 624 print "%s:%d " % (type, len(unknown_types[type])), 625 print 626 627####################################################################### 628# 629# This part writes part of the Python front-end classes based on 630# mapping rules between types and classes and also based on function 631# renaming to get consistent function names at the Python level 632# 633####################################################################### 634 635# 636# The type automatically remapped to generated classes 637# 638classes_type = { 639 "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"), 640 "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"), 641 "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 642 "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 643 "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 644 "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 645 "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), 646 "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), 647 "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"), 648 "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"), 649 "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), 650 "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), 651 "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), 652 "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), 653 "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"), 654 "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"), 655 "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), 656 "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), 657 "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"), 658 "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"), 659 "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), 660 "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), 661 "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 662 "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 663 "htmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 664 "htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 665 "xmlValidCtxtPtr": ("._o", "ValidCtxt(_obj=%s)", "ValidCtxt"), 666 "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"), 667 "xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"), 668 "xmlErrorPtr": ("._o", "Error(_obj=%s)", "Error"), 669 "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"), 670 "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"), 671 "xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"), 672 "xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"), 673 "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"), 674 'xmlRelaxNGPtr': ('._o', "relaxNgSchema(_obj=%s)", "relaxNgSchema"), 675 'xmlRelaxNGParserCtxtPtr': ('._o', "relaxNgParserCtxt(_obj=%s)", "relaxNgParserCtxt"), 676 'xmlRelaxNGValidCtxtPtr': ('._o', "relaxNgValidCtxt(_obj=%s)", "relaxNgValidCtxt"), 677 'xmlSchemaPtr': ("._o", "Schema(_obj=%s)", "Schema"), 678 'xmlSchemaParserCtxtPtr': ("._o", "SchemaParserCtxt(_obj=%s)", "SchemaParserCtxt"), 679 'xmlSchemaValidCtxtPtr': ("._o", "SchemaValidCtxt(_obj=%s)", "SchemaValidCtxt"), 680} 681 682converter_type = { 683 "xmlXPathObjectPtr": "xpathObjectRet(%s)", 684} 685 686primary_classes = ["xmlNode", "xmlDoc"] 687 688classes_ancestor = { 689 "xmlNode" : "xmlCore", 690 "xmlDtd" : "xmlNode", 691 "xmlDoc" : "xmlNode", 692 "xmlAttr" : "xmlNode", 693 "xmlNs" : "xmlNode", 694 "xmlEntity" : "xmlNode", 695 "xmlElement" : "xmlNode", 696 "xmlAttribute" : "xmlNode", 697 "outputBuffer": "ioWriteWrapper", 698 "inputBuffer": "ioReadWrapper", 699 "parserCtxt": "parserCtxtCore", 700 "xmlTextReader": "xmlTextReaderCore", 701 "ValidCtxt": "ValidCtxtCore", 702 "SchemaValidCtxt": "SchemaValidCtxtCore", 703 "relaxNgValidCtxt": "relaxNgValidCtxtCore", 704} 705classes_destructors = { 706 "parserCtxt": "xmlFreeParserCtxt", 707 "catalog": "xmlFreeCatalog", 708 "URI": "xmlFreeURI", 709# "outputBuffer": "xmlOutputBufferClose", 710 "inputBuffer": "xmlFreeParserInputBuffer", 711 "xmlReg": "xmlRegFreeRegexp", 712 "xmlTextReader": "xmlFreeTextReader", 713 "relaxNgSchema": "xmlRelaxNGFree", 714 "relaxNgParserCtxt": "xmlRelaxNGFreeParserCtxt", 715 "relaxNgValidCtxt": "xmlRelaxNGFreeValidCtxt", 716 "Schema": "xmlSchemaFree", 717 "SchemaParserCtxt": "xmlSchemaFreeParserCtxt", 718 "SchemaValidCtxt": "xmlSchemaFreeValidCtxt", 719 "ValidCtxt": "xmlFreeValidCtxt", 720} 721 722functions_noexcept = { 723 "xmlHasProp": 1, 724 "xmlHasNsProp": 1, 725 "xmlDocSetRootElement": 1, 726 "xmlNodeGetNs": 1, 727 "xmlNodeGetNsDefs": 1, 728} 729 730reference_keepers = { 731 "xmlTextReader": [('inputBuffer', 'input')], 732 "relaxNgValidCtxt": [('relaxNgSchema', 'schema')], 733 "SchemaValidCtxt": [('Schema', 'schema')], 734} 735 736function_classes = {} 737 738function_classes["None"] = [] 739 740def nameFixup(name, classe, type, file): 741 listname = classe + "List" 742 ll = len(listname) 743 l = len(classe) 744 if name[0:l] == listname: 745 func = name[l:] 746 func = string.lower(func[0:1]) + func[1:] 747 elif name[0:12] == "xmlParserGet" and file == "python_accessor": 748 func = name[12:] 749 func = string.lower(func[0:1]) + func[1:] 750 elif name[0:12] == "xmlParserSet" and file == "python_accessor": 751 func = name[12:] 752 func = string.lower(func[0:1]) + func[1:] 753 elif name[0:10] == "xmlNodeGet" and file == "python_accessor": 754 func = name[10:] 755 func = string.lower(func[0:1]) + func[1:] 756 elif name[0:9] == "xmlURIGet" and file == "python_accessor": 757 func = name[9:] 758 func = string.lower(func[0:1]) + func[1:] 759 elif name[0:9] == "xmlURISet" and file == "python_accessor": 760 func = name[6:] 761 func = string.lower(func[0:1]) + func[1:] 762 elif name[0:11] == "xmlErrorGet" and file == "python_accessor": 763 func = name[11:] 764 func = string.lower(func[0:1]) + func[1:] 765 elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor": 766 func = name[17:] 767 func = string.lower(func[0:1]) + func[1:] 768 elif name[0:11] == "xmlXPathGet" and file == "python_accessor": 769 func = name[11:] 770 func = string.lower(func[0:1]) + func[1:] 771 elif name[0:11] == "xmlXPathSet" and file == "python_accessor": 772 func = name[8:] 773 func = string.lower(func[0:1]) + func[1:] 774 elif name[0:15] == "xmlOutputBuffer" and file != "python": 775 func = name[15:] 776 func = string.lower(func[0:1]) + func[1:] 777 elif name[0:20] == "xmlParserInputBuffer" and file != "python": 778 func = name[20:] 779 func = string.lower(func[0:1]) + func[1:] 780 elif name[0:9] == "xmlRegexp" and file == "xmlregexp": 781 func = "regexp" + name[9:] 782 elif name[0:6] == "xmlReg" and file == "xmlregexp": 783 func = "regexp" + name[6:] 784 elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader": 785 func = name[20:] 786 elif name[0:18] == "xmlTextReaderConst" and file == "xmlreader": 787 func = name[18:] 788 elif name[0:13] == "xmlTextReader" and file == "xmlreader": 789 func = name[13:] 790 elif name[0:12] == "xmlReaderNew" and file == "xmlreader": 791 func = name[9:] 792 elif name[0:11] == "xmlACatalog": 793 func = name[11:] 794 func = string.lower(func[0:1]) + func[1:] 795 elif name[0:l] == classe: 796 func = name[l:] 797 func = string.lower(func[0:1]) + func[1:] 798 elif name[0:7] == "libxml_": 799 func = name[7:] 800 func = string.lower(func[0:1]) + func[1:] 801 elif name[0:6] == "xmlGet": 802 func = name[6:] 803 func = string.lower(func[0:1]) + func[1:] 804 elif name[0:3] == "xml": 805 func = name[3:] 806 func = string.lower(func[0:1]) + func[1:] 807 else: 808 func = name 809 if func[0:5] == "xPath": 810 func = "xpath" + func[5:] 811 elif func[0:4] == "xPtr": 812 func = "xpointer" + func[4:] 813 elif func[0:8] == "xInclude": 814 func = "xinclude" + func[8:] 815 elif func[0:2] == "iD": 816 func = "ID" + func[2:] 817 elif func[0:3] == "uRI": 818 func = "URI" + func[3:] 819 elif func[0:4] == "uTF8": 820 func = "UTF8" + func[4:] 821 elif func[0:3] == 'sAX': 822 func = "SAX" + func[3:] 823 return func 824 825 826def functionCompare(info1, info2): 827 (index1, func1, name1, ret1, args1, file1) = info1 828 (index2, func2, name2, ret2, args2, file2) = info2 829 if file1 == file2: 830 if func1 < func2: 831 return -1 832 if func1 > func2: 833 return 1 834 if file1 == "python_accessor": 835 return -1 836 if file2 == "python_accessor": 837 return 1 838 if file1 < file2: 839 return -1 840 if file1 > file2: 841 return 1 842 return 0 843 844def writeDoc(name, args, indent, output): 845 if functions[name][0] is None or functions[name][0] == "": 846 return 847 val = functions[name][0] 848 val = string.replace(val, "NULL", "None"); 849 output.write(indent) 850 output.write('"""') 851 while len(val) > 60: 852 if val[0] == " ": 853 val = val[1:] 854 continue 855 str = val[0:60] 856 i = string.rfind(str, " "); 857 if i < 0: 858 i = 60 859 str = val[0:i] 860 val = val[i:] 861 output.write(str) 862 output.write('\n '); 863 output.write(indent) 864 output.write(val); 865 output.write(' """\n') 866 867def buildWrappers(): 868 global ctypes 869 global py_types 870 global py_return_types 871 global unknown_types 872 global functions 873 global function_classes 874 global classes_type 875 global classes_list 876 global converter_type 877 global primary_classes 878 global converter_type 879 global classes_ancestor 880 global converter_type 881 global primary_classes 882 global classes_ancestor 883 global classes_destructors 884 global functions_noexcept 885 886 for type in classes_type.keys(): 887 function_classes[classes_type[type][2]] = [] 888 889 # 890 # Build the list of C types to look for ordered to start 891 # with primary classes 892 # 893 ctypes = [] 894 classes_list = [] 895 ctypes_processed = {} 896 classes_processed = {} 897 for classe in primary_classes: 898 classes_list.append(classe) 899 classes_processed[classe] = () 900 for type in classes_type.keys(): 901 tinfo = classes_type[type] 902 if tinfo[2] == classe: 903 ctypes.append(type) 904 ctypes_processed[type] = () 905 for type in classes_type.keys(): 906 if ctypes_processed.has_key(type): 907 continue 908 tinfo = classes_type[type] 909 if not classes_processed.has_key(tinfo[2]): 910 classes_list.append(tinfo[2]) 911 classes_processed[tinfo[2]] = () 912 913 ctypes.append(type) 914 ctypes_processed[type] = () 915 916 for name in functions.keys(): 917 found = 0; 918 (desc, ret, args, file, cond) = functions[name] 919 for type in ctypes: 920 classe = classes_type[type][2] 921 922 if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type: 923 found = 1 924 func = nameFixup(name, classe, type, file) 925 info = (0, func, name, ret, args, file) 926 function_classes[classe].append(info) 927 elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type \ 928 and file != "python_accessor": 929 found = 1 930 func = nameFixup(name, classe, type, file) 931 info = (1, func, name, ret, args, file) 932 function_classes[classe].append(info) 933 elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type: 934 found = 1 935 func = nameFixup(name, classe, type, file) 936 info = (0, func, name, ret, args, file) 937 function_classes[classe].append(info) 938 elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type \ 939 and file != "python_accessor": 940 found = 1 941 func = nameFixup(name, classe, type, file) 942 info = (1, func, name, ret, args, file) 943 function_classes[classe].append(info) 944 if found == 1: 945 continue 946 if name[0:8] == "xmlXPath": 947 continue 948 if name[0:6] == "xmlStr": 949 continue 950 if name[0:10] == "xmlCharStr": 951 continue 952 func = nameFixup(name, "None", file, file) 953 info = (0, func, name, ret, args, file) 954 function_classes['None'].append(info) 955 956 classes = open("libxml2class.py", "w") 957 txt = open("libxml2class.txt", "w") 958 txt.write(" Generated Classes for libxml2-python\n\n") 959 960 txt.write("#\n# Global functions of the module\n#\n\n") 961 if function_classes.has_key("None"): 962 flist = function_classes["None"] 963 flist.sort(functionCompare) 964 oldfile = "" 965 for info in flist: 966 (index, func, name, ret, args, file) = info 967 if file != oldfile: 968 classes.write("#\n# Functions from module %s\n#\n\n" % file) 969 txt.write("\n# functions from module %s\n" % file) 970 oldfile = file 971 classes.write("def %s(" % func) 972 txt.write("%s()\n" % func); 973 n = 0 974 for arg in args: 975 if n != 0: 976 classes.write(", ") 977 classes.write("%s" % arg[0]) 978 n = n + 1 979 classes.write("):\n") 980 writeDoc(name, args, ' ', classes); 981 982 for arg in args: 983 if classes_type.has_key(arg[1]): 984 classes.write(" if %s is None: %s__o = None\n" % 985 (arg[0], arg[0])) 986 classes.write(" else: %s__o = %s%s\n" % 987 (arg[0], arg[0], classes_type[arg[1]][0])) 988 if ret[0] != "void": 989 classes.write(" ret = "); 990 else: 991 classes.write(" "); 992 classes.write("libxml2mod.%s(" % name) 993 n = 0 994 for arg in args: 995 if n != 0: 996 classes.write(", "); 997 classes.write("%s" % arg[0]) 998 if classes_type.has_key(arg[1]): 999 classes.write("__o"); 1000 n = n + 1 1001 classes.write(")\n"); 1002 if ret[0] != "void": 1003 if classes_type.has_key(ret[0]): 1004 # 1005 # Raise an exception 1006 # 1007 if functions_noexcept.has_key(name): 1008 classes.write(" if ret is None:return None\n"); 1009 elif string.find(name, "URI") >= 0: 1010 classes.write( 1011 " if ret is None:raise uriError('%s() failed')\n" 1012 % (name)) 1013 elif string.find(name, "XPath") >= 0: 1014 classes.write( 1015 " if ret is None:raise xpathError('%s() failed')\n" 1016 % (name)) 1017 elif string.find(name, "Parse") >= 0: 1018 classes.write( 1019 " if ret is None:raise parserError('%s() failed')\n" 1020 % (name)) 1021 else: 1022 classes.write( 1023 " if ret is None:raise treeError('%s() failed')\n" 1024 % (name)) 1025 classes.write(" return "); 1026 classes.write(classes_type[ret[0]][1] % ("ret")); 1027 classes.write("\n"); 1028 else: 1029 classes.write(" return ret\n"); 1030 classes.write("\n"); 1031 1032 txt.write("\n\n#\n# Set of classes of the module\n#\n\n") 1033 for classname in classes_list: 1034 if classname == "None": 1035 pass 1036 else: 1037 if classes_ancestor.has_key(classname): 1038 txt.write("\n\nClass %s(%s)\n" % (classname, 1039 classes_ancestor[classname])) 1040 classes.write("class %s(%s):\n" % (classname, 1041 classes_ancestor[classname])) 1042 classes.write(" def __init__(self, _obj=None):\n") 1043 if classes_ancestor[classname] == "xmlCore" or \ 1044 classes_ancestor[classname] == "xmlNode": 1045 classes.write(" if type(_obj).__name__ != ") 1046 classes.write("'PyCObject':\n") 1047 classes.write(" raise TypeError, ") 1048 classes.write("'%s needs a PyCObject argument'\n" % \ 1049 classname) 1050 if reference_keepers.has_key(classname): 1051 rlist = reference_keepers[classname] 1052 for ref in rlist: 1053 classes.write(" self.%s = None\n" % ref[1]) 1054 classes.write(" self._o = _obj\n") 1055 classes.write(" %s.__init__(self, _obj=_obj)\n\n" % ( 1056 classes_ancestor[classname])) 1057 if classes_ancestor[classname] == "xmlCore" or \ 1058 classes_ancestor[classname] == "xmlNode": 1059 classes.write(" def __repr__(self):\n") 1060 format = "<%s (%%s) object at 0x%%x>" % (classname) 1061 classes.write(" return \"%s\" %% (self.name, long(pos_id (self)))\n\n" % ( 1062 format)) 1063 else: 1064 txt.write("Class %s()\n" % (classname)) 1065 classes.write("class %s:\n" % (classname)) 1066 classes.write(" def __init__(self, _obj=None):\n") 1067 if reference_keepers.has_key(classname): 1068 list = reference_keepers[classname] 1069 for ref in list: 1070 classes.write(" self.%s = None\n" % ref[1]) 1071 classes.write(" if _obj != None:self._o = _obj;return\n") 1072 classes.write(" self._o = None\n\n"); 1073 destruct=None 1074 if classes_destructors.has_key(classname): 1075 classes.write(" def __del__(self):\n") 1076 classes.write(" if self._o != None:\n") 1077 classes.write(" libxml2mod.%s(self._o)\n" % 1078 classes_destructors[classname]); 1079 classes.write(" self._o = None\n\n"); 1080 destruct=classes_destructors[classname] 1081 flist = function_classes[classname] 1082 flist.sort(functionCompare) 1083 oldfile = "" 1084 for info in flist: 1085 (index, func, name, ret, args, file) = info 1086 # 1087 # Do not provide as method the destructors for the class 1088 # to avoid double free 1089 # 1090 if name == destruct: 1091 continue; 1092 if file != oldfile: 1093 if file == "python_accessor": 1094 classes.write(" # accessors for %s\n" % (classname)) 1095 txt.write(" # accessors\n") 1096 else: 1097 classes.write(" #\n") 1098 classes.write(" # %s functions from module %s\n" % ( 1099 classname, file)) 1100 txt.write("\n # functions from module %s\n" % file) 1101 classes.write(" #\n\n") 1102 oldfile = file 1103 classes.write(" def %s(self" % func) 1104 txt.write(" %s()\n" % func); 1105 n = 0 1106 for arg in args: 1107 if n != index: 1108 classes.write(", %s" % arg[0]) 1109 n = n + 1 1110 classes.write("):\n") 1111 writeDoc(name, args, ' ', classes); 1112 n = 0 1113 for arg in args: 1114 if classes_type.has_key(arg[1]): 1115 if n != index: 1116 classes.write(" if %s is None: %s__o = None\n" % 1117 (arg[0], arg[0])) 1118 classes.write(" else: %s__o = %s%s\n" % 1119 (arg[0], arg[0], classes_type[arg[1]][0])) 1120 n = n + 1 1121 if ret[0] != "void": 1122 classes.write(" ret = "); 1123 else: 1124 classes.write(" "); 1125 classes.write("libxml2mod.%s(" % name) 1126 n = 0 1127 for arg in args: 1128 if n != 0: 1129 classes.write(", "); 1130 if n != index: 1131 classes.write("%s" % arg[0]) 1132 if classes_type.has_key(arg[1]): 1133 classes.write("__o"); 1134 else: 1135 classes.write("self"); 1136 if classes_type.has_key(arg[1]): 1137 classes.write(classes_type[arg[1]][0]) 1138 n = n + 1 1139 classes.write(")\n"); 1140 if ret[0] != "void": 1141 if classes_type.has_key(ret[0]): 1142 # 1143 # Raise an exception 1144 # 1145 if functions_noexcept.has_key(name): 1146 classes.write( 1147 " if ret is None:return None\n"); 1148 elif string.find(name, "URI") >= 0: 1149 classes.write( 1150 " if ret is None:raise uriError('%s() failed')\n" 1151 % (name)) 1152 elif string.find(name, "XPath") >= 0: 1153 classes.write( 1154 " if ret is None:raise xpathError('%s() failed')\n" 1155 % (name)) 1156 elif string.find(name, "Parse") >= 0: 1157 classes.write( 1158 " if ret is None:raise parserError('%s() failed')\n" 1159 % (name)) 1160 else: 1161 classes.write( 1162 " if ret is None:raise treeError('%s() failed')\n" 1163 % (name)) 1164 1165 # 1166 # generate the returned class wrapper for the object 1167 # 1168 classes.write(" __tmp = "); 1169 classes.write(classes_type[ret[0]][1] % ("ret")); 1170 classes.write("\n"); 1171 1172 # 1173 # Sometime one need to keep references of the source 1174 # class in the returned class object. 1175 # See reference_keepers for the list 1176 # 1177 tclass = classes_type[ret[0]][2] 1178 if reference_keepers.has_key(tclass): 1179 list = reference_keepers[tclass] 1180 for pref in list: 1181 if pref[0] == classname: 1182 classes.write(" __tmp.%s = self\n" % 1183 pref[1]) 1184 # 1185 # return the class 1186 # 1187 classes.write(" return __tmp\n"); 1188 elif converter_type.has_key(ret[0]): 1189 # 1190 # Raise an exception 1191 # 1192 if functions_noexcept.has_key(name): 1193 classes.write( 1194 " if ret is None:return None"); 1195 elif string.find(name, "URI") >= 0: 1196 classes.write( 1197 " if ret is None:raise uriError('%s() failed')\n" 1198 % (name)) 1199 elif string.find(name, "XPath") >= 0: 1200 classes.write( 1201 " if ret is None:raise xpathError('%s() failed')\n" 1202 % (name)) 1203 elif string.find(name, "Parse") >= 0: 1204 classes.write( 1205 " if ret is None:raise parserError('%s() failed')\n" 1206 % (name)) 1207 else: 1208 classes.write( 1209 " if ret is None:raise treeError('%s() failed')\n" 1210 % (name)) 1211 classes.write(" return "); 1212 classes.write(converter_type[ret[0]] % ("ret")); 1213 classes.write("\n"); 1214 else: 1215 classes.write(" return ret\n"); 1216 classes.write("\n"); 1217 1218 # 1219 # Generate enum constants 1220 # 1221 for type,enum in enums.items(): 1222 classes.write("# %s\n" % type) 1223 items = enum.items() 1224 items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1]))) 1225 for name,value in items: 1226 classes.write("%s = %s\n" % (name,value)) 1227 classes.write("\n"); 1228 1229 txt.close() 1230 classes.close() 1231 1232buildStubs() 1233buildWrappers() 1234