def generate(self, code_sink): """ Generate the getset table, return the table C name or '0' if the table is empty """ if not self.attributes: return '0' getsets = {} # attrname -> (getter, setter) for name, getter, setter in self.attributes: getter_name = 'NULL' if getter is not None: # getter.generate(code_sink) try: utils.call_with_error_handling(getter.generate, (code_sink,), {}, getter) except utils.SkipWrapper: pass else: getter_name = getter.c_function_name setter_name = 'NULL' if setter is not None: #setter.generate(code_sink) try: utils.call_with_error_handling(setter.generate, (code_sink,), {}, setter) except utils.SkipWrapper: pass else: setter_name = setter.c_function_name assert name not in getsets getsets[name] = (getter_name, setter_name) code_sink.writeln("static PyGetSetDef %s[] = {" % self.cname) code_sink.indent() for name, (getter_c_name, setter_c_name) in getsets.iteritems(): code_sink.writeln('{') code_sink.indent() code_sink.writeln('(char*) "%s", /* attribute name */' % name) ## getter code_sink.writeln( '(getter) %s, /* C function to get the attribute */' % getter_c_name) ## setter code_sink.writeln( '(setter) %s, /* C function to set the attribute */' % setter_c_name) code_sink.writeln('NULL, /* optional doc string */') code_sink.writeln('NULL /* optional additional data ' 'for getter and setter */') code_sink.unindent() code_sink.writeln('},') code_sink.writeln('{ NULL, NULL, NULL, NULL, NULL }') code_sink.unindent() code_sink.writeln('};') return self.cname
def _normalize_py_method_flags(self): """ Checks that if all overloaded wrappers have similar method flags, forcing similar flags if needed (via method.force_parse = ForwardWrapperBase.PARSE_TUPLE_AND_KEYWORDS) """ if len(self.wrappers) == 1: return for wrapper in self.wrappers: wrapper.force_parse = ForwardWrapperBase.PARSE_TUPLE_AND_KEYWORDS # loop that keeps removing wrappers until all remaining wrappers have the same flags modified = True while modified: existing_flags = None modified = False for wrapper in self.wrappers: try: wrapper_flags = utils.call_with_error_handling( wrapper.get_py_method_def_flags, args=(), kwargs={}, wrapper=wrapper) except utils.SkipWrapper, ex: modified = True self.wrappers.remove(wrapper) dummy1, dummy2, tb = sys.exc_info() settings.error_handler.handle_error(wrapper, ex, tb) break wrapper_flags = set(wrapper_flags) if existing_flags is None: existing_flags = wrapper_flags else: if wrapper_flags != existing_flags: modified = True self.wrappers.remove(wrapper) tb = traceback.extract_stack() ex = utils.SkipWrapper( "overloading: removed the wrapper %s because its" " method flags are different from existing ones." % (wrapper,)) settings.error_handler.handle_error(wrapper, ex, tb) break
def do_generate(self, out, module_file_base_name=None): """(internal) Generates the module.""" assert isinstance(out, _SinkManager) if self.parent is None: ## generate the include directives (only the root module) forward_declarations_sink = MemoryCodeSink() if not self._forward_declarations_declared: self.generate_forward_declarations(forward_declarations_sink) self.after_forward_declarations.flush_to( forward_declarations_sink) if self.parent is None: for include in self.includes: out.get_includes_code_sink().writeln("#include %s" % include) self.includes = None forward_declarations_sink.flush_to(out.get_includes_code_sink()) else: assert module_file_base_name is None, "only root modules can generate with alternate module_file_base_name" ## generate the submodules for submodule in self.submodules: submodule.do_generate(out) m = self.declarations.declare_variable('PyObject*', 'm') assert m == 'm' if module_file_base_name is None: mod_init_name = '.'.join(self.get_module_path()) else: mod_init_name = module_file_base_name self.before_init.write_code( "m = Py_InitModule3((char *) \"%s\", %s_functions, %s);" % (mod_init_name, self.prefix, self.docstring and '"' + self.docstring + '"' or 'NULL')) self.before_init.write_error_check("m == NULL") main_sink = out.get_main_code_sink() ## generate the function wrappers py_method_defs = [] if self.functions: main_sink.writeln('/* --- module functions --- */') main_sink.writeln() for func_name, overload in self.functions.iteritems(): sink, header_sink = out.get_code_sink_for_wrapper(overload) sink.writeln() try: utils.call_with_error_handling(overload.generate, (sink, ), {}, overload) except utils.SkipWrapper: continue try: utils.call_with_error_handling( overload.generate_declaration, (main_sink, ), {}, overload) except utils.SkipWrapper: continue sink.writeln() py_method_defs.append(overload.get_py_method_def(func_name)) del sink ## generate the function table main_sink.writeln("static PyMethodDef %s_functions[] = {" % (self.prefix, )) main_sink.indent() for py_method_def in py_method_defs: main_sink.writeln(py_method_def) main_sink.writeln("{NULL, NULL, 0, NULL}") main_sink.unindent() main_sink.writeln("};") ## generate the classes if self.classes: main_sink.writeln('/* --- classes --- */') main_sink.writeln() for class_ in [c for c in self.classes if c.import_from_module]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() for class_ in [ c for c in self.classes if not c.import_from_module ]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() ## generate the containers if self.containers: main_sink.writeln('/* --- containers --- */') main_sink.writeln() for container in self.containers: sink, header_sink = out.get_code_sink_for_wrapper(container) sink.writeln() container.generate(sink, self) sink.writeln() ## generate the exceptions if self.exceptions: main_sink.writeln('/* --- exceptions --- */') main_sink.writeln() for exc in self.exceptions: sink, header_sink = out.get_code_sink_for_wrapper(exc) sink.writeln() exc.generate(sink, self) sink.writeln() # typedefs for (wrapper, alias) in self.typedefs: if isinstance(wrapper, CppClass): cls = wrapper cls.generate_typedef(self, alias) ## generate the enums if self.enums: main_sink.writeln('/* --- enumerations --- */') main_sink.writeln() for enum in self.enums: sink, header_sink = out.get_code_sink_for_wrapper(enum) sink.writeln() enum.generate(sink) enum.generate_declaration(header_sink, self) sink.writeln() ## register the submodules if self.submodules: submodule_var = self.declarations.declare_variable( 'PyObject*', 'submodule') for submodule in self.submodules: self.after_init.write_code( '%s = %s();' % (submodule_var, submodule.init_function_name)) self.after_init.write_error_check('%s == NULL' % submodule_var) self.after_init.write_code('Py_INCREF(%s);' % (submodule_var, )) self.after_init.write_code( 'PyModule_AddObject(m, (char *) "%s", %s);' % ( submodule.name, submodule_var, )) ## flush the header section self.header.flush_to(out.get_includes_code_sink()) ## flush the body section self.body.flush_to(main_sink) ## now generate the module init function itself main_sink.writeln() if self.parent is None: main_sink.writeln(''' PyMODINIT_FUNC #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif''') else: main_sink.writeln("static PyObject *") if module_file_base_name is None: main_sink.writeln("%s(void)" % (self.init_function_name, )) else: main_sink.writeln("init%s(void)" % (module_file_base_name, )) main_sink.writeln('{') main_sink.indent() self.declarations.get_code_sink().flush_to(main_sink) self.before_init.sink.flush_to(main_sink) self.after_init.write_cleanup() self.after_init.sink.flush_to(main_sink) if self.parent is not None: main_sink.writeln("return m;") main_sink.unindent() main_sink.writeln('}')
def generate(self, code_sink): """ Generate all the wrappers plus the 'aggregator' wrapper to a code sink. """ self._normalize_py_method_flags() self._compute_all_wrappers() if len(self.all_wrappers) == 0: raise utils.SkipWrapper elif len(self.all_wrappers) == 1 \ and not getattr(self.all_wrappers[0], 'NEEDS_OVERLOADING_INTERFACE', False): ## special case when there's only one wrapper; keep ## simple things simple #self.all_wrappers[0].generate(code_sink) prototype_line = utils.call_with_error_handling(self.all_wrappers[0].generate, (code_sink,), {}, self.all_wrappers[0]) self.wrapper_actual_name = self.all_wrappers[0].wrapper_actual_name assert self.wrapper_actual_name is not None self.wrapper_return = self.all_wrappers[0].wrapper_return self.wrapper_args = self.all_wrappers[0].wrapper_args else: ## multiple overloaded wrappers case.. flags = self.all_wrappers[0].get_py_method_def_flags() ## Generate the individual "low level" wrappers that handle a single prototype self.wrapper_actual_name = self.all_wrappers[0].wrapper_base_name delegate_wrappers = [] for number, wrapper in enumerate(self.all_wrappers): ## enforce uniform method flags wrapper.force_parse = wrapper.PARSE_TUPLE_AND_KEYWORDS ## an extra parameter 'return_exception' is used to ## return parse error exceptions to the 'main wrapper' error_return = """{ PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } %s""" % (self.ERROR_RETURN,) wrapper_name = "%s__%i" % (self.wrapper_actual_name, number) wrapper.set_parse_error_return(error_return) code_sink.writeln() # wrapper.generate(code_sink, wrapper_name, # extra_wrapper_params=["PyObject **return_exception"]) try: utils.call_with_error_handling( wrapper.generate, args=(code_sink, wrapper_name), kwargs=dict(extra_wrapper_params=["PyObject **return_exception"]), wrapper=wrapper) except utils.SkipWrapper: continue delegate_wrappers.append(wrapper.wrapper_actual_name) ## if all wrappers did not generate, then the overload ## aggregator wrapper should not be generated either.. if not delegate_wrappers: raise utils.SkipWrapper ## Generate the 'main wrapper' that calls the other ones code_sink.writeln() self.wrapper_return = self.RETURN_TYPE self.wrapper_args = ['%s *self' % self.pystruct] if 'METH_VARARGS' in flags: self.wrapper_args.append('PyObject *args') if 'METH_KEYWORDS' in flags: self.wrapper_args.append('PyObject *kwargs') prototype_line = "%s %s(%s)" % (self.wrapper_return, self.wrapper_actual_name, ', '.join(self.wrapper_args)) code_sink.writeln(prototype_line) code_sink.writeln('{') code_sink.indent() code_sink.writeln(self.RETURN_TYPE + ' retval;') code_sink.writeln('PyObject *error_list;') code_sink.writeln('PyObject *exceptions[%i] = {0,};' % len(delegate_wrappers)) for number, delegate_wrapper in enumerate(delegate_wrappers): ## call the delegate wrapper args = ['self'] if 'METH_VARARGS' in flags: args.append('args') if 'METH_KEYWORDS' in flags: args.append('kwargs') args.append('&exceptions[%i]' % number) code_sink.writeln("retval = %s(%s);" % (delegate_wrapper, ', '.join(args))) ## if no parse exception, call was successful: ## free previous exceptions and return the result code_sink.writeln("if (!exceptions[%i]) {" % number) code_sink.indent() for i in xrange(number): code_sink.writeln("Py_DECREF(exceptions[%i]);" % i) code_sink.writeln("return retval;") code_sink.unindent() code_sink.writeln("}") ## If the following generated code is reached it means ## that all of our delegate wrappers had parsing errors: ## raise an appropriate exception, free the previous ## exceptions, and return NULL code_sink.writeln('error_list = PyList_New(%i);' % len(delegate_wrappers)) for i in xrange(len(delegate_wrappers)): code_sink.writeln( 'PyList_SET_ITEM(error_list, %i, PyObject_Str(exceptions[%i]));' % (i, i)) code_sink.writeln("Py_DECREF(exceptions[%i]);" % i) code_sink.writeln('PyErr_SetObject(PyExc_TypeError, error_list);') code_sink.writeln("Py_DECREF(error_list);") code_sink.writeln(self.ERROR_RETURN) code_sink.unindent() code_sink.writeln('}') return prototype_line
def do_generate(self, out, module_file_base_name=None): """(internal) Generates the module.""" assert isinstance(out, _SinkManager) if self.parent is None: ## generate the include directives (only the root module) forward_declarations_sink = MemoryCodeSink() if not self._forward_declarations_declared: self.generate_forward_declarations(forward_declarations_sink) self.after_forward_declarations.flush_to(forward_declarations_sink) if self.parent is None: for include in self.includes: out.get_includes_code_sink().writeln("#include %s" % include) self.includes = None forward_declarations_sink.flush_to(out.get_includes_code_sink()) else: assert module_file_base_name is None, "only root modules can generate with alternate module_file_base_name" ## generate the submodules for submodule in self.submodules: submodule.do_generate(out) m = self.declarations.declare_variable('PyObject*', 'm') assert m == 'm' if module_file_base_name is None: mod_init_name = '.'.join(self.get_module_path()) else: mod_init_name = module_file_base_name self.before_init.write_code( "m = Py_InitModule3((char *) \"%s\", %s_functions, %s);" % (mod_init_name, self.prefix, self.docstring and '"'+self.docstring+'"' or 'NULL')) self.before_init.write_error_check("m == NULL") main_sink = out.get_main_code_sink() ## generate the function wrappers py_method_defs = [] if self.functions: main_sink.writeln('/* --- module functions --- */') main_sink.writeln() for func_name, overload in self.functions.iteritems(): sink, header_sink = out.get_code_sink_for_wrapper(overload) sink.writeln() try: utils.call_with_error_handling(overload.generate, (sink,), {}, overload) except utils.SkipWrapper: continue try: utils.call_with_error_handling(overload.generate_declaration, (main_sink,), {}, overload) except utils.SkipWrapper: continue sink.writeln() py_method_defs.append(overload.get_py_method_def(func_name)) del sink ## generate the function table main_sink.writeln("static PyMethodDef %s_functions[] = {" % (self.prefix,)) main_sink.indent() for py_method_def in py_method_defs: main_sink.writeln(py_method_def) main_sink.writeln("{NULL, NULL, 0, NULL}") main_sink.unindent() main_sink.writeln("};") ## generate the classes if self.classes: main_sink.writeln('/* --- classes --- */') main_sink.writeln() for class_ in [c for c in self.classes if c.import_from_module]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() for class_ in [c for c in self.classes if not c.import_from_module]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() ## generate the containers if self.containers: main_sink.writeln('/* --- containers --- */') main_sink.writeln() for container in self.containers: sink, header_sink = out.get_code_sink_for_wrapper(container) sink.writeln() container.generate(sink, self) sink.writeln() ## generate the exceptions if self.exceptions: main_sink.writeln('/* --- exceptions --- */') main_sink.writeln() for exc in self.exceptions: sink, header_sink = out.get_code_sink_for_wrapper(exc) sink.writeln() exc.generate(sink, self) sink.writeln() # typedefs for (wrapper, alias) in self.typedefs: if isinstance(wrapper, CppClass): cls = wrapper cls.generate_typedef(self, alias) ## generate the enums if self.enums: main_sink.writeln('/* --- enumerations --- */') main_sink.writeln() for enum in self.enums: sink, header_sink = out.get_code_sink_for_wrapper(enum) sink.writeln() enum.generate(sink) enum.generate_declaration(header_sink, self) sink.writeln() ## register the submodules if self.submodules: submodule_var = self.declarations.declare_variable('PyObject*', 'submodule') for submodule in self.submodules: self.after_init.write_code('%s = %s();' % ( submodule_var, submodule.init_function_name)) self.after_init.write_error_check('%s == NULL' % submodule_var) self.after_init.write_code('Py_INCREF(%s);' % (submodule_var,)) self.after_init.write_code('PyModule_AddObject(m, (char *) "%s", %s);' % (submodule.name, submodule_var,)) ## flush the header section self.header.flush_to(out.get_includes_code_sink()) ## flush the body section self.body.flush_to(main_sink) ## now generate the module init function itself main_sink.writeln() if self.parent is None: main_sink.writeln(''' PyMODINIT_FUNC #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif''') else: main_sink.writeln("static PyObject *") if module_file_base_name is None: main_sink.writeln("%s(void)" % (self.init_function_name,)) else: main_sink.writeln("init%s(void)" % (module_file_base_name,)) main_sink.writeln('{') main_sink.indent() self.declarations.get_code_sink().flush_to(main_sink) self.before_init.sink.flush_to(main_sink) self.after_init.write_cleanup() self.after_init.sink.flush_to(main_sink) if self.parent is not None: main_sink.writeln("return m;") main_sink.unindent() main_sink.writeln('}')
def generate(self, code_sink): """ Generate the getset table, return the table C name or '0' if the table is empty """ if not self.attributes: return '0' getsets = {} # attrname -> (getter, setter) for name, getter, setter in self.attributes: getter_name = 'NULL' if getter is not None: # getter.generate(code_sink) try: utils.call_with_error_handling(getter.generate, (code_sink, ), {}, getter) except utils.SkipWrapper: pass else: getter_name = getter.c_function_name setter_name = 'NULL' if setter is not None: #setter.generate(code_sink) try: utils.call_with_error_handling(setter.generate, (code_sink, ), {}, setter) except utils.SkipWrapper: pass else: setter_name = setter.c_function_name assert name not in getsets getsets[name] = (getter_name, setter_name) code_sink.writeln("static PyGetSetDef %s[] = {" % self.cname) code_sink.indent() for name, (getter_c_name, setter_c_name) in getsets.iteritems(): code_sink.writeln('{') code_sink.indent() code_sink.writeln('(char*) "%s", /* attribute name */' % name) ## getter code_sink.writeln( '(getter) %s, /* C function to get the attribute */' % getter_c_name) ## setter code_sink.writeln( '(setter) %s, /* C function to set the attribute */' % setter_c_name) code_sink.writeln('NULL, /* optional doc string */') code_sink.writeln('NULL /* optional additional data ' 'for getter and setter */') code_sink.unindent() code_sink.writeln('},') code_sink.writeln('{ NULL, NULL, NULL, NULL, NULL }') code_sink.unindent() code_sink.writeln('};') return self.cname