1#--------------------------------------------------------------------------- 2# Name: etgtools/__init__.py 3# Author: Robin Dunn 4# 5# Created: 3-Nov-2010 6# Copyright: (c) 2010-2018 by Total Control Software 7# License: wxWindows License 8#--------------------------------------------------------------------------- 9 10""" 11Classes and tools for describing the public API of wxWidgets, parsing 12them from the Doxygen XML, and producing wrapper code from them. 13""" 14 15import sys, os 16# Mac Python actually has a buildtools module, so we need 17# to make sure ours is picked up when we're not run from the 18# Phoenix root dir. 19sys.path.insert(0, os.path.abspath(os.path.split(__file__)[0]+'/..')) 20 21from buildtools.config import Config 22from .extractors import * 23 24#--------------------------------------------------------------------------- 25cfg = Config(noWxConfig=True) 26 27phoenixRoot = cfg.ROOT_DIR 28XMLSRC = cfg.DOXY_XML_DIR 29 30class DoxyXMLError(Exception): 31 pass 32 33#--------------------------------------------------------------------------- 34 35_filesparsed = set() 36 37def parseDoxyXML(module, class_or_filename_list): 38 """ 39 Parse a list of Doxygen XML files and add the item(s) found there to the 40 ModuleDef object. 41 42 If a name in the list a wx class name then the Doxygen XML filename is 43 calculated from that name, otherwise it is treated as a filename in the 44 Doxygen XML output folder. 45 """ 46 47 def _classToDoxyName(name, attempts, base='class'): 48 import string 49 filename = base 50 for c in name: 51 if c in string.ascii_uppercase: 52 filename += '_' + c.lower() 53 else: 54 filename += c 55 filename = os.path.join(XMLSRC, filename) + '.xml' 56 attempts.append(filename) 57 return filename 58 59 def _includeToDoxyName(name): 60 name = os.path.basename(name) 61 name = name.replace('.h', '_8h') 62 pathname = os.path.join(XMLSRC, name) + '.xml' 63 if os.path.exists(pathname): 64 return pathname, name + '.xml' 65 else: 66 name = 'interface_2wx_2' + name 67 return os.path.join(XMLSRC, name) + '.xml', name + '.xml' 68 69 for class_or_filename in class_or_filename_list: 70 attempts = [] 71 pathname = _classToDoxyName(class_or_filename, attempts) 72 73 if not os.path.exists(pathname): 74 pathname = _classToDoxyName(class_or_filename, attempts, 'struct') 75 if not os.path.exists(pathname): 76 pathname = os.path.join(XMLSRC, class_or_filename) 77 attempts.append(pathname) 78 if not os.path.exists(pathname): 79 msg = "Unable to find xml file for ITEM: %s" % class_or_filename 80 print(msg) 81 print("Tried: %s" % ('\n '.join(attempts))) 82 raise DoxyXMLError(msg) 83 84 if verbose(): 85 print("Loading %s..." % pathname) 86 _filesparsed.add(pathname) 87 88 root = et.parse(pathname).getroot() 89 for element in root: 90 # extract and add top-level elements from the XML document 91 item = module.addElement(element) 92 93 # Also automatically parse the XML for the include file to get related 94 # typedefs, functions, enums, etc. 95 # Make sure though, that for interface files we only parse the one 96 # that belongs to this class. Otherwise, enums, etc. will be defined 97 # in multiple places. 98 xmlname = class_or_filename.replace('wx', '').lower() 99 100 if hasattr(item, 'includes'): 101 for inc in item.includes: 102 pathname, name = _includeToDoxyName(inc) 103 if os.path.exists(pathname) \ 104 and pathname not in _filesparsed \ 105 and ("interface" not in name or xmlname in name) \ 106 and name not in class_or_filename_list: 107 class_or_filename_list.append(name) 108 109 _filesparsed.clear() 110 111 module.parseCompleted() 112 113#--------------------------------------------------------------------------- 114 115 116#--------------------------------------------------------------------------- 117 118 119