From 43592ae473671f1360c6a1866464218dc2496f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 31 Mar 2020 05:17:59 +0200 Subject: [PATCH 01/28] Omit recycling message if target has size 1 --- R/subsetting.R | 2 +- tests/testthat/subsetting.txt | 5 +++++ tests/testthat/test-subsetting.R | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/R/subsetting.R b/R/subsetting.R index 4ad1a1b46..8540ce628 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -773,7 +773,7 @@ error_assign_incompatible_size <- function(nrow, value, j, i_arg, value_arg) { paste0("Assigned data ", tick(as_label(value_arg)), " must be compatible with ", target, ":"), x = existing, x = new, - i = "Only vectors of size 1 are recycled" + i = if (nrow != 1) "Only vectors of size 1 are recycled" ), expected = nrow, actual = vec_size(value[[j]]), diff --git a/tests/testthat/subsetting.txt b/tests/testthat/subsetting.txt index a2f20683f..1aadf0973 100644 --- a/tests/testthat/subsetting.txt +++ b/tests/testthat/subsetting.txt @@ -444,6 +444,11 @@ x It must be size 2 or 1, not 3. Error: `x` can't be recycled to size 3. x It must be size 3 or 1, not 2. +> df[1, ] <- 1:3 +Error: Assigned data `1:3` must be compatible with row subscript `1`. +x 1 row must be assigned. +x Assigned data has 3 rows. + > df[1:2, ] <- 1:3 Error: Assigned data `1:3` must be compatible with row subscript `1:2`. x 2 rows must be assigned. diff --git a/tests/testthat/test-subsetting.R b/tests/testthat/test-subsetting.R index 98b2a6e03..8cbda5f16 100644 --- a/tests/testthat/test-subsetting.R +++ b/tests/testthat/test-subsetting.R @@ -804,6 +804,7 @@ verify_output("subsetting.txt", { df <- tibble(x = 1:3, y = x, z = y) df[1:2] <- list(0, 0, 0) df[] <- list(0, 0) + df[1, ] <- 1:3 df[1:2, ] <- 1:3 df[,] <- 1:2 From ace33d25f5d21c5f1f099026de0e612509f15a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 31 Mar 2020 05:19:19 +0200 Subject: [PATCH 02/28] Bump version to 3.0.0.9000 --- DESCRIPTION | 2 +- NEWS.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 680f6c1ac..ad233a36c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tibble Title: Simple Data Frames -Version: 3.0.0 +Version: 3.0.0.9000 Authors@R: c(person(given = "Kirill", family = "M\u00fcller", diff --git a/NEWS.md b/NEWS.md index 4999f6b90..59107538d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# tibble 3.0.0.9000 + +- Same as previous version. + + # tibble 3.0.0 ## Major breaking changes From f838f0b12aca08c8c10fbe9cf4f928b0bc4d9ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 31 Mar 2020 08:48:20 +0200 Subject: [PATCH 03/28] - Tweak invariants vignette title. --- vignettes/invariants.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/invariants.Rmd b/vignettes/invariants.Rmd index 32d43991a..212eccc90 100644 --- a/vignettes/invariants.Rmd +++ b/vignettes/invariants.Rmd @@ -4,7 +4,7 @@ title: "Invariants for subsetting and subassignment" output: rmarkdown::html_vignette # devtools::load_all(); eval_details <- TRUE; rmarkdown::render("vignettes/invariants.Rmd", output_format = rmarkdown::md_document(preserve_yaml = TRUE)); system("pandoc vignettes/invariants.md -o vignettes/invariants.html") vignette: > - %\VignetteIndexEntry{invariants} + %\VignetteIndexEntry{Invariants for subsetting and subassignment} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- From 4f0fd617475656ee3fa9ba8874808358ff679358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 31 Mar 2020 11:31:54 +0200 Subject: [PATCH 04/28] - Remove superseded signal for `as_tibble.list()`, because `as_tibble_row()` only works for size 1. --- R/as_tibble.R | 3 --- 1 file changed, 3 deletions(-) diff --git a/R/as_tibble.R b/R/as_tibble.R index 7d62a948a..75f6a05cf 100644 --- a/R/as_tibble.R +++ b/R/as_tibble.R @@ -97,9 +97,6 @@ as_tibble.data.frame <- function(x, validate = NULL, ..., as_tibble.list <- function(x, validate = NULL, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal")) { - signal_superseded("3.0.0", "as_tibble(x = 'can\\'t be a list')", - "as_tibble_row()") - .name_repair <- compat_name_repair(.name_repair, validate) lst_to_tibble(x, .rows, .name_repair, col_lengths(x)) From 1bdc0cfe9d13f6bb1c28e43e2d2a24fb80044c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Wed, 8 Apr 2020 07:51:36 +0200 Subject: [PATCH 05/28] - Use delayed import for cli to work around unload problems in downstream packages (#754). Closes #754. --- NAMESPACE | 2 -- R/glimpse.R | 10 +++++----- R/print.R | 8 ++++---- R/tibble-package.R | 1 - tests/testthat/helper-output.R | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 47063074f..e00ec5b1a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -75,8 +75,6 @@ exportClasses(tbl_df) import(ellipsis) import(lifecycle) import(rlang) -importFrom(cli,cat_line) -importFrom(cli,symbol) importFrom(magrittr,"%>%") importFrom(methods,setOldClass) importFrom(pillar,is_vector_s3) diff --git a/R/glimpse.R b/R/glimpse.R index b908ea53f..e75e1c4bd 100644 --- a/R/glimpse.R +++ b/R/glimpse.R @@ -45,13 +45,13 @@ glimpse.tbl <- function(x, width = NULL, ...) { cnd_signal(error_glimpse_infinite_width()) } - cat_line("Rows: ", big_mark(nrow(x))) + cli::cat_line("Rows: ", big_mark(nrow(x))) # this is an overestimate, but shouldn't be too expensive. # every type needs at least three characters: "x, " rows <- as.integer(width / 3) df <- as.data.frame(head(x, rows)) - cat_line("Columns: ", big_mark(ncol(df))) + cli::cat_line("Columns: ", big_mark(ncol(df))) summary <- tbl_sum(x) brief_summary <- summary[-1] @@ -70,7 +70,7 @@ glimpse.tbl <- function(x, width = NULL, ...) { formatted <- map_chr(df, function(x) collapse(format_v(x))) truncated <- str_trunc(formatted, data_width) - cat_line(var_names, truncated) + cli::cat_line(var_names, truncated) invisible(x) } @@ -87,12 +87,12 @@ glimpse.default <- function(x, width = NULL, max.level = 3, ...) { str_trunc <- function(x, max_width) { width <- nchar(x) - nchar_ellipsis <- nchar_width(symbol$ellipsis) + nchar_ellipsis <- nchar_width(cli::symbol$ellipsis) for (i in seq_along(x)) { if (width[i] <= max_width[i]) next - x[i] <- paste0(substr(x[i], 1, max_width[i] - nchar_ellipsis), symbol$ellipsis) + x[i] <- paste0(substr(x[i], 1, max_width[i] - nchar_ellipsis), cli::symbol$ellipsis) } x diff --git a/R/print.R b/R/print.R index 79ade839d..613dd6364 100644 --- a/R/print.R +++ b/R/print.R @@ -67,7 +67,7 @@ NULL #' @rdname formatting #' @export print.tbl <- function(x, ..., n = NULL, width = NULL, n_extra = NULL) { - cat_line(format(x, ..., n = n, width = width, n_extra = n_extra)) + cli::cat_line(format(x, ..., n = n, width = width, n_extra = n_extra)) invisible(x) } @@ -198,7 +198,7 @@ print_without_body <- function(x, ...) { #' @export print.trunc_mat <- function(x, ...) { - cat_line(format(x, ...)) + cli::cat_line(format(x, ...)) invisible(x) } @@ -252,7 +252,7 @@ format_extra_vars <- function(extra_cols) { if (is.na(extra_cols[1])) return("") if (anyNA(extra_cols)) { - extra_cols <- c(extra_cols[!is.na(extra_cols)], symbol$ellipsis) + extra_cols <- c(extra_cols[!is.na(extra_cols)], cli::symbol$ellipsis) } paste0(": ", collapse(extra_cols)) @@ -265,7 +265,7 @@ format_comment <- function(x, width) { pre_dots <- function(x) { if (length(x) > 0) { - paste0(symbol$ellipsis, " ", x) + paste0(cli::symbol$ellipsis, " ", x) } else { character() } diff --git a/R/tibble-package.R b/R/tibble-package.R index 0669c939f..7d3cf352c 100644 --- a/R/tibble-package.R +++ b/R/tibble-package.R @@ -7,7 +7,6 @@ #' @importFrom vctrs vec_as_location vec_as_location2 vec_as_names vec_as_names_legacy vec_c #' @importFrom vctrs vec_is vec_rbind vec_recycle vec_size vec_slice vec_slice<- #' @importFrom vctrs unspecified -#' @importFrom cli symbol cat_line #' @aliases NULL tibble-package #' @details #' \lifecycle{stable} diff --git a/tests/testthat/helper-output.R b/tests/testthat/helper-output.R index 006997457..061881a67 100644 --- a/tests/testthat/helper-output.R +++ b/tests/testthat/helper-output.R @@ -1,5 +1,5 @@ unell <- function(x) { - gsub(symbol$ellipsis, "...", x, fixed = TRUE) + gsub(cli::symbol$ellipsis, "...", x, fixed = TRUE) } unell_bullets <- function(...) { From 30c0258bdc5c77b1a1a8b9c340408eb2adb6e997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 14 Apr 2020 04:30:32 +0200 Subject: [PATCH 06/28] Post-mortem revdepcheck --- revdep/.gitignore | 3 +- revdep/post-mortem/01-load.R | 25 +++++++++++ revdep/post-mortem/02-clean.R | 58 ++++++++++++++++++++++++ revdep/post-mortem/03-analyze.R | 36 +++++++++++++++ revdep/post-mortem/04-review.R | 66 ++++++++++++++++++++++++++++ revdep/post-mortem/05-count.R | 40 +++++++++++++++++ revdep/post-mortem/06-mail.R | 16 +++++++ revdep/post-mortem/post-mortem.Rproj | 16 +++++++ 8 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 revdep/post-mortem/01-load.R create mode 100644 revdep/post-mortem/02-clean.R create mode 100644 revdep/post-mortem/03-analyze.R create mode 100644 revdep/post-mortem/04-review.R create mode 100644 revdep/post-mortem/05-count.R create mode 100644 revdep/post-mortem/06-mail.R create mode 100644 revdep/post-mortem/post-mortem.Rproj diff --git a/revdep/.gitignore b/revdep/.gitignore index 15991b0a1..79ce4d629 100644 --- a/revdep/.gitignore +++ b/revdep/.gitignore @@ -2,4 +2,5 @@ !.gitignore !*.md !*.R - +!*.Rproj +!post-mortem diff --git a/revdep/post-mortem/01-load.R b/revdep/post-mortem/01-load.R new file mode 100644 index 000000000..7ae4cd43f --- /dev/null +++ b/revdep/post-mortem/01-load.R @@ -0,0 +1,25 @@ +library(tidyverse) + +new_error <- "BAwiR CGPfunctions DMwR2 INDperform MIMSunit OpenLand REDCapR RSDA RmarineHeatWaves SWMPrExtension SanzCircos SortedEffects anchoredDistr apa basket beadplexr biscale brazilmaps casen cdcfluview collateral concaveman concurve convergEU cutpointr cvms dscore epikit estatapi evaluator fable forestmangr germanpolls graphicalVAR heemod highlightHTML ijtiff ipfr jstor mcp metacoder micropan modeltests nationwider nhdplusTools nosoi openair padr pointblank portalr psychonetrics readroper rematch2 riskclustr rsample rubias simrel sjmisc ssdtools statsr taxa tidybayes tidytext tidytransit tradestatistics trialr ushr viafr vip vpc weathercan" +new_warning <- "RNeXML Rdrools analysisPipelines broom.mixed cdcfluview coveffectsplot dexter dialr dodgr highlightHTML metan naniar ozmaps photobiologyInOut poio raceland sigmajs tbrf tidydice tidytree" + +input <- tribble( + ~type, ~pkg, + "error", new_error, + "warning", new_warning +) + +long_pkg <- + input %>% + mutate(pkg = strsplit(pkg, " ")) %>% + unnest(pkg) %>% + distinct(pkg, .keep_all = TRUE) %>% + filter(!(pkg %in% c("cutpointr", "tidytransit"))) + +long_pkg %>% + count(pkg) %>% + count(n) + +fog <- foghorn::cran_details(long_pkg$pkg, src = "crandb") + +saveRDS(fog, "fog.rds") diff --git a/revdep/post-mortem/02-clean.R b/revdep/post-mortem/02-clean.R new file mode 100644 index 000000000..c8dbe1c27 --- /dev/null +++ b/revdep/post-mortem/02-clean.R @@ -0,0 +1,58 @@ +library(tidyverse) + +fog_res <- readRDS("fog_res.rds") + +fog_res %>% + arrange(-error, -fail, -warn, -note, !has_other_issues) %>% + view() + +fog <- readRDS("fog.rds") + +checked_manually <- c("cdcfluview", "metan", "openair", "vip") + +fog_recent <- + fog %>% + filter(!(package %in% checked_manually)) %>% + mutate(version = package_version(version)) %>% + group_by(package) %>% + filter(version == max(version)) %>% + ungroup() %>% + mutate(result = ordered(result, levels = c("ERROR", "WARN", "NOTE"))) %>% + group_by(package) %>% + filter(result == min(result)) %>% + ungroup() %>% + mutate( + check = case_when( + str_detect(check, "^running tests for arch") ~ "tests", + check == "re-building of vignette outputs" ~ "vignettes", + TRUE ~ check + ) + ) + +fog_recent %>% + count(check, wt = n_flavors) %>% + arrange(-n) + +# RNeXML, fixed by tibble 3.0.1 +fog_recent %>% + filter(check == "whether the namespace can be unloaded cleanly") + +# No failures +fog_recent %>% + filter(check == "whether package can be installed") %>% + filter(flavors != "r-release-windows-ix86+x86_64") %>% + pull(package) + +# Not us +fog_recent %>% + filter(check == "package dependencies") %>% + pull() + +# Not us +fog_recent %>% + filter(check == "dependencies in R code") %>% + pull() + +fog_recent %>% + filter(check %in% c("tests", "examples", "vignettes")) %>% + saveRDS("fog_recent.rds") diff --git a/revdep/post-mortem/03-analyze.R b/revdep/post-mortem/03-analyze.R new file mode 100644 index 000000000..bf5e071cf --- /dev/null +++ b/revdep/post-mortem/03-analyze.R @@ -0,0 +1,36 @@ +library(tidyverse) +library(tidytext) + + +fog_recent <- readRDS("fog_recent.rds") + +fog_words <- + fog_recent %>% + select(package, flavors, n = n_flavors, message) %>% + rowid_to_column() %>% + mutate(message = str_replace_all(message, "[0-9]", "")) %>% + unnest_tokens(token, message, "words", stopwords = c("s", "in", "re", "x", "i", "tibble", "be")) + +fog_words %>% + count(token, rowid, wt = n) %>% + bind_tf_idf(token, rowid, n) %>% + group_by(rowid) %>% + filter(row_number(-tf_idf) %in% 1:3) %>% + ungroup() %>% + count(token, sort = TRUE) + +fog_ngrams <- + fog_recent %>% + select(package, flavors, n = n_flavors, message) %>% + rowid_to_column() %>% + mutate(message = str_replace_all(message, "[0-9]", "")) %>% + unnest_tokens(token, message, "ngrams", n = 2, stopwords = c("s", "in", "re", "x", "i", "tibble", "be")) + +fog_ngrams_tf_idf <- + fog_ngrams %>% + count(token, rowid, wt = n) %>% + bind_tf_idf(token, rowid, n) + +fog_ngrams_tf_idf %>% + filter(between(percent_rank(tf_idf), 0.25, 0.75)) + diff --git a/revdep/post-mortem/04-review.R b/revdep/post-mortem/04-review.R new file mode 100644 index 000000000..910dc29d0 --- /dev/null +++ b/revdep/post-mortem/04-review.R @@ -0,0 +1,66 @@ +library(tidyverse) +library(tidytext) + + +fog_recent <- readRDS("fog_recent.rds") + +fog_recent %>% + count(message) %>% + count(n) + +tr_normal <- function(x) { + unicode_symbols <- map(cli:::symbol_utf8, rex::escape) + normal_symbols <- rlang::with_options(cli.unicode = FALSE, cli::symbol) + + reduce2(unicode_symbols, normal_symbols, str_replace_all, .init = x) +} + +clean_timings <- function(x) { + str_replace_all(x, "\\[[0-9]+s(?:/[0-9]+s)?\\]", "[timing]") +} + +clean_testthat_summary <- function(x) { + str_replace_all(x, "\\[ OK:[^\n]+ \\]", "[testthat summary]") +} + +clean_backtrace <- function(x) { + str_replace_all(x, "( +[1-9][0-9]*[.] +(?:[\\\\|+└│├].*| *)\n)+", "[backtrace]\n") +} + +clean_pre_backtrace <- function(x) { + str_replace_all(x, "[x#]\n", "[pre-backtrace]\n") +} + +clean_ptime <- function(x) { + str_replace_all(x, " [>] base::assign.*\n", "") +} + +clean_paths <- function(x) { + str_replace_all(x, "/home/hornik/tmp/[^\n]+/Work/build/Packages/|/data/gannet/ripley/R/packages/[^\n]+[.]Rcheck/|/home/ripley/R/Lib32-dev/|D:/temp/[^\n]+/RLIBS_[^\n/]+/", "[path]/") +} + +fog_clean <- + fog_recent %>% + mutate(message = tr_normal(message)) %>% + mutate(message = clean_timings(message)) %>% + mutate(message = clean_testthat_summary(message)) %>% + mutate(message = clean_backtrace(message)) %>% + mutate(message = clean_pre_backtrace(message)) %>% + mutate(message = clean_ptime(message)) %>% + mutate(message = clean_paths(message)) %>% + group_by(package, result, check, message) %>% + summarize( + flavors = paste0(flavors, collapse = ", "), + n_flavors = sum(n_flavors), + version = version[[1]] + ) %>% + ungroup() + +unlink("msg", recursive = TRUE) +dir.create("msg", showWarnings = FALSE) + +fog_clean %>% + filter(check != "vignettes") %>% + rowid_to_column() %>% + transmute(text = message, path = sprintf("msg/%04d-%s.txt", rowid, package)) %>% + pwalk(brio::write_lines) diff --git a/revdep/post-mortem/05-count.R b/revdep/post-mortem/05-count.R new file mode 100644 index 000000000..2479eb4a8 --- /dev/null +++ b/revdep/post-mortem/05-count.R @@ -0,0 +1,40 @@ +library(tidyverse) +library(tidytext) + + +fog_recent <- readRDS("fog_recent.rds") + + +fog_dump <- + fog_recent %>% + group_by(package) %>% + summarize(message = glue::glue_collapse(message, sep = "\n")) %>% + ungroup() + +# wide vector +fog_dump %>% + filter(str_detect(message, fixed("1 row must be assigned"))) + +# array indexing +fog_dump %>% + filter(str_detect(message, fixed("must have one dimension, not 2"))) + +fog_dump %>% + filter(package == "naniar") %>% + pull(message) %>% + cli::cat_line() + +# compare unnamed, perhaps ensure that names are not added to tibble +# if not intended? +fog_dump %>% + count(str_detect(message, fixed("names for"))) + +# load sf prior to adding to tibble +fog_dump %>% + count(str_detect(message, fixed("sfc"))) + +fog_dump %>% + count(str_detect(message, fixed("Input must be a vector"))) + +fog_dump %>% + count(str_detect(message, "Lossy cast from .* to .* ")) diff --git a/revdep/post-mortem/06-mail.R b/revdep/post-mortem/06-mail.R new file mode 100644 index 000000000..27c058026 --- /dev/null +++ b/revdep/post-mortem/06-mail.R @@ -0,0 +1,16 @@ +library(tidyverse) + +fog <- readRDS("fog.rds") + +fog_pkg <- + fog %>% + count(package) %>% + pull(package) + +maint <- tools:::CRAN_package_maintainers_db() + +maint %>% + filter(Package %in% !!fog_pkg) %>% + count(Maintainer) %>% + pull(Maintainer) %>% + clipr::write_clip() diff --git a/revdep/post-mortem/post-mortem.Rproj b/revdep/post-mortem/post-mortem.Rproj new file mode 100644 index 000000000..e83436a3e --- /dev/null +++ b/revdep/post-mortem/post-mortem.Rproj @@ -0,0 +1,16 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX + +AutoAppendNewline: Yes +StripTrailingWhitespace: Yes From f65bd6fe16c029a2cabb6b9f0c40847079fe0d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 14 Apr 2020 10:33:23 +0200 Subject: [PATCH 07/28] Fix glimpse() --- R/glimpse.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/glimpse.R b/R/glimpse.R index e75e1c4bd..429da11ff 100644 --- a/R/glimpse.R +++ b/R/glimpse.R @@ -57,7 +57,7 @@ glimpse.tbl <- function(x, width = NULL, ...) { brief_summary <- summary[-1] if (has_length(brief_summary)) { - cat_line(names(brief_summary), ": ", brief_summary) + cli::cat_line(names(brief_summary), ": ", brief_summary) } if (ncol(df) == 0) return(invisible(x)) From 45d28f037ac7dce36f4b1c6bf872d2e317f9bd95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 14 Apr 2020 10:54:41 +0200 Subject: [PATCH 08/28] - Subsetting and subassignment with logical matrices with one column work again, with a deprecation warning. --- R/subsetting.R | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/R/subsetting.R b/R/subsetting.R index 8540ce628..0f9b5e25d 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -548,6 +548,18 @@ vectbl_as_new_col_index <- function(j, x, value, j_arg, value_arg) { } vectbl_as_row_location <- function(i, n, i_arg, assign = FALSE) { + if (is_bare_logical(i) && is.matrix(i) && ncol(i) == 1 && nrow(i) == n) { + what <- paste0( + "tibble::", if (assign) "`[<-`" else "`[`", + "(i = 'can\\'t be a logical matrix')" + ) + + lifecycle::deprecate_soft("3.0.0", what, + details = "Convert to a logical vector." + ) + i <- i[, 1] + } + subclass_row_index_errors(vec_as_location(i, n, arg = as_label(i_arg)), i_arg = i_arg, assign = assign) } From 33da46d5cd9e0fdc642aa5aa1f1f237e8d13dad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 14 Apr 2020 10:55:24 +0200 Subject: [PATCH 09/28] Rename for clarity --- R/subsetting.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/R/subsetting.R b/R/subsetting.R index 0f9b5e25d..fde84ff7a 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -567,12 +567,12 @@ vectbl_as_row_location2 <- function(i, n, i_arg, assign = FALSE) { subclass_row_index_errors(vec_as_location2(i, n, arg = as_label(i_arg)), i_arg = i_arg, assign = assign) } -vectbl_as_col_location <- function(i, n, names = NULL, j_arg, assign = FALSE) { - subclass_col_index_errors(vec_as_location(i, n, names, arg = as_label(j_arg)), j_arg = j_arg, assign = assign) +vectbl_as_col_location <- function(j, n, names = NULL, j_arg, assign = FALSE) { + subclass_col_index_errors(vec_as_location(j, n, names, arg = as_label(j_arg)), j_arg = j_arg, assign = assign) } -vectbl_as_col_location2 <- function(i, n, names = NULL, j_arg, assign = FALSE) { - subclass_col_index_errors(vec_as_location2(i, n, names, arg = as_label(j_arg)), j_arg = j_arg, assign = assign) +vectbl_as_col_location2 <- function(j, n, names = NULL, j_arg, assign = FALSE) { + subclass_col_index_errors(vec_as_location2(j, n, names, arg = as_label(j_arg)), j_arg = j_arg, assign = assign) } is_tight_sequence_at_end <- function(i_new, n) { From 4bd8de0db2d182258dd85d18d04e1956b1b67e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 14 Apr 2020 10:58:52 +0200 Subject: [PATCH 10/28] - Attempts to update a tibble row with an atomic vector give a clearer error message. --- R/subsetting.R | 51 +++++++++++++++++++++-------------- R/utils-msg-format.R | 2 +- tests/testthat/subsetting.txt | 1 + 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/R/subsetting.R b/R/subsetting.R index fde84ff7a..b6bf4a51a 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -399,28 +399,11 @@ tbl_subset_row <- function(x, i, i_arg) { } tbl_subassign <- function(x, i, j, value, i_arg, j_arg, value_arg) { - if (!vec_is(value)) { - if (!is_null(i)) { - cnd_signal(error_need_rhs_vector(value_arg)) - } - if (!is_null(value)) { - cnd_signal(error_need_rhs_vector_or_null(value_arg)) - } - } - - if (is_null(value) || is_atomic(value)) { - value <- list(value) - } else { - value <- unclass(value) - } - - if (!is_bare_list(value)) { - cnd_signal(error_need_rhs_vector_or_null(value_arg)) - } - i <- vectbl_as_new_row_index(i, x, i_arg) if (is.null(i)) { + value <- vectbl_wrap_rhs_col(value, value_arg) + if (is.null(j)) { j <- seq_along(x) } else { @@ -434,6 +417,7 @@ tbl_subassign <- function(x, i, j, value, i_arg, j_arg, value_arg) { } else { # Fill up rows first if necessary x <- tbl_expand_to_nrow(x, i) + value <- vectbl_wrap_rhs_row(value, value_arg, i = i) if (is.null(j)) { value <- vectbl_recycle_rhs(value, length(i), length(x), i_arg, value_arg) @@ -665,7 +649,33 @@ vectbl_strip_names <- function(x) { x } -vectbl_recycle_rhs <- function(value, nrow, ncol, i_arg, value_arg, full) { +vectbl_wrap_rhs_col <- function(value, value_arg) { + if (is_null(value)) { + list(value) + } else if (!vec_is(value)) { + cnd_signal(error_need_rhs_vector_or_null(value_arg)) + } else if (is_atomic(value)) { + list(value) + } else { + value <- unclass(value) + if (!is_bare_list(value)) { + cnd_signal(error_need_rhs_vector_or_null(value_arg)) + } + value + } +} + +vectbl_wrap_rhs_row <- function(value, value_arg, i) { + if (!vec_is(value)) { + cnd_signal(error_need_rhs_vector(value_arg)) + } else if (is_atomic(value)) { + list(value) + } else { + unclass(value) + } +} + +vectbl_recycle_rhs <- function(value, nrow, ncol, i_arg, value_arg) { tryCatch( for (j in seq_along(value)) { if (!is.null(value[[j]])) { @@ -786,6 +796,7 @@ error_assign_incompatible_size <- function(nrow, value, j, i_arg, value_arg) { x = existing, x = new, i = if (nrow != 1) "Only vectors of size 1 are recycled" + i = if (nrow == 1 && vec_size(value[[j]]) != 1) "Row updates require a list value. Do you need `list()` or `as.list()`?" ), expected = nrow, actual = vec_size(value[[j]]), diff --git a/R/utils-msg-format.R b/R/utils-msg-format.R index 5ca63b13a..18c879e0b 100644 --- a/R/utils-msg-format.R +++ b/R/utils-msg-format.R @@ -93,7 +93,7 @@ commas <- function(problems) { } ensure_full_stop <- function(x) { - gsub("(?::|([^.]))$", "\\1.", x) + gsub("(?::|([^.?]))$", "\\1.", x) } set_default_name <- function(x, name) { diff --git a/tests/testthat/subsetting.txt b/tests/testthat/subsetting.txt index 1aadf0973..eb4d9dff6 100644 --- a/tests/testthat/subsetting.txt +++ b/tests/testthat/subsetting.txt @@ -448,6 +448,7 @@ x It must be size 3 or 1, not 2. Error: Assigned data `1:3` must be compatible with row subscript `1`. x 1 row must be assigned. x Assigned data has 3 rows. +i Row updates require a list value. Do you need `list()` or `as.list()`? > df[1:2, ] <- 1:3 Error: Assigned data `1:3` must be compatible with row subscript `1:2`. From 30b9d53a3e5c1b71143cca2e71170bb6f08fcd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 14 Apr 2020 11:00:36 +0200 Subject: [PATCH 11/28] Bump version to 3.0.0.9001 --- DESCRIPTION | 2 +- NEWS.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index ad233a36c..5bfb725db 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tibble Title: Simple Data Frames -Version: 3.0.0.9000 +Version: 3.0.0.9001 Authors@R: c(person(given = "Kirill", family = "M\u00fcller", diff --git a/NEWS.md b/NEWS.md index 59107538d..7dc6922b5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,12 @@ +# tibble 3.0.0.9001 + +- Attempts to update a tibble row with an atomic vector give a clearer error message. Recycling message for subassignment appears only if target size is != 1. +- Subsetting and subassignment with logical matrices with one column work again, with a deprecation warning. +- Use delayed import for cli to work around unload problems in downstream packages (#754). +- Remove superseded signal for `as_tibble.list()`, because `as_tibble_row()` only works for size 1. +- Tweak invariants vignette title. + + # tibble 3.0.0.9000 - Same as previous version. From f3422515455b8c98d96577582e1a4824a69b2eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Thu, 16 Apr 2020 05:00:38 +0200 Subject: [PATCH 12/28] Tweak --- revdep/post-mortem/05-count.R | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/revdep/post-mortem/05-count.R b/revdep/post-mortem/05-count.R index 2479eb4a8..c0f2aa856 100644 --- a/revdep/post-mortem/05-count.R +++ b/revdep/post-mortem/05-count.R @@ -31,10 +31,12 @@ fog_dump %>% # load sf prior to adding to tibble fog_dump %>% - count(str_detect(message, fixed("sfc"))) + filter(str_detect(message, fixed("sfc"))) %>% + pull(message) %>% + cli::cat_line() fog_dump %>% - count(str_detect(message, fixed("Input must be a vector"))) + filter(str_detect(message, fixed("Input must be a vector"))) fog_dump %>% count(str_detect(message, "Lossy cast from .* to .* ")) From 8efa95c017ae7ad8a9a7d92aec10d68f73c5873b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Thu, 16 Apr 2020 05:01:03 +0200 Subject: [PATCH 13/28] Oops --- R/subsetting.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/subsetting.R b/R/subsetting.R index b6bf4a51a..565dfc667 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -795,7 +795,7 @@ error_assign_incompatible_size <- function(nrow, value, j, i_arg, value_arg) { paste0("Assigned data ", tick(as_label(value_arg)), " must be compatible with ", target, ":"), x = existing, x = new, - i = if (nrow != 1) "Only vectors of size 1 are recycled" + i = if (nrow != 1) "Only vectors of size 1 are recycled", i = if (nrow == 1 && vec_size(value[[j]]) != 1) "Row updates require a list value. Do you need `list()` or `as.list()`?" ), expected = nrow, From e56c2948847447d0bed177a57664a7167f13b6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Thu, 16 Apr 2020 05:01:50 +0200 Subject: [PATCH 14/28] Up vignette --- vignettes/invariants.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/invariants.md b/vignettes/invariants.md index f3abe928b..25a0a2e3b 100644 --- a/vignettes/invariants.md +++ b/vignettes/invariants.md @@ -4,7 +4,7 @@ title: "Invariants for subsetting and subassignment" output: rmarkdown::html_vignette # devtools::load_all(); eval_details <- TRUE; rmarkdown::render("vignettes/invariants.Rmd", output_format = rmarkdown::md_document(preserve_yaml = TRUE)); system("pandoc vignettes/invariants.md -o vignettes/invariants.html") vignette: > - %\VignetteIndexEntry{invariants} + %\VignetteIndexEntry{Invariants for subsetting and subassignment} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- From e4f2656433db32bb72eddcd5a366c86b599185b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Thu, 16 Apr 2020 06:49:24 +0200 Subject: [PATCH 15/28] - `[<-` coerces matrices to data frames (#762). --- R/subsetting.R | 42 ++++++--- tests/testthat/msg.txt | 4 +- tests/testthat/subsetting.txt | 10 +- tests/testthat/test-subsetting.R | 32 +++++++ vignettes/invariants.Rmd | 22 ++++- vignettes/invariants.md | 153 +++++++++++++++++++++++++++---- 6 files changed, 218 insertions(+), 45 deletions(-) diff --git a/R/subsetting.R b/R/subsetting.R index 565dfc667..6ed09f701 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -417,7 +417,7 @@ tbl_subassign <- function(x, i, j, value, i_arg, j_arg, value_arg) { } else { # Fill up rows first if necessary x <- tbl_expand_to_nrow(x, i) - value <- vectbl_wrap_rhs_row(value, value_arg, i = i) + value <- vectbl_wrap_rhs_row(value, value_arg) if (is.null(j)) { value <- vectbl_recycle_rhs(value, length(i), length(x), i_arg, value_arg) @@ -651,23 +651,35 @@ vectbl_strip_names <- function(x) { vectbl_wrap_rhs_col <- function(value, value_arg) { if (is_null(value)) { - list(value) - } else if (!vec_is(value)) { + return(list(value)) + } + + value <- result_vectbl_wrap_rhs(value) + if (is_null(value)) { cnd_signal(error_need_rhs_vector_or_null(value_arg)) - } else if (is_atomic(value)) { - list(value) - } else { - value <- unclass(value) - if (!is_bare_list(value)) { - cnd_signal(error_need_rhs_vector_or_null(value_arg)) - } - value } + + value +} + +vectbl_wrap_rhs_row <- function(value, value_arg) { + value <- result_vectbl_wrap_rhs(value) + if (is_null(value)) { + cnd_signal(error_need_rhs_vector(value_arg)) + } + + value } -vectbl_wrap_rhs_row <- function(value, value_arg, i) { +result_vectbl_wrap_rhs <- function(value) { if (!vec_is(value)) { - cnd_signal(error_need_rhs_vector(value_arg)) + NULL + } else if (is.array(value)) { + if (any(dim(value)[-1:-2] != 1)) { + return(NULL) + } + dim(value) <- head(dim(value), 2) + as.list(as.data.frame(value, stringsAsFactors = FALSE)) } else if (is_atomic(value)) { list(value) } else { @@ -716,11 +728,11 @@ string_to_indices <- function(x) { # Errors ------------------------------------------------------------------ error_need_rhs_vector <- function(value_arg) { - tibble_error(paste0(tick(as_label(value_arg)), " must be a vector, a bare list or a data frame.")) + tibble_error(paste0(tick(as_label(value_arg)), " must be a vector, a bare list, a data frame or a matrix.")) } error_need_rhs_vector_or_null <- function(value_arg) { - tibble_error(paste0(tick(as_label(value_arg)), " must be a vector, a bare list, a data frame or NULL.")) + tibble_error(paste0(tick(as_label(value_arg)), " must be a vector, a bare list, a data frame, a matrix, or NULL.")) } error_na_column_index <- function(j) { diff --git a/tests/testthat/msg.txt b/tests/testthat/msg.txt index 93ec7e33f..3e786e444 100644 --- a/tests/testthat/msg.txt +++ b/tests/testthat/msg.txt @@ -199,11 +199,11 @@ subsetting > error_need_rhs_vector(quote(RHS)) -`RHS` must be a vector, a bare list or a data frame. +`RHS` must be a vector, a bare list, a data frame or a matrix. > error_need_rhs_vector_or_null(quote(RHS)) -`RHS` must be a vector, a bare list, a data frame or NULL. +`RHS` must be a vector, a bare list, a data frame, a matrix, or NULL. > error_na_column_index(1:3) diff --git a/tests/testthat/subsetting.txt b/tests/testthat/subsetting.txt index eb4d9dff6..0a39cc4b3 100644 --- a/tests/testthat/subsetting.txt +++ b/tests/testthat/subsetting.txt @@ -405,10 +405,10 @@ Error: Can't use NA as row index in a tibble for assignment. > df <- tibble(x = 1:2, y = x) > df[] <- mean -Error: `mean` must be a vector, a bare list, a data frame or NULL. +Error: `mean` must be a vector, a bare list, a data frame, a matrix, or NULL. > df[] <- lm(y ~ x, df) -Error: `lm(y ~ x, df)` must be a vector, a bare list, a data frame or NULL. +Error: `lm(y ~ x, df)` must be a vector, a bare list, a data frame, a matrix, or NULL. [<-.tbl_df throws an error with OOB assignment @@ -488,7 +488,7 @@ i Error occurred for column `x`. x No common type for `value` and `x` . > df[1:3, 1:3] <- NULL -Error: `NULL` must be a vector, a bare list or a data frame. +Error: `NULL` must be a vector, a bare list, a data frame or a matrix. [<-.tbl_df and overwriting NA @@ -633,10 +633,10 @@ i Only vectors of size 1 are recycled. > df <- tibble(x = 1:2, y = x) > df[1] <- lm(y ~ x, df) -Error: `lm(y ~ x, df)` must be a vector, a bare list, a data frame or NULL. +Error: `lm(y ~ x, df)` must be a vector, a bare list, a data frame, a matrix, or NULL. > df[1:2, 1] <- NULL -Error: `NULL` must be a vector, a bare list or a data frame. +Error: `NULL` must be a vector, a bare list, a data frame or a matrix. $<- recycles only values of length one diff --git a/tests/testthat/test-subsetting.R b/tests/testthat/test-subsetting.R index 8cbda5f16..5ec57d7d3 100644 --- a/tests/testthat/test-subsetting.R +++ b/tests/testthat/test-subsetting.R @@ -518,6 +518,38 @@ test_that("[<-.tbl_df supports adding duplicate columns", { expect_identical(df, tibble(x = 1:2, x = 3:4, .name_repair = "minimal")) }) + +test_that("[<-.tbl_df supports matrix on the RHS (#762)", { + df <- tibble(x = 1:4, y = letters[1:4]) + df[1:2] <- matrix(8:1, ncol = 2) + expect_identical(df, tibble(x = 8:5, y = 4:1)) + + df <- tibble(x = 1:4, y = letters[1:4]) + df[1:2] <- array(4:1, dim = c(4, 1, 1)) + expect_identical(df, tibble(x = 4:1, y = 4:1)) + + df <- tibble(x = 1:4, y = letters[1:4]) + df[1:2] <- array(8:1, dim = c(4, 2, 1)) + expect_identical(df, tibble(x = 8:5, y = 4:1)) + + df <- tibble(x = 1:4, y = letters[1:4]) + expect_tibble_error( + df[1:3, 1:2] <- matrix(6:1, ncol = 2), + error_assign_incompatible_type( + df, matrix(6:1, ncol = 2), 2, quote(matrix(6:1, ncol = 2)), + cnd_message(tryCatch(vec_assign(letters, 1:3, 3:1), error = identity)) + ) + ) + expect_tibble_error( + df[1:2] <- array(8:1, dim = c(2, 1, 4)), + error_need_rhs_vector_or_null(quote(array(8:1, dim = c(2, 1, 4)))) + ) + expect_tibble_error( + df[1:2] <- array(8:1, dim = c(4, 1, 2)), + error_need_rhs_vector_or_null(quote(array(8:1, dim = c(4, 1, 2)))) + ) +}) + test_that("[<- with explicit NULL doesn't change anything (#696)", { iris_tbl_orig <- as_tibble(iris) diff --git a/vignettes/invariants.Rmd b/vignettes/invariants.Rmd index 212eccc90..dc5c82b16 100644 --- a/vignettes/invariants.Rmd +++ b/vignettes/invariants.Rmd @@ -577,6 +577,21 @@ with_df(df[is.na(df)] <- 1:2) with_df(df[matrix(c(rep(TRUE, 5), rep(FALSE, 7)), ncol = 3)] <- 4) ``` +### `a` is a matrix or array + +If `is.matrix(a)`, then `a` is coerced to a data frame with `as.data.frame()` before assigning. +If rows are assigned, the matrix type must be compatible with all columns. +If `is.array(a)` and `any(dim(a)[-1:-2] != 1)`, an error is thrown. + +```{r bracket-assign-array, dftbl = TRUE} +with_df(df[1:2] <- matrix(8:1, ncol = 2)) +with_df(df[1:3, 1:2] <- matrix(6:1, ncol = 2)) +with_df(df[1:2] <- array(4:1, dim = c(4, 1, 1))) +with_df(df[1:2] <- array(8:1, dim = c(4, 2, 1))) +with_df(df[1:2] <- array(8:1, dim = c(2, 1, 4))) +with_df(df[1:2] <- array(8:1, dim = c(4, 1, 2))) +``` + ### `a` is another type of vector If `vec_is(a)`, then `x[j] <- a` is equivalent to `x[j] <- list(a)`. @@ -587,13 +602,12 @@ with_df(df[1] <- 0) with_df(df[1] <- list(0)) ``` -Matrices are vectors, so they are also wrapped in `list()` before assignment. -This consistently creates matrix columns, unlike data frames, which creates matrix columns when assigning to one column, but treats the matrix like a data frame when assigning to more than one column. +Matrices must be wrapped in `list()` before assignment to create a matrix column. ```{r bracket-assign-matrix, dftbl = TRUE} -with_df(df[1] <- matrix(1:8, ncol = 2)) +with_df(df[1] <- list(matrix(1:8, ncol = 2))) -with_df(df[1:2] <- matrix(1:8, ncol = 2)) +with_df(df[1:2] <- list(matrix(1:8, ncol = 2))) ``` ### `a` is `NULL` diff --git a/vignettes/invariants.md b/vignettes/invariants.md index 25a0a2e3b..2478fb44a 100644 --- a/vignettes/invariants.md +++ b/vignettes/invariants.md @@ -2522,6 +2522,132 @@ and if all columns updated are compatible with the value assigned. +### `a` is a matrix or array + +If `is.matrix(a)`, then `a` is coerced to a data frame with +`as.data.frame()` before assigning. If rows are assigned, the matrix +type must be compatible with all columns. If `is.array(a)` and +`any(dim(a)[-1:-2] != 1)`, an error is thrown. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + with_tbl(tbl[1:2] <- matrix(8:1, ncol = 2)) + #> # A tibble: 4 x 3 + #> n c li + #> + #> 1 8 4 + #> 2 7 3 + #> 3 6 2 + #> 4 5 1 + +
+ + with_df(df[1:3, 1:2] <- matrix(6:1, ncol = 2)) + #> n c li + #> 1 6 3 9 + #> 2 5 2 10, 11 + #> 3 4 1 12, 13, 14 + #> 4 NA h text + + + + with_tbl(tbl[1:3, 1:2] <- matrix(6:1, ncol = 2)) + + #> Error: Assigned data `matrix(6:1, ncol = + #> 2)` must be compatible with existing + #> data. + #> ℹ Error occurred for column `c`. + #> x No common type for `value` + #> and `x` . + +
+ + + with_tbl(tbl[1:2] <- array(4:1, dim = c(4, 1, 1))) + #> # A tibble: 4 x 3 + #> n c li + #> + #> 1 4 4 + #> 2 3 3 + #> 3 2 2 + #> 4 1 1 + +
+ + + with_tbl(tbl[1:2] <- array(8:1, dim = c(4, 2, 1))) + #> # A tibble: 4 x 3 + #> n c li + #> + #> 1 8 4 + #> 2 7 3 + #> 3 6 2 + #> 4 5 1 + +
+ + with_df(df[1:2] <- array(8:1, dim = c(2, 1, 4))) + #> n c li + #> 1 8 4 9 + #> 2 7 3 10, 11 + #> 3 6 2 12, 13, 14 + #> 4 5 1 text + + + + with_tbl(tbl[1:2] <- array(8:1, dim = c(2, 1, 4))) + + #> Error: `array(8:1, dim = c(2, 1, 4))` + #> must be a vector, a bare list, a data + #> frame, a matrix, or NULL. + +
+ + with_df(df[1:2] <- array(8:1, dim = c(4, 1, 2))) + #> n c li + #> 1 8 4 9 + #> 2 7 3 10, 11 + #> 3 6 2 12, 13, 14 + #> 4 5 1 text + + + + with_tbl(tbl[1:2] <- array(8:1, dim = c(4, 1, 2))) + + #> Error: `array(8:1, dim = c(4, 1, 2))` + #> must be a vector, a bare list, a data + #> frame, a matrix, or NULL. + +
+ ### `a` is another type of vector If `vec_is(a)`, then `x[j] <- a` is equivalent to `x[j] <- list(a)`. @@ -2564,11 +2690,8 @@ This is primarily provided for backward compatbility. -Matrices are vectors, so they are also wrapped in `list()` before -assignment. This consistently creates matrix columns, unlike data -frames, which creates matrix columns when assigning to one column, but -treats the matrix like a data frame when assigning to more than one -column. +Matrices must be wrapped in `list()` before assignment to create a +matrix column. @@ -2577,7 +2700,7 @@ column. @@ -2703,7 +2818,7 @@ scalar. See `?vec_is` and `?vec_proxy` for details. with_tbl(tbl[1] <- mean) #> Error: `mean` must be a vector, a bare - #> list, a data frame or NULL. + #> list, a data frame, a matrix, or NULL. @@ -2749,7 +2864,7 @@ scalar. See `?vec_is` and `?vec_proxy` for details. #> Error: `lm(mpg ~ wt, data = mtcars)` #> must be a vector, a bare list, a data - #> frame or NULL. + #> frame, a matrix, or NULL. @@ -3601,7 +3716,7 @@ For new columns, `x[i, j] <- a` fills the unassigned rows with `NA`. with_tbl(tbl[2:3, "n"] <- NULL) #> Error: `NULL` must be a vector, a bare - #> list or a data frame. + #> list, a data frame or a matrix. From c4cd1982410eaadecb380687636890652739f5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Thu, 16 Apr 2020 06:54:17 +0200 Subject: [PATCH 16/28] Bump version to 3.0.0.9002 --- DESCRIPTION | 2 +- NEWS.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5bfb725db..b29585183 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tibble Title: Simple Data Frames -Version: 3.0.0.9001 +Version: 3.0.0.9002 Authors@R: c(person(given = "Kirill", family = "M\u00fcller", diff --git a/NEWS.md b/NEWS.md index 7dc6922b5..8ecaf0096 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# tibble 3.0.0.9002 + +- `[<-` coerces matrices to data frames (#762). + + # tibble 3.0.0.9001 - Attempts to update a tibble row with an atomic vector give a clearer error message. Recycling message for subassignment appears only if target size is != 1. From c30c907c098a8f921c0c899f57ba181f044ffa33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Thu, 16 Apr 2020 07:01:24 +0200 Subject: [PATCH 17/28] Fix test --- tests/testthat/test-subsetting.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-subsetting.R b/tests/testthat/test-subsetting.R index 5ec57d7d3..294124d86 100644 --- a/tests/testthat/test-subsetting.R +++ b/tests/testthat/test-subsetting.R @@ -536,8 +536,8 @@ test_that("[<-.tbl_df supports matrix on the RHS (#762)", { expect_tibble_error( df[1:3, 1:2] <- matrix(6:1, ncol = 2), error_assign_incompatible_type( - df, matrix(6:1, ncol = 2), 2, quote(matrix(6:1, ncol = 2)), - cnd_message(tryCatch(vec_assign(letters, 1:3, 3:1), error = identity)) + df, as.data.frame(matrix(6:1, ncol = 2)), 2, quote(matrix(6:1, ncol = 2)), + cnd_message(tryCatch(vctrs::vec_assign(letters, 1:3, 3:1), error = identity)) ) ) expect_tibble_error( From 9edb6b4d2afaf27e5cf49ae0f3343b5e9e74f93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Fri, 17 Apr 2020 07:27:56 +0200 Subject: [PATCH 18/28] - Subsetting and subassignment of rows with one-column matrices work again, with a deprecation warning (#760). Closes #760. @lionel-: I need `foreign_caller_env()` here to see a lifecycle warning, because I'm not calling `deprecate_soft()` from the exported function. Why does this work for S3 methods? Do we want this in rlang? --- R/compat-lifecycle.R | 12 ++++++++++++ R/subsetting.R | 7 ++++--- tests/testthat/subsetting.txt | 19 +++++++++++++------ tests/testthat/test-subsetting.R | 15 +++++++++++++-- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/R/compat-lifecycle.R b/R/compat-lifecycle.R index 2af9dff2a..068376427 100644 --- a/R/compat-lifecycle.R +++ b/R/compat-lifecycle.R @@ -34,4 +34,16 @@ with_lifecycle_errors <- function(expr) { # Enable once signal_superseded() reaches stable state signal_superseded <- function(...) {} +foreign_caller_env <- function(my_env = env_parent()) { + for (n in 2:10) { + caller <- caller_env(n) + if (!is_reference(env_parent(caller), my_env)) { + return(caller) + } + } + + # Safety net + caller +} + # nocov end diff --git a/R/subsetting.R b/R/subsetting.R index 6ed09f701..78b4f50b4 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -532,14 +532,15 @@ vectbl_as_new_col_index <- function(j, x, value, j_arg, value_arg) { } vectbl_as_row_location <- function(i, n, i_arg, assign = FALSE) { - if (is_bare_logical(i) && is.matrix(i) && ncol(i) == 1 && nrow(i) == n) { + if (is_bare_atomic(i) && is.matrix(i) && ncol(i) == 1) { what <- paste0( "tibble::", if (assign) "`[<-`" else "`[`", - "(i = 'can\\'t be a logical matrix')" + "(i = 'can\\'t be a matrix')" ) lifecycle::deprecate_soft("3.0.0", what, - details = "Convert to a logical vector." + details = "Convert to a vector.", + env = foreign_caller_env() ) i <- i[, 1] } diff --git a/tests/testthat/subsetting.txt b/tests/testthat/subsetting.txt index 0a39cc4b3..044762257 100644 --- a/tests/testthat/subsetting.txt +++ b/tests/testthat/subsetting.txt @@ -104,9 +104,6 @@ i The subscript `c(-1, NA)` has a missing value at location 2. Warning: The `i` argument of ``[.tbl_df`()` must lie in [-rows, 0] if negative, as of tibble 3.0.0. Use `NA` as row index to obtain a row full of `NA` values. -> foo[as.matrix(1), ] -Error: `i` must have one dimension, not 2. - > foo[array(1, dim = c(1, 1, 1)), ] Error: `i` must have one dimension, not 3. @@ -163,9 +160,6 @@ Error: Must subset rows with a valid subscript vector. i Logical subscripts must match the size of the indexed input. x The input has size 3 but the subscript `c(TRUE, TRUE, FALSE, FALSE)` has size 4. -> foo[as.matrix(TRUE), ] -Error: `i` must have one dimension, not 2. - > foo[array(TRUE, dim = c(1, 1, 1)), ] Error: `i` must have one dimension, not 3. @@ -352,6 +346,19 @@ x The subscript `Sys.Date()` has the wrong type `date`. i It must be logical, numeric, or character. +[.tbl_df emits lifecycle warnings with one-column matrix indexes (#760) +======================================================================= + +> foo <- tibble(x = 1:10, y = 1:10, z = 1:10) +> invisible(foo[matrix(1:2, ncol = 1), ]) +Warning: The `i` argument of ``[`()` can't be a matrix as of tibble 3.0.0. +Convert to a vector. + +> invisible(foo[matrix(rep(TRUE, 10), ncol = 1), ]) +Warning: The `i` argument of ``[`()` can't be a matrix as of tibble 3.0.0. +Convert to a vector. + + [<-.tbl_df rejects unknown row indexes ====================================== diff --git a/tests/testthat/test-subsetting.R b/tests/testthat/test-subsetting.R index 294124d86..748258d54 100644 --- a/tests/testthat/test-subsetting.R +++ b/tests/testthat/test-subsetting.R @@ -284,6 +284,14 @@ test_that("[.tbl_df ignores drop argument (with warning) without j argument (#30 expect_warning(expect_identical(df_all[1, drop = TRUE], df_all[1])) }) +test_that("[.tbl_df emits errors with matrix row subsetting (#760)", { + scoped_lifecycle_errors() + + foo <- tibble(x = 1:10, y = 1:10, z = 1:10) + expect_error(foo[matrix(1:2, ncol = 2), ]) + expect_error(foo[matrix(rep(TRUE, 10), ncol = 2), ]) +}) + test_that("[.tbl_df is careful about attributes (#155)", { df <- tibble(x = 1:2, y = x) @@ -723,7 +731,6 @@ verify_output("subsetting.txt", { foo[c(-1, 1), ] foo[c(-1, NA), ] invisible(foo[-4, ]) - foo[as.matrix(1), ] foo[array(1, dim = c(1, 1, 1)), ] foo[mean, ] foo[foo, ] @@ -740,7 +747,6 @@ verify_output("subsetting.txt", { foo <- tibble(x = 1:3, y = 1:3, z = 1:3) foo[c(TRUE, TRUE), ] foo[c(TRUE, TRUE, FALSE, FALSE), ] - foo[as.matrix(TRUE), ] foo[array(TRUE, dim = c(1, 1, 1)), ] "# [.tbl_df rejects unknown column indexes (#83)" @@ -802,6 +808,11 @@ verify_output("subsetting.txt", { foo[factor(1:3)] <- 1 foo[Sys.Date()] <- 1 + "# [.tbl_df emits lifecycle warnings with one-column matrix indexes (#760)" + foo <- tibble(x = 1:10, y = 1:10, z = 1:10) + invisible(foo[matrix(1:2, ncol = 1), ]) + invisible(foo[matrix(rep(TRUE, 10), ncol = 1), ]) + "# [<-.tbl_df rejects unknown row indexes" foo <- tibble(x = 1:10, y = 1:10, z = 1:10) foo[list(1:3), ] <- 1 From e4771e9f5291f1f5a1ce11d0881919cd0cc377e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Fri, 17 Apr 2020 08:06:47 +0200 Subject: [PATCH 19/28] - `as_tibble(validate = )` now always triggers a deprecation warning. --- R/as_tibble.R | 21 +++++++----- tests/testthat/test-as_tibble.R | 51 ++++++++++++---------------- tests/testthat/test-zzz-data-frame.R | 4 +++ 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/R/as_tibble.R b/R/as_tibble.R index 75f6a05cf..b39a5db20 100644 --- a/R/as_tibble.R +++ b/R/as_tibble.R @@ -69,7 +69,7 @@ as_tibble.data.frame <- function(x, validate = NULL, ..., .name_repair = c("check_unique", "unique", "universal", "minimal"), rownames = pkgconfig::get_config("tibble::rownames", NULL)) { - .name_repair <- compat_name_repair(.name_repair, validate) + .name_repair <- compat_name_repair(.name_repair, validate, missing(.name_repair)) old_rownames <- raw_rownames(x) if (is.null(.rows)) { @@ -97,7 +97,7 @@ as_tibble.data.frame <- function(x, validate = NULL, ..., as_tibble.list <- function(x, validate = NULL, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal")) { - .name_repair <- compat_name_repair(.name_repair, validate) + .name_repair <- compat_name_repair(.name_repair, validate, missing(.name_repair)) lst_to_tibble(x, .rows, .name_repair, col_lengths(x)) } @@ -109,18 +109,21 @@ lst_to_tibble <- function(x, .rows, .name_repair, lengths = NULL) { recycle_columns(x, .rows, lengths) } -compat_name_repair <- function(.name_repair, validate) { +compat_name_repair <- function(.name_repair, validate, .missing_name_repair) { if (is.null(validate)) return(.name_repair) - name_repair <- if (isTRUE(validate)) "check_unique" else "minimal" - if (!has_length(.name_repair, 1)) { - deprecate_soft("3.0.0", "tibble::as_tibble(validate = )", "as_tibble(.name_repair =)") - } else if (.name_repair != name_repair) { - warn("`.name_repair` takes precedence over the deprecated `validate` argument argument in `as_tibble()`.") - return(.name_repair) + if (!.missing_name_repair) { + name_repair <- .name_repair + } else if (isTRUE(validate)) { + name_repair <- "check_unique" + } else { + name_repair <- "minimal" } + deprecate_soft("2.0.0", "tibble::as_tibble(validate = )", "as_tibble(.name_repair =)", + env = foreign_caller_env()) + name_repair } diff --git a/tests/testthat/test-as_tibble.R b/tests/testthat/test-as_tibble.R index eb6f8aa85..1c4e40f82 100644 --- a/tests/testthat/test-as_tibble.R +++ b/tests/testthat/test-as_tibble.R @@ -470,28 +470,23 @@ test_that("`validate` triggers deprecation message, but then works", { ) }) -test_that("Consistent `validate` and `.name_repair` used together keep silent.", { - scoped_lifecycle_warnings() - - expect_tibble_error( - expect_warning( +test_that("`validate` always raises lifecycle warning.", { + expect_deprecated( + expect_tibble_error( as_tibble(list(a = 1, "hi"), validate = TRUE, .name_repair = "check_unique"), - NA - ), - error_column_names_cannot_be_empty(2) + error_column_names_cannot_be_empty(2) + ) ) - expect_warning( - df <- as_tibble(list(a = 1, "hi", a = 2), validate = FALSE, .name_repair = "minimal"), - NA + expect_deprecated( + df <- as_tibble(list(a = 1, "hi", a = 2), validate = FALSE, .name_repair = "minimal") ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi", a = 2) names(df) <- c("a", "", "a") - expect_warning( - df <- as_tibble(df, validate = FALSE, .name_repair = "minimal"), - NA + expect_deprecated( + df <- as_tibble(df, validate = FALSE, .name_repair = "minimal") ) expect_identical(names(df), c("a", "", "a")) @@ -507,36 +502,32 @@ test_that("Consistent `validate` and `.name_repair` used together keep silent.", }) test_that("Inconsistent `validate` and `.name_repair` used together raise a warning.", { - expect_tibble_error( - expect_warning( + expect_deprecated( + expect_tibble_error( as_tibble(list(a = 1, "hi"), validate = FALSE, .name_repair = "check_unique"), - "precedence" - ), - error_column_names_cannot_be_empty(2) + error_column_names_cannot_be_empty(2) + ) ) - expect_warning( - df <- as_tibble(list(a = 1, "hi", a = 2), validate = TRUE, .name_repair = "minimal"), - "precedence" + expect_deprecated( + df <- as_tibble(list(a = 1, "hi", a = 2), validate = TRUE, .name_repair = "minimal") ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi", a = 2) names(df) <- c("a", "", "a") - expect_warning( - df <- as_tibble(df, validate = TRUE, .name_repair = "minimal"), - "precedence" + expect_deprecated( + df <- as_tibble(df, validate = TRUE, .name_repair = "minimal") ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi") names(df) <- c("a", "") - expect_tibble_error( - expect_warning( + expect_deprecated( + expect_tibble_error( as_tibble(df, validate = FALSE, .name_repair = "check_unique"), - "precedence" - ), - error_column_names_cannot_be_empty(2) + error_column_names_cannot_be_empty(2) + ) ) }) diff --git a/tests/testthat/test-zzz-data-frame.R b/tests/testthat/test-zzz-data-frame.R index c8d0a46d6..996b9fc96 100644 --- a/tests/testthat/test-zzz-data-frame.R +++ b/tests/testthat/test-zzz-data-frame.R @@ -642,6 +642,8 @@ test_that("`validate` triggers deprecation message, but then works", { }) test_that("Consistent `validate` and `.name_repair` used together keep silent.", { + skip_legacy() + scoped_lifecycle_warnings() expect_legacy_error( @@ -678,6 +680,8 @@ test_that("Consistent `validate` and `.name_repair` used together keep silent.", }) test_that("Inconsistent `validate` and `.name_repair` used together raise a warning.", { + skip_legacy() + expect_legacy_error( expect_warning( as_tibble(list(a = 1, "hi"), validate = FALSE, .name_repair = "check_unique"), From dcc436b4a41925c85cc6ea267a04a4576fa28df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Fri, 17 Apr 2020 08:08:52 +0200 Subject: [PATCH 20/28] - More soft-deprecation warnings are actually visible. --- R/subsetting.R | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/R/subsetting.R b/R/subsetting.R index 78b4f50b4..84a7b9fff 100644 --- a/R/subsetting.R +++ b/R/subsetting.R @@ -316,7 +316,8 @@ fix_oob_positive <- function(i, n, warn = TRUE) { warn_oob <- function(oob, n) { if (has_length(oob)) { deprecate_soft("3.0.0", "tibble::`[.tbl_df`(i = 'must lie in [0, rows] if positive,')", - details = "Use `NA` as row index to obtain a row full of `NA` values.") + details = "Use `NA` as row index to obtain a row full of `NA` values.", + env = foreign_caller_env()) } } @@ -334,7 +335,8 @@ fix_oob_negative <- function(i, n, warn = TRUE) { warn_oob_negative <- function(oob, n) { if (has_length(oob)) { deprecate_soft("3.0.0", "tibble::`[.tbl_df`(i = 'must lie in [-rows, 0] if negative,')", - details = "Use `NA` as row index to obtain a row full of `NA` values.") + details = "Use `NA` as row index to obtain a row full of `NA` values.", + env = foreign_caller_env()) } } @@ -343,7 +345,8 @@ fix_oob_invalid <- function(i, is_na_orig) { if (has_length(oob)) { deprecate_soft("3.0.0", "tibble::`[.tbl_df`(i = 'must use valid row names')", - details = "Use `NA` as row index to obtain a row full of `NA` values.") + details = "Use `NA` as row index to obtain a row full of `NA` values.", + env = foreign_caller_env()) i[oob] <- NA_integer_ } @@ -363,12 +366,14 @@ vectbl_as_col_index <- function(j, x, j_arg, assign = FALSE) { tbl_subset2 <- function(x, j, j_arg) { if (is.matrix(j)) { deprecate_soft("3.0.0", "tibble::`[[.tbl_df`(j = 'can\\'t be a matrix", - details = "Recursive subsetting is deprecated for tibbles.") + details = "Recursive subsetting is deprecated for tibbles.", + env = foreign_caller_env()) return(as.matrix(x)[[j]]) } else if (has_length(j, 2) && is.numeric(j)) { deprecate_soft("3.0.0", "tibble::`[[.tbl_df`(j = 'can\\'t be a vector of length 2')", - details = "Recursive subsetting is deprecated for tibbles.") + details = "Recursive subsetting is deprecated for tibbles.", + env = foreign_caller_env()) return(.subset2(x, j)) } else if (is.character(j)) { From 7652a222cf7c4dd6f2d6da4674a2eca3714b6667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Fri, 17 Apr 2020 08:23:53 +0200 Subject: [PATCH 21/28] Bump version to 3.0.0.9003 --- DESCRIPTION | 2 +- NEWS.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index b29585183..83d451305 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tibble Title: Simple Data Frames -Version: 3.0.0.9002 +Version: 3.0.0.9003 Authors@R: c(person(given = "Kirill", family = "M\u00fcller", diff --git a/NEWS.md b/NEWS.md index 8ecaf0096..ba28898ef 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,10 @@ +# tibble 3.0.0.9003 + +- More soft-deprecation warnings are actually visible. +- `as_tibble(validate = )` now always triggers a deprecation warning. +- Subsetting and subassignment of rows with one-column matrices work again, with a deprecation warning (#760). + + # tibble 3.0.0.9002 - `[<-` coerces matrices to data frames (#762). From 1ca12a3b62cc362311f95f6bb4d1cf73b23eaf5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Fri, 17 Apr 2020 09:11:55 +0200 Subject: [PATCH 22/28] Use ns_env() --- R/compat-lifecycle.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/compat-lifecycle.R b/R/compat-lifecycle.R index 068376427..f4804a974 100644 --- a/R/compat-lifecycle.R +++ b/R/compat-lifecycle.R @@ -34,7 +34,7 @@ with_lifecycle_errors <- function(expr) { # Enable once signal_superseded() reaches stable state signal_superseded <- function(...) {} -foreign_caller_env <- function(my_env = env_parent()) { +foreign_caller_env <- function(my_env = ns_env()) { for (n in 2:10) { caller <- caller_env(n) if (!is_reference(env_parent(caller), my_env)) { From 11a462050565b01bb2d7f594939b71c4901e16d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Fri, 17 Apr 2020 12:41:25 +0200 Subject: [PATCH 23/28] If `.name_repair` is a function, no repair messages are shown --- R/names.R | 2 +- tests/testthat/test-as_tibble.R | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/R/names.R b/R/names.R index 880916294..7c9d08d46 100644 --- a/R/names.R +++ b/R/names.R @@ -10,7 +10,7 @@ repaired_names <- function(name, details = NULL) { subclass_name_repair_errors(name = name, details = details, - vec_as_names(name, repair = .name_repair, quiet = quiet) + vec_as_names(name, repair = .name_repair, quiet = quiet || !is_character(.name_repair)) ) } diff --git a/tests/testthat/test-as_tibble.R b/tests/testthat/test-as_tibble.R index 1c4e40f82..e028306e5 100644 --- a/tests/testthat/test-as_tibble.R +++ b/tests/testthat/test-as_tibble.R @@ -176,9 +176,11 @@ test_that("as_tibble() implements universal names", { test_that("as_tibble() implements custom name repair", { - invalid_df <- as_tibble( - list(3, 4, 5), - .name_repair = function(x) make.names(x, unique = TRUE) + expect_silent( + invalid_df <- as_tibble( + list(3, 4, 5), + .name_repair = function(x) make.names(x, unique = TRUE) + ) ) expect_equal(length(invalid_df), 3) expect_equal(nrow(invalid_df), 1) From 80b4b15300453c000590f853b0d8469df76cf387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 19 Apr 2020 20:49:04 +0200 Subject: [PATCH 24/28] Bump version to 3.0.0.9004 --- DESCRIPTION | 2 +- NEWS.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 83d451305..db68723df 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tibble Title: Simple Data Frames -Version: 3.0.0.9003 +Version: 3.0.0.9004 Authors@R: c(person(given = "Kirill", family = "M\u00fcller", diff --git a/NEWS.md b/NEWS.md index ba28898ef..fe46d7b47 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# tibble 3.0.0.9004 + +- If `.name_repair` is a function, no repair messages are shown (#763). + + # tibble 3.0.0.9003 - More soft-deprecation warnings are actually visible. From ba6b95ee0a55430fe66f61312276c8e9ae1f23b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 19 Apr 2020 20:49:09 +0200 Subject: [PATCH 25/28] Bump version to 3.0.1 --- DESCRIPTION | 2 +- NEWS.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index db68723df..c18090f17 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tibble Title: Simple Data Frames -Version: 3.0.0.9004 +Version: 3.0.1 Authors@R: c(person(given = "Kirill", family = "M\u00fcller", diff --git a/NEWS.md b/NEWS.md index fe46d7b47..e235325e7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# tibble 3.0.1 + +- Same as previous version. + + # tibble 3.0.0.9004 - If `.name_repair` is a function, no repair messages are shown (#763). From 6cb60d077e4ad383f9f1184dfbd328c7b6f31837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 19 Apr 2020 20:52:03 +0200 Subject: [PATCH 26/28] Condense --- NEWS.md | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/NEWS.md b/NEWS.md index e235325e7..7613cfa6e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,37 +1,30 @@ # tibble 3.0.1 -- Same as previous version. +## Compatibility fixes +- `[<-.tbl_df()` coerces matrices to data frames (#762). -# tibble 3.0.0.9004 - -- If `.name_repair` is a function, no repair messages are shown (#763). +- Use delayed import for cli to work around unload problems in downstream packages (#754). -# tibble 3.0.0.9003 +## Bug fixes - More soft-deprecation warnings are actually visible. -- `as_tibble(validate = )` now always triggers a deprecation warning. -- Subsetting and subassignment of rows with one-column matrices work again, with a deprecation warning (#760). +- If `.name_repair` is a function, no repair messages are shown (#763). -# tibble 3.0.0.9002 - -- `[<-` coerces matrices to data frames (#762). +- Remove superseded signal for `as_tibble.list()`, because `as_tibble_row()` only works for size 1. -# tibble 3.0.0.9001 +## Enhancements -- Attempts to update a tibble row with an atomic vector give a clearer error message. Recycling message for subassignment appears only if target size is != 1. -- Subsetting and subassignment with logical matrices with one column work again, with a deprecation warning. -- Use delayed import for cli to work around unload problems in downstream packages (#754). -- Remove superseded signal for `as_tibble.list()`, because `as_tibble_row()` only works for size 1. -- Tweak invariants vignette title. +- `as_tibble(validate = )` now always triggers a deprecation warning. +- Subsetting and subassignment of rows with one-column matrices work again, with a deprecation warning (#760). -# tibble 3.0.0.9000 +- Attempts to update a tibble row with an atomic vector give a clearer error message. Recycling message for subassignment appears only if target size is != 1. -- Same as previous version. +- Tweak title of "Invariants" vignette. # tibble 3.0.0 From 5d3d98486faca1f83fdc76270ec3e85b78888eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 19 Apr 2020 20:52:50 +0200 Subject: [PATCH 27/28] Add link to release notes, closes #736 --- pkgdown/_pkgdown.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index b3ebbcdef..bf310a7ed 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -68,6 +68,8 @@ navbar: - text: News menu: - text: "Release notes" + - text: "Version 3.0.0" + href: https://www.tidyverse.org/blog/2020/04/tibble-3-0-0/ - text: "Version 2.1.1" href: https://www.tidyverse.org/articles/2019/03/tibble-2.1.1/ - text: "Version 2.0.1" From 85cd814acaceacee277e1571979db0051c132493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 19 Apr 2020 21:10:05 +0200 Subject: [PATCH 28/28] CRAN comments --- cran-comments.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cran-comments.md b/cran-comments.md index 15daf26da..3ae301595 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,4 +1,4 @@ -Major release. +Patch release to fix errors caught after major release. ## Test environments @@ -14,4 +14,4 @@ Major release. ## Reverse dependencies -All broken downstream package maintainers were notified, many have already updated on CRAN or GitHub. +Not checked.
- with_tbl(tbl[1] <- matrix(1:8, ncol = 2)) + with_tbl(tbl[1] <- list(matrix(1:8, ncol = 2))) #> # A tibble: 4 x 3 #> n[,1] [,2] c li #> @@ -2596,18 +2719,10 @@ column.
- - with_df(df[1:2] <- matrix(1:8, ncol = 2)) - #> n c li - #> 1 1 5 9 - #> 2 2 6 10, 11 - #> 3 3 7 12, 13, 14 - #> 4 4 8 text - - with_tbl(tbl[1:2] <- matrix(1:8, ncol = 2)) + with_tbl(tbl[1:2] <- list(matrix(1:8, ncol = 2))) #> # A tibble: 4 x 3 #> n[,1] [,2] c[,1] [,2] li #> @@ -2673,7 +2788,7 @@ Entire columns can be removed. Specifying `i` is an error. with_tbl(tbl[1, 2:3] <- NULL) #> Error: `NULL` must be a vector, a bare - #> list or a data frame. + #> list, a data frame or a matrix.