googledrive
googledrive copied to clipboard
"Error: 'levels.drive_id()' not supported." when using apply on drive_ls() output
Thank you very much for this great project.
When using apply
on the output of drive_ls()
with googledrive
2.0.0
from CRAN or this repo (e.g. to row-by-row create sub-folders and download the respective files) the error Error: 'levels.drive_id()' not supported.
is thrown. With version 1.0.1
, it is possible to run apply
on the output of drive_ls()
without this error and without converting IDs to character.
See the reprex below orientated on the workflow that I have been using:
library(googledrive)
df <- drive_examples_remote() #or for me a `drive_ls()` call
# a download function using apply (here I usually create id-based subfolders etc.)
download_files <- function(df){
catch <- apply(df, MARGIN = 1, function(x){
drive_download(file = as_id(x[["id"]]), path = x[["name"]])
})
}
Calling download_files()
with googledrive
2.0.0
fails:
# fails:
download_files(df[1:3,])
#> Error: `levels.drive_id()` not supported.
rlang::last_error()
#> <error/vctrs_error_unsupported>
#> `levels.drive_id()` not supported.
#> Backtrace:
#> 1. global::download_files(df[1:3, ])
#> 2. base::apply(...)
#> 4. base::as.matrix.data.frame(X)
#> 6. vctrs:::levels.vctrs_vctr(xj)
#> 7. vctrs:::stop_unsupported(x, "levels")
#> 8. vctrs:::stop_vctrs(...)
#> Run `rlang::last_trace()` to see the full context.
Calling apply
on a drive_ls()
output works with googledrive
1.0.1
or by converting the IDs to character and removing the drive_resource
column:
df$drive_resource <- NULL
df$id <- as.character(df$id)
download_files(df[1:2,])
#> File downloaded:
#> • 'chicken_doc' <id: 1X9pd4nOjl33zDFfTjw-_eFL7Qb9_g6VfVFDp1PPae94>
#> Saved locally as:
#> • 'chicken_doc.docx'
#> File downloaded:
#> • 'chicken_sheet' <id: 1SeFXkr3XdzPSuWauzPdN-XnaryOYmZ7sFiUF5t-wSVU>
#> Saved locally as:
#> • 'chicken_sheet.xlsx'
Created on 2021-07-26 by the reprex package (v2.0.0)
Could it be that there is a method missing for class "drive_id" "vctrs_vctr" "character"
?
Its not so problematic for me since I simply can convert to character but maybe it would be convenient if apply
would work directly.
Thanks!
sessionInfo
R version 4.1.0 (2021-05-18)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.2 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=de_DE.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=de_DE.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=de_DE.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=de_DE.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] googledrive_2.0.0.9000
loaded via a namespace (and not attached):
[1] rstudioapi_0.13 magrittr_2.0.1 rappdirs_0.3.3 tidyselect_1.1.1 R6_2.5.0 rlang_0.4.11 fansi_0.5.0
[8] httr_1.4.2 dplyr_1.0.7 tools_4.1.0 utf8_1.2.2 cli_3.0.1 withr_2.4.2 askpass_1.1
[15] ellipsis_0.3.2 openssl_1.4.4 tibble_3.1.3 gargle_1.2.0 lifecycle_1.0.0 crayon_1.4.1 purrr_0.3.4
[22] vctrs_0.3.8 fs_1.5.0 curl_4.3.2 glue_1.4.2 compiler_4.1.0 pillar_1.6.1 generics_0.1.0
[29] jsonlite_1.7.2 pkgconfig_2.0.3
EDIT: reprex with the remote examples
I believe you've come across another variation of this issue: https://github.com/r-lib/vctrs/issues/1416.
It turns out base R, in some of the apply functions, calls levels()
on columns or objects, as part of figuring out what the column is. But instead of taking the lack of a levels()
method as info, it just fails if there's no levels()
method. It strikes me as an odd thing to do and that issue is where we're thinking whether to do anything about it and if so, what.
I'm not convinced adding a levels()
method for every vctrs class is a good idea, as it allows some things in base R to appear to "work", but produce an incorrect result. I show a case of that in https://github.com/r-lib/vctrs/issues/1416, where rbind()
's idiosyncratic logic creates an invalid drive_id
column. This would undermine the whole point of creating the drive_id
class and implementing methods that codify what it is and how to combine it with other things.
My preferred solution is to use functions within the tidyverse to work with such a vector, e.g. to use purrr::map_*()
instead of [sl]apply()
, because the map_*()
functions do what I want and don't require a levels()
method to exist.
I think your choices, certainly near-term, are to either switch to something like purrr::pmap()
or purrr::pwalk()
or dplyr::rowwise() %>% dplyr::summarize()
for your row-by-row work or to do the class-stripping you describe above.
Note to self: Update on where this went in vctrs: https://github.com/r-lib/vctrs/issues/1186
vctrs has since made a change that prevents this weird error about levels.drive_id()
.