diff --git a/notebooks/quickstart/quickstart_model_documentation.Rmd b/notebooks/quickstart/quickstart_model_documentation.Rmd index 251899d47..fc48d8c44 100644 --- a/notebooks/quickstart/quickstart_model_documentation.Rmd +++ b/notebooks/quickstart/quickstart_model_documentation.Rmd @@ -64,7 +64,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 @@ -202,7 +202,7 @@ 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: diff --git a/notebooks/quickstart/quickstart_model_validation.Rmd b/notebooks/quickstart/quickstart_model_validation.Rmd index 6e43444e4..547aaf29d 100644 --- a/notebooks/quickstart/quickstart_model_validation.Rmd +++ b/notebooks/quickstart/quickstart_model_validation.Rmd @@ -65,7 +65,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/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..ccd27a16f 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 @@ -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 91eeebaaa..0359aa0b1 100644 --- a/r/validmind/NAMESPACE +++ b/r/validmind/NAMESPACE @@ -2,6 +2,7 @@ export(display_report) export(process_result) +export(py_print) export(register_custom_test) export(run_custom_test) export(save_model) @@ -17,5 +18,6 @@ importFrom(htmltools,div) importFrom(htmltools,tags) importFrom(plotly,plotly_build) importFrom(reticulate,import) +importFrom(reticulate,py_capture_output) importFrom(reticulate,py_config) importFrom(reticulate,use_python) diff --git a/r/validmind/R/platform.R b/r/validmind/R/platform.R index 5b828918f..bcdf89273 100644 --- a/r/validmind/R/platform.R +++ b/r/validmind/R/platform.R @@ -380,6 +380,26 @@ display_report <- function(processed_results) { return(all_widgets) } +#' Run a Python expression and display its print() output in R +#' +#' 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. +#' +#' Note: Python logging output (e.g. from \code{run_documentation_tests}) +#' is not captured due to reticulate limitations. +#' +#' @param expr A Python expression to evaluate +#' +#' @importFrom reticulate py_capture_output +#' +#' @export +py_print <- function(expr) { + 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 #' #' This function saves a given R model object to a randomly named `.RData` file diff --git a/r/validmind/README.md b/r/validmind/README.md index 4351790cb..d7b7b9c3a 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 @@ -173,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 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" ) } 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"