22

I am writing a package that uses tidyeval. Because I use tidyeval I have rlang listed under imports in the description file.

One of the functions contains a few lines that use :=

Like this:

data %>%
    dplyr::mutate(
      !!New_R := AP_R_X*!!X + AP_R_Y*!!Y + AP_R_Z*!!Z,
      !!New_U := AP_U_X*!!X + AP_U_Y*!!Y + AP_U_Z*!!Z,
      !!New_F := AP_F_X*!!X + AP_F_Y*!!Y + AP_F_Z*!!Z) 

The code works as intended but I get the following note when running devtools::check()

 no visible global function definition for ':='

How can I get rid of this note? Is this not a part of rlang evaluation?


EDIT: I have read the question "no visible global function definition for ‘median’, although the answers there explain why such a problem can arise. It does not explain why := is not defined when I have imported rlang. I have edited the question to make this more clear.

jjmerelo
  • 22,578
  • 8
  • 40
  • 86
Steen Harsted
  • 1,802
  • 2
  • 21
  • 34
  • 1
    Add an importFrom statement if you're using `roxygen2`. Not sure if this is from `data.table` or `rlang` or dplyr's `data.table` backend. – NelsonGon Sep 20 '19 at 10:42
  • 1
    Not sure if this answer helps? https://stackoverflow.com/a/31132798/8506921 – Jaccar Sep 20 '19 at 10:43
  • 1
    Possible duplicate of [no visible global function definition for ‘median’](https://stackoverflow.com/questions/31132552/no-visible-global-function-definition-for-median) – NelsonGon Sep 20 '19 at 10:44
  • 1
    I have joined @NelsonGon 's vote to close as a duplicate. To be fully specific on your context, it's from `rlang` – duckmayr Sep 20 '19 at 10:51
  • Thank you for your answers. I have updated the question as I don't think this is a duplicate question. – Steen Harsted Sep 20 '19 at 10:56
  • Could you link to the entire code if possible or add it to the question for more context? – NelsonGon Sep 20 '19 at 11:08
  • 2
    Your update clarified the problem for me. Your issue is that you `Import` `rlang` in the `DESCRIPTION` file, but you **still** need `NAMESPACE` directives – duckmayr Sep 20 '19 at 11:13

3 Answers3

35

After you updated your answer, to me, this is sort of on the line of whether it's a full duplicate or not. The only difference here is that you've added rlang to Imports in DESCRIPTION and haven't seen the difference between that and a NAMESPACE directive.

I mocked up an example package to show this isn't sufficient. First, I set up the package:

library(devtools)
create("anExample", rstudio = FALSE, open = FALSE)

Then, I add the example function from https://dplyr.tidyverse.org/articles/programming.html to a file R/my_mutate.R:

#' A function
#'
#' @param df A dataframe
#' @param expr A variable in the dataframe
#'
#' @return The dataframe with new mean and sum columns
#' @export
my_mutate <- function(df, expr) {
    expr <- enquo(expr)
    mean_name <- paste0("mean_", quo_name(expr))
    sum_name <- paste0("sum_", quo_name(expr))

    mutate(df,
           !! mean_name := mean(!! expr),
           !! sum_name := sum(!! expr)
    )
}

Notice there are no roxygen2 namespace tags. I make sure to add rlang and dplyr to Imports in DESCRIPTION and run devtools::document(). Then when I run devtools::check() I get the following:

my_mutate: no visible global function definition for ‘enquo’
  my_mutate: no visible global function definition for ‘quo_name’
  my_mutate: no visible global function definition for ‘mutate’
  my_mutate: no visible global function definition for ‘:=’
  Undefined global functions or variables:
    := enquo mutate quo_name

0 errors ✔ | 1 warning ✖ | 1 note ✖

However, if I change R/my_mutate.R to the following:

#' A function
#'
#' @param df A dataframe
#' @param expr A variable in the dataframe
#'
#' @return The dataframe with new mean and sum columns
#' @importFrom dplyr mutate
#' @importFrom rlang enquo
#' @importFrom rlang quo_name
#' @importFrom rlang :=
#' @export
my_mutate <- function(df, expr) {
    expr <- enquo(expr)
    mean_name <- paste0("mean_", quo_name(expr))
    sum_name <- paste0("sum_", quo_name(expr))

    mutate(df,
           !! mean_name := mean(!! expr),
           !! sum_name := sum(!! expr)
    )
}

When I run devtools::check() (after re-document()ing), I do not get that note.

Long story short, Import in DESCRIPTION is not sufficient. You also need NAMESPACE directives.

duckmayr
  • 16,303
  • 3
  • 35
  • 53
  • For easy access, put all your `@import` and `@importFrom` instructions in the header of `R/anExample.R`. See section 10.6 Documenting Packages -- https://r-pkgs.org/man.html – Gabi Nov 24 '21 at 19:14
3

Update from June 2023

You should run usethis::use_import_from("rlang", ":=").

usethis::use_import_from("rlang", ":=") will import the := function from rlang using the @importFrom tag in the package level documentation. For more information, check out the documentation here.

This will change you package level documentation to look something like:

@keywords internal
"_PACKAGE"

## usethis namespace: start
#' @importFrom rlang :=
## usethis namespace: end
NULL

Read more about this documentation in the R packages book here and here.

If you would like to use more tidy-eval functions from rlang, you should import them using usethis::use_import_from().

usethis::use_tidy_eval has been marked as defunct as of usethis 2.2.0 since it imports and re-exports an unnecessary amount of functions (see the issue here and the release notes here.

Older Update (March 2023)

I wanted to add an update as of 2023 - you can now run usethis::use_tidy_eval() to handle this issue. The function will automatically import rlang::dyn-dots, or rlang::`:=` , along with rlang::enquo, rlang::enquos, rlang::.data, rlang::as_name, and rlang::as_label to take care of potential notes that will appear while using tidyeval. These will appear in a new file titled utils-tidy-eval.R. For a little more info, the documentation is here.

This function will essentially do the same thing as the accepted answer, but it creates a new file to hold these @importFrom functions, and it creates documentation for these imports within your package.

TLDR: Just run usethis::use_tidy_eval()

mfg3z0
  • 561
  • 16
1

See Data masking and tidy selection NOTEs in Using dplyr in packages. The example is for .data, you can change it to :=.

Summarising you must do at the console:

usethis::use_import_from("rlang", ":=")

This command adds a line with the content #' @importFrom rlang := in a file with the form yourpackagename-package.R that Roxigen understands and adds the necessary entry in the NAMESPACE file when you run devtools::document() (or any other command that does, as devtools::check()).

victe
  • 516
  • 6
  • 8