diff --git a/DESCRIPTION b/DESCRIPTION index 7ebe0d7..d8c0c9e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: bedbaser Title: A BEDbase client -Version: 0.99.4 +Version: 0.99.8 Authors@R: c( person( given = "Jen", diff --git a/NAMESPACE b/NAMESPACE index 91f2bc9..7ceae29 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -7,14 +7,18 @@ export(bb_example) export(bb_list_beds) export(bb_list_bedsets) export(bb_metadata) +export(bb_save) export(bb_to_granges) export(bb_to_grangeslist) +export(getCache) +export(setCache) +exportMethods(getCache) exportMethods(operations) +exportMethods(setCache) importFrom(AnVIL,Service) importFrom(AnVIL,operations) importFrom(BiocFileCache,BiocFileCache) importFrom(BiocFileCache,bfcadd) -importFrom(BiocFileCache,bfccache) importFrom(BiocFileCache,bfcdownload) importFrom(BiocFileCache,bfcneedsupdate) importFrom(BiocFileCache,bfcquery) @@ -38,6 +42,5 @@ importFrom(stringr,str_split_1) importFrom(tibble,tibble) importFrom(tidyr,unnest) importFrom(tidyr,unnest_wider) -importFrom(tools,R_user_dir) importFrom(utils,URLencode) importFrom(utils,read.table) diff --git a/R/bedbaser.R b/R/bedbaser.R index 5a88ebf..2c4fe54 100644 --- a/R/bedbaser.R +++ b/R/bedbaser.R @@ -5,6 +5,7 @@ #' @returns BEDbase class instance .BEDbase <- setClass( "BEDbase", + slots = c("cache"), contains = "Service" ) @@ -22,6 +23,8 @@ #' #' The convenience functions are as follows #' * `bedbaser::BEDbase()`: API service constructor +#' * `bedbaser::getCache()`: Retrieve cache +#' * `bedbaser::setCache()`: Set path to cache #' * `bedbaser::bb_example()`: Retrieve an example BED file or BEDset #' * `bedbaser::bb_metadata()`: Retrieve metadata for a BED file or BEDset #' * `bedbaser::bb_list_beds()`: List all BED files @@ -30,21 +33,25 @@ #' * `bedbaser::bb_bed_text_search()`: Search BED files by text #' * `bedbaser::bb_to_granges()`: Create a `GRanges` object from a BED id #' * `bedbaser::bb_to_grangeslist()`: Create a `GrangesList` from a BEDset id -#' Set the environment variable `BEDBASER_CACHE` to alter the cache path for -#' downloaded BED files. +#' * `bedbaser::bb_save()`: Save a BED file to a path. +#' +#' @param cache_path string() cache #' #' @importFrom AnVIL Service #' @importFrom rlang warn #' -#' @returns Service object +#' @returns BEDbase object #' #' @examples #' BEDbase() #' #' @export -BEDbase <- function() { +BEDbase <- function(cache_path) { + if (missing(cache_path)) + cache_path <- tools::R_user_dir("bedbaser", which = "cache") suppressWarnings( .BEDbase( + cache = BiocFileCache::BiocFileCache(cache_path), Service( service = "bedbase", host = "api.bedbase.org", @@ -58,6 +65,69 @@ BEDbase <- function() { ) } +#' @rdname BEDbase +#' +#' @param x BEDbase object +#' @param quietly (default TRUE) display messages +#' +#' @export +setGeneric("getCache", function(x, quietly = TRUE) standardGeneric("getCache")) + +#' Return cache path +#' +#' @param x BEDbase object +#' @param quietly (default TRUE) display messages +#' +#' @return BiocFileCache cache of BED files +#' +#' @examples +#' api <- BEDbase(tempdir()) +#' getCache(api) +#' +#' @export +setMethod( + "getCache", "BEDbase", + function(x, quietly = TRUE) { + if (quietly) + BiocFileCache::bfcinfo(x@cache) + x@cache + } +) + +#' @rdname BEDbase +#' +#' @param x BEDbase object +#' @param cache_path character() +#' @param quietly (default TRUE) display messages +#' +#' @export +setGeneric("setCache", + function(x, cache_path, quietly = TRUE) standardGeneric("setCache") +) + +#' Set cache path +#' +#' @param x BEDbase object +#' @param cache_path character() +#' @param quietly (default TRUE) display messages +#' +#' @return BiocFileCache cache of BED files +#' +#' @examples +#' api <- BEDbase(tempdir()) +#' api <- setCache(api, "/tmp") +#' +#' @export +setMethod( + "setCache", "BEDbase", + function(x, cache_path, quietly = TRUE) { + x@cache <- BiocFileCache::BiocFileCache(cache_path) + if (quietly) + BiocFileCache::bfcinfo(x@cache) + x + } +) + #' Display API #' #' @param x BEDbase object @@ -332,7 +402,7 @@ bb_to_granges <- function( quietly = TRUE) { stopifnot(file_type %in% c("bed", "bigbed")) metadata <- bb_metadata(api, bed_id, TRUE) - file_path <- .get_file(metadata, file_type, "http", quietly) + file_path <- .get_file(metadata, file_type, "http", getCache(api), quietly) if (file_type == "bed") { .bed_file_to_granges(file_path, metadata, extra_cols, quietly) @@ -376,3 +446,38 @@ bb_to_grangeslist <- function(api, bedset_id, quietly = TRUE) { } GRangesList(gros) } + +#' Save a BED or BEDset files to a path given an id +#' +#' @rdname bb_save +#' +#' @param api API object of BEDbase created from BEDbase() +#' @param bed_or_bedset_id integer() BED or BEDset record identifier +#' @param path character() directory to save file +#' @param file_type character() (default bed) bed, bigbed, etc. +#' @param access_type character() (default http) s3 or http +#' @param quietly logical() (default TRUE) display messages +#' +#' @examples +#' api <- BEDbase() +#' ex <- bb_example(api, "bed") +#' bb_save(api, ex$id, tempdir()) +#' +#' @export +bb_save <- function( + api, bed_or_bedset_id, path, file_type = "bed", access_type = "http", + quietly = TRUE) +{ + if (!dir.exists(path)) + rlang::abort(paste(path, "doesn't exist.", sep = " ")) + metadata <- bb_metadata(api, bed_or_bedset_id, TRUE) + if ("bedsets" %in% names(metadata)) { + ids <- list(metadata$id) + } else { + ids <- metadata$bed_ids + } + for (id in ids) { + metadata <- bb_metadata(api, id, TRUE) + .get_file(metadata, file_type, access_type, path, quietly) + } +} diff --git a/R/cache.R b/R/cache.R index 53ca834..f4e06aa 100644 --- a/R/cache.R +++ b/R/cache.R @@ -1,37 +1,9 @@ -#' Get the cache -#' -#' Uses BEDBASER_CACHE for cache path if set; otherwise, it uses the default R -#' cache path for bedbaser. -#' -#' @param quietly logical() (default TRUE) display message -#' -#' @importFrom BiocFileCache BiocFileCache bfccache -#' @importFrom rlang inform -#' @importFrom tools R_user_dir -#' -#' @returns BiocFileCache object -#' -#' @examples -#' Sys.setenv("BEDBASER_CACHE" = ".cache/bedbaser") -#' .get_cache() -#' -#' @noRd -.get_cache <- function(quietly = TRUE) { - bfc <- ifelse(Sys.getenv("BEDBASER_CACHE") != "", - Sys.getenv("BEDBASER_CACHE"), - R_user_dir("bedbaser", which = "cache") - ) - if (!quietly) { - inform(paste("Using", bfccache())) - } - BiocFileCache(bfc) -} - #' Retrieve path from cache or download file and cache #' #' This function is described in the BiocFileCache vignette. #' #' @param url character() remote resource +#' @param bfc BiocFileCache object #' @param quietly logical() (default TRUE) display message #' #' @importFrom BiocFileCache BiocFileCache bfcadd bfcdownload bfcneedsupdate @@ -45,11 +17,10 @@ #' "https://data2.bedbase.org/files/2/6/", #' "26a57da7c732a8e63a1dda7ea18af021.bed.gz" #' ) -#' .download_and_cache(url) +#' .download_to_cache(url, BiocFileCache::BiocFileCache(tempdir())) #' #' @noRd -.download_and_cache <- function(url, quietly = TRUE) { - bfc <- .get_cache() +.download_to_cache <- function(url, bfc, quietly = TRUE) { rid <- bfcquery(bfc, url, "rname")$rid if (!length(rid)) { if (!quietly) { diff --git a/R/utils.R b/R/utils.R index 9d83b0a..8ef1e36 100644 --- a/R/utils.R +++ b/R/utils.R @@ -20,11 +20,14 @@ unnest_wider(access_url) } -#' Get a file from BEDbase +#' Save a file from BEDbase to the cache or a path +#' +#' Will create directories that do not exist when saving #' #' @param metadata list() full metadata #' @param file_type character() bed or bigbed #' @param access_type character() s3 or http +#' @param cache_or_path BiocFileCache or character() cache or save path #' @param quietly logical() (default TRUE) display messages #' #' @importFrom R.utils gunzip @@ -36,24 +39,33 @@ #' api <- BEDbase() #' ex_bed <- bb_example(api, "bed") #' md <- bb_metadata(api, ex_bed$id, TRUE) -#' .get_file(md, "bed", "http") +#' .get_file(md, "bed", "http", tempdir()) #' #' @noRd .get_file <- function( metadata, file_type = c("bed", "bigbed"), - access_type = c("s3", "http"), quietly = TRUE) { + access_type = c("s3", "http"), cache_or_path, quietly = TRUE) { file_details <- .format_metadata_files(metadata$files) |> filter( name == paste(file_type, "file", sep = "_"), access_id == access_type ) - gzipfile <- .download_and_cache(file_details$url, quietly) - tryCatch( - gunzip(gzipfile, remove = FALSE), - error = function(e) { - gsub(".gz", "", gzipfile) - } - ) + if (class(cache_or_path) == "BiocFileCache") { + cached_file <- .download_to_cache(file_details$url, cache_or_path, quietly) + bedbase_file <- tryCatch( + gunzip(cached_file, remove = FALSE), + error = function(e) { + gsub(".gz", "", cached_file) + } + ) + } else { + if (!dir.exists(cache_or_path)) + dir.create(cache_or_path, recursive = TRUE) + url_parts <- unlist(strsplit(file_details$url, "/")) + bedbase_file <- file.path(cache_or_path, url_parts[length(url_parts)]) + utils::download.file(file_details$url, bedbase_file, quiet = quietly) + } + bedbase_file } #' Get extra_cols diff --git a/man/BEDbase.Rd b/man/BEDbase.Rd index 748a9b1..8949f91 100644 --- a/man/BEDbase.Rd +++ b/man/BEDbase.Rd @@ -2,12 +2,25 @@ % Please edit documentation in R/bedbaser.R \name{BEDbase} \alias{BEDbase} +\alias{getCache} +\alias{setCache} \title{An R client for BEDbase} \usage{ -BEDbase() +BEDbase(cache_path) + +getCache(x, quietly = TRUE) + +setCache(x, cache_path, quietly = TRUE) +} +\arguments{ +\item{cache_path}{character()} + +\item{x}{BEDbase object} + +\item{quietly}{(default TRUE) display messages} } \value{ -Service object +BEDbase object } \description{ bedbaser exposes the BEDbase API and includes convenience @@ -18,6 +31,8 @@ functions for common tasks, such as to import a BED file by id into a The convenience functions are as follows \itemize{ \item \code{bedbaser::BEDbase()}: API service constructor +\item \code{bedbaser::getCache()}: Retrieve cache +\item \code{bedbaser::setCache()}: Set path to cache \item \code{bedbaser::bb_example()}: Retrieve an example BED file or BEDset \item \code{bedbaser::bb_metadata()}: Retrieve metadata for a BED file or BEDset \item \code{bedbaser::bb_list_beds()}: List all BED files @@ -26,8 +41,7 @@ The convenience functions are as follows \item \code{bedbaser::bb_bed_text_search()}: Search BED files by text \item \code{bedbaser::bb_to_granges()}: Create a \code{GRanges} object from a BED id \item \code{bedbaser::bb_to_grangeslist()}: Create a \code{GrangesList} from a BEDset id -Set the environment variable \code{BEDBASER_CACHE} to alter the cache path for -downloaded BED files. +\item \code{bedbaser::bb_save()}: Save a BED file to a path. } } \examples{ diff --git a/man/bb_save.Rd b/man/bb_save.Rd new file mode 100644 index 0000000..daf5874 --- /dev/null +++ b/man/bb_save.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bedbaser.R +\name{bb_save} +\alias{bb_save} +\title{Save a BED or BEDset files to a path given an id} +\usage{ +bb_save( + api, + bed_or_bedset_id, + path, + file_type = "bed", + access_type = "http", + quietly = TRUE +) +} +\arguments{ +\item{api}{API object of BEDbase created from BEDbase()} + +\item{bed_or_bedset_id}{integer() BED or BEDset record identifier} + +\item{path}{character() directory to save file} + +\item{file_type}{character() (default bed) bed, bigbed, etc.} + +\item{access_type}{character() (default http) s3 or http} + +\item{quietly}{logical() (default TRUE) display messages} +} +\description{ +Save a BED or BEDset files to a path given an id +} +\examples{ +api <- BEDbase() +ex <- bb_example(api, "bed") +bb_save(api, ex$id, tempdir()) + +} diff --git a/man/getCache-BEDbase-method.Rd b/man/getCache-BEDbase-method.Rd new file mode 100644 index 0000000..0b0a65b --- /dev/null +++ b/man/getCache-BEDbase-method.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bedbaser.R +\name{getCache,BEDbase-method} +\alias{getCache,BEDbase-method} +\title{Return cache path} +\usage{ +\S4method{getCache}{BEDbase}(x, quietly = TRUE) +} +\arguments{ +\item{x}{BEDbase object} + +\item{quietly}{(default TRUE) display messages} +} +\value{ +BiocFileCache cache of BED files +} +\description{ +Return cache path +} +\examples{ +api <- BEDbase(tempdir()) +getCache(api) + +} diff --git a/man/setCache-BEDbase-method.Rd b/man/setCache-BEDbase-method.Rd new file mode 100644 index 0000000..11fbff5 --- /dev/null +++ b/man/setCache-BEDbase-method.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bedbaser.R +\name{setCache,BEDbase-method} +\alias{setCache,BEDbase-method} +\title{Set cache path} +\usage{ +\S4method{setCache}{BEDbase}(x, cache_path, quietly = TRUE) +} +\arguments{ +\item{x}{BEDbase object} + +\item{cache_path}{character()} + +\item{quietly}{(default TRUE) display messages} +} +\value{ +BiocFileCache cache of BED files +} +\description{ +Set cache path +} +\examples{ +api <- BEDbase(tempdir()) +api <- setCache(api, "/tmp") + +} diff --git a/tests/testthat/test-bedbaser.R b/tests/testthat/test-bedbaser.R index 09185c7..4c83d0b 100644 --- a/tests/testthat/test-bedbaser.R +++ b/tests/testthat/test-bedbaser.R @@ -1,5 +1,13 @@ # test that there's an internet connection +test_that("setCache changes cache", { + api <- BEDbase() + path <- tempdir() + expect_true(BiocFileCache::bfccache(getCache(api)) != path) + api <- setCache(api, path) + expect_true(BiocFileCache::bfccache(getCache(api)) == path) +}) + test_that("bb_example has bed_format of 'bed' given rec_type 'bed'", { ex_bed <- bb_example(BEDbase(), "bed") expect_equal("bed", ex_bed$bed_format) @@ -163,3 +171,16 @@ test_that("bb_to_grangeslist creates a GRangesList", { expect_equal("CompressedGRangesList", class(grl)[1]) expect_equal(10, length(grl)) }) + +test_that("bb_save saves bed files to a path", { + api <- BEDbase() + path <- tempdir() + dir.create(path) + bed <- bb_example(api, "bed") + bb_save(api, bed$id, path, quietly = TRUE) + expect_true(file.exists(file.path(path, paste0(bed$id, ".bed.gz")))) + bedset <- bb_example(api, "bedset") + bb_save(api, bedset$id, path, quietly = TRUE) + for (id in bedset$bed_ids) + expect_true(file.exists(file.path(path, paste0(id, ".bed.gz")))) +}) diff --git a/tests/testthat/test-cache.R b/tests/testthat/test-cache.R index 77355cc..e94e5a5 100644 --- a/tests/testthat/test-cache.R +++ b/tests/testthat/test-cache.R @@ -1,13 +1,23 @@ -test_that("BEDBASER_CACHE is used if set", { - Sys.setenv("BEDBASER_CACHE" = tempdir()) - cache_path <- Sys.getenv("BEDBASER_CACHE") +test_that("default cache location is used", { + path <- tools::R_user_dir("bedbaser", which = "cache") api <- BEDbase() id <- "bbad85f21962bb8d972444f7f9a3a932" gro <- bb_to_granges(api, id, "bed") - bfc <- BiocFileCache::BiocFileCache(cache_path) - bfci <- BiocFileCache::bfcinfo(bfc) - expect_equal(BiocFileCache::bfccache(bfc), cache_path) + bfc <- BiocFileCache::BiocFileCache(path) + expect_equal(BiocFileCache::bfccache(bfc), path) md <- bb_metadata(api, id, TRUE) - file_path <- .get_file(md, "bed", "http") - expect_true(paste0(file_path, ".gz") %in% bfci$rpath) + file_path <- .get_file(md, "bed", "http", getCache(api)) + expect_true(paste0(file_path, ".gz") %in% BiocFileCache::bfcinfo(bfc)$rpath) +}) + +test_that("path is used if set when calling constructor", { + path <- tempdir() + api <- BEDbase(path) + bfc <- getCache(api) + id <- "bbad85f21962bb8d972444f7f9a3a932" + gro <- bb_to_granges(api, id, "bed") + expect_equal(BiocFileCache::bfccache(bfc), path) + md <- bb_metadata(api, id, TRUE) + file_path <- .get_file(md, "bed", "http", getCache(api)) + expect_true(paste0(file_path, ".gz") %in% BiocFileCache::bfcinfo(bfc)$rpath) }) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 9a081e9..5a8ff7d 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -11,7 +11,10 @@ test_that(".get_file returns a valid file path", { api <- BEDbase() ex_bed <- bb_example(api, "bed") md <- bb_metadata(api, ex_bed$id, TRUE) - file_path <- .get_file(md, "bed", "http") + temp_path <- tempdir() + file_path <- .get_file(md, "bed", "http", temp_path) + expect_true(file.exists(file_path)) + file_path <- .get_file(md, "bed", "http", getCache(api)) expect_true(file.exists(file_path)) }) @@ -19,7 +22,7 @@ test_that(".get_extra_cols returns a named vector", { api <- BEDbase() id <- "608827efc82fcaa4b0bfc65f590ffef8" md <- bb_metadata(api, id, TRUE) - file_path <- .get_file(md, "bed", "http") + file_path <- .get_file(md, "bed", "http", getCache(api)) extra_cols <- .get_extra_cols(file_path, 3, 9) expect_equal(9, length(extra_cols)) }) diff --git a/vignettes/bedbaser.Rmd b/vignettes/bedbaser.Rmd index a7abc0b..dfc77c7 100644 --- a/vignettes/bedbaser.Rmd +++ b/vignettes/bedbaser.Rmd @@ -46,12 +46,8 @@ api <- BEDbase() ## (Optional) Set the cache -Set the cache path with the environment variable `BEDBASER_CACHE`; otherwise, -bedbaser will choose the default cache location. - -```{r BEDBASER_CACHE, eval=FALSE} -Sys.setenv("BEDBASER_CACHE" = tempdir()) -``` +Set the cache path with the argument `cache_path`; otherwise, bedbaser will +choose the default cache location. # Convenience Functions