tests/testthat/test-py_func.R

context("function wrapping")

test_that("R functions can be wrapped in a Python function with the same signature", {
  skip_if_no_python()

  # R function
  f1 <- function(a, b = 3) {
    a + b
  }

  # The same function but re-written in Python
  util <- py_run_string("
def f1(a, b=3):
  return a + b
")

  # signatures should match
  inspect <- import("inspect")
  expect_equal(
    inspect$getfullargspec(py_func(f1)),
    inspect$getfullargspec(util$f1))

  # results should match
  expect_equal(
    py_func(f1)(1),
    util$f1(1))
  expect_equal(
    py_func(f1)(1, 2),
    util$f1(1, 2))
  expect_equal(
    py_func(f1)(a = 1, b = 2),
    util$f1(a = 1, b = 2))

  has_args <- function(f) {
    length(inspect$getfullargspec(f)$args) != 0
  }
  # Some micellaneous test cases which should not fail
  expect_true(has_args(py_func(function(a = c(1, 2, 3)) {})))
  expect_true(has_args(py_func(function(a = NULL) {})))
  expect_true(has_args(py_func(function(a = "abc") {})))
  expect_true(has_args(py_func(function(a, b = 3) {})))
  expect_true(has_args(py_func(function(a = list()) {})))
  expect_true(has_args(py_func(function(a = list("a", 1, list(3, "b", NULL))) {})))
  # TODO: test case for py_func(function(x = NA) {})
  # currently blocked by https://github.com/rstudio/reticulate/issues/197

  # Should error out if the R function's signature
  # contains esoteric Python-incompatible constructs
  expect_error(py_func(function(a = 1, b) {}))
  expect_error(py_func(function(a.b) {}))
})

test_that("R functions wrapped in py_main_thread_func are called on the main thread", {
  skip_if_no_python()
  expect_equal(test$invokeOnThread(py_main_thread_func(function(x) x + 1), 41), 42)
})

Try the reticulate package in your browser

Any scripts or data that you put into this service are public.

reticulate documentation built on Oct. 13, 2023, 1:08 a.m.