├── CMakeLists.txt ├── DESCRIPTION ├── NAMESPACE ├── R ├── conversion.R ├── py.R └── utility.R ├── README.Rmd ├── README.md ├── man ├── py.Rd └── pyfun.Rd ├── src ├── Conversion.cpp ├── Conversion.h ├── Makevars ├── PythonInterface.c ├── PythonInterface.h ├── RcppExtension.cpp ├── RcppExtension.h ├── Rython.cpp ├── Rython.h └── redirect.cpp └── tests ├── conversion.tests.R └── pyfun.tests.R /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(Rython) 4 | 5 | find_package(LibR REQUIRED) 6 | set(Python_ADDITIONAL_VERSIONS 2.7) 7 | find_package(PythonLibs REQUIRED) 8 | include_directories(${PYTHON_INCLUDE_DIRS}) 9 | 10 | if(${LIBR_FOUND}) 11 | else() 12 | message(FATAL_ERROR "No R...") 13 | endif() 14 | include_directories(BEFORE ${LIBR_INCLUDE_DIRS}) 15 | 16 | include_directories(BEFORE "/home/wush/R/x86_64-pc-linux-gnu-library/2.15/Rcpp/include") 17 | 18 | add_custom_target(Rython ALL 19 | COMMAND find ${CMAKE_SOURCE_DIR} -name "*.o" -exec rm "{}" "\;" 20 | COMMAND find ${CMAKE_SOURCE_DIR} -name "*.so" -exec rm "{}" "\;" 21 | COMMAND ${LIBR_EXECUTABLE} --vanilla --slave --args /home/wush/R-package-project/Rython < "/home/wush/R/i686-pc-linux-gnu-library/2.15/RCMake/roxygenize/_collatenamespacerd.R" 22 | COMMAND ${LIBR_EXECUTABLE} CMD INSTALL "${CMAKE_SOURCE_DIR}") 23 | 24 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: Rython 2 | Type: Package 3 | Title: What the package does (short line) 4 | Version: 0.2.3 5 | Date: 2013-03-02 6 | Author: Who wrote it 7 | Maintainer: Who to complain to 8 | Description: More about what it does (maybe more than one line) 9 | License: What Licence is it under ? 10 | Depends: 11 | Rcpp (>= 0.10.3) 12 | LinkingTo: Rcpp 13 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | export(import_pkg_module) 2 | export(.Last.lib) 3 | export(py) 4 | export(pyassign) 5 | export(pybool) 6 | export(pycall) 7 | export(pydict) 8 | export(pyfloat) 9 | export(pyfun) 10 | export(pylong) 11 | export(pyobj) 12 | export(pystr) 13 | export(pywrap) 14 | useDynLib(Rython) 15 | -------------------------------------------------------------------------------- /R/conversion.R: -------------------------------------------------------------------------------- 1 | #'@export 2 | pydict <- function(src, is_python_list = FALSE) { 3 | stopifnot(class(src) == "list") 4 | .Call("Rython__pydict", src, is_python_list) 5 | } 6 | 7 | #'@export 8 | pylong <- function(src) { 9 | .Call("Rython__pylong", src) 10 | } 11 | 12 | #'@export 13 | pyfloat <- function(src) { 14 | .Call("Rython__pyfloat", src) 15 | } 16 | 17 | #'@export 18 | pybool <- function(src) { 19 | .Call("Rython__pybool", src) 20 | } 21 | 22 | #'@export 23 | pystr <- function(src) { 24 | .Call("Rython__pystr", src) 25 | } 26 | 27 | #'@export 28 | pyobj <- function(obj_name, module_name = "__main__") { 29 | .Call("Rython__retrieve_pyobj", module_name, obj_name) 30 | } 31 | 32 | #'@export 33 | pycall <- function(py_callable, ...) { 34 | argv <- list(...) 35 | .Call("Rython__call", py_callable, argv); 36 | } 37 | 38 | #'@export 39 | pywrap <- function(src, is_list = TRUE) { 40 | .Call("Rython__wrap", src, is_list); 41 | } -------------------------------------------------------------------------------- /R/py.R: -------------------------------------------------------------------------------- 1 | #'@title Execute python script 2 | #' 3 | #'@param script Python Script 4 | #'@examples 5 | #'library(Rython) 6 | #'py("import sys") 7 | #'py("def test_fun(src):\n print src\n return src\n") # define test_fun in python 8 | #'@export 9 | py <- function(script) { 10 | script <- as.character(script) 11 | for(i in 1:length(script)) { 12 | .Call("Rython__run", script[i]) 13 | } 14 | } 15 | 16 | #'@title Call python function 17 | #' 18 | #'@param fun_name the name of function object in python 19 | #'@param argv A character vector which will be converted to list of string in python and send to the called function 20 | #'@param module the module where the function exists 21 | #'@examples 22 | #'library(Rython) 23 | #'py("def test_fun(src):\n print src\n return src\n") # define test_fun in python 24 | #'pyfun("test_fun", letters) 25 | #'@export 26 | pyfun <- function(fun_name, argv, module = "__main__") { 27 | if (! class(argv) %in% c("character", "list")) stop("invalid type") 28 | .Call("Rython__fun", module, as.character(fun_name)[1], argv) 29 | } 30 | 31 | #'@export 32 | pyassign <- function(Rpy_ptr, name, module = "__main__") { 33 | stopifnot(class(Rpy_ptr) == "externalptr") 34 | .Call("Rython__assign", Rpy_ptr, name, module) 35 | } -------------------------------------------------------------------------------- /R/utility.R: -------------------------------------------------------------------------------- 1 | #'@useDynLib Rython 2 | .onAttach <- function(libname, pkgname) { 3 | .Call("Rython__initialize") 4 | py("import sys") 5 | py("import redirection 6 | class StdoutCatcher: 7 | def write(self, stuff): 8 | redirection.stdoutredirect(stuff) 9 | ") 10 | py("sys.stdout = StdoutCatcher()") 11 | } 12 | 13 | #'@export 14 | .Last.lib <- function(libpath) { 15 | .Call("Rython__finalize") 16 | } 17 | 18 | #'@export 19 | import_pkg_module <- function(pkg_name, module_name) { 20 | path <- normalizePath(system.file("python", package=pkg_name), mustWork=TRUE) 21 | py("import sys") 22 | py(sprintf("sys.path.append('%s')", path)) 23 | py(sprintf("import %s", module_name)) 24 | } -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | # Rython 2 | 3 | Embed python in R 4 | 5 | # Environment 6 | 7 | Ubuntu with python 2.7 8 | 9 | Please install the following ubuntu packages: 10 | 11 | - python-dev 12 | - libboost-python-dev 13 | 14 | # Usage 15 | 16 | ```r 17 | library(Rython) 18 | py("python script") 19 | ``` 20 | 21 | # Type Mapping 22 | 23 | To pass object from *R* to *python*, use the following functions: 24 | 25 | ```{r type-mapping, echo=FALSE, message=FALSE, results='asis'} 26 | library(xtable) 27 | type.mapping <- matrix(dimnames=list(NULL, c("function name", "R type", "python type")), byrow=TRUE, ncol=3, c( 28 | "pydict", "list", "dictionary", 29 | "pylong", "integer", "list of long", 30 | "pyfloat", "numeric", "list of float", 31 | "pybool", "logical", "list of bool", 32 | "pystr", "character", "list of str" 33 | )) 34 | print(xtable(type.mapping), type="html") 35 | ``` 36 | 37 | ## API 38 | 39 | 40 | 41 | # Demo 42 | 43 | ## cql 1.4 44 | 45 | The following script query the Cassandra with python-cql 1.4 and pass the value back to R 46 | 47 | ```r 48 | library(Rython) 49 | py("import cql") 50 | py("con = cql.connect(host, port, key_space, cql_version='3.0.0')") 51 | py("cursor = con.cursor()") 52 | py("cursor.execute('select * from column_family limit 1')") 53 | py("result = cursor.fetchall()") 54 | py("print result") 55 | py("result1 = result[0]") 56 | result1 <- pyobj(obj_name="result1", module_name="") 57 | pywrap(result1) 58 | ``` 59 | 60 | ## Demo for R package with python 61 | 62 | Put your python script under `inst/python` and install it. 63 | 64 | ```r 65 | #'@export 66 | .onLoad <- function(libname, pkgname) { 67 | import_pkg_module(pkgname, "foo.py") 68 | } 69 | ``` 70 | 71 | # NEWS 72 | 73 | - 2013-04-03 74 | - add conversion functions(See `R/conversion.R`) 75 | - add import_pkg_module 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rython 2 | 3 | Embed python in R 4 | 5 | # Environment 6 | 7 | Ubuntu with python 2.7 8 | 9 | Please install the following ubuntu packages: 10 | 11 | - python-dev 12 | - libboost-python-dev 13 | 14 | # Usage 15 | 16 | ```r 17 | library(Rython) 18 | py("python script") 19 | ``` 20 | 21 | # Type Mapping 22 | 23 | To pass object from *R* to *python*, use the following functions: 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
function name R type python type
1 pydict list dictionary
2 pylong integer list of long
3 pyfloat numeric list of float
4 pybool logical list of bool
5 pystr character list of str
35 | 36 | 37 | ## API 38 | 39 | 40 | 41 | # Demo 42 | 43 | ## cql 1.4 44 | 45 | The following script query the Cassandra with python-cql 1.4 and pass the value back to R 46 | 47 | ```r 48 | library(Rython) 49 | py("import cql") 50 | py("con = cql.connect(host, port, key_space, cql_version='3.0.0')") 51 | py("cursor = con.cursor()") 52 | py("cursor.execute('select * from column_family limit 1')") 53 | py("result = cursor.fetchall()") 54 | py("print result") 55 | py("result1 = result[0]") 56 | result1 <- pyobj(obj_name="result1", module_name="") 57 | pywrap(result1) 58 | ``` 59 | 60 | ## Demo for R package with python 61 | 62 | Put your python script under `inst/python` and install it. 63 | 64 | ```r 65 | #'@export 66 | .onLoad <- function(libname, pkgname) { 67 | import_pkg_module(pkgname, "foo.py") 68 | } 69 | ``` 70 | 71 | # NEWS 72 | 73 | - 2013-04-03 74 | - add conversion functions(See `R/conversion.R`) 75 | - add import_pkg_module 76 | -------------------------------------------------------------------------------- /man/py.Rd: -------------------------------------------------------------------------------- 1 | \name{py} 2 | \alias{py} 3 | \title{Execute python script} 4 | \usage{ 5 | py(script) 6 | } 7 | \arguments{ 8 | \item{script}{Python Script} 9 | } 10 | \description{ 11 | Execute python script 12 | } 13 | \examples{ 14 | library(Rython) 15 | py("import sys") 16 | py("def test_fun(src):\\n print src\\n return src\\n") # define test_fun in python 17 | } 18 | 19 | -------------------------------------------------------------------------------- /man/pyfun.Rd: -------------------------------------------------------------------------------- 1 | \name{pyfun} 2 | \alias{pyfun} 3 | \title{Call python function} 4 | \usage{ 5 | pyfun(fun_name, argv, module = "__main__") 6 | } 7 | \arguments{ 8 | \item{fun_name}{the name of function object in python} 9 | 10 | \item{argv}{A character vector which will be converted to 11 | list of string in python and send to the called function} 12 | 13 | \item{module}{the module where the function exists} 14 | } 15 | \description{ 16 | Call python function 17 | } 18 | \examples{ 19 | library(Rython) 20 | py("def test_fun(src):\\n print src\\n return src\\n") # define test_fun in python 21 | pyfun("test_fun", letters) 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/Conversion.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Conversion.h" 3 | #include 4 | 5 | namespace py = boost::python; 6 | 7 | typedef Rcpp::XPtr PyList; 8 | typedef Rcpp::XPtr PyDict; 9 | typedef Rcpp::XPtr PyObj; 10 | typedef std::vector< std::string > StrVec; 11 | 12 | template 13 | py::list Rython__as_py_list(SEXP Rsrc) { 14 | py::list retval; 15 | T_in src(Rsrc); 16 | T_glue glue; 17 | for(int i = 0;i < src.size();i++) { 18 | glue = src[i]; 19 | retval.append(glue); 20 | } 21 | return retval; 22 | } 23 | 24 | template 25 | PyList Rython__as(SEXP Rsrc) { 26 | PyList retval(new py::list(Rython__as_py_list(Rsrc))); 27 | return retval; 28 | } 29 | 30 | void Rython__python_add_auto_type(py::dict& dst, int i, SEXP src, bool is_python_list) { 31 | if (is_python_list) { 32 | switch(TYPEOF(src)) { 33 | case LGLSXP: 34 | dst[i] = Rython__as_py_list(src); 35 | return; 36 | case INTSXP: 37 | dst[i] = Rython__as_py_list(src); 38 | return; 39 | case REALSXP: 40 | dst[i] = Rython__as_py_list(src); 41 | return; 42 | case STRSXP: 43 | dst[i] = Rython__as_py_list(src); 44 | return; 45 | default: 46 | throw std::invalid_argument("invalid type"); 47 | } 48 | } 49 | switch(TYPEOF(src)) { 50 | case LGLSXP: 51 | dst[i] = Rcpp::as(src); 52 | return; 53 | case INTSXP: 54 | dst[i] = Rcpp::as(src); 55 | return; 56 | case REALSXP: 57 | dst[i] = Rcpp::as(src); 58 | return; 59 | case STRSXP: 60 | dst[i] = Rcpp::as(src); 61 | return; 62 | default: 63 | throw std::invalid_argument("invalid type"); 64 | } 65 | } 66 | 67 | void Rython__python_add_auto_type(py::dict& dst, const std::string& i, SEXP src, bool is_python_list) { 68 | switch(TYPEOF(src)) { 69 | case LGLSXP: 70 | dst[i] = Rcpp::as(src); 71 | case INTSXP: 72 | dst[i] = Rcpp::as(src); 73 | case REALSXP: 74 | dst[i] = Rcpp::as(src); 75 | case STRSXP: 76 | dst[i] = Rcpp::as(src); 77 | default: 78 | throw std::invalid_argument("invalid type"); 79 | } 80 | } 81 | 82 | 83 | SEXP Rython__pydict(SEXP Rsrc, SEXP Ris_python_list) { 84 | BEGIN_RCPP 85 | Rcpp::List src(Rsrc); 86 | bool is_python_list(Rcpp::as(Ris_python_list)); 87 | Rcpp::CharacterVector src_name(Rcpp::wrap(src.names())); 88 | std::string name_glue; 89 | PyDict retval(new py::dict); 90 | (*retval)[0] = 1; 91 | (*retval)["test"] = 2; 92 | (*retval)[5] = 3.0; 93 | return retval; 94 | for(int i = 0;i < src.size();i++) { 95 | name_glue.assign(src_name[i]); 96 | if (name_glue.size() == 0) { 97 | Rython__python_add_auto_type(*retval, i, Rcpp::wrap(src[i]), is_python_list); 98 | } 99 | else { 100 | Rython__python_add_auto_type(*retval, name_glue, Rcpp::wrap(src[i]), is_python_list); 101 | } 102 | } 103 | return retval; 104 | END_RCPP 105 | } 106 | 107 | SEXP Rython__pylong(SEXP Rsrc) { 108 | BEGIN_RCPP 109 | return Rcpp::wrap(Rython__as(Rsrc)); 110 | END_RCPP 111 | } 112 | 113 | SEXP Rython__pyfloat(SEXP Rsrc) { 114 | BEGIN_RCPP 115 | return Rcpp::wrap(Rython__as(Rsrc)); 116 | END_RCPP 117 | } 118 | 119 | SEXP Rython__pybool(SEXP Rsrc) { 120 | BEGIN_RCPP 121 | return Rcpp::wrap(Rython__as(Rsrc)); 122 | END_RCPP 123 | } 124 | 125 | SEXP Rython__pystr(SEXP Rsrc) { 126 | BEGIN_RCPP 127 | return Rcpp::wrap(Rython__as(Rsrc)); 128 | END_RCPP 129 | } 130 | 131 | SEXP Rython__retrieve_pyobj(SEXP Rmodule_name, SEXP Robj_name) { 132 | BEGIN_RCPP 133 | try { 134 | std::string 135 | pymodule_name(Rcpp::as(Rmodule_name)), 136 | obj_name(Rcpp::as(Robj_name)); 137 | std::auto_ptr pmodule; 138 | if (pymodule_name.size() > 0) { 139 | pmodule.reset(new py::object((py::handle<>(py::borrowed(PyImport_AddModule(pymodule_name.c_str())))))); 140 | } 141 | else { 142 | pmodule.reset(new py::object(py::handle<>(py::borrowed(PyImport_AddModule("__main__"))))); 143 | } 144 | py::object dictionary = pmodule->attr("__dict__"); 145 | PyObj retval(new py::object(dictionary[obj_name.c_str()])); 146 | return retval; 147 | } 148 | catch (py::error_already_set) { 149 | PyErr_Print(); 150 | } 151 | END_RCPP 152 | } 153 | 154 | SEXP Rython__call(SEXP Rpy_callable, SEXP Rargv) { 155 | BEGIN_RCPP 156 | 157 | try { 158 | PyObj py_callable(Rpy_callable); 159 | Rcpp::List argv(Rargv); 160 | py::list args; 161 | for(int i = 0;i < argv.size();i++) { 162 | PyList argv_element(Rcpp::wrap(argv[i])); 163 | args.append(*argv_element); 164 | } 165 | PyObj retval(new py::object((*py_callable)(*boost::python::tuple(args)))); 166 | return retval; 167 | } 168 | catch (py::error_already_set) { 169 | PyErr_Print(); 170 | } 171 | 172 | END_RCPP 173 | } 174 | 175 | RcppExport SEXP Rython__wrap(SEXP Rsrc, SEXP Ris_list) { 176 | BEGIN_RCPP 177 | try { 178 | bool is_list(Rcpp::as(Ris_list)); 179 | py::list& src(*PyList(Rsrc)); 180 | int n = py::len(*src); 181 | if (n == 0) return R_NilValue; 182 | if (is_list) { 183 | Rcpp::List retval(n); 184 | for(int i = 0;i < n;i++) { 185 | py::object temp = py::extract(src[i]); 186 | if (PyString_Check(temp.ptr())) { 187 | retval[i] = Rcpp::wrap(py::extract(src[i])); 188 | } 189 | else if (temp.ptr() == Py_None) { 190 | retval[i] = R_NilValue; 191 | } 192 | else if (PyBool_Check(temp.ptr())) { 193 | retval[i] = Rcpp::wrap(py::extract(src[i])); 194 | } 195 | else if (PyInt_Check(temp.ptr()) || PyLong_Check(temp.ptr())) { 196 | retval[i] = Rcpp::wrap(py::extract(src[i])); 197 | } 198 | else if (PyFloat_Check(temp.ptr())) { 199 | retval[i] = Rcpp::wrap(py::extract(src[i])); 200 | } 201 | else if (PyUnicode_Check(temp.ptr())) { 202 | retval[i] = Rcpp::wrap(py::extract(src[i])); 203 | } 204 | } // for 205 | return retval; 206 | } 207 | else { // is_list 208 | int j = 0; 209 | py::object first_element = py::extract(src[j]); 210 | if (PyString_Check(first_element.ptr())) { 211 | std::vector retval; 212 | retval.reserve(n); 213 | for(int i = 0;i < n;i++) { 214 | retval.push_back(py::extract(src[i])); 215 | } 216 | return Rcpp::wrap(retval); 217 | } 218 | else if (first_element.ptr() == Py_None) { 219 | return R_NilValue; 220 | } 221 | else if (PyBool_Check(first_element.ptr())) { 222 | Rcpp::LogicalVector retval(n); 223 | for(int i = 0;i < n;i++) { 224 | retval[i] = py::extract(src[i]); 225 | } 226 | return retval; 227 | } 228 | else if (PyInt_Check(first_element.ptr()) || PyLong_Check(first_element.ptr())) { 229 | Rcpp::IntegerVector retval(n); 230 | for(int i = 0;i < n;i++) { 231 | retval[i] = py::extract(src[i]); 232 | } 233 | return retval; 234 | } 235 | else if (PyFloat_Check(first_element.ptr())) { 236 | Rcpp::NumericVector retval(n); 237 | for(int i = 0;i < n;i++) { 238 | retval[i] = py::extract(src[i]); 239 | } 240 | return retval; 241 | } 242 | else if (PyUnicode_Check(first_element.ptr())) { 243 | std::vector< std::wstring > retval; 244 | retval.resize(n); 245 | for(int i = 0;i < n;i++) { 246 | retval.push_back(py::extract(src[i])); 247 | } 248 | return Rcpp::wrap >(retval); 249 | } 250 | } 251 | } 252 | catch (py::error_already_set) { 253 | PyErr_Print(); 254 | } 255 | END_RCPP 256 | } -------------------------------------------------------------------------------- /src/Conversion.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONVERSION_H__ 2 | #define __CONVERSION_H__ 3 | 4 | #include 5 | 6 | #include 7 | 8 | RcppExport SEXP Rython__pydict(SEXP Rsrc, SEXP Ris_python_list); 9 | RcppExport SEXP Rython__pylong(SEXP Rsrc); 10 | RcppExport SEXP Rython__pyfloat(SEXP Rscr); 11 | RcppExport SEXP Rython__pybool(SEXP Rscr); 12 | RcppExport SEXP Rython__pystr(SEXP Rscr); 13 | RcppExport SEXP Rython__retrieve_pyobj(SEXP Rmodule_name, SEXP Rfun_name); 14 | RcppExport SEXP Rython__call(SEXP Rpy_callable, SEXP Rargv); 15 | RcppExport SEXP Rython__wrap(SEXP Rsrc, SEXP Ris_list); 16 | 17 | #endif //__CONVERSION_H__ -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | ## Use the R_HOME indirection to support installations of multiple R version 2 | PKG_LIBS = `$(R_HOME)/bin/Rscript -e "Rcpp:::LdFlags()"` -lboost_python-py27 `python2.7-config --ldflags` 3 | 4 | ## As an alternative, one can also add this code in a file 'configure' 5 | ## 6 | ## PKG_LIBS=`${R_HOME}/bin/Rscript -e "Rcpp:::LdFlags()"` 7 | ## 8 | ## sed -e "s|@PKG_LIBS@|${PKG_LIBS}|" \ 9 | ## src/Makevars.in > src/Makevars 10 | ## 11 | ## which together with the following file 'src/Makevars.in' 12 | ## 13 | ## PKG_LIBS = @PKG_LIBS@ 14 | ## 15 | ## can be used to create src/Makevars dynamically. This scheme is more 16 | ## powerful and can be expanded to also check for and link with other 17 | ## libraries. It should be complemented by a file 'cleanup' 18 | ## 19 | ## rm src/Makevars 20 | ## 21 | ## which removes the autogenerated file src/Makevars. 22 | ## 23 | ## Of course, autoconf can also be used to write configure files. This is 24 | ## done by a number of packages, but recommended only for more advanced users 25 | ## comfortable with autoconf and its related tools. 26 | 27 | PKG_CFLAGS = `python2.7-config --cflags` 28 | PKG_CXXFLAGS = `python2.7-config --cflags` -------------------------------------------------------------------------------- /src/PythonInterface.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "PythonInterface.h" 3 | 4 | void Rython_initialize(void) { 5 | Py_SetProgramName("Rython"); 6 | dlopen("libpython2.7.so", RTLD_LAZY | RTLD_GLOBAL); 7 | Py_Initialize(); 8 | Py_InitModule("redirection", RedirectionMethods); 9 | } 10 | 11 | void Rython_finalize(void) { 12 | Py_Finalize(); 13 | } 14 | -------------------------------------------------------------------------------- /src/PythonInterface.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __PYTHONINTERFACE_H__ 3 | #define __PYTHONINTERFACE_H__ 4 | 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif //__cplusplus 10 | 11 | void Rython_initialize(void); 12 | void Rython_finalize(void); 13 | static PyObject* redirection_stdoutredirect(PyObject* self, PyObject *args); 14 | extern PyMethodDef RedirectionMethods[]; 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif //__cplusplus 19 | 20 | #endif //__PYTHONINTERFACE_H__ 21 | -------------------------------------------------------------------------------- /src/RcppExtension.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "RcppExtension.h" 5 | 6 | namespace py = boost::python; 7 | 8 | using Rcpp::CharacterVector; 9 | using Rcpp::List; 10 | 11 | typedef std::vector StrVec; 12 | 13 | namespace Rython { 14 | 15 | py::list as(const CharacterVector& src) { 16 | std::string glue; 17 | py::list retval; 18 | for(int i = 0;i < src.size();i++) { 19 | glue.assign(CHAR(STRING_ELT(wrap(src), i))); 20 | retval.append(glue); 21 | } 22 | return retval; 23 | } 24 | 25 | py::list as(const List& src) { 26 | py::list retval; 27 | 28 | for(int i = 0;i < src.size();i++) { 29 | CharacterVector element(VECTOR_ELT(wrap(src), i)); 30 | retval.append(as(element)); 31 | } 32 | return(retval); 33 | } 34 | 35 | SEXP wrap(py::list& src) { 36 | std::vector< std::string > glue; 37 | for(int i = 0;i < py::len(src);i++) { 38 | glue.push_back(py::extract(src[i])); 39 | } 40 | return Rcpp::wrap(glue); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/RcppExtension.h: -------------------------------------------------------------------------------- 1 | #ifndef __H_RCPPEXTENSION__ 2 | #define __H_RCPPEXTENSION__ 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace Rython { 9 | 10 | boost::python::list as(const Rcpp::CharacterVector& src); 11 | boost::python::list as(const Rcpp::List& src); 12 | 13 | SEXP wrap(boost::python::list&); 14 | 15 | } 16 | 17 | #endif //__H_RCPPEXTENSION__ 18 | -------------------------------------------------------------------------------- /src/Rython.cpp: -------------------------------------------------------------------------------- 1 | #include "Rython.h" 2 | 3 | namespace py = boost::python; 4 | 5 | SEXP Rython__initialize() { 6 | BEGIN_RCPP 7 | Rython_initialize(); 8 | Rcpp::Rcout << "Initializing Python Interpreter..." << std::endl; 9 | return R_NilValue; 10 | END_RCPP 11 | } 12 | 13 | SEXP Rython__finalize() { 14 | BEGIN_RCPP 15 | Rython_finalize(); 16 | Rcpp::Rcout << "Finalizing Python Interpreter..." << std::endl; 17 | return R_NilValue; 18 | END_RCPP 19 | } 20 | 21 | SEXP Rython__run(SEXP Rpy_script) { 22 | BEGIN_RCPP 23 | std::string py_script(Rcpp::as(Rpy_script)); 24 | if (0 != ::PyRun_SimpleString(py_script.c_str())) { 25 | throw new std::runtime_error(""); 26 | } 27 | END_RCPP 28 | } 29 | 30 | SEXP Rython__fun(SEXP Rpymodule_name, SEXP Rpyfun_name, SEXP Rpyfun_argv) { 31 | BEGIN_RCPP 32 | 33 | try { 34 | const char 35 | *pymodule_name = ::CHAR(::STRING_ELT(Rpymodule_name, 0)), 36 | *pyfun_name = ::CHAR(::STRING_ELT(Rpyfun_name, 0)); 37 | py::object module((py::handle<>(py::borrowed(PyImport_AddModule(pymodule_name))))); 38 | py::object pyfun = module.attr("__dict__")[pyfun_name]; 39 | if (!pyfun.ptr()) { 40 | throw std::invalid_argument("pyfun_name not found in python"); 41 | } 42 | if (!PyCallable_Check(pyfun.ptr())) { 43 | throw std::invalid_argument("pyfun_name is not a callable"); 44 | } 45 | if (Rf_isString(Rpyfun_argv)) { 46 | Rcpp::CharacterVector pyfun_argv(Rpyfun_argv); 47 | py::list argv(Rython::as(pyfun_argv)); 48 | py::list result(pyfun(argv)); 49 | return Rython::wrap(result); 50 | } 51 | if (Rf_isVector(Rpyfun_argv)) { 52 | Rcpp::List pyfun_argv(Rpyfun_argv); 53 | py::list argv(Rython::as(pyfun_argv)); 54 | py::list result(pyfun(argv)); 55 | return Rython::wrap(result); 56 | } 57 | } 58 | catch (py::error_already_set) { 59 | PyErr_Print(); 60 | throw new std::runtime_error(""); 61 | } 62 | 63 | END_RCPP 64 | } 65 | 66 | SEXP Rython__assign(SEXP Rpy_ptr, SEXP Rname, SEXP Rmodule_name) { 67 | BEGIN_RCPP 68 | try { 69 | const char 70 | *pymodule_name = ::CHAR(::STRING_ELT(Rmodule_name, 0)), 71 | *name = ::CHAR(::STRING_ELT(Rname, 0)); 72 | py::object module((py::handle<>(py::borrowed(PyImport_AddModule(pymodule_name))))); 73 | Rcpp::XPtr ppy_obj(Rpy_ptr); 74 | module.attr("__dict__")[name] = *ppy_obj; 75 | } 76 | catch (py::error_already_set) { 77 | PyErr_Print(); 78 | throw new std::runtime_error(""); 79 | } 80 | END_RCPP 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/Rython.h: -------------------------------------------------------------------------------- 1 | #include "RcppExtension.h" 2 | #include "PythonInterface.h" 3 | 4 | RcppExport SEXP Rython__initialize(); 5 | 6 | RcppExport SEXP Rython__finalize(); 7 | 8 | RcppExport SEXP Rython__run(SEXP Rpy_script); 9 | 10 | RcppExport SEXP Rython__fun(SEXP Rpymodule_name, SEXP Rpyfun_name, SEXP Rpyfun_argv); 11 | 12 | RcppExport SEXP Rython__assign(SEXP Rpy_ptr, SEXP Rname, SEXP Rmodule_name); -------------------------------------------------------------------------------- /src/redirect.cpp: -------------------------------------------------------------------------------- 1 | // redirect python stdout to R stdout 2 | 3 | #include "PythonInterface.h" 4 | #include 5 | 6 | static PyObject* redirection_stdoutredirect(PyObject* self, PyObject *args) { 7 | const char* string; 8 | if (!PyArg_ParseTuple(args, "s", &string)) 9 | return NULL; 10 | Rcpp::Rcout << string; 11 | Py_INCREF(Py_None); 12 | return Py_None; 13 | } 14 | 15 | PyMethodDef RedirectionMethods[] = { 16 | {"stdoutredirect", redirection_stdoutredirect, METH_VARARGS, 17 | "stdout redirection helper"}, 18 | {NULL, NULL, 0, NULL} 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /tests/conversion.tests.R: -------------------------------------------------------------------------------- 1 | library(Rython) 2 | 3 | for(i in 1:100) { 4 | a <- 1:10L 5 | stopifnot(class(a) == "integer") 6 | b <- pylong(a) 7 | rm(b) 8 | gc() 9 | } 10 | for(i in 1:100) { 11 | a <- rnorm(10) 12 | stopifnot(class(a) == "numeric") 13 | b <- pyfloat(a) 14 | rm(b) 15 | gc() 16 | } 17 | for(i in 1:100) { 18 | a <- sample(c(TRUE, FALSE), 10, TRUE) 19 | stopifnot(class(a) == "logical") 20 | b <- pybool(a) 21 | rm(b) 22 | gc() 23 | } 24 | for(i in 1:100) { 25 | a <- sample(letters, 10, TRUE) 26 | stopifnot(class(a) == "character") 27 | b <- pystr(a) 28 | rm(b) 29 | gc() 30 | } 31 | 32 | py("import urllib") 33 | urllib.urlencode <- pyobj("urllib", "urlencode") 34 | 35 | py(" 36 | def test_fun(*args): 37 | for arg in args: 38 | print 'another arg:', arg 39 | return arg 40 | ") 41 | 42 | test_fun <- pyobj("", "test_fun") 43 | gc() 44 | temp <- capture.output(temp2 <- pycall(test_fun, pylong(1:10L), pystr(letters))) 45 | stopifnot(length(temp) == 2) 46 | stopifnot(temp[1] == "another arg: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]") 47 | stopifnot(temp[2] == "another arg: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']") 48 | stopifnot(class(temp2) == "externalptr") 49 | 50 | result <- pywrap(temp2) 51 | stopifnot(class(result) == "list") 52 | stopifnot(all.equal(unlist(result), letters)) 53 | result <- pywrap(temp2, FALSE) 54 | stopifnot(all.equal(result, letters)) 55 | 56 | # test pydict 57 | temp <- pydict(list(a=1L, b=2.0, c=letters), TRUE) 58 | pyassign(temp, "temp") 59 | py("print temp") -------------------------------------------------------------------------------- /tests/pyfun.tests.R: -------------------------------------------------------------------------------- 1 | library(Rython) 2 | 3 | script <- ' 4 | def test_Rython1(argv): 5 | print argv 6 | return argv 7 | ' 8 | 9 | py(script) 10 | pyfun("test_Rython1", letters) 11 | 12 | temp <- capture.output({ 13 | stopifnot(all.equal(letters, pyfun("test_Rython1", letters))) 14 | }, file=NULL) 15 | stopifnot(all.equal(temp, "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']")) 16 | --------------------------------------------------------------------------------