Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
^\.Rproj\.user$
.*~
^\.circleci/config\.yml$
^\.github/
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: flipData
Type: Package
Title: Functions for extracting and describing data
Version: 1.8.9
Version: 1.8.10
Author: Displayr <opensource@displayr.com>
Maintainer: Displayr <opensource@displayr.com>
Description: Functions for extracting data from formulas and
Expand Down
109 changes: 65 additions & 44 deletions R/mergingandstackingutilities.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@ readDataSets <- function(data.set.names, min.data.sets = 1)
data.set.names <- vapply(data.set.names, trimws, character(1),
USE.NAMES = FALSE)

if (length(data.set.names) < min.data.sets)
if (length(data.set.names) < min.data.sets) {
StopForUserError("At least ", min.data.sets, " data set(s) are required.")
}

if (!all(grepl('.+\\.sav$', data.set.names, ignore.case = TRUE))) {
StopForUserError("An input data file was not an SPSS .sav data file. ",
"Only SPSS .sav data files are accepted.")
if (!all(grepl(".+\\.sav$", data.set.names, ignore.case = TRUE))) {
StopForUserError(
"An input data file was not an SPSS .sav data file. ",
"Only SPSS .sav data files are accepted."
)
}

if (IsDisplayrCloudDriveAvailable())
if (IsDisplayrCloudDriveAvailable()) {
readDataSetsFromDisplayrCloudDrive(data.set.names)
else
} else {
readLocalDataSets(data.set.names)
}
}

#' @param data.set.paths A character vector of paths to local data files.
Expand All @@ -34,7 +38,7 @@ readDataSets <- function(data.set.names, min.data.sets = 1)
readLocalDataSets <- function(data.set.paths, parser = read_sav)
{
result <- lapply(data.set.paths, function(path) {
handler = createReadErrorHandler(path)
handler <- createReadErrorHandler(path)
InterceptExceptions(parser(path), error.handler = handler)
})
names(result) <- basename(data.set.paths)
Expand All @@ -49,43 +53,57 @@ readLocalDataSets <- function(data.set.paths, parser = read_sav)
readDataSetsFromDisplayrCloudDrive <- function(data.set.names)
{
result <- lapply(data.set.names, function(nm) {
handler = createReadErrorHandler(nm)
handler <- createReadErrorHandler(nm)
InterceptExceptions(QLoadData(nm), error.handler = handler)
})
names(result) <- data.set.names
result
}

createExceptionHandler <- function(intercept.messages,
replacement.messages, warn = FALSE)
{
if (length(replacement.messages) == 1 && length(intercept.messages) > 1)
#' @importFrom flipU StopForUserError
createExceptionHandler <- function(
intercept.messages,
replacement.messages,
warn = FALSE
) {
if (length(replacement.messages) == 1 && length(intercept.messages) > 1) {
replacement.messages <- rep(replacement.messages, length(intercept.messages))
condition.fun <- if (warn) warning else stop
function(e)
{
}
function(e) {
condition.fun <- function(...) {
if (warn) {
warning(..., call. = FALSE)
} else if (inherits(e, "UserError")) {
StopForUserError(...)
} else {
stop(..., call. = FALSE)
Comment on lines +73 to +79
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition.fun closure captures the exception e from the outer scope, but this creates a dependency on the outer variable that may not be the intended behavior. When condition.fun is called with different messages, it still checks inherits(e, "UserError") based on the original exception, which may not match the current context where condition.fun is being invoked.

Suggested change
condition.fun <- function(...) {
if (warn) {
warning(..., call. = FALSE)
} else if (inherits(e, "UserError")) {
StopForUserError(...)
} else {
stop(..., call. = FALSE)
condition.fun <- function(msg) {
if (warn) {
warning(msg, call. = FALSE)
} else {
if (inherits(e, "UserError")) {
StopForUserError(msg)
} else {
stop(msg, call. = FALSE)
}

Copilot uses AI. Check for mistakes.
}
}
Comment on lines +73 to +81
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the actual change. Some minor differences below since the call. argument is already specified here.

msg.found <- FALSE
for (i in seq_along(intercept.messages))
{
if (grepl(intercept.messages[i], e$message))
{
condition.fun(replacement.messages[i], call. = FALSE)
for (i in seq_along(intercept.messages)) {
if (grepl(intercept.messages[i], e$message)) {
condition.fun(replacement.messages[i])
msg.found <- TRUE
}
}
if (!msg.found)
condition.fun(e$message, call. = FALSE)
if (!msg.found) {
condition.fun(e$message)
}
}
}

createReadErrorHandler <- function(data.set.name)
{
replacement.msg <- paste0("The data file '", data.set.name, "' could not be parsed. ",
"The data file may be fixed by inserting it in a Displayr document, ",
"exporting it as an SPSS file (.sav) via the Publish button, ",
"and then uploading it back to the cloud drive.")
intercept.msgs <- c("Invalid file, or file has unsupported features",
"Unable to convert string to the requested encoding")
replacement.msg <- paste0(
"The data file '", data.set.name, "' could not be parsed. ",
"The data file may be fixed by inserting it in a Displayr document, ",
"exporting it as an SPSS file (.sav) via the Publish button, ",
"and then uploading it back to the cloud drive."
)
intercept.msgs <- c(
"Invalid file, or file has unsupported features",
"Unable to convert string to the requested encoding"
)
createExceptionHandler(intercept.msgs, replacement.msg, warn = FALSE)
}

Expand All @@ -97,24 +115,24 @@ createReadErrorHandler <- function(data.set.name)
#' @importFrom flipAPI QSaveData IsDisplayrCloudDriveAvailable
#' @importFrom flipU InterceptExceptions
#' @importFrom tools file_path_sans_ext
writeDataSet <- function(data.set, data.set.name, is.saved.to.cloud)
{
if (is.saved.to.cloud)
{
writeDataSet <- function(data.set, data.set.name, is.saved.to.cloud) {
if (is.saved.to.cloud) {
warn.msg <- paste0("The data file ", data.set.name,
" has been compressed into ", file_path_sans_ext(data.set.name),
".zip on the Cloud Drive as it is too large. ",
"It needs to be downloaded, unzipped and re-uploaded to be ",
"used in a Displayr document.")
error.msg <- paste0("The data file could not be saved due to invalid characters ",
"in some of the variable names. Please contact support for assistance.")
InterceptExceptions(QSaveData(data.set, data.set.name, 2e9), # 2e9 bytes seems to be just below the API upload limit for the cloud drive
warning.handler = createExceptionHandler("Object compressed into a zip file",
warn.msg, TRUE),
error.handler = createExceptionHandler("must have valid SPSS variable names",
error.msg, FALSE))
}else
# 2e9 bytes seems to be just below the API upload limit for the cloud drive
InterceptExceptions(
QSaveData(data.set, data.set.name, 2e9),
warning.handler = createExceptionHandler("Object compressed into a zip file", warn.msg, TRUE),
error.handler = createExceptionHandler("must have valid SPSS variable names", error.msg, FALSE)
)
} else {
write_sav(data.set, data.set.name)
}
}

#' @description Creates a list of metadata for a data set
Expand Down Expand Up @@ -239,12 +257,12 @@ variableType <- function(variable)
StopForUserError("Variable type not recognised")
}

NUMERIC.VARIABLE.TYPE = "Numeric";
TEXT.VARIABLE.TYPE = "Text";
CATEGORICAL.VARIABLE.TYPE = "Categorical";
DATE.VARIABLE.TYPE = "Date";
DATE.TIME.VARIABLE.TYPE = "Date/Time";
DURATION.VARIABLE.TYPE = "Duration";
NUMERIC.VARIABLE.TYPE <- "Numeric"
TEXT.VARIABLE.TYPE <- "Text"
CATEGORICAL.VARIABLE.TYPE <- "Categorical"
DATE.VARIABLE.TYPE <- "Date"
DATE.TIME.VARIABLE.TYPE <- "Date/Time"
DURATION.VARIABLE.TYPE <- "Duration"

#' @param var.types A character vector containing variable types (see function
#' variableType).
Expand Down Expand Up @@ -342,6 +360,9 @@ splitByComma <- function(input.text, ignore.commas.in.parentheses = FALSE)
result <- result[result != ""]
result
}
result <- trimws(result)
result <- result[result != ""]
result
}

#' @param x A vector.
Expand Down
Loading