annotate PyPlugin.cpp @ 92:a6718f9fe942

If a module appears to redefine one of our own types, refuse to load it. Also clear out the class dict for all refused modules now, so that we don't get stale names on the next scan due to not having cleared the module on unload
author Chris Cannam
date Mon, 14 Jan 2019 16:19:44 +0000
parents f92587bedb2c
children
rev   line source
fazekasgy@37 1 /*
fazekasgy@37 2
fazekasgy@37 3 * Vampy : This plugin is a wrapper around the Vamp plugin API.
fazekasgy@37 4 * It allows for writing Vamp plugins in Python.
fazekasgy@37 5
fazekasgy@37 6 * Centre for Digital Music, Queen Mary University of London.
fazekasgy@37 7 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources
fazekasgy@37 8 * for licence information.)
fazekasgy@37 9
fazekasgy@37 10 */
fazekasgy@37 11
fazekasgy@37 12 #include <Python.h>
fazekasgy@37 13 #include "PyPlugin.h"
fazekasgy@37 14 #include "PyTypeInterface.h"
fazekasgy@37 15 #include <stdlib.h>
fazekasgy@37 16 #include "PyExtensionModule.h"
Chris@67 17 #include "Debug.h"
fazekasgy@37 18
fazekasgy@37 19 #ifdef _WIN32
fazekasgy@37 20 #define PATHSEP ('\\')
fazekasgy@37 21 #else
fazekasgy@37 22 #define PATHSEP ('/')
fazekasgy@37 23 #endif
fazekasgy@37 24
fazekasgy@37 25 using std::string;
fazekasgy@37 26 using std::vector;
fazekasgy@37 27 using std::cerr;
fazekasgy@37 28 using std::endl;
fazekasgy@37 29 using std::map;
fazekasgy@37 30
fazekasgy@37 31 Mutex PyPlugin::m_pythonInterpreterMutex;
fazekasgy@37 32
fazekasgy@51 33 PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass, int &instcount, bool &numpyInstalled) :
fazekasgy@37 34 Plugin(inputSampleRate),
fazekasgy@37 35 m_pyClass(pyClass),
fazekasgy@37 36 m_instcount(instcount),
fazekasgy@37 37 m_stepSize(0),
fazekasgy@37 38 m_blockSize(0),
fazekasgy@37 39 m_channels(0),
fazekasgy@37 40 m_plugin(pluginKey),
fazekasgy@37 41 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
fazekasgy@37 42 m_path((pluginKey.substr(0,pluginKey.rfind(PATHSEP)))),
fazekasgy@37 43 m_processType(not_implemented),
fazekasgy@37 44 m_pyProcess(NULL),
fazekasgy@37 45 m_inputDomain(TimeDomain),
fazekasgy@37 46 m_quitOnErrorFlag(false),
fazekasgy@51 47 m_debugFlag(false),
fazekasgy@51 48 m_numpyInstalled(numpyInstalled),
fazekasgy@51 49 m_processFailure(false)
fazekasgy@37 50 {
fazekasgy@37 51 m_ti.setInputSampleRate(inputSampleRate);
fazekasgy@37 52 MutexLocker locker(&m_pythonInterpreterMutex);
Chris@67 53 DSTREAM << "Creating instance " << m_instcount << " of " << pluginKey << endl;
fazekasgy@37 54
fazekasgy@37 55 // Create an instance
fazekasgy@37 56 Py_INCREF(m_pyClass);
fazekasgy@37 57 PyObject *pyInputSampleRate = PyFloat_FromDouble(inputSampleRate);
fazekasgy@37 58 PyObject *args = PyTuple_Pack(1, pyInputSampleRate);
fazekasgy@37 59 m_pyInstance = PyObject_Call(m_pyClass, args, NULL);
fazekasgy@37 60
fazekasgy@37 61 if (!m_pyInstance || PyErr_Occurred()) {
fazekasgy@37 62 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 63 Py_DECREF(m_pyClass);
fazekasgy@37 64 Py_CLEAR(args);
fazekasgy@37 65 Py_CLEAR(pyInputSampleRate);
fazekasgy@37 66 cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \""
Chris@89 67 << pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl;
fazekasgy@37 68 throw std::string("Constructor failed");
fazekasgy@37 69 }
Chris@89 70
fazekasgy@37 71 Py_INCREF(m_pyInstance);
fazekasgy@37 72 Py_DECREF(args);
fazekasgy@37 73 Py_DECREF(pyInputSampleRate);
fazekasgy@37 74
fazekasgy@37 75 m_instcount++;
fazekasgy@37 76
fazekasgy@37 77 // query and decode vampy flags
fazekasgy@37 78 m_vampyFlags = getBinaryFlags("vampy_flags",vf_NULL);
fazekasgy@37 79
fazekasgy@37 80 m_debugFlag = (bool) (m_vampyFlags & vf_DEBUG);
fazekasgy@37 81 m_quitOnErrorFlag = (bool) (m_vampyFlags & vf_QUIT);
fazekasgy@37 82 bool st_flag = (bool) (m_vampyFlags & vf_STRICT);
fazekasgy@37 83 m_useRealTimeFlag = (bool) (m_vampyFlags & vf_REALTIME);
fazekasgy@37 84
fazekasgy@37 85 if (m_debugFlag) cerr << "Debug messages ON for Vampy plugin: " << m_class << endl;
Chris@67 86 else DSTREAM << "Debug messages OFF for Vampy plugin: " << m_class << endl;
fazekasgy@37 87
fazekasgy@37 88 if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl;
fazekasgy@37 89
fazekasgy@37 90 if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl;
fazekasgy@37 91 m_ti.setStrictTypingFlag(st_flag);
fazekasgy@51 92 m_ti.setNumpyInstalled(m_numpyInstalled);
fazekasgy@37 93
fazekasgy@37 94 }
fazekasgy@37 95
fazekasgy@37 96 PyPlugin::~PyPlugin()
fazekasgy@37 97 {
fazekasgy@37 98 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 99 m_instcount--;
fazekasgy@37 100 // cerr << "Deleting plugin instance. Count: " << m_instcount << endl;
fazekasgy@37 101
fazekasgy@37 102 if (m_pyInstance) Py_DECREF(m_pyInstance);
fazekasgy@37 103 //we increase the class refcount before creating an instance
fazekasgy@37 104 if (m_pyClass) Py_DECREF(m_pyClass);
fazekasgy@37 105 if (m_pyProcess) Py_CLEAR(m_pyProcess);
fazekasgy@37 106
Chris@67 107 DSTREAM << "PyPlugin::PyPlugin:" << m_class << " instance " << m_instcount << " deleted." << endl;
fazekasgy@37 108 }
fazekasgy@37 109
fazekasgy@37 110 string
fazekasgy@37 111 PyPlugin::getIdentifier() const
fazekasgy@37 112 {
fazekasgy@37 113 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 114 string rString="vampy-xxx";
fazekasgy@37 115 if (!m_debugFlag) return genericMethodCall("getIdentifier",rString);
fazekasgy@37 116
fazekasgy@37 117 rString = genericMethodCall("getIdentifier",rString);
fazekasgy@37 118 if (rString == "vampy-xxx")
fazekasgy@37 119 cerr << "Warning: Plugin must return a unique identifier." << endl;
fazekasgy@37 120 return rString;
fazekasgy@37 121 }
fazekasgy@37 122
fazekasgy@37 123 string
fazekasgy@37 124 PyPlugin::getName() const
fazekasgy@37 125 {
fazekasgy@37 126 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 127 string rString="VamPy Plugin (Noname)";
fazekasgy@37 128 return genericMethodCall("getName",rString);
fazekasgy@37 129 }
fazekasgy@37 130
fazekasgy@37 131 string
fazekasgy@37 132 PyPlugin::getDescription() const
fazekasgy@37 133 {
fazekasgy@37 134 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 135 string rString="Not given. (Hint: Implement getDescription method.)";
fazekasgy@37 136 return genericMethodCall("getDescription",rString);
fazekasgy@37 137 }
fazekasgy@37 138
fazekasgy@37 139
fazekasgy@37 140 string
fazekasgy@37 141 PyPlugin::getMaker() const
fazekasgy@37 142 {
fazekasgy@37 143 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 144 string rString="VamPy Plugin.";
fazekasgy@37 145 return genericMethodCall("getMaker",rString);
fazekasgy@37 146 }
fazekasgy@37 147
fazekasgy@37 148 int
fazekasgy@37 149 PyPlugin::getPluginVersion() const
fazekasgy@37 150 {
fazekasgy@37 151 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 152 size_t rValue=2;
fazekasgy@37 153 return genericMethodCall("getPluginVersion",rValue);
fazekasgy@37 154 }
fazekasgy@37 155
fazekasgy@37 156 string
fazekasgy@37 157 PyPlugin::getCopyright() const
fazekasgy@37 158 {
fazekasgy@37 159 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 160 string rString="Licence information not available.";
fazekasgy@37 161 return genericMethodCall("getCopyright",rString);
fazekasgy@37 162 }
fazekasgy@37 163
fazekasgy@37 164
fazekasgy@37 165 bool
fazekasgy@37 166 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
fazekasgy@37 167 {
fazekasgy@37 168
fazekasgy@37 169 if (channels < getMinChannelCount() ||
fazekasgy@37 170 channels > getMaxChannelCount()) return false;
fazekasgy@37 171
fazekasgy@37 172 m_inputDomain = getInputDomain();
fazekasgy@37 173
fazekasgy@37 174 //Note: placing Mutex before the calls above causes deadlock !!
fazekasgy@37 175 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 176
fazekasgy@37 177 m_stepSize = stepSize;
fazekasgy@37 178 m_blockSize = blockSize;
fazekasgy@37 179 m_channels = channels;
fazekasgy@37 180
fazekasgy@37 181 //query the process implementation type
fazekasgy@37 182 //two optional flags can be used: 'use_numpy_interface' or 'use_legacy_interface'
fazekasgy@37 183 //if they are not provided, we fall back to the original method
fazekasgy@37 184 setProcessType();
fazekasgy@37 185
fazekasgy@37 186 return genericMethodCallArgs<bool>("initialise",channels,stepSize,blockSize);
fazekasgy@37 187 }
fazekasgy@37 188
fazekasgy@37 189 void
fazekasgy@37 190 PyPlugin::reset()
fazekasgy@37 191 {
fazekasgy@37 192 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@51 193 m_processFailure = false;
fazekasgy@37 194 genericMethodCall("reset");
fazekasgy@37 195 }
fazekasgy@37 196
fazekasgy@37 197 PyPlugin::InputDomain
fazekasgy@37 198 PyPlugin::getInputDomain() const
fazekasgy@37 199 {
fazekasgy@37 200 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 201 return genericMethodCall("getInputDomain",m_inputDomain);
fazekasgy@37 202 }
fazekasgy@37 203
fazekasgy@37 204 size_t
fazekasgy@37 205 PyPlugin::getPreferredBlockSize() const
fazekasgy@37 206 {
fazekasgy@37 207 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 208 size_t rValue = 0;
fazekasgy@37 209 return genericMethodCall("getPreferredBlockSize",rValue);
fazekasgy@37 210 }
fazekasgy@37 211
fazekasgy@37 212 size_t
fazekasgy@37 213 PyPlugin::getPreferredStepSize() const
fazekasgy@37 214 {
fazekasgy@37 215 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 216 size_t rValue = 0;
fazekasgy@37 217 return genericMethodCall("getPreferredStepSize",rValue);
fazekasgy@37 218 }
fazekasgy@37 219
fazekasgy@37 220 size_t
fazekasgy@37 221 PyPlugin::getMinChannelCount() const
fazekasgy@37 222 {
fazekasgy@37 223 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 224 size_t rValue = 1;
fazekasgy@37 225 return genericMethodCall("getMinChannelCount",rValue);
fazekasgy@37 226 }
fazekasgy@37 227
fazekasgy@37 228 size_t
fazekasgy@37 229 PyPlugin::getMaxChannelCount() const
fazekasgy@37 230 {
fazekasgy@37 231 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 232 size_t rValue = 1;
fazekasgy@37 233 return genericMethodCall("getMaxChannelCount",rValue);
fazekasgy@37 234 }
fazekasgy@37 235
fazekasgy@37 236 PyPlugin::OutputList
fazekasgy@37 237 PyPlugin::getOutputDescriptors() const
fazekasgy@37 238 {
fazekasgy@37 239 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 240 OutputList list;
fazekasgy@37 241 return genericMethodCall("getOutputDescriptors",list);
fazekasgy@37 242 }
fazekasgy@37 243
fazekasgy@37 244 PyPlugin::ParameterList
fazekasgy@37 245 PyPlugin::getParameterDescriptors() const
fazekasgy@37 246 {
fazekasgy@37 247 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 248 ParameterList list;
fazekasgy@37 249 #ifdef _DEBUG
fazekasgy@37 250 ///Note: This function is often called first by the host.
fazekasgy@37 251 if (!m_pyInstance) {cerr << "Error: pyInstance is NULL" << endl; return list;}
fazekasgy@37 252 #endif
fazekasgy@37 253
fazekasgy@37 254 return genericMethodCall("getParameterDescriptors",list);
fazekasgy@37 255 }
fazekasgy@37 256
fazekasgy@37 257 void PyPlugin::setParameter(std::string paramid, float newval)
fazekasgy@37 258 {
fazekasgy@37 259 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 260 genericMethodCallArgs<NoneType>("setParameter",paramid,newval);
fazekasgy@37 261 }
fazekasgy@37 262
fazekasgy@37 263 float PyPlugin::getParameter(std::string paramid) const
fazekasgy@37 264 {
fazekasgy@37 265 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 266 return genericMethodCallArgs<float>("getParameter",paramid);
fazekasgy@37 267 }
fazekasgy@37 268
fazekasgy@37 269 #ifdef _DEBUG_VALUES
fazekasgy@37 270 static int proccounter = 0;
fazekasgy@37 271 #endif
fazekasgy@37 272
fazekasgy@37 273 PyPlugin::FeatureSet
fazekasgy@37 274 PyPlugin::process(const float *const *inputBuffers,Vamp::RealTime timestamp)
fazekasgy@37 275 {
fazekasgy@37 276 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@37 277
fazekasgy@37 278 #ifdef _DEBUG_VALUES
fazekasgy@37 279 /// we only need this if we'd like to see what frame a set of values belong to
fazekasgy@37 280 cerr << "[Vampy::call] process, frame:" << proccounter << endl;
fazekasgy@37 281 proccounter++;
fazekasgy@37 282 #endif
fazekasgy@37 283
fazekasgy@37 284 if (m_blockSize == 0 || m_channels == 0) {
fazekasgy@37 285 cerr << "ERROR: PyPlugin::process: "
fazekasgy@37 286 << "Plugin has not been initialised" << endl;
fazekasgy@37 287 return FeatureSet();
fazekasgy@37 288 }
fazekasgy@37 289
fazekasgy@37 290 if (m_processType == not_implemented) {
fazekasgy@37 291 cerr << "ERROR: In Python plugin [" << m_class
fazekasgy@37 292 << "] No process implementation found. Returning empty feature set." << endl;
fazekasgy@37 293 return FeatureSet();
fazekasgy@37 294 }
fazekasgy@37 295
fazekasgy@51 296 if (m_processFailure) return FeatureSet();
fazekasgy@51 297
fazekasgy@37 298 return processMethodCall(inputBuffers,timestamp);
fazekasgy@37 299
fazekasgy@37 300 }
fazekasgy@37 301
fazekasgy@37 302 PyPlugin::FeatureSet
fazekasgy@37 303 PyPlugin::getRemainingFeatures()
fazekasgy@37 304 {
fazekasgy@37 305 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@51 306 if (m_processFailure) return FeatureSet();
fazekasgy@37 307 FeatureSet rValue;
fazekasgy@37 308 return genericMethodCall("getRemainingFeatures",rValue);
fazekasgy@37 309 }
fazekasgy@37 310
fazekasgy@37 311 bool
Chris@66 312 PyPlugin::getBooleanFlag(const char flagName[], bool defValue = false) const
fazekasgy@37 313 {
fazekasgy@37 314 bool rValue = defValue;
fazekasgy@37 315 if (PyObject_HasAttrString(m_pyInstance,flagName))
fazekasgy@37 316 {
fazekasgy@37 317 PyObject *pyValue = PyObject_GetAttrString(m_pyInstance,flagName);
fazekasgy@37 318 if (!pyValue)
fazekasgy@37 319 {
fazekasgy@37 320 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 321 } else {
fazekasgy@37 322 rValue = m_ti.PyValue_To_Bool(pyValue);
fazekasgy@37 323 if (m_ti.error) {
fazekasgy@37 324 Py_CLEAR(pyValue);
fazekasgy@37 325 typeErrorHandler(flagName);
fazekasgy@37 326 rValue = defValue;
fazekasgy@37 327 } else Py_DECREF(pyValue);
fazekasgy@37 328 }
fazekasgy@37 329 }
fazekasgy@37 330 if (m_debugFlag) cerr << FLAG_VALUE << endl;
fazekasgy@37 331 return rValue;
fazekasgy@37 332 }
fazekasgy@37 333
fazekasgy@37 334 int
Chris@66 335 PyPlugin::getBinaryFlags(const char flagName[], eVampyFlags defValue = vf_NULL) const
fazekasgy@37 336 {
fazekasgy@37 337 int rValue = defValue;
fazekasgy@37 338 if (PyObject_HasAttrString(m_pyInstance,flagName))
fazekasgy@37 339 {
fazekasgy@37 340 PyObject *pyValue = PyObject_GetAttrString(m_pyInstance,flagName);
fazekasgy@37 341 if (!pyValue)
fazekasgy@37 342 {
fazekasgy@37 343 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 344 } else {
fazekasgy@37 345 rValue |= (int) m_ti.PyValue_To_Size_t(pyValue);
fazekasgy@37 346 if (m_ti.error) {
fazekasgy@37 347 Py_CLEAR(pyValue);
fazekasgy@37 348 typeErrorHandler(flagName);
fazekasgy@37 349 rValue = defValue;
fazekasgy@37 350 } else Py_DECREF(pyValue);
fazekasgy@37 351 }
fazekasgy@37 352 }
fazekasgy@37 353 if (m_debugFlag) cerr << FLAG_VALUE << endl;
fazekasgy@37 354 return rValue;
fazekasgy@37 355 }
fazekasgy@37 356
fazekasgy@37 357
fazekasgy@37 358 void
fazekasgy@37 359 PyPlugin::setProcessType()
fazekasgy@37 360 {
fazekasgy@37 361 //quering process implementation type
fazekasgy@37 362 char legacyMethod[]="process";
fazekasgy@37 363 char numpyMethod[]="processN";
fazekasgy@51 364 m_processFailure = false;
fazekasgy@37 365
fazekasgy@37 366 if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
fazekasgy@37 367 m_processType == 0)
fazekasgy@37 368 {
fazekasgy@37 369 m_processType = legacyProcess;
fazekasgy@37 370 m_pyProcess = PyString_FromString(legacyMethod);
fazekasgy@37 371 m_pyProcessCallable = PyObject_GetAttr(m_pyInstance,m_pyProcess);
fazekasgy@37 372 }
fazekasgy@37 373
fazekasgy@37 374 if (PyObject_HasAttrString(m_pyInstance,numpyMethod) &&
fazekasgy@37 375 m_processType == 0)
fazekasgy@37 376 {
fazekasgy@37 377 m_processType = numpy_bufferProcess;
fazekasgy@37 378 m_pyProcess = PyString_FromString(numpyMethod);
fazekasgy@37 379 m_pyProcessCallable = PyObject_GetAttr(m_pyInstance,m_pyProcess);
fazekasgy@37 380 }
fazekasgy@37 381
fazekasgy@37 382 // These flags are optional. If provided, they override the
fazekasgy@37 383 // implementation type making the use of the odd processN()
fazekasgy@37 384 // function redundant.
fazekasgy@37 385 // However, the code above provides backward compatibility.
fazekasgy@37 386
fazekasgy@37 387 if (m_vampyFlags & vf_BUFFER) {
fazekasgy@37 388 m_processType = numpy_bufferProcess;
fazekasgy@37 389 if (m_debugFlag) cerr << "Process using (numpy) buffer interface." << endl;
fazekasgy@37 390 }
fazekasgy@37 391
fazekasgy@37 392 if (m_vampyFlags & vf_ARRAY) {
fazekasgy@37 393 #ifdef HAVE_NUMPY
fazekasgy@51 394 if (m_numpyInstalled) { m_processType = numpy_arrayProcess;
fazekasgy@51 395 if (m_debugFlag)
fazekasgy@51 396 cerr << "Process using numpy array interface." << endl;
fazekasgy@51 397 }
fazekasgy@51 398 else {
fazekasgy@51 399 m_processFailure = true;
fazekasgy@51 400 char method[]="initialise::setProcessType";
fazekasgy@51 401 cerr << PLUGIN_ERROR
fazekasgy@51 402 << "This plugin requests the Numpy array interface by setting "
fazekasgy@51 403 << " the vf_ARRAY flag in its __init__() function." << endl
fazekasgy@51 404 << "However, we could not found a version of Numpy compatible with this build of Vampy." << endl
fazekasgy@51 405 << "If you have a numerical library installed that supports the buffer interface, " << endl
fazekasgy@51 406 << "you can request this interface instead by setting the vf_BUFFER flag." << endl;
fazekasgy@51 407 }
fazekasgy@37 408 #else
fazekasgy@51 409 m_processFailure = true;
fazekasgy@51 410 char method[]="initialise::setProcessType";
fazekasgy@51 411 cerr << PLUGIN_ERROR
fazekasgy@51 412 << "Error: This version of vampy was compiled without numpy support, "
fazekasgy@51 413 << "however the vf_ARRAY flag is set for plugin: " << m_class << endl
fazekasgy@51 414 << "The default behaviour is: passing a python list of samples for each channel in process() "
fazekasgy@51 415 << "or a list of memory buffers in processN(). " << endl
fazekasgy@51 416 << "This can be used create numpy arrays using the numpy.frombuffer() command." << endl;
fazekasgy@37 417 #endif
fazekasgy@37 418 }
fazekasgy@37 419
fazekasgy@51 420 if (!m_pyProcessCallable)
fazekasgy@37 421 {
fazekasgy@37 422 m_processType = not_implemented;
fazekasgy@37 423 m_pyProcess = NULL;
fazekasgy@37 424 char method[]="initialise::setProcessType";
fazekasgy@37 425 cerr << PLUGIN_ERROR << " No process implementation found. Plugin will do nothing." << endl;
fazekasgy@51 426 m_processFailure = true;
fazekasgy@37 427 }
fazekasgy@37 428 }
fazekasgy@37 429
fazekasgy@37 430 void
Chris@66 431 PyPlugin::typeErrorHandler(const char *method, bool process) const
fazekasgy@37 432 {
fazekasgy@37 433 bool strict = false;
fazekasgy@37 434 while (m_ti.error) {
fazekasgy@37 435 PyTypeInterface::ValueError e = m_ti.getError();
fazekasgy@51 436 #ifdef HAVE_NUMPY
fazekasgy@51 437 // disable the process completely if numpy types are returned
fazekasgy@51 438 // but a compatible version was not loaded.
fazekasgy@51 439 // This is required because if an object is returned from
fazekasgy@51 440 // the wrong build, malloc complains about its size
fazekasgy@51 441 // (i.e. the interpreter doesn't free it properly)
fazekasgy@51 442 // and the process may be leaking.
fazekasgy@51 443 // Note: this only happens in the obscure situation when
fazekasgy@51 444 // someone forces to return wrong numpy types from an
fazekasgy@51 445 // incompatible version using the buffer interface.
fazekasgy@51 446 // In this case the incampatible library is still usable,
fazekasgy@51 447 // but manual conversion to python builtins is required.
fazekasgy@51 448 // If the ARRAY interface is set but Numpy is not installed
fazekasgy@51 449 // the process will be disabled already at initialisation.
fazekasgy@51 450 if (process && !m_numpyInstalled && e.str().find("numpy")!=std::string::npos)
fazekasgy@51 451 {
fazekasgy@51 452 m_processFailure = true;
fazekasgy@51 453 cerr << "Warning: incompatible numpy type encountered. Disabling process." << endl;
fazekasgy@51 454 }
fazekasgy@51 455 #endif
fazekasgy@37 456 cerr << PLUGIN_ERROR << e.str() << endl;
fazekasgy@37 457 if (e.strict) strict = true;
fazekasgy@37 458 // e.print();
fazekasgy@37 459 }
fazekasgy@37 460 /// quit on hard errors like accessing NULL pointers or strict type conversion
fazekasgy@37 461 /// errors IF the user sets the quitOnErrorFlag in the plugin.
fazekasgy@37 462 /// Otherwise most errors will go unnoticed apart from
fazekasgy@37 463 /// a messages in the terminal.
fazekasgy@37 464 /// It would be best if hosts could catch an exception instead
fazekasgy@37 465 /// and display something meaningful to the user.
fazekasgy@37 466 if (strict && m_quitOnErrorFlag) exit(EXIT_FAILURE);
fazekasgy@51 467
fazekasgy@51 468 // this would disable all outputs even if some are valid
fazekasgy@51 469 // if (process) m_processFailure = true;
fazekasgy@51 470
fazekasgy@37 471 }
fazekasgy@37 472