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
Example #2
0
    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
Example #3
0
    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('}')
Example #4
0
    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
Example #5
0
    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('}')
Example #6
0
    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