Skip to content

Commit

Permalink
$get_used() is relative to $current_vars(), not names(.data) (#5584)
Browse files Browse the repository at this point in the history
* $get_used() is relative to $current_vars(), not names(.data)

* `mutate()` always keeps grouping variables, unconditional to `.keep=`

closes #5582

* documentation update for mutate(.keep=)

* testthat update
  • Loading branch information
romainfrancois committed Nov 4, 2020
1 parent 3652eb5 commit df43c73
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 8 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Expand Up @@ -7,6 +7,8 @@

* `across()` handles data frames with 0 columns (#5523).

* `mutate()` always keeps grouping variables, unconditional to `.keep=` (#5582).

# dplyr 1.0.2

* Fixed `across()` issue where data frame columns would mask objects referred to
Expand Down
16 changes: 11 additions & 5 deletions R/mutate.R
Expand Up @@ -161,6 +161,8 @@ mutate <- function(.data, ...) {
#' * `"unused"` keeps only existing variables **not** used to make new
#' variables.
#' * `"none"`, only keeps grouping keys (like [transmute()]).
#'
#' Grouping variables are always kept, unconditional to `.keep`.
#' @param .before,.after \Sexpr[results=rd]{lifecycle::badge("experimental")}
#' <[`tidy-select`][dplyr_tidy_select]> Optionally, control where new columns
#' should appear (the default is to add to the right hand side). See
Expand All @@ -185,12 +187,14 @@ mutate.data.frame <- function(.data, ...,
if (keep == "all") {
out
} else if (keep == "unused") {
unused <- c(names(.data)[!attr(cols, "used")])
keep <- intersect(names(out), c(unused, names(cols)))
used <- attr(cols, "used")
unused <- names(used)[!used]
keep <- intersect(names(out), c(group_vars(.data), unused, names(cols)))
dplyr_col_select(out, keep)
} else if (keep == "used") {
used <- names(.data)[attr(cols, "used")]
keep <- intersect(names(out), c(used, names(cols)))
used <- attr(cols, "used")
used <- names(used)[used]
keep <- intersect(names(out), c(group_vars(.data), used, names(cols)))
dplyr_col_select(out, keep)
} else if (keep == "none") {
keep <- c(
Expand Down Expand Up @@ -383,6 +387,8 @@ mutate_cols <- function(.data, ...) {

is_zap <- map_lgl(new_columns, inherits, "rlang_zap")
new_columns[is_zap] <- rep(list(NULL), sum(is_zap))
attr(new_columns, "used") <- mask$get_used()
used <- mask$get_used()
names(used) <- mask$current_vars()
attr(new_columns, "used") <- used
new_columns
}
4 changes: 3 additions & 1 deletion man/mutate.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions tests/testthat/test-deprec-combine-errors.txt
@@ -1,6 +1,12 @@
> combine("a", 1)
Warning: `combine()` is deprecated as of dplyr 1.0.0.
Please use `vctrs::vec_c()` instead.

Error: Can't combine `..1` <character> and `..2` <double>.

> combine(factor("a"), 1L)
Warning: `combine()` is deprecated as of dplyr 1.0.0.
Please use `vctrs::vec_c()` instead.

Error: Can't combine `..1` <factor<127a2>> and `..2` <integer>.

2 changes: 0 additions & 2 deletions tests/testthat/test-deprec-dbi-errors.txt
@@ -1,8 +1,6 @@
> src_sqlite(":memory:")
Warning: `src_sqlite()` is deprecated as of dplyr 1.0.0.
Please use `tbl()` directly with a database connection
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.

Error: `path` must already exist, unless `create` = TRUE.

24 changes: 24 additions & 0 deletions tests/testthat/test-deprec-funs-errors.txt
@@ -1,10 +1,34 @@
> funs(function(si) {
+ mp[si]
+ })
Warning: `funs()` is deprecated as of dplyr 0.8.0.
Please use a list of either functions or lambdas:

# Simple named list:
list(mean = mean, median = median)

# Auto named with `tibble::lst()`:
tibble::lst(mean, median)

# Using lambdas
list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

Error: `function(si) {
mp[si]
}` must be a function name (quoted or unquoted) or an unquoted call, not `function`.

> funs(~mp[.])
Warning: `funs()` is deprecated as of dplyr 0.8.0.
Please use a list of either functions or lambdas:

# Simple named list:
list(mean = mean, median = median)

# Auto named with `tibble::lst()`:
tibble::lst(mean, median)

# Using lambdas
list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

Error: `~mp[.]` must be a function name (quoted or unquoted) or an unquoted call, not `~`.

6 changes: 6 additions & 0 deletions tests/testthat/test-deprec-src-local-errors.txt
Expand Up @@ -3,9 +3,13 @@ src_local errs with pkg/env
===========================

> src_df("base", new.env())
Warning: `src_local()` is deprecated as of dplyr 1.0.0.

Error: Exactly one of `pkg` and `env` must be non-NULL, not 2.

> src_df()
Warning: `src_local()` is deprecated as of dplyr 1.0.0.

Error: Exactly one of `pkg` and `env` must be non-NULL, not 0.


Expand All @@ -15,6 +19,8 @@ copy_to
> env <- new.env(parent = emptyenv())
> env$x <- 1
> src_env <- src_df(env = env)
Warning: `src_local()` is deprecated as of dplyr 1.0.0.

> copy_to(src_env, tibble(x = 1), name = "x")
Error: object with `name` = `x` must not already exist, unless `overwrite` = TRUE.

4 changes: 4 additions & 0 deletions tests/testthat/test-do-errors.txt
Expand Up @@ -10,9 +10,13 @@ unnamed elements must return data frames
Error: Result must be a data frame, not numeric

> df %>% do(1)
Warning: `progress_estimated()` is deprecated as of dplyr 1.0.0.

Error: Results 1, 2, 3 must be data frames, not numeric

> df %>% do("a")
Warning: `progress_estimated()` is deprecated as of dplyr 1.0.0.

Error: Results 1, 2, 3 must be data frames, not character


Expand Down
20 changes: 20 additions & 0 deletions tests/testthat/test-mutate.r
Expand Up @@ -354,6 +354,26 @@ test_that("can use .before and .after to control column position", {
expect_named(mutate(df, x = 1, .after = y), c("x", "y"))
})

test_that(".keep= always retains grouping variables (#5582)", {
df <- tibble(x = 1, y = 2, z = 3) %>% group_by(z)
expect_equal(
df %>% mutate(a = x + 1, .keep = "none"),
tibble(z = 3, a = 2) %>% group_by(z)
)
expect_equal(
df %>% mutate(a = x + 1, .keep = "all"),
tibble(x = 1, y = 2, z = 3, a = 2) %>% group_by(z)
)
expect_equal(
df %>% mutate(a = x + 1, .keep = "used"),
tibble(x = 1, z = 3, a = 2) %>% group_by(z)
)
expect_equal(
df %>% mutate(a = x + 1, .keep = "unused"),
tibble(y = 2, z = 3, a = 2) %>% group_by(z)
)
})

test_that("mutate() preserves the call stack on error (#5308)", {
foobar <- function() stop("foo")

Expand Down

0 comments on commit df43c73

Please sign in to comment.