| 202 | } |
| 203 | |
| 204 | PyObject* ExtensionContainerPy::addExtension(PyObject* args) |
| 205 | { |
| 206 | |
| 207 | char* typeId; |
| 208 | PyObject* proxy = nullptr; |
| 209 | if (!PyArg_ParseTuple(args, "s|O", &typeId, &proxy)) { |
| 210 | return nullptr; |
| 211 | } |
| 212 | |
| 213 | if (proxy) { |
| 214 | PyErr_SetString( |
| 215 | PyExc_DeprecationWarning, |
| 216 | "Second argument is deprecated. It is ignored and will be removed in future versions. " |
| 217 | "The default Python feature proxy is used for extension method overrides."); |
| 218 | PyErr_Print(); |
| 219 | } |
| 220 | |
| 221 | // get the extension type asked for |
| 222 | Base::Type extension = Base::Type::fromName(typeId); |
| 223 | if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) { |
| 224 | std::stringstream str; |
| 225 | str << "No extension found of type '" << typeId << "'" << std::ends; |
| 226 | throw Py::TypeError(str.str()); |
| 227 | } |
| 228 | |
| 229 | // register the extension |
| 230 | App::Extension* ext = static_cast<App::Extension*>(extension.createInstance()); |
| 231 | // check if this really is a python extension! |
| 232 | if (!ext->isPythonExtension()) { |
| 233 | delete ext; |
| 234 | std::stringstream str; |
| 235 | str << "Extension is not a python addable version: '" << typeId << "'" << std::ends; |
| 236 | throw Py::TypeError(str.str()); |
| 237 | } |
| 238 | |
| 239 | GetApplication().signalBeforeAddingDynamicExtension(*getExtensionContainerPtr(), typeId); |
| 240 | ext->initExtension(getExtensionContainerPtr()); |
| 241 | |
| 242 | // The PyTypeObject is shared by all instances of this type and therefore |
| 243 | // we have to add new methods only once. |
| 244 | PyObject* obj = ext->getExtensionPyObject(); |
| 245 | PyMethodDef* meth = obj->ob_type->tp_methods; |
| 246 | PyTypeObject* type = this->ob_type; |
| 247 | PyObject* dict = type->tp_dict; |
| 248 | |
| 249 | // make sure to do the initialization only once |
| 250 | if (meth->ml_name) { |
| 251 | PyObject* item = PyDict_GetItemString(dict, meth->ml_name); |
| 252 | if (!item) { |
| 253 | // Note: this adds the methods to the type object to make sure |
| 254 | // it appears in the call tips. The function will not be bound |
| 255 | // to an instance |
| 256 | Py_INCREF(dict); |
| 257 | while (meth->ml_name) { |
| 258 | PyObject* func; |
| 259 | func = PyCFunction_New(meth, 0); |
| 260 | if (!func) { |
| 261 | break; |
no test coverage detected