8  Package Maintenance

Recording

How to run CMD-check to make sure everything is put together right, and how to troubleshoot the inevitable problems.

Packages required for this chapter
library(usethis)
library(devtools)

8.1 CMD Check

You can run diagnostic tests on your package by clicking the Check button in the Build tab, or with the function devtools::check(). This will:

  • Update documentation
  • Build your package manual and vignettes
  • Check the format of the DESCRIPTION file
  • Run a variety of checks
  • Run the function documentation examples
  • Run the unit tests

Ideally, you’ll see a bunch of green checks for a minute or two, and then this output:

── R CMD check results ── demopkg 0.0.0.9008 ──
Duration: 13.2s

0 errors ✔ | 0 warnings ✔ | 0 notes ✔

Errors are things you really have to fix, warnings should probably be fixed but often won’t break your package, and notes are optional unless you’re submitting to CRAN.

Goose from untitled goose game witht he words: I think I will cause problems on purpose

Unfortunately, in real package development that’s rare enough to be exciting. Let’s make a few things go wrong so we can see what that looks like.

8.2 Unit Tests

What if a test produces an unexpected warning or error? Create a new test file so we can make some mistakes.

run in the console
usethis::use_test("error")

In the file that opens up, edit the demo test to create an error and add a new test that creates a warning.

tests/testhat/test-error.R
test_that("error", {
  expect_equal(2 * 2, 5)
})

test_that("warning", {
  expect_false(all(1:2 == 1:3))
})
Note

The second test should produce the warning “longer object length is not a multiple of shorter object length”. If you check for equivalence of vectors that have different lengths, the shorter one is “recycled”.

1:2 == rep(1:2, 2)
[1] TRUE TRUE TRUE TRUE

If the length of the shorter vector doesn’t divide evenly into the length of the longer one, you will get a warning, but the result will be as expected. If you are writing code where this might happen and isn’t a problem, you can suppress warnings.

suppressWarnings(
  1:2 == rep(1:2, length.out = 5)
)
[1] TRUE TRUE TRUE TRUE TRUE

Save the test file and run the CMD check again. You can skip building the vignettes if they take too long.

run in the console
devtools::check(vignettes = FALSE)

You will see the normal test output at the end, which will have a lot of text about the errors. The test section will conclude with [ FAIL 1 | WARN 1 | SKIP 0 | PASS 8 ] and then the CMD check summary will display:

1 error ✖ | 0 warnings ✔ | 0 notes ✔
Error: R CMD check found ERRORs
Execution halted

Exited with status 1.

This one is pretty easy to figure out because the error is right before the CMD check summary. Typically, I would run the tests separately (see Section 5.5) because the output is better for figuring out the problem. This will tell us that our failed and warning tests were in test-error.R and give error messages of variable helpfulness.

Failure (test-error.R:2:3): error
2 * 2 (`actual`) not equal to 5 (`expected`).

  `actual`: 4
`expected`: 5

Warning (test-error.R:6:3): warning
longer object length is not a multiple of shorter object length
Backtrace:
 1. testthat::expect_false(all(1:2 == 1:3))
      at test-error.R:6:2
 2. testthat::quasi_label(enquo(object), label, arg = "object")
 3. rlang::eval_bare(expr, quo_get_env(quo))

You can find the approximate location of the problem in this text, “Failure (test-error.R:2:3)”, which means that the error is in the file test-error.R on line 2 and character 3. Sometimes the actual error is before or after this point, but it’s a good place to start.

Warning

Remember to delete the file test-error.R after this exercise!

8.3 DESCRIPTION

Now let’s make an error in the DESCRIPTION file. Delete one of the commas under “Suggests:”. I recommend adding package dependencies to this file using usethis::use_package() because I often cause this error when I do it manually.

Suggests: 
    dplyr,
    knitr,
    rmarkdown
    testthat (>= 3.0.0)

Save the file and re-run the CMD check. The CMD check will end with:

Execution halted

Exited with status 1.

Scroll back until you see a red line reading:

E  checking DESCRIPTION meta-information ...

This will be followed by a somewhat helpful human-readable message, and then dozens of lines of backtrace that you can ignore. This message at least alerts you to the fact that the problem is in your DESCRIPTION file and near “rmarkdown” and “testthat (>= 3.0.0)”. You can fix the comma now.

Another common DESCRIPTION error is with the format of the Authors list. Remove the last round bracket, save the file and re-run the CMD check.

Authors@R: 
    person(given = "Lisa",
           family = "DeBruine",
           role = c("aut", "cre"),
           email = "debruine@gmail.com",
           comment = c(ORCID = "0000-0002-7523-5539")

You will again see that the check terminates with a red error message: “Exited with status 1.” Scroll back up to the red error message to see that the problem was “Malformed Authors@R field”. This is almost always a problem with commas or brackets. Go add the bracket back in.

A slightly more esoteric problem will be flagged if you delete the full stop from the end of your Description. The CMD check will succeed, but will give you the following note:

❯ checking DESCRIPTION meta-information ... NOTE
  Malformed Description field: should contain one or more complete sentences.

0 errors ✔ | 0 warnings ✔ | 1 note ✖

R CMD check succeeded

Add the full stop back in.

8.4 Unexpected files

You’ll also get a warning if there are unexpected files in your package directory that aren’t included in .Rbuildignore. Open up that file and delete ^pkgdown$. This should produce the following note.

❯ checking top-level files ... NOTE
  Non-standard file/directory found at top level:
    ‘pkgdown’

0 errors ✔ | 0 warnings ✔ | 1 note ✖

The .Rbuildignore file uses regex to match files, so the easiest way to add a directory or file to it is to use a function from usethis.

run in the console
usethis::use_build_ignore("pkgdown")

8.5 Function documentation

You will also get check errors if your function documentation doesn’t match the function. Open up a function and change the name of one argument in the roxygen documentation to an argument that doesn’t exist (e.g., change the argument x to z).

R/apa_t_pair.R
#' @param z A vector of the values for level 1.

Save the file and run CMD check. You will get the following warning:

❯ checking Rd \usage sections ... WARNING
  Undocumented arguments in documentation object 'apa_t_pair'
    ‘x’

8.6 Large files

If you have large file or the total package size is too big, you will get a warning. You can ignore this unless you’re planning on submitting to CRAN.

To test this, add a file that is 5MB or larger to the inst directory (or run the code below) and run the CMD check.

run in the console
# downloads a 5.1 MB file to your inst directory
download.file("https://webmorph.org/include/images/gifs/id.gif", "inst/delete_me.gif")

You’ll get a note like this.

❯ checking installed package size ... NOTE
    installed size is  5.6Mb

0 errors ✔ | 0 warnings ✔ | 1 note ✖

8.7 Glossary

term definition
argument A variable that provides input to a function.
cran The Comprehensive R Archive Network: a network of ftp and web servers around the world that store identical, up-to-date, versions of code and documentation for R.
vector A type of data structure that collects values with the same data type, like T/F values, numbers, or strings.

8.8 Further Resources