JobParametersProxy.cxx
Exceptions.cxx
MonoPyJob.cxx
+ PyStudyJob.cxx
)
SET(ydefx_HEADERS
TMonoPyJob.hxx
Job.hxx
Launcher.hxx
+ PyStudyJob.hxx
+ TPyStudyJob.hxx
)
SET(ydefx_LINK
#define YDEFX_LAUNCHER_H
#include "TMonoPyJob.hxx"
+#include "TPyStudyJob.hxx"
namespace ydefx
{
Sample<Ts...>& sample,
const JobParametersProxy& params);
+ template <class ...Ts>
+ Job* submitPyStudyJob(py2cpp::PyPtr& pyStudyObj,
+ const PyStudyFunction& fnScript,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params);
+
/*!
* Connect to an already created job.
* Return nullptr in case of failure. Check the error with lastError().
return result;
}
+template <class ...Ts>
+Job* Launcher::submitPyStudyJob(py2cpp::PyPtr& pyStudyObj,
+ const PyStudyFunction& fnScript,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params)
+{
+ Job* result = nullptr;
+ _lastError = "";
+ try
+ {
+ result = new TPyStudyJob<Ts...>(pyStudyObj, fnScript, sample, params);
+ }
+ catch(std::exception& e)
+ {
+ if(result != nullptr)
+ delete result;
+ result = nullptr;
+ _lastError = e.what();
+ return result;
+ }
+
+ if(!result->lastError().empty())
+ {
+ _lastError = result->lastError();
+ delete result;
+ result = nullptr;
+ return result;
+ }
+
+ if(!result->launch())
+ {
+ _lastError = "Failed to submit job.\n";
+ _lastError += result->lastError();
+ delete result;
+ result = nullptr;
+ }
+ return result;
+}
+
template <class ...Ts>
Job* Launcher::connectJob(const std::string& jobDump,
Sample<Ts...>& sample)
--- /dev/null
+// Copyright (C) 2019 EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#include "PyStudyJob.hxx"
+#include <py2cpp/py2cpp.hxx>
+
+namespace ydefx
+{
+PyStudyJob::PyStudyJob()
+: _pyStudy()
+, _lastError()
+, _waitDelay(10)
+{
+ py2cpp::PyFunction objConstructor;
+ objConstructor.loadExp("pydefx", "PyStudy");
+ _pyStudy = objConstructor();
+}
+
+PyStudyJob::PyStudyJob(const std::string& pymodule_name, const std::string& pyclass_name)
+: _pyStudy()
+, _lastError()
+, _waitDelay(10)
+{
+ py2cpp::PyFunction objConstructor;
+ objConstructor.loadExp(pymodule_name, pyclass_name);
+ _pyStudy = objConstructor();
+}
+
+PyStudyJob::PyStudyJob(py2cpp::PyPtr& pyStudyObj)
+: _pyStudy(pyStudyObj)
+, _lastError()
+, _waitDelay(10)
+{
+}
+
+PyStudyJob::~PyStudyJob()
+{
+}
+
+std::string PyStudyJob::state()
+{
+ std::string result;
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "getJobState");
+ py2cpp::pyResult(result) = pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while retrieving job's state.\n";
+ _lastError += e.what();
+ }
+ return result;
+}
+
+double PyStudyJob::progress()
+{
+ double result;
+ py2cpp::PyFunction pyFn;
+ _lastError = "";
+ try
+ {
+ pyFn.loadExp(_pyStudy, "getProgress");
+ py2cpp::pyResult(result) = pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while retrieving job's progress.\n";
+ _lastError += e.what();
+ }
+ return result;
+}
+
+std::string PyStudyJob::dump()
+{
+ std::string result;
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "dump");
+ py2cpp::pyResult(result) = pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while dumping the job.\n";
+ _lastError += e.what();
+ }
+ return result;
+}
+
+bool PyStudyJob::launch()
+{
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "launch");
+ pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while launching the job.\n";
+ _lastError += e.what();
+ }
+ return _lastError.empty();
+}
+
+const std::string& PyStudyJob::lastError()
+{
+ return _lastError;
+}
+
+bool PyStudyJob::wait()
+{
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "wait");
+ pyFn(_waitDelay);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while waiting the end of the job.\n";
+ _lastError += e.what();
+ }
+ return _lastError.empty();
+}
+
+void PyStudyJob::configureWaitDelay(int seconds)
+{
+ _waitDelay = seconds;
+}
+
+}
--- /dev/null
+// Copyright (C) 2019 EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#ifndef YDEFX_PYSTUDYJOB_HXX
+#define YDEFX_PYSTUDYJOB_HXX
+#include "Job.hxx"
+#include <py2cpp/PyPtr.hxx>
+
+namespace ydefx
+{
+class PyStudyJob : public Job
+{
+public:
+ PyStudyJob(const std::string& pymodule_name, const std::string& pyclass_name);
+ PyStudyJob(py2cpp::PyPtr& pyStudyObj);
+ PyStudyJob();
+ virtual ~PyStudyJob();
+ virtual std::string state();
+ virtual double progress();
+ virtual std::string dump();
+ virtual bool launch(); // return false when it fails
+ virtual bool fetch()=0; // return false when it fails
+ virtual const std::string& lastError();
+ virtual bool wait(); // Wait for the end of the job. Return false when it fails.
+ virtual void configureWaitDelay(int seconds);
+protected:
+ py2cpp::PyPtr _pyStudy;
+ std::string _lastError;
+ int _waitDelay;
+};
+
+}
+
+#endif //YDEFX_PYSTUDYJOB_HXX
--- /dev/null
+// Copyright (C) 2019 EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#ifndef YDEFX_TPYSTUDYJOB_HXX
+#define YDEFX_TPYSTUDYJOB_HXX
+#include "JobParametersProxy.hxx"
+#include "PyStudyJob.hxx"
+#include "SamplePyConversions.hxx"
+#include "PyStudyFunction.hxx"
+
+namespace ydefx
+{
+template <class ...Ts>
+class TPyStudyJob : public PyStudyJob
+{
+public:
+ //! Create a new job using the default pystudy class.
+ TPyStudyJob(const PyStudyFunction& fnScript,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params)
+ : PyStudyJob()
+ , _sample(sample)
+ {
+ createNewJob(fnScript, params);
+ /*if(_lastError.empty()) // no errors during parent construction
+ {
+ try
+ {
+ py2cpp::PyPtr pySample = createPySample(sample);
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "createNewJob");
+ pyFn(fnScript, pySample, params);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while creating the job.\n";
+ _lastError += e.what();
+ }
+ }*/
+ }
+
+ TPyStudyJob(py2cpp::PyPtr& pyStudyObj,
+ const PyStudyFunction& fnScript,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params)
+ : PyStudyJob(pyStudyObj)
+ , _sample(sample)
+ {
+ createNewJob(fnScript, params);
+ }
+
+ //! Connect to an existing job.
+ TPyStudyJob(const std::string& jobDump, Sample<Ts...>& sample)
+ : PyStudyJob()
+ , _sample(sample)
+ {
+ if(_lastError.empty()) // no errors during parent construction
+ {
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "loadFromString");
+ pyFn(jobDump);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while creating the job.\n";
+ _lastError += e.what();
+ }
+ }
+ }
+
+ virtual ~TPyStudyJob(){}
+ virtual bool fetch()
+ {
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "getResult");
+ pyFn(); // python call: _pyStudy.getResult()
+ fetchResults(_pyStudy.getAttr("sample"), _sample);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while fetching the results.\n";
+ _lastError += e.what();
+ }
+ return _lastError.empty();
+ }
+
+ const Sample<Ts...>& getSample()const{return _sample;}
+
+private:
+ void createNewJob(const PyStudyFunction& fnScript, const JobParametersProxy& params)
+ {
+ if(_lastError.empty()) // no errors during parent construction
+ {
+ try
+ {
+ py2cpp::PyPtr pySample = createPySample(_sample);
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "createNewJob");
+ pyFn(fnScript, pySample, params);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while creating the job.\n";
+ _lastError += e.what();
+ }
+ }
+ }
+
+private:
+ Sample<Ts...>& _sample;
+};
+
+}
+
+#endif //YDEFX_TPYSTUDYJOB_HXX
--- /dev/null
+// Copyright (C) 2019 EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TextTestProgressListener.h>
+#include <cppunit/BriefTestProgressListener.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/TestRunner.h>
+#include <cppunit/TextTestRunner.h>
+#include <stdexcept>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <Python.h>
+
+// ============================================================================
+/*!
+ * Main program source for Unit Tests with cppunit package does not depend
+ * on actual tests, so we use the same for all partial unit tests.
+ * This version of TestMain initializes the python library and it can be used
+ * if you have several tests which need Py_Initialize and salome_init.
+ */
+// ============================================================================
+
+int main(int argc, char* argv[])
+{
+ Py_Initialize();
+ // --- Create the event manager and test controller
+ CPPUNIT_NS::TestResult controller;
+
+ // --- Add a listener that collects test result
+ CPPUNIT_NS::TestResultCollector result;
+ controller.addListener( &result );
+
+ // --- Add a listener that print dots as test run.
+#ifdef WIN32
+ CPPUNIT_NS::TextTestProgressListener progress;
+#else
+ CPPUNIT_NS::BriefTestProgressListener progress;
+#endif
+ controller.addListener( &progress );
+
+ // --- Get the top level suite from the registry
+
+ CPPUNIT_NS::Test *suite =
+ CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest();
+
+ // --- Adds the test to the list of test to run
+
+ CPPUNIT_NS::TestRunner runner;
+ runner.addTest( suite );
+ runner.run( controller);
+
+ // --- Print test in a compiler compatible format.
+ std::ofstream testFile;
+ testFile.open("test.log", std::ios::out | std::ios::app);
+ testFile << "------ Idefix test log:" << std::endl;
+ CPPUNIT_NS::CompilerOutputter outputter( &result, testFile );
+ outputter.write();
+
+ // --- Run the tests.
+
+ bool wasSucessful = result.wasSuccessful();
+ testFile.close();
+ Py_Finalize();
+
+ // --- Return error code 1 if the one of test failed.
+
+ return wasSucessful ? 0 : 1;
+}
void SampleTest::fullStudy()
{
- Py_Initialize();
- {
std::list<std::string> resources = ydefx::JobParametersProxy::AvailableResources();
CPPUNIT_ASSERT(resources.size() > 0);
jobParams.configureResource("localhost");
jobParams.work_directory(jobParams.work_directory() + "/GeneralTest");
jobParams.createResultDirectory("/tmp");
- std::string pyScript =
+ std::string pyScript =
"def _exec(a, b):\n"
" d = a / b\n"
" t = ['object which needs pickel protocol']\n"
myJob = l.submitMonoPyJob(wrongStudy, sample, jobParams);
CPPUNIT_ASSERT(myJob == nullptr);
CPPUNIT_ASSERT(l.lastError().find("SyntaxError") != std::string::npos);
- }
- Py_Finalize();
+}
+
+void SampleTest::genericStudy()
+{
+ std::list<std::string> resources = ydefx::JobParametersProxy::AvailableResources();
+ CPPUNIT_ASSERT(resources.size() > 0);
+
+ ydefx::JobParametersProxy jobParams;
+ jobParams.configureResource("localhost");
+ jobParams.work_directory(jobParams.work_directory() + "/GenericTest");
+ jobParams.createResultDirectory("/tmp");
+ std::string pyScript =
+"def _exec(a, b):\n"
+" d = a / b\n"
+" t = ['object which needs pickel protocol']\n"
+" return d,t\n";
+
+ ydefx::PyStudyFunction studyFunction;
+ studyFunction.loadString(pyScript);
+ CPPUNIT_ASSERT(studyFunction.isValid());
+ const std::list<std::string>& inputs = studyFunction.inputNames();
+ CPPUNIT_ASSERT(std::find(inputs.begin(), inputs.end(), "a")!=inputs.end());
+ CPPUNIT_ASSERT(std::find(inputs.begin(), inputs.end(), "b")!=inputs.end());
+ const std::list<std::string>& outputs = studyFunction.outputNames();
+ CPPUNIT_ASSERT(std::find(outputs.begin(), outputs.end(), "d")
+ != outputs.end());
+ CPPUNIT_ASSERT(std::find(outputs.begin(), outputs.end(), "t")
+ != outputs.end());
+
+ ydefx::Sample<double, py2cpp::PyPtr > sample;
+ std::vector<double> a_vals = {1.1, 4.4, 9, 4};
+ std::vector<double> b_vals = {1.1, 2.2, 3, 1};
+ sample.inputs<double>().set("a", a_vals);
+ sample.inputs<double>().set("b", b_vals);
+ sample.outputs<double>().addName("d");
+ sample.outputs<py2cpp::PyPtr >().addName("t");
+
+ py2cpp::PyFunction objConstructor;
+ objConstructor.loadExp("pydefx", "PyStudy");
+ py2cpp::PyPtr pyStudy = objConstructor();
+
+ ydefx::Launcher l;
+ ydefx::Job* myJob = l.submitPyStudyJob(pyStudy, studyFunction, sample, jobParams);
+ CPPUNIT_ASSERT(myJob);
+ CPPUNIT_ASSERT(l.lastError().empty());
+ std::string jobDump = myJob->dump();
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ std::string jobState = myJob->state();
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ CPPUNIT_ASSERT(jobState == "QUEUED" || jobState == "RUNNING"
+ || jobState == "FINISHED");
+ double progress = myJob->progress();
+ CPPUNIT_ASSERT(progress >= 0.0 && progress <= 1.0 );
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ bool ok = myJob->wait();
+ CPPUNIT_ASSERT(ok);
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ jobState = myJob->state();
+ CPPUNIT_ASSERT(jobState == "FINISHED");
+ progress = myJob->progress();
+ CPPUNIT_ASSERT(progress == 1.0);
+ ok = myJob->fetch();
+ CPPUNIT_ASSERT(ok);
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ std::vector<double> expectedResult = {1,2,3,4};
+ const std::vector<double>& result = sample.outputs<double>().get("d");
+ CPPUNIT_ASSERT(expectedResult == result);
+ const std::vector<py2cpp::PyPtr>& pyobjResult
+ = sample.outputs<py2cpp::PyPtr>().get("t");
+ for(const py2cpp::PyPtr& obj : pyobjResult)
+ CPPUNIT_ASSERT(obj.repr() == "['object which needs pickel protocol']");
+ delete myJob;
+
+ // test a case of error
+ std::string wrongScript = "wrong 'script";
+ ydefx::PyStudyFunction wrongStudy;
+ wrongStudy.loadString(wrongScript);
+ CPPUNIT_ASSERT(!wrongStudy.isValid());
+ myJob = l.submitPyStudyJob(pyStudy, wrongStudy, sample, jobParams);
+ CPPUNIT_ASSERT(myJob == nullptr);
+ CPPUNIT_ASSERT(l.lastError().find("SyntaxError") != std::string::npos);
}
CPPUNIT_TEST_SUITE_REGISTRATION( SampleTest );
-#include "TestMain.cxx"
+#include "PyTestMain.cxx"
{
CPPUNIT_TEST_SUITE(SampleTest);
CPPUNIT_TEST(fullStudy);
+ CPPUNIT_TEST(genericStudy);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void cleanUp();
void fullStudy();
+ void genericStudy();
};
#endif // YDEFX_SAMPLETEST_HXX
import time
import traceback
+pydefx.forceNoSalomeServers()
class Context:
def __init__(self):
self.launcher = pydefx.salome_proxy.getLauncher() # getLauncher()