Managing dependencies

Last updated on 2024-04-23 | Edit this page

Overview

Questions

  • How can I make my package as easy to install as possible?

Objectives

  • Use the DESCRIPTION file for declaring dependencies

What are dependencies?


Very often, our own code uses functions from a different package. For instance, we used some functions from the package testthat in our episode about testing. When that’s the case, we need the potential users of our package to, at least, have those other packages also installed in their machines. The, so to say, sub-packages, are the dependencies of our package.

Providing a list of dependencies will greatly simplify the task of installing our package. And the DESCRIPTION file provides a simple and handy way of creating this list.

Using the DESCRIPTION file


At this moment, our DESCRIPTION file should look approximately like this:

TXT

Package: mysterycoffee
Type: Package
Title: Simulation of random encounters between couples of persons
Version: 0.1.0
Author: Pablo Rodriguez-Sanchez
Maintainer: Pablo Rodriguez-Sanchez <p.rodriguez-sanchez@esciencecenter.nl>
Description: Simulates random encounters between couples of persons
    This package was inspired by the need to mitigate social isolation in remote
    working environments. The idea is to simulate random encounters at the office's
    coffee machine... when there is no such an office.
License: What license is it under?
Encoding: UTF-8
LazyData: true
RoxygenNote: 7.1.1
Suggests:
    testthat (>= 3.0.0)

The most important keywords to declare dependencies are:

  • Suggests: for recommended dependencies, such as the ones required for testing, creating vignettes (see this episode) or plotting.
  • Imports: for mandatory dependencies, that is, required for the basic functionality of the package.

As we can see in our DESCRIPTION file, the last two lines already contain a dependency statement. Under the category Suggests we can see the package testthat. More specifically, we can see that a version equal or higher than 3.0.0 is suggested.

What do you mean mandatory?

Please note that, even if we tag a dependency as mandatory using the Imports key, it will never be automatically installed by our new package. We have to do install it ourselves. What is then the use of tagging it as mandatory? That now our package is aware that the dependency should be installed, and it is going to throw an error if that’s not the case.

Add some dependencies

Let’s add some dependencies to this list. Particularly, we want you to add:

  • knitr as an mandatory dependency.
  • tidyr as a recommended dependency.

Tip: take a look at the help menu of usethis::use_package().

We can add the new dependencies by:

usethis::use_package("knitr", type = "Imports")
usethis::use_package("tidyr", type = "Suggests")

Please notice how the DESCRIPTION file changed:

TXT

Suggests:
  tidyr,
  testthat (>= 3.0.0)
Imports:
  knitr

If you prefer, you can also add the dependencies by directly editing the DESCRIPTION file. But using usethis::use_package() is handy!

Running devtools::check()


devtools::check() checks for many different things, but here we want to see it in action for dependencies.

Let’s start by adding a function that depends on another package. We use usethis::use_r() to initiate a file for this function:

R

usethis::use_r("make_groups_and_time")

Then add the following function to the file make_groups_and_time.R:

R

#' Make groups of 2 persons and coffee time
#'
#' Randomly arranges a vector of names into a data frame with
#' 3 columns and whatever number of rows is required. The first
#' two columns are the two persons that meet for the coffee; 
#' the last column is the randomly sampled time at which they meet.
#'
#' @param names The vector of names
#'
#' @return A data frame with re-arranged names in groups and assigned coffee time.
#' @export
#'
make_groups_and_time <- function(names) {
  groups <- data.frame(make_groups(names))
  names(groups) <- c("person1", "person2")
  possible_times <- c("09:30", "10:00", "15:15", "15:45")
  groups_and_time <- dplyr::mutate(
    groups,
    coffee_time = sample(possible_times, 
                         size = nrow(groups), 
                         replace = TRUE)
  )
  return(groups_and_time)
}

Challenge

With this in place, or with your own package, do the following. Run devtools::check() (or click [ Build ] > [ Check ]). What messages do you get about dependencies? Optionally, you can address the messages by changing the code, and re-run devtools::check() to see if you were successful.

From running devtools::check() we get:

OUTPUT

W  checking dependencies in R code ...
 '::' or ':::' import not declared from: ‘dplyr’

We can add the dplyr dependency with usethis::use_package("dplyr", type = "imports"). This updates the DESCRIPTION.

Key Points

  • The DESCRIPTION file helps us keeping track of our package’s dependencies