使用testthat测试含reticulate::source_python的R函数时遇状态9错误求助
Let’s break down why you’re hitting that status 9 error and how to fix it. This error usually pops up when there’s an issue with how reticulate interacts with the Python environment during testing, or with repeated imports causing conflicts.
First, Let’s Diagnose the Likely Causes
- Uninitialized Python Environment: Testthat runs in a clean session, so reticulate might not have picked up a valid Python interpreter automatically.
- Repeated Module Imports: Your current
f1_sourced_from_python()function callssource_pythonevery time it runs. This can lead to duplicate definitions or environment clashes in the test session. - Incorrect File Path: If your package structure isn’t set up right,
system.filemight not be finding your Python module during testing.
Step-by-Step Fixes
1. Fix Your Package Structure
Make sure your Python module lives in the inst/python directory of your package—this is where system.file looks for files by default. Your structure should look like this:
test_package/ ├── R/ │ └── your_function_file.R ├── inst/ │ └── python/ │ └── the_py_module.py └── tests/ └── testthat/ └── test_f1.R
2. Optimize the R Function to Avoid Repeated Imports
Instead of importing the Python module every time the function runs, import it once when the package loads. This prevents conflicts in test sessions:
# Import the Python module once when the package is loaded .onLoad <- function(libname, pkgname) { reticulate::source_python( system.file("python", "the_py_module.py", package = pkgname, mustWork = TRUE) ) } #' Testing F1 function sourced from python #' @return "f one" #' @export f1_sourced_from_python <- function() { f1() # Now f1 is already available from the package load }
If you need to keep the import inside the function (for rare cases), add a check to avoid re-importing:
#' Testing F1 function sourced from python #' @return "f one" #' @export f1_sourced_from_python <- function() { # Only import if the function doesn't exist yet if (!exists("f1", envir = parent.env(environment()))) { reticulate::source_python( system.file("python", "the_py_module.py", package = "test_package", mustWork = TRUE) ) } f1() }
3. Explicitly Initialize Python Environment in Tests
Testthat starts with a fresh session, so tell reticulate exactly which Python environment to use at the start of your test:
test_that("Testing sourcing python file in testthat", { # Point to your Python interpreter or virtual environment # Use use_virtualenv/use_condaenv if you're using those reticulate::use_python("/path/to/your/python/interpreter", required = TRUE) output <- f1_sourced_from_python() expect_type(output, "character") # expect_type is more precise than is_a here })
4. Test with the Right Workflow
Make sure you’re testing the installed version of your package (or run devtools::load_all() before running tests). Running tests directly on the script without loading the package can cause path issues. Use devtools::test() or the Testthat pane in RStudio to run your tests properly.
Verify the Fix
After making these changes, run your test again. The status 9 error should disappear because we’ve stabilized the Python environment and eliminated repeated import conflicts.
内容的提问来源于stack exchange,提问作者John

