diff --git a/etgtools/__init__.py b/etgtools/__init__.py index 637861c0..35ad46ce 100644 --- a/etgtools/__init__.py +++ b/etgtools/__init__.py @@ -38,12 +38,12 @@ def parseDoxyXML(module, class_or_filename_list): """ Parse a list of Doxygen XML files and add the item(s) found there to the ModuleDef object. - + If a name in the list a wx class name then the Doxygen XML filename is calculated from that name, otherwise it is treated as a filename in the Doxygen XML output folder. """ - + def _classToDoxyName(name, attempts, base='class'): import string filename = base @@ -51,11 +51,11 @@ def parseDoxyXML(module, class_or_filename_list): if c in string.ascii_uppercase: filename += '_' + c.lower() else: - filename += c + filename += c filename = os.path.join(XMLSRC, filename) + '.xml' attempts.append(filename) return filename - + def _includeToDoxyName(name): name = os.path.basename(name) name = name.replace('.h', '_8h') @@ -65,7 +65,7 @@ def parseDoxyXML(module, class_or_filename_list): else: name = 'interface_2wx_2' + name return os.path.join(XMLSRC, name) + '.xml', name + '.xml' - + for class_or_filename in class_or_filename_list: attempts = [] pathname = _classToDoxyName(class_or_filename, attempts) @@ -80,23 +80,23 @@ def parseDoxyXML(module, class_or_filename_list): print(msg) print("Tried: %s" % ('\n '.join(attempts))) raise DoxyXMLError(msg) - + if verbose(): print("Loading %s..." % pathname) _filesparsed.add(pathname) - + root = et.parse(pathname).getroot() for element in root: # extract and add top-level elements from the XML document item = module.addElement(element) - + # Also automatically parse the XML for the include file to get related # typedefs, functions, enums, etc. # Make sure though, that for interface files we only parse the one # that belongs to this class. Otherwise, enums, etc. will be defined # in multiple places. xmlname = class_or_filename.replace('wx', '').lower() - + if hasattr(item, 'includes'): for inc in item.includes: pathname, name = _includeToDoxyName(inc) @@ -104,15 +104,15 @@ def parseDoxyXML(module, class_or_filename_list): and pathname not in _filesparsed \ and ("interface" not in name or xmlname in name) \ and name not in class_or_filename_list: - class_or_filename_list.append(name) + class_or_filename_list.append(name) _filesparsed.clear() - + module.parseCompleted() #--------------------------------------------------------------------------- - + #--------------------------------------------------------------------------- - - + + diff --git a/etgtools/extractors.py b/etgtools/extractors.py index 0270e30c..e90080a1 100644 --- a/etgtools/extractors.py +++ b/etgtools/extractors.py @@ -46,8 +46,8 @@ class BaseDef(object): # The items list is used by some subclasses to collect items that are # part of that item, like methods of a ClassDef, etc. - self.items = [] - + self.items = [] + if element is not None: self.extract(element) @@ -70,12 +70,12 @@ class BaseDef(object): self.briefDoc = bd[0] # Should be just one element self.detailedDoc = list(element.find('detaileddescription')) - + def ignore(self, val=True): self.ignored = val return self - - + + def find(self, name): """ Locate and return an item within this item that has a matching name. @@ -91,11 +91,11 @@ class BaseDef(object): if not tail: return item else: - return item.find(tail) + return item.find(tail) else: # got though all items with no match raise ExtractorError("Unable to find item named '%s' within %s named '%s'" % (head, self.__class__.__name__, self.name)) - + def findItem(self, name): """ Just like find() but does not raise an exception if the item is not found. @@ -105,16 +105,16 @@ class BaseDef(object): return item except ExtractorError: return None - + def addItem(self, item): self.items.append(item) return item - + def insertItem(self, index, item): self.items.insert(index, item) return item - + def insertItemAfter(self, after, item): try: idx = self.items.index(after) @@ -122,7 +122,7 @@ class BaseDef(object): except ValueError: self.items.append(item) return item - + def insertItemBefore(self, before, item): try: idx = self.items.index(before) @@ -131,7 +131,7 @@ class BaseDef(object): self.items.insert(0, item) return item - + def allItems(self): """ Recursively create a sequence for traversing all items in the @@ -147,10 +147,10 @@ class BaseDef(object): if hasattr(item, 'innerclasses'): for o in item.innerclasses: items.extend(o.allItems()) - + return items - - + + def findAll(self, name): """ Search recursivly for items that have the given name. @@ -160,8 +160,8 @@ class BaseDef(object): if item.name == name or item.pyName == name: matches.append(item) return matches - - + + def _findItems(self): # If there are more items to be searched than what is in self.items, a # subclass can override this to give a different list. @@ -179,12 +179,12 @@ class VariableDef(BaseDef): super(VariableDef, self).__init__() self.type = None self.definition = '' - self.argsString = '' + self.argsString = '' self.pyInt = False self.__dict__.update(**kw) if element is not None: self.extract(element) - + def extract(self, element): super(VariableDef, self).extract(element) self.type = flattenNode(element.find('type')) @@ -192,7 +192,7 @@ class VariableDef(BaseDef): self.argsString = element.find('argsstring').text - + #--------------------------------------------------------------------------- # These need the same attributes as VariableDef, but we use separate classes # so we can identify what kind of element it came from originally. @@ -225,7 +225,7 @@ class MemberVarDef(VariableDef): self.__dict__.update(kw) if element is not None: self.extract(element) - + def extract(self, element): super(MemberVarDef, self).extract(element) self.isStatic = element.get('static') == 'yes' @@ -236,7 +236,7 @@ class MemberVarDef(VariableDef): if self.protection == 'protected': self.ignore() - + #--------------------------------------------------------------------------- _globalIsCore = None @@ -261,14 +261,14 @@ class FunctionDef(BaseDef, FixWxPrefix): self.pyInt = False # treat char types as integers self.transfer = False # transfer ownership of return value to C++? self.transferBack = False # transfer ownership of return value from C++ to Python? - self.transferThis = False # ownership of 'this' pointer transfered to C++ + self.transferThis = False # ownership of 'this' pointer transfered to C++ self.cppCode = None # Use this code instead of the default wrapper self.noArgParser = False # set the NoargParser annotation self.__dict__.update(kw) if element is not None: self.extract(element) - - + + def extract(self, element): super(FunctionDef, self).extract(element) self.type = flattenNode(element.find('type')) @@ -281,45 +281,45 @@ class FunctionDef(BaseDef, FixWxPrefix): # parameter description items and assign that value as the # briefDoc for this ParamDef object. - + def releaseGIL(self, release=True): self.pyReleaseGIL = release - + def holdGIL(self, hold=True): self.pyHoldGIL = hold - + def setCppCode_sip(self, code): """ Use the given C++ code instead of that automatically generated by the back-end. This is similar to adding a new C++ method, except it uses info we've already received from the source XML such as the argument types and names, docstring, etc. - + The code generated for this verison will expect the given code to use SIP specfic variable names, etc. For example:: - + sipRes = sipCpp->Foo(); """ self.cppCode = (code, 'sip') - + def setCppCode(self, code): """ Use the given C++ code instead of that automatically generated by the back-end. This is similar to adding a new C++ method, except it uses info we've already received from the source XML such as the argument types and names, docstring, etc. - + The code generated for this version will put the given code in a wrapper function that will enable it to be more independent, not SIP specific, and also more natural. For example:: - + return self->Foo(); """ self.cppCode = (code, 'function') - + def checkForOverload(self, methods): for m in methods: if isinstance(m, FunctionDef) and m.name == self.name: @@ -328,11 +328,11 @@ class FunctionDef(BaseDef, FixWxPrefix): return True return False - + def all(self): return [self] + self.overloads - - + + def findOverload(self, matchText, isConst=None, printSig=False): """ Search for an overloaded method that has matchText in its C++ argsString. @@ -347,7 +347,7 @@ class FunctionDef(BaseDef, FixWxPrefix): if o.isConst == isConst: return o return None - + def hasOverloads(self): """ @@ -368,9 +368,9 @@ class FunctionDef(BaseDef, FixWxPrefix): else: parent = self.klass item = self.findOverload(matchText) - item.pyName = newName + item.pyName = newName item.__dict__.update(kw) - + if item is self and not self.hasOverloads(): # We're done, there actually is only one instance of this method pass @@ -385,18 +385,18 @@ class FunctionDef(BaseDef, FixWxPrefix): idx = parent.items.index(self) parent.items[idx] = first parent.insertItemAfter(first, self) - + else: # Just remove from the overloads list and insert it into the parent. self.overloads.remove(item) parent.insertItemAfter(self, item) return item - - + + def ignore(self, val=True): # In addition to ignoring this item, reorder any overloads to ensure # the primary overload is not ignored, if possible. - super(FunctionDef, self).ignore(val) + super(FunctionDef, self).ignore(val) if val and self.overloads: self.reorderOverloads() return self @@ -419,21 +419,21 @@ class FunctionDef(BaseDef, FixWxPrefix): idx = parent.items.index(self) parent.items[idx] = first - + def _findItems(self): items = list(self.items) for o in self.overloads: items.extend(o.items) return items - - + + def makePyArgsString(self): """ Create a pythonized version of the argsString in function and method items that can be used as part of the docstring. - + TODO: Maybe (optionally) use this syntax to document arg types? - http://www.python.org/dev/peps/pep-3107/ + http://www.python.org/dev/peps/pep-3107/ """ def _cleanName(name): for txt in ['const', '*', '&', ' ']: @@ -441,15 +441,15 @@ class FunctionDef(BaseDef, FixWxPrefix): name = name.replace('::', '.') name = self.fixWxPrefix(name, True) return name - + params = list() returns = list() if self.type and self.type != 'void': returns.append(_cleanName(self.type)) - + defValueMap = { 'true': 'True', 'false': 'False', - 'NULL': 'None', + 'NULL': 'None', 'wxString()': '""', 'wxArrayString()' : '[]', 'wxArrayInt()' : '[]', @@ -487,26 +487,26 @@ class FunctionDef(BaseDef, FixWxPrefix): returns.append(s) else: if param.inOut: - returns.append(s) + returns.append(s) if param.default: default = param.default if default in defValueMap: default = defValueMap.get(default) - + s += '=' + '|'.join([_cleanName(x) for x in default.split('|')]) params.append(s) - + self.pyArgsString = '(' + ', '.join(params) + ')' if len(returns) == 1: self.pyArgsString += ' -> ' + returns[0] if len(returns) > 1: self.pyArgsString += ' -> (' + ', '.join(returns) + ')' - + def collectPySignatures(self): """ Collect the pyArgsStrings for self and any overloads, and create a - list of function signatures for the docstrings. + list of function signatures for the docstrings. """ sigs = list() for f in [self] + self.overloads: @@ -515,16 +515,16 @@ class FunctionDef(BaseDef, FixWxPrefix): continue if not f.pyArgsString: f.makePyArgsString() - + sig = f.pyName or self.fixWxPrefix(f.name) if sig in magicMethods: sig = magicMethods[sig] sig += f.pyArgsString sigs.append(sig) return sigs - + #--------------------------------------------------------------------------- - + class MethodDef(FunctionDef): """ Represents a class method, ctor or dtor declaration. @@ -543,12 +543,12 @@ class MethodDef(FunctionDef): self.noDerivedCtor = False # don't generate a ctor in the derived class for this ctor self.cppSignature = None self.virtualCatcherCode = None - self.__dict__.update(kw) + self.__dict__.update(kw) if element is not None: self.extract(element) elif not hasattr(self, 'isCore'): self.isCore = _globalIsCore - + def extract(self, element): super(MethodDef, self).extract(element) @@ -565,8 +565,8 @@ class MethodDef(FunctionDef): if self.protection == 'protected': self.ignore() - - + + #--------------------------------------------------------------------------- @@ -590,7 +590,7 @@ class ParamDef(BaseDef): self.__dict__.update(kw) if element is not None: self.extract(element) - + def extract(self, element): try: self.type = flattenNode(element.find('type')) @@ -640,14 +640,14 @@ class ClassDef(BaseDef): self.innerclasses = [] self.isInner = False # Is this a nested class? self.klass = None # if so, then this is the outer class - + # Stuff that needs to be generated after the class instead of within # it. Some back-end generators need to put stuff inside the class, and # others need to do it outside the class definition. The generators # can move things here for later processing when they encounter those # items. - self.generateAfterClass = [] - + self.generateAfterClass = [] + self.__dict__.update(kw) if element is not None: self.extract(element) @@ -664,7 +664,7 @@ class ClassDef(BaseDef): def findHierarchy(self, element, all_classes, specials, read): from etgtools import XMLSRC - + if not read: fullname = self.name specials = [fullname] @@ -673,16 +673,16 @@ class ClassDef(BaseDef): baselist = [] - if read: + if read: refid = element.get('refid') if refid is None: return all_classes, specials - + fname = os.path.join(XMLSRC, refid+'.xml') root = et.parse(fname).getroot() compounds = findDescendants(root, 'basecompoundref') else: - compounds = element.findall('basecompoundref') + compounds = element.findall('basecompoundref') for c in compounds: baselist.append(c.text) @@ -701,16 +701,16 @@ class ClassDef(BaseDef): self.nodeBases = self.findHierarchy(element, {}, [], False) for node in element.findall('basecompoundref'): - self.bases.append(node.text) + self.bases.append(node.text) for node in element.findall('derivedcompoundref'): - self.subClasses.append(node.text) + self.subClasses.append(node.text) for node in element.findall('includes'): self.includes.append(node.text) for node in element.findall('templateparamlist/param'): txt = node.find('type').text txt = txt.replace('class ', '') self.templateParams.append(txt) - + for node in element.findall('innerclass'): if node.get('prot') == 'private': continue @@ -726,8 +726,8 @@ class ClassDef(BaseDef): item.isInner = True item.klass = self # This makes a reference cycle but it's okay self.innerclasses.append(item) - - + + # TODO: Is it possible for there to be memberdef's w/o a sectiondef? for node in element.findall('sectiondef/memberdef'): # skip any private items @@ -751,29 +751,29 @@ class ClassDef(BaseDef): continue else: raise ExtractorError('Unknown memberdef kind: %s' % kind) - - + + def _findItems(self): return self.items + self.innerclasses - + def addHeaderCode(self, code): if isinstance(code, list): self.headerCode.extend(code) else: self.headerCode.append(code) - + def addCppCode(self, code): if isinstance(code, list): self.cppCode.extend(code) else: self.cppCode.append(code) - + def includeCppCode(self, filename): self.addCppCode(textfile_open(filename).read()) - - + + def addAutoProperties(self): """ Look at MethodDef and PyMethodDef items and generate properties if @@ -794,7 +794,7 @@ class ClassDef(BaseDef): if arg != 'self': count += 1 return count - + def countPyNonDefaultArgs(item): count = 0 args = item.argsString.replace('(', '').replace(')', '') @@ -802,7 +802,7 @@ class ClassDef(BaseDef): if arg != 'self' and '=' not in arg: count += 1 return count - + props = dict() for item in self.items: if isinstance(item, (MethodDef, PyMethodDef)) \ @@ -824,7 +824,7 @@ class ClassDef(BaseDef): ok = True prop.setter = item.name prop.usesPyMethod = True - + else: # look at all overloads ok = False @@ -853,7 +853,7 @@ class ClassDef(BaseDef): if hasattr(prop, 'usesPyMethod'): prop = PyPropertyDef(prop.name, prop.getter, prop.setter) props[name] = prop - + if props: self.addPublic() for name, prop in sorted(props.items()): @@ -866,7 +866,7 @@ class ClassDef(BaseDef): starts_with_number = True except: pass - + # only create the prop if a method with that name does not exist, and it is a valid name if starts_with_number: print('WARNING: Invalid property name %s for class %s' % (name, self.name)) @@ -875,9 +875,9 @@ class ClassDef(BaseDef): else: self.items.append(prop) - - - + + + def addProperty(self, *args, **kw): """ Add a property to a class, with a name, getter function and optionally @@ -899,9 +899,9 @@ class ClassDef(BaseDef): p = PropertyDef(*args, **kw) self.items.append(p) return p - - - + + + def addPyProperty(self, *args, **kw): """ Add a property to a class that can use PyMethods that have been @@ -924,7 +924,7 @@ class ClassDef(BaseDef): return p #------------------------------------------------------------------ - + def _addMethod(self, md, overloadOkay=True): md.klass = self if overloadOkay and self.findItem(md.name): @@ -935,7 +935,7 @@ class ClassDef(BaseDef): self.items.append(md) - def addCppMethod(self, type, name, argsString, body, doc=None, isConst=False, + def addCppMethod(self, type, name, argsString, body, doc=None, isConst=False, cppSignature=None, overloadOkay=True, **kw): """ Add a new C++ method to a class. This method doesn't have to actually @@ -943,29 +943,29 @@ class ClassDef(BaseDef): back-end wrapper generator such that it is visible in the class in the target language. """ - md = CppMethodDef(type, name, argsString, body, doc, isConst, klass=self, + md = CppMethodDef(type, name, argsString, body, doc, isConst, klass=self, cppSignature=cppSignature, **kw) self._addMethod(md, overloadOkay) return md - - def addCppCtor(self, argsString, body, doc=None, noDerivedCtor=True, + + def addCppCtor(self, argsString, body, doc=None, noDerivedCtor=True, useDerivedName=False, cppSignature=None, **kw): """ Add a C++ method that is a constructor. """ - md = CppMethodDef('', self.name, argsString, body, doc=doc, - isCtor=True, klass=self, noDerivedCtor=noDerivedCtor, + md = CppMethodDef('', self.name, argsString, body, doc=doc, + isCtor=True, klass=self, noDerivedCtor=noDerivedCtor, useDerivedName=useDerivedName, cppSignature=cppSignature, **kw) self._addMethod(md) return md - + def addCppDtor(self, body, useDerivedName=False, **kw): """ Add a C++ method that is a destructor. """ - md = CppMethodDef('', '~'+self.name, '()', body, isDtor=True, klass=self, + md = CppMethodDef('', '~'+self.name, '()', body, isDtor=True, klass=self, useDerivedName=useDerivedName, **kw) self._addMethod(md) return md @@ -980,20 +980,20 @@ class ClassDef(BaseDef): self._addMethod(md) return md - def addCppCtor_sip(self, argsString, body, doc=None, noDerivedCtor=True, + def addCppCtor_sip(self, argsString, body, doc=None, noDerivedCtor=True, cppSignature=None, **kw): """ Add a C++ method that is a constructor. """ - md = CppMethodDef_sip('', self.name, argsString, body, doc=doc, - isCtor=True, klass=self, noDerivedCtor=noDerivedCtor, + md = CppMethodDef_sip('', self.name, argsString, body, doc=doc, + isCtor=True, klass=self, noDerivedCtor=noDerivedCtor, cppSignature=cppSignature, **kw) self._addMethod(md) return md #------------------------------------------------------------------ - - + + def addPyMethod(self, name, argsString, body, doc=None, **kw): """ Add a (monkey-patched) Python method to this class. @@ -1002,16 +1002,16 @@ class ClassDef(BaseDef): self.items.append(pm) return pm - + def addPyCode(self, code): """ Add a snippet of Python code which is to be associated with this class. - """ + """ pc = PyCodeDef(code, klass=self, protection = 'public') self.items.append(pc) return pc - + def addPublic(self, code=''): """ Adds a 'public:' protection keyword to the class, optionally followed @@ -1021,7 +1021,7 @@ class ClassDef(BaseDef): if code: text = text + '\n' + code self.addItem(WigCode(text)) - + def addProtected(self, code=''): """ Adds a 'protected:' protection keyword to the class, optionally followed @@ -1032,7 +1032,7 @@ class ClassDef(BaseDef): text = text + '\n' + code self.addItem(WigCode(text)) - + def addPrivate(self, code=''): """ Adds a 'private:' protection keyword to the class, optionally followed @@ -1043,7 +1043,7 @@ class ClassDef(BaseDef): text = text + '\n' + code self.addItem(WigCode(text)) - + def addCopyCtor(self, prot='protected'): # add declaration of a copy constructor to this class wig = WigCode("""\ @@ -1053,7 +1053,7 @@ class ClassDef(BaseDef): def addPrivateCopyCtor(self): self.addCopyCtor('private') - + def addPrivateAssignOp(self): # add declaration of an assignment opperator to this class wig = WigCode("""\ @@ -1096,14 +1096,14 @@ class EnumDef(BaseDef): self.ignore() self.extract(element) self.__dict__.update(kw) - + def extract(self, element): super(EnumDef, self).extract(element) for node in element.findall('enumvalue'): value = EnumValueDef(node) self.items.append(value) - - + + class EnumValueDef(BaseDef): @@ -1116,7 +1116,7 @@ class EnumValueDef(BaseDef): self.extract(element) self.__dict__.update(kw) - + #--------------------------------------------------------------------------- class DefineDef(BaseDef): @@ -1129,7 +1129,7 @@ class DefineDef(BaseDef): self.name = element.find('name').text self.value = flattenNode(element.find('initializer')) self.__dict__.update(kw) - + #--------------------------------------------------------------------------- @@ -1166,7 +1166,7 @@ class CppMethodDef(MethodDef): NOTE: This one is not automatically extracted, but can be added to classes in the tweaker stage """ - def __init__(self, type, name, argsString, body, doc=None, isConst=False, + def __init__(self, type, name, argsString, body, doc=None, isConst=False, cppSignature=None, virtualCatcherCode=None, **kw): super(CppMethodDef, self).__init__() self.type = type @@ -1197,8 +1197,8 @@ class CppMethodDef(MethodDef): m = CppMethodDef('', '', '', '') m.__dict__.update(method.__dict__) return m - - + + class CppMethodDef_sip(CppMethodDef): """ Just like the above, but instead of generating a new function from the @@ -1207,8 +1207,8 @@ class CppMethodDef_sip(CppMethodDef): beyond the general scope of the other C++ Method implementation. """ pass - - + + #--------------------------------------------------------------------------- class WigCode(BaseDef): @@ -1292,7 +1292,7 @@ class PyClassDef(BaseDef): self.__dict__.update(kw) self.nodeBases = self.findHierarchy() - + def findHierarchy(self): @@ -1307,8 +1307,8 @@ class PyClassDef(BaseDef): all_classes[base] = (base, []) return all_classes, specials - - + + #--------------------------------------------------------------------------- class PyMethodDef(PyFunctionDef): @@ -1321,7 +1321,7 @@ class PyMethodDef(PyFunctionDef): self.klass = klass self.protection = 'public' self.__dict__.update(kw) - + #--------------------------------------------------------------------------- class ModuleDef(BaseDef): @@ -1367,27 +1367,27 @@ class ModuleDef(BaseDef): elif isinstance(item, GlobalVarDef): three.append(item) # template instantiations go at the end - elif isinstance(item, TypedefDef) and '<' in item.type: + elif isinstance(item, TypedefDef) and '<' in item.type: three.append(item) - + else: one.append(item) self.items = one + two + three - + # give everything an isCore flag - global _globalIsCore + global _globalIsCore _globalIsCore = self.module == '_core' for item in self.allItems(): item.isCore = _globalIsCore - - + + def addHeaderCode(self, code): if isinstance(code, list): self.headerCode.extend(code) else: self.headerCode.append(code) - + def addCppCode(self, code): if isinstance(code, list): self.cppCode.extend(code) @@ -1396,38 +1396,38 @@ class ModuleDef(BaseDef): def includeCppCode(self, filename): self.addCppCode(textfile_open(filename).read()) - + def addInitializerCode(self, code): if isinstance(code, list): self.initializerCode.extend(code) else: self.initializerCode.append(code) - + def addPreInitializerCode(self, code): if isinstance(code, list): self.preInitializerCode.extend(code) else: self.preInitializerCode.append(code) - + def addPostInitializerCode(self, code): if isinstance(code, list): self.postInitializerCode.extend(code) else: self.postInitializerCode.append(code) - + def addInclude(self, name): if isinstance(name, list): self.includes.extend(name) else: self.includes.append(name) - + def addImport(self, name): if isinstance(name, list): self.imports.extend(name) else: self.imports.append(name) - - + + def addElement(self, element): item = None kind = element.get('kind') @@ -1446,27 +1446,27 @@ class ModuleDef(BaseDef): item = FunctionDef(element, module=self) if not item.checkForOverload(self.items): self.items.append(item) - + elif kind == 'enum': inClass = [] for el in self.items: if isinstance(el, ClassDef): inClass.append(el) - + extractingMsg(kind, element) item = EnumDef(element, inClass) self.items.append(item) - + elif kind == 'variable': extractingMsg(kind, element) item = GlobalVarDef(element) self.items.append(item) - elif kind == 'typedef': + elif kind == 'typedef': extractingMsg(kind, element) item = TypedefDef(element) self.items.append(item) - + elif kind == 'define': # if it doesn't have a value, it must be a macro. value = flattenNode(element.find("initializer")) @@ -1487,11 +1487,11 @@ class ModuleDef(BaseDef): else: raise ExtractorError('Unknown module item kind: %s' % kind) - + return item - - - + + + def addCppFunction(self, type, name, argsString, body, doc=None, **kw): """ Add a new C++ function into the module that is written by hand, not @@ -1501,7 +1501,7 @@ class ModuleDef(BaseDef): self.items.append(md) return md - + def addCppFunction_sip(self, type, name, argsString, body, doc=None, **kw): """ Add a new C++ function into the module that is written by hand, not @@ -1515,12 +1515,12 @@ class ModuleDef(BaseDef): def addPyCode(self, code, order=None): """ Add a snippet of Python code to the wrapper module. - """ + """ pc = PyCodeDef(code, order) self.items.append(pc) return pc - + def addGlobalStr(self, name, before=None): if self.findItem(name): self.findItem(name).ignore() @@ -1530,8 +1530,8 @@ class ModuleDef(BaseDef): else: self.insertItemBefore(before, gv) return gv - - + + def includePyCode(self, filename, order=None): """ Add a snippet of Python code from a file to the wrapper module. @@ -1539,7 +1539,7 @@ class ModuleDef(BaseDef): text = textfile_open(filename).read() return self.addPyCode( "#" + '-=' * 38 + '\n' + - ("# This code block was included from %s\n%s\n" % (filename, text)) + + ("# This code block was included from %s\n%s\n" % (filename, text)) + "# End of included code block\n" "#" + '-=' * 38 + '\n' , order @@ -1554,7 +1554,7 @@ class ModuleDef(BaseDef): self.items.append(pf) return pf - + def addPyClass(self, name, bases=[], doc=None, items=[], order=None, **kw): """ Add a pure Python class to this module. @@ -1562,9 +1562,9 @@ class ModuleDef(BaseDef): pc = PyClassDef(name, bases, doc, items, order, **kw) self.items.append(pc) return pc - - - + + + #--------------------------------------------------------------------------- # Some helper functions and such #--------------------------------------------------------------------------- @@ -1586,7 +1586,7 @@ def flattenNode(node, rstrip=True): text = node.text or "" for n in node: text += flattenNode(n, rstrip) - if node.tail: + if node.tail: text += node.tail if rstrip: text = text.rstrip() @@ -1604,7 +1604,7 @@ def prettifyNode(elem): from xml.dom import minidom rough_string = ElementTree.tostring(elem, 'utf-8') reparsed = minidom.parseString(rough_string) - return reparsed.toprettyxml(indent=" ") + return reparsed.toprettyxml(indent=" ") def appendText(node, text): @@ -1623,14 +1623,14 @@ def prependText(node, text): # If the node has text then just insert the new bti as a string if hasattr(node, 'text') and node.text: node.text = text + node.text - + # otherwise insert it as an element else: ele = makeTextElement(text) node.insert(0, ele) - - - + + + def makeTextElement(text): element = et.Element('para') element.text = text @@ -1655,7 +1655,7 @@ def _pf(item, indent): if '\n' in txt: txt = '\n' + txt return txt - + def verbose(): return '--verbose' in sys.argv @@ -1663,11 +1663,11 @@ def verbose(): def extractingMsg(kind, element, nameTag='name'): if verbose(): print('Extracting %s: %s' % (kind, element.find(nameTag).text)) - + def skippingMsg(kind, element): if verbose(): print('Skipping %s: %s' % (kind, element.find('name').text)) - - + + #--------------------------------------------------------------------------- diff --git a/etgtools/generators.py b/etgtools/generators.py index d4017e18..741e1fe8 100644 --- a/etgtools/generators.py +++ b/etgtools/generators.py @@ -17,18 +17,18 @@ import sys class WrapperGeneratorBase(object): def __init__(self): - pass + pass def generate(self, module, destFile=None): raise NotImplementedError - - + + class DocsGeneratorBase(object): def __init__(self): - pass + pass def generate(self, module): raise NotImplementedError - - + + class StubbedDocsGenerator(DocsGeneratorBase): def generate(self, module): pass @@ -44,7 +44,7 @@ class SphinxGenerator(DocsGeneratorBase): def nci(text, numSpaces=0, stripLeading=True): """ Normalize Code Indents - + First use the count of leading spaces on the first line and remove that many spaces from the front of all lines, and then indent each line by adding numSpaces spaces. This is used so we can convert the arbitrary @@ -59,20 +59,20 @@ def nci(text, numSpaces=0, stripLeading=True): break count += 1 return count - + def _allSpaces(text): for c in text: if c != ' ': return False return True - + lines = text.rstrip().split('\n') if stripLeading: numStrip = _getLeadingSpaceCount(lines[0]) else: numStrip = 0 - + for idx, line in enumerate(lines): assert _allSpaces(line[:numStrip]), "Indentation inconsistent with first line" lines[idx] = ' '*numSpaces + line[numStrip:] @@ -102,8 +102,8 @@ class Utf8EncodingStream(io.StringIO): if isinstance(text, str): text = text.decode('utf-8') return io.StringIO.write(self, text) - - + + def textfile_open(filename, mode='rt'): @@ -119,7 +119,7 @@ def textfile_open(filename, mode='rt'): return codecs.open(filename, mode, encoding='utf-8') else: return open(filename, mode, encoding='utf-8') - - + + #--------------------------------------------------------------------------- diff --git a/etgtools/pi_generator.py b/etgtools/pi_generator.py index a847d7da..b5b0fb5f 100644 --- a/etgtools/pi_generator.py +++ b/etgtools/pi_generator.py @@ -35,7 +35,7 @@ header_pi = """\ # -*- coding: utf-8 -*- #--------------------------------------------------------------------------- # This file is generated by wxPython's PI generator. Do not edit by hand. -# +# # The *.pi files are used by WingIDE to provide more information than it is # able to glean from introspection of extension types and methods. They are # not intended to be imported, executed or used for any other purpose other @@ -72,13 +72,13 @@ header_pyi = """\ #--------------------------------------------------------------------------- class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): - + def generate(self, module, destFile=None): stream = Utf8EncodingStream() - + # process the module object and its child objects self.generateModule(module, stream) - + # Write the contents of the stream to the destination file if not destFile: name = module.module @@ -115,14 +115,14 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): sectionEndLine = -1 sectionBeginMarker = '#-- begin-%s --#' % sectionName sectionEndMarker = '#-- end-%s --#' % sectionName - + lines = textfile_open(destFile, 'rt').readlines() for idx, line in enumerate(lines): if line.startswith(sectionBeginMarker): sectionBeginLine = idx if line.startswith(sectionEndMarker): sectionEndLine = idx - + if sectionBeginLine == -1: # not there already, add to the end lines.append(sectionBeginMarker + '\n') @@ -131,12 +131,12 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): else: # replace the existing lines lines[sectionBeginLine+1:sectionEndLine] = [sectionText] - + f = textfile_open(destFile, 'wt') f.writelines(lines) f.close() - - + + #----------------------------------------------------------------------- def generateModule(self, module, stream): @@ -145,14 +145,14 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): """ assert isinstance(module, extractors.ModuleDef) self.isCore = module.module == '_core' - + for item in module.imports: if item.startswith('_'): item = item[1:] if item == 'core': continue stream.write('import wx.%s\n' % item) - + # Move all PyCode items with an order value to the begining of the # list as they most likely should appear before everything else. pycode = list() @@ -162,7 +162,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): for item in pycode: module.items.remove(item) module.items = pycode + module.items - + methodMap = { extractors.ClassDef : self.generateClass, extractors.DefineDef : self.generateDefine, @@ -173,18 +173,18 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): extractors.WigCode : self.generateWigCode, extractors.PyCodeDef : self.generatePyCode, extractors.PyFunctionDef : self.generatePyFunction, - extractors.PyClassDef : self.generatePyClass, + extractors.PyClassDef : self.generatePyClass, extractors.CppMethodDef : self.generateCppMethod, extractors.CppMethodDef_sip : self.generateCppMethod_sip, } - + for item in module: if item.ignored: continue function = methodMap[item.__class__] function(item, stream) - + #----------------------------------------------------------------------- def generateEnum(self, enum, stream, indent=''): assert isinstance(enum, extractors.EnumDef) @@ -193,9 +193,9 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): for v in enum.items: if v.ignored: continue - name = v.pyName or v.name + name = v.pyName or v.name stream.write('%s%s = 0\n' % (indent, name)) - + #----------------------------------------------------------------------- def generateGlobalVar(self, globalVar, stream): assert isinstance(globalVar, extractors.GlobalVarDef) @@ -216,9 +216,9 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): valTyp = valTyp.replace(' ', '') valTyp = self.fixWxPrefix(valTyp) valTyp += '()' - + stream.write('%s = %s\n' % (name, valTyp)) - + #----------------------------------------------------------------------- def generateDefine(self, define, stream): assert isinstance(define, extractors.DefineDef) @@ -229,7 +229,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): stream.write('%s = ""\n' % (define.pyName or define.name)) else: stream.write('%s = 0\n' % (define.pyName or define.name)) - + #----------------------------------------------------------------------- def generateTypedef(self, typedef, stream, indent=''): assert isinstance(typedef, extractors.TypedefDef) @@ -241,20 +241,20 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): # ignore the typedef and return. if not ('<' in typedef.type and '>' in typedef.type) and not typedef.docAsClass: return - + # Otherwise write a mock class for it that combines the template and class. # First, extract the info we need. if typedef.docAsClass: bases = [self.fixWxPrefix(b, True) for b in typedef.bases] name = self.fixWxPrefix(typedef.name) - + elif '<' in typedef.type and '>' in typedef.type: t = typedef.type.replace('>', '') t = t.replace(' ', '') bases = t.split('<') bases = [self.fixWxPrefix(b, True) for b in bases] name = self.fixWxPrefix(typedef.name) - + # Now write the Python equivallent class for the typedef if not bases: bases = ['object'] # this should not happpen, but just in case... @@ -272,14 +272,14 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): def generateWigCode(self, wig, stream, indent=''): assert isinstance(wig, extractors.WigCode) # write nothing for this one - - + + #----------------------------------------------------------------------- def generatePyCode(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyCodeDef) code = pc.code if hasattr(pc, 'klass'): - code = code.replace(pc.klass.pyName+'.', '') + code = code.replace(pc.klass.pyName+'.', '') stream.write('\n') stream.write(nci(code, len(indent))) @@ -288,9 +288,9 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): assert isinstance(pf, extractors.PyFunctionDef) stream.write('\n') if pf.deprecated: - stream.write('%s@wx.deprecated\n' % indent) + stream.write('%s@wx.deprecated\n' % indent) if pf.isStatic: - stream.write('%s@staticmethod\n' % indent) + stream.write('%s@staticmethod\n' % indent) stream.write('%sdef %s%s:\n' % (indent, pf.name, pf.argsString)) indent2 = indent + ' '*4 if pf.briefDoc: @@ -298,11 +298,11 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): stream.write(nci(pf.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) stream.write('%spass\n' % indent2) - + #----------------------------------------------------------------------- def generatePyClass(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyClassDef) - + # write the class declaration and docstring if pc.deprecated: stream.write('%s@wx.deprecated\n' % indent) @@ -355,8 +355,8 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): stream.write(' """\n') stream.write(nci(function.pyDocstring, 4)) stream.write(' """\n') - - + + def generateParameters(self, parameters, stream, indent): def _lastParameter(idx): if idx == len(parameters)-1: @@ -365,7 +365,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): if not parameters[i].ignored: return False return True - + for idx, param in enumerate(parameters): if param.ignored: continue @@ -374,25 +374,25 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): stream.write('=%s' % param.default) if not _lastParameter(idx): stream.write(', ') - - + + #----------------------------------------------------------------------- def generateClass(self, klass, stream, indent=''): assert isinstance(klass, extractors.ClassDef) if klass.ignored: return - + # check if there is a pi-customized version of the base class names if hasattr(klass, 'piBases'): bases = klass.piBases - + else: # check if it's a template with the template parameter as the base class bases = klass.bases[:] for tp in klass.templateParams: if tp in bases: bases.remove(tp) - + # write class declaration klassName = klass.pyName or klass.name stream.write('\n%sclass %s' % (indent, klassName)) @@ -405,24 +405,24 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): stream.write('(object)') stream.write(':\n') indent2 = indent + ' '*4 - + # docstring stream.write('%s"""\n' % indent2) stream.write(nci(klass.pyDocstring, len(indent2))) stream.write('%s"""\n' % indent2) - + # generate nested classes for item in klass.innerclasses: self.generateClass(item, stream, indent2) - + # Split the items into public and protected groups - enums = [i for i in klass if - isinstance(i, extractors.EnumDef) and + enums = [i for i in klass if + isinstance(i, extractors.EnumDef) and i.protection == 'public'] - ctors = [i for i in klass if - isinstance(i, extractors.MethodDef) and + ctors = [i for i in klass if + isinstance(i, extractors.MethodDef) and i.protection == 'public' and (i.isCtor or i.isDtor)] - public = [i for i in klass if i.protection == 'public' and + public = [i for i in klass if i.protection == 'public' and i not in ctors and i not in enums] protected = [i for i in klass if i.protection == 'protected'] @@ -444,25 +444,25 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): item.klass = klass self.generateEnum(item, stream, indent2) - for item in ctors: + for item in ctors: if item.isCtor: item.klass = klass - self.generateMethod(item, stream, indent2, + self.generateMethod(item, stream, indent2, name='__init__', docstring=klass.pyDocstring) for item in public: item.klass = klass f = dispatch[item.__class__] f(item, stream, indent2) - + for item in protected: item.klass = klass f = dispatch[item.__class__] f(item, stream, indent2) stream.write('%s# end of class %s\n\n' % (indent, klassName)) - - + + def generateMemberVar(self, memberVar, stream, indent): assert isinstance(memberVar, extractors.MemberVarDef) if memberVar.ignored: @@ -494,7 +494,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): return if method.isDtor: return - + name = name or method.pyName or method.name if name in magicMethods: name = magicMethods[name] @@ -527,7 +527,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): stream.write(argsString) stream.write(':\n') indent2 = indent + ' '*4 - + # docstring if not docstring: if hasattr(method, 'pyDocstring'): @@ -538,8 +538,8 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): if docstring.strip(): stream.write(nci(docstring, len(indent2))) stream.write('%s"""\n' % indent2) - - + + def generateCppMethod(self, method, stream, indent=''): assert isinstance(method, extractors.CppMethodDef) @@ -549,7 +549,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): def generateCppMethod_sip(self, method, stream, indent=''): assert isinstance(method, extractors.CppMethodDef_sip) self.generateMethod(method, stream, indent) - + def generatePyMethod(self, pm, stream, indent): assert isinstance(pm, extractors.PyMethodDef) @@ -565,9 +565,9 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase, FixWxPrefix): stream.write('%s"""\n' % indent2) stream.write(nci(pm.pyDocstring, len(indent2))) stream.write('%s"""\n' % indent2) - - - - + + + + #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- diff --git a/etgtools/sip_generator.py b/etgtools/sip_generator.py index cdab8b1f..2c0edcd1 100644 --- a/etgtools/sip_generator.py +++ b/etgtools/sip_generator.py @@ -32,27 +32,27 @@ class SipGeneratorError(RuntimeError): # This is a list of types that are used as return by value or by reference # function return types that we need to ensure are actually using pointer # types in their CppMethodDef or cppCode wrappers. -forcePtrTypes = [ 'wxString', +forcePtrTypes = [ 'wxString', ] #--------------------------------------------------------------------------- class SipWrapperGenerator(generators.WrapperGeneratorBase): - + def generate(self, module, destFile=None): stream = Utf8EncodingStream() - + # generate SIP code from the module and its objects self.generateModule(module, stream) - + # Write the contents of the stream to the destination file if not destFile: destFile = os.path.join(phoenixRoot, 'sip/gen', module.name + '.sip') f = textfile_open(destFile, 'wt') f.write(stream.getvalue()) f.close() - - + + #----------------------------------------------------------------------- def generateModule(self, module, stream): assert isinstance(module, extractors.ModuleDef) @@ -60,15 +60,15 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase): # write the file header stream.write(divider + """\ // This file is generated by wxPython's SIP generator. Do not edit by hand. -// +// // Copyright: (c) 2011-2016 by Total Control Software // License: wxWindows License """) if module.name == module.module: stream.write(""" -%%Module( name=%s.%s, +%%Module( name=%s.%s, keyword_arguments="All", - use_argument_names=True, + use_argument_names=True, all_raise_py_exception=True, language="C++") { @@ -91,7 +91,7 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase): stream.write("""\ %%Extract(id=pycode%s, order=5) # This file is generated by wxPython's SIP generator. Do not edit by hand. -# +# # Copyright: (c) 2011-2016 by Total Control Software # License: wxWindows License %s @@ -100,20 +100,20 @@ from .%s import * %%End """ % ( module.name, doc, module.name)) - + else: stream.write("//\n// This file will be included by %s.sip\n//\n" % module.module) - + stream.write(divider) self.module_name = module.module - # C++ code to be written to the module's header + # C++ code to be written to the module's header if module.headerCode: stream.write("\n%ModuleHeaderCode\n") for c in module.headerCode: stream.write('%s\n' % c) stream.write("%End\n\n") - + # %Imports and %Includes if module.imports: for i in module.imports: @@ -123,7 +123,7 @@ from .%s import * for i in module.includes: stream.write("%%Include %s.sip\n" % i) stream.write("\n") - + # C++ code to be written out to the generated module if module.cppCode: stream.write("%ModuleCode\n") @@ -132,31 +132,31 @@ from .%s import * stream.write("%End\n") stream.write('\n%s\n' % divider) - + # Now generate each of the items in the module self.generateModuleItems(module, stream) - + # Add code for the module initialization sections. if module.preInitializerCode: stream.write('\n%s\n\n%%PreInitialisationCode\n' % divider) for i in module.preInitializerCode: stream.write('%s\n' % i) - stream.write('%End\n') + stream.write('%End\n') if module.initializerCode: stream.write('\n%s\n\n%%InitialisationCode\n' % divider) for i in module.initializerCode: stream.write('%s\n' % i) - stream.write('%End\n') + stream.write('%End\n') if module.postInitializerCode: stream.write('\n%s\n\n%%PostInitialisationCode\n' % divider) for i in module.postInitializerCode: stream.write('%s\n' % i) - stream.write('%End\n') - + stream.write('%End\n') + stream.write('\n%s\n' % divider) - - - + + + def generateModuleItems(self, module, stream): methodMap = { extractors.ClassDef : self.generateClass, @@ -172,14 +172,14 @@ from .%s import * extractors.CppMethodDef : self.generateCppMethod, extractors.CppMethodDef_sip : self.generateCppMethod_sip, } - + for item in module: if item.ignored: continue function = methodMap[item.__class__] function(item, stream) - - + + #----------------------------------------------------------------------- def generateFunction(self, function, stream, _needDocstring=True): assert isinstance(function, extractors.FunctionDef) @@ -206,9 +206,9 @@ from .%s import * raise NotImplementedError() # TODO: See generateMethod for an example, refactor to share code... for f in function.overloads: self.generateFunction(f, stream, _needDocstring) - stream.write('\n') + stream.write('\n') + - def generateParameters(self, parameters, stream, indent): def _lastParameter(idx): if idx == len(parameters)-1: @@ -217,7 +217,7 @@ from .%s import * if not parameters[i].ignored: return False return True - + for idx, param in enumerate(parameters): if param.ignored: continue @@ -229,8 +229,8 @@ from .%s import * if not _lastParameter(idx): stream.write(',') stream.write('\n') - - + + #----------------------------------------------------------------------- def generateEnum(self, enum, stream, indent=''): assert isinstance(enum, extractors.EnumDef) @@ -247,8 +247,8 @@ from .%s import * values.append("%s %s%s" % (indent, v.name, self.annotate(v))) stream.write(',\n'.join(values)) stream.write('%s\n%s};\n\n' % (indent, indent)) - - + + #----------------------------------------------------------------------- def generateGlobalVar(self, globalVar, stream): assert isinstance(globalVar, extractors.GlobalVarDef) @@ -257,14 +257,14 @@ from .%s import * stream.write('%s %s' % (globalVar.type, globalVar.name)) stream.write('%s;\n\n' % self.annotate(globalVar)) - + #----------------------------------------------------------------------- def generateDefine(self, define, stream): assert isinstance(define, extractors.DefineDef) if define.ignored: return - # We're assuming that the #define is either an integer or a string value, + # We're assuming that the #define is either an integer or a string value, # so tell sip that's what it is. if '"' in define.value: stream.write('const char* %s;\n' % define.name) @@ -274,14 +274,14 @@ from .%s import * stream.write('%PostInitialisationCode\n') #stream.write('printf("**** %s: %%d\\n", %s);\n' % (define.name, define.name)) stream.write((' PyDict_SetItemString(sipModuleDict, "%s", ' - 'wxPyInt_FromLong(static_cast(%s)));\n') % + 'wxPyInt_FromLong(static_cast(%s)));\n') % (define.pyName, define.name)) - stream.write('%End\n') + stream.write('%End\n') else: stream.write('const int %s;\n' % define.name) - - + + #----------------------------------------------------------------------- def generateTypedef(self, typedef, stream, indent=''): assert isinstance(typedef, extractors.TypedefDef) @@ -289,15 +289,15 @@ from .%s import * return stream.write('%stypedef %s %s' % (indent, typedef.type, typedef.name)) stream.write('%s;\n\n' % self.annotate(typedef)) - - + + #----------------------------------------------------------------------- def generateWigCode(self, wig, stream, indent=''): assert isinstance(wig, extractors.WigCode) stream.write(nci(wig.code, len(indent), False)) stream.write('\n\n') - - + + #----------------------------------------------------------------------- def generatePyCode(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyCodeDef) @@ -314,7 +314,7 @@ from .%s import * if len(indent) == 0: stream.write('\n%End\n\n') - + #----------------------------------------------------------------------- def generatePyProperty(self, prop, stream, indent=''): assert isinstance(prop, extractors.PyPropertyDef) @@ -338,7 +338,7 @@ from .%s import * setter = prop.setter else: setter = '%s.%s' % (klassName, prop.setter) - + stream.write("%%Extract(id=pycode%s)\n" % self.module_name) stream.write("%s.%s = property(%s" % (klassName, prop.name, getter)) if prop.setter: @@ -372,8 +372,8 @@ from .%s import * if len(indent) == 0: stream.write('\n%End\n') stream.write('\n') - - + + #----------------------------------------------------------------------- def generatePyClass(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyClassDef) @@ -411,18 +411,18 @@ from .%s import * item.klass = pc f = dispatch[item.__class__] f(item, stream, indent2) - + if len(indent) == 0: stream.write('\n%End\n') stream.write('\n') - - + + #----------------------------------------------------------------------- def generateClass(self, klass, stream, indent=''): assert isinstance(klass, extractors.ClassDef) if klass.ignored: return - + # write the class header if klass.templateParams: stream.write('%stemplate<%s>\n' % (indent, ', '.join(klass.templateParams))) @@ -443,20 +443,20 @@ from .%s import * stream.write('%s #include <%s>\n' % (indent2, inc)) stream.write('%s%%End\n\n' % indent2) - # C++ code to be written to the Type's header + # C++ code to be written to the Type's header if klass.headerCode: stream.write("%s%%TypeHeaderCode\n" % indent2) for c in klass.headerCode: stream.write(nci(c, len(indent2)+4)) stream.write("%s%%End\n" % indent2) - + # C++ code to be written out to the this Type's wrapper code module if klass.cppCode: stream.write("%s%%TypeCode\n" % indent2) for c in klass.cppCode: stream.write(nci(c, len(indent2)+4)) stream.write("%s%%End\n" % indent2) - + # C++ code to create a new instance of this class if klass.instanceCode: stream.write("%s%%InstanceCode\n" % indent2) @@ -464,19 +464,19 @@ from .%s import * stream.write("%s%%End\n" % indent2) # is the generator currently inside the class or after it? - klass.generatingInClass = True + klass.generatingInClass = True # Split the items into public and protected groups - ctors = [i for i in klass if - isinstance(i, extractors.MethodDef) and + ctors = [i for i in klass if + isinstance(i, extractors.MethodDef) and i.protection == 'public' and (i.isCtor or i.isDtor)] - enums = [i for i in klass if - isinstance(i, extractors.EnumDef) and + enums = [i for i in klass if + isinstance(i, extractors.EnumDef) and i.protection == 'public'] public = [i for i in klass if i.protection == 'public' and i not in ctors+enums] protected = [i for i in klass if i.protection == 'protected'] private = [i for i in klass if i.protection == 'private'] - + if klass.kind == 'class': stream.write('%spublic:\n' % indent) @@ -484,18 +484,18 @@ from .%s import * # methods or in nested classes for item in enums: self.dispatchClassItem(klass, item, stream, indent2) - + # Next do inner classes for item in klass.innerclasses: if klass.kind == 'class': stream.write('%s%s:\n' % (indent, item.protection)) item.klass = klass self.generateClass(item, stream, indent2) - + # and then the ctors and the rest of the items in the class for item in ctors: self.dispatchClassItem(klass, item, stream, indent2) - + for item in public: self.dispatchClassItem(klass, item, stream, indent2) @@ -518,16 +518,16 @@ from .%s import * self.generateConvertCode('%ConvertFromTypeCode', klass.convertToPyObject, stream, indent + ' '*4) - + stream.write('%s}; // end of class %s\n\n\n' % (indent, klass.name)) - + # Now generate anything that was deferred until after the class is finished klass.generatingInClass = False for item in klass.generateAfterClass: self.dispatchClassItem(klass, item, stream, indent) - - + + def dispatchClassItem(self, klass, item, stream, indent): dispatch = { extractors.TypedefDef : self.generateTypedef, @@ -551,8 +551,8 @@ from .%s import * stream.write('%s%s\n' % (indent, kind)) stream.write(nci(code, len(indent)+4)) stream.write('%s%%End\n' % indent) - - + + def generateMemberVar(self, memberVar, stream, indent): assert isinstance(memberVar, extractors.MemberVarDef) if memberVar.ignored: @@ -560,7 +560,7 @@ from .%s import * stream.write('%s%s %s' % (indent, memberVar.type, memberVar.name)) stream.write('%s;\n\n' % self.annotate(memberVar)) - + def generateProperty(self, prop, stream, indent): assert isinstance(prop, extractors.PropertyDef) if prop.ignored: @@ -572,18 +572,18 @@ from .%s import * if prop.briefDoc: stream.write(' // %s' % prop.briefDoc) stream.write('\n') - - + + def generateDocstring(self, item, stream, indent): item.pyDocstring = "" - + if item.name.startswith('operator'): return # Apparently sip doesn't like operators to have docstrings... - + # get the docstring text text = nci(extractors.flattenNode(item.briefDoc, False)) - text = wrapText(text) - + text = wrapText(text) + #if isinstance(item, extractors.ClassDef): # # append the function signatures for the class constructors (if any) to the class' docstring @@ -596,12 +596,12 @@ from .%s import * # pass #else: # # Prepend function signature string(s) for functions and methods - # sigs = item.collectPySignatures() + # sigs = item.collectPySignatures() # if sigs: # if text: # text = '\n\n' + text # text = '\n'.join(sigs) + text - + sigs = None if isinstance(item, extractors.ClassDef): try: @@ -610,12 +610,12 @@ from .%s import * except extractors.ExtractorError: pass else: - sigs = item.collectPySignatures() + sigs = item.collectPySignatures() if sigs: if text: text = '\n\n' + text text = '\n'.join(sigs) + text - + # write the docstring directive and the text stream.write('%s%%Docstring\n' % indent) stream.write(nci(text, len(indent)+4)) @@ -625,7 +625,7 @@ from .%s import * # generators later on item.pyDocstring = nci(text) - + def generateMethod(self, method, stream, indent): assert isinstance(method, extractors.MethodDef) _needDocstring = getattr(method, '_needDocstring', True) @@ -648,17 +648,17 @@ from .%s import * stream.write(' const') if method.isPureVirtual: stream.write(' = 0') - cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" + cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" if cppSig: stream.write(cppSig) stream.write('%s;\n' % self.annotate(method)) - + if _needDocstring and not (method.isCtor or method.isDtor): self.generateDocstring(method, stream, indent) # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False - + if method.cppCode: #checkOverloads = False ## SIP now allows overloads to have %MethodCode code, codeType = method.cppCode @@ -674,25 +674,25 @@ from .%s import * # and virtual catcher code, so we can just return from # here. return - + if method.virtualCatcherCode: stream.write('%s%%VirtualCatcherCode\n' % indent) stream.write(nci(method.virtualCatcherCode, len(indent)+4)) stream.write('%s%%End\n' % indent) - + stream.write('\n') - + if checkOverloads and method.overloads: for m in method.overloads: m._needDocstring = _needDocstring self.dispatchClassItem(method.klass, m, stream, indent) - + def generateCppMethod(self, method, stream, indent='', skipDeclaration=False): # Add a new C++ method to a class. This one adds the code as a # separate function and then adds a call to that function in the # MethodCode directive. - + def _removeIgnoredParams(argsString, paramList): # if there are ignored parameters adjust the argsString to match lastP = argsString.rfind(')') @@ -702,7 +702,7 @@ from .%s import * args[idx] = '' args = [a for a in args if a != ''] return '(' + ', '.join(args) + ')' - + assert isinstance(method, extractors.CppMethodDef) if method.ignored: return @@ -713,40 +713,40 @@ from .%s import * pnames = argsString[:lastP].strip('()').split(',') for idx, pn in enumerate(pnames): # take only the part before the =, if there is one - name = pn.split('=')[0].strip() + name = pn.split('=')[0].strip() # remove annotations - name = re.sub('/[A-Za-z]*/', '', name) + name = re.sub('/[A-Za-z]*/', '', name) name = name.strip() # now get just the part after any space, * or &, which should be # the parameter name - name = re.split(r'[ \*\&]+', name)[-1] + name = re.split(r'[ \*\&]+', name)[-1] pnames[idx] = name pnames = ', '.join(pnames) typ = method.type if not skipDeclaration: - cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" + cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" # First insert the method declaration if method.isCtor or method.isDtor: virtual = 'virtual ' if method.isVirtual else '' - stream.write('%s%s%s%s%s%s;\n' % + stream.write('%s%s%s%s%s%s;\n' % (indent, virtual, method.name, argsString, self.annotate(method), cppSig)) else: constMod = " const" if method.isConst else "" static = "static " if method.isStatic else "" - virtual = "virtual " if method.isVirtual else "" + virtual = "virtual " if method.isVirtual else "" pure = " = 0" if method.isPureVirtual else "" - stream.write('%s%s%s%s %s%s%s%s%s%s;\n' % - (indent, static, virtual, typ, + stream.write('%s%s%s%s %s%s%s%s%s%s;\n' % + (indent, static, virtual, typ, method.name, argsString, constMod, pure, self.annotate(method), cppSig)) - + # write the docstring if _needDocstring and not (method.isCtor or method.isDtor): self.generateDocstring(method, stream, indent) # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False - + klass = method.klass if klass: assert isinstance(klass, extractors.ClassDef) @@ -757,7 +757,7 @@ from .%s import * fargs = argsString[:lastP].strip('()').split(',') for idx, arg in enumerate(fargs): # take only the part before the =, if there is one - arg = arg.split('=')[0].strip() + arg = arg.split('=')[0].strip() arg = arg.replace('&', '*') # SIP will always want to use pointers for parameters arg = re.sub('/[A-Za-z]*/', '', arg) # remove annotations fargs[idx] = arg @@ -774,7 +774,7 @@ from .%s import * fstream.write(nci(method.body, len(indent)+4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) - + elif method.isDtor: fname = '_%s_dtor' % klass.name fargs = '(%s* self)' % klass.name @@ -783,7 +783,7 @@ from .%s import * fstream.write(nci(method.body, len(indent)+4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) - + else: if klass: fname = '_%s_%s' % (klass.name, method.name) @@ -803,7 +803,7 @@ from .%s import * fname = '_%s_function' % method.name fargs = '(%s)' % fargs fstream.write('%s%%ModuleCode\n' % indent) - + # If the return type is in the forcePtrTypes list then make sure # that it is a pointer, not a return by value or reference, since # SIP almost always deals with pointers to newly allocated @@ -814,7 +814,7 @@ from .%s import * typPtr.replace('&', '*') elif '*' not in typPtr: typPtr += '*' - + fstream.write('%s%s %s%s\n%s{\n' % (indent, typPtr, fname, fargs, indent)) fstream.write(nci(method.body, len(indent)+4)) fstream.write('%s}\n' % indent) @@ -827,14 +827,14 @@ from .%s import * # _THREAD macros are intentionally not used in this case stream.write('PyErr_Clear();\n') stream.write('%ssipCpp = %s(%s);\n' % (indent+' '*4, fname, pnames)) - + elif method.isDtor: stream.write('PyErr_Clear();\n') stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent+' '*4)) stream.write(indent+' '*4) stream.write('%s(sipCpp);\n' % fname) - stream.write('%sPy_END_ALLOW_THREADS\n' % (indent+' '*4)) - + stream.write('%sPy_END_ALLOW_THREADS\n' % (indent+' '*4)) + else: stream.write('PyErr_Clear();\n') stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent+' '*4)) @@ -852,7 +852,7 @@ from .%s import * stream.write('%s(sipCpp%s);\n' % (fname, pnames)) else: stream.write('%s(%s);\n' % (fname, pnames)) - stream.write('%sPy_END_ALLOW_THREADS\n' % (indent+' '*4)) + stream.write('%sPy_END_ALLOW_THREADS\n' % (indent+' '*4)) stream.write('%sif (PyErr_Occurred()) sipIsErr = 1;\n' % (indent+' '*4)) stream.write('%s%%End\n' % indent) @@ -860,7 +860,7 @@ from .%s import * stream.write('%s%%VirtualCatcherCode\n' % indent) stream.write(nci(method.virtualCatcherCode, len(indent)+4)) stream.write('%s%%End\n' % indent) - + # and finally, add the new function itself stream.write(fstream.getvalue()) stream.write('\n') @@ -869,29 +869,29 @@ from .%s import * for m in method.overloads: m._needDocstring = _needDocstring self.dispatchClassItem(method.klass, m, stream, indent) - - + + def generateCppMethod_sip(self, method, stream, indent=''): # Add a new C++ method to a class without the extra generated # function, so SIP specific stuff can be done in the function body. assert isinstance(method, extractors.CppMethodDef_sip) if method.ignored: return - cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" + cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" if method.isCtor: - stream.write('%s%s%s%s%s;\n' % + stream.write('%s%s%s%s%s;\n' % (indent, method.name, method.argsString, self.annotate(method), cppSig)) else: - stream.write('%s%s %s%s%s%s;\n' % - (indent, method.type, method.name, method.argsString, + stream.write('%s%s %s%s%s%s;\n' % + (indent, method.type, method.name, method.argsString, self.annotate(method), cppSig)) stream.write('%s%%MethodCode\n' % indent) stream.write(nci(method.body, len(indent)+4)) stream.write('%s%%End\n\n' % indent) - - + + def generatePyMethod(self, pm, stream, indent): assert isinstance(pm, extractors.PyMethodDef) if pm.ignored: @@ -943,7 +943,7 @@ from .%s import * annotations.append('ArraySize') if item.keepReference: annotations.append('KeepReference') - + if isinstance(item, (extractors.ParamDef, extractors.FunctionDef)): if item.transfer: annotations.append('Transfer') @@ -953,7 +953,7 @@ from .%s import * annotations.append('TransferThis') if item.pyInt: annotations.append('PyInt') - + if isinstance(item, extractors.VariableDef): if item.pyInt: annotations.append('PyInt') @@ -967,21 +967,21 @@ from .%s import * annotations.append('Deprecated') if item.factory: annotations.append('Factory') - if item.pyReleaseGIL: + if item.pyReleaseGIL: annotations.append('ReleaseGIL') - if item.pyHoldGIL: + if item.pyHoldGIL: annotations.append('HoldGIL') if item.noCopy: annotations.append('NoCopy') if item.noArgParser: annotations.append('NoArgParser') - + if isinstance(item, extractors.MethodDef): if item.defaultCtor: annotations.append('Default') if item.noDerivedCtor: annotations.append('NoDerived') - + if isinstance(item, extractors.ClassDef): if item.abstract: annotations.append('Abstract') @@ -995,7 +995,7 @@ from .%s import * annotations.append('NoDefaultCtors') if item.singlton: annotations.append('DelayDtor') - + if annotations: return ' /%s/' % ', '.join(annotations) else: diff --git a/etgtools/sphinx_generator.py b/etgtools/sphinx_generator.py index 855ac9d2..2d0ac05c 100644 --- a/etgtools/sphinx_generator.py +++ b/etgtools/sphinx_generator.py @@ -26,7 +26,7 @@ if sys.version_info < (3, ): else: from io import StringIO string_base = str - + import xml.etree.ElementTree as et # Phoenix-specific stuff @@ -79,12 +79,12 @@ class Node(object): self.element = element self.parent = parent - + self.children = [] if parent is not None: parent.Add(self) - + # ----------------------------------------------------------------------- @@ -123,7 +123,7 @@ class Node(object): parent = self.parent while 1: - + if parent is None: return @@ -131,8 +131,8 @@ class Node(object): return parent parent = parent.parent - - + + # ----------------------------------------------------------------------- def GetTag(self, tag_name): @@ -147,7 +147,7 @@ class Node(object): if isinstance(self.element, string_base): return None - + return self.element.get(tag_name) @@ -188,7 +188,7 @@ class Node(object): if top_level is None: return '' - + xml_docs = top_level.xml_docs if xml_docs.kind != 'class': @@ -196,7 +196,7 @@ class Node(object): dummy, class_name = wx2Sphinx(xml_docs.class_name) return class_name - + # ----------------------------------------------------------------------- @@ -212,21 +212,21 @@ class Node(object): :rtype: `bool` .. note:: This is a recursive method. - + """ - + if node is None: node = self - + for child in node.children: if isinstance(child, klass): return True - return self.Find(klass, child) + return self.Find(klass, child) + + return False - return False - # ----------------------------------------------------------------------- @@ -235,12 +235,12 @@ class Node(object): hierarchy = self.GetHierarchy() if 'ParameterList' in hierarchy: return ' ' - + elif not isinstance(self, ListItem) and 'List' in hierarchy: return ' '*2 - + return '' - + # ----------------------------------------------------------------------- @@ -266,7 +266,7 @@ class Node(object): if self.element is None: return text - + if isinstance(self.element, string_base): text = self.element else: @@ -277,20 +277,20 @@ class Node(object): for link in REMOVED_LINKS: if link in text.strip(): return '' - + text = convertToPython(text) for child in self.children: text += child.Join(with_tail) - + if with_tail and tail: text += convertToPython(tail) if text.strip() and not text.endswith('\n'): text += ' ' - + return text - + # ----------------------------------------------------------------------- # @@ -316,10 +316,10 @@ class Root(Node): Node.__init__(self, '', None) - self.xml_docs = xml_docs + self.xml_docs = xml_docs self.is_overload = is_overload self.share_docstrings = share_docstrings - + self.sections = ODict() @@ -332,7 +332,7 @@ class Root(Node): """ insert_at = -1 - + for index, child in enumerate(self.children): if (before and child.Find(before)) or (after and child.Find(after)): insert_at = index @@ -352,7 +352,7 @@ class Root(Node): return False return True - + # ----------------------------------------------------------------------- @@ -397,7 +397,7 @@ class Root(Node): raise Exception('Unconverted sections remain: %s'%(', '.join(existing_sections))) return text - + # ----------------------------------------------------------------------- @@ -414,15 +414,15 @@ class Root(Node): .. note:: This is a recursive method. """ - + for child in node.children: if isinstance(child, (ParameterList, Section)): docstrings += child.Join() - + docstrings = self.CommonJoin(child, docstrings) return docstrings - + # ----------------------------------------------------------------------- @@ -436,17 +436,17 @@ class Root(Node): than in wxWidgets or when the XML docs are a mess and an admonition ends up into a tail of an xml element... - :param Section `section`: an instance of :class:`Section`. - + :param Section `section`: an instance of :class:`Section`. + """ kind = section.section_type - + if kind == 'return': self.sections[kind] = [section] elif kind == 'available': - + if kind not in self.sections: text = section.element.text @@ -457,7 +457,7 @@ class Root(Node): newtext = ', '.join(newtext) newtext = 'Only available for %s'%newtext - + if section.element.tail and section.element.tail.strip(): newtext += ' ' + section.element.tail.strip() + ' ' else: @@ -470,33 +470,33 @@ class Root(Node): prevsection = self.sections[kind][0] prevtext = prevsection.element.text - + currtext = section.element.text pos = 1000 if '.' in currtext: pos = currtext.index('.') - + if currtext and currtext.strip(): prevtext = prevtext + currtext[pos+1:].strip() prevsection.element.text = prevtext self.sections[kind] = [prevsection] - + else: if kind not in self.sections: self.sections[kind] = [] self.sections[kind].append(section) - + # ----------------------------------------------------------------------- # class ParameterList(Node): """ This class holds information about XML elements with a ```` tag. - """ + """ # ----------------------------------------------------------------------- @@ -513,18 +513,18 @@ class ParameterList(Node): """ Node.__init__(self, element, parent) - + self.xml_item = xml_item self.kind = kind - self.checked = False + self.checked = False self.py_parameters = ODict() - + for pdef in xml_item.items: - name = pdef.name + name = pdef.name parameter = Parameter(self, pdef) self.py_parameters[name] = parameter - + # ----------------------------------------------------------------------- @@ -540,10 +540,10 @@ class ParameterList(Node): .. note:: Very often the list of parameters in wxWidgets does not match the Phoenix Python signature, as some of the parameters in Python get merged into one or removed altogether. - """ + """ name = element_name.strip() - + if name in self.py_parameters: return self.py_parameters[name] @@ -564,23 +564,23 @@ class ParameterList(Node): for which the function signature does not match the parameter list (see, for example, the `shortName` parameter in the signature against the `name` in the parameter list). - These kind of mismatches can sometimes break the ReST docstrings. + These kind of mismatches can sometimes break the ReST docstrings. """ if self.checked: return - self.checked = True + self.checked = True xml_item = self.xml_item if isinstance(xml_item, (extractors.PyFunctionDef, extractors.CppMethodDef)): return - + name = xml_item.pyName if xml_item.pyName else removeWxPrefix(xml_item.name) parent = self.GetTopLevelParent() is_overload = parent.is_overload if parent else False - + if xml_item.hasOverloads() and not is_overload: return @@ -593,7 +593,7 @@ class ParameterList(Node): return arguments = arguments[1:] - + if '->' in arguments: arguments, dummy = arguments.split("->") @@ -606,7 +606,7 @@ class ParameterList(Node): if arguments.endswith(')'): arguments = arguments[0:-1] - signature = name + '(%s)'%arguments + signature = name + '(%s)'%arguments arguments = arguments.split(',') py_parameters = [] @@ -616,7 +616,7 @@ class ParameterList(Node): continue py_parameters.append(key) - + message = '\nSEVERE: Incompatibility between function/method signature and list of parameters in `%s`:\n\n' \ 'The parameter `%s` appears in the method signature but could not be found in the parameter list.\n\n' \ ' ==> Function/Method signature from `extractors`: %s\n' \ @@ -624,7 +624,7 @@ class ParameterList(Node): 'This may be a documentation bug in wxWidgets or a side-effect of removing the `wx` prefix from signatures.\n\n' theargs = [] - + for arg in arguments: myarg = arg.split('=')[0].strip() @@ -633,7 +633,7 @@ class ParameterList(Node): if '*' in arg or ')' in arg: continue - + arg = arg.split('=')[0].strip() if arg and arg not in py_parameters: @@ -654,7 +654,7 @@ class ParameterList(Node): ## fid = open('mismatched.txt', 'a') ## fid.write('%s;%s;%s\n'%(class_name[0:-1], signature, param)) ## fid.close() - + # ----------------------------------------------------------------------- @@ -677,11 +677,11 @@ class ParameterList(Node): """ docstrings = '' - + for name, parameter in list(self.py_parameters.items()): pdef = parameter.pdef - + if pdef.out or pdef.ignored: continue @@ -693,7 +693,7 @@ class ParameterList(Node): docstrings += ':type `%s`: %s\n'%(name, parameter.type) else: docstrings += ':param `%s`: %s\n'%(name, parameter.Join().lstrip('\n')) - + if docstrings: docstrings = '\n\n\n%s\n\n'%docstrings @@ -701,17 +701,17 @@ class ParameterList(Node): for child in self.children: if not isinstance(child, Parameter): docstrings += child.Join() + '\n\n' - - return docstrings - + return docstrings + + # ----------------------------------------------------------------------- # class Parameter(Node): """ This class holds information about XML elements with ```` ```` tags. - """ + """ # ----------------------------------------------------------------------- @@ -724,19 +724,19 @@ class Parameter(Node): """ Node.__init__(self, '', parent) - + self.pdef = pdef self.name = pdef.name self.type = pythonizeType(pdef.type, is_param=True) - -# ----------------------------------------------------------------------- # + +# ----------------------------------------------------------------------- # class Paragraph(Node): """ This class holds information about XML elements with a ```` tag. - """ + """ # ----------------------------------------------------------------------- @@ -753,7 +753,7 @@ class Paragraph(Node): Node.__init__(self, element, parent) self.kind = kind - + # ----------------------------------------------------------------------- @@ -774,18 +774,18 @@ class Paragraph(Node): :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order to avoid wrong ReST output. """ - + text = Node.Join(self, with_tail) if 'Availability:' not in text: return text - + newtext = '' for line in text.splitlines(): if 'Availability:' in line: - + first = line.index('Availability:') element = et.Element('available', kind='available') @@ -793,23 +793,23 @@ class Paragraph(Node): section = Section(element, None, self.kind) - root = self.GetTopLevelParent() + root = self.GetTopLevelParent() root.AddSection(section) - + else: - + newtext += line + '\n' return newtext - - + + # ----------------------------------------------------------------------- # class ReturnType(Node): """ A special admonition section to customize the `:rtype:` ReST role from the XML / Python description. - """ + """ # ----------------------------------------------------------------------- @@ -843,7 +843,7 @@ class ReturnType(Node): :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order to avoid wrong ReST output. """ - + docstrings = '\n\n:rtype: %s\n\n' % self.element return docstrings @@ -855,7 +855,7 @@ class List(Node): """ This class holds information about XML elements with the ```` and ```` tags. - """ + """ # ----------------------------------------------------------------------- @@ -890,7 +890,7 @@ class List(Node): :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order to avoid wrong ReST output. """ - + docstrings = Node.Join(self, with_tail=False) docstrings = '\n\n%s\n'%docstrings @@ -898,16 +898,16 @@ class List(Node): spacer = ('ParameterList' in self.GetHierarchy() and [' '] or [''])[0] text = '%s%s\n'%(spacer, convertToPython(self.element.tail.strip())) docstrings += text - + return docstrings - + # ----------------------------------------------------------------------- # class ListItem(Node): """ This class holds information about XML elements with the ```` tag. - """ + """ # ----------------------------------------------------------------------- @@ -930,13 +930,13 @@ class ListItem(Node): def GetSpacing(self): hierarchy = self.GetHierarchy() - + if 'ParameterList' in hierarchy: return ' ' elif 'Section' in hierarchy: return ' '*3 - + return ' ' * self.level @@ -959,14 +959,14 @@ class ListItem(Node): :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order to avoid wrong ReST output. """ - + spacer = self.GetSpacing() to_remove = ['(id, event, func)', '(id1, id2, event, func)', '(id1, id2, func)', '(id, func)', '(func)', '(id, event, func)', '(id1, id2, event, func)', '(id1, id2, func)', '(id, func)'] - + docstrings = '' for child in self.children: @@ -976,9 +976,9 @@ class ListItem(Node): if '_:' in child_text: child_text = child_text.replace('_:', '_*:') - + docstrings += child_text - + docstrings = '%s- %s\n'%(spacer, docstrings) return docstrings @@ -989,7 +989,7 @@ class Section(Node): """ This class holds information about XML elements with the ```` and ```` tags. - """ + """ # ----------------------------------------------------------------------- @@ -1008,7 +1008,7 @@ class Section(Node): """ Node.__init__(self, element, parent) - + self.kind = kind self.is_overload = is_overload self.share_docstrings = share_docstrings @@ -1036,11 +1036,11 @@ class Section(Node): :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order to avoid wrong ReST output. """ - + section_type = self.section_type - + text = Node.Join(self, with_tail=False) - + if not text.strip() or len(text.strip()) < 3: # Empy text or just trailing commas return '' @@ -1063,7 +1063,7 @@ class Section(Node): version = text[vindex1:vindex2].strip() if version.endswith('.'): version = version[0:-1] - text = '%s\n%s%s'%(version, sub_spacer, text) + text = '%s\n%s%s'%(version, sub_spacer, text) elif section_type == 'deprecated': # Special treatment for deprecated, wxWidgets devs do not put the version number @@ -1080,31 +1080,31 @@ class Section(Node): break return '\n\n' + '\n'.join(split[current:]) + '\n\n' - + if section_type in ['note', 'remark', 'remarks', 'return']: text = '\n\n' + sub_spacer + text for section, replacement in SECTIONS: if section == section_type: break - + docstrings = '' section_spacer = '' - + if section_type != 'return': section_spacer = self.GetSpacing() - + docstrings = '\n%s%s %s\n\n'%(section_spacer, replacement, text) return '\n' + docstrings - + # ----------------------------------------------------------------------- # class Image(Node): """ This class holds information about XML elements with the ```` tag. - """ + """ # ----------------------------------------------------------------------- @@ -1139,14 +1139,14 @@ class Image(Node): :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order to avoid wrong ReST output. """ - + for key, value in list(self.element.items()): if key == 'name': break if 'appear-' in value: return '' - + image_path = os.path.normpath(os.path.join(DOXYROOT, 'images', value)) static_path = os.path.join(OVERVIEW_IMAGES_ROOT, os.path.split(image_path)[1]) @@ -1158,7 +1158,7 @@ class Image(Node): rel_path_index = static_path.rfind('_static') rel_path = os.path.normpath(static_path[rel_path_index:]) - + docstrings = '\n\n' docstrings += '.. figure:: %s\n' % rel_path docstrings += ' :align: center\n\n\n' @@ -1174,7 +1174,7 @@ class Image(Node): class Table(Node): """ This class holds information about XML elements with the ```` tag. - """ + """ # ----------------------------------------------------------------------- @@ -1189,10 +1189,10 @@ class Table(Node): inside the ``TABLEROOT`` folder, the `xml_item_name` string will match the ``*.rst`` file name for the custom table. - .. note:: + .. note:: There are 4 customized versions of 4 XML tables up to now, for various reasons: - + 1. The `wx.Sizer` flags table is a flexible grid table, very difficult to ReSTify automatically due to embedded newlines messing up the col width calculations. @@ -1206,13 +1206,13 @@ class Table(Node): """ Node.__init__(self, element, parent) - + self.xml_item_name = xml_item_name # ----------------------------------------------------------------------- - def Join(self, with_tail=True): + def Join(self, with_tail=True): """ Join this node `element` attribute text and tail, adding all its children's node text and tail in the meanwhile. @@ -1230,7 +1230,7 @@ class Table(Node): to avoid wrong ReST output. """ - needs_space = 'ParameterList' in self.GetHierarchy() + needs_space = 'ParameterList' in self.GetHierarchy() spacer = (needs_space and [' '] or [''])[0] rows, cols = int(self.element.get('rows')), int(self.element.get('cols')) @@ -1238,11 +1238,11 @@ class Table(Node): longest = [0]*cols has_title = False - count = 0 + count = 0 for row in range(rows): for col in range(cols): child = self.children[count] - + text = child.Join(with_tail) longest[col] = max(len(text), longest[col]) @@ -1250,7 +1250,7 @@ class Table(Node): has_title = True count += 1 - + table = '\n\n' table += spacer formats = [] @@ -1258,15 +1258,15 @@ class Table(Node): for lng in longest: table += '='* lng + ' ' formats.append('%-' + '%ds'%(lng+1)) - + table += '\n' count = 0 - + for row in range(rows): table += spacer - + for col in range(cols): table += formats[col] % (self.children[count].Join(with_tail).strip()) count += 1 @@ -1276,21 +1276,21 @@ class Table(Node): if row == 0 and has_title: table += spacer - + for lng in longest: table += '='* lng + ' ' table += '\n' table += spacer - + for lng in longest: table += '='* lng + ' ' table += '\n\n%s|\n\n'%spacer possible_rest_input = os.path.join(TABLEROOT, self.xml_item_name) - + if os.path.isfile(possible_rest_input): # Work around for the buildbot sphinx generator which seems unable # to find the tables... @@ -1313,7 +1313,7 @@ class Table(Node): class TableEntry(Node): """ This class holds information about XML elements with the ```` tag. - """ + """ pass # ----------------------------------------------------------------------- # @@ -1323,7 +1323,7 @@ class Snippet(Node): This class holds information about XML elements with the ````, ````, ````, ```` and ```` (but only when the ```` tags appears as a child of ````) tags. - """ + """ # ----------------------------------------------------------------------- @@ -1341,17 +1341,17 @@ class Snippet(Node): ``SNIPPETROOT/python`` folder :param string `converted_py`: the path to the fully-converted to Python snippet of code found in the XML wxWidgets docstring, saved into the - ``SNIPPETROOT/python/converted`` folder. + ``SNIPPETROOT/python/converted`` folder. """ - + Node.__init__(self, element, parent) - + self.cpp_file = cpp_file self.python_file = python_file self.converted_py = converted_py self.snippet = '' - + # ----------------------------------------------------------------------- @@ -1364,15 +1364,15 @@ class Snippet(Node): """ tag = element.tag - + if tag == 'codeline': self.snippet += '\n' - + elif tag in ['highlight', 'ref', 'sp']: if tag == 'sp': self.snippet += ' ' - + if isinstance(element, string_base): self.snippet += element else: @@ -1380,10 +1380,10 @@ class Snippet(Node): self.snippet += element.text.strip(' ') if element.tail: self.snippet += element.tail.strip(' ') - + else: raise Exception('Unhandled tag in class Snippet: %s'%tag) - + # ----------------------------------------------------------------------- @@ -1404,12 +1404,12 @@ class Snippet(Node): :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order to avoid wrong ReST output. """ - + docstrings = '' if not os.path.exists(os.path.dirname(self.cpp_file)): os.makedirs(os.path.dirname(self.cpp_file)) - + fid = open(self.cpp_file, 'wt') fid.write(self.snippet) fid.close() @@ -1420,7 +1420,7 @@ class Snippet(Node): message += '\n\nA slightly Pythonized version of this snippet has been saved into:\n\n ==> %s\n\n'%self.python_file print(message) - + py_code = self.snippet.replace(';', '') py_code = py_code.replace('{', '').replace('}', '') py_code = py_code.replace('->', '.').replace('//', '#') @@ -1433,7 +1433,7 @@ class Snippet(Node): spacer = ' '*4 new_py_code = '' - + for code in py_code.splitlines(): new_py_code += spacer + code + '\n' @@ -1445,7 +1445,7 @@ class Snippet(Node): fid = open(self.converted_py, 'rt') highlight = None - + while 1: tline = fid.readline() @@ -1457,7 +1457,7 @@ class Snippet(Node): if 'code-block::' in tline: highlight = tline.replace('#', '').strip() continue - + if not tline.strip(): continue @@ -1469,7 +1469,7 @@ class Snippet(Node): docstrings += '\n\n%s\n\n'%highlight else: docstrings += '::\n\n' - + docstrings += code.rstrip() + '\n\n' if self.element.tail and len(self.element.tail.strip()) > 1: @@ -1481,13 +1481,13 @@ class Snippet(Node): spacer = ' ' elif 'List' in hierarchy: spacer = ' ' - + tail = convertToPython(self.element.tail.lstrip()) tail = tail.replace('\n', ' ') docstrings += spacer + tail.replace(' ', ' ') return docstrings - + # ----------------------------------------------------------------------- # @@ -1495,7 +1495,7 @@ class XRef(Node): """ This class holds information about XML elements with the ```` tag, excluding when these elements are children of a ```` element. - """ + """ # ----------------------------------------------------------------------- @@ -1537,13 +1537,13 @@ class XRef(Node): tail = element.tail tail = (tail is not None and [tail] or [''])[0] - + hascomma = '::' in text - original = text + original = text text = removeWxPrefix(text) text = text.replace("::", ".") - + if "(" in text: text = text[0:text.index("(")] @@ -1553,10 +1553,10 @@ class XRef(Node): space_before, space_after = countSpaces(text) stripped = text.strip() - + if stripped in IGNORE: return space_before + text + space_after + tail - + if ' ' in stripped or 'overview' in values: if 'classwx_' in refid: ref = 1000 @@ -1587,19 +1587,19 @@ class XRef(Node): backlink = 'programming with boxsizer' text = ':ref:`%s <%s>`'%(stripped, backlink) - + elif (text.upper() == text and len(stripped) > 4): if not original.strip().startswith('wx') or ' ' in stripped: text = '' - + elif not isNumeric(text): text = '``%s``'%text - + elif 'funcmacro' in values: if '(' in stripped: stripped = stripped[0:stripped.index('(')].strip() - + text = ':func:`%s`'%stripped elif hascomma or len(remainder) > 30: @@ -1620,7 +1620,7 @@ class XRef(Node): if stripped in imm: text = ':ref:`%s`' % (imm.get_fullname(stripped)) - else: + else: if '.' not in stripped: klass = self.IsClassDescription() if klass: @@ -1636,14 +1636,14 @@ class XRef(Node): text = ':ref:`%s`' % wx2Sphinx(stripped)[1] return space_before + text + space_after + convertToPython(tail) - + # ----------------------------------------------------------------------- # class ComputerOutput(Node): """ This class holds information about XML elements with the ```` tag. - """ + """ def __init__(self, element, parent): """ @@ -1684,7 +1684,7 @@ class ComputerOutput(Node): if text is not None: stripped = text.strip() space_before, space_after = countSpaces(text) - + text = removeWxPrefix(text.strip()) else: @@ -1712,7 +1712,7 @@ class Emphasis(Node): """ This class holds information about XML elements with the ```` and ```` tags. - """ + """ # ----------------------------------------------------------------------- @@ -1776,7 +1776,7 @@ class Emphasis(Node): if tail.strip() != ':': childText = childText.replace(convertToPython(tail), '') - + fullChildText = child.Join() endPos = text.index(childText) @@ -1791,11 +1791,11 @@ class Emphasis(Node): newText += emphasys + remaining.strip() + emphasys + ' ' else: newText += emphasys + ' ' - + startPos = endPos text = newText - + else: if text.strip(): @@ -1812,7 +1812,7 @@ class Emphasis(Node): class Title(Node): """ This class holds information about XML elements with the ```` tag. - """ + """ # ----------------------------------------------------------------------- @@ -1868,7 +1868,7 @@ class Title(Node): class ULink(Node): """ This class holds information about XML elements with the ``<ulink>`` tag. - """ + """ # ----------------------------------------------------------------------- @@ -1906,7 +1906,7 @@ class ULink(Node): dummy, link = list(self.element.items())[0] text = self.element.text - + text = '`%s <%s>`_'%(text, link) if self.element.tail: @@ -1914,7 +1914,7 @@ class ULink(Node): return text - + # ----------------------------------------------------------------------- # class XMLDocString(object): @@ -1923,8 +1923,8 @@ class XMLDocString(object): subclasses documented above. The :class:`XMLDocString` is responsible for building function/method signatures, - class descriptions, window styles and events and so on. - """ + class descriptions, window styles and events and so on. + """ # ----------------------------------------------------------------------- @@ -1943,26 +1943,26 @@ class XMLDocString(object): self.xml_item = xml_item self.is_overload = is_overload self.share_docstrings = share_docstrings - + self.docstrings = '' self.class_name = '' - + self.snippet_count = 0 self.contrib_snippets = [] self.table_count = 0 - self.list_level = 1 + self.list_level = 1 self.list_order = {} self.parameter_list = None self.root = Root(self, is_overload, share_docstrings) - + self.appearance = [] self.overloads = [] - + if isinstance(xml_item, extractors.MethodDef): self.kind = 'method' elif isinstance(xml_item, (extractors.FunctionDef, extractors.PyFunctionDef)): @@ -1982,10 +1982,10 @@ class XMLDocString(object): if hasattr(xml_item, 'deprecated') and xml_item.deprecated and isinstance(xml_item.deprecated, string_base): element = et.Element('deprecated', kind='deprecated') element.text = VERSION - + deprecated_section = Section(element, None, self.kind, self.is_overload, self.share_docstrings) self.root.AddSection(deprecated_section) - + # ----------------------------------------------------------------------- @@ -1995,7 +1995,7 @@ class XMLDocString(object): brief, detailed = self.xml_item.briefDoc, self.xml_item.detailedDoc self.RecurseXML(brief, self.root) - + for detail in detailed: blank_element = Node('\n\n\n', self.root) self.RecurseXML(detail, self.root) @@ -2003,7 +2003,7 @@ class XMLDocString(object): self.InsertParameterList() self.BuildSignature() self.docstrings = self.root.Join() - + self.LoadOverLoads() @@ -2021,7 +2021,7 @@ class XMLDocString(object): dummy_root = Root(self, False, False) rest_class = self.RecurseXML(brief, dummy_root) return rest_class.Join() - + # ----------------------------------------------------------------------- @@ -2030,10 +2030,10 @@ class XMLDocString(object): Extracts the overloaded implementations of a method/function, unless this class is itself an overload or the current method/function has no overloads. """ - + if self.is_overload: return - + if self.kind not in ['method', 'function'] or not self.xml_item.overloads: return @@ -2052,18 +2052,18 @@ class XMLDocString(object): self.RecurseXML(det, dummy_root) all_docs.append(dummy_root.Join()) - + if len(all_docs) == 1: # Only one overload, don't act like there were more self.xml_item.overloads = [] return - + zero = all_docs[0] for docs in all_docs[1:]: if docs != zero: share_docstrings = False break - + self.share_docstrings = share_docstrings snippet_count = 0 @@ -2071,7 +2071,7 @@ class XMLDocString(object): if sub_item.ignored: continue - + sub_item.name = self.xml_item.pyName or removeWxPrefix(self.xml_item.name) docstring = XMLDocString(sub_item, is_overload=True, share_docstrings=share_docstrings) docstring.class_name = self.class_name @@ -2095,21 +2095,21 @@ class XMLDocString(object): :rtype: a subclass of :class:`Node` - .. note: This is a recursive method. + .. note: This is a recursive method. """ if element is None: - return Node('', parent) + return Node('', parent) if isinstance(element, string_base): rest_class = Paragraph(element, parent, self.kind) return rest_class - + tag, text, tail = element.tag, element.text, element.tail text = (text is not None and [text] or [''])[0] tail = (tail is not None and [tail] or [''])[0] - + if tag == 'parameterlist': rest_class = ParameterList(element, parent, self.xml_item, self.kind) self.parameter_list = rest_class @@ -2125,7 +2125,7 @@ class XMLDocString(object): parameter_class.element = element else: rest_class = self.parameter_list - + elif tag in ['itemizedlist', 'orderedlist']: rest_class = List(element, parent) @@ -2150,7 +2150,7 @@ class XMLDocString(object): else: rest_class = Section(element, None, self.kind, self.is_overload, self.share_docstrings) self.root.AddSection(rest_class) - + elif tag == 'image': rest_class = Image(element, parent) @@ -2166,7 +2166,7 @@ class XMLDocString(object): elif tag == 'row': rest_class = self.table - + elif tag == 'programlisting': cpp_file, python_file, converted_py = self.SnippetName() rest_class = Snippet(element, parent, cpp_file, python_file, converted_py) @@ -2175,17 +2175,17 @@ class XMLDocString(object): elif tag in ['codeline', 'highlight', 'sp']: self.code.AddCode(element) rest_class = self.code - + elif tag == 'ref': if 'Snippet' in parent.GetHierarchy(): self.code.AddCode(element) rest_class = self.code else: rest_class = XRef(element, parent) - + elif tag == 'computeroutput': rest_class = ComputerOutput(element, parent) - + elif tag in ['emphasis', 'bold']: rest_class = Emphasis(element, parent) @@ -2200,10 +2200,10 @@ class XMLDocString(object): spacer = ('ParameterList' in parent.GetHierarchy() and [' '] or [''])[0] dummy = Node('\n\n%s%s'%(spacer, tail.strip()), parent) rest_class = parent - + elif tag == 'ulink': rest_class = ULink(element, parent) - + elif tag == 'onlyfor': onlyfor = et.Element('available', kind='available') onlyfor.text = text @@ -2214,14 +2214,14 @@ class XMLDocString(object): self.root.AddSection(section) rest_class = parent - else: + else: rest_class = Node('', parent) for child_element in element: self.RecurseXML(child_element, rest_class) - return rest_class - + return rest_class + # ----------------------------------------------------------------------- @@ -2262,8 +2262,8 @@ class XMLDocString(object): if not fullname.strip(): dummy = xml_item.name or xml_item.pyName raise Exception('Invalid item name for %s (kind=%s)'%(dummy, self.kind)) - - return fullname + + return fullname # ----------------------------------------------------------------------- @@ -2279,22 +2279,22 @@ class XMLDocString(object): ``SNIPPETROOT/python`` folder 3. `converted_py`: the path to the fully-converted to Python snippet of code found in the XML wxWidgets docstring, saved into the - ``SNIPPETROOT/python/converted`` folder. + ``SNIPPETROOT/python/converted`` folder. """ fullname = self.GetFullName() self.snippet_count += 1 - + cpp_file = os.path.join(SNIPPETROOT, 'cpp', fullname + '.%d.cpp'%self.snippet_count) python_file = os.path.join(SNIPPETROOT, 'python', fullname + '.%d.py'%self.snippet_count) converted_py = os.path.join(SNIPPETROOT, 'python', 'converted', fullname + '.%d.py'%self.snippet_count) - + return cpp_file, python_file, converted_py def HuntContributedSnippets(self): - + fullname = self.GetFullName() contrib_folder = os.path.join(SNIPPETROOT, 'python', 'contrib') @@ -2310,7 +2310,7 @@ class XMLDocString(object): possible_py.append(sample) return possible_py - + # ----------------------------------------------------------------------- @@ -2325,7 +2325,7 @@ class XMLDocString(object): """ self.ToReST() - + methodMap = { 'class' : self.DumpClass, 'method' : self.DumpMethod, @@ -2349,7 +2349,7 @@ class XMLDocString(object): :rtype: `string` """ - stream = StringIO() + stream = StringIO() # class declaration klass = self.xml_item @@ -2359,7 +2359,7 @@ class XMLDocString(object): # if '.' in fullname: # module = self.current_module[:-1] # stream.write('\n\n.. currentmodule:: %s\n\n' % module) - + stream.write(templates.TEMPLATE_DESCRIPTION % (fullname, fullname)) self.Reformat(stream) @@ -2381,7 +2381,7 @@ class XMLDocString(object): stream.write(subs_desc) possible_py = self.HuntContributedSnippets() - + if possible_py: possible_py.sort() snippets = formatContributedSnippets(self.kind, possible_py) @@ -2400,7 +2400,7 @@ class XMLDocString(object): stream.write("\n.. class:: %s" % fullname) bases = klass.bases or ['object'] - + if bases: stream.write('(') bases = [removeWxPrefix(b) for b in bases] # *** @@ -2441,16 +2441,16 @@ class XMLDocString(object): writeSphinxOutput(stream, self.output_file) else: return stream.getvalue() - + # ----------------------------------------------------------------------- def BuildSignature(self): """ Builds a function/method signature. """ - + if self.kind not in ['method', 'function']: return - + if self.kind == 'method': method = self.xml_item @@ -2471,7 +2471,7 @@ class XMLDocString(object): arguments = '(self)' + arguments[2:] else: arguments = '(self, ' + arguments[1:] - + if '->' in arguments: arguments, after = arguments.split("->") self.AddReturnType(after, name) @@ -2479,7 +2479,7 @@ class XMLDocString(object): arguments = arguments.rstrip() if arguments.endswith(','): arguments = arguments[0:-1] - + if not arguments.endswith(')'): arguments += ')' @@ -2500,7 +2500,7 @@ class XMLDocString(object): self.AddReturnType(after, name) else: arguments = function.pyArgsString - + if self.is_overload: arguments = '`%s`'%arguments.strip() @@ -2525,28 +2525,28 @@ class XMLDocString(object): return if not self.xml_item.hasOverloads() or self.is_overload: - self.parameter_list = ParameterList('', None, self.xml_item, self.kind) + self.parameter_list = ParameterList('', None, self.xml_item, self.kind) self.root.Insert(self.parameter_list, before=Section) self.parameter_list.CheckSignature() - + # ----------------------------------------------------------------------- def AddReturnType(self, after, name): after = after.strip() - + if not after: return - + if '(' in after: rtype = ReturnType('`tuple`', None) - + return_section = after.lstrip('(').rstrip(')') return_section = return_section.split(',') new_section = [] - + for ret in return_section: stripped = ret.strip() imm = ItemModuleMap() @@ -2561,17 +2561,17 @@ class XMLDocString(object): element = et.Element('return', kind='return') element.text = '( %s )'%(', '.join(new_section)) - + return_section = Section(element, None, self.kind, self.is_overload, self.share_docstrings) self.root.AddSection(return_section) - + else: rtype = pythonizeType(after, is_param=False) if not rtype: return - + if rtype[0].isupper() or '.' in rtype: rtype = ':ref:`%s`'%rtype else: @@ -2598,7 +2598,7 @@ class XMLDocString(object): """ stream = StringIO() - + method = self.xml_item name = method.pyName if method.pyName else method.name name = removeWxPrefix(name) @@ -2610,10 +2610,10 @@ class XMLDocString(object): definition = ' .. staticmethod:: ' + name else: definition = ' .. method:: ' + name - + # write the method declaration stream.write('\n%s'%definition) - + stream.write(self.arguments) stream.write('\n\n') @@ -2626,7 +2626,7 @@ class XMLDocString(object): stream.write(text) possible_py = self.HuntContributedSnippets() - + if possible_py: possible_py.sort() snippets = formatContributedSnippets(self.kind, possible_py) @@ -2653,7 +2653,7 @@ class XMLDocString(object): """ stream = StringIO() - + function = self.xml_item name = function.pyName or function.name fullname = ItemModuleMap().get_fullname(name) @@ -2664,9 +2664,9 @@ class XMLDocString(object): definition = '.. function:: ' + fullname stream.write('\n%s' % definition) - + stream.write(self.arguments.strip()) - stream.write('\n\n') + stream.write('\n\n') self.Reformat(stream) @@ -2679,13 +2679,13 @@ class XMLDocString(object): stream.write(text) possible_py = self.HuntContributedSnippets() - + if possible_py: possible_py.sort() snippets = formatContributedSnippets(self.kind, possible_py) stream.write(snippets) - if not self.is_overload and write: + if not self.is_overload and write: pickleItem(stream.getvalue(), self.current_module, name, 'function') return stream.getvalue() @@ -2717,16 +2717,16 @@ class XMLDocString(object): # if self.current_module.strip(): # module = self.current_module.strip()[:-1] # stream.write('\n\n.. currentmodule:: %s\n\n' % module) - + stream.write(templates.TEMPLATE_DESCRIPTION % (fullname, fullname)) stream.write('\n\nThe `%s` enumeration provides the following values:\n\n' % enum_name) - + stream.write('\n\n' + '='*80 + ' ' + '='*80 + '\n') stream.write('%-80s **Value**\n'%'**Description**') stream.write('='*80 + ' ' + '='*80 + '\n') count = 0 - + for v in self.xml_item.items: if v.ignored: continue @@ -2735,7 +2735,7 @@ class XMLDocString(object): name = v.pyName if v.pyName else removeWxPrefix(v.name) name = convertToPython(name) stream.write('%-80s' % name) - + if not isinstance(docstrings, string_base): rest_class = self.RecurseXML(docstrings, self.root) docstrings = rest_class.Join() @@ -2751,7 +2751,7 @@ class XMLDocString(object): writeSphinxOutput(stream, self.output_file) return stream.getvalue() - + # ----------------------------------------------------------------------- @@ -2765,7 +2765,7 @@ class XMLDocString(object): # Crappy wxWidgets docs!!! They put the Window Styles inside the # constructor!!! docstrings += templates.TEMPLATE_WINDOW_STYLES % class_name - + elif 'The following event handler macros' in line and not added: index = line.index('The following event handler macros') newline1 = line[0:index] + '\n\n' @@ -2773,11 +2773,11 @@ class XMLDocString(object): last = macro_line.index(':') line = macro_line[last+1:].strip() - if line.count(':') > 2: + if line.count(':') > 2: newline = 'Handlers bound for the following event types will receive one of the %s parameters.'%line else: newline = 'Handlers bound for the following event types will receive a %s parameter.'%line - + docstrings += newline1 + templates.TEMPLATE_EVENTS % class_name docstrings = docstrings.replace('Event macros for events emitted by this class: ', '') newline = newline.replace('Event macros for events emitted by this class: ', '') @@ -2795,7 +2795,7 @@ class XMLDocString(object): docstrings += templates.TEMPLATE_WINDOW_EXTRASTYLES % class_name return docstrings, newline, added - + # ----------------------------------------------------------------------- @@ -2807,7 +2807,7 @@ class XMLDocString(object): return newlines start = code.index('(') - wrapped = textwrap.wrap(code, width=72) + wrapped = textwrap.wrap(code, width=72) newcode = '' for indx, line in enumerate(wrapped): @@ -2822,7 +2822,7 @@ class XMLDocString(object): # ----------------------------------------------------------------------- - + def Indent(self, class_name, item, spacer, docstrings): added = False @@ -2834,12 +2834,12 @@ class XMLDocString(object): docstrings += spacer + newline + '\n' else: docstrings += line + '\n' - + return docstrings - + # ----------------------------------------------------------------------- - + def Reformat(self, stream): spacer = '' @@ -2855,7 +2855,7 @@ class XMLDocString(object): docstrings = '' elif self.is_overload and self.share_docstrings: - + docstrings = self.Indent(None, self.docstrings, spacer, '') else: @@ -2873,12 +2873,12 @@ class XMLDocString(object): docstrings = '' else: docstrings = self.Indent(class_name, self.docstrings, spacer, '') - + if self.kind == 'class': desc = chopDescription(docstrings) self.short_description = desc pickleItem(desc, self.current_module, self.class_name, 'class') - + if self.overloads: docstrings += '\n\n%s|overload| Overloaded Implementations:\n\n'%spacer @@ -2889,18 +2889,18 @@ class XMLDocString(object): docstrings += spacer + line + '\n' docstrings += '%s**~~~**\n\n'%spacer - + if '**Perl Note:**' in docstrings: index = docstrings.index('**Perl Note:**') docstrings = docstrings[0:index] stream.write(docstrings + "\n\n") - - + + # --------------------------------------------------------------------------- class SphinxGenerator(generators.DocsGeneratorBase): - + def generate(self, module): self.current_module = MODULENAME_REPLACE[module.module] self.module_name = module.name @@ -2921,7 +2921,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): message = '\nWARNING: Duplicated instance of %s `%s` encountered in class `%s`.\n' \ 'The last occurrence of `%s` (an instance of `%s`) will be discarded.\n\n' - + for index, item in enumerate(class_items): if isinstance(item, methods): name, dummy = self.getName(item) @@ -2937,23 +2937,23 @@ class SphinxGenerator(generators.DocsGeneratorBase): duplicated_indexes.append(index) continue - done.append(name) + done.append(name) - duplicated_indexes.reverse() + duplicated_indexes.reverse() for index in duplicated_indexes: class_items.pop(index) - return class_items + return class_items + - # ----------------------------------------------------------------------- - + def generateModule(self, module): """ Generate code for each of the top-level items in the module. """ assert isinstance(module, extractors.ModuleDef) - + methodMap = { extractors.ClassDef : self.generateClass, extractors.DefineDef : self.generateDefine, @@ -2983,7 +2983,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): # ----------------------------------------------------------------------- - + def generatePyFunction(self, function): name = function.pyName if function.pyName else removeWxPrefix(function.name) imm = ItemModuleMap() @@ -2993,7 +2993,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): function.pyArgsString = function.argsString self.unIndent(function) - + # docstring docstring = XMLDocString(function) docstring.kind = 'function' @@ -3004,7 +3004,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): pickleFunctionInfo(fullname, desc) # ----------------------------------------------------------------------- - + def generateFunction(self, function): name = function.pyName if function.pyName else removeWxPrefix(function.name) if name.startswith('operator'): @@ -3042,10 +3042,10 @@ class SphinxGenerator(generators.DocsGeneratorBase): newdocs += line + '\n' item.briefDoc = newdocs - - + + # ----------------------------------------------------------------------- - + def generatePyClass(self, klass): self.fixNodeBaseNames(klass, ItemModuleMap()) @@ -3065,7 +3065,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): class_items = self.removeDuplicated(class_fullname, class_items) init_position = -1 - + for index, item in enumerate(class_items): if isinstance(item, extractors.PyFunctionDef): method_name, simple_docs = self.getName(item) @@ -3124,12 +3124,12 @@ class SphinxGenerator(generators.DocsGeneratorBase): filename = "%s.txt" % fullname writeSphinxOutput(stream, filename, append=True) - + # ----------------------------------------------------------------------- def generateClass(self, klass): assert isinstance(klass, extractors.ClassDef) - + if klass.ignored: return @@ -3170,7 +3170,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): # Build a list to check if there are any properties properties = (extractors.PropertyDef, extractors.PyPropertyDef) methods = (extractors.MethodDef, extractors.CppMethodDef, extractors.CppMethodDef_sip, extractors.PyMethodDef) - + # Split the items documenting the __init__ methods first ctors = [i for i in klass if isinstance(i, extractors.MethodDef) and @@ -3195,11 +3195,11 @@ class SphinxGenerator(generators.DocsGeneratorBase): description = self.createMemberVarDescription(item) klass.memberVar_list.append(('%s.%s' % (fullname, item.name), description)) - for item in ctors: + for item in ctors: if item.isCtor: method_name, simple_docs = self.getName(item) klass.method_list.insert(0, ('%s.__init__'%fullname, simple_docs)) - + docstring = XMLDocString(klass) filename = "%s.txt" % fullname @@ -3209,11 +3209,11 @@ class SphinxGenerator(generators.DocsGeneratorBase): docstring.Dump() pickleClassInfo(fullname, self.current_class, docstring.short_description) - - for item in ctors: + + for item in ctors: if item.isCtor: self.generateMethod(item, name='__init__', docstring=klass.pyDocstring) - + for item in class_items: f = dispatch[item.__class__][0] f(item) @@ -3280,22 +3280,22 @@ class SphinxGenerator(generators.DocsGeneratorBase): docstring.current_module = self.current_module docstring.Dump() - + # ----------------------------------------------------------------------- def IsFullyDeprecated(self, pyMethod): if not isinstance(pyMethod, extractors.PyMethodDef): return False - + if pyMethod.deprecated: brief, detailed = pyMethod.briefDoc, pyMethod.detailedDoc if not brief and not detailed: # Skip simple wrappers unless they have a brief or a detailed doc return True - return False - + return False + def generatePyMethod(self, pm): @@ -3309,27 +3309,27 @@ class SphinxGenerator(generators.DocsGeneratorBase): stream = StringIO() stream.write('\n .. method:: %s%s\n\n' % (pm.name, pm.argsString)) - + docstrings = return_type = '' - + for line in pm.pyDocstring.splitlines(): if '->' in line: arguments, after = line.strip().split("->") return_type = self.returnSection(after) else: docstrings += line + '\n' - + docstrings = convertToPython(docstrings) newdocs = '' spacer = ' '*6 - + for line in docstrings.splitlines(): if not line.startswith(spacer): newdocs += spacer + line + "\n" else: newdocs += line + "\n" - + stream.write(newdocs + '\n\n') if hasattr(pm, 'deprecated') and pm.deprecated: @@ -3342,7 +3342,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): filename = "%s.txt" % imm.get_fullname(name) writeSphinxOutput(stream, filename, append=True) - + # ----------------------------------------------------------------------- def generateMemberVar(self, memberVar): @@ -3414,13 +3414,13 @@ class SphinxGenerator(generators.DocsGeneratorBase): if prop.getter and prop.setter: return 'See :meth:`~%s.%s` and :meth:`~%s.%s`' % (name, prop.getter, name, prop.setter) else: - method = (prop.getter and [prop.getter] or [prop.setter])[0] + method = (prop.getter and [prop.getter] or [prop.setter])[0] return 'See :meth:`~%s.%s`' % (name, method) - + # ----------------------------------------------------------------------- def generateEnum(self, enum): - + assert isinstance(enum, extractors.EnumDef) if enum.ignored: return @@ -3451,7 +3451,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): def generateDefine(self, define): assert isinstance(define, extractors.DefineDef) # write nothing for this one - + # ----------------------------------------------------------------------- def generateTypedef(self, typedef): assert isinstance(typedef, extractors.TypedefDef) @@ -3500,7 +3500,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): def generateWigCode(self, wig): assert isinstance(wig, extractors.WigCode) # write nothing for this one - + # ----------------------------------------------------------------------- def generatePyCode(self, pc): @@ -3517,7 +3517,7 @@ class SphinxGenerator(generators.DocsGeneratorBase): method_name = MAGIC_METHODS[method_name] simple_docs = '' - + if isinstance(method, extractors.PyMethodDef): simple_docs = convertToPython(method.pyDocstring) else: @@ -3540,11 +3540,11 @@ class SphinxGenerator(generators.DocsGeneratorBase): if '(' in after: rtype1 = ReturnType('`tuple`', None) - + return_section = after.strip().lstrip('(').rstrip(')') return_section = return_section.split(',') new_section = [] - + for ret in return_section: stripped = ret.strip() imm = ItemModuleMap() @@ -3559,17 +3559,17 @@ class SphinxGenerator(generators.DocsGeneratorBase): element = et.Element('return', kind='return') element.text = '( %s )'%(', '.join(new_section)) - + rtype2 = Section(element, None, 'method') rtype = rtype1.Join() + rtype2.Join() - + else: rtype = pythonizeType(after, is_param=False) if not rtype: return '' - + if rtype[0].isupper() or '.' in rtype: rtype = ':ref:`%s`'%rtype else: @@ -3577,14 +3577,14 @@ class SphinxGenerator(generators.DocsGeneratorBase): rtype = ReturnType(rtype, None) rtype = rtype.Join() - + out = '' for r in rtype.splitlines(): out += 6*' ' + r + '\n' - + return out - + # --------------------------------------------------------------------------- # helpers diff --git a/etgtools/tweaker_tools.py b/etgtools/tweaker_tools.py index 9f226e74..3a4f6d0f 100644 --- a/etgtools/tweaker_tools.py +++ b/etgtools/tweaker_tools.py @@ -54,7 +54,7 @@ def removeWxPrefixes(node): if item.name.startswith('wxEVT_') and 'CATEGORY' not in item.name: # give these their actual name so the auto-renamer won't touch them item.pyName = item.name - + def removeWxPrefix(name): """ @@ -62,13 +62,13 @@ def removeWxPrefix(name): """ if name.startswith('wx.') or name.startswith('``wx.'): return name - + if name.startswith('wx') and not name.startswith('wxEVT_'): name = name[2:] - + if name.startswith('``wx') and not name.startswith('``wxEVT_'): name = name[0:2] + name[4:] - + return name @@ -78,25 +78,25 @@ class FixWxPrefix(object): A mixin class that can help with removing the wx prefix, or changing it in to a "wx.Name" depending on where it is being used from. """ - + _coreTopLevelNames = None - + def fixWxPrefix(self, name, checkIsCore=False): # By default remove the wx prefix like normal name = removeWxPrefix(name) if not checkIsCore or self.isCore: return name - + # Otherwise, if we're not processing the core module currently then check # if the name is local or if it resides in core. If it does then return # the name as 'wx.Name' if FixWxPrefix._coreTopLevelNames is None: self._getCoreTopLevelNames() - + testName = name if '(' in name: testName = name[:name.find('(')] - + if testName in FixWxPrefix._coreTopLevelNames: return 'wx.'+name else: @@ -119,7 +119,7 @@ class FixWxPrefix(object): names.append(item.name) elif isinstance(item, ast.FunctionDef): names.append(item.name) - + names = list() filename = 'wx/core.pi' if PY3: @@ -133,8 +133,8 @@ class FixWxPrefix(object): _processItem(item, names) FixWxPrefix._coreTopLevelNames = names - - + + def ignoreAssignmentOperators(node): @@ -145,7 +145,7 @@ def ignoreAssignmentOperators(node): if isinstance(item, extractors.MethodDef) and item.name == 'operator=': item.ignore() - + def ignoreAllOperators(node): """ Set the ignored flag for all class methods that are any kind of operator @@ -170,7 +170,7 @@ def ignoreConstOverloads(node): item2 = overloads[j] if item1.ignored or item2.ignored: continue - if (item1.argsString.replace(' const', '').strip() == + if (item1.argsString.replace(' const', '').strip() == item2.argsString.replace(' const', '').strip()): if item1.isConst: item1.ignore() @@ -178,13 +178,13 @@ def ignoreConstOverloads(node): elif item2.isConst: item2.ignore() return - + for item in node.items: if isinstance(item, extractors.MethodDef) and item.overloads: _checkOverloads(item) - - - + + + def addAutoProperties(node): """ Call klass.addAutoProperties for all classes in node with @@ -199,7 +199,7 @@ def addAutoProperties(node): continue item.addAutoProperties() - + def fixEventClass(klass, ignoreProtected=True): """ Add the extra stuff that an event class needs that are lacking from the @@ -223,9 +223,9 @@ def fixEventClass(klass, ignoreProtected=True): for item in klass.allItems(): if isinstance(item, extractors.MethodDef) and item.protection == 'protected': item.ignore(False) - - + + def fixWindowClass(klass, hideVirtuals=True, ignoreProtected=True): """ Do common tweaks for a window class. @@ -267,7 +267,7 @@ def fixWindowClass(klass, hideVirtuals=True, ignoreProtected=True): def fixTopLevelWindowClass(klass, hideVirtuals=True, ignoreProtected=True): """ - Tweaks for TLWs + Tweaks for TLWs """ # TLW tweaks are a little different. We use the function annotation for # TransferThis instead of the argument annotation. @@ -306,17 +306,17 @@ def fixSizerClass(klass): removeVirtuals(klass) klass.find('CalcMin').isVirtual = True klass.find('RecalcSizes').isVirtual = True - + # in the wxSizer class they are pure-virtual if klass.name == 'wxSizer': klass.find('CalcMin').isPureVirtual = True klass.find('RecalcSizes').isPureVirtual = True - - + + def fixBookctrlClass(klass, treeBook=False): """ Add declarations of the pure virtual methods from the base class. - """ + """ klass.addItem(extractors.WigCode("""\ virtual int GetPageImage(size_t nPage) const; virtual bool SetPageImage(size_t page, int image); @@ -332,7 +332,7 @@ def fixBookctrlClass(klass, treeBook=False): bool select = false, int imageId = NO_IMAGE); """)) - + def fixHtmlSetFonts(klass): # Use wxArrayInt instead of a C array of ints. m = klass.find('SetFonts') @@ -373,13 +373,13 @@ def removeVirtuals(klass): if isinstance(item, extractors.MethodDef): item.isVirtual = item.isPureVirtual = False - + def addWindowVirtuals(klass): """ Either turn the virtual flag back on or add a declaration for the subset of the C++ virtuals in wxWindow classes that we will be supporting. """ - publicWindowVirtuals = [ + publicWindowVirtuals = [ ('GetClientAreaOrigin', 'wxPoint GetClientAreaOrigin() const'), ('Validate', 'bool Validate()'), ('TransferDataToWindow', 'bool TransferDataToWindow()'), @@ -393,19 +393,19 @@ def addWindowVirtuals(klass): ('InheritAttributes', 'void InheritAttributes()'), ('ShouldInheritColours', 'bool ShouldInheritColours() const'), ('OnInternalIdle', 'void OnInternalIdle()'), - ('GetMainWindowOfCompositeControl', + ('GetMainWindowOfCompositeControl', 'wxWindow *GetMainWindowOfCompositeControl()'), ('InformFirstDirection', 'bool InformFirstDirection(int direction, int size, int availableOtherDir)'), ('SetCanFocus', 'void SetCanFocus(bool canFocus)'), ('Destroy', 'bool Destroy()'), ## What about these? - #bool HasMultiplePages() const + #bool HasMultiplePages() const #void UpdateWindowUI(long flags = wxUPDATE_UI_NONE); #void DoUpdateWindowUI(wxUpdateUIEvent& event) ; ] - - protectedWindowVirtuals = [ + + protectedWindowVirtuals = [ ('ProcessEvent', 'bool ProcessEvent(wxEvent & event)'), ('DoEnable', 'void DoEnable(bool enable)'), ('DoGetPosition', 'void DoGetPosition(int *x, int *y) const'), @@ -432,7 +432,7 @@ def addWindowVirtuals(klass): #('DoSetVirtualSize', 'void DoSetVirtualSize( int x, int y )'), #('DoGetVirtualSize', 'wxSize DoGetVirtualSize() const'), ] - + def _processItems(klass, prot, virtuals): txt = '' for name, decl in virtuals: @@ -445,14 +445,14 @@ def addWindowVirtuals(klass): if txt: txt = prot + txt return txt - + txt = _processItems(klass, 'public:\n', publicWindowVirtuals) klass.addItem(extractors.WigCode(txt)) txt = _processItems(klass, 'protected:\n', protectedWindowVirtuals) klass.addItem(extractors.WigCode(txt)) klass.addPublic() - - + + def addSipConvertToSubClassCode(klass): """ Teach SIP how to convert to specific subclass types @@ -467,14 +467,14 @@ def addSipConvertToSubClassCode(klass): name = info->GetClassName(); exists = sipFindType(name) != NULL; } - if (info) + if (info) sipType = sipFindType(name); else sipType = NULL; %End """)) - - + + def getEtgFiles(names): """ Create a list of the files from the basenames in the names list that @@ -490,7 +490,7 @@ def getNonEtgFiles(names, template='src/%s.sip'): """ return getMatchingFiles(names, template) - + def getMatchingFiles(names, template): """ Create a list of files from the basenames in names that match the template @@ -502,9 +502,9 @@ def getMatchingFiles(names, template): if os.path.exists(name): files.append(name) return files - - + + def doCommonTweaks(module): """ A collection of tweaks that should probably be done to all modules. @@ -512,8 +512,8 @@ def doCommonTweaks(module): ignoreAssignmentOperators(module) removeWxPrefixes(module) addAutoProperties(module) - - + + def changeTypeNames(module, oldName, newName, skipTypedef=False): """ Changes the matching type names for functions and parameters to a new @@ -559,13 +559,13 @@ def getWrapperGenerator(): else: # The default is sip from etgtools import sip_generator - gClass = sip_generator.SipWrapperGenerator + gClass = sip_generator.SipWrapperGenerator return gClass() def getDocsGenerator(): if '--nodoc' in sys.argv: - from etgtools import generators + from etgtools import generators return generators.StubbedDocsGenerator() elif '--sphinx' in sys.argv: from etgtools import sphinx_generator @@ -574,20 +574,20 @@ def getDocsGenerator(): # the current default is sphinx from etgtools import sphinx_generator return sphinx_generator.SphinxGenerator() - + def runGenerators(module): checkForUnitTestModule(module) generators = list() - + # Create the code generator selected from command line args generators.append(getWrapperGenerator()) - + # Toss in the PI generator too from etgtools import pi_generator - generators.append(pi_generator.PiWrapperGenerator()) + generators.append(pi_generator.PiWrapperGenerator()) # Now the item map generator from etgtools import map_generator @@ -599,7 +599,7 @@ def runGenerators(module): # run the generators for g in generators: g.generate(module) - + def checkForUnitTestModule(module): @@ -625,15 +625,15 @@ def convertTwoIntegersTemplate(CLASS): int rval = 1; PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); - if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) + if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) rval = 0; Py_DECREF(o1); Py_DECREF(o2); return rval; }} return 0; - }} - + }} + // otherwise do the conversion if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) {{ // Just fetch the existing instance @@ -641,7 +641,7 @@ def convertTwoIntegersTemplate(CLASS): sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); return 0; // not a new instance }} - + // or create a new instance PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); @@ -660,14 +660,14 @@ def convertFourIntegersTemplate(CLASS): // is it already an instance of {CLASS}? if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) return 1; - + if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 4) {{ int rval = 1; PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); PyObject* o3 = PySequence_ITEM(sipPy, 2); PyObject* o4 = PySequence_ITEM(sipPy, 3); - if (!PyNumber_Check(o1) || !PyNumber_Check(o2) || !PyNumber_Check(o3) || !PyNumber_Check(o4)) + if (!PyNumber_Check(o1) || !PyNumber_Check(o2) || !PyNumber_Check(o3) || !PyNumber_Check(o4)) rval = 0; Py_DECREF(o1); Py_DECREF(o2); @@ -676,8 +676,8 @@ def convertFourIntegersTemplate(CLASS): return rval; }} return 0; - }} - + }} + // otherwise do the conversion if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) {{ // Just fetch the existing instance @@ -689,7 +689,7 @@ def convertFourIntegersTemplate(CLASS): PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); PyObject* o3 = PySequence_ITEM(sipPy, 2); - PyObject* o4 = PySequence_ITEM(sipPy, 3); + PyObject* o4 = PySequence_ITEM(sipPy, 3); *sipCppPtr = new {CLASS}(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3), wxPyInt_AsLong(o4)); Py_DECREF(o1); @@ -707,20 +707,20 @@ def convertTwoDoublesTemplate(CLASS): // is it already an instance of {CLASS}? if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) return 1; - + if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 2) {{ int rval = 1; PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); - if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) + if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) rval = 0; Py_DECREF(o1); Py_DECREF(o2); return rval; }} return 0; - }} - + }} + // otherwise do the conversion if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) {{ // Just fetch the existing instance @@ -728,7 +728,7 @@ def convertTwoDoublesTemplate(CLASS): sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); return 0; // not a new instance }} - + // or create a new instance PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); @@ -747,14 +747,14 @@ def convertFourDoublesTemplate(CLASS): // is it already an instance of {CLASS}? if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) return 1; - + if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 4) {{ int rval = 1; PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); PyObject* o3 = PySequence_ITEM(sipPy, 2); PyObject* o4 = PySequence_ITEM(sipPy, 3); - if (!PyNumber_Check(o1) || !PyNumber_Check(o2) || !PyNumber_Check(o3) || !PyNumber_Check(o4)) + if (!PyNumber_Check(o1) || !PyNumber_Check(o2) || !PyNumber_Check(o3) || !PyNumber_Check(o4)) rval = 0; Py_DECREF(o1); Py_DECREF(o2); @@ -763,8 +763,8 @@ def convertFourDoublesTemplate(CLASS): return rval; }} return 0; - }} - + }} + // otherwise do the conversion if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) {{ // Just fetch the existing instance @@ -772,12 +772,12 @@ def convertFourDoublesTemplate(CLASS): sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); return 0; // not a new instance }} - + // or create a new instance PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); PyObject* o3 = PySequence_ITEM(sipPy, 2); - PyObject* o4 = PySequence_ITEM(sipPy, 3); + PyObject* o4 = PySequence_ITEM(sipPy, 3); *sipCppPtr = new {CLASS}(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2), PyFloat_AsDouble(o3), PyFloat_AsDouble(o4)); Py_DECREF(o1); @@ -791,26 +791,26 @@ def convertFourDoublesTemplate(CLASS): # Templates for creating wrappers for type-specific wxList and wxArray classes -def wxListWrapperTemplate(ListClass, ItemClass, module, RealItemClass=None, +def wxListWrapperTemplate(ListClass, ItemClass, module, RealItemClass=None, includeConvertToType=False, fakeListClassName=None): if RealItemClass is None: - RealItemClass = ItemClass + RealItemClass = ItemClass if fakeListClassName: TypeDef = "typedef %s %s;" % (ListClass, fakeListClassName) ListClass = fakeListClassName else: TypeDef = "" - - moduleName = module.module + + moduleName = module.module ListClass_pyName = removeWxPrefix(ListClass) - + # *** TODO: This can probably be done in a way that is not SIP-specfic. # Try creating extractor objects from scratch and attach cppMethods to # them as needed, etc.. - + klassCode = '''\ -class {ListClass}_iterator /Abstract/ +class {ListClass}_iterator /Abstract/ {{ // the C++ implementation of this class %TypeHeaderCode @@ -819,7 +819,7 @@ class {ListClass}_iterator /Abstract/ public: {ListClass}_iterator({ListClass}::compatibility_iterator start) : m_node(start) {{}} - + {ItemClass}* __next__() {{ {RealItemClass}* obj = NULL; if (m_node) {{ @@ -842,13 +842,13 @@ public: if (PyErr_Occurred()) return NULL; %End -}}; +}}; -class {ListClass} +class {ListClass} {{ %TypeHeaderCode {TypeDef} - %End + %End public: SIP_SSIZE_T __len__(); %MethodCode @@ -859,7 +859,7 @@ public: %MethodCode if (index < sipCpp->size()) {{ {ListClass}::compatibility_iterator node = sipCpp->Item(index); - if (node) + if (node) sipRes = ({ItemClass}*)node->GetData(); }} else {{ @@ -891,7 +891,7 @@ public: }} sipRes = idx; %End - + @ConvertToTypeCode@ }}; @@ -912,7 +912,7 @@ del _{ListClass_pyName}___repr__ if (sipCanConvertToType(sipPy, sipType_{ListClass}, SIP_NO_CONVERTORS)) return success; // otherwise ensure that it is a sequence - if (! PySequence_Check(sipPy)) + if (! PySequence_Check(sipPy)) success = FALSE; // ensure it is not a string or unicode object (they are sequences too) else if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) @@ -928,9 +928,9 @@ del _{ListClass_pyName}___repr__ break; }} Py_DECREF(item); - }} + }} }} - if (!success) + if (!success) PyErr_SetString(PyExc_TypeError, "Sequence of {ItemClass} compatible objects expected."); return success; }} @@ -938,11 +938,11 @@ del _{ListClass_pyName}___repr__ // Is it already a {ListClass}? Return the exiting instance if so if (sipCanConvertToType(sipPy, sipType_{ListClass}, SIP_NO_CONVERTORS)) {{ *sipCppPtr = reinterpret_cast<{ListClass}*>( - sipConvertToType(sipPy, sipType_{ListClass}, NULL, + sipConvertToType(sipPy, sipType_{ListClass}, NULL, SIP_NO_CONVERTORS, 0, sipIsErr)); return 0; }} - + // Create a new {ListClass} and convert compatible PyObjects from the sequence {ListClass} *list = new {ListClass}; list->DeleteContents(true); // tell the list to take ownership of the items @@ -951,7 +951,7 @@ del _{ListClass_pyName}___repr__ int state; PyObject* pyItem = PySequence_ITEM(sipPy, i); {ItemClass}* cItem = reinterpret_cast<{ItemClass}*>( - sipConvertToType(pyItem, sipType_{ItemClass}, + sipConvertToType(pyItem, sipType_{ItemClass}, NULL, 0, &state, sipIsErr)); if (!state) // a temporary was not created for us, make one now cItem = new {ItemClass}(*cItem); @@ -971,7 +971,7 @@ del _{ListClass_pyName}___repr__ def wxArrayWrapperTemplate(ArrayClass, ItemClass, module, itemIsPtr=False): - moduleName = module.module + moduleName = module.module ArrayClass_pyName = removeWxPrefix(ArrayClass) itemRef = '*' if itemIsPtr else '&' itemDeref = '' if itemIsPtr else '*' @@ -980,9 +980,9 @@ def wxArrayWrapperTemplate(ArrayClass, ItemClass, module, itemIsPtr=False): # *** TODO: This can probably be done in a way that is not SIP-specfic. # Try creating extractor objects from scratch and attach cppMethods to # them as needed, etc.. - + return extractors.WigCode('''\ -class {ArrayClass} +class {ArrayClass} {{ public: SIP_SSIZE_T __len__(); @@ -1037,15 +1037,15 @@ del _{ArrayClass_pyName}___repr__ # Same as the above, but for use with WX_DEFINE_ARRAY_PTR def wxArrayPtrWrapperTemplate(ArrayClass, ItemClass, module): - moduleName = module.module + moduleName = module.module ArrayClass_pyName = removeWxPrefix(ArrayClass) - + # *** TODO: This can probably be done in a way that is not SIP-specfic. # Try creating extractor objects from scratch and attach cppMethods to # them as needed, etc.. - + return extractors.WigCode('''\ -class {ArrayClass} +class {ArrayClass} {{ public: SIP_SSIZE_T __len__(); @@ -1104,8 +1104,8 @@ def ObjArrayHelperTemplate(objType, sipType, errmsg): Generates a helper function that can convert from a Python sequence of objects (or items that can be converted to the target type) into a C array of values. Copies are made of the items so the object types should - support implicit or explicit copies and the copy should be cheap. - + support implicit or explicit copies and the copy should be cheap. + This kind of helper is useful for situations where the C/C++ API takes a simple pointer and a count, and there is no higher level container object (like a wxList or wxArray) being used. If there is an overloaded method @@ -1113,9 +1113,9 @@ def ObjArrayHelperTemplate(objType, sipType, errmsg): ignored. But for those cases where the C array is the only option then this helper can be used to make the array from a sequence. """ - + cppCode = """\ -// Convert a Python sequence of {objType} objects, or items that can be converted +// Convert a Python sequence of {objType} objects, or items that can be converted // to {objType} into a C array of {objType} instances. static {objType}* {objType}_array_helper(PyObject* source, size_t *count) @@ -1123,9 +1123,9 @@ static {objType}* array; Py_ssize_t idx, len; wxPyThreadBlocker blocker; - + // ensure that it is a sequence - if (! PySequence_Check(source)) + if (! PySequence_Check(source)) goto error0; // ensure it is not a string or unicode object (they are sequences too) else if (PyBytes_Check(source) || PyUnicode_Check(source)) @@ -1142,7 +1142,7 @@ static Py_DECREF(item); }} }} - + // The length of the sequence is returned in count. *count = len; array = new {objType}[*count];