diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index c4eafb3..a8e0d97 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -12,6 +12,8 @@ on: name: R-CMD-check +permissions: read-all + jobs: R-CMD-check: runs-on: ${{ matrix.config.os }} @@ -22,19 +24,18 @@ jobs: fail-fast: false matrix: config: - - {os: macOS-latest, r: 'release'} + - {os: macos-latest, r: 'release'} - {os: windows-latest, r: 'release'} - # Use 3.6 to trigger usage of RTools35 - - {os: windows-latest, r: '3.6'} + # use 4.1 to check with rtools40's older compiler + - {os: windows-latest, r: '4.1'} - # Use older ubuntu to maximise backward compatibility - - {os: ubuntu-20.04, r: 'devel', http-user-agent: 'release'} - - {os: ubuntu-20.04, r: 'release'} - - {os: ubuntu-20.04, r: 'oldrel-1'} - - {os: ubuntu-20.04, r: 'oldrel-2'} - - {os: ubuntu-20.04, r: 'oldrel-3'} - - {os: ubuntu-20.04, r: 'oldrel-4'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + - {os: ubuntu-latest, r: 'oldrel-2'} + - {os: ubuntu-latest, r: 'oldrel-3'} + - {os: ubuntu-latest, r: 'oldrel-4'} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} @@ -62,3 +63,4 @@ jobs: - uses: r-lib/actions/check-r-package@v2 with: upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 8f0272c..c9f0165 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -11,6 +11,8 @@ on: name: pkgdown +permissions: read-all + jobs: pkgdown: runs-on: ubuntu-latest @@ -19,6 +21,8 @@ jobs: group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write steps: - uses: actions/checkout@v4 @@ -39,7 +43,7 @@ jobs: - name: Deploy to GitHub pages 🚀 if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@4.1.4 + uses: JamesIves/github-pages-deploy-action@v4.5.0 with: clean: false branch: gh-pages diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml index eea58c5..d1f7650 100644 --- a/.github/workflows/pr-commands.yaml +++ b/.github/workflows/pr-commands.yaml @@ -6,6 +6,8 @@ on: name: Commands +permissions: read-all + jobs: document: if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index d9d5c3d..fefc52e 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -8,6 +8,8 @@ on: name: test-coverage +permissions: read-all + jobs: test-coverage: runs-on: ubuntu-latest @@ -23,9 +25,37 @@ jobs: - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: any::covr + extra-packages: any::covr, any::xml2 needs: coverage - name: Test coverage - run: covr::codecov(quiet = FALSE) + run: | + cov <- covr::package_coverage( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) + covr::to_cobertura(cov) shell: Rscript {0} + + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} + file: ./cobertura.xml + plugin: noop + disable_search: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/DESCRIPTION b/DESCRIPTION index e98931e..00bb5d8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,57 +1,33 @@ Package: withr Title: Run Code 'With' Temporarily Modified Global State Version: 3.0.0.9000 -Authors@R: - c(person(given = "Jim", - family = "Hester", - role = "aut"), - person(given = "Lionel", - family = "Henry", - role = c("aut", "cre"), - email = "lionel@posit.co"), - person(given = "Kirill", - family = "Müller", - role = "aut", - email = "krlmlr+r@mailbox.org"), - person(given = "Kevin", - family = "Ushey", - role = "aut", - email = "kevinushey@gmail.com"), - person(given = "Hadley", - family = "Wickham", - role = "aut", - email = "hadley@posit.co"), - person(given = "Winston", - family = "Chang", - role = "aut"), - person(given = "Jennifer", - family = "Bryan", - role = "ctb"), - person(given = "Richard", - family = "Cotton", - role = "ctb"), - person(given = "Posit Software, PBC", - role = c("cph", "fnd"))) -Description: A set of functions to run code 'with' safely and - temporarily modified global state. Many of these functions were - originally a part of the 'devtools' package, this provides a simple - package with limited dependencies to provide access to these - functions. +Authors@R: c( + person("Jim", "Hester", role = "aut"), + person("Lionel", "Henry", , "lionel@posit.co", role = c("aut", "cre")), + person("Kirill", "Müller", , "krlmlr+r@mailbox.org", role = "aut"), + person("Kevin", "Ushey", , "kevinushey@gmail.com", role = "aut"), + person("Hadley", "Wickham", , "hadley@posit.co", role = "aut"), + person("Winston", "Chang", role = "aut"), + person("Jennifer", "Bryan", role = "ctb"), + person("Richard", "Cotton", role = "ctb"), + person("Posit Software, PBC", role = c("cph", "fnd")) + ) +Description: A set of functions to run code 'with' safely and temporarily + modified global state. Many of these functions were originally a part + of the 'devtools' package, this provides a simple package with limited + dependencies to provide access to these functions. License: MIT + file LICENSE -URL: https://withr.r-lib.org, - https://github.com/r-lib/withr#readme +URL: https://withr.r-lib.org, https://github.com/r-lib/withr#readme BugReports: https://github.com/r-lib/withr/issues Depends: R (>= 3.5.0) Imports: graphics, - grDevices, + grDevices Suggests: callr, - covr, DBI, knitr, - lattice, methods, rlang, rmarkdown (>= 2.12), @@ -59,9 +35,11 @@ Suggests: testthat (>= 3.0.0) VignetteBuilder: knitr +Config/Needs/website: tidyverse/tidytemplate +Config/testthat/edition: 3 Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.0.9000 +RoxygenNote: 7.3.2 Collate: 'aaa.R' 'collate.R' @@ -93,5 +71,3 @@ Collate: 'torture.R' 'utils.R' 'with.R' -Config/testthat/edition: 3 -Config/Needs/website: tidyverse/tidytemplate diff --git a/R/torture.R b/R/torture.R index cb7e9a6..1b08e42 100644 --- a/R/torture.R +++ b/R/torture.R @@ -4,6 +4,7 @@ #' #' @template with #' @param new `[integer]`\cr run GC every 'step' allocations. +#' @param wait integer; number of allocations to wait before starting GC torture. #' @inheritParams base::gctorture #' @inheritParams local_ with_gctorture2 <- with_(gctorture2) diff --git a/R/with.R b/R/with.R index 745d3fd..51a1b5b 100644 --- a/R/with.R +++ b/R/with.R @@ -59,3 +59,6 @@ #' } #' Sys.getenv("WITHR") "_PACKAGE" + +# Enable pkgload to hotpatch `::` in detached namespaces +on_load(`::` <- base::`::`) diff --git a/man/devices.Rd b/man/devices.Rd index acb45af..11ed45b 100644 --- a/man/devices.Rd +++ b/man/devices.Rd @@ -224,7 +224,7 @@ local_jpeg(new = list(), ..., .local_envir = parent.frame()) string specify a font family to be searched for in a system-dependent way. - On unix-alikes (incl.\\ Mac), see + On unix-alikes (incl.\\ macOS), see the \sQuote{Cairo fonts} section in the help for \code{\link[grDevices]{X11}}. } @@ -247,16 +247,32 @@ local_jpeg(new = list(), ..., .local_envir = parent.frame()) The default is \code{"special"}, which means that the \code{width} and \code{height} specify the paper size. A further choice is \code{"default"}; if this is selected, the - papersize is taken from the option \code{"papersize"} + paper size is taken from the option \code{"papersize"} if that is set and as \code{"a4"} if it is unset or empty. Defaults to \code{"special"}. } -\item{encoding}{the name of an encoding file. See - \code{\link[grDevices]{postscript}} for details. Defaults to \code{"default"}.} +\item{encoding}{the name of an encoding file. Defaults to + \code{"default"}. The latter is interpreted + \describe{ + \item{on Unix-alikes}{ + as \file{"ISOLatin1.enc"} unless the locale is recognized as + corresponding to a language using ISO 8859-\{2,5,7,13,15\} or KOI8-\{R,U\}. + } + \item{on Windows}{ + as \file{"CP1250.enc"} (Central European), \code{"CP1251.enc"} (Cyrillic), + \code{"CP1253.enc"} (Greek) or \code{"CP1257.enc"} (Baltic) if one + of those codepages is in use, otherwise \file{"WinAnsi.enc"} + (codepage 1252). + } + } + The file is looked for in the \file{enc} directory of package + \pkg{grDevices} if the path does not contain a path separator. An + extension \code{".enc"} can be omitted. + } \item{bg}{the initial background colour: can be overridden by setting - par("bg").} + \code{par("bg")}.} \item{fg}{the initial foreground color to be used. Defaults to \code{"black"}.} @@ -275,7 +291,7 @@ local_jpeg(new = list(), ..., .local_envir = parent.frame()) \item{useDingbats}{logical. Should small circles be rendered \emph{via} the Dingbats font? Defaults to \code{FALSE}. If \code{TRUE}, this can produce smaller and better output, but - there can font display problems in broken PDF viewers: although this + can cause font display problems in broken PDF viewers: although this font is one of the 14 guaranteed to be available in all PDF viewers, that guarantee is not always honoured. @@ -307,11 +323,11 @@ length limit is \code{2*PATH_MAX}, typically 8096 bytes on unix systems and \item{antialias}{string, the type of anti-aliasing (if any) to be used; defaults to \code{"default"}.} -\item{defaultfont}{logical: should the device use xfig's default +\item{defaultfont}{logical: should the device use XFig's default font?} \item{textspecial}{logical: should the device set the textspecial flag - for all text elements. This is useful when generating pstex from xfig + for all text elements? This is useful when generating pstex from XFig figures.} } \value{ diff --git a/man/with_gctorture2.Rd b/man/with_gctorture2.Rd index da93d0e..61126db 100644 --- a/man/with_gctorture2.Rd +++ b/man/with_gctorture2.Rd @@ -11,8 +11,7 @@ with_gctorture2(new, code, wait = new, inhibit_release = FALSE) \item{code}{\code{[any]}\cr Code to execute in the temporary environment} -\item{wait}{integer; number of allocations to wait before starting - GC torture.} +\item{wait}{integer; number of allocations to wait before starting GC torture.} \item{inhibit_release}{logical; do not release free objects for re-use: use with caution.} diff --git a/man/with_tempfile.Rd b/man/with_tempfile.Rd index 9a9f9d5..6f4a479 100644 --- a/man/with_tempfile.Rd +++ b/man/with_tempfile.Rd @@ -55,9 +55,9 @@ local_tempdir( \item{pattern}{a non-empty character vector giving the initial part of the name.} -\item{tmpdir}{a non-empty character vector giving the directory name} +\item{tmpdir}{a non-empty character vector giving the directory name.} -\item{fileext}{a non-empty character vector giving the file extension} +\item{fileext}{a non-empty character vector giving the file extension.} \item{lines}{Optionally, supply a character vector of lines to be written to \code{path}. This is useful if you want to seed the file with some default diff --git a/tests/testthat/_snaps/defer.md b/tests/testthat/_snaps/defer.md index f1a6fae..de90ea5 100644 --- a/tests/testthat/_snaps/defer.md +++ b/tests/testthat/_snaps/defer.md @@ -35,7 +35,7 @@ Output - ```r + ``` r withr::deferred_run() ``` @@ -43,7 +43,7 @@ ## No deferred expressions to run ``` - ```r + ``` r defer(writeLines('1')) writeLines('2') ``` @@ -52,11 +52,11 @@ ## 2 ``` - ```r + ``` r defer(writeLines('3')) ``` - ```r + ``` r writeLines('4') ``` @@ -64,7 +64,7 @@ ## 4 ``` - ```r + ``` r withr::deferred_run() ``` diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index a90b3cb..b8f6cdc 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -1,7 +1,3 @@ -set_state_inspector(function() { - dir(".") -}) - expect_no_output <- function(...) { testthat::expect_output(..., regexp = NA) } diff --git a/tests/testthat/test-devices.R b/tests/testthat/test-devices.R index 2858846..2993e64 100644 --- a/tests/testthat/test-devices.R +++ b/tests/testthat/test-devices.R @@ -6,76 +6,36 @@ skip_if_needs_cairo <- function(fn) { } test_that("with_*device* functions create a plot file", { - skip_if_not_installed("lattice") - # A plot - p <- lattice::xyplot(y ~ x, data.frame(x = -2:2, y = dnorm(-2:2))) - - # A directory to store the plots - plot_dir <- tempfile("withr-test-plots-") - dir.create(plot_dir) - fn_names <- c("with_bmp", "with_jpeg", "with_pdf", "with_png", - "with_tiff", "with_xfig", "with_svg", "with_cairo_pdf", "with_cairo_ps") + "with_tiff", "with_svg", "with_cairo_pdf", "with_cairo_ps") fns <- mget(fn_names, envir = asNamespace("withr")) - extensions <- c("bmp", "pdf", "ps", "jpg", "pdf", "png", "tiff", "xfig", "svg", "pdf", "ps") for (i in seq_along(fns)) { skip_if_needs_cairo(fn_names[[i]]) - filename <- file.path(plot_dir, paste0("test-", fn_names[i], ".", extensions[i])) - info <- paste0("function = ", fn_names[i], "; filename = ", filename) - if (fn_names[i] == "with_xfig") { - # grDevices::xfig weirdly gives a warning with the default inputs - expect_warning( - fns[[i]](filename, print(p)), - "will only return the last plot" - ) - } else { - expect_silent(fns[[i]](filename, print(p))) - } - expect_true(file.exists(filename), info = info) - expect_gt(file.info(filename)$size, 0, label = info) + filename <- withr::local_tempfile() + expect_no_error(fns[[i]](filename, plot(1))) + expect_true(file.exists(filename), info = fn_names[[i]]) + expect_gt(file.info(filename)$size, 0, label = fn_names[[i]]) } - - unlink(plot_dir) }) test_that("local_device functions create a plot file", { - skip_if_not_installed("lattice") - # A plot - p <- lattice::xyplot(y ~ x, data.frame(x = -2:2, y = dnorm(-2:2))) - - # A directory to store the plots - plot_dir <- tempfile("withr-test-plots-local-") - dir.create(plot_dir) - fn_names <- c("local_bmp", "local_jpeg", "local_pdf", "local_png", - "local_tiff", "local_xfig", "local_svg", "local_cairo_pdf", "local_cairo_ps") + "local_tiff", "local_svg", "local_cairo_pdf", "local_cairo_ps") fns <- mget(fn_names, envir = asNamespace("withr")) - extensions <- c("bmp", "pdf", "ps", "jpg", "pdf", "png", "tiff", "xfig", "svg", "pdf", "ps") - for (i in seq_along(fns)) { skip_if_needs_cairo(fn_names[[i]]) - filename <- file.path(plot_dir, paste0("test-", fn_names[i], ".", extensions[i])) - info <- paste0("function = ", fn_names[i], "; filename = ", filename) - (function(i) { - if (fn_names[i] == "local_xfig") { - # grDevices::xfig weirdly gives a warning with the default inputs - expect_warning( - fns[[i]](filename), - "will only return the last plot") - } else { - expect_silent(fns[[i]](filename)) - } - print(p) - })(i) - expect_true(file.exists(filename), info = info) - expect_gt(file.info(filename)$size, 0, label = info) + filename <- withr::local_tempfile() + local({ + expect_no_error(fns[[i]](filename)) + plot(1) + }) + expect_true(file.exists(filename), info = fn_names[[i]]) + expect_gt(file.info(filename)$size, 0, label = fn_names[[i]]) } - - unlink(plot_dir) }) test_that("multiple devices closed in correct order", { diff --git a/tests/testthat/test-par.R b/tests/testthat/test-par.R index 7221c85..8609035 100644 --- a/tests/testthat/test-par.R +++ b/tests/testthat/test-par.R @@ -6,7 +6,6 @@ test_that("with_par works as expected", { expect_equal(par("pty"), "s") }) expect_equal(par("pty"), old) - dev.off() }) test_that("local_par works as expected", {