From b94ed241f1c4e674aaa1c51750b14de5e9b5bcb9 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Thu, 26 Aug 2021 20:35:25 -0700 Subject: [PATCH 01/19] cols arg should not be provided by user --- man/measure.Rd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/man/measure.Rd b/man/measure.Rd index 73a315e006..60c94d6ac5 100644 --- a/man/measure.Rd +++ b/man/measure.Rd @@ -38,7 +38,10 @@ measurev(fun.list, sep, pattern, cols, multiple.keyword="value.name", are considered measure variables.} \item{pattern}{Perl-compatible regex with capture groups to match to \code{cols}. Columns that match the regex are considered measure variables.} - \item{cols}{A character vector of column names.} + \item{cols}{A character vector that is automatically provided, + with all of the column names of the data table input to melt. + The user should NOT provide this argument; + to specify the columns to be measured, use the pattern argument.} \item{multiple.keyword}{A string, if used as a group name, then measure returns a list and melt returns multiple value columns (with names defined by the unique values in that From 7ef1cc300c40b803f7c37891c0cdb685465d583e Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Fri, 27 Aug 2021 07:22:53 -0700 Subject: [PATCH 02/19] lower case not --- man/measure.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/measure.Rd b/man/measure.Rd index 60c94d6ac5..db706d3619 100644 --- a/man/measure.Rd +++ b/man/measure.Rd @@ -40,7 +40,7 @@ measurev(fun.list, sep, pattern, cols, multiple.keyword="value.name", \code{cols}. Columns that match the regex are considered measure variables.} \item{cols}{A character vector that is automatically provided, with all of the column names of the data table input to melt. - The user should NOT provide this argument; + The user should not provide this argument; to specify the columns to be measured, use the pattern argument.} \item{multiple.keyword}{A string, if used as a group name, then measure returns a list and melt returns multiple From 010d42782dd8c95ba168c0f5191371ab792c2d06 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Fri, 30 Jun 2023 23:01:40 -0400 Subject: [PATCH 03/19] error user should not provide cols argument --- R/utils.R | 8 ++++++-- inst/tests/tests.Rraw | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/R/utils.R b/R/utils.R index 575913d345..456b422e67 100644 --- a/R/utils.R +++ b/R/utils.R @@ -132,8 +132,12 @@ eval_with_cols = function(orig_call, all_cols) { }) if (!is.primitive(fun)) { named_call = match.call(fun, orig_call) - if ("cols" %in% names(formals(fun)) && !"cols" %in% names(named_call)) { - named_call[["cols"]] = all_cols + if ("cols" %in% names(formals(fun))) { + if ("cols" %in% names(named_call)) { + stopf("user should not provide cols argument to %s", paste(fun_uneval)) + } else { + named_call[["cols"]] = all_cols + } } named_call[[1L]] = fun eval(named_call, parent) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index a9eb68ab09..8765141078 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -14068,6 +14068,7 @@ DT = data.table( V9 = c(0.2, -0.1, 1.2, -0.5, 1.4, 1, 0.2, 0.7, 0.4, 1.6), V10 = c(0.8, 0.7, -1.2, -0.9, -0.6, 0.4, -2.3, 2.2, 0.5, -1.4) ) +test(1971.01, DT[ , lapply(.SD, sum), .SDcols = patterns('^V', cols="V7")], error="user should not provide cols argument to patterns") test(1971.1, DT[ , lapply(.SD, sum), .SDcols = patterns('^V')], data.table(V1=-6.3, V2=-6.5, V3=1.3, V4=3.4, V5=-0.9, V6=-1.6, V7=-2, V8=-0.4, V9=6.1, V10=-1.8)) # multiple pattens --> intersection of patterns @@ -17659,6 +17660,7 @@ test(2182.6, melt(DT.wide, measure.vars=list(b=c("b1","b2"))), data.table(a2=2, # new variable_table attribute for measure.vars, PR#4731 for multiple issues measurev = function(cols)cols # user-defined function for computing measure.vars, same name as data.table::measure but user-defined version should be used. test(2183.00001, melt(DT.wide, measure.vars=measurev()), data.table(variable=factor(c("a2","b1","b2")), value=c(2,1,2))) +test(2183.000015, melt(DT.wide, measure.vars=measurev("a2")), error="user should not provide cols argument to measurev") measurev = list("foo", "bar")#measurev below should not use this since it is not a function. test(2183.00002, melt(DTid, measure.vars=measurev(list(value.name=NULL, num=as.complex), pattern="([ab])([12])")), error="Type 'complex' is not supported for joining/merging") test(2183.00004, melt(DTid, measure.vars=measurev(list(value.name=NULL, istr=NULL), pattern="([ab])([12])"))[order(b)], data.table(id=1, istr=paste(c(1,2)), a=c(NA, 2), b=c(1,2))) @@ -17682,6 +17684,7 @@ test(2183.00060, melt(DTid, measure.vars=measurev(list(letter=myfac, value.name= # new variable_table attribute for measure.vars, PR#4731 for multiple issues measure = function(cols)cols # user-defined function for computing measure.vars, same name as data.table::measure but user-defined version should be used. test(2183.01, melt(DT.wide, measure.vars=measure()), data.table(variable=factor(c("a2","b1","b2")), value=c(2,1,2))) +test(2183.015, melt(DT.wide, measure.vars=measure(cols="b2")), error="user should not provide cols argument to measure") measure = list("foo", "bar")#measure below should not use this since it is not a function. test(2183.02, melt(DTid, measure.vars=measure(value.name, num=as.complex, pattern="([ab])([12])")), error="Type 'complex' is not supported for joining/merging") test(2183.03, melt(DTid, measure.vars=structure(list(a=c(NA,"a2"),b=c("b1","b2")), variable_table=data.table(number=as.complex(1:2)))), error="variable_table does not support column type 'complex' for column 'number'") From 66f95d59a842f7d666f0fdeb418844524e2a3813 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Fri, 30 Jun 2023 23:13:59 -0400 Subject: [PATCH 04/19] do not provide cols arg --- inst/tests/tests.Rraw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 8765141078..31a218ea99 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -12362,7 +12362,7 @@ DTout = data.table( value1 = 1:10, value2 = c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j") ) -test(1866.6, melt(DT, measure.vars = patterns("^x", "^y", cols=names(DT))), DTout) +test(1866.6, melt(DT, measure.vars = patterns("^x", "^y")), DTout) # auto fill too few column names (#1625) and auto fill=TRUE when too many column names test(1867.01, fread("A,B\n1,3,5,7\n2,4,6,8\n"), data.table(A=1:2, B=3:4, V3=5:6, V4=7:8), From d597620b53569512a7b9b48f478a7e3ffd3e7e2e Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Fri, 30 Jun 2023 23:36:52 -0400 Subject: [PATCH 05/19] cols arg: user should not provide, add example for .SDcols --- man/patterns.Rd | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/man/patterns.Rd b/man/patterns.Rd index 5041975dc0..018714ea65 100644 --- a/man/patterns.Rd +++ b/man/patterns.Rd @@ -16,18 +16,25 @@ patterns(\dots, cols=character(0)) } \arguments{ \item{\dots}{A set of regular expression patterns.} - \item{cols}{A character vector of names to which each pattern is matched.} + \item{cols}{A character vector of column names to match with + patterns. When used in the context of + \code{melt(measure.vars=patterns())} or + \code{DT[, .SDcols=patterns()]}, the + user should not provide the \code{cols} argument, which is + automatically set to all of the column names of the input data table. + } } \seealso{ - \code{\link{melt}}, - \url{https://github.com/Rdatatable/data.table/wiki/Getting-started} + \code{\link{melt}}, \code{\link{.SD}}, + \url{https://github.com/Rdatatable/data.table/wiki/Getting-started}, + \url{https://cloud.r-project.org/web/packages/data.table/vignettes/datatable-reshape.html}, + \url{https://cloud.r-project.org/web/packages/data.table/vignettes/datatable-sd-usage.html} } \examples{ DT = data.table(x1 = 1:5, x2 = 6:10, y1 = letters[1:5], y2 = letters[6:10]) # melt all columns that begin with 'x' & 'y', respectively, into separate columns -melt(DT, measure.vars = patterns("^x", "^y", cols=names(DT))) -# when used with melt, 'cols' is implicitly assumed to be names of input -# data.table, if not provided. -melt(DT, measure.vars = patterns("^x", "^y")) +melt(DT, measure.vars = patterns(x="^x", y="^y")) +# summarize all columns that contain x +DT[, lapply(.SD, sum), .SDcols=patterns("x")] } \keyword{data} From e8ecedcb31cdbee877d50fba730cfc35308afab4 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Fri, 30 Jun 2023 23:37:39 -0400 Subject: [PATCH 06/19] test error messages --- inst/tests/tests.Rraw | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 9e636c8b7f..d0ecffa2c6 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -17194,7 +17194,7 @@ test(2183.00002, melt(DTid, measure.vars=measurev(list(value.name=NULL, num=as.c test(2183.00004, melt(DTid, measure.vars=measurev(list(value.name=NULL, istr=NULL), pattern="([ab])([12])"))[order(b)], data.table(id=1, istr=paste(c(1,2)), a=c(NA, 2), b=c(1,2))) test(2183.00005, melt(DTid, measure.vars=measurev(list(column=NULL, istr=NULL), pattern="([ab])([12])", multiple.keyword="column"))[order(b)], data.table(id=1, istr=paste(c(1,2)), a=c(NA, 2), b=c(1,2)))#same computation but different multiple.keyword iris.dt = data.table(datasets::iris) -test(2183.00020, melt(iris.dt, measure.vars=measurev(value.name, dim, sep=".", pattern="foo")), error="both sep and pattern arguments used; must use either sep or pattern (not both)") +test(2183.00020, melt(iris.dt, measure.vars=measurev(list(value.name=NULL, dim=NULL), sep=".", pattern="foo")), error="both sep and pattern arguments used; must use either sep or pattern (not both)") test(2183.000201, melt(iris.dt, measure.vars=measurev(list(NULL, dim=NULL), sep=".")), error="in measurev, elements of fun.list must be named, problems: [1]") test(2183.000202, melt(iris.dt, measure.vars=measurev(list(NULL, NULL), sep=".")), error="in measurev, elements of fun.list must be named, problems: [1, 2]") test(2183.00027, melt(iris.dt, measure.vars=measurev(list(value.name=NULL, dim="bar"), sep=".")), error="in the measurev fun.list, each non-NULL element must be a function with at least one argument, problem: dim") @@ -17284,9 +17284,10 @@ test(2183.74, melt(DTid, measure.vars=measure(letter, number, multiple.keyword=a test(2183.75, melt(DTid, measure.vars=measure(letter, number, multiple.keyword=NA_character_, pattern="([ab])([12])")), error="multiple.keyword must be a character string") test(2183.76, melt(DTid, measure.vars=measure(letter, number, multiple.keyword="", pattern="([ab])([12])")), error="multiple.keyword must be a character string with nchar>0") test(2183.77, melt(DTid, measure.vars=measure(letter, cols, pattern="([ab])([12])")), error="group names specified in ... conflict with measure argument names; please fix by changing group names: [cols]") -test(2183.78, melt(DTid, measure.vars=measure(letter, cols=as.integer, pattern="([ab])([12])")), error="cols must be a character vector of column names") +test(2183.78, melt(DTid, measure.vars=measure(letter, cols=as.integer, pattern="([ab])([12])")), error="user should not provide cols argument to measure") test(2183.79, melt(DTid, measure.vars=measure(letter, number, pattern=as.integer)), error="pattern must be character string") test(2183.80, melt(DTid, measure.vars=measure(letter, number, sep=as.integer)), error="sep must be character string") +test(2183.81, data.table:::measure(cols=as.integer), error="cols must be a character vector of column names") # `keyby` allows mixing eval/get with direct columns, #4981 dt <- data.table(a=c(1,2), b=c(3,4), c=c(1,0)) From 776aebb6067a4378f6a22516a3c9e7a7205cb86c Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Thu, 12 Oct 2023 16:10:27 -0700 Subject: [PATCH 07/19] remove mention of cols argument, add link to measure --- man/melt.data.table.Rd | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/man/melt.data.table.Rd b/man/melt.data.table.Rd index 6dd74291d5..d8975f49e5 100644 --- a/man/melt.data.table.Rd +++ b/man/melt.data.table.Rd @@ -66,10 +66,8 @@ into multiple columns in a single function call efficiently. If a vector in the list contains missing values, or is shorter than the max length of the list elements, then the output will include runs of missing values at the specified position, or at the end. -The function -\code{\link{patterns}} can be used to provide regular expression patterns. When -used along with \code{melt}, if \code{cols} argument is not provided, the -patterns will be matched against \code{names(data)}, for convenience. +The functions \code{\link{patterns}} and \code{\link{measure}} +can be used in \code{measure.vars} to melt all columns matching a regular expression. Attributes are preserved if all \code{value} columns are of the same type. By default, if any of the columns to be melted are of type \code{factor}, it'll From 755ab25ca6ae0757a59933fae52d0d0dfb52d21a Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Thu, 15 Feb 2024 15:24:43 -0700 Subject: [PATCH 08/19] add news item --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 81406fed24..8f16dac2ba 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,10 @@ # data.table [v1.15.99](https://github.com/Rdatatable/data.table/milestone/30) (in development) +## BUG FIXES + +X. `measure()` and `patterns()` documentation and error messages now more clearly explain that cols argument of should not be provided by the user, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @tdhock for fixing. + # data.table [v1.15.0](https://github.com/Rdatatable/data.table/milestone/29) (30 Jan 2024) ## BREAKING CHANGE From 7dbdcbeccdd21b022f4c172dd01dd65ba54f8bee Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Mon, 26 Feb 2024 14:12:30 -0700 Subject: [PATCH 09/19] mention NSE more in docs --- NEWS.md | 4 +++- R/utils.R | 3 ++- man/measure.Rd | 20 ++++++++++++-------- man/patterns.Rd | 7 ++++--- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8f16dac2ba..6eee001e9c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,7 +4,9 @@ ## BUG FIXES -X. `measure()` and `patterns()` documentation and error messages now more clearly explain that cols argument of should not be provided by the user, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @tdhock for fixing. +## BREAKING CHANGE + +X. `measure()` and `patterns()` no longer allow `cols` argument to be provided by the user, in the context of `.SDcols` or `melt`. Documentation and error messages now more clearly explain that cols argument of should not be provided by the user, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @tdhock for fixing. # data.table [v1.15.0](https://github.com/Rdatatable/data.table/milestone/29) (30 Jan 2024) diff --git a/R/utils.R b/R/utils.R index 8189cea9f2..cdf4d368fc 100644 --- a/R/utils.R +++ b/R/utils.R @@ -120,6 +120,7 @@ brackify = function(x, quote=FALSE) { eval_with_cols = function(orig_call, all_cols) { parent = parent.frame(2L) fun_uneval = orig_call[[1L]] + stopifnot(length(fun_uneval) == 1) # take fun from either calling env (parent) or from data.table fun = tryCatch({ maybe_fun = eval(fun_uneval, parent) @@ -134,7 +135,7 @@ eval_with_cols = function(orig_call, all_cols) { named_call = match.call(fun, orig_call) if ("cols" %in% names(formals(fun))) { if ("cols" %in% names(named_call)) { - stopf("user should not provide cols argument to %s", paste(fun_uneval)) + stopf("user should not provide cols argument to %s, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument", paste(fun_uneval)) } else { named_call[["cols"]] = all_cols } diff --git a/man/measure.Rd b/man/measure.Rd index db706d3619..d6dd2a1475 100644 --- a/man/measure.Rd +++ b/man/measure.Rd @@ -5,16 +5,15 @@ \description{ These functions compute an integer vector or list for use as the \code{measure.vars} argument to \code{melt}. - Each measured variable name is converted into several groups that occupy + Either \code{sep} or \code{pattern} argument can be used to specify + a subset of input column/variable names to be measured. + Each measured variable name is converted into one or more groups that occupy different columns in the output melted data. \code{measure} allows specifying group names/conversions in R code (each group and conversion specified as an argument) whereas \code{measurev} allows specifying group names/conversions using data values (each group and conversion specified as a list element). - See - \href{../doc/datatable-reshape.html}{\code{vignette("datatable-reshape")}} - for more info. } \usage{ measure(\dots, sep, pattern, cols, multiple.keyword="value.name") @@ -38,10 +37,15 @@ measurev(fun.list, sep, pattern, cols, multiple.keyword="value.name", are considered measure variables.} \item{pattern}{Perl-compatible regex with capture groups to match to \code{cols}. Columns that match the regex are considered measure variables.} - \item{cols}{A character vector that is automatically provided, - with all of the column names of the data table input to melt. - The user should not provide this argument; - to specify the columns to be measured, use the pattern argument.} + \item{cols}{ + A character vector of column names. + When used in the context of + \code{melt(measure.vars=measure())}, the + user should not provide the \code{cols} argument, which is + automatically set to all of the column names of the input data + table, using non-standard evaluation. + To specify the columns to be measured, + use either \code{sep} or \code{pattern} argument.} \item{multiple.keyword}{A string, if used as a group name, then measure returns a list and melt returns multiple value columns (with names defined by the unique values in that diff --git a/man/patterns.Rd b/man/patterns.Rd index 018714ea65..1c0cb45f3d 100644 --- a/man/patterns.Rd +++ b/man/patterns.Rd @@ -21,14 +21,15 @@ patterns(\dots, cols=character(0)) \code{melt(measure.vars=patterns())} or \code{DT[, .SDcols=patterns()]}, the user should not provide the \code{cols} argument, which is - automatically set to all of the column names of the input data table. + automatically set to all of the column names of the input data + table, using non-standard evaluation. } } \seealso{ \code{\link{melt}}, \code{\link{.SD}}, \url{https://github.com/Rdatatable/data.table/wiki/Getting-started}, - \url{https://cloud.r-project.org/web/packages/data.table/vignettes/datatable-reshape.html}, - \url{https://cloud.r-project.org/web/packages/data.table/vignettes/datatable-sd-usage.html} + [`vignette("datatable-reshape")`](https://cloud.r-project.org/web/packages/data.table/vignettes/datatable-reshape.html), + [`vignette("datatable-sd-usage")`](https://cloud.r-project.org/web/packages/data.table/vignettes/datatable-sd-usage.html) } \examples{ DT = data.table(x1 = 1:5, x2 = 6:10, y1 = letters[1:5], y2 = letters[6:10]) From d5b9e81f1c5439b6fb4b67c0cb6470c0cda83cfb Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Tue, 27 Feb 2024 09:45:49 -0700 Subject: [PATCH 10/19] document and test current behavior --- inst/tests/tests.Rraw | 19 +++++++++++++++---- man/data.table.Rd | 4 ++++ man/measure.Rd | 2 ++ man/melt.data.table.Rd | 6 +++--- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 0ddbc50cf5..cc71827ffb 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -13950,7 +13950,18 @@ DT = data.table( V9 = c(0.2, -0.1, 1.2, -0.5, 1.4, 1, 0.2, 0.7, 0.4, 1.6), V10 = c(0.8, 0.7, -1.2, -0.9, -0.6, 0.4, -2.3, 2.2, 0.5, -1.4) ) -test(1971.01, DT[ , lapply(.SD, sum), .SDcols = patterns('^V', cols="V7")], error="user should not provide cols argument to patterns") +test(1971.01, DT[ , lapply(.SD, sum), .SDcols = patterns('^V', cols="V7")], error="user should not provide cols argument to patterns, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") +not_patterns <- function()c("V4","V8") +test(1971.02, DT[ , lapply(.SD, sum), .SDcols = not_patterns()], data.table(V4=3.4, V8=-0.4)) +not_patterns <- function(cols)cols +test(1971.03, DT[ , lapply(.SD, sum), .SDcols = not_patterns()], error='argument "cols" is missing, with no default') +test(1971.04, DT[ , lapply(.SD, sum), .SDcols = not_patterns(c("V4","V8"))], data.table(V4=3.4, V8=-0.4)) +patterns <- function(cols)list(cols[c(6,10)])#with cols arg +test(1971.05, DT[ , lapply(.SD, sum), .SDcols = patterns()], data.table(V4=3.4, V8=-0.4)) +test(1971.06, DT[ , lapply(.SD, sum), .SDcols = patterns(cols="foo")], error="user should not provide cols argument to patterns, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") +patterns <- function()list(c("V4","V8"))#without cols arg +test(1971.07, DT[ , lapply(.SD, sum), .SDcols = patterns()], data.table(V4=3.4, V8=-0.4)) +rm(patterns) test(1971.1, DT[ , lapply(.SD, sum), .SDcols = patterns('^V')], data.table(V1=-6.3, V2=-6.5, V3=1.3, V4=3.4, V5=-0.9, V6=-1.6, V7=-2, V8=-0.4, V9=6.1, V10=-1.8)) # multiple pattens --> intersection of patterns @@ -17241,7 +17252,7 @@ test(2182.6, melt(DT.wide, measure.vars=list(b=c("b1","b2"))), data.table(a2=2, # new variable_table attribute for measure.vars, PR#4731 for multiple issues measurev = function(cols)cols # user-defined function for computing measure.vars, same name as data.table::measure but user-defined version should be used. test(2183.00001, melt(DT.wide, measure.vars=measurev()), data.table(variable=factor(c("a2","b1","b2")), value=c(2,1,2))) -test(2183.000015, melt(DT.wide, measure.vars=measurev("a2")), error="user should not provide cols argument to measurev") +test(2183.000015, melt(DT.wide, measure.vars=measurev("a2")), error="user should not provide cols argument to measurev, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") measurev = list("foo", "bar")#measurev below should not use this since it is not a function. test(2183.00002, melt(DTid, measure.vars=measurev(list(value.name=NULL, num=as.complex), pattern="([ab])([12])")), error="Type 'complex' is not supported for joining/merging") test(2183.00004, melt(DTid, measure.vars=measurev(list(value.name=NULL, istr=NULL), pattern="([ab])([12])"))[order(b)], data.table(id=1, istr=paste(c(1,2)), a=c(NA, 2), b=c(1,2))) @@ -17265,7 +17276,7 @@ test(2183.00060, melt(DTid, measure.vars=measurev(list(letter=myfac, value.name= # new variable_table attribute for measure.vars, PR#4731 for multiple issues measure = function(cols)cols # user-defined function for computing measure.vars, same name as data.table::measure but user-defined version should be used. test(2183.01, melt(DT.wide, measure.vars=measure()), data.table(variable=factor(c("a2","b1","b2")), value=c(2,1,2))) -test(2183.015, melt(DT.wide, measure.vars=measure(cols="b2")), error="user should not provide cols argument to measure") +test(2183.015, melt(DT.wide, measure.vars=measure(cols="b2")), error="user should not provide cols argument to measure, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") measure = list("foo", "bar")#measure below should not use this since it is not a function. test(2183.02, melt(DTid, measure.vars=measure(value.name, num=as.complex, pattern="([ab])([12])")), error="Type 'complex' is not supported for joining/merging") test(2183.03, melt(DTid, measure.vars=structure(list(a=c(NA,"a2"),b=c("b1","b2")), variable_table=data.table(number=as.complex(1:2)))), error="variable_table does not support column type 'complex' for column 'number'") @@ -17337,7 +17348,7 @@ test(2183.74, melt(DTid, measure.vars=measure(letter, number, multiple.keyword=a test(2183.75, melt(DTid, measure.vars=measure(letter, number, multiple.keyword=NA_character_, pattern="([ab])([12])")), error="multiple.keyword must be a character string") test(2183.76, melt(DTid, measure.vars=measure(letter, number, multiple.keyword="", pattern="([ab])([12])")), error="multiple.keyword must be a character string with nchar>0") test(2183.77, melt(DTid, measure.vars=measure(letter, cols, pattern="([ab])([12])")), error="group names specified in ... conflict with measure argument names; please fix by changing group names: [cols]") -test(2183.78, melt(DTid, measure.vars=measure(letter, cols=as.integer, pattern="([ab])([12])")), error="user should not provide cols argument to measure") +test(2183.78, melt(DTid, measure.vars=measure(letter, cols=as.integer, pattern="([ab])([12])")), error="user should not provide cols argument to measure, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") test(2183.79, melt(DTid, measure.vars=measure(letter, number, pattern=as.integer)), error="pattern must be character string") test(2183.80, melt(DTid, measure.vars=measure(letter, number, sep=as.integer)), error="sep must be character string") test(2183.81, data.table:::measure(cols=as.integer), error="cols must be a character vector of column names") diff --git a/man/data.table.Rd b/man/data.table.Rd index 2e326fed0b..8778d4e718 100644 --- a/man/data.table.Rd +++ b/man/data.table.Rd @@ -152,6 +152,10 @@ data.table(\dots, keep.rownames=FALSE, check.names=FALSE, key=NULL, stringsAsFac Inversion (column dropping instead of keeping) can be accomplished be prepending the argument with \code{!} or \code{-} (there's no difference between these), e.g. \code{.SDcols = !c('x', 'y')}. Finally, you can filter columns to include in \code{.SD} based on their \emph{names} according to regular expressions via \code{.SDcols=patterns(regex1, regex2, ...)}. The included columns will be the \emph{intersection} of the columns identified by each pattern; pattern unions can easily be specified with \code{|} in a regex. You can filter columns on \code{values} by passing a function, e.g. \code{.SDcols=\link{is.numeric}}. You can also invert a pattern as usual with \code{.SDcols=!patterns(...)} or \code{.SDcols=!is.numeric}. + + Note that if there is a user-defined function named \code{patterns}, it will be used instead of the usual patterns, and it should return a list of column names to intersect, and if that function has an argument named \code{cols}, then that argument will be set to \code{names(x)} by non-standard evaluation. + + In addition, \code{.SDcols=fun_not_named_patterns()} is possible, and that function should return a character vector of column names, and non-standard evaluation is not used, even if there is an argument named \code{cols}. } \item{verbose}{ \code{TRUE} turns on status and information messages to the console. Turn this on by default using \code{options(datatable.verbose=TRUE)}. The quantity and types of verbosity may be expanded in future. diff --git a/man/measure.Rd b/man/measure.Rd index d6dd2a1475..d230ac7478 100644 --- a/man/measure.Rd +++ b/man/measure.Rd @@ -61,6 +61,8 @@ measurev(fun.list, sep, pattern, cols, multiple.keyword="value.name", (two.iris = data.table(datasets::iris)[c(1,150)]) # melt into a single value column. melt(two.iris, measure.vars = measure(part, dim, sep=".")) +# do the same, with a regex pattern. +melt(two.iris, measure.vars = measure(part, dim, pattern="(.*)[.](.*)")) # do the same, programmatically with measurev my.list = list(part=NULL, dim=NULL) melt(two.iris, measure.vars=measurev(my.list, sep=".")) diff --git a/man/melt.data.table.Rd b/man/melt.data.table.Rd index d8975f49e5..a63b7e17a5 100644 --- a/man/melt.data.table.Rd +++ b/man/melt.data.table.Rd @@ -21,16 +21,16 @@ multiple columns simultaneously. \item{id.vars}{vector of id variables. Can be integer (corresponding id column numbers) or character (id column names) vector. If missing, all non-measure columns will be assigned to it. If integer, must be positive; see Details. } -\item{measure.vars}{Measure variables for \code{melt}ing. Can be missing, vector, list, or pattern-based. +\item{measure.vars}{Measure variables for \code{melt}ing. Can be missing, vector, list, or function. \itemize{ \item{ When missing, \code{measure.vars} will become all columns outside \code{id.vars}. } \item{ Vector can be \code{integer} (implying column numbers) or \code{character} (column names). } \item{ \code{list} is a generalization of the vector version -- each element of the list (which should be \code{integer} or \code{character} as above) will become a \code{melt}ed column. } - \item{ Pattern-based column matching can be achieved with the regular expression-based \code{\link{patterns}} syntax; multiple patterns will produce multiple columns. } + \item{ Pattern-based column matching can be achieved by using the result of \code{\link{patterns}} or \code{\link{measure}} functions. More generally, it is possible to use any function that returns a character vector or list of measure variables, and if this function has an argument named \code{cols}, then that argument will be set to \code{names(data)} by non-standard evaluation. } } - For convenience/clarity in the case of multiple \code{melt}ed columns, resulting column names can be supplied as names to the elements \code{measure.vars} (in the \code{list} and \code{patterns} usages). See also \code{Examples}. } + For convenience/clarity in the case of multiple \code{melt}ed columns, resulting column names can be supplied as names to the elements \code{measure.vars} (in the \code{list} and \code{patterns} usages). See also Examples below. } \item{variable.name}{name (default \code{'variable'}) of output column containing information about which input column(s) were melted. If \code{measure.vars} is an integer/character vector, then each entry of this column contains the name of a melted column from \code{data}. If \code{measure.vars} is a list of integer/character vectors, then each entry of this column contains an integer indicating an index/position in each of those vectors. If \code{measure.vars} has attribute \code{variable_table} then it must be a data table with nrow = length of \code{measure.vars} vector(s), each row describing the corresponding measured variables(s), (typically created via \code{measure}) and its columns will be output instead of the \code{variable.name} column.} \item{value.name}{name for the molten data values column(s). The default name is \code{'value'}. Multiple names can be provided here for the case when \code{measure.vars} is a \code{list}, though note well that the names provided in \code{measure.vars} take precedence. } \item{na.rm}{If \code{TRUE}, \code{NA} values will be removed from the molten From fad662424f06fd6cee381d6b70aa89734dfa66e4 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Wed, 28 Feb 2024 20:49:15 -0700 Subject: [PATCH 11/19] measure = data.table:::measure at top --- inst/tests/tests.Rraw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index b8b5603d1b..45ee3630d3 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -50,6 +50,7 @@ if (exists("test.data.table", .GlobalEnv, inherits=FALSE)) { isReallyReal = data.table:::isReallyReal isRealReallyInt = data.table:::isRealReallyInt is_utc = data.table:::is_utc + measure = data.table:::measure # for test 2183.001 melt.data.table = data.table:::melt.data.table # for test 1953.4 null.data.table = data.table:::null.data.table print.data.table = data.table:::print.data.table @@ -17279,6 +17280,7 @@ test(2183.00060, melt(DTid, measure.vars=measurev(list(letter=myfac, value.name= ### Second block testing measure # new variable_table attribute for measure.vars, PR#4731 for multiple issues +test(2183.001, measure(cols=as.integer), error="cols must be a character vector of column names") measure = function(cols)cols # user-defined function for computing measure.vars, same name as data.table::measure but user-defined version should be used. test(2183.01, melt(DT.wide, measure.vars=measure()), data.table(variable=factor(c("a2","b1","b2")), value=c(2,1,2))) test(2183.015, melt(DT.wide, measure.vars=measure(cols="b2")), error="user should not provide cols argument to measure, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") @@ -17356,7 +17358,6 @@ test(2183.77, melt(DTid, measure.vars=measure(letter, cols, pattern="([ab])([12] test(2183.78, melt(DTid, measure.vars=measure(letter, cols=as.integer, pattern="([ab])([12])")), error="user should not provide cols argument to measure, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") test(2183.79, melt(DTid, measure.vars=measure(letter, number, pattern=as.integer)), error="pattern must be character string") test(2183.80, melt(DTid, measure.vars=measure(letter, number, sep=as.integer)), error="sep must be character string") -test(2183.81, data.table:::measure(cols=as.integer), error="cols must be a character vector of column names") # `keyby` allows mixing eval/get with direct columns, #4981 dt <- data.table(a=c(1,2), b=c(3,4), c=c(1,0)) From 1358da45076d0703a607302e2b68c2654903d01c Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Wed, 28 Feb 2024 20:57:32 -0700 Subject: [PATCH 12/19] paste -> as.character --- R/utils.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index cdf4d368fc..33bdf2ebe4 100644 --- a/R/utils.R +++ b/R/utils.R @@ -135,7 +135,7 @@ eval_with_cols = function(orig_call, all_cols) { named_call = match.call(fun, orig_call) if ("cols" %in% names(formals(fun))) { if ("cols" %in% names(named_call)) { - stopf("user should not provide cols argument to %s, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument", paste(fun_uneval)) + stopf("user should not provide cols argument to %s, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument", as.character(fun_uneval)) } else { named_call[["cols"]] = all_cols } From 5084a6a15fd00ecf5c2bb28667838960e911b04b Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Wed, 28 Feb 2024 21:01:58 -0700 Subject: [PATCH 13/19] fix typo --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 15e53003fb..d0ff902462 100644 --- a/NEWS.md +++ b/NEWS.md @@ -20,7 +20,7 @@ ## BREAKING CHANGE -X. `measure()` and `patterns()` no longer allow `cols` argument to be provided by the user, in the context of `.SDcols` or `melt`. Documentation and error messages now more clearly explain that cols argument of should not be provided by the user, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @tdhock for fixing. +X. `measure()` and `patterns()` no longer allow `cols` argument to be provided by the user, in the context of `.SDcols` or `melt`. Documentation and error messages now more clearly explain that cols argument should not be provided by the user, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @tdhock for fixing. 3. Namespace-qualifying `data.table::shift()`, `data.table::first()`, or `data.table::last()` will not deactivate GForce, [#5942](https://github.com/Rdatatable/data.table/issues/5942). Thanks @MichaelChirico for the proposal and fix. Namespace-qualifying other calls like `stats::sum()`, `base::prod()`, etc., continue to work as an escape valve to avoid GForce, e.g. to ensure S3 method dispatch. From 0ff5d9ba7f75dc657ef9b3c010312ce5c1c2842a Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Wed, 28 Feb 2024 21:06:34 -0700 Subject: [PATCH 14/19] function can be called --- man/melt.data.table.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/melt.data.table.Rd b/man/melt.data.table.Rd index a63b7e17a5..8ec6202513 100644 --- a/man/melt.data.table.Rd +++ b/man/melt.data.table.Rd @@ -21,13 +21,13 @@ multiple columns simultaneously. \item{id.vars}{vector of id variables. Can be integer (corresponding id column numbers) or character (id column names) vector. If missing, all non-measure columns will be assigned to it. If integer, must be positive; see Details. } -\item{measure.vars}{Measure variables for \code{melt}ing. Can be missing, vector, list, or function. +\item{measure.vars}{Measure variables for \code{melt}ing. Can be missing, vector, list, or a function can be called. \itemize{ \item{ When missing, \code{measure.vars} will become all columns outside \code{id.vars}. } \item{ Vector can be \code{integer} (implying column numbers) or \code{character} (column names). } \item{ \code{list} is a generalization of the vector version -- each element of the list (which should be \code{integer} or \code{character} as above) will become a \code{melt}ed column. } - \item{ Pattern-based column matching can be achieved by using the result of \code{\link{patterns}} or \code{\link{measure}} functions. More generally, it is possible to use any function that returns a character vector or list of measure variables, and if this function has an argument named \code{cols}, then that argument will be set to \code{names(data)} by non-standard evaluation. } + \item{ Pattern-based column matching can be achieved by using the result of \code{\link{patterns}} or \code{\link{measure}} functions. More generally, it is possible to call any function that returns a character vector or list of measure variables, and if this function has an argument named \code{cols}, then that argument will be set to \code{names(data)} by non-standard evaluation. } } For convenience/clarity in the case of multiple \code{melt}ed columns, resulting column names can be supplied as names to the elements \code{measure.vars} (in the \code{list} and \code{patterns} usages). See also Examples below. } From 8dbbe0c9fc1d050efad82642e9a9d4bf6082f71d Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Fri, 1 Mar 2024 12:12:01 -0800 Subject: [PATCH 15/19] refactor+refine NEWS --- NEWS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index d0ff902462..abd7a57d53 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,10 @@ # data.table [v1.15.99](https://github.com/Rdatatable/data.table/milestone/30) (in development) +## BREAKING CHANGE + +1. `measure()` and `patterns()` no longer allow `cols` argument to be provided by the user, in the context of `.SDcols` or `melt`. Documentation and error messages also now more clearly explain this, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks @UweBlock for the report and to @tdhock for fixing. + ## NEW FEATURES 1. `print.data.table()` shows empty (`NULL`) list column entries as `[NULL]` for emphasis. Previously they would just print nothing (same as for empty string). Part of [#4198](https://github.com/Rdatatable/data.table/issues/4198). Thanks @sritchie73 for the proposal and fix. @@ -18,10 +22,6 @@ ## BUG FIXES -## BREAKING CHANGE - -X. `measure()` and `patterns()` no longer allow `cols` argument to be provided by the user, in the context of `.SDcols` or `melt`. Documentation and error messages now more clearly explain that cols argument should not be provided by the user, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @tdhock for fixing. - 3. Namespace-qualifying `data.table::shift()`, `data.table::first()`, or `data.table::last()` will not deactivate GForce, [#5942](https://github.com/Rdatatable/data.table/issues/5942). Thanks @MichaelChirico for the proposal and fix. Namespace-qualifying other calls like `stats::sum()`, `base::prod()`, etc., continue to work as an escape valve to avoid GForce, e.g. to ensure S3 method dispatch. ## BUG FIXES From 5bc9f5494759a07b26a862908bdb69767eb781f6 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Thu, 4 Apr 2024 20:29:31 -0700 Subject: [PATCH 16/19] rm docs and tests for user-defined patterns --- inst/tests/tests.Rraw | 6 ------ man/data.table.Rd | 4 ---- 2 files changed, 10 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 45ee3630d3..638ff48e5b 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -13962,12 +13962,6 @@ test(1971.02, DT[ , lapply(.SD, sum), .SDcols = not_patterns()], data.table(V4=3 not_patterns <- function(cols)cols test(1971.03, DT[ , lapply(.SD, sum), .SDcols = not_patterns()], error='argument "cols" is missing, with no default') test(1971.04, DT[ , lapply(.SD, sum), .SDcols = not_patterns(c("V4","V8"))], data.table(V4=3.4, V8=-0.4)) -patterns <- function(cols)list(cols[c(6,10)])#with cols arg -test(1971.05, DT[ , lapply(.SD, sum), .SDcols = patterns()], data.table(V4=3.4, V8=-0.4)) -test(1971.06, DT[ , lapply(.SD, sum), .SDcols = patterns(cols="foo")], error="user should not provide cols argument to patterns, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") -patterns <- function()list(c("V4","V8"))#without cols arg -test(1971.07, DT[ , lapply(.SD, sum), .SDcols = patterns()], data.table(V4=3.4, V8=-0.4)) -rm(patterns) test(1971.1, DT[ , lapply(.SD, sum), .SDcols = patterns('^V')], data.table(V1=-6.3, V2=-6.5, V3=1.3, V4=3.4, V5=-0.9, V6=-1.6, V7=-2, V8=-0.4, V9=6.1, V10=-1.8)) # multiple pattens --> intersection of patterns diff --git a/man/data.table.Rd b/man/data.table.Rd index 8778d4e718..2e326fed0b 100644 --- a/man/data.table.Rd +++ b/man/data.table.Rd @@ -152,10 +152,6 @@ data.table(\dots, keep.rownames=FALSE, check.names=FALSE, key=NULL, stringsAsFac Inversion (column dropping instead of keeping) can be accomplished be prepending the argument with \code{!} or \code{-} (there's no difference between these), e.g. \code{.SDcols = !c('x', 'y')}. Finally, you can filter columns to include in \code{.SD} based on their \emph{names} according to regular expressions via \code{.SDcols=patterns(regex1, regex2, ...)}. The included columns will be the \emph{intersection} of the columns identified by each pattern; pattern unions can easily be specified with \code{|} in a regex. You can filter columns on \code{values} by passing a function, e.g. \code{.SDcols=\link{is.numeric}}. You can also invert a pattern as usual with \code{.SDcols=!patterns(...)} or \code{.SDcols=!is.numeric}. - - Note that if there is a user-defined function named \code{patterns}, it will be used instead of the usual patterns, and it should return a list of column names to intersect, and if that function has an argument named \code{cols}, then that argument will be set to \code{names(x)} by non-standard evaluation. - - In addition, \code{.SDcols=fun_not_named_patterns()} is possible, and that function should return a character vector of column names, and non-standard evaluation is not used, even if there is an argument named \code{cols}. } \item{verbose}{ \code{TRUE} turns on status and information messages to the console. Turn this on by default using \code{options(datatable.verbose=TRUE)}. The quantity and types of verbosity may be expanded in future. From ad39048bb3803ab6d04b3e33e991cadbb645cbe0 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Thu, 4 Apr 2024 20:33:01 -0700 Subject: [PATCH 17/19] rm not_patterns tests --- inst/tests/tests.Rraw | 5 ----- 1 file changed, 5 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 638ff48e5b..7d3daef1e8 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -13957,11 +13957,6 @@ DT = data.table( V10 = c(0.8, 0.7, -1.2, -0.9, -0.6, 0.4, -2.3, 2.2, 0.5, -1.4) ) test(1971.01, DT[ , lapply(.SD, sum), .SDcols = patterns('^V', cols="V7")], error="user should not provide cols argument to patterns, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument") -not_patterns <- function()c("V4","V8") -test(1971.02, DT[ , lapply(.SD, sum), .SDcols = not_patterns()], data.table(V4=3.4, V8=-0.4)) -not_patterns <- function(cols)cols -test(1971.03, DT[ , lapply(.SD, sum), .SDcols = not_patterns()], error='argument "cols" is missing, with no default') -test(1971.04, DT[ , lapply(.SD, sum), .SDcols = not_patterns(c("V4","V8"))], data.table(V4=3.4, V8=-0.4)) test(1971.1, DT[ , lapply(.SD, sum), .SDcols = patterns('^V')], data.table(V1=-6.3, V2=-6.5, V3=1.3, V4=3.4, V5=-0.9, V6=-1.6, V7=-2, V8=-0.4, V9=6.1, V10=-1.8)) # multiple pattens --> intersection of patterns From a485c791c05a0983a56e21ef5b43392d7e7a1ee9 Mon Sep 17 00:00:00 2001 From: Toby Dylan Hocking Date: Thu, 4 Apr 2024 20:29:00 -0700 Subject: [PATCH 18/19] remove un-necessary nesting Co-authored-by: Michael Chirico --- R/utils.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/utils.R b/R/utils.R index 33bdf2ebe4..d06dee7413 100644 --- a/R/utils.R +++ b/R/utils.R @@ -136,9 +136,8 @@ eval_with_cols = function(orig_call, all_cols) { if ("cols" %in% names(formals(fun))) { if ("cols" %in% names(named_call)) { stopf("user should not provide cols argument to %s, when specifying the columns for melt or .SDcols; in this context, non-standard evaluation is used internally to set cols to all data table column names, so please fix by removing cols argument", as.character(fun_uneval)) - } else { - named_call[["cols"]] = all_cols } + named_call[["cols"]] = all_cols } named_call[[1L]] = fun eval(named_call, parent) From 5a8448367c2a3f2abbccf4d5b9f4d1c557345e89 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 8 Apr 2024 09:35:28 -0700 Subject: [PATCH 19/19] revert --- R/utils.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index d06dee7413..ecc36e9a43 100644 --- a/R/utils.R +++ b/R/utils.R @@ -120,7 +120,6 @@ brackify = function(x, quote=FALSE) { eval_with_cols = function(orig_call, all_cols) { parent = parent.frame(2L) fun_uneval = orig_call[[1L]] - stopifnot(length(fun_uneval) == 1) # take fun from either calling env (parent) or from data.table fun = tryCatch({ maybe_fun = eval(fun_uneval, parent)