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