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;' 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__'
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;' 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( "m = Py_InitModule3((char *) \"%s\", %s_functions, %s);" % (mod_init_name, self.prefix, self.docstring and '"' + self.docstring + '"' or 'NULL')) self.before_init.write_error_check("m == NULL") main_sink = out.get_main_code_sink() ## generate the function wrappers py_method_defs = [] if self.functions: main_sink.writeln('/* --- module functions --- */') main_sink.writeln() for func_name, overload in self.functions.iteritems(): sink, header_sink = out.get_code_sink_for_wrapper(overload) sink.writeln() try: utils.call_with_error_handling(overload.generate, (sink, ), {}, overload) except utils.SkipWrapper: continue try: utils.call_with_error_handling( overload.generate_declaration, (main_sink, ), {}, overload) except utils.SkipWrapper: continue sink.writeln() py_method_defs.append(overload.get_py_method_def(func_name)) del sink ## generate the function table main_sink.writeln("static PyMethodDef %s_functions[] = {" % (self.prefix, )) main_sink.indent() for py_method_def in py_method_defs: main_sink.writeln(py_method_def) main_sink.writeln("{NULL, NULL, 0, NULL}") main_sink.unindent() main_sink.writeln("};") ## generate the classes if self.classes: main_sink.writeln('/* --- classes --- */') main_sink.writeln() for class_ in [c for c in self.classes if c.import_from_module]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() for class_ in [ c for c in self.classes if not c.import_from_module ]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() ## generate the containers if self.containers: main_sink.writeln('/* --- containers --- */') main_sink.writeln() for container in self.containers: sink, header_sink = out.get_code_sink_for_wrapper(container) sink.writeln() container.generate(sink, self) sink.writeln() ## generate the exceptions if self.exceptions: main_sink.writeln('/* --- exceptions --- */') main_sink.writeln() for exc in self.exceptions: sink, header_sink = out.get_code_sink_for_wrapper(exc) sink.writeln() exc.generate(sink, self) sink.writeln() # typedefs for (wrapper, alias) in self.typedefs: if isinstance(wrapper, CppClass): cls = wrapper cls.generate_typedef(self, alias) ## generate the enums if self.enums: main_sink.writeln('/* --- enumerations --- */') main_sink.writeln() for enum in self.enums: sink, header_sink = out.get_code_sink_for_wrapper(enum) sink.writeln() enum.generate(sink) enum.generate_declaration(header_sink, self) sink.writeln() ## register the submodules if self.submodules: submodule_var = self.declarations.declare_variable( 'PyObject*', 'submodule') for submodule in self.submodules: self.after_init.write_code( '%s = %s();' % (submodule_var, submodule.init_function_name)) self.after_init.write_error_check('%s == NULL' % submodule_var) self.after_init.write_code('Py_INCREF(%s);' % (submodule_var, )) self.after_init.write_code( 'PyModule_AddObject(m, (char *) "%s", %s);' % ( submodule.name, submodule_var, )) ## flush the header section self.header.flush_to(out.get_includes_code_sink()) ## flush the body section self.body.flush_to(main_sink) ## now generate the module init function itself main_sink.writeln() if self.parent is None: main_sink.writeln(''' PyMODINIT_FUNC #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif''') else: main_sink.writeln("static PyObject *") if module_file_base_name is None: main_sink.writeln("%s(void)" % (self.init_function_name, )) else: main_sink.writeln("init%s(void)" % (module_file_base_name, )) main_sink.writeln('{') main_sink.indent() self.declarations.get_code_sink().flush_to(main_sink) self.before_init.sink.flush_to(main_sink) self.after_init.write_cleanup() self.after_init.sink.flush_to(main_sink) if self.parent is not None: main_sink.writeln("return m;") main_sink.unindent() main_sink.writeln('}') def __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)
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;' 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( "m = Py_InitModule3((char *) \"%s\", %s_functions, %s);" % (mod_init_name, self.prefix, self.docstring and '"'+self.docstring+'"' or 'NULL')) self.before_init.write_error_check("m == NULL") main_sink = out.get_main_code_sink() ## generate the function wrappers py_method_defs = [] if self.functions: main_sink.writeln('/* --- module functions --- */') main_sink.writeln() for func_name, overload in self.functions.iteritems(): sink, header_sink = out.get_code_sink_for_wrapper(overload) sink.writeln() try: utils.call_with_error_handling(overload.generate, (sink,), {}, overload) except utils.SkipWrapper: continue try: utils.call_with_error_handling(overload.generate_declaration, (main_sink,), {}, overload) except utils.SkipWrapper: continue sink.writeln() py_method_defs.append(overload.get_py_method_def(func_name)) del sink ## generate the function table main_sink.writeln("static PyMethodDef %s_functions[] = {" % (self.prefix,)) main_sink.indent() for py_method_def in py_method_defs: main_sink.writeln(py_method_def) main_sink.writeln("{NULL, NULL, 0, NULL}") main_sink.unindent() main_sink.writeln("};") ## generate the classes if self.classes: main_sink.writeln('/* --- classes --- */') main_sink.writeln() for class_ in [c for c in self.classes if c.import_from_module]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() for class_ in [c for c in self.classes if not c.import_from_module]: sink, header_sink = out.get_code_sink_for_wrapper(class_) sink.writeln() class_.generate(sink, self) sink.writeln() ## generate the containers if self.containers: main_sink.writeln('/* --- containers --- */') main_sink.writeln() for container in self.containers: sink, header_sink = out.get_code_sink_for_wrapper(container) sink.writeln() container.generate(sink, self) sink.writeln() ## generate the exceptions if self.exceptions: main_sink.writeln('/* --- exceptions --- */') main_sink.writeln() for exc in self.exceptions: sink, header_sink = out.get_code_sink_for_wrapper(exc) sink.writeln() exc.generate(sink, self) sink.writeln() # typedefs for (wrapper, alias) in self.typedefs: if isinstance(wrapper, CppClass): cls = wrapper cls.generate_typedef(self, alias) ## generate the enums if self.enums: main_sink.writeln('/* --- enumerations --- */') main_sink.writeln() for enum in self.enums: sink, header_sink = out.get_code_sink_for_wrapper(enum) sink.writeln() enum.generate(sink) enum.generate_declaration(header_sink, self) sink.writeln() ## register the submodules if self.submodules: submodule_var = self.declarations.declare_variable('PyObject*', 'submodule') for submodule in self.submodules: self.after_init.write_code('%s = %s();' % ( submodule_var, submodule.init_function_name)) self.after_init.write_error_check('%s == NULL' % submodule_var) self.after_init.write_code('Py_INCREF(%s);' % (submodule_var,)) self.after_init.write_code('PyModule_AddObject(m, (char *) "%s", %s);' % (submodule.name, submodule_var,)) ## flush the header section self.header.flush_to(out.get_includes_code_sink()) ## flush the body section self.body.flush_to(main_sink) ## now generate the module init function itself main_sink.writeln() if self.parent is None: main_sink.writeln(''' PyMODINIT_FUNC #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif''') else: main_sink.writeln("static PyObject *") if module_file_base_name is None: main_sink.writeln("%s(void)" % (self.init_function_name,)) else: main_sink.writeln("init%s(void)" % (module_file_base_name,)) main_sink.writeln('{') main_sink.indent() self.declarations.get_code_sink().flush_to(main_sink) self.before_init.sink.flush_to(main_sink) self.after_init.write_cleanup() self.after_init.sink.flush_to(main_sink) if self.parent is not None: main_sink.writeln("return m;") main_sink.unindent() main_sink.writeln('}') def __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)