Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAPI/ScriptBuilder.h"
#include "MantidAPI/AlgorithmFactory.h"
#include "MantidAPI/AlgorithmHistory.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/IAlgorithm.h"
#include "MantidKernel/DateAndTime.h"
#include "MantidKernel/Logger.h"
#include "MantidKernel/Property.h"
#include "MantidKernel/PropertyHistory.h"
namespace Mantid {
namespace API {
using Mantid::Kernel::PropertyHistory_const_sptr;
using Mantid::Kernel::PropertyHistory_sptr;
namespace {
Mantid::Kernel::Logger g_log("ScriptBuilder");
const std::string COMMENT_ALG = "Comment";
ScriptBuilder::ScriptBuilder(boost::shared_ptr<HistoryView> view,
std::string versionSpecificity,
bool appendTimestamp)
: m_historyItems(view->getAlgorithmsList()), m_output(),
m_versionSpecificity(versionSpecificity),
m_timestampCommands(appendTimestamp) {}
/**
* Build a python script for each algorithm included in the history view.
*
* @return a formatted python string of the history
*/
const std::string ScriptBuilder::build() {
auto iter = m_historyItems.begin();
for (; iter != m_historyItems.end(); ++iter) {
writeHistoryToStream(os, iter);
}
return os.str();
}
/**
* Write out an algorithm to the script.
*
* If the entry is unrolled this will recurse and output the children of
* that entry instead. If not, it will just output the algorithm to the stream.
*
* @param os :: output string stream to append algorithms to.
* @param iter :: reference to the iterator pointing to the vector of history
*items
* @param depth :: count of how far we've recursed into the history
void ScriptBuilder::writeHistoryToStream(
std::ostringstream &os, std::vector<HistoryItem>::const_iterator &iter,
int depth) {
auto algHistory = iter->getAlgorithmHistory();
os << std::string(depth, '#');
os << " Child algorithms of " << algHistory->name() << "\n";
// don't create a line for the algorithm, just output its children
buildChildren(os, iter, depth + 1);
os << std::string(depth, '#');
os << " End of child algorithms of " << algHistory->name() << "\n";
if (boost::next(iter) == m_historyItems.end() ||
!boost::next(iter)->isUnrolled()) {
if (m_timestampCommands) {
os << " # " << algHistory->executionDate().toISO8601String();
}
} else {
// create the string for this algorithm
os << buildAlgorithmString(algHistory);
if (m_timestampCommands) {
os << " # " << algHistory->executionDate().toISO8601String();
}
os << "\n";
/**
* Iterate over each of the items children and output them to the script.
*
* This moves the iterator forward over each of the child records and writes
*them to
* the stream.
*
* @param os :: output string stream to append algorithms to.
* @param iter :: reference to the iterator pointing to the vector of history
*items
* @param depth :: count of how far we've recursed into the history
void ScriptBuilder::buildChildren(
std::ostringstream &os, std::vector<HistoryItem>::const_iterator &iter,
int depth) {
size_t numChildren = iter->numberOfChildren();
++iter; // move to first child
for (size_t i = 0; i < numChildren && iter != m_historyItems.end();
++i, ++iter) {
writeHistoryToStream(os, iter, depth);
* Build the script output for a single comment
*
* @param algHistory :: pointer to an algorithm history object
* @returns std::string to run this algorithm
*/
const std::string
ScriptBuilder::buildCommentString(AlgorithmHistory_const_sptr algHistory) {
std::ostringstream comment;
const std::string name = algHistory->name();
auto props = algHistory->getProperties();
for (auto &prop : props) {
if (prop->name() == "Note") {
comment << "# " << prop->value();
}
}
}
return comment.str();
}
* Build the script output for a single algorithm
*
* @param algHistory :: pointer to an algorithm history object
* @returns std::string to run this algorithm
*/
const std::string
ScriptBuilder::buildAlgorithmString(AlgorithmHistory_const_sptr algHistory) {
std::ostringstream properties;
const std::string name = algHistory->name();
if (name == COMMENT_ALG)
return buildCommentString(algHistory);
auto props = algHistory->getProperties();
try {
// create a fresh version of the algorithm - unmanaged
IAlgorithm_sptr algFresh = AlgorithmManager::Instance().createUnmanaged(
name, algHistory->version());
algFresh->initialize();
const auto &propsFresh = algFresh->getProperties();
// just get the names out of the fresh alg properties
std::set<std::string> freshPropNames;
freshPropNames.insert(propFresh->name());
}
// remove output properties that are not present on a fresh algorithm
// i.e. remove dynamically added properties
for (auto prop_iter = props.begin(); prop_iter != props.end();) {
if (freshPropNames.find((*prop_iter)->name()) == freshPropNames.end() &&
(*prop_iter)->direction() == Kernel::Direction::Output) {
prop_iter = props.erase(prop_iter);
} else {
++prop_iter;
}
}
} catch (std::exception &) {
g_log.error() << "Could not create a fresh version of " << name
<< " version " << algHistory->version() << "\n";
}
for (auto &propIter : props) {
prop = buildPropertyString(propIter);
properties << prop << ", ";
// Three cases, we can either specify the version of every algorithm...
if (m_versionSpecificity == "all") {
properties << "Version=" << algHistory->version() << ", ";
} else if (m_versionSpecificity == "old") {
//...or only specify algorithm versions when they're not the newest version
bool oldVersion = false;
std::vector<AlgorithmDescriptor> descriptors =
AlgorithmFactory::Instance().getDescriptors();
for (auto &descriptor : descriptors) {
// If a newer version of this algorithm exists, then this must be an old
// version.
if (descriptor.name == algHistory->name() &&
descriptor.version > algHistory->version()) {
oldVersion = true;
break;
}
}
properties << "Version=" << algHistory->version() << ", ";
}
}
// Third case is we never specify the version, so do nothing.
std::string propStr = properties.str();
if (propStr.length() > 0) {
// remove trailing comma & space
propStr.erase(propStr.size() - 1);
propStr.erase(propStr.size() - 1);
return name + "(" + propStr + ")";
/**
* Build the script output for a single property
*
* @param propHistory :: reference to a property history object
* @returns std::string for this property
*/
const std::string
ScriptBuilder::buildPropertyString(PropertyHistory_const_sptr propHistory) {
using Mantid::Kernel::Direction;
// Create a vector of all non workspace property type names
std::vector<std::string> nonWorkspaceTypes{"number", "boolean", "string"};
// No need to specify value for default properties
// Do not give values to output properties other than workspace properties
if (find(nonWorkspaceTypes.begin(), nonWorkspaceTypes.end(),
propHistory->type()) != nonWorkspaceTypes.end() &&
propHistory->direction() == Direction::Output) {
g_log.debug() << "Ignoring property " << propHistory->name()
<< " of type " << propHistory->type() << '\n';
} else if (propHistory->type() == "number") {
prop = propHistory->name() + "=" + propHistory->value();
} else if (propHistory->type() == "boolean") {
std::string value = (propHistory->value() == "1" ? "True" : "False");
prop = propHistory->name() + "=" + value;
} else {
std::string opener = "='";
if (propHistory->value().find('\\') != std::string::npos) {
opener = "=r'";
}
prop = propHistory->name() + opener + propHistory->value() + "'";
}
return prop;
}
} // namespace API
} // namespace Mantid