class _MonolithicSinkManager(_SinkManager): """ Sink manager that deals with single-section monolithic code generation. """ def __init__(self, code_sink): super(_MonolithicSinkManager, self).__init__() self.final_code_sink = code_sink self.null_sink = NullCodeSink() self.includes = MemoryCodeSink() self.code_sink = MemoryCodeSink() utils.write_preamble(code_sink) def get_code_sink_for_wrapper(self, dummy_wrapper): return self.code_sink, self.code_sink def get_includes_code_sink(self): return self.includes def get_main_code_sink(self): return self.code_sink def close(self): self.includes.flush_to(self.final_code_sink) self.code_sink.flush_to(self.final_code_sink)
def __init__(self, name, parent=None, docstring=None, cpp_namespace=None): """ Note: this is an abstract base class, see L{Module} :param name: module name :param parent: parent L{module<Module>} (i.e. the one that contains this submodule) or None if this is a root module :param docstring: docstring to use for this module :param cpp_namespace: C++ namespace prefix associated with this module :return: a new module object """ super(ModuleBase, self).__init__() self.parent = parent self.docstring = docstring self.submodules = [] self.enums = [] self.typedefs = [] # list of (wrapper, alias) tuples self._forward_declarations_declared = False self.cpp_namespace = cpp_namespace if self.parent is None: error_return = 'return MOD_ERROR;' self.after_forward_declarations = MemoryCodeSink() else: self.after_forward_declarations = None self.parent.submodules.append(self) error_return = 'return NULL;' self.prefix = None self.init_function_name = None self._name = None self.name = name path = self.get_namespace_path() if path and path[0] == '::': del path[0] self.cpp_namespace_prefix = '::'.join(path) self.declarations = DeclarationsScope() self.functions = {} # name => OverloadedFunction self.classes = [] self.containers = [] self.exceptions = [] self.before_init = CodeBlock(error_return, self.declarations) self.after_init = CodeBlock(error_return, self.declarations, predecessor=self.before_init) self.c_function_name_transformer = None self.set_strip_prefix(name + '_') if parent is None: self.header = MemoryCodeSink() self.body = MemoryCodeSink() self.one_time_definitions = {} self.includes = [] else: self.header = parent.header self.body = parent.body self.one_time_definitions = parent.one_time_definitions self.includes = parent.includes self._current_section = '__main__'
def __init__(self, code_sink): super(_MonolithicSinkManager, self).__init__() self.final_code_sink = code_sink self.null_sink = NullCodeSink() self.includes = MemoryCodeSink() self.code_sink = MemoryCodeSink() utils.write_preamble(code_sink)
def __init__(self, code_sink): super(_MonolithicSinkManager, self).__init__() self.final_code_sink = code_sink self.null_sink = NullCodeSink() self.includes = MemoryCodeSink() self.code_sink = MemoryCodeSink() utils.write_preamble(code_sink)
class _MonolithicSinkManager(_SinkManager): """ Sink manager that deals with single-section monolithic code generation. """ def __init__(self, code_sink): super(_MonolithicSinkManager, self).__init__() self.final_code_sink = code_sink self.null_sink = NullCodeSink() self.includes = MemoryCodeSink() self.code_sink = MemoryCodeSink() utils.write_preamble(code_sink) def get_code_sink_for_wrapper(self, dummy_wrapper): return self.code_sink, self.code_sink def get_includes_code_sink(self): return self.includes def get_main_code_sink(self): return self.code_sink def close(self): self.includes.flush_to(self.final_code_sink) self.code_sink.flush_to(self.final_code_sink)
def generate_callback_classes(out, callbacks): for callback_impl_num, template_parameters in enumerate(callbacks): sink = MemoryCodeSink() cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) class_name = "PythonCallbackImpl%i" % callback_impl_num sink.writeln( % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) sink.indent() callback_return = template_parameters[0] return_ctype = ctypeparser.parse_type(callback_return) if ('const' in return_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: return_type = ReturnValue.new(str(return_ctype), **kwargs) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r" % (callback_return, cls_name, ex), Warning) continue arguments = [] ok = True callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty'] for arg_num, arg_type in enumerate(callback_parameters): arg_name = 'arg%i' % (arg_num+1) param_ctype = ctypeparser.parse_type(arg_type) if ('const' in param_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: arguments.append(Parameter.new(str(param_ctype), arg_name, **kwargs)) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r" % (arg_type, arg_name, cls_name, ex), Warning) ok = False
def __init__(self, name, parent=None, docstring=None, cpp_namespace=None): """ Note: this is an abstract base class, see L{Module} :param name: module name :param parent: parent L{module<Module>} (i.e. the one that contains this submodule) or None if this is a root module :param docstring: docstring to use for this module :param cpp_namespace: C++ namespace prefix associated with this module :return: a new module object """ super(ModuleBase, self).__init__() self.parent = parent self.docstring = docstring self.submodules = [] self.enums = [] self.typedefs = [] # list of (wrapper, alias) tuples self._forward_declarations_declared = False self.cpp_namespace = cpp_namespace if self.parent is None: error_return = 'return MOD_ERROR;' self.after_forward_declarations = MemoryCodeSink() else: self.after_forward_declarations = None self.parent.submodules.append(self) error_return = 'return NULL;' self.prefix = None self.init_function_name = None self._name = None self.name = name path = self.get_namespace_path() if path and path[0] == '::': del path[0] self.cpp_namespace_prefix = '::'.join(path) self.declarations = DeclarationsScope() self.functions = {} # name => OverloadedFunction self.classes = [] self.containers = [] self.exceptions = [] self.before_init = CodeBlock(error_return, self.declarations) self.after_init = CodeBlock(error_return, self.declarations, predecessor=self.before_init) self.c_function_name_transformer = None self.set_strip_prefix(name + '_') if parent is None: self.header = MemoryCodeSink() self.body = MemoryCodeSink() self.one_time_definitions = {} self.includes = [] else: self.header = parent.header self.body = parent.body self.one_time_definitions = parent.one_time_definitions self.includes = parent.includes self._current_section = '__main__'
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('#if PY_VERSION_HEX >= 0x03000000') self.before_init.write_code( "m = PyModule_Create(&%s_moduledef);" % (self.prefix)) self.before_init.write_code('#else') 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_code('#endif') 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.items(): 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 PY_VERSION_HEX >= 0x03000000\n' 'static struct PyModuleDef %s_moduledef = {\n' ' PyModuleDef_HEAD_INIT,\n' ' "%s",\n' ' %s,\n' ' -1,\n' ' %s_functions,\n' '};\n' '#endif' % (self.prefix, mod_init_name, self.docstring and '"'+self.docstring+'"' or 'NULL', self.prefix)) main_sink.writeln() if self.parent is None: main_sink.writeln(''' #if PY_VERSION_HEX >= 0x03000000 #define MOD_ERROR NULL #define MOD_INIT(name) PyObject* PyInit_##name(void) #define MOD_RETURN(val) val #else #define MOD_ERROR #define MOD_INIT(name) void init##name(void) #define MOD_RETURN(val) #endif #if defined(__cplusplus) extern "C" #endif #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif ''') else: main_sink.writeln("static PyObject *") if self.parent is None: main_sink.writeln("MOD_INIT(%s)" % (self.name,)) elif 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;") else: main_sink.writeln("return MOD_RETURN(m);") main_sink.unindent() main_sink.writeln('}')
class ModuleBase(dict): """ ModuleBase objects can be indexed dictionary style to access contained types. Example:: >>> from enum import Enum >>> from cppclass import CppClass >>> m = Module("foo", cpp_namespace="foo") >>> subm = m.add_cpp_namespace("subm") >>> c1 = m.add_class("Bar") >>> c2 = subm.add_class("Zbr") >>> e1 = m.add_enum("En1", ["XX"]) >>> e2 = subm.add_enum("En2", ["XX"]) >>> m["Bar"] is c1 True >>> m["foo::Bar"] is c1 True >>> m["En1"] is e1 True >>> m["foo::En1"] is e1 True >>> m["badname"] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'badname' >>> m["foo::subm::Zbr"] is c2 True >>> m["foo::subm::En2"] is e2 True """ def __init__(self, name, parent=None, docstring=None, cpp_namespace=None): """ Note: this is an abstract base class, see L{Module} :param name: module name :param parent: parent L{module<Module>} (i.e. the one that contains this submodule) or None if this is a root module :param docstring: docstring to use for this module :param cpp_namespace: C++ namespace prefix associated with this module :return: a new module object """ super(ModuleBase, self).__init__() self.parent = parent self.docstring = docstring self.submodules = [] self.enums = [] self.typedefs = [] # list of (wrapper, alias) tuples self._forward_declarations_declared = False self.cpp_namespace = cpp_namespace if self.parent is None: error_return = 'return MOD_ERROR;' self.after_forward_declarations = MemoryCodeSink() else: self.after_forward_declarations = None self.parent.submodules.append(self) error_return = 'return NULL;' self.prefix = None self.init_function_name = None self._name = None self.name = name path = self.get_namespace_path() if path and path[0] == '::': del path[0] self.cpp_namespace_prefix = '::'.join(path) self.declarations = DeclarationsScope() self.functions = {} # name => OverloadedFunction self.classes = [] self.containers = [] self.exceptions = [] self.before_init = CodeBlock(error_return, self.declarations) self.after_init = CodeBlock(error_return, self.declarations, predecessor=self.before_init) self.c_function_name_transformer = None self.set_strip_prefix(name + '_') if parent is None: self.header = MemoryCodeSink() self.body = MemoryCodeSink() self.one_time_definitions = {} self.includes = [] else: self.header = parent.header self.body = parent.body self.one_time_definitions = parent.one_time_definitions self.includes = parent.includes self._current_section = '__main__' def get_current_section(self): return self.get_root()._current_section current_section = property(get_current_section) def begin_section(self, section_name): """ Declare that types and functions registered with the module in the future belong to the section given by that section_name parameter, until a matching end_section() is called. .. note:: :meth:`begin_section`/:meth:`end_section` are silently ignored unless a :class:`MultiSectionFactory` object is used as code generation output. """ if self.current_section != '__main__': raise ValueError("begin_section called while current section not ended") if section_name == '__main__': raise ValueError ("__main__ not allowed as section name") assert self.parent is None self._current_section = section_name def end_section(self, section_name): """ Declare the end of a section, i.e. further types and functions will belong to the main module. :param section_name: name of section; must match the one in the previous :meth:`begin_section` call. """ assert self.parent is None if self._current_section != section_name: raise ValueError("end_section called for wrong section: expected %r, got %r" % (self._current_section, section_name)) self._current_section = '__main__' def get_name(self): return self._name def set_name(self, name): self._name = name if self.parent is None: self.prefix = self.name.replace('.', '_') self.init_function_name = "init%s" % (self.name.split('.')[-1],) else: self.prefix = self.parent.prefix + "_" + self.name self.init_function_name = "init%s" % (self.prefix,) name = property(get_name, set_name) def get_submodule(self, submodule_name): "get a submodule by its name" for submodule in self.submodules: if submodule.name == submodule_name: return submodule raise ValueError("submodule %s not found" % submodule_name) def get_root(self): ":return: the root :class:`Module` (even if it is self)" root = self while root.parent is not None: root = root.parent return root def set_strip_prefix(self, prefix): """Sets the prefix string to be used when transforming a C function name into the python function name; the given prefix string is removed from the C function name.""" def strip_prefix(c_name): """A C funtion name transformer that simply strips a common prefix from the name""" if c_name.startswith(prefix): return c_name[len(prefix):] else: return c_name self.c_function_name_transformer = strip_prefix def set_c_function_name_transformer(self, transformer): """Sets the function to be used when transforming a C function name into the python function name; the given given function is called like this:: python_name = transformer(c_name) """ self.c_function_name_transformer = transformer def add_include(self, include): """ Adds an additional include directive, needed to compile this python module :param include: the name of the header file to include, including surrounding "" or <>. """ include = utils.ascii(include) assert include.startswith('"') or include.startswith('<') assert include.endswith('"') or include.endswith('>') if include not in self.includes: self.includes.append(include) def _add_function_obj(self, wrapper): assert isinstance(wrapper, Function) name = utils.ascii(wrapper.custom_name) if name is None: name = self.c_function_name_transformer(wrapper.function_name) name = utils.get_mangled_name(name, wrapper.template_parameters) try: overload = self.functions[name] except KeyError: overload = OverloadedFunction(name) self.functions[name] = overload wrapper.module = self wrapper.section = self.current_section overload.add(wrapper) def add_function(self, *args, **kwargs): """ Add a function to the module/namespace. See the documentation for :meth:`Function.__init__` for information on accepted parameters. """ if len(args) >= 1 and isinstance(args[0], Function): func = args[0] warnings.warn("add_function has changed API; see the API documentation", DeprecationWarning, stacklevel=2) if len(args) == 2: func.custom_name = args[1] elif 'name' in kwargs: assert len(args) == 1 func.custom_name = kwargs['name'] else: assert len(args) == 1 assert len(kwargs) == 0 else: try: func = Function(*args, **kwargs) except utils.SkipWrapper: return None self._add_function_obj(func) return func def add_custom_function_wrapper(self, *args, **kwargs): """ Add a function, using custom wrapper code, to the module/namespace. See the documentation for :class:`pybindgen.function.CustomFunctionWrapper` for information on accepted parameters. """ try: func = CustomFunctionWrapper(*args, **kwargs) except utils.SkipWrapper: return None self._add_function_obj(func) return func def register_type(self, name, full_name, type_wrapper): """ Register a type wrapper with the module, for easy access in the future. Normally should not be called by the programmer, as it is meant for internal pybindgen use and called automatically. :param name: type name without any C++ namespace prefix, or None :param full_name: type name with a C++ namespace prefix, or None :param type_wrapper: the wrapper object for the type (e.g. L{CppClass} or L{Enum}) """ module = self if name: module[name] = type_wrapper if full_name: while module is not None: module[full_name] = type_wrapper module = module.parent def _add_class_obj(self, class_): """ Add a class to the module. :param class_: a CppClass object """ assert isinstance(class_, CppClass) class_.module = self class_.section = self.current_section self.classes.append(class_) self.register_type(class_.name, class_.full_name, class_) def add_class(self, *args, **kwargs): """ Add a class to the module. See the documentation for L{CppClass.__init__} for information on accepted parameters. """ if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], CppClass): cls = args[0] warnings.warn("add_class has changed API; see the API documentation", DeprecationWarning, stacklevel=2) else: cls = CppClass(*args, **kwargs) self._add_class_obj(cls) return cls def add_struct(self, *args, **kwargs): """ Add a struct to the module. In addition to the parameters accepted by L{CppClass.__init__}, this method accepts the following keyword parameters: - no_constructor (bool): if True, the structure will not have a constructor by default (if omitted, it will be considered to have a trivial constructor). - no_copy (bool): if True, the structure will not have a copy constructor by default (if omitted, it will be considered to have a simple copy constructor). """ try: no_constructor = kwargs['no_constructor'] except KeyError: no_constructor = False else: del kwargs['no_constructor'] try: no_copy = kwargs['no_copy'] except KeyError: no_copy = False else: del kwargs['no_copy'] struct = CppClass(*args, **kwargs) struct.stack_where_defined = traceback.extract_stack() self._add_class_obj(struct) if not no_constructor: struct.add_constructor([]) if not no_copy: struct.add_copy_constructor() return struct def add_cpp_namespace(self, name): """ Add a nested module namespace corresponding to a C++ namespace. If the requested namespace was already added, the existing module is returned instead of creating a new one. :param name: name of C++ namespace (just the last component, not full scoped name); this also becomes the name of the submodule. :return: a L{SubModule} object that maps to this namespace. """ name = utils.ascii(name) try: return self.get_submodule(name) except ValueError: module = SubModule(name, parent=self, cpp_namespace=name) module.stack_where_defined = traceback.extract_stack() return module def _add_enum_obj(self, enum): """ Add an enumeration. """ assert isinstance(enum, Enum) self.enums.append(enum) enum.module = self enum.section = self.current_section self.register_type(enum.name, enum.full_name, enum) def add_enum(self, *args, **kwargs): """ Add an enumeration to the module. See the documentation for L{Enum.__init__} for information on accepted parameters. """ if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], Enum): enum = args[0] warnings.warn("add_enum has changed API; see the API documentation", DeprecationWarning, stacklevel=2) else: enum = Enum(*args, **kwargs) enum.stack_where_defined = traceback.extract_stack() self._add_enum_obj(enum) return enum def _add_container_obj(self, container): """ Add a container to the module. :param container: a L{Container} object """ assert isinstance(container, Container) container.module = self container.section = self.current_section self.containers.append(container) self.register_type(container.name, container.full_name, container) def add_container(self, *args, **kwargs): """ Add a container to the module. See the documentation for L{Container.__init__} for information on accepted parameters. """ try: container = Container(*args, **kwargs) except utils.SkipWrapper: return None container.stack_where_defined = traceback.extract_stack() self._add_container_obj(container) return container def _add_exception_obj(self, exc): assert isinstance(exc, CppException) exc.module = self exc.section = self.current_section self.exceptions.append(exc) self.register_type(exc.name, exc.full_name, exc) def add_exception(self, *args, **kwargs): """ Add a C++ exception to the module. See the documentation for L{CppException.__init__} for information on accepted parameters. """ exc = CppException(*args, **kwargs) self._add_exception_obj(exc) return exc def declare_one_time_definition(self, definition_name): """ Internal helper method for code geneneration to coordinate generation of code that can only be defined once per compilation unit (note: assuming here one-to-one mapping between 'module' and 'compilation unit'). :param definition_name: a string that uniquely identifies the code definition that will be added. If the given definition was already declared KeyError is raised. >>> module = Module('foo') >>> module.declare_one_time_definition("zbr") >>> module.declare_one_time_definition("zbr") Traceback (most recent call last): ... KeyError: 'zbr' >>> module.declare_one_time_definition("bar") """ definition_name = utils.ascii(definition_name) if definition_name in self.one_time_definitions: raise KeyError(definition_name) self.one_time_definitions[definition_name] = None def generate_forward_declarations(self, code_sink): """(internal) generate forward declarations for types""" assert not self._forward_declarations_declared if self.classes or self.containers or self.exceptions: code_sink.writeln('/* --- forward declarations --- */') code_sink.writeln() for class_ in [c for c in self.classes if c.import_from_module]: class_.generate_forward_declarations(code_sink, self) for class_ in [c for c in self.classes if not c.import_from_module]: class_.generate_forward_declarations(code_sink, self) for container in self.containers: container.generate_forward_declarations(code_sink, self) for exc in self.exceptions: exc.generate_forward_declarations(code_sink, self) ## recurse to submodules for submodule in self.submodules: submodule.generate_forward_declarations(code_sink) self._forward_declarations_declared = True def get_module_path(self): """Get the full [module, submodule, submodule,...] path """ names = [self.name] parent = self.parent while parent is not None: names.insert(0, parent.name) parent = parent.parent return names def get_namespace_path(self): """Get the full [root_namespace, namespace, namespace,...] path (C++)""" if not self.cpp_namespace: names = [] else: if self.cpp_namespace == '::': names = [] else: names = self.cpp_namespace.split('::') if not names[0]: del names[0] parent = self.parent while parent is not None: if parent.cpp_namespace and parent.cpp_namespace != '::': parent_names = parent.cpp_namespace.split('::') if not parent_names[0]: del parent_names[0] names = parent_names + names parent = parent.parent return names 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('#if PY_VERSION_HEX >= 0x03000000') self.before_init.write_code( "m = PyModule_Create(&%s_moduledef);" % (self.prefix)) self.before_init.write_code('#else') 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_code('#endif') 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.items(): 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 PY_VERSION_HEX >= 0x03000000\n' 'static struct PyModuleDef %s_moduledef = {\n' ' PyModuleDef_HEAD_INIT,\n' ' "%s",\n' ' %s,\n' ' -1,\n' ' %s_functions,\n' '};\n' '#endif' % (self.prefix, mod_init_name, self.docstring and '"'+self.docstring+'"' or 'NULL', self.prefix)) main_sink.writeln() if self.parent is None: main_sink.writeln(''' #if PY_VERSION_HEX >= 0x03000000 #define MOD_ERROR NULL #define MOD_INIT(name) PyObject* PyInit_##name(void) #define MOD_RETURN(val) val #else #define MOD_ERROR #define MOD_INIT(name) void init##name(void) #define MOD_RETURN(val) #endif #if defined(__cplusplus) extern "C" #endif #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif ''') else: main_sink.writeln("static PyObject *") if self.parent is None: main_sink.writeln("MOD_INIT(%s)" % (self.name,)) elif 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;") else: main_sink.writeln("return MOD_RETURN(m);") main_sink.unindent() main_sink.writeln('}') def __repr__(self): return "<pybindgen.module.Module %r>" % self.name def add_typedef(self, wrapper, alias): """ Declares an equivalent to a typedef in C:: typedef Foo Bar; :param wrapper: the wrapper object to alias (Foo in the example) :param alias: name of the typedef alias @note: only typedefs for CppClass objects have been implemented so far; others will be implemented in the future. """ assert isinstance(wrapper, CppClass) alias = utils.ascii(alias) self.typedefs.append((wrapper, alias)) self.register_type(alias, alias, wrapper) wrapper.register_alias(alias) full_name = '::'.join(self.get_namespace_path() + [alias]) wrapper.register_alias(full_name)
def generate_callback_classes(module, callbacks): out = module.after_forward_declarations for callback_impl_num, template_parameters in enumerate(callbacks): sink = MemoryCodeSink() cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) #print >> sys.stderr, "***** trying to register callback: %r" % cls_name class_name = "PythonCallbackImpl%i" % callback_impl_num sink.writeln(''' class %s : public ns3::CallbackImpl<%s> { public: PyObject *m_callback; %s(PyObject *callback) { Py_INCREF(callback); m_callback = callback; } virtual ~%s() { PyGILState_STATE __py_gil_state; __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0); Py_DECREF(m_callback); m_callback = NULL; PyGILState_Release(__py_gil_state); } virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const { const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base)); if (other != NULL) return (other->m_callback == m_callback); else return false; } ''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) sink.indent() callback_return = template_parameters[0] return_ctype = ctypeparser.parse_type(callback_return) if ('const' in return_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: return_type = ReturnValue.new(str(return_ctype), **kwargs) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r" % (callback_return, cls_name, ex), Warning) continue arguments = [] ok = True callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty'] for arg_num, arg_type in enumerate(callback_parameters): arg_name = 'arg%i' % (arg_num+1) param_ctype = ctypeparser.parse_type(arg_type) if ('const' in param_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: param = Parameter.new(str(param_ctype), arg_name, **kwargs) cpp_class = getattr(param, "cpp_class", None) if isinstance(cpp_class, cppclass.CppClass): # check if the "helper class" can be constructed if cpp_class.helper_class is not None: cpp_class.helper_class.generate_forward_declarations( MemoryCodeSink()) if cpp_class.helper_class.cannot_be_constructed: cpp_class.helper_class = None cpp_class.helper_class_disabled = True arguments.append(param) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r" % (arg_type, arg_name, cls_name, ex), Warning) ok = False if not ok: try: typehandlers.return_type_matcher.lookup(cls_name)[0].DISABLED = True except typehandlers.TypeLookupError: pass try: typehandlers.param_type_matcher.lookup(cls_name)[0].DISABLED = True except typehandlers.TypeLookupError: pass continue wrapper = CallbackImplProxyMethod(return_type, arguments) wrapper.generate(sink, 'operator()', decl_modifiers=[]) sink.unindent() sink.writeln('};\n') print("Flushing to ", out, file=sys.stderr) sink.flush_to(out)
def generate_callback_classes(module, callbacks): out = module.after_forward_declarations for callback_impl_num, template_parameters in enumerate(callbacks): sink = MemoryCodeSink() cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) #print >> sys.stderr, "***** trying to register callback: %r" % cls_name class_name = "PythonCallbackImpl%i" % callback_impl_num sink.writeln(''' class %s : public ns3::CallbackImpl<%s> { public: PyObject *m_callback; %s(PyObject *callback) { Py_INCREF(callback); m_callback = callback; } virtual ~%s() { PyGILState_STATE __py_gil_state; __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0); Py_DECREF(m_callback); m_callback = NULL; PyGILState_Release(__py_gil_state); } virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const { const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base)); if (other != NULL) return (other->m_callback == m_callback); else return false; } ''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) sink.indent() callback_return = template_parameters[0] return_ctype = ctypeparser.parse_type(callback_return) if ('const' in return_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: return_type = ReturnValue.new(str(return_ctype), **kwargs) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn( "***** Unable to register callback; Return value '%s' error (used in %s): %r" % (callback_return, cls_name, ex), Warning) continue arguments = [] ok = True callback_parameters = [ arg for arg in template_parameters[1:] if arg != 'ns3::empty' ] for arg_num, arg_type in enumerate(callback_parameters): arg_name = 'arg%i' % (arg_num + 1) param_ctype = ctypeparser.parse_type(arg_type) if ('const' in param_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: param = Parameter.new(str(param_ctype), arg_name, **kwargs) cpp_class = getattr(param, "cpp_class", None) if isinstance(cpp_class, cppclass.CppClass): # check if the "helper class" can be constructed if cpp_class.helper_class is not None: cpp_class.helper_class.generate_forward_declarations( MemoryCodeSink()) if cpp_class.helper_class.cannot_be_constructed: cpp_class.helper_class = None cpp_class.helper_class_disabled = True arguments.append(param) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn( "***** Unable to register callback; parameter '%s %s' error (used in %s): %r" % (arg_type, arg_name, cls_name, ex), Warning) ok = False if not ok: try: typehandlers.return_type_matcher.lookup( cls_name)[0].DISABLED = True except typehandlers.TypeLookupError: pass try: typehandlers.param_type_matcher.lookup( cls_name)[0].DISABLED = True except typehandlers.TypeLookupError: pass continue wrapper = CallbackImplProxyMethod(return_type, arguments) wrapper.generate(sink, 'operator()', decl_modifiers=[]) sink.unindent() sink.writeln('};\n') print("Flushing to ", out, file=sys.stderr) sink.flush_to(out)
def generate_callback_classes(out, callbacks): for callback_impl_num, template_parameters in enumerate(callbacks): sink = MemoryCodeSink() cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) #print >> sys.stderr, "***** trying to register callback: %r" % cls_name class_name = "PythonCallbackImpl%i" % callback_impl_num sink.writeln(''' class %s : public ns3::CallbackImpl<%s> { public: PyObject *m_callback; %s(PyObject *callback) { Py_INCREF(callback); m_callback = callback; } virtual ~%s() { Py_DECREF(m_callback); m_callback = NULL; } virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const { const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base)); if (other != NULL) return (other->m_callback == m_callback); else return false; } ''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) sink.indent() callback_return = template_parameters[0] return_ctype = ctypeparser.parse_type(callback_return) if ('const' in return_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: return_type = ReturnValue.new(str(return_ctype), **kwargs) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r" % (callback_return, cls_name, ex), Warning) continue arguments = [] ok = True callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty'] for arg_num, arg_type in enumerate(callback_parameters): arg_name = 'arg%i' % (arg_num+1) param_ctype = ctypeparser.parse_type(arg_type) if ('const' in param_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: arguments.append(Parameter.new(str(param_ctype), arg_name, **kwargs)) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r" % (arg_type, arg_name, cls_name, ex), Warning) ok = False
def generate_callback_classes(out, callbacks): for callback_impl_num, template_parameters in enumerate(callbacks): sink = MemoryCodeSink() cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) #print >> sys.stderr, "***** trying to register callback: %r" % cls_name class_name = "PythonCallbackImpl%i" % callback_impl_num sink.writeln(''' class %s : public ns3::CallbackImpl<%s> { public: PyObject *m_callback; %s(PyObject *callback) { Py_INCREF(callback); m_callback = callback; } virtual ~%s() { PyGILState_STATE __py_gil_state; __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0); Py_DECREF(m_callback); m_callback = NULL; PyGILState_Release(__py_gil_state); } virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const { const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base)); if (other != NULL) return (other->m_callback == m_callback); else return false; } ''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) sink.indent() callback_return = template_parameters[0] return_ctype = ctypeparser.parse_type(callback_return) if ('const' in return_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: return_type = ReturnValue.new(str(return_ctype), **kwargs) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r" % (callback_return, cls_name, ex), Warning) continue arguments = [] ok = True callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty'] for arg_num, arg_type in enumerate(callback_parameters): arg_name = 'arg%i' % (arg_num+1) param_ctype = ctypeparser.parse_type(arg_type) if ('const' in param_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: arguments.append(Parameter.new(str(param_ctype), arg_name, **kwargs)) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r" % (arg_type, arg_name, cls_name, ex), Warning) ok = False if not ok: continue wrapper = CallbackImplProxyMethod(return_type, arguments) wrapper.generate(sink, 'operator()', decl_modifiers=[]) sink.unindent() sink.writeln('};\n') sink.flush_to(out) class PythonCallbackParameter(Parameter): "Class handlers" CTYPES = [cls_name] print("***** registering callback handler: %r" % ctypeparser.normalize_type_string(cls_name), file=sys.stderr) DIRECTIONS = [Parameter.DIRECTION_IN] PYTHON_CALLBACK_IMPL_NAME = class_name TEMPLATE_ARGS = template_parameters def convert_python_to_c(self, wrapper): "parses python args to get C++ value" assert isinstance(wrapper, typehandlers.ForwardWrapperBase) if self.default_value is None: py_callback = wrapper.declarations.declare_variable('PyObject*', self.name) wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name) wrapper.before_call.write_error_check( '!PyCallable_Check(%s)' % py_callback, 'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name) callback_impl = wrapper.declarations.declare_variable( 'ns3::Ptr<%s>' % self.PYTHON_CALLBACK_IMPL_NAME, '%s_cb_impl' % self.name) wrapper.before_call.write_code("%s = ns3::Create<%s> (%s);" % (callback_impl, self.PYTHON_CALLBACK_IMPL_NAME, py_callback)) wrapper.call_params.append( 'ns3::Callback<%s> (%s)' % (', '.join(self.TEMPLATE_ARGS), callback_impl)) else: py_callback = wrapper.declarations.declare_variable('PyObject*', self.name, 'NULL') wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name, optional=True) value = wrapper.declarations.declare_variable( 'ns3::Callback<%s>' % ', '.join(self.TEMPLATE_ARGS), self.name+'_value', self.default_value) wrapper.before_call.write_code("if (%s) {" % (py_callback,)) wrapper.before_call.indent() wrapper.before_call.write_error_check( '!PyCallable_Check(%s)' % py_callback, 'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name) wrapper.before_call.write_code("%s = ns3::Callback<%s> (ns3::Create<%s> (%s));" % (value, ', '.join(self.TEMPLATE_ARGS), self.PYTHON_CALLBACK_IMPL_NAME, py_callback)) wrapper.before_call.unindent() wrapper.before_call.write_code("}") # closes: if (py_callback) { wrapper.call_params.append(value) def convert_c_to_python(self, wrapper): raise typehandlers.NotSupportedError("Reverse wrappers for ns3::Callback<...> types " "(python using callbacks defined in C++) not implemented.")
class ModuleBase(dict): """ ModuleBase objects can be indexed dictionary style to access contained types. Example:: >>> from enum import Enum >>> from cppclass import CppClass >>> m = Module("foo", cpp_namespace="foo") >>> subm = m.add_cpp_namespace("subm") >>> c1 = m.add_class("Bar") >>> c2 = subm.add_class("Zbr") >>> e1 = m.add_enum("En1", ["XX"]) >>> e2 = subm.add_enum("En2", ["XX"]) >>> m["Bar"] is c1 True >>> m["foo::Bar"] is c1 True >>> m["En1"] is e1 True >>> m["foo::En1"] is e1 True >>> m["badname"] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'badname' >>> m["foo::subm::Zbr"] is c2 True >>> m["foo::subm::En2"] is e2 True """ def __init__(self, name, parent=None, docstring=None, cpp_namespace=None): """ Note: this is an abstract base class, see L{Module} :param name: module name :param parent: parent L{module<Module>} (i.e. the one that contains this submodule) or None if this is a root module :param docstring: docstring to use for this module :param cpp_namespace: C++ namespace prefix associated with this module :return: a new module object """ super(ModuleBase, self).__init__() self.parent = parent self.docstring = docstring self.submodules = [] self.enums = [] self.typedefs = [] # list of (wrapper, alias) tuples self._forward_declarations_declared = False self.cpp_namespace = cpp_namespace if self.parent is None: error_return = 'return MOD_ERROR;' self.after_forward_declarations = MemoryCodeSink() else: self.after_forward_declarations = None self.parent.submodules.append(self) error_return = 'return NULL;' self.prefix = None self.init_function_name = None self._name = None self.name = name path = self.get_namespace_path() if path and path[0] == '::': del path[0] self.cpp_namespace_prefix = '::'.join(path) self.declarations = DeclarationsScope() self.functions = {} # name => OverloadedFunction self.classes = [] self.containers = [] self.exceptions = [] self.before_init = CodeBlock(error_return, self.declarations) self.after_init = CodeBlock(error_return, self.declarations, predecessor=self.before_init) self.c_function_name_transformer = None self.set_strip_prefix(name + '_') if parent is None: self.header = MemoryCodeSink() self.body = MemoryCodeSink() self.one_time_definitions = {} self.includes = [] else: self.header = parent.header self.body = parent.body self.one_time_definitions = parent.one_time_definitions self.includes = parent.includes self._current_section = '__main__' def get_current_section(self): return self.get_root()._current_section current_section = property(get_current_section) def begin_section(self, section_name): """ Declare that types and functions registered with the module in the future belong to the section given by that section_name parameter, until a matching end_section() is called. .. note:: :meth:`begin_section`/:meth:`end_section` are silently ignored unless a :class:`MultiSectionFactory` object is used as code generation output. """ if self.current_section != '__main__': raise ValueError("begin_section called while current section not ended") if section_name == '__main__': raise ValueError ("__main__ not allowed as section name") assert self.parent is None self._current_section = section_name def end_section(self, section_name): """ Declare the end of a section, i.e. further types and functions will belong to the main module. :param section_name: name of section; must match the one in the previous :meth:`begin_section` call. """ assert self.parent is None if self._current_section != section_name: raise ValueError("end_section called for wrong section: expected %r, got %r" % (self._current_section, section_name)) self._current_section = '__main__' def get_name(self): return self._name def set_name(self, name): self._name = name if self.parent is None: self.prefix = self.name.replace('.', '_') self.init_function_name = "init%s" % (self.name.split('.')[-1],) else: self.prefix = self.parent.prefix + "_" + self.name self.init_function_name = "init%s" % (self.prefix,) name = property(get_name, set_name) def get_submodule(self, submodule_name): "get a submodule by its name" for submodule in self.submodules: if submodule.name == submodule_name: return submodule raise ValueError("submodule %s not found" % submodule_name) def get_root(self): ":return: the root :class:`Module` (even if it is self)" root = self while root.parent is not None: root = root.parent return root def set_strip_prefix(self, prefix): """Sets the prefix string to be used when transforming a C function name into the python function name; the given prefix string is removed from the C function name.""" def strip_prefix(c_name): """A C funtion name transformer that simply strips a common prefix from the name""" if c_name.startswith(prefix): return c_name[len(prefix):] else: return c_name self.c_function_name_transformer = strip_prefix def set_c_function_name_transformer(self, transformer): """Sets the function to be used when transforming a C function name into the python function name; the given given function is called like this:: python_name = transformer(c_name) """ self.c_function_name_transformer = transformer def add_include(self, include): """ Adds an additional include directive, needed to compile this python module :param include: the name of the header file to include, including surrounding "" or <>. """ include = utils.ascii(include) assert include.startswith('"') or include.startswith('<') assert include.endswith('"') or include.endswith('>') if include not in self.includes: self.includes.append(include) def _add_function_obj(self, wrapper): assert isinstance(wrapper, Function) name = utils.ascii(wrapper.custom_name) if name is None: name = self.c_function_name_transformer(wrapper.function_name) name = utils.get_mangled_name(name, wrapper.template_parameters) try: overload = self.functions[name] except KeyError: overload = OverloadedFunction(name) self.functions[name] = overload wrapper.module = self wrapper.section = self.current_section overload.add(wrapper) def add_function(self, *args, **kwargs): """ Add a function to the module/namespace. See the documentation for :meth:`Function.__init__` for information on accepted parameters. """ if len(args) >= 1 and isinstance(args[0], Function): func = args[0] warnings.warn("add_function has changed API; see the API documentation", DeprecationWarning, stacklevel=2) if len(args) == 2: func.custom_name = args[1] elif 'name' in kwargs: assert len(args) == 1 func.custom_name = kwargs['name'] else: assert len(args) == 1 assert len(kwargs) == 0 else: try: func = Function(*args, **kwargs) except utils.SkipWrapper: return None self._add_function_obj(func) return func def add_custom_function_wrapper(self, *args, **kwargs): """ Add a function, using custom wrapper code, to the module/namespace. See the documentation for :class:`pybindgen.function.CustomFunctionWrapper` for information on accepted parameters. """ try: func = CustomFunctionWrapper(*args, **kwargs) except utils.SkipWrapper: return None self._add_function_obj(func) return func def register_type(self, name, full_name, type_wrapper): """ Register a type wrapper with the module, for easy access in the future. Normally should not be called by the programmer, as it is meant for internal pybindgen use and called automatically. :param name: type name without any C++ namespace prefix, or None :param full_name: type name with a C++ namespace prefix, or None :param type_wrapper: the wrapper object for the type (e.g. L{CppClass} or L{Enum}) """ module = self if name: module[name] = type_wrapper if full_name: while module is not None: module[full_name] = type_wrapper module = module.parent def _add_class_obj(self, class_): """ Add a class to the module. :param class_: a CppClass object """ assert isinstance(class_, CppClass) class_.module = self class_.section = self.current_section self.classes.append(class_) self.register_type(class_.name, class_.full_name, class_) def add_class(self, *args, **kwargs): """ Add a class to the module. See the documentation for L{CppClass.__init__} for information on accepted parameters. """ if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], CppClass): cls = args[0] warnings.warn("add_class has changed API; see the API documentation", DeprecationWarning, stacklevel=2) else: cls = CppClass(*args, **kwargs) self._add_class_obj(cls) return cls def add_struct(self, *args, **kwargs): """ Add a struct to the module. In addition to the parameters accepted by L{CppClass.__init__}, this method accepts the following keyword parameters: - no_constructor (bool): if True, the structure will not have a constructor by default (if omitted, it will be considered to have a trivial constructor). - no_copy (bool): if True, the structure will not have a copy constructor by default (if omitted, it will be considered to have a simple copy constructor). """ try: no_constructor = kwargs['no_constructor'] except KeyError: no_constructor = False else: del kwargs['no_constructor'] try: no_copy = kwargs['no_copy'] except KeyError: no_copy = False else: del kwargs['no_copy'] struct = CppClass(*args, **kwargs) struct.stack_where_defined = traceback.extract_stack() self._add_class_obj(struct) if not no_constructor: struct.add_constructor([]) if not no_copy: struct.add_copy_constructor() return struct def add_cpp_namespace(self, name): """ Add a nested module namespace corresponding to a C++ namespace. If the requested namespace was already added, the existing module is returned instead of creating a new one. :param name: name of C++ namespace (just the last component, not full scoped name); this also becomes the name of the submodule. :return: a L{SubModule} object that maps to this namespace. """ name = utils.ascii(name) try: return self.get_submodule(name) except ValueError: module = SubModule(name, parent=self, cpp_namespace=name) module.stack_where_defined = traceback.extract_stack() return module def _add_enum_obj(self, enum): """ Add an enumeration. """ assert isinstance(enum, Enum) self.enums.append(enum) enum.module = self enum.section = self.current_section self.register_type(enum.name, enum.full_name, enum) def add_enum(self, *args, **kwargs): """ Add an enumeration to the module. See the documentation for L{Enum.__init__} for information on accepted parameters. """ if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], Enum): enum = args[0] warnings.warn("add_enum has changed API; see the API documentation", DeprecationWarning, stacklevel=2) else: enum = Enum(*args, **kwargs) enum.stack_where_defined = traceback.extract_stack() self._add_enum_obj(enum) return enum def _add_container_obj(self, container): """ Add a container to the module. :param container: a L{Container} object """ assert isinstance(container, Container) container.module = self container.section = self.current_section self.containers.append(container) self.register_type(container.name, container.full_name, container) def add_container(self, *args, **kwargs): """ Add a container to the module. See the documentation for L{Container.__init__} for information on accepted parameters. """ try: container = Container(*args, **kwargs) except utils.SkipWrapper: return None container.stack_where_defined = traceback.extract_stack() self._add_container_obj(container) return container def _add_exception_obj(self, exc): assert isinstance(exc, CppException) exc.module = self exc.section = self.current_section self.exceptions.append(exc) self.register_type(exc.name, exc.full_name, exc) def add_exception(self, *args, **kwargs): """ Add a C++ exception to the module. See the documentation for L{CppException.__init__} for information on accepted parameters. """ exc = CppException(*args, **kwargs) self._add_exception_obj(exc) return exc def declare_one_time_definition(self, definition_name): """ Internal helper method for code geneneration to coordinate generation of code that can only be defined once per compilation unit (note: assuming here one-to-one mapping between 'module' and 'compilation unit'). :param definition_name: a string that uniquely identifies the code definition that will be added. If the given definition was already declared KeyError is raised. >>> module = Module('foo') >>> module.declare_one_time_definition("zbr") >>> module.declare_one_time_definition("zbr") Traceback (most recent call last): ... KeyError: 'zbr' >>> module.declare_one_time_definition("bar") """ definition_name = utils.ascii(definition_name) if definition_name in self.one_time_definitions: raise KeyError(definition_name) self.one_time_definitions[definition_name] = None def generate_forward_declarations(self, code_sink): """(internal) generate forward declarations for types""" assert not self._forward_declarations_declared if self.classes or self.containers or self.exceptions: code_sink.writeln('/* --- forward declarations --- */') code_sink.writeln() for class_ in [c for c in self.classes if c.import_from_module]: class_.generate_forward_declarations(code_sink, self) for class_ in [c for c in self.classes if not c.import_from_module]: class_.generate_forward_declarations(code_sink, self) for container in self.containers: container.generate_forward_declarations(code_sink, self) for exc in self.exceptions: exc.generate_forward_declarations(code_sink, self) ## recurse to submodules for submodule in self.submodules: submodule.generate_forward_declarations(code_sink) self._forward_declarations_declared = True def get_module_path(self): """Get the full [module, submodule, submodule,...] path """ names = [self.name] parent = self.parent while parent is not None: names.insert(0, parent.name) parent = parent.parent return names def get_namespace_path(self): """Get the full [root_namespace, namespace, namespace,...] path (C++)""" if not self.cpp_namespace: names = [] else: if self.cpp_namespace == '::': names = [] else: names = self.cpp_namespace.split('::') if not names[0]: del names[0] parent = self.parent while parent is not None: if parent.cpp_namespace and parent.cpp_namespace != '::': parent_names = parent.cpp_namespace.split('::') if not parent_names[0]: del parent_names[0] names = parent_names + names parent = parent.parent return names 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('#if PY_VERSION_HEX >= 0x03000000') self.before_init.write_code( "m = PyModule_Create(&%s_moduledef);" % (self.name)) self.before_init.write_code('#else') 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_code('#endif') 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.items(): 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 PY_VERSION_HEX >= 0x03000000\n' 'static struct PyModuleDef %s_moduledef = {\n' ' PyModuleDef_HEAD_INIT,\n' ' "%s",\n' ' %s,\n' ' -1,\n' ' %s_functions,\n' '};\n' '#endif' % (self.name, mod_init_name, self.docstring and '"'+self.docstring+'"' or 'NULL', self.prefix)) main_sink.writeln() if self.parent is None: main_sink.writeln(''' #if PY_VERSION_HEX >= 0x03000000 #define MOD_ERROR NULL #define MOD_INIT(name) PyObject* PyInit_##name(void) #define MOD_RETURN(val) val #else #define MOD_ERROR #define MOD_INIT(name) void init##name(void) #define MOD_RETURN(val) #endif #if defined(__cplusplus) extern "C" #endif #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif ''') else: main_sink.writeln("static PyObject *") if self.parent is None: main_sink.writeln("MOD_INIT(%s)" % (self.name,)) elif 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;") else: main_sink.writeln("return MOD_RETURN(m);") main_sink.unindent() main_sink.writeln('}') def __repr__(self): return "<pybindgen.module.Module %r>" % self.name def add_typedef(self, wrapper, alias): """ Declares an equivalent to a typedef in C:: typedef Foo Bar; :param wrapper: the wrapper object to alias (Foo in the example) :param alias: name of the typedef alias @note: only typedefs for CppClass objects have been implemented so far; others will be implemented in the future. """ assert isinstance(wrapper, CppClass) alias = utils.ascii(alias) self.typedefs.append((wrapper, alias)) self.register_type(alias, alias, wrapper) wrapper.register_alias(alias) full_name = '::'.join(self.get_namespace_path() + [alias]) wrapper.register_alias(full_name)
def generate_callback_classes(out, callbacks): for callback_impl_num, template_parameters in enumerate(callbacks): sink = MemoryCodeSink() cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) #print >> sys.stderr, "***** trying to register callback: %r" % cls_name class_name = "PythonCallbackImpl%i" % callback_impl_num sink.writeln(''' class %s : public ns3::CallbackImpl<%s> { public: PyObject *m_callback; %s(PyObject *callback) { Py_INCREF(callback); m_callback = callback; } virtual ~%s() { Py_DECREF(m_callback); m_callback = NULL; } virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const { const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base)); if (other != NULL) return (other->m_callback == m_callback); else return false; } ''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) sink.indent() callback_return = template_parameters[0] return_ctype = ctypeparser.parse_type(callback_return) if ('const' in return_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: return_type = ReturnValue.new(str(return_ctype), **kwargs) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: warnings.warn( "***** Unable to register callback; Return value '%s' error (used in %s): %r" % (callback_return, cls_name, ex), Warning) continue arguments = [] ok = True callback_parameters = [ arg for arg in template_parameters[1:] if arg != 'ns3::empty' ] for arg_num, arg_type in enumerate(callback_parameters): arg_name = 'arg%i' % (arg_num + 1) param_ctype = ctypeparser.parse_type(arg_type) if ('const' in param_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: arguments.append( Parameter.new(str(param_ctype), arg_name, **kwargs)) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: warnings.warn( "***** Unable to register callback; parameter '%s %s' error (used in %s): %r" % (arg_type, arg_name, cls_name, ex), Warning) ok = False
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('#if PY_VERSION_HEX >= 0x03000000') self.before_init.write_code( "m = PyModule_Create(&%s_moduledef);" % (self.name)) self.before_init.write_code('#else') 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_code('#endif') 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.items(): 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 PY_VERSION_HEX >= 0x03000000\n' 'static struct PyModuleDef %s_moduledef = {\n' ' PyModuleDef_HEAD_INIT,\n' ' "%s",\n' ' %s,\n' ' -1,\n' ' %s_functions,\n' '};\n' '#endif' % (self.name, mod_init_name, self.docstring and '"'+self.docstring+'"' or 'NULL', self.prefix)) main_sink.writeln() if self.parent is None: main_sink.writeln(''' #if PY_VERSION_HEX >= 0x03000000 #define MOD_ERROR NULL #define MOD_INIT(name) PyObject* PyInit_##name(void) #define MOD_RETURN(val) val #else #define MOD_ERROR #define MOD_INIT(name) void init##name(void) #define MOD_RETURN(val) #endif #if defined(__cplusplus) extern "C" #endif #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif ''') else: main_sink.writeln("static PyObject *") if self.parent is None: main_sink.writeln("MOD_INIT(%s)" % (self.name,)) elif 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;") else: main_sink.writeln("return MOD_RETURN(m);") main_sink.unindent() main_sink.writeln('}')
def generate_callback_classes(out, callbacks): for callback_impl_num, template_parameters in enumerate(callbacks): sink = MemoryCodeSink() cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) #print >> sys.stderr, "***** trying to register callback: %r" % cls_name class_name = "PythonCallbackImpl%i" % callback_impl_num sink.writeln(''' class %s : public ns3::CallbackImpl<%s> { public: PyObject *m_callback; %s(PyObject *callback) { Py_INCREF(callback); m_callback = callback; } virtual ~%s() { PyGILState_STATE __py_gil_state; __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0); Py_DECREF(m_callback); m_callback = NULL; PyGILState_Release(__py_gil_state); } virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const { const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base)); if (other != NULL) return (other->m_callback == m_callback); else return false; } ''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) sink.indent() callback_return = template_parameters[0] return_ctype = ctypeparser.parse_type(callback_return) if ('const' in return_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: return_type = ReturnValue.new(str(return_ctype), **kwargs) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn( "***** Unable to register callback; Return value '%s' error (used in %s): %r" % (callback_return, cls_name, ex), Warning) continue arguments = [] ok = True callback_parameters = [ arg for arg in template_parameters[1:] if arg != 'ns3::empty' ] for arg_num, arg_type in enumerate(callback_parameters): arg_name = 'arg%i' % (arg_num + 1) param_ctype = ctypeparser.parse_type(arg_type) if ('const' in param_ctype.remove_modifiers()): kwargs = {'is_const': True} else: kwargs = {} try: arguments.append( Parameter.new(str(param_ctype), arg_name, **kwargs)) except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: warnings.warn( "***** Unable to register callback; parameter '%s %s' error (used in %s): %r" % (arg_type, arg_name, cls_name, ex), Warning) ok = False if not ok: continue wrapper = CallbackImplProxyMethod(return_type, arguments) wrapper.generate(sink, 'operator()', decl_modifiers=[]) sink.unindent() sink.writeln('};\n') sink.flush_to(out) class PythonCallbackParameter(Parameter): "Class handlers" CTYPES = [cls_name] print("***** registering callback handler: %r" % ctypeparser.normalize_type_string(cls_name), file=sys.stderr) DIRECTIONS = [Parameter.DIRECTION_IN] PYTHON_CALLBACK_IMPL_NAME = class_name TEMPLATE_ARGS = template_parameters def convert_python_to_c(self, wrapper): "parses python args to get C++ value" assert isinstance(wrapper, typehandlers.ForwardWrapperBase) if self.default_value is None: py_callback = wrapper.declarations.declare_variable( 'PyObject*', self.name) wrapper.parse_params.add_parameter('O', ['&' + py_callback], self.name) wrapper.before_call.write_error_check( '!PyCallable_Check(%s)' % py_callback, 'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name) callback_impl = wrapper.declarations.declare_variable( 'ns3::Ptr<%s>' % self.PYTHON_CALLBACK_IMPL_NAME, '%s_cb_impl' % self.name) wrapper.before_call.write_code( "%s = ns3::Create<%s> (%s);" % (callback_impl, self.PYTHON_CALLBACK_IMPL_NAME, py_callback)) wrapper.call_params.append( 'ns3::Callback<%s> (%s)' % (', '.join(self.TEMPLATE_ARGS), callback_impl)) else: py_callback = wrapper.declarations.declare_variable( 'PyObject*', self.name, 'NULL') wrapper.parse_params.add_parameter('O', ['&' + py_callback], self.name, optional=True) value = wrapper.declarations.declare_variable( 'ns3::Callback<%s>' % ', '.join(self.TEMPLATE_ARGS), self.name + '_value', self.default_value) wrapper.before_call.write_code("if (%s) {" % (py_callback, )) wrapper.before_call.indent() wrapper.before_call.write_error_check( '!PyCallable_Check(%s)' % py_callback, 'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name) wrapper.before_call.write_code( "%s = ns3::Callback<%s> (ns3::Create<%s> (%s));" % (value, ', '.join(self.TEMPLATE_ARGS), self.PYTHON_CALLBACK_IMPL_NAME, py_callback)) wrapper.before_call.unindent() wrapper.before_call.write_code( "}") # closes: if (py_callback) { wrapper.call_params.append(value) def convert_c_to_python(self, wrapper): raise typehandlers.NotSupportedError( "Reverse wrappers for ns3::Callback<...> types " "(python using callbacks defined in C++) not implemented.")