1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
import settings
import utils
class CppException(object):
def __init__(self, name, parent=None, outer_class=None, custom_name=None,
foreign_cpp_namespace=None, message_rvalue=None):
"""
:param name: exception class name
:param parent: optional parent class wrapper
:param custom_name: an alternative name to give to this
exception class at python-side; if omitted, the name of
the class in the python module will be the same name as
the class in C++ (minus namespace).
:param foreign_cpp_namespace: if set, the class is assumed to
belong to the given C++ namespace, regardless of the
C++ namespace of the python module it will be added to.
For instance, this can be useful to wrap std classes,
like std::ofstream, without having to create an extra
python submodule.
:param message_rvalue: if not None, this parameter is a string
that contains an rvalue C expression that evaluates to
the exception message. The Python % operator will be
used to substitute %(EXC)s for the caught exception
variable name. The rvalue expression must return a
string of type "char const*", a pointer owned by the
exception instance.
"""
self.name = name
self.full_name = None
self.parent = parent
self._module = None
self.outer_class = outer_class
self.custom_name = custom_name
self.mangled_name = None
self.mangled_full_name = None
self.pytypestruct = None
self.foreign_cpp_namespace = foreign_cpp_namespace
self.message_rvalue = message_rvalue
def __repr__(self):
return "<pybindgen.CppException %r>" % self.full_name
def write_convert_to_python(self, code_block, variable_name):
if self.message_rvalue is None:
code_block.write_code('PyErr_SetNone((PyObject *) %s);' % self.pytypestruct)
else:
code_block.write_code('PyErr_SetString((PyObject *) %s, %s);'
% (self.pytypestruct, (self.message_rvalue % dict(EXC=variable_name))))
def get_module(self):
"""Get the Module object this type belongs to"""
return self._module
def set_module(self, module):
"""Set the Module object this type belongs to"""
self._module = module
self._update_names()
module = property(get_module, set_module)
def _update_names(self):
prefix = settings.name_prefix.capitalize()
if self.outer_class is None:
if self.foreign_cpp_namespace:
self.full_name = self.foreign_cpp_namespace + '::' + self.name
else:
if self._module.cpp_namespace_prefix:
if self._module.cpp_namespace_prefix == '::':
self.full_name = '::' + self.name
else:
self.full_name = self._module.cpp_namespace_prefix + '::' + self.name
else:
self.full_name = self.name
else:
assert not self.foreign_cpp_namespace
self.full_name = '::'.join([self.outer_class.full_name, self.name])
def make_upper(s):
if s and s[0].islower():
return s[0].upper()+s[1:]
else:
return s
def flatten(name):
"make a name like::This look LikeThis"
return ''.join([make_upper(utils.mangle_name(s)) for s in name.split('::')])
self.mangled_name = flatten(self.name)
self.mangled_full_name = utils.mangle_name(self.full_name)
self.pytypestruct = "Py%s%s_Type" % (prefix, self.mangled_full_name)
def _get_python_name(self):
if self.custom_name is None:
class_python_name = self.name
else:
class_python_name = self.custom_name
return class_python_name
python_name = property(_get_python_name)
def _get_python_full_name(self):
if self.outer_class is None:
mod_path = self._module.get_module_path()
mod_path.append(self.python_name)
return '.'.join(mod_path)
else:
return '%s.%s' % (self.outer_class.pytype.slots['tp_name'], self.python_name)
python_full_name = property(_get_python_full_name)
def generate_forward_declarations(self, code_sink, dummy_module):
code_sink.writeln()
code_sink.writeln('extern PyTypeObject *%s;' % (self.pytypestruct,))
code_sink.writeln()
def generate(self, code_sink, module, docstring=None):
"""Generates the class to a code sink"""
code_sink.writeln('PyTypeObject *%s;' % (self.pytypestruct,))
## --- register the class type in the module ---
module.after_init.write_code("/* Register the '%s' exception */" % self.full_name)
if self.parent is None:
parent = 'NULL'
else:
parent = "(PyObject*) "+self.parent.pytypestruct
module.after_init.write_error_check('(%s = (PyTypeObject*) PyErr_NewException((char*)"%s", %s, NULL)) == NULL'
% (self.pytypestruct, self.python_full_name, parent))
if docstring:
module.after_init.write_code("%s->tp_doc = (char*)\"%s\";" % (self.pytypestruct, docstring))
if self.outer_class is None:
module.after_init.write_code(
'Py_INCREF((PyObject *) %s);\n'
'PyModule_AddObject(m, (char *) \"%s\", (PyObject *) %s);' % (
self.pytypestruct, self.python_name, self.pytypestruct))
else:
module.after_init.write_code(
'Py_INCREF((PyObject *) %s);\n'
'PyDict_SetItemString((PyObject*) %s.tp_dict, (char *) \"%s\", (PyObject *) %s);' % (
self.pytypestruct, self.outer_class.pytypestruct, self.python_name, self.pytypestruct))
|