diff --git a/.gitignore b/.gitignore index 807ea25..d1de5fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .Rproj.user .Rhistory .RData +.DS_Store \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index 05daf1a..8a0cc16 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: BiocProject Title: Bioconductor Management with Portable Encapsulated Project (PEP) Objects -Version: 0.0.3 +Version: 0.0.4 Authors@R: c(person("Michal", "Stolarczyk", email = "mjs5kd@virginia.edu",role = c("aut", "cre")), person("Nathan", "Sheffield", email = "nathan@code.databio.org",role = c("aut"))) Description: A Bioconductor-oriented project management class. It wraps the diff --git a/NEWS.md b/NEWS.md index 080f7a4..9d59ba6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,13 @@ +# BiocProject 0.0.4 + +## Unreleased + +## Changed + +* better custom data loading function error/warning communication +* all exceptions are caught with `BiocProject` constructor +* fix `.updateSubconfig(.Object@config, sp) : Subproject not found:` warning in `toProject` method + # BiocProject 0.0.3 ## 2018-12-21 diff --git a/R/methods.R b/R/methods.R index 3364eea..c9bde5d 100644 --- a/R/methods.R +++ b/R/methods.R @@ -116,7 +116,7 @@ setMethod( #' @param .Object an object of \code{\link{BiocProject-class}} #' @param subproject a character with the name of the subproject #' that should be activated during the converstion -#' to the \code{\link[pepr]{Project-class}} object +#' to the \code{\link[pepr]{Project-class}} object (optional) #' #' @return an object of \code{\link[pepr]{Project-class}} object #' @@ -134,7 +134,7 @@ setMethod( #' toProject(bp) #' #' @export -setGeneric("toProject", function(.Object,subproject=character()) +setGeneric("toProject", function(.Object,subproject=NULL) standardGeneric("toProject")) #' @export @@ -147,9 +147,9 @@ setMethod( ) -#' Extract data from \code{\link[pepr]{Project-class}} objects +#' Extract data from \code{\link{BiocProject-class}} objects #' -#' This method extracts the data from \code{\link[pepr]{Project-class}} objects +#' This method extracts the data from \code{\link{BiocProject-class}} objects #' #' @param .Object an object of \code{\link{BiocProject-class}} #' diff --git a/R/utils.R b/R/utils.R index 71d163b..f4a7be0 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,36 +1,48 @@ # internal function used for wrapping the user-supplied function meessages # in a box -.wrapFunMessages = function(str, type) { - str = trimws(str, which = "both") - n = options("width")[[1]] - header = paste0(" Your function ", type, "(s) ") - nH = floor(nchar(header) / 2) - nFill = floor(n / 2) - message(rep("-", nFill - nH), header, rep("-", nFill - nH)) - message("\n", str, "\n") - message(rep("-", n)) +.wrapFunMessages = function(messages, type) { + n = options("width")[[1]] + header = ifelse( + length(messages) > 1, + paste0(" Your function ", type, "s (", length(messages), ") "), + paste0(" Your function ", type, " ") + ) + nH = floor(nchar(header) / 2) + nFill = floor(n / 2) + message("\n",rep("-", nFill - nH), header, rep("-", nFill - nH)) + i = 1 + for (i in seq_along(messages)) { + m = trimws(messages[i], which="both") + message("\n", type, " ", i , ": ", m, "\n") + } + message(rep("-", n), "\n") } + # internal function that wraps the external function execution # in tryCatch to indicate problems with the external function execution -.callBiocFun = function(f, a) { - readData = tryCatch({ - do.call(f, a) - }, warning = function(w) { - warning( - "There are warnings associated with your function execution." - ) - .wrapFunMessages(w$message,"warning") - message("No data was read. Creating an empty BiocProject object...") - return(w$message) - }, error = function(e) { - warning( - "There are errors associated with your function execution." - ) - .wrapFunMessages(e$message,"error") - message("No data was read. Creating an empty BiocProject object...") - return(e$message) - }) - return(readData) +.callBiocFun <- function(func, arguments) +{ + .warnings = c() + frameNumber <- sys.nframe() + wHandler <- function(w){ + # warning handler + assign(".warnings", append(.warnings,w$message), + envir = sys.frame(frameNumber)) + invokeRestart("muffleWarning") + } + eHandler <- function(e){ + # error handler + .wrapFunMessages(e$message,"error") + message("No data was read. Creating an empty BiocProject object...") + message("The error message was saved in the .Data slot.") + e$message + } + res = withCallingHandlers(tryCatch(do.call(func, arguments), error = eHandler),warning = wHandler) + if(length(.warnings) > 0){ + warning("There were warnings associated with your function execution.") + .wrapFunMessages(.warnings,"warning") + } + return(res) } #' Create an absolute path from a primary target and a parent candidate. diff --git a/inst/extdata/example_peps-master/example_BiocProject_exceptions/project_config.yaml b/inst/extdata/example_peps-master/example_BiocProject_exceptions/project_config.yaml new file mode 100644 index 0000000..b572fe4 --- /dev/null +++ b/inst/extdata/example_peps-master/example_BiocProject_exceptions/project_config.yaml @@ -0,0 +1,6 @@ +metadata: + sample_annotation: sample_annotation.csv + +bioconductor: + read_fun_name: readBedFilesExceptions + read_fun_path: readBedFilesExceptions.R diff --git a/inst/extdata/example_peps-master/example_BiocProject_exceptions/readBedFilesExceptions.R b/inst/extdata/example_peps-master/example_BiocProject_exceptions/readBedFilesExceptions.R new file mode 100644 index 0000000..9a6c1d6 --- /dev/null +++ b/inst/extdata/example_peps-master/example_BiocProject_exceptions/readBedFilesExceptions.R @@ -0,0 +1,18 @@ +readBedFilesExceptions = function(project) { + warning("first test warning") + warning("second test warning") + stop("test error") + paths = pepr::samples(project)$file_path + sampleNames = pepr::samples(project)$sample_name + setwd(dirname(project@file)) + result = lapply(paths, function(x){ + df = read.table(x) + colnames(df) = c('chr', 'start', 'end') + gr = GenomicRanges::GRanges(df) + }) + names(result) = sampleNames + return(result) + +} + + diff --git a/inst/extdata/example_peps-master/example_BiocProject_exceptions/sample_annotation.csv b/inst/extdata/example_peps-master/example_BiocProject_exceptions/sample_annotation.csv new file mode 100644 index 0000000..59de6e5 --- /dev/null +++ b/inst/extdata/example_peps-master/example_BiocProject_exceptions/sample_annotation.csv @@ -0,0 +1,3 @@ +sample_name,file_path +laminB1Lads,data/laminB1Lads.bed +vistaEnhancers,data/vistaEnhancers.bed diff --git a/man/getData.Rd b/man/getData.Rd index 10217ee..4770dcf 100644 --- a/man/getData.Rd +++ b/man/getData.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/methods.R \name{getData} \alias{getData} -\title{Extract data from \code{\link[pepr]{Project-class}} objects} +\title{Extract data from \code{\link{BiocProject-class}} objects} \usage{ getData(.Object) } @@ -13,7 +13,7 @@ getData(.Object) a list with the data elements } \description{ -This method extracts the data from \code{\link[pepr]{Project-class}} objects +This method extracts the data from \code{\link{BiocProject-class}} objects } \examples{ ProjectConfig = system.file( diff --git a/man/toProject.Rd b/man/toProject.Rd index 5a1a705..753258b 100644 --- a/man/toProject.Rd +++ b/man/toProject.Rd @@ -4,14 +4,14 @@ \alias{toProject} \title{Get \code{\link[pepr]{Project-class}} object} \usage{ -toProject(.Object, subproject = character()) +toProject(.Object, subproject = NULL) } \arguments{ \item{.Object}{an object of \code{\link{BiocProject-class}}} \item{subproject}{a character with the name of the subproject that should be activated during the converstion -to the \code{\link[pepr]{Project-class}} object} +to the \code{\link[pepr]{Project-class}} object (optional)} } \value{ an object of \code{\link[pepr]{Project-class}} object diff --git a/update_examples.sh b/update_examples.sh index 3bf288d..5cd7055 100755 --- a/update_examples.sh +++ b/update_examples.sh @@ -5,5 +5,6 @@ mkdir -p inst/extdata/example_peps-master/example_BiocProject mkdir -p inst/extdata/example_peps-master/example_BiocProject_remote mv example_peps-master/example_BiocProject inst/extdata/example_peps-master mv example_peps-master/example_BiocProject_remote inst/extdata/example_peps-master +mv example_peps-master/example_BiocProject_exceptions inst/extdata/example_peps-master rm -rf example_peps-master rm master.zip \ No newline at end of file diff --git a/vignettes/1getStarted.Rmd b/vignettes/1getStarted.Rmd index c9d20c0..c8d752f 100644 --- a/vignettes/1getStarted.Rmd +++ b/vignettes/1getStarted.Rmd @@ -168,7 +168,7 @@ The function specified can be a data processing function of any complexity, but 1. the argument must be a [`pepr::Project`](http://code.databio.org/pepr/reference/Project-class.html) object (should use that input to load all the relevant data into `R`), 1. must return one or more data objects. -For example, consider the [parseEncodeRegions function](https://raw.githubusercontent.com/pepkit/example_peps/master/example_BiocProject/parseEncodeRegions.R): +For example, consider the [readBedFiles function](https://github.com/pepkit/example_peps/blob/master/example_BiocProject/readBedFiles.R): ```{r echo=FALSE, eval=TRUE, comment=""} processFunction = system.file( @@ -181,11 +181,32 @@ processFunction = system.file( source(processFunction) readBedFiles ``` +# Data reading function error/warning handling -# Advanced `BiocProject` features +The `BiocProject` constructor provides a way to rigorously monitor exceptions related to your data reading function. All the produced warnings and errors are caught, processed and displayed in an organized way: -See this [BiocProject advanced features vignette](./2multipleArguments.html) if you want to: +```{r} +configFile = system.file( + "extdata", + "example_peps-master", + "example_BiocProject_exceptions", + "project_config.yaml", + package = "BiocProject" +) -* use a anonymous function instead of one defined *a priori* +bpExceptions = BiocProject(configFile) +``` +In case an error is caught, the erorr message is preserved and stored in the `.Data` slot of the `BiocProject` object, so it can be accessed the regular way: +```{r} +getData(bpExceptions) +``` +# Further reading + +See this [More arguments than just a PEP in your function?](./2multipleArguments.html) vignette if you want to: + +* use an anonymous function instead of one defined *a priori* * use a function that requires more arguments than just a PEP -* use a function that is a part of another `R` package \ No newline at end of file + +See the [Working with remote data](./4remoteData.html) vignette to learn how to download the data from the Internet and store it conveniently in the `BiocProject` object. + +See the [Working with large datasets - simpleCache](./3simpleCache.html) vignette to learn how the `simpleCache` R package can be used to prevent copious and lengthy results recalculations when working with large datasets. \ No newline at end of file diff --git a/vignettes/2multipleArguments.Rmd b/vignettes/2multipleArguments.Rmd index a526b35..12139b5 100644 --- a/vignettes/2multipleArguments.Rmd +++ b/vignettes/2multipleArguments.Rmd @@ -72,9 +72,9 @@ bpArgs = BiocProject(file=ProjectConfigArgs, funcArgs=list(resize.width=100)) The `funcArgs` argument gets a one element list and passes the `resize.width` argument to your custom data processing function. -# How to use a anonymous function +# How to use an anonymous function -You can use a [anonymous function](https://en.wikipedia.org/wiki/Anonymous_function) (that is implemented in the `BiocProject` function call) to provide additional arguments to your function of interest. For example: +You can use an [anonymous function](https://en.wikipedia.org/wiki/Anonymous_function) (that is implemented in the `BiocProject` function call) to provide additional arguments to your function of interest. For example: ```{r} bpAnonymous = BiocProject(file=ProjectConfigArgs, func=function(x){ @@ -83,7 +83,4 @@ bpAnonymous = BiocProject(file=ProjectConfigArgs, func=function(x){ ) #Inspect it bpAnonymous -``` - - - +``` \ No newline at end of file