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

"Error: 'levels.drive_id()' not supported." when using apply on drive_ls() output #369

Closed
16EAGLE opened this issue Jul 26, 2021 · 3 comments

Comments

@16EAGLE
Copy link

16EAGLE commented Jul 26, 2021

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

@jennybc
Copy link
Member

jennybc commented Jul 26, 2021

I believe you've come across another variation of this issue: r-lib/vctrs#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 r-lib/vctrs#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.

@jennybc
Copy link
Member

jennybc commented Oct 29, 2021

Note to self: Update on where this went in vctrs: r-lib/vctrs#1186

@jennybc
Copy link
Member

jennybc commented Mar 20, 2023

vctrs has since made a change that prevents this weird error about levels.drive_id().

@jennybc jennybc closed this as completed Mar 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants