Baixando e carregando objetos do Google Drive

Oi, povo R!
Estou tentando criar uma função que carregue objetos no global environment lendo arquivos armazenados no Google Drive.
Como são arquivos .csv e .rds, acredito que não dá pra ler direto com googlesheets, então a estratégia foi baixar para a pasta Downloads, e depois ler com readr::read_csv2 ou readr::read_rds.
Eu rodei o código passo a passo antes de encapsular na fórmula, e deu tudo certo.
Porém, depois de encapsular, ela passou a funcionar parcialmente, conforme descrito depois do código.

Obs.1: separei nome e tipo para o nome do arquivo não ficar com “extensão duplicada”. Na primeira tentativa, o arquivo e o objeto foram nomeados como “tabela.csv.csv”.
Obs.2: depois pretendo editar o código para passar vetores com vários nomes e links para baixar e carregar vários arquivos de uma vez.
Obs.3: o código de atribuição do caminho tem uma alternativa relativa, ao invés do caminho absoluto que acabei usando. Eu uso Windows, e ainda não domino bem os caminhos relativos, mas vou deixar esse tema pra outra questão, pois essa aqui já está gigantesa.

carregar_do_drive_downloads <- function(gmail, nome, tipo, link) {

  googledrive::drive_auth(gmail)

  caminho <- paste0("C:/Users/pedro/Downloads/", nome, ".", tipo)
  #caminho <- paste0("~/ProjetosR/CearaFinancas/data/", nome, ".", tipo)

  googledrive::drive_download(
    file = link,
    path = caminho,
    overwrite = T
  )

  if (tipo == "csv") {
    assign(
      x = nome[1],
      value = readr::read_csv2(file = caminho)
    )
  } else {
    assign(
      x = nome[1],
      value = readr::read_rds(file = caminho)
    )
  }

  remove(gmail, nome, tipo, link, caminho)
}

Funcionamento parcial
Quando rodei a fórmula com um arquivo .csv, o arquivo foi baixado para Downloads, e no console até apareceram as mensagens de leitura* do readr::read_csv2 (que está dentro do assign), mas o objeto não foi atribuído no global environment.
Quando rodei a fórmula com um arquivo .rds, o arquivo foi baixado para Downloads, mas também não carregou o objeto no global environment.
Não há nenhuma mensagem de erro.

*Mensagem de leitura a que me refiro:

i Using “’,’” as decimal and “’.’” as grouping mark. Use read_delim() for more control.
Rows: 29 Columns: 1
0s-- Column specification ----------------------------------------
Delimiter: “;”
chr (1): Variação acumulada no ano durante o Plano Real

i Use spec() to retrieve the full column specification for this data.
i Specify the column types or set show_col_types = FALSE to quiet this message.

Ex.:
gmail <- "email.google@gmail.com"

#[1KB]
nome <- "ipca_1995_2021"
tipo <- "csv"
link <- paste0("https://drive.google.com/file/d/",
               "1U5dq6UHbclIXcUW6yb_3eQ5P41hNGI9D/view?usp=sharing")

#[6KB]
nome <- "municipios_ce"
tipo <- "rds"
link <- paste0("https://drive.google.com/file/d/",
               "1iuWuWEI5wC1m68pBJTgksLV74eJKl41X/view?usp=sharing")

Obs.: não sei se é de bom tom colocar links para baixar arquivos, pelo risco de malwares. Se não for recomendável, eu edito aqui pra excluir. Ajudem o amigo novato, gente hehe

Dúvida: organização de projeto
Os arquivos são originais da Base dos Dados / SICONFI, a query processa ~2GB, e os arquivos finais têm entre 50 e 100MB. Por isso, resolvi armazená-los no Google Drive, ao invés de colocar no /data e dar push para o Github. O código para isso (baixar, filtrar e carregar no Drive) está em outro script. Os links diretos para os arquivos no Google Drive estão configurados para “qualquer pessoa com o link pode visualizar”. A ideia de baixar do Google Drive pra Downloads é para que os arquivos fiquem armazenados apenas temporariamente na máquina. Já vi gente colocando numa pasta temp, mas não tive capacidade hehe
Essa organização faz sentido? Como vcs organizariam esse projeto?
O objetivo era economizar espaço e processamento, mas acho que criei uma complexidade que gera riscos, e talvez não compense.

Dúvida: objetos-parâmetros no global environment
Antes de rodar a fórmula, os parâmetros gmail, nome, tipo e link são atribuídos a objetos pelo usuário antes de rodar a fórmula, mas o parâmetro caminho (utilizado tanto no googledrive::drive_download quanto no assign) só é atribuído a um objeto já dentro da fórmula.
Por um lado, eu sei que o objeto caminho é devidamente atribuído no curso da fórmula, pois o googledrive::drive_download funciona normalmente, e o assign encontra o caminho e lê o arquivo, apesar de não carregar o objeto no global environment como desejado.
Por outro lado, o caminho não aparece no global environment. Isso é normal? Por que? Vasculhando o stackoverflow, encontrei gente dizendo que “global assignments within functions are a recipe for disaster, or ‘life by a volcano’”. Será que isso tem a ver?

Dúvida: objetos-tibble no global environment
Como descrito, apesar do código funcionar quando executado passo a passo, ele não faz as atribuições que solicitei quando executado no curso da fórmula - ou pelo menos não aparece no global environmet, assim como o caminho. Será que eles estão sendo carregados em algum outro environment?

Desculpa a pergunta imensa. Acho que daria pra quebrar em tópicos diferentes, mas fiquei com medo de perder alguma parte do contexto que fosse importante pra resolução do problema.

1 curtida

Oieee

Vamos lá, Paulo! São várias dúvidas kkkk

  • Carregando os CSVs diretamente do google drive
  • Environments
  • Organização do projeto

Dúvida 1:

Como são arquivos .csv e .rds, acredito que não dá pra ler direto com googlesheets

O csv é um texto, então a gente consegue com a função googledrive::drive_read_string(). Ex:

# caminho do arquivo
arquivo <- "https://drive.google.com/file/d/1U5dq6UHbclIXcUW6yb_3eQ5P41hNGI9D/view"

# ler o texto desse caminho
# já que o csv é um texto também
arquivo_string <- googledrive::drive_read_string(arquivo)
#> ℹ Suitable tokens found in the cache, associated with these emails:

#>   Defaulting to the first email.
#> ! Using an auto-discovered, cached token.
#>   To suppress this message, modify your code or options to clearly consent to
#>   the use of a cached token.
#>   See gargle's "Non-interactive auth" vignette for more details:
#>   <https://gargle.r-lib.org/articles/non-interactive-auth.html>
#> ℹ The googledrive package is using a cached token for 'beatriz.milz@usp.br'.
#> Auto-refreshing stale OAuth token.
#> No encoding supplied: defaulting to UTF-8.

# ler esse texto como um csv
base_raw <- readr::read_delim(arquivo_string, 
           delim = ";", 
           escape_double = FALSE, 
           col_types = readr::cols(Brasil = readr::col_double()), 
           trim_ws = TRUE, skip = 1)
#> New names:
#> * `` -> ...1
#> Warning: One or more parsing issues, see `problems()` for details


# arrumar nome das colunas
base_csv <- base_raw |>  
  dplyr::rename(
   "mes_ano" = 1,  "variacao" = 2) |> 
  dplyr::filter(!stringr::str_starts(mes_ano, "Fonte:")) |> 
  tidyr::separate(mes_ano, c("mes", "ano"), " ")

# ver a base resultante
dplyr::glimpse(base_csv)
#> Rows: 27
#> Columns: 3
#> $ mes      <chr> "dezembro", "dezembro", "dezembro", "dezembro", "dezembro", "…
#> $ ano      <chr> "1995", "1996", "1997", "1998", "1999", "2000", "2001", "2002…
#> $ variacao <dbl> 22.41, 9.56, 5.22, 1.65, 8.94, 5.97, 7.67, 12.53, 9.30, 7.60,…

Created on 2022-02-15 by the reprex package (v2.0.1)

Ainda não testei com o .rds!

Dúvida 2.1

encontrei gente dizendo que “global assignments within functions are a recipe for disaster, or ‘life by a volcano’”.

Fazer alterações no Global Env dentro de funções não é recomendado… por isso essa frase :slight_smile:

Dúvida 2.2

mas o objeto não foi atribuído no global environment

Sobre sua função não salvar o objeto no global environment:
Quando você executa uma função, um novo ambiente temporário é criado para que ela seja executada nele. Assim o que acontece dentro dela não afeta o Global environment. Por isso, ao menos que você seja explícito que quer criar esse objeto em outro environment, ele vai ser criado nesse environment temporário. Isso acontece pois, idealmente, espera-se que as funções que instalamos não altere nada nos nossos ambientes. Uma forma para retornar os dados e que não afeta o Global env é retornar por último a base de dados, e salvar o que foi retornado em um objeto o que foi retornado.

Poréeeem, se você está criando a função para você usar e tem certeza que quer fazer uma função que altere seu Global Env, você até pode fazer isso.
Eu lembro que esse capítulo foi útil para entender melhor os environments: Hands-On Programming with R - 6  Environments

Uma das formas é com o operador <<- . Ele é parecido com o <-, mas o objeto salvo ficará salvo fora do ambiente de execução da função também.
Você usou a função assign e lendo a documentação dela dá pra ver que tem um argumento que permite definir em qual Environment ela será salva: assign function - RDocumentation (veja o exemplo onde usa envir = .GlobalEnv)

Acho que essa ideia já ajuda a entender a outra dúvida:

" objetos-parâmetros no global environment"

O que foi criado dentro da função apenas existe no ambiente onde ela é executada (e enquanto ela é executada). Por isso você não encontra o caminho no seu global env, já que o caminho é criado dentro de uma função.

Boas práticas de organização

O tamanho apontado para os arquivos finais mostra que é melhor não deixar dentro de um pacote mesmo… Sobre deixar no Google Drive: existe algum risco de alguém que não deveria, acessar isso?

2 curtidas