From ecc1df19d5c3df090126e660c2b030491fd06e45 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 17 Mar 2010 11:18:55 +0000 Subject: [PATCH] Realign Python ns3.Object constructors with C++ The Python constructors are now parameter oriented instead of attribute oriented. The main motivation for this change is that Python bindings become broken with new Object types being introduced that do not have a default constructor (constructor without parameters). Another reason is to shorten the gap between C++ and Python, API-wise--the more similar they are, the less confusing it becomes. --- .../ns3modulegen_core_customizations.py | 189 ++---------------- bindings/python/wscript | 2 +- 2 files changed, 16 insertions(+), 175 deletions(-) diff --git a/bindings/python/ns3modulegen_core_customizations.py b/bindings/python/ns3modulegen_core_customizations.py index 807dbabb0..fa768264a 100644 --- a/bindings/python/ns3modulegen_core_customizations.py +++ b/bindings/python/ns3modulegen_core_customizations.py @@ -24,7 +24,7 @@ class SmartPointerTransformation(typehandlers.TypeTransformation): """ def __init__(self): super(SmartPointerTransformation, self).__init__() - self.rx = re.compile(r'(ns3::|::ns3::|)Ptr<([^>]+)>') + self.rx = re.compile(r'(ns3::|::ns3::|)Ptr<([^>]+)>\s*$') def _get_untransformed_type_traits(self, name): m = self.rx.match(name) @@ -350,180 +350,21 @@ static ns3::TypeId GetTypeId (void) "NS_OBJECT_ENSURE_REGISTERED (%s);" % helper_class.name) Object.add_helper_class_hook(helper_class_hook) - ## Replace all class constructors with a generic constructor based on CreateObjectWithAttributes (AttributeList) - module.header.writeln(''' -namespace ns3 { + def ns3_object_instance_creation_function(cpp_class, code_block, lvalue, + parameters, construct_type_name): + assert lvalue + assert not lvalue.startswith('None') + if cpp_class.cannot_be_constructed: + raise CodeGenerationError("%s cannot be constructed (%s)" + % cpp_class.full_name) + if cpp_class.incomplete_type: + raise CodeGenerationError("%s cannot be constructed (incomplete type)" + % cpp_class.full_name) + code_block.write_code("%s = new %s(%s);" % (lvalue, construct_type_name, parameters)) + code_block.write_code("%s->Ref ();" % (lvalue)) + code_block.write_code("ns3::CompleteConstruct(%s);" % (lvalue, )) -void PythonCompleteConstruct (Ptr object, TypeId typeId, const AttributeList &attributes); - -template -Ptr CreateObjectPython (PyObject *pyobj, const AttributeList &attributes) -{ - Ptr p = Ptr (new T (), false); - p->set_pyobj (pyobj); - PythonCompleteConstruct (p, T::GetTypeId (), attributes); - return p; -} - -} // namespace ns3 - -''') - - for cls in module.classes: - if not cls.is_subclass(Object): - continue - cls.constructors = [] # clear the list of constructors - - ## add our own custom constructor, if possible - try: - construct_name = cls.get_construct_name() - except CodeGenerationError: - construct_name = None - - if construct_name and not cls.helper_class: - construct_code = ''' - ns3::Ptr< %(CONSTRUCT_NAME)s > obj = ns3::CreateObjectWithAttributes< %(CONSTRUCT_NAME)s > (attrList); - obj->Ref (); - self->obj = ns3::PeekPointer (obj); -''' % dict (CONSTRUCT_NAME=construct_name) - - elif not construct_name and not cls.helper_class: - continue - - elif not construct_name and cls.helper_class: - construct_code = ''' - if (self->ob_type != &%(PYTYPESTRUCT)s) - { - ns3::Ptr< %(HELPER_CLASS_NAME)s > obj = ns3::CreateObjectPython< %(HELPER_CLASS_NAME)s > ((PyObject *)self, attrList); - obj->Ref (); - self->obj = ns3::PeekPointer (obj); - } else { - PyErr_SetString(PyExc_TypeError, "Class cannot be constructed (unless subclassed)"); - { - PyObject *exc_type, *traceback; - PyErr_Fetch(&exc_type, return_exception, &traceback); - Py_XDECREF(exc_type); - Py_XDECREF(traceback); - } - return -1; - } -''' % dict (CONSTRUCT_NAME=construct_name, HELPER_CLASS_NAME=cls.helper_class.name, - PYTYPESTRUCT=cls.pytypestruct) - - elif construct_name and cls.helper_class: - construct_code = ''' - if (self->ob_type != &%(PYTYPESTRUCT)s) - { - ns3::Ptr< %(HELPER_CLASS_NAME)s > obj = ns3::CreateObjectPython< %(HELPER_CLASS_NAME)s > ((PyObject *)self, attrList); - obj->Ref (); - self->obj = ns3::PeekPointer (obj); - } else { - ns3::Ptr< %(CONSTRUCT_NAME)s > obj = ns3::CreateObjectWithAttributes< %(CONSTRUCT_NAME)s > (attrList); - obj->Ref (); - self->obj = ns3::PeekPointer (obj); - } -''' % dict (CONSTRUCT_NAME=construct_name, HELPER_CLASS_NAME=cls.helper_class.name, - PYTYPESTRUCT=cls.pytypestruct) - else: - raise AssertionError - - wrapper_name = "_wrap_create_object_%s" % (cls.mangled_full_name,) - constructor = ''' -static int %(WRAPPER_NAME)s (%(PYSTRUCT)s *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) -{ - if (PyTuple_Size(args)) { - PyErr_SetString(PyExc_TypeError, "positional arguments not supported " - "for ns3.Object constructors, only keyword arguments" - " should be used (AttributeName=Value)"); - { - PyObject *exc_type, *traceback; - PyErr_Fetch(&exc_type, return_exception, &traceback); - Py_XDECREF(exc_type); - Py_XDECREF(traceback); - } - return -1; - } - ns3::AttributeList attrList; - if (kwargs && KwargsToAttributeList(kwargs, %(CLASS_NAME)s::GetTypeId(), attrList)) { - { - PyObject *exc_type, *traceback; - PyErr_Fetch(&exc_type, return_exception, &traceback); - Py_XDECREF(exc_type); - Py_XDECREF(traceback); - } - return -1; - } - %(CONSTRUCT_CODE)s - PyNs3ObjectBase_wrapper_registry[(void *) self->obj] = (PyObject *) self; - return 0; -} -''' % dict(WRAPPER_NAME=wrapper_name, PYSTRUCT=cls.pystruct, CLASS_NAME=cls.full_name, - CONSTRUCT_CODE=construct_code, PURE_VIRTUALS=cls.have_pure_virtual_methods) - cls.add_constructor(CustomCppConstructorWrapper(wrapper_name, constructor)) - - - # Generate conversion function from PyObject* to AttributeValue -# sink = module.body -# sink.writeln(''' -# Ptr AttributeValueFromPyObject (PyObject *obj) -# { -# // note: needs to check for bool first, because bool is a subclass of int -# if (PyBool_Check(obj)) { -# return Create(PyObject_IsTrue(obj)); -# } else if (PyInt_Check(obj)) { -# return Create(PyInt_AsLong(obj)); -# } else if (PyLong_Check(obj)) { -# return Create(PyLong_AsLongLong(obj)); -# } else if (PyFloat_Check(obj)) { -# return Create(PyFloat_AsDouble(obj)); -# } - -# ''') - - - - ## --------------------------------------------------------------------- - ## -------------- write the KwargsToAttributeList function ------------- - ## --------------------------------------------------------------------- - Attribute = module['ns3::AttributeValue'] - module.after_forward_declarations.writeln( - 'int KwargsToAttributeList(PyObject *kwargs, ns3::TypeId tid, ns3::AttributeList &oAttrList);') - - module.body.writeln( -''' -int KwargsToAttributeList(PyObject *kwargs, ns3::TypeId tid, ns3::AttributeList &oAttrList) -{ - PyObject *key, *value; - Py_ssize_t pos = 0; - - while (PyDict_Next(kwargs, &pos, &key, &value)) { - if (!PyString_Check(key)) { - PyErr_SetString(PyExc_TypeError, "kwargs keys must be strings"); - return -1; - } - if (PyObject_IsInstance(value, (PyObject*) &%s)) { - oAttrList.SetWithTid(tid, PyString_AsString(key), *((%s *) value)->obj);''' \ - % (Attribute.pytypestruct, Attribute.pystruct)) - - for conversion_source in Attribute.get_all_implicit_conversions(): - module.body.writeln(''' - } else if (PyObject_IsInstance(value, (PyObject*) &%s)) { - oAttrList.SetWithTid(tid, PyString_AsString(key), *((%s *) value)->obj);''' \ - % (conversion_source.pytypestruct, conversion_source.pystruct)) - - possible_type_names = ", ".join([cls.name for cls in [Attribute] + Attribute.get_all_implicit_conversions()]) - module.body.writeln(''' - } else { - PyErr_Format(PyExc_TypeError, \"parameter must an instance of one of the types (%s), not %%s\", value->ob_type->tp_name); - return -1; - }''' % (possible_type_names)) - - module.body.writeln( -''' - } - return 0; -} -''') + Object.set_instance_creation_function(ns3_object_instance_creation_function) def Attribute_customizations(module): diff --git a/bindings/python/wscript b/bindings/python/wscript index a555a47bc..f4653b997 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -15,7 +15,7 @@ import Build import Utils ## https://launchpad.net/pybindgen/ -REQUIRED_PYBINDGEN_VERSION = (0, 13, 0, 745) +REQUIRED_PYBINDGEN_VERSION = (0, 14, 0, 755) REQUIRED_PYGCCXML_VERSION = (0, 9, 5)