From a1e79e856f078edf980153f63628fd5cd650075f Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Tue, 10 Nov 2020 16:00:11 -0600 Subject: [PATCH] Remove extractStackTrace and formatStackTrace --- NAMESPACE | 2 - R/conditions.R | 156 +++++++--------------------------------------- man/stacktrace.Rd | 28 --------- 3 files changed, 23 insertions(+), 163 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 1b6ceaa258..47eaae46db 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -101,7 +101,6 @@ export(enableBookmarking) export(eventReactive) export(exportTestValues) export(exprToFunction) -export(extractStackTrace) export(fileInput) export(fillCol) export(fillPage) @@ -112,7 +111,6 @@ export(fixedRow) export(flowLayout) export(fluidPage) export(fluidRow) -export(formatStackTrace) export(freezeReactiveVal) export(freezeReactiveValue) export(getCurrentOutputInfo) diff --git a/R/conditions.R b/R/conditions.R index 70e64bc699..6bc1d8b473 100644 --- a/R/conditions.R +++ b/R/conditions.R @@ -133,7 +133,7 @@ captureStackTraces <- function(expr) { createStackTracePromiseDomain <- function() { # These are actually stateless, we wouldn't have to create a new one each time # if we didn't want to. They're pretty cheap though. - + d <- promises::new_promise_domain( wrapOnFulfilled = function(onFulfilled) { force(onFulfilled) @@ -266,10 +266,10 @@ withLogErrors <- function(expr, printError <- function(cond, full = getOption("shiny.fullstacktrace", FALSE), offset = getOption("shiny.stacktraceoffset", TRUE)) { - - warning(call. = FALSE, immediate. = TRUE, sprintf("Error in %s: %s", + + warning(call. = FALSE, immediate. = TRUE, sprintf("Error in %s: %s", getCallNames(list(conditionCall(cond))), conditionMessage(cond))) - + printStackTrace(cond, full = full, offset = offset) } @@ -282,16 +282,16 @@ printStackTrace <- function(cond, should_drop <- !full should_strip <- !full should_prune <- !full - + stackTraceCalls <- c( attr(cond, "deep.stack.trace", exact = TRUE), list(attr(cond, "stack.trace", exact = TRUE)) ) - + stackTraceParents <- lapply(stackTraceCalls, attr, which = "parents", exact = TRUE) stackTraceCallNames <- lapply(stackTraceCalls, getCallNames) stackTraceCalls <- lapply(stackTraceCalls, offsetSrcrefs, offset = offset) - + # Use dropTrivialFrames logic to remove trailing bits (.handleSimpleError, h) if (should_drop) { # toKeep is a list of logical vectors, of which elements (stack frames) to keep @@ -301,7 +301,7 @@ printStackTrace <- function(cond, stackTraceCallNames <- mapply(stackTraceCallNames, FUN = `[`, toKeep, SIMPLIFY = FALSE) stackTraceParents <- mapply(stackTraceParents, FUN = `[`, toKeep, SIMPLIFY = FALSE) } - + delayedAssign("all_true", { # List of logical vectors that are all TRUE, the same shape as # stackTraceCallNames. Delay the evaluation so we don't create it unless @@ -310,7 +310,7 @@ printStackTrace <- function(cond, rep_len(TRUE, length(st)) }) }) - + # stripStackTraces and lapply(stackTraceParents, pruneStackTrace) return lists # of logical vectors. Use mapply(FUN = `&`) to boolean-and each pair of the # logical vectors. @@ -320,7 +320,7 @@ printStackTrace <- function(cond, FUN = `&`, SIMPLIFY = FALSE ) - + dfs <- mapply(seq_along(stackTraceCalls), rev(stackTraceCalls), rev(stackTraceCallNames), rev(toShow), FUN = function(i, calls, nms, index) { st <- data.frame( num = rev(which(index)), @@ -329,7 +329,7 @@ printStackTrace <- function(cond, category = rev(getCallCategories(calls[index])), stringsAsFactors = FALSE ) - + if (i != 1) { message("From earlier call:") } @@ -357,83 +357,8 @@ printStackTrace <- function(cond, st }, SIMPLIFY = FALSE) - - invisible() -} - -#' @details `extractStackTrace` takes a list of calls (e.g. as returned -#' from `conditionStackTrace(cond)`) and returns a data frame with one -#' row for each stack frame and the columns `num` (stack frame number), -#' `call` (a function name or similar), and `loc` (source file path -#' and line number, if available). It was deprecated after shiny 1.0.5 because -#' it doesn't support deep stack traces. -#' @rdname stacktrace -#' @export -extractStackTrace <- function(calls, - full = getOption("shiny.fullstacktrace", FALSE), - offset = getOption("shiny.stacktraceoffset", TRUE)) { - - shinyDeprecated(NULL, - "extractStackTrace is deprecated. Please contact the Shiny team if you were using this functionality.", - version = "1.0.5") - - srcrefs <- getSrcRefs(calls) - if (offset) { - # Offset calls vs. srcrefs by 1 to make them more intuitive. - # E.g. for "foo [bar.R:10]", line 10 of bar.R will be part of - # the definition of foo(). - srcrefs <- c(utils::tail(srcrefs, -1), list(NULL)) - } - calls <- setSrcRefs(calls, srcrefs) - - callnames <- getCallNames(calls) - - # Hide and show parts of the callstack based on ..stacktrace(on|off).. - if (full) { - toShow <- rep.int(TRUE, length(calls)) - } else { - # Remove stop(), .handleSimpleError(), and h() calls from the end of - # the calls--they don't add any helpful information. But only remove - # the last *contiguous* block of them, and then, only if they are the - # last thing in the calls list. - hideable <- callnames %in% c("stop", ".handleSimpleError", "h") - # What's the last that *didn't* match stop/.handleSimpleError/h? - lastGoodCall <- max(which(!hideable)) - toRemove <- length(calls) - lastGoodCall - # But don't remove more than 5 levels--that's an indication we might - # have gotten it wrong, I guess - if (toRemove > 0 && toRemove < 5) { - calls <- utils::head(calls, -toRemove) - callnames <- utils::head(callnames, -toRemove) - } - # This uses a ref-counting scheme. It might make sense to switch this - # to a toggling scheme, so the most recent ..stacktrace(on|off).. - # directive wins, regardless of what came before it. - # Also explicitly remove ..stacktraceon.. because it can appear with - # score > 0 but still should never be shown. - score <- rep.int(0, length(callnames)) - score[callnames == "..stacktraceoff.."] <- -1 - score[callnames == "..stacktraceon.."] <- 1 - toShow <- (1 + cumsum(score)) > 0 & !(callnames %in% c("..stacktraceon..", "..stacktraceoff..", "..stacktracefloor..")) - - # doTryCatch, tryCatchOne, and tryCatchList are not informative--they're - # just internals for tryCatch - toShow <- toShow & !(callnames %in% c("doTryCatch", "tryCatchOne", "tryCatchList")) - } - calls <- calls[toShow] - - calls <- rev(calls) # Show in traceback() order - index <- rev(which(toShow)) - width <- floor(log10(max(index))) + 1 - - data.frame( - num = index, - call = getCallNames(calls), - loc = getLocs(calls), - category = getCallCategories(calls), - stringsAsFactors = FALSE - ) + invisible() } stripStackTraces <- function(stackTraces, values = FALSE) { @@ -459,19 +384,19 @@ stripOneStackTrace <- function(stackTrace, truncateFloor, startingScore) { prefix <- rep_len(FALSE, indexOfFloor) } } - + if (length(stackTrace) == 0) { return(list(score = startingScore, character(0))) } - + score <- rep.int(0L, length(stackTrace)) score[stackTrace == "..stacktraceon.."] <- 1L score[stackTrace == "..stacktraceoff.."] <- -1L score <- startingScore + cumsum(score) - + toShow <- score > 0 & !(stackTrace %in% c("..stacktraceon..", "..stacktraceoff..", "..stacktracefloor..")) - - + + list(score = utils::tail(score, 1), trace = c(prefix, toShow)) } @@ -486,11 +411,11 @@ pruneStackTrace <- function(parents) { # sufficient; we also need to drop nodes that are the last child, but one of # their ancestors is not. is_dupe <- duplicated(parents, fromLast = TRUE) - + # The index of the most recently seen node that was actually kept instead of # dropped. current_node <- 0 - + # Loop over the parent indices. Anything that is not parented by current_node # (a.k.a. last-known-good node), or is a dupe, can be discarded. Anything that # is kept becomes the new current_node. @@ -502,7 +427,7 @@ pruneStackTrace <- function(parents) { FALSE } }, FUN.VALUE = logical(1)) - + include } @@ -515,7 +440,7 @@ dropTrivialFrames <- function(callnames) { # What's the last that *didn't* match stop/.handleSimpleError/h? lastGoodCall <- max(which(!hideable)) toRemove <- length(callnames) - lastGoodCall - + c( rep_len(TRUE, length(callnames) - toRemove), rep_len(FALSE, toRemove) @@ -530,46 +455,11 @@ offsetSrcrefs <- function(calls, offset = TRUE) { # E.g. for "foo [bar.R:10]", line 10 of bar.R will be part of # the definition of foo(). srcrefs <- c(utils::tail(srcrefs, -1), list(NULL)) - - calls <- setSrcRefs(calls, srcrefs) - } - - calls -} - -#' @details `formatStackTrace` is similar to `extractStackTrace`, but -#' it returns a preformatted character vector instead of a data frame. It was -#' deprecated after shiny 1.0.5 because it doesn't support deep stack traces. -#' @param indent A string to prefix every line of the stack trace. -#' @rdname stacktrace -#' @export -formatStackTrace <- function(calls, indent = " ", - full = getOption("shiny.fullstacktrace", FALSE), - offset = getOption("shiny.stacktraceoffset", TRUE)) { - shinyDeprecated(NULL, - "extractStackTrace is deprecated. Please contact the Shiny team if you were using this functionality.", - version = "1.0.5") - - st <- extractStackTrace(calls, full = full, offset = offset) - if (nrow(st) == 0) { - return(character(0)) + calls <- setSrcRefs(calls, srcrefs) } - width <- floor(log10(max(st$num))) + 1 - paste0( - indent, - formatC(st$num, width = width), - ": ", - mapply(paste0(st$call, st$loc), st$category, FUN = function(name, category) { - if (category == "pkg") - crayon::silver(name) - else if (category == "user") - crayon::blue$bold(name) - else - crayon::white(name) - }) - ) + calls } getSrcRefs <- function(calls) { diff --git a/man/stacktrace.Rd b/man/stacktrace.Rd index 8e5494b71c..51f88415f9 100644 --- a/man/stacktrace.Rd +++ b/man/stacktrace.Rd @@ -6,8 +6,6 @@ \alias{withLogErrors} \alias{printError} \alias{printStackTrace} -\alias{extractStackTrace} -\alias{formatStackTrace} \alias{conditionStackTrace} \alias{conditionStackTrace<-} \alias{..stacktraceon..} @@ -34,19 +32,6 @@ printStackTrace( offset = getOption("shiny.stacktraceoffset", TRUE) ) -extractStackTrace( - calls, - full = getOption("shiny.fullstacktrace", FALSE), - offset = getOption("shiny.stacktraceoffset", TRUE) -) - -formatStackTrace( - calls, - indent = " ", - full = getOption("shiny.fullstacktrace", FALSE), - offset = getOption("shiny.stacktraceoffset", TRUE) -) - conditionStackTrace(cond) conditionStackTrace(cond) <- value @@ -72,8 +57,6 @@ left alone (traditional R treatment where the srcref is of the callsite).} \item{cond}{A condition that may have previously been annotated by \code{captureStackTraces} (or \code{withLogErrors}).} -\item{indent}{A string to prefix every line of the stack trace.} - \item{value}{The stack trace value to assign to the condition.} } \value{ @@ -108,17 +91,6 @@ to \code{withLogErrors}. \code{warning(immediate.=TRUE)}. \code{printStackTrace} prints the stack trace only. -\code{extractStackTrace} takes a list of calls (e.g. as returned -from \code{conditionStackTrace(cond)}) and returns a data frame with one -row for each stack frame and the columns \code{num} (stack frame number), -\code{call} (a function name or similar), and \code{loc} (source file path -and line number, if available). It was deprecated after shiny 1.0.5 because -it doesn't support deep stack traces. - -\code{formatStackTrace} is similar to \code{extractStackTrace}, but -it returns a preformatted character vector instead of a data frame. It was -deprecated after shiny 1.0.5 because it doesn't support deep stack traces. - \code{conditionStackTrace} and \verb{conditionStackTrace<-} are accessor functions for getting/setting stack traces on conditions.