diff --git a/DESCRIPTION b/DESCRIPTION index af55439..86d0aca 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: churon -Title: 'ONNX' Runtime Integration for R -Version: 0.1.11 +Title: 'ONNX Runtime' Integration +Version: 0.1.12 Authors@R: c( person(given = "Chanyub", family = "Park", role = c("aut", "cre"), email = "mrchypark@gmail.com", @@ -12,13 +12,14 @@ Authors@R: c( person(given = "Microsoft Corporation", role = "cph", comment = "ONNX Runtime, downloaded only on explicit user request") ) -Description: Provides high-performance R bindings for 'ONNX' Runtime, enabling - efficient machine learning model inference. Written in Rust for memory safety +Description: Provides high-performance R bindings for 'ONNX Runtime' + , enabling efficient machine learning model inference. Written in 'Rust' for memory safety and speed, the package supports cross-platform model execution with multiple execution providers. Includes comprehensive error handling and validation, - with bundled 'MNIST' example model for immediate testing and prototyping. + with bundled MNIST example model for immediate testing and prototyping. Designed for production use with support for macOS (arm64), Linux (x64/arm64), - and Windows (x64). + and Windows (x64). Runtime libraries are downloaded on explicit request from + . License: MIT + file LICENSE URL: https://github.com/mrchypark/churon BugReports: https://github.com/mrchypark/churon/issues diff --git a/R/install_onnx_runtime.R b/R/install_onnx_runtime.R index a04584f..248b70d 100644 --- a/R/install_onnx_runtime.R +++ b/R/install_onnx_runtime.R @@ -7,27 +7,39 @@ #' @param version Character string specifying the ONNX Runtime version to install. #' Defaults to "1.29.0". Supported versions are "1.28.0" and "1.29.0"; #' "latest" selects "1.29.0". +#' @param destdir Required character string naming the installation directory. #' @param quiet Logical. If TRUE, suppress download progress messages. #' @param ... Additional arguments passed to download.file() #' #' @return Invisible TRUE on success, stops with error on failure. #' @export -#' @examples -#' \dontrun{ -#' # Install ONNX Runtime -#' install_onnx_runtime() -#' -#' # Install specific version -#' install_onnx_runtime(version = "1.28.0") -#' -#' # Install with no output -#' install_onnx_runtime(quiet = TRUE) -#' } -install_onnx_runtime <- function(version = "1.29.0", quiet = FALSE, ...) { +#' @details +#' This function installs external software only when explicitly called. Supply +#' `destdir` yourself; no installation directory is selected by default. +#' The library is placed in `destdir/lib` and configured for this R session. +#' In later sessions, set `ORT_DYLIB_PATH` to the installed library file before +#' loading churon. Restart R before switching an already loaded runtime. +install_onnx_runtime <- function( + version = "1.29.0", + quiet = FALSE, + destdir, + ... +) { if (!is.character(version) || length(version) != 1L || is.na(version)) { stop("version must be one non-missing character string.") } + if ( + missing(destdir) || + !is.character(destdir) || + length(destdir) != 1L || + is.na(destdir) || + !nzchar(trimws(destdir)) + ) { + stop("destdir must be supplied as one non-empty directory path.") + } + destdir <- path.expand(destdir) + # Platform detection platform <- Sys.info()[["sysname"]] machine <- Sys.info()[["machine"]] @@ -149,7 +161,7 @@ install_onnx_runtime <- function(version = "1.29.0", quiet = FALSE, ...) { } # Determine library path - lib_dir <- file.path(.libPaths()[1], "churon", "onnxruntime", "lib") + lib_dir <- file.path(destdir, "lib") # Create directory if needed if (!dir.exists(lib_dir)) { @@ -186,7 +198,7 @@ install_onnx_runtime <- function(version = "1.29.0", quiet = FALSE, ...) { ) if (!copied) { stop( - "Failed to copy the ONNX Runtime library into the package library." + "Failed to copy the ONNX Runtime library into destdir." ) } @@ -206,35 +218,18 @@ install_onnx_runtime <- function(version = "1.29.0", quiet = FALSE, ...) { stop("Could not find ", lib_filename, " in extracted archive") } - # Copy include directory (for future use) - include_dir <- file.path( - .libPaths()[1], - "churon", - "onnxruntime", - "include" - ) - if (!dir.exists(include_dir)) { - dir.create(include_dir, showWarnings = FALSE, recursive = TRUE) - } - include_src_dir <- file.path(extracted_dir, "include") - if (dir.exists(include_src_dir)) { - file.copy( - list.files(include_src_dir, full.names = TRUE, recursive = TRUE), - include_dir, - overwrite = TRUE, - recursive = TRUE - ) - } - # Clean up unlink(temp_dir, recursive = TRUE) # Verify installation - lib_file <- onnx_runtime_lib_path() + lib_file <- file.path(lib_dir, lib_filename) if (!file.exists(lib_file)) { stop("Installation verification failed: library file not found") } + Sys.setenv(ORT_DYLIB_PATH = normalizePath(lib_file)) + setup_onnx_runtime() + if (!quiet) { message(sprintf("ONNX Runtime installed successfully!")) message(sprintf("Library: %s", lib_file)) @@ -291,6 +286,10 @@ onnx_runtime_is_installed <- function() { #' @return Character string with the library path. #' @keywords internal onnx_runtime_lib_path <- function() { + configured_path <- Sys.getenv("ORT_DYLIB_PATH", unset = "") + if (nzchar(configured_path) && file.exists(configured_path)) { + return(configured_path) + } platform <- Sys.info()[["sysname"]] pkg_path <- system.file(package = "churon") diff --git a/R/onnx_interface.R b/R/onnx_interface.R index 7edfa3e..6ec2303 100644 --- a/R/onnx_interface.R +++ b/R/onnx_interface.R @@ -23,12 +23,12 @@ NULL #' @return An RSession object for running inference #' @export #' @examples -#' \dontrun{ -#' # Create session with default providers -#' session <- onnx_session("path/to/model.onnx") +#' if (check_onnx_runtime_available()) { +#' # Create session with default providers +#' session <- onnx_example_session() #' -#' # Create session with specific providers -#' session <- onnx_session("path/to/model.onnx", providers = c("cuda", "cpu")) +#' # Create session with specific providers +#' session <- onnx_example_session(providers = "cpu") #' } onnx_session <- function(model_path, providers = NULL) { # Input validation @@ -131,10 +131,10 @@ onnx_session <- function(model_path, providers = NULL) { #' @return A named list of output tensors #' @export #' @examples -#' \dontrun{ -#' session <- onnx_session("path/to/model.onnx") -#' inputs <- list(input_tensor = matrix(rnorm(10), nrow = 2, ncol = 5)) -#' outputs <- onnx_run(session, inputs) +#' if (check_onnx_runtime_available()) { +#' session <- onnx_example_session() +#' inputs <- list(Input3 = array(0, dim = c(1, 1, 28, 28))) +#' outputs <- onnx_run(session, inputs) #' } onnx_run <- function(session, inputs) { .validate_session(session) @@ -261,10 +261,10 @@ onnx_run <- function(session, inputs) { #' @return A list of TensorInfo objects containing input tensor metadata #' @export #' @examples -#' \dontrun{ -#' session <- onnx_session("path/to/model.onnx") -#' input_info <- onnx_input_info(session) -#' print(input_info) +#' if (check_onnx_runtime_available()) { +#' session <- onnx_example_session() +#' input_info <- onnx_input_info(session) +#' print(input_info) #' } onnx_input_info <- function(session) { .validate_session(session) @@ -294,10 +294,10 @@ onnx_input_info <- function(session) { #' @return A list of TensorInfo objects containing output tensor metadata #' @export #' @examples -#' \dontrun{ -#' session <- onnx_session("path/to/model.onnx") -#' output_info <- onnx_output_info(session) -#' print(output_info) +#' if (check_onnx_runtime_available()) { +#' session <- onnx_example_session() +#' output_info <- onnx_output_info(session) +#' print(output_info) #' } onnx_output_info <- function(session) { .validate_session(session) @@ -327,10 +327,10 @@ onnx_output_info <- function(session) { #' @return A character vector of available execution providers #' @export #' @examples -#' \dontrun{ -#' session <- onnx_session("path/to/model.onnx") -#' providers <- onnx_providers(session) -#' cat("Available execution providers:", paste(providers, collapse = ", "), "\n") +#' if (check_onnx_runtime_available()) { +#' session <- onnx_example_session() +#' providers <- onnx_providers(session) +#' cat("Available execution providers:", paste(providers, collapse = ", "), "\n") #' } onnx_providers <- function(session) { .validate_session(session) @@ -360,10 +360,10 @@ onnx_providers <- function(session) { #' @return Character string with the model path #' @export #' @examples -#' \dontrun{ -#' session <- onnx_session("path/to/model.onnx") -#' model_path <- onnx_model_path(session) -#' cat("Model path:", model_path, "\n") +#' if (check_onnx_runtime_available()) { +#' session <- onnx_example_session() +#' model_path <- onnx_model_path(session) +#' cat("Model path:", model_path, "\n") #' } onnx_model_path <- function(session) { .validate_session(session) diff --git a/R/s3_methods.R b/R/s3_methods.R index c25540f..0370dcc 100644 --- a/R/s3_methods.R +++ b/R/s3_methods.R @@ -4,6 +4,10 @@ #' #' @param x A TensorInfo or RSession object #' @param name Property name to access +#' @return For `name` and `data_type`, a character scalar identifying the tensor +#' or its element type. For `shape`, an integer vector of tensor dimensions +#' (negative dimensions indicate dynamic sizes). For a method name, a function +#' bound to the object; for an unknown name, `NULL`. #' @export `$.TensorInfo` <- function(x, name) { if (name == "name") { diff --git a/R/zzz.R b/R/zzz.R index 90eaadd..5f1c07f 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -14,7 +14,9 @@ if (!check_onnx_runtime_available()) { packageStartupMessage("") packageStartupMessage("ONNX Runtime is not installed.") - packageStartupMessage("To install, run: install_onnx_runtime()") + packageStartupMessage( + "To install, call install_onnx_runtime() with an explicit destdir." + ) packageStartupMessage("") } else { packageStartupMessage("ONNX Runtime loaded successfully.") diff --git a/cran-comments.md b/cran-comments.md index b888d3d..be3e980 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,18 +1,37 @@ -## Test environments +## Resubmission (0.1.12) -* GitHub Actions: R-devel, R-release, and R 4.0 on Ubuntu (without ONNX - Runtime and without network access during package installation) -* GitHub Actions: R-release on Ubuntu x86_64 and arm64, macOS, and Windows -* r-universe: R-devel, R-release, and R-oldrel native builders, plus WebAssembly +This resubmission addresses the CRAN review of version 0.1.11: -## R CMD check results +* Removed the redundant "for R" from the title and quoted software names + consistently; MNIST is no longer quoted. +* Added ONNX Runtime and GitHub release URLs to DESCRIPTION. +* Documented the return types and meaning of `$.TensorInfo` results. +* Replaced non-running placeholder examples with executable examples using + the bundled MNIST model, conditional on runtime availability. +* Removed software installation calls from the installer examples. +* Required an explicit `destdir` for runtime installation. The installer no + longer writes into the package library, and configures `ORT_DYLIB_PATH` + for the current session. Later-session configuration is documented. +* Removed automatic R package installation from the development setup script. -0 errors | 0 warnings | 0 notes +## Local validation (2026-09-11) + +* macOS arm64, R 4.5.2, Rust 1.97.1. +* Runtime-enabled tests: 90 passed, no failures, warnings, or skips. +* Offline `R CMD check --as-cran --no-manual`: 0 errors, 0 warnings, 1 note. + The note reports that current time could not be verified with network access + disabled. The official Debian `checkbashisms` utility was supplied for this check. + Package installation, documentation, examples, and tests passed. ## Additional notes -This is a new submission. +Rust dependencies are vendored in the source package for offline builds. +ONNX Runtime is not bundled. The dedicated installer downloads it only on +explicit request with a user-supplied destination. Tests requiring a runtime +are skipped when it is absent; tests do not download or install software. + +## Submission status -Rust dependencies are vendored in the source package for offline builds. ONNX -Runtime is not bundled; users may download it explicitly with -`install_onnx_runtime()`. Tests that require it are skipped when it is absent. +Version 0.1.12 was uploaded and submitted through the CRAN web form on +2026-09-11 (upload ID 354755). The maintainer subsequently confirmed publication on CRAN. +The Git repository is being synchronized with the published 0.1.12 release. diff --git a/man/cash-.TensorInfo.Rd b/man/cash-.TensorInfo.Rd index dba9417..d404f8b 100644 --- a/man/cash-.TensorInfo.Rd +++ b/man/cash-.TensorInfo.Rd @@ -11,6 +11,12 @@ \item{name}{Property name to access} } +\value{ +For \code{name} and \code{data_type}, a character scalar identifying the tensor +or its element type. For \code{shape}, an integer vector of tensor dimensions +(negative dimensions indicate dynamic sizes). For a method name, a function +bound to the object; for an unknown name, \code{NULL}. +} \description{ These methods provide convenient access to object properties. } diff --git a/man/install_onnx_runtime.Rd b/man/install_onnx_runtime.Rd index 9c8751e..a97565b 100644 --- a/man/install_onnx_runtime.Rd +++ b/man/install_onnx_runtime.Rd @@ -4,7 +4,7 @@ \alias{install_onnx_runtime} \title{Install ONNX Runtime} \usage{ -install_onnx_runtime(version = "1.29.0", quiet = FALSE, ...) +install_onnx_runtime(version = "1.29.0", quiet = FALSE, destdir, ...) } \arguments{ \item{version}{Character string specifying the ONNX Runtime version to install. @@ -13,6 +13,8 @@ Defaults to "1.29.0". Supported versions are "1.28.0" and "1.29.0"; \item{quiet}{Logical. If TRUE, suppress download progress messages.} +\item{destdir}{Required character string naming the installation directory.} + \item{...}{Additional arguments passed to download.file()} } \value{ @@ -23,15 +25,10 @@ Download and install ONNX Runtime library for your platform. This is required before using the churon package if ONNX Runtime is not already installed on your system. } -\examples{ -\dontrun{ -# Install ONNX Runtime -install_onnx_runtime() - -# Install specific version -install_onnx_runtime(version = "1.28.0") - -# Install with no output -install_onnx_runtime(quiet = TRUE) -} +\details{ +This function installs external software only when explicitly called. Supply +\code{destdir} yourself; no installation directory is selected by default. +The library is placed in \code{destdir/lib} and configured for this R session. +In later sessions, set \code{ORT_DYLIB_PATH} to the installed library file before +loading churon. Restart R before switching an already loaded runtime. } diff --git a/man/onnx_input_info.Rd b/man/onnx_input_info.Rd index 098dc58..59242f1 100644 --- a/man/onnx_input_info.Rd +++ b/man/onnx_input_info.Rd @@ -16,9 +16,9 @@ A list of TensorInfo objects containing input tensor metadata Retrieve information about model input tensors. } \examples{ -\dontrun{ -session <- onnx_session("path/to/model.onnx") -input_info <- onnx_input_info(session) -print(input_info) +if (check_onnx_runtime_available()) { + session <- onnx_example_session() + input_info <- onnx_input_info(session) + print(input_info) } } diff --git a/man/onnx_model_path.Rd b/man/onnx_model_path.Rd index 1ac8418..c19e626 100644 --- a/man/onnx_model_path.Rd +++ b/man/onnx_model_path.Rd @@ -16,9 +16,9 @@ Character string with the model path Get the model path from a session. } \examples{ -\dontrun{ -session <- onnx_session("path/to/model.onnx") -model_path <- onnx_model_path(session) -cat("Model path:", model_path, "\n") +if (check_onnx_runtime_available()) { + session <- onnx_example_session() + model_path <- onnx_model_path(session) + cat("Model path:", model_path, "\n") } } diff --git a/man/onnx_output_info.Rd b/man/onnx_output_info.Rd index 14efd7f..34eee32 100644 --- a/man/onnx_output_info.Rd +++ b/man/onnx_output_info.Rd @@ -16,9 +16,9 @@ A list of TensorInfo objects containing output tensor metadata Retrieve information about model output tensors. } \examples{ -\dontrun{ -session <- onnx_session("path/to/model.onnx") -output_info <- onnx_output_info(session) -print(output_info) +if (check_onnx_runtime_available()) { + session <- onnx_example_session() + output_info <- onnx_output_info(session) + print(output_info) } } diff --git a/man/onnx_providers.Rd b/man/onnx_providers.Rd index 70d634f..e7fa27b 100644 --- a/man/onnx_providers.Rd +++ b/man/onnx_providers.Rd @@ -16,9 +16,9 @@ A character vector of available execution providers Get the execution providers available for the session. } \examples{ -\dontrun{ -session <- onnx_session("path/to/model.onnx") -providers <- onnx_providers(session) -cat("Available execution providers:", paste(providers, collapse = ", "), "\n") +if (check_onnx_runtime_available()) { + session <- onnx_example_session() + providers <- onnx_providers(session) + cat("Available execution providers:", paste(providers, collapse = ", "), "\n") } } diff --git a/man/onnx_run.Rd b/man/onnx_run.Rd index b7a9981..0bb067a 100644 --- a/man/onnx_run.Rd +++ b/man/onnx_run.Rd @@ -18,9 +18,9 @@ A named list of output tensors Execute inference on an ONNX model with input data. } \examples{ -\dontrun{ -session <- onnx_session("path/to/model.onnx") -inputs <- list(input_tensor = matrix(rnorm(10), nrow = 2, ncol = 5)) -outputs <- onnx_run(session, inputs) +if (check_onnx_runtime_available()) { + session <- onnx_example_session() + inputs <- list(Input3 = array(0, dim = c(1, 1, 28, 28))) + outputs <- onnx_run(session, inputs) } } diff --git a/man/onnx_session.Rd b/man/onnx_session.Rd index b772ca7..41cdb90 100644 --- a/man/onnx_session.Rd +++ b/man/onnx_session.Rd @@ -20,11 +20,11 @@ An RSession object for running inference Create a new ONNX Runtime session from a model file. } \examples{ -\dontrun{ -# Create session with default providers -session <- onnx_session("path/to/model.onnx") +if (check_onnx_runtime_available()) { + # Create session with default providers + session <- onnx_example_session() -# Create session with specific providers -session <- onnx_session("path/to/model.onnx", providers = c("cuda", "cpu")) + # Create session with specific providers + session <- onnx_example_session(providers = "cpu") } } diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index a4fa52f..5b8fafe 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -467,7 +467,7 @@ impl RSession { path } else { // Try to find the library in the package installation directory - // This is the default location used by install_onnx_runtime() + // Compatibility fallback for existing package-local installations let pkg_path = std::env::var("R_PACKAGE_DIR") .ok() .or_else(|| std::env::var("R_LIBS_USER").ok()) @@ -485,7 +485,7 @@ impl RSession { } else { // Library not found - return error instead of panicking return Err(extendr_api::Error::EvalError( - "ONNX Runtime library not found. Please run install_onnx_runtime() to download it.".into(), + "ONNX Runtime library not found. Please call install_onnx_runtime() with an explicit destdir to download it.".into(), )); } }; diff --git a/tests/testthat/test-end-to-end.R b/tests/testthat/test-end-to-end.R index 4a191c2..c85fd0e 100644 --- a/tests/testthat/test-end-to-end.R +++ b/tests/testthat/test-end-to-end.R @@ -3,7 +3,9 @@ test_that("end-to-end workflow with example models", { # Check if ONNX Runtime is actually available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } # Get available example models @@ -43,7 +45,9 @@ test_that("convenience functions work correctly", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } models <- onnx_example_models() @@ -67,7 +71,9 @@ test_that("error handling in real scenarios", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } # Test with non-existent model @@ -104,7 +110,9 @@ test_that("input validation works correctly", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } models <- onnx_example_models() diff --git a/tests/testthat/test-error-handling.R b/tests/testthat/test-error-handling.R index 9a2ef24..374641e 100644 --- a/tests/testthat/test-error-handling.R +++ b/tests/testthat/test-error-handling.R @@ -30,7 +30,9 @@ test_that("error handling for invalid execution providers", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } model_dir <- system.file("model", package = "churon") @@ -63,7 +65,9 @@ test_that("error handling for inference failures", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } model_dir <- system.file("model", package = "churon") diff --git a/tests/testthat/test-inference-execution.R b/tests/testthat/test-inference-execution.R index e5a1393..b52c830 100644 --- a/tests/testthat/test-inference-execution.R +++ b/tests/testthat/test-inference-execution.R @@ -3,7 +3,9 @@ test_that("basic inference execution", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } expect_true(TRUE) @@ -14,7 +16,9 @@ test_that("inference with invalid input data", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } model_dir <- system.file("model", package = "churon") diff --git a/tests/testthat/test-package-loading.R b/tests/testthat/test-package-loading.R index 4326022..f7ce358 100644 --- a/tests/testthat/test-package-loading.R +++ b/tests/testthat/test-package-loading.R @@ -46,7 +46,7 @@ test_that("package metadata is correct", { desc <- packageDescription("churon") expect_equal(desc$Package, "churon") - expect_match(desc$Title, "'ONNX' Runtime") + expect_identical(desc$Title, "'ONNX Runtime' Integration") expect_match(desc$Description, "ONNX") # Check for ONNX mention expect_equal(desc$License, "MIT + file LICENSE") }) diff --git a/tests/testthat/test-runtime-configuration.R b/tests/testthat/test-runtime-configuration.R index 0fdb23a..338f911 100644 --- a/tests/testthat/test-runtime-configuration.R +++ b/tests/testthat/test-runtime-configuration.R @@ -32,6 +32,8 @@ test_that("a valid configured ONNX Runtime path is preserved", { Sys.setenv(ORT_DYLIB_PATH = runtime) expect_true(churon:::setup_onnx_runtime()) expect_equal(Sys.getenv("ORT_DYLIB_PATH"), normalizePath(runtime)) + expect_identical(churon:::onnx_runtime_lib_path(), normalizePath(runtime)) + expect_true(onnx_runtime_is_installed()) }) test_that("a missing configured ONNX Runtime path falls back gracefully", { @@ -62,11 +64,11 @@ test_that("a missing configured ONNX Runtime path falls back gracefully", { test_that("runtime installer enforces verified compatible versions", { expect_error( - install_onnx_runtime(NA_character_, quiet = TRUE), + install_onnx_runtime(NA_character_, quiet = TRUE, destdir = tempdir()), "version must be one non-missing character string" ) expect_error( - install_onnx_runtime("1.27.0", quiet = TRUE), + install_onnx_runtime("1.27.0", quiet = TRUE, destdir = tempdir()), "supports ONNX Runtime versions 1.28.0 and 1.29.0" ) expect_identical( @@ -77,3 +79,22 @@ test_that("runtime installer enforces verified compatible versions", { "c3fddc4f139a045b0c4902c57410f0694f1c2fdf9b6939fbe38b1aeae7cd14ba" ) }) + + +test_that("runtime installation requires an explicit valid destination", { + expect_error(install_onnx_runtime(), "destdir must be supplied") + for (destdir in list( + NULL, + NA_character_, + "", + " ", + character(), + c("a", "b"), + 1 + )) { + expect_error( + install_onnx_runtime(destdir = destdir), + "destdir must be supplied" + ) + } +}) diff --git a/tests/testthat/test-session-management.R b/tests/testthat/test-session-management.R index 2c1422a..172a794 100644 --- a/tests/testthat/test-session-management.R +++ b/tests/testthat/test-session-management.R @@ -3,7 +3,9 @@ test_that("session creation with valid model", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } models <- onnx_example_models() @@ -23,7 +25,9 @@ test_that("session creation with execution providers", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } models <- onnx_example_models() @@ -46,7 +50,9 @@ test_that("session information retrieval", { # Check if ONNX Runtime is available if (!check_onnx_runtime_available()) { - skip("ONNX Runtime not installed - run install_onnx_runtime()") + skip( + "ONNX Runtime not installed - run install_onnx_runtime(destdir = tempdir())" + ) } models <- onnx_example_models() diff --git a/tools/setup-dev.R b/tools/setup-dev.R index a9af5ec..9a2877f 100644 --- a/tools/setup-dev.R +++ b/tools/setup-dev.R @@ -1,31 +1,26 @@ # Setup Development Environment -# Run this script to install all dependencies required for development and testing +# Run this script to check dependencies required for development and testing setup_dev_env <- function() { - # CRAN mirror - r_repo <- "https://cloud.r-project.org" - - # Helper to install if missing - install_if_missing <- function(pkg) { - if (!requireNamespace(pkg, quietly = TRUE)) { - message(sprintf("Installing %s...", pkg)) - install.packages(pkg, repos = r_repo) - } + packages <- c( + "devtools", + "testthat", + "roxygen2", + "rcmdcheck", + "rextendr", + "knitr", + "rmarkdown" + ) + missing <- packages[ + !vapply(packages, requireNamespace, logical(1), quietly = TRUE) + ] + if (length(missing)) { + stop( + "Install these development dependencies before continuing: ", + paste(missing, collapse = ", ") + ) } - # Core dev tools - install_if_missing("devtools") - install_if_missing("testthat") - install_if_missing("roxygen2") - install_if_missing("rcmdcheck") - - # Rust interop - install_if_missing("rextendr") - - # Documentation - install_if_missing("knitr") - install_if_missing("rmarkdown") - # Check for system dependencies message("Checking system requirements...") @@ -50,7 +45,9 @@ setup_dev_env <- function() { churon:::onnx_runtime_lib_path() )) } else { - warning("ONNX Runtime not installed. Run churon::install_onnx_runtime()") + warning( + "ONNX Runtime not installed. Run churon::install_onnx_runtime(destdir = tempdir())" + ) } }