Mantid
Loading...
Searching...
No Matches
ScriptBuilder.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
17#include "MantidKernel/Logger.h"
21
22#include <boost/algorithm/string/classification.hpp>
23#include <boost/range/algorithm/remove_if.hpp>
24#include <boost/utility.hpp>
25#include <set>
26#include <utility>
27
28namespace Mantid::API {
29
32
33namespace {
34Mantid::Kernel::Logger g_log("ScriptBuilder");
35}
36
37const std::string COMMENT_ALG = "Comment";
38
39ScriptBuilder::ScriptBuilder(const std::shared_ptr<HistoryView> &view, std::string versionSpecificity,
40 bool appendTimestamp, std::vector<std::string> ignoreTheseAlgs,
41 std::vector<std::vector<std::string>> ignoreTheseAlgProperties, bool appendExecCount)
42 : m_historyItems(view->getAlgorithmsList()), m_output(), m_versionSpecificity(std::move(versionSpecificity)),
43 m_timestampCommands(appendTimestamp), m_algsToIgnore(std::move(ignoreTheseAlgs)),
44 m_propertiesToIgnore(std::move(ignoreTheseAlgProperties)), m_execCount(appendExecCount) {}
45
51const std::string ScriptBuilder::build() {
52 std::ostringstream os;
53 os << "from mantid.simpleapi import *\n\n";
54 auto iter = m_historyItems.begin();
55 for (; iter != m_historyItems.end(); ++iter) {
56 writeHistoryToStream(os, iter);
57 }
58 return os.str();
59}
60
72void ScriptBuilder::writeHistoryToStream(std::ostringstream &os, std::vector<HistoryItem>::const_iterator &iter,
73 int depth) {
74 auto algHistory = iter->getAlgorithmHistory();
75 if (iter->isUnrolled()) {
76 os << "\n";
77 os << std::string(depth, '#');
78 os << " Child algorithms of " << algHistory->name() << "\n";
79
80 // don't create a line for the algorithm, just output its children
81 buildChildren(os, iter, depth + 1);
82
83 os << std::string(depth, '#');
84 os << " End of child algorithms of " << algHistory->name() << "\n";
85
86 if (boost::next(iter) == m_historyItems.end() || !boost::next(iter)->isUnrolled()) {
87
89 os << " # " << algHistory->executionDate().toISO8601String();
90 }
91
92 os << "\n";
93 }
94 } else {
95 // create the string for this algorithm if not found to be in the ignore
96 // list
97 if (!(std::find(m_algsToIgnore.begin(), m_algsToIgnore.end(), algHistory->name()) != m_algsToIgnore.end())) {
98 createStringForAlg(os, algHistory);
99 }
100 }
101}
102
103void ScriptBuilder::createStringForAlg(std::ostringstream &os,
104 std::shared_ptr<const Mantid::API::AlgorithmHistory> &algHistory) {
105 os << buildAlgorithmString(*algHistory);
107 os << " # " << algHistory->executionDate().toISO8601String();
108 }
109
110 if (m_execCount) {
112 os << " execCount: " << algHistory->execCount();
113 } else {
114 os << " # execCount: " << algHistory->execCount();
115 }
116 }
117
118 os << "\n";
119}
120
133void ScriptBuilder::buildChildren(std::ostringstream &os, std::vector<HistoryItem>::const_iterator &iter, int depth) {
134 size_t numChildren = iter->numberOfChildren();
135 ++iter; // move to first child
136 for (size_t i = 0; i < numChildren && iter != m_historyItems.end(); ++i, ++iter) {
137 writeHistoryToStream(os, iter, depth);
138 }
139 --iter;
140}
141
148const std::string ScriptBuilder::buildCommentString(const AlgorithmHistory &algHistory) {
149 std::ostringstream comment;
150 const std::string name = algHistory.name();
151 if (name == COMMENT_ALG) {
152 auto props = algHistory.getProperties();
153 for (auto &prop : props) {
154 if (prop->name() == "Text") {
155 comment << "# " << prop->value();
156 }
157 }
158 }
159 return comment.str();
160}
161
168const std::string ScriptBuilder::buildAlgorithmString(const AlgorithmHistory &algHistory) {
169 std::ostringstream properties;
170 const std::string name = algHistory.name();
171
172 if (name == COMMENT_ALG)
173 return buildCommentString(algHistory);
174
175 auto props = algHistory.getProperties();
176
177 try {
179 // create a fresh version of the algorithm - unmanaged
180 if (name == "Load") {
181 int version = std::stoi(algHistory.getPropertyValue("LoaderVersion"));
182 algFresh = AlgorithmManager::Instance().createUnmanaged(algHistory.getPropertyValue("LoaderName"), version);
183 } else {
184 algFresh = AlgorithmManager::Instance().createUnmanaged(name, algHistory.version());
185 }
186 algFresh->initialize();
187
188 const auto &propsFresh = algFresh->getProperties();
189 // just get the names out of the fresh alg properties
190 std::set<std::string> freshPropNames;
191 for (const auto &propFresh : propsFresh) {
192 freshPropNames.insert(propFresh->name());
193 }
194
195 // remove output properties that are not present on a fresh algorithm
196 // i.e. remove dynamically added properties
197 for (auto prop_iter = props.begin(); prop_iter != props.end();) {
198 if (freshPropNames.find((*prop_iter)->name()) == freshPropNames.end() &&
199 (*prop_iter)->direction() == Kernel::Direction::Output) {
200 prop_iter = props.erase(prop_iter);
201 } else {
202 ++prop_iter;
203 }
204 }
205
206 } catch (std::exception &) {
207 g_log.error() << "Could not create a fresh version of " << name << " version " << algHistory.version() << "\n";
208 }
209
210 const bool storeInADS = algHistory.getStoreInADS();
211
212 for (const auto &propIter : props) {
213 if (!storeInADS && propIter->name() == "OutputWorkspace") {
214 continue;
215 }
216 std::string prop = buildPropertyString(*propIter, name);
217 if (prop.length() > 0) {
218 properties << prop << ", ";
219 }
220 }
221
222 // Three cases, we can either specify the version of every algorithm...
223 if (m_versionSpecificity == "all") {
224 properties << "Version=" << algHistory.version() << ", ";
225 } else if (m_versionSpecificity == "old") {
226 //...or only specify algorithm versions when they're not the newest version
227 const auto &algName = algHistory.name();
228 auto &algFactory = API::AlgorithmFactory::Instance();
229 int latestVersion = 0;
230
231 if (algFactory.exists(algName)) { // Check the alg still exists in Mantid
232 latestVersion = AlgorithmFactory::Instance().highestVersion(algName);
233 }
234 // If a newer version of this algorithm exists, then this must be an old
235 // version.
236 if (latestVersion > algHistory.version()) {
237 properties << "Version=" << algHistory.version() << ", ";
238 }
239 }
240 // Third case is we never specify the version, so do nothing.
241
242 std::string assignmentStatement("");
243 if (!storeInADS) {
244 properties << "StoreInADS=False, ";
245 const auto it =
246 std::find_if(props.cbegin(), props.cend(), [](const auto &prop) { return prop->name() == "OutputWorkspace"; });
247 if (it != props.cend()) {
248 assignmentStatement = (*it)->value() + " = ";
249 }
250 }
251
252 std::string propStr = properties.str();
253 if (propStr.length() > 0) {
254 // remove trailing comma & space
255 propStr.erase(propStr.size() - 1);
256 propStr.erase(propStr.size() - 1);
257 }
258
259 std::string historyEntry = assignmentStatement + name + "(" + propStr + ")";
260 historyEntry.erase(boost::remove_if(historyEntry, boost::is_any_of("\n\r")), historyEntry.end());
261 return historyEntry;
262}
263
264GNU_DIAG_OFF("maybe-uninitialized")
265
266
273const std::string ScriptBuilder::buildPropertyString(const Mantid::Kernel::PropertyHistory &propHistory,
274 const std::string &algName) {
276
277 // If the property is to be ignored then return with an empty string
278 if (std::find_if(m_propertiesToIgnore.begin(), m_propertiesToIgnore.end(),
279 [&propHistory, algName](std::vector<std::string> const &c) -> bool {
280 return algName == c[0] && propHistory.name() == c[1];
281 }) != m_propertiesToIgnore.end()) {
282 return "";
283 }
284
285 std::string prop;
286 // No need to specify value for default properties
287 if (!propHistory.isDefault()) {
288 // Create a vector of all non workspace property type names
289 std::vector<std::string> nonWorkspaceTypes{"number", "boolean", "string"};
290 // Do not give values to output properties other than workspace properties
291 if (find(nonWorkspaceTypes.begin(), nonWorkspaceTypes.end(), propHistory.type()) != nonWorkspaceTypes.end() &&
292 propHistory.direction() == Direction::Output) {
293 // If algs are to be ignored (Common use case is project recovery) ignore
294 if (m_algsToIgnore.size() == 0) {
295 g_log.debug() << "Ignoring property " << propHistory.name() << " of type " << propHistory.type() << '\n';
296 }
297 // Handle numerical properties
298 } else if (propHistory.type() == "number") {
299 prop = propHistory.name() + "=" + propHistory.value();
300 // Handle boolean properties
301 } else if (propHistory.type() == "boolean") {
302 std::string value = (propHistory.value() == "1" ? "True" : "False");
303 prop = propHistory.name() + "=" + value;
304 // Handle all other property types
305 } else {
306 std::string opener = "='";
307 std::string closer = "'";
308 if (propHistory.value().find('\\') != std::string::npos) {
309 opener = "=r'";
310 } else if (propHistory.pythonVariable()) {
311 opener = "=";
312 closer = "";
313 }
314
315 prop = propHistory.name() + opener + propHistory.value() + closer;
316 }
317 }
318
319 return prop;
320}
321
322GNU_DIAG_ON("maybe-uninitialized")
323
324} // namespace Mantid::API
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
#define GNU_DIAG_ON(x)
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
This class stores information about the Command History used by algorithms on a workspace.
const bool & getStoreInADS() const
get storeInADS
const std::string & getPropertyValue(const std::string &name) const
get the string representation of a specified property
const std::string & name() const
get name of algorithm in history const
const int & version() const
get version number of algorithm in history const
const Mantid::Kernel::PropertyHistories & getProperties() const
get parameter list of algorithm in history const
This class build a sttring which cana be executed as a python script.
void createStringForAlg(std::ostringstream &os, std::shared_ptr< const Mantid::API::AlgorithmHistory > &algHistory)
const std::string buildCommentString(const AlgorithmHistory &algHistory)
Build the script output for a single comment.
void writeHistoryToStream(std::ostringstream &os, std::vector< HistoryItem >::const_iterator &iter, int depth=1)
Write out an algorithm to the script.
std::vector< std::string > m_algsToIgnore
const std::vector< HistoryItem > m_historyItems
ScriptBuilder(const std::shared_ptr< HistoryView > &view, std::string versionSpecificity="old", bool appendTimestamp=false, std::vector< std::string > ignoreTheseAlgs={}, std::vector< std::vector< std::string > > ignoreTheseAlgProperties={}, bool appendExecCount=false)
void buildChildren(std::ostringstream &os, std::vector< HistoryItem >::const_iterator &iter, int depth=1)
Iterate over each of the items children and output them to the script.
const std::string buildAlgorithmString(const AlgorithmHistory &algHistory)
Build the script output for a single algorithm.
const std::string buildPropertyString(const Mantid::Kernel::PropertyHistory &propHistory, const std::string &algName)
Build the script output for a single property.
const std::string build()
build a python script from the history view
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
This class stores information about the parameters used by an algorithm.
Kernel::Logger g_log("ExperimentInfo")
static logger object
const std::string COMMENT_ALG
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
std::shared_ptr< const PropertyHistory > PropertyHistory_const_sptr
std::shared_ptr< PropertyHistory > PropertyHistory_sptr
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Output
An output workspace.
Definition Property.h:54