context("formals") fmt_formals <- function(f) { formatted <- vapply(names(f), function(n) { v <- as.character(f[[n]]) if (is.null(f[[n]])) paste(n, '= NULL') else if (nchar(v) == 0) n else paste(n, '=', v) }, character(1)) sprintf('(%s)', paste(formatted, collapse = ', ')) } expect_formals <- function(given, expected) { if (is.character(given)) { sig <- given object <- py_eval(sprintf('lambda %s: None', given)) given <- py_get_formals(object) } else { sig <- '?' } info <- sprintf('(%s)/%s != %s', sig, fmt_formals(given), fmt_formals(expected)) expect_identical(as.list(given), expected, info) } test_that("Python signatures convert properly", { skip_if(py_version() < "3.3") expect_formals('a', alist(a = )) expect_formals('a, b=1', alist(a = , b = 1L)) expect_formals('a, *, b=1', alist(a = , ... = , b = 1L)) expect_formals('a, *args, b=1', alist(a = , ... = , b = 1L)) expect_formals('a, b=1, **kw', alist(a = , b = 1L, ... = )) expect_formals('a, *args, **kw', alist(a = , ... = )) expect_formals('a, *args, b=1, **kw', alist(a = , ... = , b = 1L)) }) test_that("Errors from e.g. builtins are not propagated", { skip_if(py_version() < "3.3") print <- import_builtins()$print expect_no_error(py_get_formals(print)) }) test_that("The inspect.Parameter signature converts properly", { skip_if(py_version() < "3.3") # Parameter.empty usually signifies no default parameter, # but for args 3 and 4 here, it *is* the default parameter. inspect <- import("inspect", convert = TRUE) Parameter <- inspect$Parameter fmls <- py_get_formals(Parameter) expect_formals(fmls, alist( name = , kind = , ... = , default = , annotation = )) }) test_that("Parameters are not matched by prefix", { skip_if(py_version() < "3.3") f_r <- function(long = NULL, ...) list(long, list(...)) f_py <- py_eval('lambda long=None, **kw: (long, kw)') expect_identical(formals(f_r), py_get_formals(f_py)) if(getRversion() >= "3.6") { op <- options(warnPartialMatchArgs = FALSE) on.exit(options(op)) } # Normal R functions match partially: expect_identical(f_r(l = 2L), list(2L, list())) # Python functions behave as expected: expect_identical(f_py(l = 2L), list(NULL, list(l = 2L))) })