[C++-sig] [pybindgen] Problems on class constructor

Gustavo Carneiro gjcarneiro at gmail.com
Thu Aug 21 20:05:10 CEST 2008


2008/8/21 Gustavo Carneiro <gjcarneiro at gmail.com>

>
>
> 2008/8/21 Olaf Peter <ope-devel at gmx.de>
>
> Hi,
>>
>> given the following header:
>>
>> ---8<---
>> class PyConsole;
>>
>> class StdoutPy
>> {
>> public:
>>    StdoutPy(PyConsole* console);
>>    void write(PyObject* args);
>>    void flush();
>> private:
>>    PyConsole*                  m_console;
>> };
>>
>> class PyConsole
>> {
>>    void writeOut(PyObject* args);
>>    void writeErr(PyObject* args);
>>    void flush();
>> };
>> --->8---
>>
>>
>> and the python script:
>>
>> ---8<---
>> import pybindgen
>> import sys
>>
>> # convenience
>> param=pybindgen.param
>> retval=pybindgen.retval
>>
>> pybindgen.settings.min_python_version = (2,5)
>>
>> mod = pybindgen.Module('redirector')
>> mod.add_include('"redirector.hpp"')
>>
>> stdout_py = mod.add_class('StdoutPy')
>> stdout_py.add_constructor([param('PyConsole*', 'cpp_parent',
>> transfer_ownership=False)])
>> stdout_py.add_method('write', None, [param('PyObject*', 'value',
>> transfer_ownership=False)])
>> stdout_py.add_method('flush', None, [])
>>
>> mod.generate(sys.stdout)
>> --->8---
>>
>> I get the error:
>>
>> $ python redirector.py
>> Traceback (most recent call last):
>>  File "redirector.py", line 14, in <module>
>>    stdout_py.add_constructor([param('PyConsole*', 'cpp_parent',
>> transfer_ownership=False)])
>>  File "/usr/lib/python2.5/site-packages/pybindgen/cppclass.py", line
>> 1228, in add_constructor
>>    constructor = CppConstructor(*args, **kwargs)
>>  File "/usr/lib/python2.5/site-packages/pybindgen/cppmethod.py", line
>> 415, in __init__
>>    parameters = [utils.eval_param(param, self) for param in parameters]
>>  File "/usr/lib/python2.5/site-packages/pybindgen/utils.py", line 205,
>> in eval_param
>>    TypeLookupError))
>>  File "/usr/lib/python2.5/site-packages/pybindgen/utils.py", line 115,
>> in call_with_error_handling
>>    return callable(*args, **kwargs)
>>  File
>> "/usr/lib/python2.5/site-packages/pybindgen/typehandlers/base.py", line
>> 1167, in new
>>    param_type_matcher.lookup(ctype)
>>  File
>> "/usr/lib/python2.5/site-packages/pybindgen/typehandlers/base.py", line
>> 1300, in lookup
>>    raise TypeLookupError(name)
>> pybindgen.typehandlers.base.TypeLookupError: PyConsole *
>>
>>
>> It seems, that I have to register my own types but I have no idea how to
>> do this.
>
>
> You just have to declare the PyConsole class, with:
> mod.add_class('PyConsole')
>
> For Testing I've used the xmlgcc approach:
>>
>> ---8<---
>> import sys
>>
>> from pybindgen import FileCodeSink
>> from pybindgen.gccxmlparser import ModuleParser
>>
>> def my_module_gen():
>>    module_parser = ModuleParser('redirector', '::')
>>    module_parser.parse([sys.argv[1]],
>> include_paths=['/usr/include/python2.5'],includes=['"redirector.hpp"'],
>> pygen_sink=FileCodeSink(sys.stdout))
>>
>> if __name__ == '__main__':
>>    my_module_gen()
>> --->8---
>>
>> which results in errors too:
>>
>> /usr/lib/python2.5/site-packages/pybindgen/gccxmlparser.py:580:
>> DeprecationWarning: Parameter include_paths is deprecated, use
>> gccxml_options instead
>>  self.parse_init(header_files, include_paths, whitelist_paths,
>> includes, pygen_sink, pygen_classifier)
>>
>> INFO Parsing source file "redirector.hpp" ...
>>
>> INFO gccxml cmd: /usr/bin/gccxml  -I"." -I"/usr/include/python2.5"
>> "redirector.hpp" -fxml="/tmp/tmp5ORqw3.xml"
>>
>> INFO GCCXML version - 0.7
>> /usr/lib/python2.5/site-packages/pygccxml/parser/scanner.py:335:
>> UserWarning: unable to find out array size from expression ""
>>  warnings.warn( msg )
>> from pybindgen import Module, FileCodeSink, param, retval, cppclass
>>
>>
>> import pybindgen.settings
>> import warnings
>>
>> class ErrorHandler(pybindgen.settings.ErrorHandler):
>>    def handle_error(self, wrapper, exception, traceback_):
>>        warnings.warn("exception %r in wrapper %s" % (exception, wrapper))
>>        return True
>> pybindgen.settings.error_handler = ErrorHandler()
>>
>>
>> import sys
>>
>> def module_init():
>>    root_module = Module('redirector', cpp_namespace='::')
>>    root_module.add_include('"redirector.hpp"')
>>    return root_module
>>
>> def register_types(module):
>>    root_module = module.get_root()
>>
>>    module.add_class('StdoutPy')
>>    module.add_class('PyConsole')
>>
>>    ## Register a nested module for the namespace std
>>
>>    nested_module = module.add_cpp_namespace('std')
>>    register_types_std(nested_module)
>>
>>
>> def register_types_std(module):
>>    root_module = module.get_root()
>>
>>
>> def register_methods(root_module):
>>    register_StdoutPy_methods(root_module, root_module['StdoutPy'])
>>    register_PyConsole_methods(root_module, root_module['PyConsole'])
>>    return
>>
>> def register_StdoutPy_methods(root_module, cls):
>> /usr/lib/python2.5/site-packages/pybindgen/gccxmlparser.py:215:
>> UserWarning: multiple &'s not handled
>>  warnings.warn("multiple &'s not handled")
>> /usr/lib/python2.5/site-packages/pybindgen/gccxmlparser.py:211:
>> UserWarning: multiple consts not handled
>>  warnings.warn("multiple consts not handled")
>>    cls.add_constructor([param('StdoutPy&', '_ctor_arg', is_const=True)])
>>    cls.add_constructor([param('PyConsole *', 'console')])
>> /var/tmp/redirector.hpp:12: WrapperWarning: Parameter '::PyConsole *
>> console' error (used in StdoutPy::StdoutPy(PyConsole * console)
>> [constructor]): TypeConfigurationError('transfer_ownership parameter
>> missing',)
>>  StdoutPy(PyConsole* console);
>>    cls.add_method('write',
>>                   'void',
>>                   [param('PyObject *', 'args')])
>> /usr/lib/python2.5/site-packages/pybindgen/typehandlers/base.py:1173:
>> UserWarning: Exception '__init__() takes at least 4 arguments (3 given)'
>> in type handler <class
>> 'pybindgen.typehandlers.pyobjecttype.PyObjectParam'> constructor
>>  warnings.warn("Exception %r in type handler %s constructor" %
>> (str(ex), type_handler_class))
>> Traceback (most recent call last):
>>  File "redirector_py.py", line 13, in <module>
>>    my_module_gen()
>>  File "redirector_py.py", line 10, in my_module_gen
>>    module_parser.parse([sys.argv[1]],
>> include_paths=['/usr/include/python2.5'],includes=['"redirector.hpp"'],
>> pygen_sink=FileCodeSink(sys.stdout))
>>  File "/usr/lib/python2.5/site-packages/pybindgen/gccxmlparser.py",
>> line 582, in parse
>>    self.scan_methods()
>>  File "/usr/lib/python2.5/site-packages/pybindgen/gccxmlparser.py",
>> line 809, in scan_methods
>>    self._scan_class_methods(class_wrapper.gccxml_definition,
>> class_wrapper, pygen_sink)
>>  File "/usr/lib/python2.5/site-packages/pybindgen/gccxmlparser.py",
>> line 1420, in _scan_class_methods
>>    arguments.append(Parameter.new(*arg[0], **arg[1]))
>>  File
>> "/usr/lib/python2.5/site-packages/pybindgen/typehandlers/base.py", line
>> 1171, in new
>>    return type_handler_class(*args, **kwargs)
>> TypeError: __init__() takes at least 4 arguments (3 given)
>
>
> I am guessing you need to add a transfer_ownership=false annotation in some
> places.  I know, annotations are not properly documented, so I don't blame
> you for the mistake :P
>
> I think your header file would need something like this (check the -#-
> comments):
>
> class PyConsole;
>
> class StdoutPy
> {
> public:
>    // -#- @console(transfer_ownership=false) -#-
>    StdoutPy(PyConsole* console);
>    // -#- @args(transfer_ownership=false) -#-
>    void write(PyObject* args);
>    void flush();
> private:
>    PyConsole*                  m_console;
> };
>
> class PyConsole
> {
>    // -#- @args(transfer_ownership=false) -#-
>    void writeOut(PyObject* args);
>    // -#- @args(transfer_ownership=false) -#-
>    void writeErr(PyObject* args);
>    void flush();
> };
>
>
>>
>> BTW, how can I prevent the construction of the StdoutPy class from
>> python? It has to be created from c++ side.
>>
>
> Using gccxml scanner, there's no easy way to do it.  I guess that, after
> scanning, you can reset the list of constructors to the empty list:
> module['StdoutPy'].constructors = []
>

After hitting send I remembered...  A less hackish way to do it with the
gccxml scanner is to add 'ignore' annotations to the constructors.

class PyConsole
{
public:

  // -#- ignore -#-
   PyConsole () {} // need to make the constructor explicit for this to
work...

[...]
};

P. S.: the annotations system is rather fragile.  Annotations are looked for
in the line above the line where GCC-XML reports that the declaration is
defined.  But GCC-XML reports weird line numbers on multi-line declarations,
so beware.

-- 
Gustavo J. A. M. Carneiro
INESC Porto, Telecommunications and Multimedia Unit
"The universe is always one step beyond logic." -- Frank Herbert
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20080821/8e33b6c4/attachment.htm>


More information about the Cplusplus-sig mailing list