annotate PyPlugin.cpp @ 71:40a01bb24209 vampyhost

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