Skip to content

Commit fea68c2

Browse files
authored
Merge pull request #468 from llaniewski/feature/runpython
RunPython
2 parents 4e28d4e + e096d7d commit fea68c2

File tree

2 files changed

+154
-44
lines changed

2 files changed

+154
-44
lines changed

src/Handlers/cbRunR.cpp

+150-42
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
#define rNull Rcpp::NumericVector(0)
66
template <typename T> Rcpp::IntegerVector SingleInteger(T i) { Rcpp::IntegerVector v(1); v[0] = i; return v; }
77

8-
//RInside RunR::R(0,0,true,false,true);
9-
RInside RunR::R(0,0,true,false,true);
10-
118
class rWrapper { // Wrapper for all my R objects
129
public:
1310
Solver * solver;
@@ -613,48 +610,147 @@ void CLB_WriteConsoleEx( const char* message, int len, int oType ){
613610
}
614611
}
615612

616-
#define R_INTERFACE_PTRS
617-
#include <Rinterface.h>
613+
#define R_INTERFACE_PTRS
614+
#include <Rinterface.h>
618615

619-
int RunR::Init() {
620-
Callback::Init();
621-
notice("R: Initializing R environment ...");
622616

623-
R["CLBFunctionCall"] = Rcpp::InternalFunction( &CLBFunctionCall );
624-
R["$.CLB"] = Rcpp::InternalFunction( &CLBDollar );
625-
R["[[.CLB"] = Rcpp::InternalFunction( &CLBDollar );
626-
R["$<-.CLB"] = Rcpp::InternalFunction( &CLBDollarAssign );
627-
R["print.CLB"] = Rcpp::InternalFunction( &CLBPrint );
628-
R["names.CLB"] = Rcpp::InternalFunction( &CLBNames );
629-
R.parseEval("'CLBFunctionWrap' <- function(obj) { function(...) CLBFunctionCall(obj, list(...)); }");
617+
namespace RunR {
618+
RInside& GetR() {
619+
static RInside * Rptr;
620+
if (Rptr == NULL) {
621+
notice("R: Initializing R environment ...");
622+
Rptr = new RInside(0,0,true,false,true);
623+
RInside& R = *Rptr;
624+
625+
R["CLBFunctionCall"] = Rcpp::InternalFunction( &CLBFunctionCall );
626+
R["$.CLB"] = Rcpp::InternalFunction( &CLBDollar );
627+
R["[[.CLB"] = Rcpp::InternalFunction( &CLBDollar );
628+
R["$<-.CLB"] = Rcpp::InternalFunction( &CLBDollarAssign );
629+
R["[[<-.CLB"] = Rcpp::InternalFunction( &CLBDollarAssign );
630+
R["print.CLB"] = Rcpp::InternalFunction( &CLBPrint );
631+
R["names.CLB"] = Rcpp::InternalFunction( &CLBNames );
632+
R.parseEval("'CLBFunctionWrap' <- function(obj) { function(...) CLBFunctionCall(obj, list(...)); }");
633+
ptr_R_WriteConsoleEx = CLB_WriteConsoleEx ;
634+
ptr_R_WriteConsole = NULL;
635+
R_Outputfile = NULL;
636+
R_Consolefile = NULL;
637+
R.parseEval("options(prompt='[ ] R:> ');");
638+
}
639+
return *Rptr;
640+
};
641+
642+
void parseEval(const std::string& source) {
643+
RInside& R = GetR();
644+
R.parseEval(source);
645+
}
646+
647+
int replInit() {
648+
R_ReplDLLinit();
649+
return 0;
650+
}
651+
652+
int replDo() {
653+
return R_ReplDLLdo1();
654+
}
655+
656+
SEXP wrap_solver(Solver* solver, vHandler * hand) {
657+
rWrapper base;
658+
base.solver = solver;
659+
base.hand = hand;
660+
return base.rWrap(new rSolver ());
661+
}
662+
663+
SEXP wrap_handler(Solver* solver, vHandler * hand, const pugi::xml_node& par) {
664+
rWrapper base;
665+
base.solver = solver;
666+
base.hand = hand;
667+
return base.rWrap(new rXMLNode (par));
668+
}
669+
};
630670

631-
rWrapper base;
632-
base.solver = solver;
633-
base.hand = this;
634-
R["Solver"] = base.rWrap(new rSolver ());
671+
namespace RunPython {
672+
bool has_reticulate = false;
673+
bool py_initialised = false;
674+
void initializePy();
635675

636-
ptr_R_WriteConsoleEx = CLB_WriteConsoleEx ;
637-
ptr_R_WriteConsole = NULL;
638-
R_Outputfile = NULL;
639-
R_Consolefile = NULL;
676+
void parseEval(const std::string& source) {
677+
if (! py_initialised) initializePy();
678+
Rcpp::Function py_run_string("py_run_string");
679+
py_run_string(source);
680+
return;
681+
}
682+
683+
void initializePy() {
684+
RInside& R = RunR::GetR();
685+
has_reticulate = R.parseEval("require(reticulate, quietly=TRUE)");
686+
if (!has_reticulate) throw std::string("Tried to call Python, but no reticulate installed");
687+
py_initialised = true;
688+
R.parseEval(
689+
"py_names = function(obj) names(obj) \n"
690+
"py_element = function(obj, name) `[[`(obj,name) \n"
691+
"py_element_assign = function(obj, name, value) `[[<-`(obj,name,value) \n"
692+
"r_to_py.CLB = function(x, convert=FALSE) py$S3(reticulate:::py_capsule(x))\n"
693+
);
694+
parseEval(
695+
"class S3: \n"
696+
" def __init__(self, obj): \n"
697+
" object.__setattr__(self,'obj',obj) \n"
698+
" def print(self): \n"
699+
" return r.print(self.obj) \n"
700+
" def __dir__(self): \n"
701+
" return r.py_names(self.obj) \n"
702+
" def __getattr__(self, index): \n"
703+
" if index.startswith('_'): \n"
704+
" return None \n"
705+
" return r.py_element(self.obj, index) \n"
706+
" def __setattr__(self, index, value): \n"
707+
" return r.py_element_assign(self.obj, index, value) \n"
708+
" def __call__(self): \n"
709+
" raise TypeError('not really callable') \n"
710+
);
711+
R.parseEval(
712+
"py$Solver = r_to_py(Solver)"
713+
);
714+
}
715+
716+
int replRun() {
717+
if (! py_initialised) initializePy();
718+
Rcpp::Function repl_python("repl_python");
719+
repl_python();
720+
return 0;
721+
}
722+
}
640723

641-
R.parseEval("options(prompt='[ ] R:> ');");
724+
int cbRunR::Init() {
725+
Callback::Init();
726+
RInside& R = RunR::GetR();
727+
R["Solver"] = RunR::wrap_solver(solver,this);
642728

729+
python = false;
643730
interactive = false;
644731
echo = true;
645732

733+
std::string name = node.name();
734+
if (name == "RunPython") python = true;
646735
pugi::xml_attribute attr;
647736
attr = node.attribute("interactive");
648737
if (attr) interactive = attr.as_bool();
649738
attr = node.attribute("echo");
650739
if (attr) echo = attr.as_bool();
651740

741+
s_tag++;
742+
tag = s_tag;
743+
652744
source = "";
653-
for (pugi::xml_node par = node.first_child(); par; par = par.next_sibling()) {
745+
for (pugi::xml_node par = node.first_child(); par; par = par.next_sibling()) {
654746
if (par.type() == pugi::node_element) {
747+
if (python) {
748+
ERROR("Code-embedded xml nodes not supported for python");
749+
return -1;
750+
}
655751
char nd_name[20];
656752
sprintf(nd_name, "xml_%0zx", par.hash_value());
657-
R[nd_name] = base.rWrap(new rXMLNode (par));
753+
R[nd_name] = RunR::wrap_handler(solver,this,par);
658754

659755
source = source + nd_name + "()\n";
660756
output("element\n");
@@ -668,27 +764,28 @@ int RunR::Init() {
668764
output("Unknown\n");
669765
}
670766
}
671-
// output("----- RunR -----\n");
672-
// output("%s\n",source.c_str());
673-
// output("----------------\n");
674-
767+
if (echo) {
768+
output("-----[ %9s code %03d ]-----\n", node.name(), tag);
769+
output("%s\n",source.c_str());
770+
output("--------------------------------\n");
771+
}
675772
return 0;
676773
}
677774

775+
int cbRunR::s_tag = 0;
678776

679-
int RunR::DoIt() {
777+
int cbRunR::DoIt() {
680778
try {
681779
if (source != "") {
682-
solver->print("Running R ...");
683-
if (echo) {
684-
output("----- RunR -----\n");
685-
output("%s\n",source.c_str());
686-
output("----------------\n");
780+
output("%8d it Executing %s code %03d\n", solver->iter, node.name(), tag);
781+
if (python) {
782+
RunPython::parseEval(source);
783+
} else {
784+
RunR::parseEval(source);
687785
}
688-
R.parseEval(source);
689786
}
690787
if (!interactive) {
691-
if (echo) NOTICE("You can run interactive R session with Ctrl+X");
788+
if (echo) NOTICE("You can run interactive %s session with Ctrl+X", node.name());
692789
int c = kbhit();
693790
if (c == 24) {
694791
int a = getchar();
@@ -698,10 +795,21 @@ int RunR::DoIt() {
698795
}
699796
}
700797
if (interactive) {
701-
R_ReplDLLinit();
702-
while( R_ReplDLLdo1() > 0 ) {}
798+
if (python) {
799+
RunPython::replRun();
800+
} else {
801+
RunR::replInit();
802+
while( RunR::replDo() > 0 ) {}
803+
}
703804
}
805+
} catch (Rcpp::exception& ex) {
806+
ERROR("Caught Rcpp exception");
807+
return -1;
808+
} catch(std::exception &ex) {
809+
ERROR("Caught std exception: %s", ex.what());
810+
return -1;
704811
} catch (...) {
812+
ERROR("Caught uknown exception");
705813
return -1;
706814
}
707815
return 0;
@@ -713,9 +821,9 @@ int RunR::DoIt() {
713821
// Function created only to check to create Handler for specific conditions
714822
vHandler * Ask_For_RunR(const pugi::xml_node& node) {
715823
std::string name = node.name();
716-
if (name == "RunR") {
824+
if (name == "RunR" || name == "RunPython") {
717825
#ifdef WITH_R
718-
return new RunR;
826+
return new cbRunR;
719827
#else
720828
ERROR("No R support. configure with --enable-rinside\n");
721829
exit(-1);

src/Handlers/cbRunR.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222

2323
#ifdef WITH_R
2424

25-
class RunR : public Callback {
25+
class cbRunR : public Callback {
2626
std::string source;
2727
bool interactive;
2828
bool echo;
29+
bool python;
30+
static int s_tag;
31+
int tag;
2932
public:
30-
static RInside R;
3133
int Init ();
3234
int DoIt ();
3335
};

0 commit comments

Comments
 (0)