Skip to content

Commit

Permalink
Add ADS observers for each python scope. Refs #4219
Browse files Browse the repository at this point in the history
  • Loading branch information
martyngigg committed Jan 6, 2012
1 parent 72a0fda commit c0006de
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 143 deletions.
132 changes: 131 additions & 1 deletion Code/Mantid/MantidPlot/src/PythonScript.cpp
Expand Up @@ -70,7 +70,8 @@ namespace
PythonScript::PythonScript(PythonScripting *env, const QString &code, QObject *context,
const QString &name, bool interactive, bool reportProgress)
: Script(env, code, context, name, interactive, reportProgress), PyCode(NULL), localDict(NULL),
stdoutSave(NULL), stderrSave(NULL), isFunction(false), m_isInitialized(false)
stdoutSave(NULL), stderrSave(NULL), isFunction(false), m_isInitialized(false),
m_workspaceHandles()
{
ROOT_CODE_OBJECT = NULL;
CURRENT_SCRIPT_OBJECT = this;
Expand All @@ -80,13 +81,27 @@ PythonScript::PythonScript(PythonScripting *env, const QString &code, QObject *c
localDict = PyDict_Copy(PyModule_GetDict(pymodule));
setQObject(Context, "self");
updatePath(Name, true);

// Observe ADS updates
if( interactive )
{
observeAdd();
observeAfterReplace();
observePostDelete();
observeADSClear();
}
}

/**
* Destructor
*/
PythonScript::~PythonScript()
{
observeAdd(false);
observeAfterReplace(false);
observePostDelete(false);
observeADSClear(false);

this->disconnect();
updatePath(Name, false);
Py_XDECREF(PyCode);
Expand Down Expand Up @@ -645,3 +660,118 @@ void PythonScript::endStdoutRedirect()
PyDict_SetItemString(env()->sysDict(), "stderr", stderrSave);
Py_XDECREF(stderrSave);
}

/**
* Listen to add notifications from the ADS and add a Python variable of the workspace name
* to the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScript::addHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws)
{
addPythonReference(wsName, ws);
}

/**
* Listen to add/replace notifications from the ADS and add a Python variable of the workspace name
* to the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScript::afterReplaceHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws)
{
addPythonReference(wsName, ws);
}

/**
* Removes a Python variable of the workspace name from the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScript::postDeleteHandle(const std::string& wsName)
{
deletePythonReference(wsName);
}

/**
* Clear all workspace handle references
*/
void PythonScript::clearADSHandle()
{
std::set<std::string>::const_iterator iend = m_workspaceHandles.end();
for( std::set<std::string>::const_iterator itr = m_workspaceHandles.begin(); itr != iend; )
{
// This also erases the element from current set. The standard says that erase only invalidates
// iterators of erased elements so we need to increment the iterator and get back the previous value
// i.e. the postfix operator
this->deletePythonReference(*(itr++));
}

assert(m_workspaceHandles.empty());
}


/**
* Add a Python variable of the workspace name
* to the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScript::addPythonReference(const std::string& wsName,const Mantid::API::Workspace_sptr ws)
{
UNUSED_ARG(ws);

// Compile a code object
const size_t length = wsName.length() * 2 + 10;
char * code = new char[length + 1];
const char * name = wsName.c_str();
sprintf(code, "%s = mtd['%s']", name, name);
GILHolder gil;
PyObject *codeObj = Py_CompileString(code, "PythonScript::addPythonReference", Py_file_input);
if( codeObj )
{
PyObject *ret = PyEval_EvalCode((PyCodeObject*)codeObj,localDict, localDict);
Py_XDECREF(ret);
}
if( PyErr_Occurred() )
{
PyErr_Clear();
}
else
{
// Keep track of it
m_workspaceHandles.insert(m_workspaceHandles.end(), wsName);
}
Py_XDECREF(codeObj);
delete [] code;
}


/**
* Delete a Python reference to the given workspace name
* @param wsName The name of the workspace
*/
void PythonScript::deletePythonReference(const std::string& wsName)
{
const size_t length = wsName.length() + 4;
char * code = new char[length + 1];
sprintf(code, "del %s", wsName.c_str());
GILHolder gil;
PyObject *codeObj = Py_CompileString(code, "PythonScript::deleteHandle", Py_file_input);
if( codeObj )
{
PyObject *ret = PyEval_EvalCode((PyCodeObject*)codeObj,localDict, localDict);
Py_XDECREF(ret);
}
if( PyErr_Occurred() )
{
PyErr_Clear();
}
else
{
m_workspaceHandles.erase(wsName);
}
Py_XDECREF(codeObj);
delete [] code;

}
20 changes: 18 additions & 2 deletions Code/Mantid/MantidPlot/src/PythonScript.h
Expand Up @@ -31,6 +31,7 @@

#include "PythonSystemHeader.h"
#include "Script.h"
#include "MantidQtAPI/WorkspaceObserver.h"

class QObject;
class QString;
Expand All @@ -40,13 +41,13 @@ class PythonScripting;
/**
* This class holds, compiles and executes the Python code.
*/
class PythonScript : public Script
class PythonScript : public Script, MantidQt::API::WorkspaceObserver
{
Q_OBJECT
public:
/// Constructor
PythonScript(PythonScripting *env, const QString &code, QObject *context = 0,
const QString &name="<input>", bool interactive = true, bool reportProgress = false);
const QString &name="<input>", bool interactive = false, bool reportProgress = false);
///Destructor
~PythonScript();
/// A function to connect to the ouput stream of the running Python code
Expand Down Expand Up @@ -83,6 +84,19 @@ public slots:
void setContext(QObject *context);

private:
/// Listen to add notifications from the ADS
void addHandle(const std::string& wsName, const Mantid::API::Workspace_sptr ws);
/// Listen to add/replace notifications from the ADS
void afterReplaceHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws);
/// Listen to delete notifications
void postDeleteHandle(const std::string& wsName);
/// Listen to ADS clear notifications
void clearADSHandle();
/// Add/update a Python reference to the given workspace
void addPythonReference(const std::string& wsName,const Mantid::API::Workspace_sptr ws);
/// Delete a Python reference to the given workspace name
void deletePythonReference(const std::string& wsName);

// Append or remove a path from the Python sys.path
void updatePath(const QString & filename, bool append = true);
/// Perform a call to the Python eval function with the necessary wrapping
Expand All @@ -99,6 +113,8 @@ public slots:
bool isFunction;
QString fileName;
bool m_isInitialized;
/// Set of current python variables that point to worksapce handles
std::set<std::string> m_workspaceHandles;
};

#endif
124 changes: 1 addition & 123 deletions Code/Mantid/MantidPlot/src/PythonScripting.cpp
Expand Up @@ -71,7 +71,7 @@ ScriptingEnv *PythonScripting::constructor(ApplicationWindow *parent)
/** Constructor */
PythonScripting::PythonScripting(ApplicationWindow *parent)
: ScriptingEnv(parent, langName), m_globals(NULL), m_math(NULL),
m_sys(NULL), refresh_allowed(0), m_workspaceHandles()
m_sys(NULL), refresh_allowed(0)
{
// MG (Russell actually found this for OS X): We ship SIP and PyQt4 with Mantid and we need to
// ensure that the internal import that sip does of PyQt picks up the correct version.
Expand All @@ -96,11 +96,6 @@ PythonScripting::PythonScripting(ApplicationWindow *parent)
setenv(envname, value.c_str(), 1);
#endif

// Observe ADS updates
//observeAdd();
//observeAfterReplace();
//observeDelete();
//observeADSClear();
}

PythonScripting::~PythonScripting()
Expand Down Expand Up @@ -392,120 +387,3 @@ bool PythonScripting::loadInitFile(const QString & filename)

return success;
}

/**
* Listen to add notifications from the ADS and add a Python variable of the workspace name
* to the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScripting::addHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws)
{
addPythonReference(wsName, ws);
}

/**
* Listen to add/replace notifications from the ADS and add a Python variable of the workspace name
* to the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScripting::afterReplaceHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws)
{
addPythonReference(wsName, ws);
}

/**
* Removes a Python variable of the workspace name from the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScripting::deleteHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws)
{
UNUSED_ARG(ws);
deletePythonReference(wsName);
}

/**
* Clear all workspace handle references
*/
void PythonScripting::clearADSHandle()
{
std::set<std::string>::const_iterator iend = m_workspaceHandles.end();
for( std::set<std::string>::const_iterator itr = m_workspaceHandles.begin(); itr != iend; )
{
// This also erases the element from current set. The standard says that erase only invalidates
// iterators of erased elements so we need to increment the iterator and get back the previous value
// i.e. the postfix operator
this->deletePythonReference(*(itr++));
}

assert(m_workspaceHandles.empty());
}


/**
* Add a Python variable of the workspace name
* to the current scope
* @param wsName The name of the workspace
* @param ws The ws ptr (unused)
*/
void PythonScripting::addPythonReference(const std::string& wsName,const Mantid::API::Workspace_sptr ws)
{
UNUSED_ARG(ws);

// Compile a code object
const size_t length = wsName.length() * 2 + 10;
char * code = new char[length + 1];
const char * name = wsName.c_str();
sprintf(code, "%s = mtd['%s']", name, name);
GILHolder gil;
PyObject *codeObj = Py_CompileString(code, "PythonScripting::addPythonReference", Py_file_input);
if( codeObj )
{
PyObject *ret = PyEval_EvalCode((PyCodeObject*)codeObj,globalDict(), globalDict());
Py_XDECREF(ret);
}
if( PyErr_Occurred() )
{
PyErr_Clear();
}
else
{
// Keep track of it
m_workspaceHandles.insert(m_workspaceHandles.end(), wsName);
}
Py_XDECREF(codeObj);
delete [] code;
}


/**
* Delete a Python reference to the given workspace name
* @param wsName The name of the workspace
*/
void PythonScripting::deletePythonReference(const std::string& wsName)
{
const size_t length = wsName.length() + 4;
char * code = new char[length + 1];
sprintf(code, "del %s", wsName.c_str());
GILHolder gil;
PyObject *codeObj = Py_CompileString(code, "PythonScripting::deleteHandle", Py_file_input);
if( codeObj )
{
PyObject *ret = PyEval_EvalCode((PyCodeObject*)codeObj,globalDict(), globalDict());
Py_XDECREF(ret);
}
if( PyErr_Occurred() )
{
PyErr_Clear();
}
else
{
m_workspaceHandles.erase(wsName);
}
Py_XDECREF(codeObj);
delete [] code;

}

18 changes: 1 addition & 17 deletions Code/Mantid/MantidPlot/src/PythonScripting.h
Expand Up @@ -31,16 +31,14 @@

#include "PythonScript.h"
#include "ScriptingEnv.h"
#include "MantidQtAPI/WorkspaceObserver.h"
#include <set>

class QObject;
class QString;

/**
* A scripting environment for executing Python code.
*/
class PythonScripting: public ScriptingEnv, MantidQt::API::WorkspaceObserver
class PythonScripting: public ScriptingEnv
{

Q_OBJECT
Expand Down Expand Up @@ -108,18 +106,6 @@ public slots:
void shutdown();
/// Run execfile on a given file
bool loadInitFile(const QString &path);
/// Listen to add notifications from the ADS
void addHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws);
/// Listen to add/replace notifications from the ADS
void afterReplaceHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws);
/// Listen to delete notifications
void deleteHandle(const std::string& wsName,const Mantid::API::Workspace_sptr ws);
/// Listen to ADS clear notifications
void clearADSHandle();
/// Add/update a Python reference to the given workspace
void addPythonReference(const std::string& wsName,const Mantid::API::Workspace_sptr ws);
/// Delete a Python reference to the given workspace name
void deletePythonReference(const std::string& wsName);

private:
/// The global dictionary
Expand All @@ -130,8 +116,6 @@ public slots:
PyObject *m_sys;
/// Refresh protection
int refresh_allowed;
/// Set of current python variables that point to worksapce handles
std::set<std::string> m_workspaceHandles;
};

//-----------------------------------------------------------------------------
Expand Down

0 comments on commit c0006de

Please sign in to comment.