From 21ec51e89d2381bd709f6fa33baaed9804be8bb4 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 14:28:33 -0700 Subject: [PATCH 01/12] enable_py_output --- .../quickstart_model_documentation.Rmd | 3 ++ .../quickstart_model_validation.Rmd | 3 ++ r/validmind/R/platform.R | 40 +++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/notebooks/quickstart/quickstart_model_documentation.Rmd b/notebooks/quickstart/quickstart_model_documentation.Rmd index 251899d47..7fd0c88c1 100644 --- a/notebooks/quickstart/quickstart_model_documentation.Rmd +++ b/notebooks/quickstart/quickstart_model_documentation.Rmd @@ -37,6 +37,9 @@ library(caTools) library(knitr) knitr::opts_chunk$set(warning = FALSE, message = FALSE) + +# Make Python print/logging output visible in R Jupyter notebooks +enable_py_output() ``` ## Initialize the ValidMind Library diff --git a/notebooks/quickstart/quickstart_model_validation.Rmd b/notebooks/quickstart/quickstart_model_validation.Rmd index 6e43444e4..ab3f497c7 100644 --- a/notebooks/quickstart/quickstart_model_validation.Rmd +++ b/notebooks/quickstart/quickstart_model_validation.Rmd @@ -37,6 +37,9 @@ library(caTools) library(knitr) knitr::opts_chunk$set(warning = FALSE, message = FALSE) + +# Make Python print/logging output visible in R Jupyter notebooks +enable_py_output() ``` ## Initialize the ValidMind Library diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index 5b828918f..8ad02b52e 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -380,6 +380,46 @@ display_report <- function(processed_results) { return(all_widgets) } +#' Redirect Python stdout/stderr to R output +#' +#' Call this once in your setup chunk to make Python print() and logging +#' output visible in R Jupyter notebooks. This is not needed in terminal +#' R sessions where Python output is already displayed. +#' +#' @importFrom reticulate py_run_string +#' +#' @export +enable_py_output <- function() { + py_run_string(" +import sys + +class _ROutputRedirect: + def __init__(self, original): + self._original = original + + def write(self, text): + if text and text.strip(): + try: + from rpytools.output import write_stdout + write_stdout(text + '\\n') + except Exception: + self._original.write(text) + self._original.flush() + return len(text) if text else 0 + + def flush(self): + try: + self._original.flush() + except Exception: + pass + +if not isinstance(sys.stdout, _ROutputRedirect): + sys.stdout = _ROutputRedirect(sys.stdout) + sys.stderr = _ROutputRedirect(sys.stderr) +") + invisible(NULL) +} + #' Save an R model to a temporary file #' #' This function saves a given R model object to a randomly named `.RData` file From 3e2ac46ec16b7bc2cb32dae72b777ffad9bf2912 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 14:41:33 -0700 Subject: [PATCH 02/12] Add enable_py_output --- r/validmind/NAMESPACE | 2 ++ 1 file changed, 2 insertions(+) diff --git a/r/validmind/NAMESPACE b/r/validmind/NAMESPACE index 91eeebaaa..628926e92 100644 --- a/r/validmind/NAMESPACE +++ b/r/validmind/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(display_report) +export(enable_py_output) export(process_result) export(register_custom_test) export(run_custom_test) @@ -18,4 +19,5 @@ importFrom(htmltools,tags) importFrom(plotly,plotly_build) importFrom(reticulate,import) importFrom(reticulate,py_config) +importFrom(reticulate,py_run_string) importFrom(reticulate,use_python) From 158de14c0369d343a8f06e6c1861e7172d37fd0b Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 14:48:45 -0700 Subject: [PATCH 03/12] py_print --- .../quickstart_model_documentation.Rmd | 8 ++-- .../quickstart_model_validation.Rmd | 4 +- r/validmind/NAMESPACE | 4 +- r/validmind/R/platform.R | 45 +++++-------------- 4 files changed, 17 insertions(+), 44 deletions(-) diff --git a/notebooks/quickstart/quickstart_model_documentation.Rmd b/notebooks/quickstart/quickstart_model_documentation.Rmd index 7fd0c88c1..93142995c 100644 --- a/notebooks/quickstart/quickstart_model_documentation.Rmd +++ b/notebooks/quickstart/quickstart_model_documentation.Rmd @@ -38,8 +38,6 @@ library(knitr) knitr::opts_chunk$set(warning = FALSE, message = FALSE) -# Make Python print/logging output visible in R Jupyter notebooks -enable_py_output() ``` ## Initialize the ValidMind Library @@ -67,7 +65,7 @@ vm_r <- vm( Verify the connection and see the documentation structure: ```{r} -vm_r$preview_template() +py_print(vm_r$preview_template()) ``` ## Load the demo dataset @@ -205,13 +203,13 @@ Preview the test configuration: ```{r} vm_utils <- reticulate::import("validmind.utils") -vm_utils$preview_test_config(test_config) +py_print(vm_utils$preview_test_config(test_config)) ``` Run the full documentation test suite and upload results to the ValidMind Platform: ```{r} -full_suite <- vm_r$run_documentation_tests(config = test_config) +py_print(full_suite <- vm_r$run_documentation_tests(config = test_config)) ``` ## Next steps diff --git a/notebooks/quickstart/quickstart_model_validation.Rmd b/notebooks/quickstart/quickstart_model_validation.Rmd index ab3f497c7..9cfca0a93 100644 --- a/notebooks/quickstart/quickstart_model_validation.Rmd +++ b/notebooks/quickstart/quickstart_model_validation.Rmd @@ -38,8 +38,6 @@ library(knitr) knitr::opts_chunk$set(warning = FALSE, message = FALSE) -# Make Python print/logging output visible in R Jupyter notebooks -enable_py_output() ``` ## Initialize the ValidMind Library @@ -68,7 +66,7 @@ vm_r <- vm( Verify the connection and see the validation report structure: ```{r} -vm_r$preview_template() +py_print(vm_r$preview_template()) ``` ## Identify available tests diff --git a/r/validmind/NAMESPACE b/r/validmind/NAMESPACE index 628926e92..24cb63f6d 100644 --- a/r/validmind/NAMESPACE +++ b/r/validmind/NAMESPACE @@ -1,7 +1,7 @@ # Generated by roxygen2: do not edit by hand export(display_report) -export(enable_py_output) +export(py_print) export(process_result) export(register_custom_test) export(run_custom_test) @@ -19,5 +19,5 @@ importFrom(htmltools,tags) importFrom(plotly,plotly_build) importFrom(reticulate,import) importFrom(reticulate,py_config) -importFrom(reticulate,py_run_string) +importFrom(reticulate,py_capture_output) importFrom(reticulate,use_python) diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index 8ad02b52e..9b01fea5f 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -380,44 +380,21 @@ display_report <- function(processed_results) { return(all_widgets) } -#' Redirect Python stdout/stderr to R output +#' Run a Python expression and display its output in R #' -#' Call this once in your setup chunk to make Python print() and logging -#' output visible in R Jupyter notebooks. This is not needed in terminal -#' R sessions where Python output is already displayed. +#' Wraps a Python call with \code{reticulate::py_capture_output()} and prints +#' the result with \code{cat()}. Use this in R Jupyter notebooks where Python +#' print/logging output is not displayed automatically. #' -#' @importFrom reticulate py_run_string +#' @param expr A Python expression to evaluate (e.g. \code{vm_r$preview_template()}) +#' +#' @importFrom reticulate py_capture_output #' #' @export -enable_py_output <- function() { - py_run_string(" -import sys - -class _ROutputRedirect: - def __init__(self, original): - self._original = original - - def write(self, text): - if text and text.strip(): - try: - from rpytools.output import write_stdout - write_stdout(text + '\\n') - except Exception: - self._original.write(text) - self._original.flush() - return len(text) if text else 0 - - def flush(self): - try: - self._original.flush() - except Exception: - pass - -if not isinstance(sys.stdout, _ROutputRedirect): - sys.stdout = _ROutputRedirect(sys.stdout) - sys.stderr = _ROutputRedirect(sys.stderr) -") - invisible(NULL) +py_print <- function(expr) { + output <- py_capture_output(expr) + if (nchar(output) > 0) cat(output, "\n") + invisible(output) } #' Save an R model to a temporary file From cd9a6db265d65fa329676593beff91e420480692 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 14:57:46 -0700 Subject: [PATCH 04/12] Attempt to fix run_documentation_tests --- r/validmind/R/platform.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index 9b01fea5f..3cb659ac0 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -392,7 +392,9 @@ display_report <- function(processed_results) { #' #' @export py_print <- function(expr) { - output <- py_capture_output(expr) + # Use non-standard evaluation so py_capture_output can intercept + # stdout/stderr during execution, not after + output <- py_capture_output(eval(substitute(expr), envir = parent.frame())) if (nchar(output) > 0) cat(output, "\n") invisible(output) } From c132d29a57419476652251e37c6314340740b28b Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:03:05 -0700 Subject: [PATCH 05/12] Fixing py_print --- r/validmind/NAMESPACE | 1 + r/validmind/R/platform.R | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/r/validmind/NAMESPACE b/r/validmind/NAMESPACE index 24cb63f6d..7cc141941 100644 --- a/r/validmind/NAMESPACE +++ b/r/validmind/NAMESPACE @@ -20,4 +20,5 @@ importFrom(plotly,plotly_build) importFrom(reticulate,import) importFrom(reticulate,py_config) importFrom(reticulate,py_capture_output) +importFrom(reticulate,py_run_string) importFrom(reticulate,use_python) diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index 3cb659ac0..bd6aeab16 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -382,19 +382,32 @@ display_report <- function(processed_results) { #' Run a Python expression and display its output in R #' -#' Wraps a Python call with \code{reticulate::py_capture_output()} and prints -#' the result with \code{cat()}. Use this in R Jupyter notebooks where Python -#' print/logging output is not displayed automatically. +#' Captures Python print() and logging output during execution and displays +#' it with \code{cat()}. Use this in R Jupyter notebooks where Python output +#' is not displayed automatically. #' #' @param expr A Python expression to evaluate (e.g. \code{vm_r$preview_template()}) #' -#' @importFrom reticulate py_capture_output +#' @importFrom reticulate py_capture_output py_run_string #' #' @export py_print <- function(expr) { - # Use non-standard evaluation so py_capture_output can intercept - # stdout/stderr during execution, not after + # Redirect Python logging to stdout so py_capture_output can intercept it + py_run_string(" +import sys, logging +_py_print_handler = logging.StreamHandler(sys.stdout) +_py_print_handler.setFormatter(logging.Formatter('%(message)s')) +logging.getLogger().addHandler(_py_print_handler) +") + output <- py_capture_output(eval(substitute(expr), envir = parent.frame())) + + # Remove the temporary handler + py_run_string(" +logging.getLogger().removeHandler(_py_print_handler) +del _py_print_handler +") + if (nchar(output) > 0) cat(output, "\n") invisible(output) } From c53c07fa670598b95157eb2e0b9d457faf7c08f2 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:12:52 -0700 Subject: [PATCH 06/12] Fixes --- r/validmind/NAMESPACE | 1 - r/validmind/R/platform.R | 40 +++++++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/r/validmind/NAMESPACE b/r/validmind/NAMESPACE index 7cc141941..c205843f1 100644 --- a/r/validmind/NAMESPACE +++ b/r/validmind/NAMESPACE @@ -19,6 +19,5 @@ importFrom(htmltools,tags) importFrom(plotly,plotly_build) importFrom(reticulate,import) importFrom(reticulate,py_config) -importFrom(reticulate,py_capture_output) importFrom(reticulate,py_run_string) importFrom(reticulate,use_python) diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index bd6aeab16..0ba369fa3 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -388,28 +388,42 @@ display_report <- function(processed_results) { #' #' @param expr A Python expression to evaluate (e.g. \code{vm_r$preview_template()}) #' -#' @importFrom reticulate py_capture_output py_run_string +#' @importFrom reticulate py_run_string #' #' @export py_print <- function(expr) { - # Redirect Python logging to stdout so py_capture_output can intercept it + # Redirect stdout, stderr, and logging to a StringIO buffer py_run_string(" -import sys, logging -_py_print_handler = logging.StreamHandler(sys.stdout) -_py_print_handler.setFormatter(logging.Formatter('%(message)s')) -logging.getLogger().addHandler(_py_print_handler) +import sys, io, logging +_py_print_buf = io.StringIO() +_py_print_old_stdout = sys.stdout +_py_print_old_stderr = sys.stderr +sys.stdout = _py_print_buf +sys.stderr = _py_print_buf +_py_print_log_handler = logging.StreamHandler(_py_print_buf) +_py_print_log_handler.setFormatter(logging.Formatter('%(message)s')) +logging.getLogger().addHandler(_py_print_log_handler) ") - output <- py_capture_output(eval(substitute(expr), envir = parent.frame())) + result <- tryCatch( + eval(substitute(expr), envir = parent.frame()), + error = function(e) e + ) - # Remove the temporary handler - py_run_string(" -logging.getLogger().removeHandler(_py_print_handler) -del _py_print_handler + # Restore and read captured output + captured <- py_run_string(" +logging.getLogger().removeHandler(_py_print_log_handler) +sys.stdout = _py_print_old_stdout +sys.stderr = _py_print_old_stderr +_py_print_result = _py_print_buf.getvalue() +_py_print_buf.close() ") - if (nchar(output) > 0) cat(output, "\n") - invisible(output) + output <- captured[["_py_print_result"]] + if (nchar(output) > 0) cat(output) + + if (inherits(result, "error")) stop(result$message) + invisible(result) } #' Save an R model to a temporary file From 15c646587c051e6e75d53468c8c668c43563d010 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:20:03 -0700 Subject: [PATCH 07/12] Fix propagation --- r/validmind/R/platform.R | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index 0ba369fa3..34b93b697 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -392,7 +392,7 @@ display_report <- function(processed_results) { #' #' @export py_print <- function(expr) { - # Redirect stdout, stderr, and logging to a StringIO buffer + # Redirect stdout, stderr, and ValidMind logging to a StringIO buffer py_run_string(" import sys, io, logging _py_print_buf = io.StringIO() @@ -400,9 +400,14 @@ _py_print_old_stdout = sys.stdout _py_print_old_stderr = sys.stderr sys.stdout = _py_print_buf sys.stderr = _py_print_buf + +# Add handler to the validmind logger (propagate=False so root handler won't see it) _py_print_log_handler = logging.StreamHandler(_py_print_buf) -_py_print_log_handler.setFormatter(logging.Formatter('%(message)s')) -logging.getLogger().addHandler(_py_print_log_handler) +_py_print_log_handler.setFormatter( + logging.Formatter('%(asctime)s - %(levelname)s(%(name)s): %(message)s') +) +_py_print_vm_logger = logging.getLogger('validmind') +_py_print_vm_logger.addHandler(_py_print_log_handler) ") result <- tryCatch( @@ -412,7 +417,7 @@ logging.getLogger().addHandler(_py_print_log_handler) # Restore and read captured output captured <- py_run_string(" -logging.getLogger().removeHandler(_py_print_log_handler) +_py_print_vm_logger.removeHandler(_py_print_log_handler) sys.stdout = _py_print_old_stdout sys.stderr = _py_print_old_stderr _py_print_result = _py_print_buf.getvalue() From 87f003d74ae0ab0ceb27bc8989e59c603d4c27a0 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:26:33 -0700 Subject: [PATCH 08/12] Revert changes --- .../quickstart_model_documentation.Rmd | 3 +- .../quickstart_model_validation.Rmd | 1 - r/validmind/NAMESPACE | 1 + r/validmind/R/platform.R | 55 ++++--------------- 4 files changed, 14 insertions(+), 46 deletions(-) diff --git a/notebooks/quickstart/quickstart_model_documentation.Rmd b/notebooks/quickstart/quickstart_model_documentation.Rmd index 93142995c..fc48d8c44 100644 --- a/notebooks/quickstart/quickstart_model_documentation.Rmd +++ b/notebooks/quickstart/quickstart_model_documentation.Rmd @@ -37,7 +37,6 @@ library(caTools) library(knitr) knitr::opts_chunk$set(warning = FALSE, message = FALSE) - ``` ## Initialize the ValidMind Library @@ -209,7 +208,7 @@ py_print(vm_utils$preview_test_config(test_config)) Run the full documentation test suite and upload results to the ValidMind Platform: ```{r} -py_print(full_suite <- vm_r$run_documentation_tests(config = test_config)) +full_suite <- vm_r$run_documentation_tests(config = test_config) ``` ## Next steps diff --git a/notebooks/quickstart/quickstart_model_validation.Rmd b/notebooks/quickstart/quickstart_model_validation.Rmd index 9cfca0a93..547aaf29d 100644 --- a/notebooks/quickstart/quickstart_model_validation.Rmd +++ b/notebooks/quickstart/quickstart_model_validation.Rmd @@ -37,7 +37,6 @@ library(caTools) library(knitr) knitr::opts_chunk$set(warning = FALSE, message = FALSE) - ``` ## Initialize the ValidMind Library diff --git a/r/validmind/NAMESPACE b/r/validmind/NAMESPACE index c205843f1..7cc141941 100644 --- a/r/validmind/NAMESPACE +++ b/r/validmind/NAMESPACE @@ -19,5 +19,6 @@ importFrom(htmltools,tags) importFrom(plotly,plotly_build) importFrom(reticulate,import) importFrom(reticulate,py_config) +importFrom(reticulate,py_capture_output) importFrom(reticulate,py_run_string) importFrom(reticulate,use_python) diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index 34b93b697..bcdf89273 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -380,55 +380,24 @@ display_report <- function(processed_results) { return(all_widgets) } -#' Run a Python expression and display its output in R +#' Run a Python expression and display its print() output in R #' -#' Captures Python print() and logging output during execution and displays -#' it with \code{cat()}. Use this in R Jupyter notebooks where Python output -#' is not displayed automatically. +#' Wraps a Python call with \code{reticulate::py_capture_output()} and +#' displays the result with \code{cat()}. Useful in R Jupyter notebooks +#' where Python print() output is not displayed automatically. #' -#' @param expr A Python expression to evaluate (e.g. \code{vm_r$preview_template()}) +#' Note: Python logging output (e.g. from \code{run_documentation_tests}) +#' is not captured due to reticulate limitations. #' -#' @importFrom reticulate py_run_string +#' @param expr A Python expression to evaluate +#' +#' @importFrom reticulate py_capture_output #' #' @export py_print <- function(expr) { - # Redirect stdout, stderr, and ValidMind logging to a StringIO buffer - py_run_string(" -import sys, io, logging -_py_print_buf = io.StringIO() -_py_print_old_stdout = sys.stdout -_py_print_old_stderr = sys.stderr -sys.stdout = _py_print_buf -sys.stderr = _py_print_buf - -# Add handler to the validmind logger (propagate=False so root handler won't see it) -_py_print_log_handler = logging.StreamHandler(_py_print_buf) -_py_print_log_handler.setFormatter( - logging.Formatter('%(asctime)s - %(levelname)s(%(name)s): %(message)s') -) -_py_print_vm_logger = logging.getLogger('validmind') -_py_print_vm_logger.addHandler(_py_print_log_handler) -") - - result <- tryCatch( - eval(substitute(expr), envir = parent.frame()), - error = function(e) e - ) - - # Restore and read captured output - captured <- py_run_string(" -_py_print_vm_logger.removeHandler(_py_print_log_handler) -sys.stdout = _py_print_old_stdout -sys.stderr = _py_print_old_stderr -_py_print_result = _py_print_buf.getvalue() -_py_print_buf.close() -") - - output <- captured[["_py_print_result"]] - if (nchar(output) > 0) cat(output) - - if (inherits(result, "error")) stop(result$message) - invisible(result) + output <- py_capture_output(eval(substitute(expr), envir = parent.frame())) + if (nchar(output) > 0) cat(output, "\n") + invisible(output) } #' Save an R model to a temporary file From 9752339698a14cf0a25974f99fcc01a5670f2e57 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:31:46 -0700 Subject: [PATCH 09/12] Document py_print() helper for R Jupyter notebooks Co-Authored-By: Claude Opus 4.6 (1M context) --- r/validmind/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/r/validmind/README.md b/r/validmind/README.md index 4351790cb..b1166846c 100644 --- a/r/validmind/README.md +++ b/r/validmind/README.md @@ -105,7 +105,7 @@ Since the R package returns the full Python `validmind` module, you can call any ```r # Preview the documentation template -vm_r$preview_template() +py_print(vm_r$preview_template()) # Initialize datasets vm_dataset <- vm_r$init_dataset(dataset=df, input_id="my_dataset", target_column="target") @@ -128,6 +128,23 @@ vm_r$tests$list_tests(tags=list("data_quality"), task="classification") vm_r$tests$list_tasks_and_tags() ``` +### Python output in R Jupyter notebooks + +When running R notebooks in Jupyter (via IRkernel), Python `print()` output is not +displayed automatically due to a reticulate limitation. Use the `py_print()` helper +to capture and display output from Python functions: + +```r +# These produce print() output — wrap with py_print() +py_print(vm_r$preview_template()) +py_print(vm_utils$preview_test_config(test_config)) +``` + +Note: Python logging output (e.g. progress from `run_documentation_tests()` or +`assign_predictions()`) cannot be captured this way. These functions run silently +in R Jupyter — check the ValidMind Platform for results. This is not an issue in +terminal R sessions where all Python output is displayed normally. + ## Troubleshooting ### Initializating vm() on Mac From eb9f66cc6c40bc25a3bac14841b1ca357a6ce8a2 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:35:53 -0700 Subject: [PATCH 10/12] 2.12.5 --- pyproject.toml | 2 +- r/validmind/DESCRIPTION | 2 +- validmind/__version__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6de558bf2..18afed736 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "validmind" -version = "2.12.4" +version = "2.12.5" description = "ValidMind Library" readme = "README.pypi.md" requires-python = ">=3.9,<3.15" diff --git a/r/validmind/DESCRIPTION b/r/validmind/DESCRIPTION index 37e80f97d..ad4fe20ce 100644 --- a/r/validmind/DESCRIPTION +++ b/r/validmind/DESCRIPTION @@ -1,7 +1,7 @@ Package: validmind Type: Package Title: Interface to the 'ValidMind' Platform -Version: 2.12.4 +Version: 2.12.5 Authors@R: c(person("Andres", "Rodriguez", role = c("aut", "cre","cph"), email = "andres@validmind.ai")) Maintainer: Andres Rodriguez diff --git a/validmind/__version__.py b/validmind/__version__.py index 896b89678..336282f43 100644 --- a/validmind/__version__.py +++ b/validmind/__version__.py @@ -1 +1 @@ -__version__ = "2.12.4" +__version__ = "2.12.5" From c24ae330a177e14b5a8637df35cd0d7b04d97b20 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:46:46 -0700 Subject: [PATCH 11/12] Regenerate roxygen docs for CRAN check (fixes 2 WARNINGs) - Generate py_print.Rd (was missing) - Update vm.Rd to reflect document param and python_version default Co-Authored-By: Claude Opus 4.6 (1M context) --- r/validmind/DESCRIPTION | 2 +- r/validmind/NAMESPACE | 5 ++--- r/validmind/man/py_print.Rd | 20 ++++++++++++++++++++ r/validmind/man/vm.Rd | 15 ++++++++++----- 4 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 r/validmind/man/py_print.Rd diff --git a/r/validmind/DESCRIPTION b/r/validmind/DESCRIPTION index ad4fe20ce..ccd27a16f 100644 --- a/r/validmind/DESCRIPTION +++ b/r/validmind/DESCRIPTION @@ -14,7 +14,7 @@ Encoding: UTF-8 LazyData: true URL: https://github.com/validmind/validmind-library BugReports: https://github.com/validmind/validmind-library/issues -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 Imports: glue, reticulate, diff --git a/r/validmind/NAMESPACE b/r/validmind/NAMESPACE index 7cc141941..0359aa0b1 100644 --- a/r/validmind/NAMESPACE +++ b/r/validmind/NAMESPACE @@ -1,8 +1,8 @@ # Generated by roxygen2: do not edit by hand export(display_report) -export(py_print) export(process_result) +export(py_print) export(register_custom_test) export(run_custom_test) export(save_model) @@ -18,7 +18,6 @@ importFrom(htmltools,div) importFrom(htmltools,tags) importFrom(plotly,plotly_build) importFrom(reticulate,import) -importFrom(reticulate,py_config) importFrom(reticulate,py_capture_output) -importFrom(reticulate,py_run_string) +importFrom(reticulate,py_config) importFrom(reticulate,use_python) diff --git a/r/validmind/man/py_print.Rd b/r/validmind/man/py_print.Rd new file mode 100644 index 000000000..c2a9e5268 --- /dev/null +++ b/r/validmind/man/py_print.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/platform.R +\name{py_print} +\alias{py_print} +\title{Run a Python expression and display its print() output in R} +\usage{ +py_print(expr) +} +\arguments{ +\item{expr}{A Python expression to evaluate} +} +\description{ +Wraps a Python call with \code{reticulate::py_capture_output()} and +displays the result with \code{cat()}. Useful in R Jupyter notebooks +where Python print() output is not displayed automatically. +} +\details{ +Note: Python logging output (e.g. from \code{run_documentation_tests}) +is not captured due to reticulate limitations. +} diff --git a/r/validmind/man/vm.Rd b/r/validmind/man/vm.Rd index 816f0448f..820a43d1a 100644 --- a/r/validmind/man/vm.Rd +++ b/r/validmind/man/vm.Rd @@ -8,8 +8,9 @@ vm( api_key, api_secret, model, - python_version, - api_host = "http://localhost:3000/api/v1/tracking" + python_version = Sys.getenv("VALIDMIND_PYTHON", Sys.which("python")), + api_host = "http://localhost:3000/api/v1/tracking", + document = NULL ) } \arguments{ @@ -19,9 +20,13 @@ vm( \item{model}{The ValidMind model} -\item{python_version}{The Python Version to use} +\item{python_version}{The path to the Python binary to use. Defaults to +the VALIDMIND_PYTHON environment variable, or the system Python.} \item{api_host}{The ValidMind host, defaulting to local} + +\item{document}{The document type to associate with this session +(e.g. "documentation", "validation-report"). Defaults to NULL.} } \value{ A validmind connection object, obtained from `reticulate`, @@ -33,11 +38,11 @@ Retrieve a validmind (vm) connection object using reticulate \examples{ \dontrun{ vm_r <- vm( + api_host="https://app.prod.validmind.ai/api/v1/tracking", api_key="", api_secret="", model="", - python_version=python_version, - api_host="https://app.prod.validmind.ai/api/v1/tracking" + document="documentation" ) } From 98ac14cc6892fff941196bb9b5f4ba874194864a Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 25 Mar 2026 15:51:17 -0700 Subject: [PATCH 12/12] Document CRAN publishing process in R README Co-Authored-By: Claude Opus 4.6 (1M context) --- r/validmind/README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/r/validmind/README.md b/r/validmind/README.md index b1166846c..d7b7b9c3a 100644 --- a/r/validmind/README.md +++ b/r/validmind/README.md @@ -190,3 +190,39 @@ pip install -U numba ``` And restart the R session. + +## Publishing to CRAN + +### 1. Update version + +The R package version is kept in sync with the Python package. Running `make version tag=patch` from the repo root updates both `pyproject.toml` and `r/validmind/DESCRIPTION`. + +### 2. Regenerate documentation + +```bash +cd r/validmind +Rscript -e 'roxygen2::roxygenise()' +``` + +This updates the `man/` Rd files and `NAMESPACE` from the roxygen comments in `R/platform.R`. + +### 3. Build and check + +```bash +cd r/validmind +R CMD build . +R CMD check --as-cran validmind_*.tar.gz +``` + +Fix all ERRORs and WARNINGs before submitting. NOTEs are generally acceptable. + +### 4. Submit + +Upload the `.tar.gz` at https://cran.r-project.org/submit.html + +### 5. After submission + +- CRAN sends a confirmation email — click the link to confirm +- CRAN runs automated checks on Windows and Linux — fix any issues they flag +- A CRAN volunteer manually reviews — this can take days to weeks +- They may email back with requests for changes before accepting