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 if name.startswith('_'): name = name[1:] destFile = os.path.join(phoenixRoot, 'wx', name) destFile_pi = destFile + '.pi' destFile_pyi = destFile + '.pyi' def _checkAndWriteHeader(destFile, header, docstring): if not os.path.exists(destFile): # create the file and write the header f = textfile_open(destFile, 'wt') f.write(header) if docstring: f.write('\n"""\n%s"""\n' % docstring) f.close() if not SKIP_PI_FILE: _checkAndWriteHeader(destFile_pi, header_pi, module.docstring) self.writeSection(destFile_pi, module.name, stream.getvalue()) if not SKIP_PYI_FILE: _checkAndWriteHeader(destFile_pyi, header_pyi, module.docstring) self.writeSection(destFile_pyi, module.name, stream.getvalue())
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') with textfile_open(destFile, 'wt') as f: f.write(stream.getvalue())
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 + '.pi' if name.startswith('_'): name = name[1:] destFile = os.path.join(phoenixRoot, 'wx', name) if not os.path.exists(destFile): # create the file and write the header f = textfile_open(destFile, 'wt') f.write(header) f.close() self.writeSection(destFile, module.name, stream.getvalue())
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(')') args = argsString[:lastP].strip('()').split(',') for idx, p in enumerate(paramList): if p.ignored: args[idx] = '' args = [a for a in args if a != ''] return '(' + ', '.join(args) + ')' assert isinstance(method, extractors.CppMethodDef) if method.ignored: return _needDocstring = getattr(method, '_needDocstring', True) argsString = _removeIgnoredParams(method.argsString, method.items) lastP = argsString.rfind(')') 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() # remove annotations 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] pnames[idx] = name pnames = ', '.join(pnames) typ = method.type if not skipDeclaration: 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' % (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 "" pure = " = 0" if method.isPureVirtual else "" 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) # create the new function fstream = Utf8EncodingStream( ) # using a new stream so we can do the actual write a little later lastP = argsString.rfind(')') 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.replace( '&', '*') # SIP will always want to use pointers for parameters arg = re.sub('/[A-Za-z]*/', '', arg) # remove annotations fargs[idx] = arg fargs = ', '.join(fargs) if method.isCtor: fname = '_%s_ctor' % klass.name fargs = '(%s)' % fargs fstream.write('%s%%TypeCode\n' % indent) typ = klass.name if method.useDerivedName: typ = 'sip' + klass.name fstream.write( '%sclass %s;\n' % (indent, typ)) # forward declare the derived class fstream.write('%s%s* %s%s\n%s{\n' % (indent, typ, fname, fargs, indent)) 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 fstream.write('%s%%TypeCode\n' % indent) fstream.write('%svoid %s%s\n%s{\n' % (indent, fname, fargs, indent)) 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) if method.isStatic: # If the method is static then there is no sipCpp to send to # the new function, so it should not have a self parameter. fargs = '(%s)' % fargs else: if fargs: fargs = ', ' + fargs selfConst = '' if method.isConst: selfConst = 'const ' fargs = '(%s%s* self%s)' % (selfConst, klass.name, fargs) fstream.write('%s%%TypeCode\n' % indent) else: 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 # objects. typPtr = method.type if typPtr in forcePtrTypes: if '&' in typPtr: 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) fstream.write('%s%%End\n' % indent) # Write the code that will call the new function stream.write('%s%%MethodCode\n' % indent) stream.write(indent + ' ' * 4) if method.isCtor: # _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)) else: stream.write('PyErr_Clear();\n') stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent + ' ' * 4)) stream.write(indent + ' ' * 4) if method.type != 'void': stream.write('sipRes = ') if klass: if method.isStatic: # If the method is static then there is no sipCpp to send to # the new function, so it should not have a self parameter. stream.write('%s(%s);\n' % (fname, pnames)) else: if pnames: pnames = ', ' + pnames if method.isSlot: argname = 'a0' else: argname = 'sipCpp' stream.write('%s(%s%s);\n' % (fname, argname, pnames)) else: stream.write('%s(%s);\n' % (fname, pnames)) 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) if method.virtualCatcherCode: 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') if method.overloads: for m in method.overloads: m._needDocstring = _needDocstring self.dispatchClassItem(method.klass, m, stream, indent)