Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zap openxlsx and use writexl instead, fix #310 #359

Merged
merged 3 commits into from
Sep 11, 2023
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
7 changes: 4 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: rio
Type: Package
Title: A Swiss-Army Knife for Data I/O
Version: 0.5.30
Version: 0.5.31
Authors@R: c(person("Jason", "Becker", role = "aut", email = "jason@jbecker.co"),
person("Chung-hong", "Chan", role = c("aut", "cre"), email = "chainsawtiney@gmail.com",
comment = c(ORCID = "0000-0002-6232-7530")),
Expand Down Expand Up @@ -49,9 +49,10 @@ Imports:
curl (>= 0.6),
data.table (>= 1.11.2),
readxl (>= 0.1.1),
openxlsx,
tibble,
stringi
stringi,
writexl,
lifecycle
Suggests:
datasets,
bit64,
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* `export_list` can write multiple data frames to a single archive file (e.g. zip, tar) or a directory #346 h/t David Schoch
* `get_info` is added #350
* POTENTIALLY BREAKING: `setclass` parameter is now authoritative. Therefore: `import("starwars.csv", data.table = TRUE, setclass = "tibble")` will return a tibble (unlike previous versions where a data.table is returned). The default class is data frame. You can either explicitly use the `setclass` parameter; or set the option: `options(rio.import.class = "data.table")`. h/t David Schoch #336
* Use `writexl` instead of `openxlsx`. Option to read xlsx with `openxlsx` (i.e. `import("starwars.xlsx", readxl = FALSE)`) is always `TRUE`. The ability to overwrite an existing sheet in an existing xlsx file is also removed. It is against the design principle of `rio`.
* Bug fixes
- ... is correctly passed for exporting ODS and feather #318
- POTENTIALLY BREAKING: JSON are exported in UTF-8 by default; solved encoding issues on
Expand Down
2 changes: 1 addition & 1 deletion R/export.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#' \item SPSS (.sav), using [haven::write_sav()]
#' \item SPSS compressed (.zsav), using [haven::write_sav()]
#' \item Stata (.dta), using [haven::write_dta()]. Note that variable/column names containing dots (.) are not allowed and will produce an error.
#' \item Excel (.xlsx), using [openxlsx::write.xlsx()]. Existing workbooks are overwritten unless `which` is specified, in which case only the specified sheet (if it exists) is overwritten. If the file exists but the `which` sheet does not, data are added as a new sheet to the existing workbook. `x` can also be a list of data frames; the list entry names are used as sheet names.
#' \item Excel (.xlsx), using [writexl::write_xlsx()]. `x` can also be a list of data frames; the list entry names are used as sheet names.
#' \item R syntax object (.R), using [base::dput()] (by default) or [base::dump()] (if `format = 'dump'`)
#' \item Saved R objects (.RData,.rda), using [base::save()]. In this case, `x` can be a data frame, a named list of objects, an R environment, or a character vector containing the names of objects if a corresponding `envir` argument is specified.
#' \item Serialized R objects (.rds), using [base::saveRDS()]. In this case, `x` can be any serializable R object.
Expand Down
30 changes: 2 additions & 28 deletions R/export_methods.R
Original file line number Diff line number Diff line change
Expand Up @@ -219,34 +219,8 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE,
}

#' @export
.export.rio_xlsx <- function(file, x, which, ...) {
dots <- list(...)
if (!missing(which)) {
if (file.exists(file)) {
wb <- openxlsx::loadWorkbook(file = file)
sheets <- openxlsx::getSheetNames(file = file)
if (is.numeric(which)) {
if (which <= length(sheets)) {
which <- sheets[which]
} else {
which <- paste("Sheet", length(sheets) + 1L)
}
}
if (!which %in% sheets) {
openxlsx::addWorksheet(wb, sheet = which)
} else {
openxlsx::removeWorksheet(wb, sheet = which)
openxlsx::addWorksheet(wb, sheet = which)
openxlsx::worksheetOrder(wb) <- sheets
}
openxlsx::writeData(wb, sheet = which, x = x)
openxlsx::saveWorkbook(wb, file = file, overwrite = TRUE)
} else {
openxlsx::write.xlsx(x = x, file = file, sheetName = which, ...)
}
} else {
openxlsx::write.xlsx(x = x, file = file, ...)
}
.export.rio_xlsx <- function(file, x, ...) {
writexl::write_xlsx(x = x, path = file, ...)
}

#' @export
Expand Down
2 changes: 1 addition & 1 deletion R/import.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#' \item SPSS compressed (.zsav), using [haven::read_sav()].
#' \item Stata (.dta), using [haven::read_dta()]. If `haven = FALSE`, [foreign::read.dta()] can be used.
#' \item SPSS Portable Files (.por), using [haven::read_por()].
#' \item Excel (.xls and .xlsx), using [readxl::read_excel()]. Use `which` to specify a sheet number. For .xlsx files, it is possible to set `readxl = FALSE`, so that [openxlsx::read.xlsx()] can be used instead of readxl (the default).
#' \item Excel (.xls and .xlsx), using [readxl::read_xlsx()] or [readxl::read_xls()]. Use `which` to specify a sheet number.
#' \item R syntax object (.R), using [base::dget()]
#' \item Saved R objects (.RData,.rda), using [base::load()] for single-object .Rdata files. Use `which` to specify an object name for multi-object .Rdata files. This can be any R object (not just a data frame).
#' \item Serialized R objects (.rds), using [base::readRDS()]. This can be any R object (not just a data frame).
Expand Down
24 changes: 9 additions & 15 deletions R/import_methods.R
Original file line number Diff line number Diff line change
Expand Up @@ -311,22 +311,16 @@ import_delim <-
}

#' @export
.import.rio_xlsx <- function(file, which = 1, readxl = TRUE, ...) {
if (isTRUE(readxl)) {
.check_pkg_availability("readxl")
arg_reconcile(readxl::read_xlsx,
path = file, ..., sheet = which,
.docall = TRUE,
.remap = c(colNames = "col_names", na.strings = "na")
)
} else {
.check_pkg_availability("openxlsx")
arg_reconcile(openxlsx::read.xlsx,
xlsxFile = file, ..., sheet = which,
.docall = TRUE,
.remap = c(col_names = "colNames", na = "na.strings")
)
.import.rio_xlsx <- function(file, which = 1, readxl = lifecycle::deprecated(), ...) {
if (lifecycle::is_present(readxl)) {
lifecycle::deprecate_warn(
when = "0.5.31",
what = "import(readxl)",
details = "xlsx will always be read by `readxl`. The parameter `readxl` will be dropped in v2.0.0.")
}
arg_reconcile(readxl::read_xlsx,
path = file, ..., sheet = which,
.docall = TRUE)
}

#' @export
Expand Down
2 changes: 1 addition & 1 deletion man/export.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/import.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 30 additions & 1 deletion tests/testthat/test_format_xls.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,36 @@ require("datasets")

test_that("Export to Excel (.xlsx)", {
expect_true(export(iris, "iris.xlsx") %in% dir())
expect_true(export(mtcars, "iris.xlsx", which = 2) %in% dir())
})

test_that("Expert to Excel (.xlsx) a list", {
tempxlsx <- tempfile(fileext = ".xlsx")
export(list(
mtcars3 = mtcars[1:10, ],
mtcars2 = mtcars[11:20, ],
mtcars1 = mtcars[21:32, ]
), tempxlsx)
expect_equal(readxl::excel_sheets(tempxlsx), c("mtcars3", "mtcars2", "mtcars1"))
})

test_that("Is `sheet` passed?", {
tempxlsx <- tempfile(fileext = ".xlsx")
export(list(
mtcars3 = mtcars[1:10, ],
mtcars2 = mtcars[11:20, ],
mtcars1 = mtcars[21:32, ]
), tempxlsx)
expect_equal(readxl::excel_sheets(tempxlsx), c("mtcars3", "mtcars2", "mtcars1"))
content <- import(tempxlsx, sheet = "mtcars2")
expect_equal(content$mpg, mtcars[11:20, ]$mpg)
content <- import(tempxlsx, which = 2)
expect_equal(content$mpg, mtcars[11:20, ]$mpg)
})


test_that("readxl is deprecated", {
lifecycle::expect_deprecated(import("iris.xlsx", readxl = TRUE))
lifecycle::expect_deprecated(import("iris.xlsx", readxl = FALSE))
})

test_that("Import from Excel (.xlsx)", {
Expand Down