bindings/python/ns3modulegen_core_customizations.py
changeset 3408 2cc40b3e4fa5
child 3412 518719e905a0
equal deleted inserted replaced
3396:0d83aa14b65d 3408:2cc40b3e4fa5
       
     1 import re
       
     2 
       
     3 from pybindgen.typehandlers import base as typehandlers
       
     4 from pybindgen import (ReturnValue, Parameter)
       
     5 from pybindgen.cppmethod import CustomCppMethodWrapper, CustomCppConstructorWrapper
       
     6 from pybindgen.typehandlers.codesink import MemoryCodeSink
       
     7 from pybindgen.typehandlers import ctypeparser
       
     8 import warnings
       
     9 
       
    10 from pybindgen.typehandlers.base import CodeGenerationError
       
    11 
       
    12 import sys
       
    13 
       
    14 class SmartPointerTransformation(typehandlers.TypeTransformation):
       
    15     """
       
    16     This class provides a "type transformation" that tends to support
       
    17     NS-3 smart pointers.  Parameters such as "Ptr<Foo> foo" are
       
    18     transformed into something like Parameter.new("Foo*", "foo",
       
    19     transfer_ownership=False).  Return values such as Ptr<Foo> are
       
    20     transformed into ReturnValue.new("Foo*",
       
    21     caller_owns_return=False).  Since the underlying objects have
       
    22     reference counting, PyBindGen does the right thing.
       
    23     """
       
    24     def __init__(self):
       
    25         super(SmartPointerTransformation, self).__init__()
       
    26         self.rx = re.compile(r'(ns3::|::ns3::|)Ptr<([^>]+)>')
       
    27 
       
    28     def _get_untransformed_type_traits(self, name):
       
    29         m = self.rx.match(name)
       
    30         is_const = False
       
    31         if m is None:
       
    32             return None, False
       
    33         else:
       
    34             name1 = m.group(2).strip()
       
    35             if name1.startswith('const '):
       
    36                 name1 = name1[len('const '):]
       
    37                 is_const = True
       
    38             if name1.endswith(' const'):
       
    39                 name1 = name1[:-len(' const')]
       
    40                 is_const = True
       
    41             new_name = name1+' *'
       
    42 
       
    43             if new_name.startswith('::'):
       
    44                 new_name = new_name[2:]
       
    45             return new_name, is_const
       
    46 
       
    47     def get_untransformed_name(self, name):
       
    48         new_name, dummy_is_const = self._get_untransformed_type_traits(name)
       
    49         return new_name
       
    50 
       
    51     def create_type_handler(self, type_handler, *args, **kwargs):
       
    52         if issubclass(type_handler, Parameter):
       
    53             kwargs['transfer_ownership'] = False
       
    54         elif issubclass(type_handler, ReturnValue):
       
    55             kwargs['caller_owns_return'] = False
       
    56         else:
       
    57             raise AssertionError
       
    58 
       
    59         ## fix the ctype, add ns3:: namespace
       
    60         orig_ctype, is_const = self._get_untransformed_type_traits(args[0])
       
    61         if is_const:
       
    62             kwargs['is_const'] = True
       
    63             correct_ctype = 'ns3::Ptr< %s const >' % orig_ctype[:-2]
       
    64         else:
       
    65             correct_ctype = 'ns3::Ptr< %s >' % orig_ctype[:-2]
       
    66         args = tuple([correct_ctype] + list(args[1:]))
       
    67 
       
    68         handler = type_handler(*args, **kwargs)
       
    69         handler.set_tranformation(self, orig_ctype)
       
    70         return handler
       
    71 
       
    72     def untransform(self, type_handler, declarations, code_block, expression):
       
    73         return 'ns3::PeekPointer (%s)' % (expression,)
       
    74 
       
    75     def transform(self, type_handler, declarations, code_block, expression):
       
    76         assert type_handler.untransformed_ctype[-1] == '*'
       
    77         return 'ns3::Ptr< %s > (%s)' % (type_handler.untransformed_ctype[:-1], expression)
       
    78 
       
    79 ## register the type transformation
       
    80 transf = SmartPointerTransformation()
       
    81 typehandlers.return_type_matcher.register_transformation(transf)
       
    82 typehandlers.param_type_matcher.register_transformation(transf)
       
    83 del transf
       
    84 
       
    85 
       
    86 class ArgvParam(Parameter):
       
    87     """
       
    88     Converts a python list-of-strings argument to a pair of 'int argc,
       
    89     char *argv[]' arguments to pass into C.
       
    90 
       
    91     One Python argument becomes two C function arguments -> it's a miracle!
       
    92 
       
    93     Note: this parameter type handler is not registered by any name;
       
    94     must be used explicitly.
       
    95     """
       
    96 
       
    97     DIRECTIONS = [Parameter.DIRECTION_IN]
       
    98     CTYPES = []
       
    99     
       
   100     def convert_c_to_python(self, wrapper):
       
   101         raise NotImplementedError
       
   102 
       
   103     def convert_python_to_c(self, wrapper):
       
   104         py_name = wrapper.declarations.declare_variable('PyObject*', 'py_' + self.name)
       
   105         argc_var = wrapper.declarations.declare_variable('int', 'argc')
       
   106         name = wrapper.declarations.declare_variable('char**', self.name)
       
   107         idx = wrapper.declarations.declare_variable('Py_ssize_t', 'idx')
       
   108         wrapper.parse_params.add_parameter('O!', ['&PyList_Type', '&'+py_name], self.name)
       
   109 
       
   110         #wrapper.before_call.write_error_check('!PyList_Check(%s)' % py_name) # XXX
       
   111 
       
   112         wrapper.before_call.write_code("%s = (char **) malloc(sizeof(char*)*PyList_Size(%s));"
       
   113                                        % (name, py_name))
       
   114         wrapper.before_call.add_cleanup_code('free(%s);' % name)
       
   115         wrapper.before_call.write_code('''
       
   116 for (%(idx)s = 0; %(idx)s < PyList_Size(%(py_name)s); %(idx)s++)
       
   117 {
       
   118 ''' % vars())
       
   119         wrapper.before_call.sink.indent()
       
   120         wrapper.before_call.write_code('''
       
   121 PyObject *item = PyList_GET_ITEM(%(py_name)s, %(idx)s);
       
   122 ''' % vars())
       
   123         #wrapper.before_call.write_error_check('item == NULL')
       
   124         wrapper.before_call.write_error_check(
       
   125             '!PyString_Check(item)',
       
   126             failure_cleanup=('PyErr_SetString(PyExc_TypeError, '
       
   127                              '"argument %s must be a list of strings");') % self.name)
       
   128         wrapper.before_call.write_code(
       
   129             '%s[%s] = PyString_AsString(item);' % (name, idx))
       
   130         wrapper.before_call.sink.unindent()
       
   131         wrapper.before_call.write_code('}')
       
   132         wrapper.before_call.write_code('%s = PyList_Size(%s);' % (argc_var, py_name))
       
   133         
       
   134         wrapper.call_params.append(argc_var)
       
   135         wrapper.call_params.append(name)
       
   136 
       
   137 
       
   138 class CallbackImplProxyMethod(typehandlers.ReverseWrapperBase):
       
   139     """
       
   140     Class that generates a proxy virtual method that calls a similarly named python method.
       
   141     """
       
   142 
       
   143     def __init__(self, return_value, parameters):
       
   144         super(CallbackImplProxyMethod, self).__init__(return_value, parameters)
       
   145 
       
   146     def generate_python_call(self):
       
   147         """code to call the python method"""
       
   148         build_params = self.build_params.get_parameters()
       
   149         if build_params[0][0] == '"':
       
   150             build_params[0] = '(char *) ' + build_params[0]
       
   151         args = self.before_call.declare_variable('PyObject*', 'args')
       
   152         self.before_call.write_code('%s = Py_BuildValue(%s);'
       
   153                                     % (args, ', '.join(build_params)))
       
   154         self.before_call.add_cleanup_code('Py_DECREF(%s);' % args)
       
   155         self.before_call.write_code('py_retval = PyObject_CallObject(m_callback, %s);' % args)
       
   156         self.before_call.write_error_check('py_retval == NULL')
       
   157         self.before_call.add_cleanup_code('Py_DECREF(py_retval);')
       
   158 
       
   159 
       
   160 
       
   161 
       
   162 def generate_callback_classes(out, callbacks):
       
   163     for callback_impl_num, template_parameters in enumerate(callbacks):
       
   164         sink = MemoryCodeSink()
       
   165         cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters)
       
   166         #print >> sys.stderr, "***** trying to register callback: %r" % cls_name
       
   167         class_name = "PythonCallbackImpl%i" % callback_impl_num
       
   168         sink.writeln('''
       
   169 class %s : public ns3::CallbackImpl<%s>
       
   170 {
       
   171 public:
       
   172     PyObject *m_callback;
       
   173     %s(PyObject *callback)
       
   174     {
       
   175         Py_INCREF(callback);
       
   176         m_callback = callback;
       
   177     }
       
   178     virtual ~%s()
       
   179     {
       
   180         Py_DECREF(m_callback);
       
   181         m_callback = NULL;
       
   182     }
       
   183 
       
   184     virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const
       
   185     {
       
   186         const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base));
       
   187         if (other != NULL)
       
   188             return (other->m_callback == m_callback);
       
   189         else
       
   190             return false;
       
   191     }
       
   192 
       
   193 ''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name))
       
   194         sink.indent()
       
   195         callback_return = template_parameters[0]
       
   196         return_ctype = ctypeparser.parse_type(callback_return)
       
   197         if ('const' in return_ctype.remove_modifiers()):
       
   198             kwargs = {'is_const': True}
       
   199         else:
       
   200             kwargs = {}
       
   201         try:
       
   202             return_type = ReturnValue.new(str(return_ctype), **kwargs)
       
   203         except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex:
       
   204             warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r"
       
   205                           % (callback_return, cls_name, ex),
       
   206                           Warning)
       
   207             continue
       
   208 
       
   209         arguments = []
       
   210         ok = True
       
   211         callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty']
       
   212         for arg_num, arg_type in enumerate(callback_parameters):
       
   213             arg_name = 'arg%i' % (arg_num+1)
       
   214 
       
   215             param_ctype = ctypeparser.parse_type(arg_type)
       
   216             if ('const' in param_ctype.remove_modifiers()):
       
   217                 kwargs = {'is_const': True}
       
   218             else:
       
   219                 kwargs = {}
       
   220             try:
       
   221                 arguments.append(Parameter.new(str(param_ctype), arg_name, **kwargs))
       
   222             except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex:
       
   223                 warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r"
       
   224                               % (arg_type, arg_name, cls_name, ex),
       
   225                               Warning)
       
   226                 ok = False
       
   227         if not ok:
       
   228             continue
       
   229 
       
   230         wrapper = CallbackImplProxyMethod(return_type, arguments)
       
   231         wrapper.generate(sink, 'operator()', decl_modifiers=[])
       
   232             
       
   233         sink.unindent()
       
   234         sink.writeln('};\n')
       
   235         sink.flush_to(out)
       
   236         
       
   237         class PythonCallbackParameter(Parameter):
       
   238             "Class handlers"
       
   239             CTYPES = [cls_name]
       
   240             #print >> sys.stderr, "***** registering callback handler: %r" % ctypeparser.normalize_type_string(cls_name)
       
   241             DIRECTIONS = [Parameter.DIRECTION_IN]
       
   242             PYTHON_CALLBACK_IMPL_NAME = class_name
       
   243             TEMPLATE_ARGS = template_parameters
       
   244 
       
   245             def convert_python_to_c(self, wrapper):
       
   246                 "parses python args to get C++ value"
       
   247                 assert isinstance(wrapper, typehandlers.ForwardWrapperBase)
       
   248 
       
   249                 py_callback = wrapper.declarations.declare_variable('PyObject*', self.name)
       
   250                 wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name)
       
   251                 wrapper.before_call.write_error_check(
       
   252                     '!PyCallable_Check(%s)' % py_callback,
       
   253                     'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name)
       
   254                 callback_impl = wrapper.declarations.declare_variable(
       
   255                     'ns3::Ptr<%s>' % self.PYTHON_CALLBACK_IMPL_NAME,
       
   256                     '%s_cb_impl' % self.name)
       
   257                 wrapper.before_call.write_code("%s = ns3::Create<%s> (%s);"
       
   258                                                % (callback_impl, self.PYTHON_CALLBACK_IMPL_NAME, py_callback))
       
   259                 wrapper.call_params.append(
       
   260                     'ns3::Callback<%s> (%s)' % (', '.join(self.TEMPLATE_ARGS), callback_impl))
       
   261 
       
   262             def convert_c_to_python(self, wrapper):
       
   263                 raise typehandlers.NotSupportedError("Reverse wrappers for ns3::Callback<...> types "
       
   264                                                      "(python using callbacks defined in C++) not implemented.")
       
   265 
       
   266 
       
   267 # def write_preamble(out):
       
   268 #     pybindgen.write_preamble(out)
       
   269 #     out.writeln("#include \"ns3/everything.h\"")
       
   270 
       
   271 
       
   272 
       
   273 def Simulator_customizations(module):
       
   274     Simulator = module['ns3::Simulator']
       
   275 
       
   276     ## Simulator::Schedule(delay, callback, ...user..args...)
       
   277     Simulator.add_custom_method_wrapper("Schedule", "_wrap_Simulator_Schedule",
       
   278                                         flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
       
   279 
       
   280 
       
   281     ## Simulator::ScheduleNow(callback, ...user..args...)
       
   282     Simulator.add_custom_method_wrapper("ScheduleNow", "_wrap_Simulator_ScheduleNow",
       
   283                                         flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
       
   284 
       
   285 
       
   286     ## Simulator::ScheduleDestroy(callback, ...user..args...)
       
   287     Simulator.add_custom_method_wrapper("ScheduleDestroy", "_wrap_Simulator_ScheduleDestroy",
       
   288                                         flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
       
   289 
       
   290 
       
   291 def CommandLine_customizations(module):
       
   292     CommandLine = module['ns3::CommandLine']
       
   293     CommandLine.add_method('Parse', None, [ArgvParam(None, 'argv')],
       
   294                            is_static=False)
       
   295 
       
   296 
       
   297 def Object_customizations(module):
       
   298     ## ---------------------------------------------------------------------
       
   299     ## Here we generate custom constructor code for all classes that
       
   300     ## derive from ns3::Object.  The custom constructors are needed in
       
   301     ## order to support kwargs only and to translate kwargs into ns3
       
   302     ## attributes, etc.
       
   303     ## ---------------------------------------------------------------------
       
   304     Object = module['ns3::Object']
       
   305 
       
   306 
       
   307     ## add a GetTypeId method to all generatd helper classes
       
   308     def helper_class_hook(helper_class):
       
   309         decl = """
       
   310 static ns3::TypeId GetTypeId (void)
       
   311 {
       
   312   static ns3::TypeId tid = ns3::TypeId ("%s")
       
   313     .SetParent< %s > ()
       
   314     ;
       
   315   return tid;
       
   316 }"""  % (helper_class.name, helper_class.class_.full_name)
       
   317 
       
   318         helper_class.add_custom_method(decl)
       
   319         helper_class.add_post_generation_code(
       
   320             "NS_OBJECT_ENSURE_REGISTERED (%s);" % helper_class.name)
       
   321     Object.add_helper_class_hook(helper_class_hook)
       
   322 
       
   323     ## Replace all class constructors with a generic constructor based on CreateObject<T> (AttributeList)
       
   324     module.header.writeln('''
       
   325 namespace ns3 {
       
   326 
       
   327 void PythonCompleteConstruct (Ptr<Object> object, TypeId typeId, const AttributeList &attributes);
       
   328 
       
   329 template <typename T>
       
   330 Ptr<T> CreateObjectPython (PyObject *pyobj, const AttributeList &attributes)
       
   331 {
       
   332   Ptr<T> p = Ptr<T> (new T (), false);
       
   333   p->set_pyobj (pyobj);
       
   334   PythonCompleteConstruct (p, T::GetTypeId (), attributes);
       
   335   return p;  
       
   336 }
       
   337 
       
   338 } // namespace ns3
       
   339 
       
   340 ''')
       
   341     
       
   342     for cls in module.classes:
       
   343         if not cls.is_subclass(Object):
       
   344             continue
       
   345         cls.constructors = [] # clear the list of constructors
       
   346 
       
   347         ## add our own custom constructor, if possible
       
   348         try:
       
   349             construct_name = cls.get_construct_name()
       
   350         except CodeGenerationError:
       
   351             construct_name = None
       
   352 
       
   353         if construct_name and not cls.helper_class:
       
   354             construct_code = '''
       
   355     ns3::Ptr< %(CONSTRUCT_NAME)s > obj = ns3::CreateObject< %(CONSTRUCT_NAME)s > (attrList);
       
   356     obj->Ref ();
       
   357     self->obj = ns3::PeekPointer (obj);
       
   358 ''' % dict (CONSTRUCT_NAME=construct_name)
       
   359 
       
   360         elif not construct_name and not cls.helper_class:
       
   361             continue
       
   362 
       
   363         elif not construct_name and cls.helper_class:
       
   364             construct_code = '''
       
   365     if (self->ob_type != &%(PYTYPESTRUCT)s)
       
   366     {
       
   367         ns3::Ptr< %(HELPER_CLASS_NAME)s > obj = ns3::CreateObjectPython< %(HELPER_CLASS_NAME)s > ((PyObject *)self, attrList);
       
   368         obj->Ref ();
       
   369         self->obj = ns3::PeekPointer (obj);
       
   370     } else {
       
   371         PyErr_SetString(PyExc_TypeError, "Class cannot be constructed (unless subclassed)");
       
   372         {
       
   373             PyObject *exc_type, *traceback;
       
   374             PyErr_Fetch(&exc_type, return_exception, &traceback);
       
   375             Py_XDECREF(exc_type);
       
   376             Py_XDECREF(traceback);
       
   377         }
       
   378         return -1;
       
   379     }
       
   380 ''' % dict (CONSTRUCT_NAME=construct_name, HELPER_CLASS_NAME=cls.helper_class.name,
       
   381             PYTYPESTRUCT=cls.pytypestruct)
       
   382 
       
   383         elif construct_name and cls.helper_class:
       
   384             construct_code = '''
       
   385     if (self->ob_type != &%(PYTYPESTRUCT)s)
       
   386     {
       
   387         ns3::Ptr< %(HELPER_CLASS_NAME)s > obj = ns3::CreateObjectPython< %(HELPER_CLASS_NAME)s > ((PyObject *)self, attrList);
       
   388         obj->Ref ();
       
   389         self->obj = ns3::PeekPointer (obj);
       
   390     } else {
       
   391         ns3::Ptr< %(CONSTRUCT_NAME)s > obj = ns3::CreateObject< %(CONSTRUCT_NAME)s > (attrList);
       
   392         obj->Ref ();
       
   393         self->obj = ns3::PeekPointer (obj);
       
   394     }
       
   395 ''' % dict (CONSTRUCT_NAME=construct_name, HELPER_CLASS_NAME=cls.helper_class.name,
       
   396             PYTYPESTRUCT=cls.pytypestruct)
       
   397         else:
       
   398             raise AssertionError
       
   399 
       
   400         wrapper_name = "_wrap_create_object_%s" % (cls.full_name.replace(':', '_'),) 
       
   401         constructor = '''
       
   402 static int %(WRAPPER_NAME)s (%(PYSTRUCT)s *self, PyObject *args, PyObject *kwargs, PyObject **return_exception)
       
   403 {
       
   404     if (PyTuple_Size(args)) {
       
   405         PyErr_SetString(PyExc_TypeError, "positional arguments not supported "
       
   406                         "for ns3.Object constructors, only keyword arguments"
       
   407                         " should be used (AttributeName=Value)");
       
   408         {
       
   409             PyObject *exc_type, *traceback;
       
   410             PyErr_Fetch(&exc_type, return_exception, &traceback);
       
   411             Py_XDECREF(exc_type);
       
   412             Py_XDECREF(traceback);
       
   413         }
       
   414         return -1;
       
   415     }
       
   416     ns3::AttributeList attrList;
       
   417     if (kwargs && KwargsToAttributeList(kwargs, %(CLASS_NAME)s::GetTypeId(), attrList)) {
       
   418         {
       
   419             PyObject *exc_type, *traceback;
       
   420             PyErr_Fetch(&exc_type, return_exception, &traceback);
       
   421             Py_XDECREF(exc_type);
       
   422             Py_XDECREF(traceback);
       
   423         }
       
   424         return -1;
       
   425     }
       
   426     %(CONSTRUCT_CODE)s
       
   427     return 0;
       
   428 }
       
   429 ''' % dict(WRAPPER_NAME=wrapper_name, PYSTRUCT=cls.pystruct, CLASS_NAME=cls.full_name,
       
   430            CONSTRUCT_CODE=construct_code, PURE_VIRTUALS=cls.have_pure_virtual_methods)
       
   431         cls.add_constructor(CustomCppConstructorWrapper(wrapper_name, constructor))
       
   432 
       
   433 
       
   434     # Generate conversion function from PyObject* to AttributeValue
       
   435 #     sink = module.body
       
   436 #     sink.writeln('''
       
   437 # Ptr<AttributeValue> AttributeValueFromPyObject (PyObject *obj)
       
   438 # {
       
   439 #     // note: needs to check for bool first, because bool is a subclass of int
       
   440 #     if (PyBool_Check(obj)) {
       
   441 #         return Create<BooleanValue>(PyObject_IsTrue(obj));
       
   442 #     } else if (PyInt_Check(obj)) {
       
   443 #         return Create<IntegerValue>(PyInt_AsLong(obj));
       
   444 #     } else if (PyLong_Check(obj)) {
       
   445 #         return Create<IntegerValue>(PyLong_AsLongLong(obj));
       
   446 #     } else if (PyFloat_Check(obj)) {
       
   447 #         return Create<DoubleValue>(PyFloat_AsDouble(obj));
       
   448 #     }
       
   449 
       
   450 # ''')
       
   451     
       
   452 
       
   453 
       
   454     ## ---------------------------------------------------------------------
       
   455     ## -------------- write the KwargsToAttributeList function -------------
       
   456     ## ---------------------------------------------------------------------
       
   457     Attribute = module['ns3::AttributeValue']
       
   458     module.after_forward_declarations.writeln(
       
   459         'int KwargsToAttributeList(PyObject *kwargs, ns3::TypeId tid, ns3::AttributeList &oAttrList);')
       
   460 
       
   461     module.body.writeln(
       
   462 '''
       
   463 int KwargsToAttributeList(PyObject *kwargs, ns3::TypeId tid, ns3::AttributeList &oAttrList)
       
   464 {
       
   465     PyObject *key, *value;
       
   466     Py_ssize_t pos = 0;
       
   467 
       
   468     while (PyDict_Next(kwargs, &pos, &key, &value)) {
       
   469         if (!PyString_Check(key)) {
       
   470             PyErr_SetString(PyExc_TypeError, "kwargs keys must be strings");
       
   471             return -1;
       
   472         }
       
   473         if (PyObject_IsInstance(value, (PyObject*) &%s)) {
       
   474             oAttrList.SetWithTid(tid, PyString_AsString(key), *((%s *) value)->obj);''' \
       
   475     % (Attribute.pytypestruct, Attribute.pystruct))
       
   476 
       
   477     for conversion_source in Attribute.get_all_implicit_conversions():
       
   478         module.body.writeln('''
       
   479         } else if (PyObject_IsInstance(value, (PyObject*) &%s)) {
       
   480             oAttrList.SetWithTid(tid, PyString_AsString(key), *((%s *) value)->obj);''' \
       
   481                         % (conversion_source.pytypestruct, conversion_source.pystruct))
       
   482 
       
   483     possible_type_names = ", ".join([cls.name for cls in [Attribute] + Attribute.get_all_implicit_conversions()])
       
   484     module.body.writeln('''
       
   485         } else {
       
   486             PyErr_Format(PyExc_TypeError, \"parameter must an instance of one of the types (%s), not %%s\", value->ob_type->tp_name);
       
   487             return -1;
       
   488         }''' % (possible_type_names))
       
   489 
       
   490     module.body.writeln(
       
   491 '''
       
   492     }
       
   493     return 0;
       
   494 }
       
   495 ''')