PyStudyFunction is now full python.
IF(EXISTS ${CONFIGURATION_ROOT_DIR})
LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake")
INCLUDE(SalomeMacros)
+ INCLUDE(SalomeSetupPlatform)
ELSE()
MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !"
)
ENDIF()
-SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to Salome KERNEL")
-IF( EXISTS ${KERNEL_ROOT_DIR} )
- LIST(APPEND CMAKE_MODULE_PATH "${KERNEL_ROOT_DIR}/salome_adm/cmake_files")
-ELSE()
- MESSAGE(FATAL_ERROR "We absolutely need Salome KERNEL, please define KERNEL_ROOT_DIR")
-ENDIF()
-FIND_PACKAGE(SalomeKERNEL REQUIRED)
-ADD_DEFINITIONS(${KERNEL_DEFINITIONS} )
-INCLUDE_DIRECTORIES(${KERNEL_INCLUDE_DIRS})
-
-SET(YACS_ROOT_DIR $ENV{YACS_ROOT_DIR} CACHE PATH "Path to Salome YACS")
-IF( EXISTS ${YACS_ROOT_DIR} )
- LIST(APPEND CMAKE_MODULE_PATH "${YACS_ROOT_DIR}/salome_adm/cmake_files")
-ELSE()
- MESSAGE(FATAL_ERROR "We absolutely need Salome YACS, please define YACS_ROOT_DIR")
-ENDIF()
-FIND_PACKAGE(SalomeYACS REQUIRED)
-ADD_DEFINITIONS(${YACS_DEFINITIONS})
-INCLUDE_DIRECTORIES(${YACS_INCLUDE_DIRS})
+FIND_PACKAGE(SalomePythonInterp REQUIRED)
+FIND_PACKAGE(SalomePythonLibs REQUIRED)
SET(PY2CPP_ROOT_DIR $ENV{PY2CPP_ROOT_DIR} CACHE PATH "Path to py2cpp")
IF( EXISTS ${PY2CPP_ROOT_DIR} )
#
# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
#
-ADD_DEFINITIONS(${YACS_DEFINITIONS})
-INCLUDE_DIRECTORIES(${YACS_INCLUDE_DIRS})
+
+INCLUDE_DIRECTORIES(
+ ${PYTHON_INCLUDE_DIR}
+)
+
+ADD_DEFINITIONS(
+ ${PYTHON_DEFINITIONS}
+)
SET(ydefx_SOURCES
PyStudyFunction.cxx
)
SET(ydefx_LINK
- py2yacslib
py2cpp
+ ${PYTHON_LIBRARIES}
)
ADD_LIBRARY(ydefx ${ydefx_SOURCES})
//
#ifndef YDEFX_JOBPARAMETERSPROXY_H
#define YDEFX_JOBPARAMETERSPROXY_H
-#include <py2cpp/PyPtr.hxx>
#include <string>
#include <list>
#include <map>
-
-namespace ydefx
-{
-class JobParametersProxy;
-}
-namespace py2cpp
-{
-PyObject * toPy(const ydefx::JobParametersProxy& jp);
-}
-
-#include <py2cpp/py2cpp.hxx>
+#include "PyConversions.hxx"
namespace ydefx
{
#include "PyStudyFunction.hxx"
#include <fstream>
#include <sstream>
-#include <py2yacs.hxx>
+#include <py2cpp/py2cpp.hxx>
+
+PyObject * py2cpp::toPy(const ydefx::PyStudyFunction& studyFn)
+{
+ PyObject * result = studyFn._pyObject.get();
+ Py_IncRef(result);
+ return result;
+}
namespace ydefx
{
PyStudyFunction::PyStudyFunction()
-: _content()
-, _input()
-, _output()
-, _errors()
+: _pyObject(nullptr)
{
- _errors.push_back("Function \"_exec\" not found!");
+ py2cpp::PyFunction objConstructor;
+ objConstructor.loadExp("pydefx", "PyScript");
+ _pyObject = objConstructor();
}
PyStudyFunction::~PyStudyFunction(){}
void PyStudyFunction::loadFile(const std::string& path)
{
- std::ifstream infile(path.c_str());
- std::stringstream buffer;
- buffer << infile.rdbuf();
- loadString(buffer.str());
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyObject, "loadFile");
+ pyFn(path);
}
void PyStudyFunction::loadString(const std::string& value)
{
- _content = value;
- _input.clear();
- _output.clear();
- _errors.clear();
- // TODO: use py2yacs
- Py2yacs p2y;
- p2y.load(value);
- if(p2y.getGlobalErrors().size() == 0)
- {
- const std::list<FunctionProperties>& fn_prop = p2y.getFunctionProperties();
- std::list<FunctionProperties>::const_iterator prop_it = fn_prop.begin();
- while(prop_it != fn_prop.end() && prop_it->_name != "_exec")
- ++ prop_it;
- if(prop_it != fn_prop.end() && prop_it->_errors.empty())
- {
- for(const std::string& name: prop_it->_input_ports)
- _input.push_back(name);
- for(const std::string& name: prop_it->_output_ports)
- _output.push_back(name);
- }
- }
- // TODO: deal with the errors
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyObject, "loadString");
+ pyFn(value);
}
void PyStudyFunction::save(const std::string& path)
{
- std::ofstream outfile(path.c_str());
- outfile << _content;
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyObject, "saveFile");
+ pyFn(path);
+}
+
+std::string PyStudyFunction::content()const
+{
+ std::string result;
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyObject, "content");
+ py2cpp::pyResult(result) = pyFn();
+ return result;
+}
+
+std::list<std::string> PyStudyFunction::inputNames()const
+{
+ std::list<std::string> result;
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyObject, "getInputNames");
+ py2cpp::pyResult(result) = pyFn();
+ return result;
}
-const std::string& PyStudyFunction::content()const
+std::list<std::string> PyStudyFunction::outputNames()const
{
- return _content;
+ std::list<std::string> result;
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyObject, "getOutputNames");
+ py2cpp::pyResult(result) = pyFn();
+ return result;
}
-const std::list<std::string>& PyStudyFunction::inputNames()const
+std::string PyStudyFunction::errors()const
{
- return _input;
+ std::string result;
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyObject, "getErrors");
+ py2cpp::pyResult(result) = pyFn();
+ return result;
}
-const std::list<std::string>& PyStudyFunction::outputNames()const
+bool PyStudyFunction::isValid()const
{
- return _output;
+ std::string err = errors();
+ return err.empty();
}
-const std::list<std::string>& PyStudyFunction::errors()const
+std::list<std::string> PyStudyFunction::datafiles()const
{
- return _errors;
+ return std::list<std::string>();
}
}
#ifndef YDEFX_PYSTUDYFUNCTION_H
#define YDEFX_PYSTUDYFUNCTION_H
#include "StudyFunction.hxx"
+#include "PyConversions.hxx"
+
namespace ydefx
{
class PyStudyFunction : StudyFunction
virtual void loadFile(const std::string& path);
virtual void loadString(const std::string&);
virtual void save(const std::string& path);
- virtual const std::string& content()const;
- virtual const std::list<std::string>& inputNames()const;
- virtual const std::list<std::string>& outputNames()const;
- virtual const std::list<std::string>& errors()const;
+ virtual std::string content()const;
+ virtual std::list<std::string> inputNames()const;
+ virtual std::list<std::string> outputNames()const;
+ virtual std::string errors()const;
+ virtual bool isValid()const;
+ virtual std::list<std::string> datafiles()const;
+ friend PyObject * py2cpp::toPy(const PyStudyFunction& jp);
private:
- std::string _content;
- std::list<std::string> _input;
- std::list<std::string> _output;
- std::list<std::string> _errors;
+ py2cpp::PyPtr _pyObject;
};
}
#endif // YDEFX_PYSTUDYFUNCTION_H
virtual void loadFile(const std::string& path)=0;
virtual void loadString(const std::string&)=0;
virtual void save(const std::string& path)=0;
- virtual const std::string& content()const=0;
- virtual const std::list<std::string>& inputNames()const=0;
- virtual const std::list<std::string>& outputNames()const=0;
- virtual const std::list<std::string>& errors()const=0;
- std::list<std::string> datafiles;
+ virtual std::string content()const=0;
+ virtual std::list<std::string> inputNames()const=0;
+ virtual std::list<std::string> outputNames()const=0;
+ virtual std::string errors()const=0;
+ virtual std::list<std::string> datafiles()const=0;
+ virtual bool isValid()const=0;
};
}
#endif // YDEFX_STUDYFUNCTION_H
py2cpp::PyPtr pySample = createPySample(sample);
py2cpp::PyFunction pyFn;
pyFn.loadExp(_pyStudy, "createNewJob");
- pyFn(fnScript.content(), pySample, params);
+ pyFn(fnScript, pySample, params);
}
catch(std::exception& e)
{
ydefx::PyStudyFunction studyFunction;
studyFunction.loadString(pyScript);
- CPPUNIT_ASSERT(studyFunction.errors().empty());
+ 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());
!= outputs.end());
ydefx::Sample<double> sample;
- std::vector<double> a_vals = {1.1, 2.2, 3.4, 5.5};
- std::vector<double> b_vals = {2.2, 4.4, 6.8, 11};
+ 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");
ok = myJob->fetch();
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT(myJob->lastError().empty());
- std::vector<double> expectedResult = {0.5, 0.5, 0.5, 0.5};
+ std::vector<double> expectedResult = {1,2,3,4};
const std::vector<double>& result = sample.outputs<double>().get("d");
CPPUNIT_ASSERT(expectedResult == result);
delete myJob;
#include "StudyRestartTest.hxx"
#include "../Launcher.hxx" // possible conflict with KERNEL/Launcher/Launcher.hxx
#include <algorithm>
+#include <thread>
+#include <chrono>
void SampleTest::setUp()
{
{
}
+/*
+ * There are some limitations when you reconnect to a job launched on a resource
+ * which does not have a batch manager. The state of the reconnected job will
+ * always be "ERROR" and it is not possible to know when it is finished.
+ */
void SampleTest::studyTest()
{
Py_Initialize();
delete myJob;
ydefx::Job* restoredJob = l.connectJob(jobDump, sample);
+ // On localhost you cannot completely reconnect the job because there is no
+ // batch manager. The job will be in the state "ERROR" but you can fetch the
+ // results anyway.
CPPUNIT_ASSERT(restoredJob);
CPPUNIT_ASSERT(l.lastError().empty());
+ // This "wait" will end instantly because of the "ERROR" state.
bool ok = restoredJob->wait();
CPPUNIT_ASSERT(ok);
double progress = restoredJob->progress();
- CPPUNIT_ASSERT(progress == 1.0);
+ // We can check the progress in order to know if the job is done, but we
+ // cannot detect if the job finished in error.
+ if(progress < 1.0)
+ std::this_thread::sleep_for(std::chrono::seconds(10));
+ double progress2 = restoredJob->progress();
+ CPPUNIT_ASSERT(progress <= progress2);
ok = restoredJob->fetch();
CPPUNIT_ASSERT(ok);
std::vector<double> expectedResult = {0.5, 0.5, 0.5, 0.5};
#)
SET(CMAKE_AUTOMOC ON)
-INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/cpp)
+INCLUDE_DIRECTORIES(
+ ${PROJECT_SOURCE_DIR}/src/cpp
+ ${PYTHON_INCLUDE_DIR}
+)
+
+ADD_DEFINITIONS(
+ ${PYTHON_DEFINITIONS}
+)
SET(YDEFX_SOURCES
ResourceWidget.cxx
QWidget* parent)
: QScrollArea(parent)
, _model(model)
+, _extraEdit(nullptr)
{
QWidget* mainWidget = new QWidget();
QVBoxLayout *mainLayout = new QVBoxLayout();
QWidget* parent)
: QScrollArea(parent)
, _model(model)
+, _localdirEdit(nullptr)
+, _inputFilesList(nullptr)
+, _removeInputFilesButton(nullptr)
{
QWidget* mainWidget = new QWidget();
QVBoxLayout *mainLayout = new QVBoxLayout();
# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
#
from . import sample
+import py2yacs
class PyScriptException(Exception):
pass
class PyScript:
def __init__(self):
self.script = ""
+ self.properties, self.errors = py2yacs.get_properties(self.script)
def loadFile(self,path):
with open(path, "r") as f:
self.script = f.read()
+ self.properties, self.errors = py2yacs.get_properties(self.script)
def loadString(self, script):
self.script = script
+ self.properties, self.errors = py2yacs.get_properties(self.script)
+
+ def content(self):
+ return self.script
def saveFile(self, path):
with open(path, "w") as f:
print(f.errors) # list of py2yacs errors in the function
print(f.imports) # list of import statements in the function
"""
- import py2yacs
return py2yacs.get_properties(self.script)
- def getFunctionProperties(self, fname):
+ def getFunctionProperties(self, fname = "_exec"):
"""
Properties of the _exec function:
- fn_properties, errors = myscript.getExecProperties("_exec")
+ fn_properties = myscript.getFunctionProperties()
fn_properties.name : "_exec"
fn_properties.inputs : list of input variable names
fn_properties.outputs : list of output variable names
fn_properties.errors : list of py2yacs errors in the function
fn_properties.imports : list of import statements in the function
- errors : list of syntax errors in the script
fn_properties is None if the "_exec" function does not exist.
"""
- functions,errors = self.getAllProperties()
- fn_properties = next((f for f in functions if f.name == fname), None)
- return fn_properties, errors
+ fn_properties = next((f for f in self.properties if f.name == fname), None)
+ return fn_properties
+
+ def getOutputNames(self, fname = "_exec"):
+ errorsText = self.getErrors(fname)
+ if len(errorsText) > 0:
+ raise PyScriptException(errorsText)
+ fnProperties = self.getFunctionProperties(fname)
+ return fnProperties.outputs
+
+ def getInputNames(self, fname = "_exec"):
+ errorsText = self.getErrors(fname)
+ if len(errorsText) > 0:
+ raise PyScriptException(errorsText)
+ fnProperties = self.getFunctionProperties(fname)
+ return fnProperties.inputs
+
+ def getErrors(self, fname = "_exec"):
+ error_string = ""
+ if len(self.errors) > 0:
+ error_string = "global errors:\n"
+ error_string += '\n'.join(errors)
+ else:
+ properties = self.getFunctionProperties(fname)
+ if properties is None:
+ error_string += "Function {} not found in the script!".format(fname)
+ else:
+ error_string += '\n'.join(properties.errors)
+ return error_string
def CreateEmptySample(self):
"""
Create a sample with input and output variable names set.
"""
fn = "_exec"
- fn_properties, errors = self.getFunctionProperties(fn)
+ errors = self.getErrors(fn)
if len(errors) > 0:
- error_string = "global errors:\n"
- error_string += '\n'.join(errors)
- raise PyScriptException(error_string)
- if fn_properties is None:
- raise PyScriptException("Function {} not found!".format(fn))
- if len(fn_properties.errors) > 0:
- error_string = "Errors in function {}:\n".format(fn)
- error_string += '\n'.join(fn_properties.errors)
- raise PyScriptException(error_string)
+ raise PyScriptException(errors)
+ fn_properties = self.getFunctionProperties(fn)
return sample.Sample(fn_properties.inputs, fn_properties.outputs)
-
sample : Sample type
result_directory : path to a result working directory.
nb_branches : int
- script : string
+ script : script / pyscript type
return:
extra_in_files: list of files to add to salome_parameters.in_files
yacs_schema_path: path to the yacs schema (xml file).
if sampleManager is None:
sampleManager = defaultSampleManager()
# export sample to result_directory
- inputFiles = sampleManager.prepareRun(sample, result_directory)
+ inputFiles = sampleManager.prepareRun(script, sample, result_directory)
+
# export nbbranches
configpath = os.path.join(result_directory, "idefixconfig.json")
dicconfig = {}
json.dump(dicconfig, f, indent=2)
studypath = os.path.join(result_directory, "idefixstudy.py")
with open(studypath, "w") as f:
- f.write(script)
+ f.write(script.script)
# find generic schema
filename = inspect.getframeinfo(inspect.currentframe()).filename
install_directory = pathlib.Path(filename).resolve().parent
def createNewJob(self, script, sample, params, sampleManager=None):
"""
Create a new job out of those parameters:
- script : string
+ script : script / pyscript type
sample : sample to be evaluated (Sample class)
params : job submission parameters (Parameters class)
The result directory will contain all the files needed for a launch and a
def __init__(self):
pass
- def prepareRun(self, sample, directory):
+ def prepareRun(self, script, sample, directory):
"""
Create a dump of the sample in the given directory.
+ script: PyScript object.
+ sample: Sample object.
+ directory: path to a local working directory where all the working files are
+ copied. This directory should be already created.
Return a list of files to add to the input files list of the job.
"""
datapath = os.path.join(directory, SampleIterator.DATAFILE)
quoting=csv.QUOTE_NONNUMERIC )
writer.writeheader()
writer.writerows(sample.inputIterator())
-
+
outnamespath = os.path.join(directory, SampleIterator.OUTPUTNAMESFILE)
with open(outnamespath, 'w') as outputfile:
- for v in sample.getOutputNames():
+ for v in script.getOutputNames():
outputfile.write(v+'\n')
filename = inspect.getframeinfo(inspect.currentframe()).filename
install_directory = pathlib.Path(filename).resolve().parent
import pydefx
import os
-myParams = pydefx.Parameters(resource="localhost",nb_branches=2);
-#wd = os.path.join(myParams.salome_parameters.work_directory, "minifixtest")
-#myParams.salome_parameters.local_directory = "/toto/titi/tata"
+myParams = pydefx.Parameters();
+myParams.configureResource("localhost")
+myParams.createResultDirectory("/tmp")
+myParams.nb_branches = 2
myScript = pydefx.PyScript()
myScript.loadFile("scenario_study.py")
"y":[1.0, 2.0, 3.0, 4.0, 5.0],
"z":["a", "b", "c", "d", "e"]})
-myStudy = pydefx.PyStudy(myScript.script, mySample, myParams)
-myStudy.run()
+myStudy = pydefx.PyStudy()
+myStudy.createNewJob(myScript, mySample, myParams)
+myStudy.launch()
wd = os.path.join(myParams.salome_parameters.work_directory, "minifixtest")
myParams.salome_parameters.work_directory = wd
-myStudy.createNewJob(myScript.script, mySample, myParams)
+myStudy.createNewJob(myScript, mySample, myParams)
myStudy.launch()
print(myStudy.getJobState())
mySample.setInputValues(mydata)
myStudy = pydefx.PyStudy()
-myStudy.createNewJob(myScript.script, mySample, myParams)
+myStudy.createNewJob(myScript, mySample, myParams)
print(myStudy.getProgress())
myStudy.launch()
print(myStudy.getJobState())
mySample.setInputValues(mydata)
myStudy = pydefx.PyStudy()
-myStudy.createNewJob(myScript.script, mySample, myParams)
+myStudy.createNewJob(myScript, mySample, myParams)
myStudy.launch()
strdmp= myStudy.dump()