1 #!/usr/bin/python -u 2 # 3 # generate python wrappers from the XML API description 4 # 5 6 functions = {} 7 enums = {} # { enumType: { enumConstant: enumValue } } 8 9 import os 10 import sys 11 import string 12 13 if __name__ == "__main__": 14 # launched as a script 15 srcPref = os.path.dirname(sys.argv[0]) 16 else: 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 ####################################################################### 26 import os 27 import xml.sax 28 29 debug = 0 30 31 def 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 38 class 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 138 def function(name, desc, ret, args, file, cond): 139 functions[name] = (desc, ret, args, file, cond) 140 141 def 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 153 skipped_modules = { 154 'xmlmemory': None, 155 'DOCBparser': None, 156 'SAX': None, 157 'hash': None, 158 'list': None, 159 'threads': None, 160 # 'xpointer': None, 161 } 162 skipped_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 181 py_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 258 py_return_types = { 259 'xmlXPathObjectPtr': ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"), 260 } 261 262 unknown_types = {} 263 264 foreign_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()). 287 skip_impl = ( 288 'xmlSaveFileTo', 289 'xmlSaveFormatFileTo', 290 ) 291 292 def 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 347 def 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 + " int 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 510 def 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("#include <Python.h>\n") 559 wrapper.write("#include <libxml/xmlversion.h>\n") 560 wrapper.write("#include <libxml/tree.h>\n") 561 wrapper.write("#include <libxml/xmlschemastypes.h>\n") 562 wrapper.write("#include \"libxml_wrap.h\"\n") 563 wrapper.write("#include \"libxml2-py.h\"\n\n") 564 for function in sorted(functions.keys()): 565 ret = print_function_wrapper(function, wrapper, export, include) 566 if ret < 0: 567 failed = failed + 1 568 del functions[function] 569 if ret == 0: 570 skipped = skipped + 1 571 del functions[function] 572 if ret == 1: 573 nb_wrap = nb_wrap + 1 574 include.close() 575 export.close() 576 wrapper.close() 577 578 print("Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap, 579 failed, skipped)) 580 print("Missing type converters: ") 581 for type in list(unknown_types.keys()): 582 print("%s:%d " % (type, len(unknown_types[type]))) 583 print() 584 585 ####################################################################### 586 # 587 # This part writes part of the Python front-end classes based on 588 # mapping rules between types and classes and also based on function 589 # renaming to get consistent function names at the Python level 590 # 591 ####################################################################### 592 593 # 594 # The type automatically remapped to generated classes 595 # 596 classes_type = { 597 "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"), 598 "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"), 599 "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 600 "xmlDoc *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 601 "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 602 "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 603 "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), 604 "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), 605 "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"), 606 "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"), 607 "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), 608 "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), 609 "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), 610 "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), 611 "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"), 612 "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"), 613 "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), 614 "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), 615 "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"), 616 "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"), 617 "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), 618 "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), 619 "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 620 "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 621 "htmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 622 "htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 623 "xmlValidCtxtPtr": ("._o", "ValidCtxt(_obj=%s)", "ValidCtxt"), 624 "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"), 625 "xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"), 626 "xmlErrorPtr": ("._o", "Error(_obj=%s)", "Error"), 627 "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"), 628 "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"), 629 "xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"), 630 "xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"), 631 "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"), 632 'xmlRelaxNGPtr': ('._o', "relaxNgSchema(_obj=%s)", "relaxNgSchema"), 633 'xmlRelaxNGParserCtxtPtr': ('._o', "relaxNgParserCtxt(_obj=%s)", "relaxNgParserCtxt"), 634 'xmlRelaxNGValidCtxtPtr': ('._o', "relaxNgValidCtxt(_obj=%s)", "relaxNgValidCtxt"), 635 'xmlSchemaPtr': ("._o", "Schema(_obj=%s)", "Schema"), 636 'xmlSchemaParserCtxtPtr': ("._o", "SchemaParserCtxt(_obj=%s)", "SchemaParserCtxt"), 637 'xmlSchemaValidCtxtPtr': ("._o", "SchemaValidCtxt(_obj=%s)", "SchemaValidCtxt"), 638 } 639 640 converter_type = { 641 "xmlXPathObjectPtr": "xpathObjectRet(%s)", 642 } 643 644 primary_classes = ["xmlNode", "xmlDoc"] 645 646 classes_ancestor = { 647 "xmlNode" : "xmlCore", 648 "xmlDtd" : "xmlNode", 649 "xmlDoc" : "xmlNode", 650 "xmlAttr" : "xmlNode", 651 "xmlNs" : "xmlNode", 652 "xmlEntity" : "xmlNode", 653 "xmlElement" : "xmlNode", 654 "xmlAttribute" : "xmlNode", 655 "outputBuffer": "ioWriteWrapper", 656 "inputBuffer": "ioReadWrapper", 657 "parserCtxt": "parserCtxtCore", 658 "xmlTextReader": "xmlTextReaderCore", 659 "ValidCtxt": "ValidCtxtCore", 660 "SchemaValidCtxt": "SchemaValidCtxtCore", 661 "relaxNgValidCtxt": "relaxNgValidCtxtCore", 662 } 663 classes_destructors = { 664 "parserCtxt": "xmlFreeParserCtxt", 665 "catalog": "xmlFreeCatalog", 666 "URI": "xmlFreeURI", 667 # "outputBuffer": "xmlOutputBufferClose", 668 "inputBuffer": "xmlFreeParserInputBuffer", 669 "xmlReg": "xmlRegFreeRegexp", 670 "xmlTextReader": "xmlFreeTextReader", 671 "relaxNgSchema": "xmlRelaxNGFree", 672 "relaxNgParserCtxt": "xmlRelaxNGFreeParserCtxt", 673 "relaxNgValidCtxt": "xmlRelaxNGFreeValidCtxt", 674 "Schema": "xmlSchemaFree", 675 "SchemaParserCtxt": "xmlSchemaFreeParserCtxt", 676 "SchemaValidCtxt": "xmlSchemaFreeValidCtxt", 677 "ValidCtxt": "xmlFreeValidCtxt", 678 } 679 680 functions_noexcept = { 681 "xmlHasProp": 1, 682 "xmlHasNsProp": 1, 683 "xmlDocSetRootElement": 1, 684 "xmlNodeGetNs": 1, 685 "xmlNodeGetNsDefs": 1, 686 "xmlNextElementSibling": 1, 687 "xmlPreviousElementSibling": 1, 688 "xmlFirstElementChild": 1, 689 "xmlLastElementChild": 1, 690 } 691 692 reference_keepers = { 693 "xmlTextReader": [('inputBuffer', 'input')], 694 "relaxNgValidCtxt": [('relaxNgSchema', 'schema')], 695 "SchemaValidCtxt": [('Schema', 'schema')], 696 } 697 698 function_classes = {} 699 700 function_classes["None"] = [] 701 702 def nameFixup(name, classe, type, file): 703 listname = classe + "List" 704 ll = len(listname) 705 l = len(classe) 706 if name[0:l] == listname: 707 func = name[l:] 708 func = func[0:1].lower() + func[1:] 709 elif name[0:12] == "xmlParserGet" and file == "python_accessor": 710 func = name[12:] 711 func = func[0:1].lower() + func[1:] 712 elif name[0:12] == "xmlParserSet" and file == "python_accessor": 713 func = name[12:] 714 func = func[0:1].lower() + func[1:] 715 elif name[0:10] == "xmlNodeGet" and file == "python_accessor": 716 func = name[10:] 717 func = func[0:1].lower() + func[1:] 718 elif name[0:9] == "xmlURIGet" and file == "python_accessor": 719 func = name[9:] 720 func = func[0:1].lower() + func[1:] 721 elif name[0:9] == "xmlURISet" and file == "python_accessor": 722 func = name[6:] 723 func = func[0:1].lower() + func[1:] 724 elif name[0:11] == "xmlErrorGet" and file == "python_accessor": 725 func = name[11:] 726 func = func[0:1].lower() + func[1:] 727 elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor": 728 func = name[17:] 729 func = func[0:1].lower() + func[1:] 730 elif name[0:11] == "xmlXPathGet" and file == "python_accessor": 731 func = name[11:] 732 func = func[0:1].lower() + func[1:] 733 elif name[0:11] == "xmlXPathSet" and file == "python_accessor": 734 func = name[8:] 735 func = func[0:1].lower() + func[1:] 736 elif name[0:15] == "xmlOutputBuffer" and file != "python": 737 func = name[15:] 738 func = func[0:1].lower() + func[1:] 739 elif name[0:20] == "xmlParserInputBuffer" and file != "python": 740 func = name[20:] 741 func = func[0:1].lower() + func[1:] 742 elif name[0:9] == "xmlRegexp" and file == "xmlregexp": 743 func = "regexp" + name[9:] 744 elif name[0:6] == "xmlReg" and file == "xmlregexp": 745 func = "regexp" + name[6:] 746 elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader": 747 func = name[20:] 748 elif name[0:18] == "xmlTextReaderConst" and file == "xmlreader": 749 func = name[18:] 750 elif name[0:13] == "xmlTextReader" and file == "xmlreader": 751 func = name[13:] 752 elif name[0:12] == "xmlReaderNew" and file == "xmlreader": 753 func = name[9:] 754 elif name[0:11] == "xmlACatalog": 755 func = name[11:] 756 func = func[0:1].lower() + func[1:] 757 elif name[0:l] == classe: 758 func = name[l:] 759 func = func[0:1].lower() + func[1:] 760 elif name[0:7] == "libxml_": 761 func = name[7:] 762 func = func[0:1].lower() + func[1:] 763 elif name[0:6] == "xmlGet": 764 func = name[6:] 765 func = func[0:1].lower() + func[1:] 766 elif name[0:3] == "xml": 767 func = name[3:] 768 func = func[0:1].lower() + func[1:] 769 else: 770 func = name 771 if func[0:5] == "xPath": 772 func = "xpath" + func[5:] 773 elif func[0:4] == "xPtr": 774 func = "xpointer" + func[4:] 775 elif func[0:8] == "xInclude": 776 func = "xinclude" + func[8:] 777 elif func[0:2] == "iD": 778 func = "ID" + func[2:] 779 elif func[0:3] == "uRI": 780 func = "URI" + func[3:] 781 elif func[0:4] == "uTF8": 782 func = "UTF8" + func[4:] 783 elif func[0:3] == 'sAX': 784 func = "SAX" + func[3:] 785 return func 786 787 788 def functionCompare(info1, info2): 789 (index1, func1, name1, ret1, args1, file1) = info1 790 (index2, func2, name2, ret2, args2, file2) = info2 791 if file1 == file2: 792 if func1 < func2: 793 return -1 794 if func1 > func2: 795 return 1 796 if file1 == "python_accessor": 797 return -1 798 if file2 == "python_accessor": 799 return 1 800 if file1 < file2: 801 return -1 802 if file1 > file2: 803 return 1 804 return 0 805 806 def cmp_to_key(mycmp): 807 'Convert a cmp= function into a key= function' 808 class K(object): 809 def __init__(self, obj, *args): 810 self.obj = obj 811 def __lt__(self, other): 812 return mycmp(self.obj, other.obj) < 0 813 def __gt__(self, other): 814 return mycmp(self.obj, other.obj) > 0 815 def __eq__(self, other): 816 return mycmp(self.obj, other.obj) == 0 817 def __le__(self, other): 818 return mycmp(self.obj, other.obj) <= 0 819 def __ge__(self, other): 820 return mycmp(self.obj, other.obj) >= 0 821 def __ne__(self, other): 822 return mycmp(self.obj, other.obj) != 0 823 return K 824 def writeDoc(name, args, indent, output): 825 if functions[name][0] is None or functions[name][0] == "": 826 return 827 val = functions[name][0] 828 val = val.replace("NULL", "None") 829 output.write(indent) 830 output.write('"""') 831 while len(val) > 60: 832 if val[0] == " ": 833 val = val[1:] 834 continue 835 str = val[0:60] 836 i = str.rfind(" ") 837 if i < 0: 838 i = 60 839 str = val[0:i] 840 val = val[i:] 841 output.write(str) 842 output.write('\n ') 843 output.write(indent) 844 output.write(val) 845 output.write(' """\n') 846 847 def buildWrappers(): 848 global ctypes 849 global py_types 850 global py_return_types 851 global unknown_types 852 global functions 853 global function_classes 854 global classes_type 855 global classes_list 856 global converter_type 857 global primary_classes 858 global converter_type 859 global classes_ancestor 860 global converter_type 861 global primary_classes 862 global classes_ancestor 863 global classes_destructors 864 global functions_noexcept 865 866 for type in classes_type.keys(): 867 function_classes[classes_type[type][2]] = [] 868 869 # 870 # Build the list of C types to look for ordered to start 871 # with primary classes 872 # 873 ctypes = [] 874 classes_list = [] 875 ctypes_processed = {} 876 classes_processed = {} 877 for classe in primary_classes: 878 classes_list.append(classe) 879 classes_processed[classe] = () 880 for type in classes_type.keys(): 881 tinfo = classes_type[type] 882 if tinfo[2] == classe: 883 ctypes.append(type) 884 ctypes_processed[type] = () 885 for type in sorted(classes_type.keys()): 886 if type in ctypes_processed: 887 continue 888 tinfo = classes_type[type] 889 if tinfo[2] not in classes_processed: 890 classes_list.append(tinfo[2]) 891 classes_processed[tinfo[2]] = () 892 893 ctypes.append(type) 894 ctypes_processed[type] = () 895 896 for name in functions.keys(): 897 found = 0 898 (desc, ret, args, file, cond) = functions[name] 899 for type in ctypes: 900 classe = classes_type[type][2] 901 902 if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type: 903 found = 1 904 func = nameFixup(name, classe, type, file) 905 info = (0, func, name, ret, args, file) 906 function_classes[classe].append(info) 907 elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type \ 908 and file != "python_accessor": 909 found = 1 910 func = nameFixup(name, classe, type, file) 911 info = (1, func, name, ret, args, file) 912 function_classes[classe].append(info) 913 elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type: 914 found = 1 915 func = nameFixup(name, classe, type, file) 916 info = (0, func, name, ret, args, file) 917 function_classes[classe].append(info) 918 elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type \ 919 and file != "python_accessor": 920 found = 1 921 func = nameFixup(name, classe, type, file) 922 info = (1, func, name, ret, args, file) 923 function_classes[classe].append(info) 924 if found == 1: 925 continue 926 if name[0:8] == "xmlXPath": 927 continue 928 if name[0:6] == "xmlStr": 929 continue 930 if name[0:10] == "xmlCharStr": 931 continue 932 func = nameFixup(name, "None", file, file) 933 info = (0, func, name, ret, args, file) 934 function_classes['None'].append(info) 935 936 classes = open("libxml2class.py", "w") 937 txt = open("libxml2class.txt", "w") 938 txt.write(" Generated Classes for libxml2-python\n\n") 939 940 txt.write("#\n# Global functions of the module\n#\n\n") 941 if "None" in function_classes: 942 flist = function_classes["None"] 943 flist = sorted(flist, key=cmp_to_key(functionCompare)) 944 oldfile = "" 945 for info in flist: 946 (index, func, name, ret, args, file) = info 947 if file != oldfile: 948 classes.write("#\n# Functions from module %s\n#\n\n" % file) 949 txt.write("\n# functions from module %s\n" % file) 950 oldfile = file 951 classes.write("def %s(" % func) 952 txt.write("%s()\n" % func) 953 n = 0 954 for arg in args: 955 if n != 0: 956 classes.write(", ") 957 classes.write("%s" % arg[0]) 958 n = n + 1 959 classes.write("):\n") 960 writeDoc(name, args, ' ', classes) 961 962 for arg in args: 963 if arg[1] in classes_type: 964 classes.write(" if %s is None: %s__o = None\n" % 965 (arg[0], arg[0])) 966 classes.write(" else: %s__o = %s%s\n" % 967 (arg[0], arg[0], classes_type[arg[1]][0])) 968 if arg[1] in py_types: 969 (f, t, n, c) = py_types[arg[1]] 970 if t == "File": 971 classes.write(" if %s is not None: %s.flush()\n" % ( 972 arg[0], arg[0])) 973 974 if ret[0] != "void": 975 classes.write(" ret = ") 976 else: 977 classes.write(" ") 978 classes.write("libxml2mod.%s(" % name) 979 n = 0 980 for arg in args: 981 if n != 0: 982 classes.write(", ") 983 classes.write("%s" % arg[0]) 984 if arg[1] in classes_type: 985 classes.write("__o") 986 n = n + 1 987 classes.write(")\n") 988 989 # This may be needed to reposition the I/O, but likely to cause more harm 990 # than good. Those changes in Python3 really break the model. 991 # for arg in args: 992 # if arg[1] in py_types: 993 # (f, t, n, c) = py_types[arg[1]] 994 # if t == "File": 995 # classes.write(" if %s is not None: %s.seek(0,0)\n"%( 996 # arg[0], arg[0])) 997 998 if ret[0] != "void": 999 if ret[0] in classes_type: 1000 # 1001 # Raise an exception 1002 # 1003 if name in functions_noexcept: 1004 classes.write(" if ret is None:return None\n") 1005 elif name.find("URI") >= 0: 1006 classes.write( 1007 " if ret is None:raise uriError('%s() failed')\n" 1008 % (name)) 1009 elif name.find("XPath") >= 0: 1010 classes.write( 1011 " if ret is None:raise xpathError('%s() failed')\n" 1012 % (name)) 1013 elif name.find("Parse") >= 0: 1014 classes.write( 1015 " if ret is None:raise parserError('%s() failed')\n" 1016 % (name)) 1017 else: 1018 classes.write( 1019 " if ret is None:raise treeError('%s() failed')\n" 1020 % (name)) 1021 classes.write(" return ") 1022 classes.write(classes_type[ret[0]][1] % ("ret")) 1023 classes.write("\n") 1024 else: 1025 classes.write(" return ret\n") 1026 classes.write("\n") 1027 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 classname in classes_ancestor: 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 classes_ancestor[classname] == "xmlCore" or \ 1040 classes_ancestor[classname] == "xmlNode": 1041 classes.write(" if checkWrapper(_obj) != 0:") 1042 classes.write(" raise TypeError") 1043 classes.write("('%s got a wrong wrapper object type')\n" % \ 1044 classname) 1045 if classname in reference_keepers: 1046 rlist = reference_keepers[classname] 1047 for ref in rlist: 1048 classes.write(" self.%s = None\n" % ref[1]) 1049 classes.write(" self._o = _obj\n") 1050 classes.write(" %s.__init__(self, _obj=_obj)\n\n" % ( 1051 classes_ancestor[classname])) 1052 if classes_ancestor[classname] == "xmlCore" or \ 1053 classes_ancestor[classname] == "xmlNode": 1054 classes.write(" def __repr__(self):\n") 1055 format = "<%s (%%s) object at 0x%%x>" % (classname) 1056 classes.write(" return \"%s\" %% (self.name, int(pos_id (self)))\n\n" % ( 1057 format)) 1058 else: 1059 txt.write("Class %s()\n" % (classname)) 1060 classes.write("class %s:\n" % (classname)) 1061 classes.write(" def __init__(self, _obj=None):\n") 1062 if classname in reference_keepers: 1063 list = reference_keepers[classname] 1064 for ref in list: 1065 classes.write(" self.%s = None\n" % ref[1]) 1066 classes.write(" if _obj != None:self._o = _obj;return\n") 1067 classes.write(" self._o = None\n\n") 1068 destruct=None 1069 if classname in classes_destructors: 1070 classes.write(" def __del__(self):\n") 1071 classes.write(" if self._o != None:\n") 1072 classes.write(" libxml2mod.%s(self._o)\n" % 1073 classes_destructors[classname]) 1074 classes.write(" self._o = None\n\n") 1075 destruct=classes_destructors[classname] 1076 flist = function_classes[classname] 1077 flist = sorted(flist, key=cmp_to_key(functionCompare)) 1078 oldfile = "" 1079 for info in flist: 1080 (index, func, name, ret, args, file) = info 1081 # 1082 # Do not provide as method the destructors for the class 1083 # to avoid double free 1084 # 1085 if name == destruct: 1086 continue 1087 if file != oldfile: 1088 if file == "python_accessor": 1089 classes.write(" # accessors for %s\n" % (classname)) 1090 txt.write(" # accessors\n") 1091 else: 1092 classes.write(" #\n") 1093 classes.write(" # %s functions from module %s\n" % ( 1094 classname, file)) 1095 txt.write("\n # functions from module %s\n" % file) 1096 classes.write(" #\n\n") 1097 oldfile = file 1098 classes.write(" def %s(self" % func) 1099 txt.write(" %s()\n" % func) 1100 n = 0 1101 for arg in args: 1102 if n != index: 1103 classes.write(", %s" % arg[0]) 1104 n = n + 1 1105 classes.write("):\n") 1106 writeDoc(name, args, ' ', classes) 1107 n = 0 1108 for arg in args: 1109 if arg[1] in classes_type: 1110 if n != index: 1111 classes.write(" if %s is None: %s__o = None\n" % 1112 (arg[0], arg[0])) 1113 classes.write(" else: %s__o = %s%s\n" % 1114 (arg[0], arg[0], classes_type[arg[1]][0])) 1115 n = n + 1 1116 if ret[0] != "void": 1117 classes.write(" ret = ") 1118 else: 1119 classes.write(" ") 1120 classes.write("libxml2mod.%s(" % name) 1121 n = 0 1122 for arg in args: 1123 if n != 0: 1124 classes.write(", ") 1125 if n != index: 1126 classes.write("%s" % arg[0]) 1127 if arg[1] in classes_type: 1128 classes.write("__o") 1129 else: 1130 classes.write("self") 1131 if arg[1] in classes_type: 1132 classes.write(classes_type[arg[1]][0]) 1133 n = n + 1 1134 classes.write(")\n") 1135 if ret[0] != "void": 1136 if ret[0] in classes_type: 1137 # 1138 # Raise an exception 1139 # 1140 if name in functions_noexcept: 1141 classes.write( 1142 " if ret is None:return None\n") 1143 elif name.find("URI") >= 0: 1144 classes.write( 1145 " if ret is None:raise uriError('%s() failed')\n" 1146 % (name)) 1147 elif name.find("XPath") >= 0: 1148 classes.write( 1149 " if ret is None:raise xpathError('%s() failed')\n" 1150 % (name)) 1151 elif name.find("Parse") >= 0: 1152 classes.write( 1153 " if ret is None:raise parserError('%s() failed')\n" 1154 % (name)) 1155 else: 1156 classes.write( 1157 " if ret is None:raise treeError('%s() failed')\n" 1158 % (name)) 1159 1160 # 1161 # generate the returned class wrapper for the object 1162 # 1163 classes.write(" __tmp = ") 1164 classes.write(classes_type[ret[0]][1] % ("ret")) 1165 classes.write("\n") 1166 1167 # 1168 # Sometime one need to keep references of the source 1169 # class in the returned class object. 1170 # See reference_keepers for the list 1171 # 1172 tclass = classes_type[ret[0]][2] 1173 if tclass in reference_keepers: 1174 list = reference_keepers[tclass] 1175 for pref in list: 1176 if pref[0] == classname: 1177 classes.write(" __tmp.%s = self\n" % 1178 pref[1]) 1179 # 1180 # return the class 1181 # 1182 classes.write(" return __tmp\n") 1183 elif ret[0] in converter_type: 1184 # 1185 # Raise an exception 1186 # 1187 if name in functions_noexcept: 1188 classes.write( 1189 " if ret is None:return None") 1190 elif name.find("URI") >= 0: 1191 classes.write( 1192 " if ret is None:raise uriError('%s() failed')\n" 1193 % (name)) 1194 elif name.find("XPath") >= 0: 1195 classes.write( 1196 " if ret is None:raise xpathError('%s() failed')\n" 1197 % (name)) 1198 elif name.find("Parse") >= 0: 1199 classes.write( 1200 " if ret is None:raise parserError('%s() failed')\n" 1201 % (name)) 1202 else: 1203 classes.write( 1204 " if ret is None:raise treeError('%s() failed')\n" 1205 % (name)) 1206 classes.write(" return ") 1207 classes.write(converter_type[ret[0]] % ("ret")) 1208 classes.write("\n") 1209 else: 1210 classes.write(" return ret\n") 1211 classes.write("\n") 1212 1213 # 1214 # Generate enum constants 1215 # 1216 for type,enum in enums.items(): 1217 classes.write("# %s\n" % type) 1218 items = enum.items() 1219 items = sorted(items, key=(lambda i: int(i[1]))) 1220 for name,value in items: 1221 classes.write("%s = %s\n" % (name,value)) 1222 classes.write("\n") 1223 1224 txt.close() 1225 classes.close() 1226 1227 buildStubs() 1228 buildWrappers() 1229