From 2b10409ccf67aaf35aae5b2ffa9812692a8bf4c4 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Sun, 19 Jul 2026 17:07:36 -0700 Subject: [PATCH 1/5] backport deparse1() --- R/data.table.R | 8 ++++---- R/transpose.R | 2 +- R/utils.R | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/R/data.table.R b/R/data.table.R index f1eae31ea6..81c3596643 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -567,7 +567,7 @@ replace_dot_alias = function(e) { stopf("When by and keyby are both provided, keyby must be TRUE or FALSE") } if (missing(by)) { missingby=TRUE; by=bysub=NULL } # possible when env is used, PR#4304 - else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "by", paste(deparse(bysub, width.cutoff=500L), collapse="\n")) + else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "by", deparse1(bysub, width.cutoff=500L, collapse="\n")) } bynull = !missingby && is.null(by) #3530 byjoin = !is.null(by) && is.symbol(bysub) && bysub==".EACHI" @@ -632,7 +632,7 @@ replace_dot_alias = function(e) { substitute2(.j, env), list(.j = substitute(j)) )) - if (missing(jsub)) {j = substitute(); jsub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "j", paste(deparse(jsub, width.cutoff=500L), collapse="\n")) + if (missing(jsub)) {j = substitute(); jsub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "j", deparse1(jsub, width.cutoff=500L, collapse="\n")) } } if (!missing(j)) { @@ -722,7 +722,7 @@ replace_dot_alias = function(e) { substitute2(.i, env), list(.i = substitute(i)) )) - if (missing(isub)) {i = substitute(); isub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "i", paste(deparse(isub, width.cutoff=500L), collapse="\n")) + if (missing(isub)) {i = substitute(); isub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "i", deparse1(isub, width.cutoff=500L, collapse="\n")) } } if (!missing(i)) { @@ -2252,7 +2252,7 @@ replace_dot_alias = function(e) { # What's the name of the top-level call in 'j'? # NB: earlier, we used 'as.character()' but that fails for closures/builtins (#6026). -root_name = function(jsub) if (is.call(jsub)) paste(deparse(jsub[[1L]]), collapse = " ") else "" +root_name = function(jsub) if (is.call(jsub)) deparse1(jsub[[1L]]) else "" DT = function(x, ...) { #4872 old = getOption("datatable.optimize") diff --git a/R/transpose.R b/R/transpose.R index 0da0123b94..a9d504408b 100644 --- a/R/transpose.R +++ b/R/transpose.R @@ -51,7 +51,7 @@ tstrsplit = function(x, ..., fill=NA, type.convert=FALSE, keep, names=FALSE) { if(!n) stopf("The argument 'type.convert' does not support empty list.") is_named = nzchar(names(type.convert)) all_is_named = length(is_named) && all(is_named) # because all(is_named)=TRUE if is_named=NULL <-- names(type.convert)=NULL - last_item = paste(deparse(substitute(type.convert)[[n + 1L]], width.cutoff=500L), collapse=" ") + last_item = deparse1(substitute(type.convert)[[n + 1L]], width.cutoff=500L) if (!all_is_named) { if (!(sum(!is_named) == 1L && !is_named[n] && is.function(type.convert[[n]]))) stopf("When the argument 'type.convert' contains an unnamed element, it is expected to be the last element and should be a function. More than one unnamed element is not allowed unless all elements are functions with length equal to %d (the length of the transpose list or 'keep' argument if it is specified).", length(keep)) diff --git a/R/utils.R b/R/utils.R index 27df811832..0e104e267c 100644 --- a/R/utils.R +++ b/R/utils.R @@ -11,6 +11,8 @@ nan_is_na = function(x) { stopf("Argument 'nan' must be NA or NaN") } +if (!exists("deparse1", "package:base")) deparse1 <- function(x, collapse=" ", width.cutoff=60L) paste(deparse(x, width.cutoff=width.cutoff), collapse=collapse) # nolint: paste_linter. + # R 4.4.0 if (!exists("%||%", "package:base")) `%||%` <- function(x, y) if (is.null(x)) y else x # nolint: coalesce_linter. @@ -202,7 +204,7 @@ is_utc = function(tz) { if (!is.call(e)) return(FALSE) if (is.name(e1 <- e[[1L]])) return(e1 %chin% f) if (e1 %iscall% c('::', ':::')) return(e1[[3L]] %chin% f) - paste(deparse(e1), collapse = " ") %chin% f # complicated cases e.g. a closure/builtin on LHS of call; note that format() is much (e.g. 40x) slower than deparse() + deparse(e1) %chin% f # complicated cases e.g. a closure/builtin on LHS of call; note that format() is much (e.g. 40x) slower than deparse() } # nocov start #593 always return a data.table From f29cccbc9de61975a4c751354618de0fea1a1600 Mon Sep 17 00:00:00 2001 From: Ivan K Date: Mon, 20 Jul 2026 11:21:43 +0300 Subject: [PATCH 2/5] Fix %iscall% for complex LHS --- R/utils.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 0e104e267c..90a54616bb 100644 --- a/R/utils.R +++ b/R/utils.R @@ -204,7 +204,7 @@ is_utc = function(tz) { if (!is.call(e)) return(FALSE) if (is.name(e1 <- e[[1L]])) return(e1 %chin% f) if (e1 %iscall% c('::', ':::')) return(e1[[3L]] %chin% f) - deparse(e1) %chin% f # complicated cases e.g. a closure/builtin on LHS of call; note that format() is much (e.g. 40x) slower than deparse() + deparse1(e1) %chin% f # complicated cases e.g. a closure/builtin on LHS of call; note that format() is much (e.g. 40x) slower than deparse() } # nocov start #593 always return a data.table From f8e4b85155ff9035b5dad8a4218bd95f6d633e5a Mon Sep 17 00:00:00 2001 From: Ivan K Date: Mon, 20 Jul 2026 11:25:32 +0300 Subject: [PATCH 3/5] Comment, style change --- R/utils.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 90a54616bb..7c7fc7f004 100644 --- a/R/utils.R +++ b/R/utils.R @@ -11,7 +11,8 @@ nan_is_na = function(x) { stopf("Argument 'nan' must be NA or NaN") } -if (!exists("deparse1", "package:base")) deparse1 <- function(x, collapse=" ", width.cutoff=60L) paste(deparse(x, width.cutoff=width.cutoff), collapse=collapse) # nolint: paste_linter. +# R 4.4.0 +if (!exists("deparse1", "package:base")) deparse1 = function(x, collapse=" ", width.cutoff=60L) paste(deparse(x, width.cutoff=width.cutoff), collapse=collapse) # nolint: paste_linter. # R 4.4.0 if (!exists("%||%", "package:base")) `%||%` <- function(x, y) if (is.null(x)) y else x # nolint: coalesce_linter. From f4648f7b3fc8b2d7eb05ab4509f2c1a203e391c1 Mon Sep 17 00:00:00 2001 From: aitap Date: Mon, 20 Jul 2026 13:17:13 +0000 Subject: [PATCH 4/5] width.cutoff=500L Co-authored-by: Benjamin Schwendinger <52290390+ben-schwen@users.noreply.github.com> --- R/utils.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 7c7fc7f004..7d2c944bc4 100644 --- a/R/utils.R +++ b/R/utils.R @@ -12,7 +12,7 @@ nan_is_na = function(x) { } # R 4.4.0 -if (!exists("deparse1", "package:base")) deparse1 = function(x, collapse=" ", width.cutoff=60L) paste(deparse(x, width.cutoff=width.cutoff), collapse=collapse) # nolint: paste_linter. +if (!exists("deparse1", "package:base")) deparse1 = function(x, collapse=" ", width.cutoff=500L) paste(deparse(x, width.cutoff=width.cutoff), collapse=collapse) # nolint: paste_linter. # R 4.4.0 if (!exists("%||%", "package:base")) `%||%` <- function(x, y) if (is.null(x)) y else x # nolint: coalesce_linter. From 48b5cd4d30426a5361849b764760ac381d7df315 Mon Sep 17 00:00:00 2001 From: aitap Date: Mon, 20 Jul 2026 13:29:41 +0000 Subject: [PATCH 5/5] Fix widths according to default argument Co-authored-by: aitap --- R/data.table.R | 8 ++++---- R/transpose.R | 2 +- R/utils.R | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/R/data.table.R b/R/data.table.R index 81c3596643..70160affa1 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -567,7 +567,7 @@ replace_dot_alias = function(e) { stopf("When by and keyby are both provided, keyby must be TRUE or FALSE") } if (missing(by)) { missingby=TRUE; by=bysub=NULL } # possible when env is used, PR#4304 - else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "by", deparse1(bysub, width.cutoff=500L, collapse="\n")) + else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "by", deparse1(bysub, collapse="\n")) } bynull = !missingby && is.null(by) #3530 byjoin = !is.null(by) && is.symbol(bysub) && bysub==".EACHI" @@ -632,7 +632,7 @@ replace_dot_alias = function(e) { substitute2(.j, env), list(.j = substitute(j)) )) - if (missing(jsub)) {j = substitute(); jsub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "j", deparse1(jsub, width.cutoff=500L, collapse="\n")) + if (missing(jsub)) {j = substitute(); jsub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "j", deparse1(jsub, collapse="\n")) } } if (!missing(j)) { @@ -722,7 +722,7 @@ replace_dot_alias = function(e) { substitute2(.i, env), list(.i = substitute(i)) )) - if (missing(isub)) {i = substitute(); isub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "i", deparse1(isub, width.cutoff=500L, collapse="\n")) + if (missing(isub)) {i = substitute(); isub=NULL} else if (verbose && !is.null(env)) catf("Argument '%s' after substitute: %s\n", "i", deparse1(isub, collapse="\n")) } } if (!missing(i)) { @@ -2252,7 +2252,7 @@ replace_dot_alias = function(e) { # What's the name of the top-level call in 'j'? # NB: earlier, we used 'as.character()' but that fails for closures/builtins (#6026). -root_name = function(jsub) if (is.call(jsub)) deparse1(jsub[[1L]]) else "" +root_name = function(jsub) if (is.call(jsub)) deparse1(jsub[[1L]], width.cutoff=60L) else "" DT = function(x, ...) { #4872 old = getOption("datatable.optimize") diff --git a/R/transpose.R b/R/transpose.R index a9d504408b..6ade0cb138 100644 --- a/R/transpose.R +++ b/R/transpose.R @@ -51,7 +51,7 @@ tstrsplit = function(x, ..., fill=NA, type.convert=FALSE, keep, names=FALSE) { if(!n) stopf("The argument 'type.convert' does not support empty list.") is_named = nzchar(names(type.convert)) all_is_named = length(is_named) && all(is_named) # because all(is_named)=TRUE if is_named=NULL <-- names(type.convert)=NULL - last_item = deparse1(substitute(type.convert)[[n + 1L]], width.cutoff=500L) + last_item = deparse1(substitute(type.convert)[[n + 1L]]) if (!all_is_named) { if (!(sum(!is_named) == 1L && !is_named[n] && is.function(type.convert[[n]]))) stopf("When the argument 'type.convert' contains an unnamed element, it is expected to be the last element and should be a function. More than one unnamed element is not allowed unless all elements are functions with length equal to %d (the length of the transpose list or 'keep' argument if it is specified).", length(keep)) diff --git a/R/utils.R b/R/utils.R index 7d2c944bc4..4fc6b6cae9 100644 --- a/R/utils.R +++ b/R/utils.R @@ -205,7 +205,7 @@ is_utc = function(tz) { if (!is.call(e)) return(FALSE) if (is.name(e1 <- e[[1L]])) return(e1 %chin% f) if (e1 %iscall% c('::', ':::')) return(e1[[3L]] %chin% f) - deparse1(e1) %chin% f # complicated cases e.g. a closure/builtin on LHS of call; note that format() is much (e.g. 40x) slower than deparse() + deparse1(e1, width.cutoff=60L) %chin% f # complicated cases e.g. a closure/builtin on LHS of call; note that format() is much (e.g. 40x) slower than deparse() } # nocov start #593 always return a data.table