From a4cb3e3de8531a7694f675e26074f0b1da4f23d7 Mon Sep 17 00:00:00 2001 From: Pralit Patel Date: Thu, 25 May 2023 14:18:16 -0400 Subject: [PATCH] We seem to really have to call the R/python level flush commands to ensure our "cout" reaches Jupyter notebooks in a timely fashion --- R/query_library.R | 1 + inst/include/interp_interface.h | 47 ++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/R/query_library.R b/R/query_library.R index f1ce5e4..3956aac 100644 --- a/R/query_library.R +++ b/R/query_library.R @@ -47,6 +47,7 @@ wrap_get_query <- function() { #' @return (string) The raw query from the query file with units set as an attribute #' if specified. #' @importFrom yaml read_yaml +#' @export get_query <- wrap_get_query() diff --git a/inst/include/interp_interface.h b/inst/include/interp_interface.h index 2e9bc00..3b16cb2 100644 --- a/inst/include/interp_interface.h +++ b/inst/include/interp_interface.h @@ -4,6 +4,10 @@ #include #include +// use boost::iostreams to wrap Interp API for cout +#include +#include + #if __has_include("Rcpp.h") #define IS_INTERP_R #define STRICT_R_HEADERS @@ -13,9 +17,6 @@ #include #include -// use boost::iostreams to wrap Python's C API for cout -#include -#include #include #else #error "Could not determine, or using an unknown interpreter. Only R and Python are currently supported." @@ -32,6 +33,26 @@ class gcam_exception : public std::exception { }; #if defined(USING_R) + +/*! + * \brief Wrap Rprintf in a boost::iostreams so we can use a C++ interface. + * \details We couldn't just use Rcout directly because we need to add a flush + * for it to show up in a notebook in a timeley manner. + */ +class RStdoutSink { +public: + typedef char char_type; + typedef boost::iostreams::sink_tag category; + + inline std::streamsize write(const char* aString, std::streamsize aSize) { + Rprintf("%.*s", aSize, aString); + // using R_FlushConsole() doesn't work for whatever reason + Rcpp::Function flush("flush.console"); + flush(); + return aSize; + } +}; + namespace Interp { using Rcpp::stop; using Rcpp::warning; @@ -42,7 +63,8 @@ namespace Interp { using Rcpp::NumericMatrix; inline std::ostream& getInterpCout() { - return Rcpp::Rcout; + static boost::iostreams::stream sRCout; + return sRCout; } inline std::string extract(const Rcpp::String& aStr) { @@ -101,15 +123,16 @@ namespace Interp { */ class PySysStdoutSink { public: - typedef char char_type; - typedef boost::iostreams::sink_tag category; + typedef char char_type; + typedef boost::iostreams::sink_tag category; - inline std::streamsize write(const char* aString, std::streamsize aSize) { - const std::streamsize MAX_PY_SIZE = 1000; - std::streamsize actualSize = std::min(aSize, MAX_PY_SIZE); - PySys_WriteStdout((boost::format("%%.%1%s") % actualSize).str().c_str(), aString); - return actualSize; - } + inline std::streamsize write(const char* aString, std::streamsize aSize) { + const std::streamsize MAX_PY_SIZE = 1000; + std::streamsize actualSize = std::min(aSize, MAX_PY_SIZE); + PySys_WriteStdout((boost::format("%%.%1%s") % actualSize).str().c_str(), aString); + boost::python::call_method(PySys_GetObject("stdout"), "flush"); + return actualSize; + } }; namespace Interp {