Skip to content

Commit

Permalink
Merge pull request #28 from pepkit/dev
Browse files Browse the repository at this point in the history
Release 0.2
  • Loading branch information
stolarczyk authored Apr 19, 2019
2 parents 2a5f00c + 420c96c commit d5f99cd
Show file tree
Hide file tree
Showing 23 changed files with 160 additions and 57 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ r_github_packages:
bioc_packages:
- GenomicRanges
- BiocStyle
- BiocFileCache
- BiocFileCache

2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: BiocProject
Title: Bioconductor Management with Portable Encapsulated Project (PEP) Objects
Version: 0.1.1
Version: 0.1.2
Authors@R: c(person("Michal", "Stolarczyk", email = "[email protected]",role = c("aut", "cre")),
person("Nathan", "Sheffield", email = "[email protected]",role = c("aut")))
Description: A Bioconductor-oriented project management class. It wraps the
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Generated by roxygen2: do not edit by hand

export(.insertPEP)
export(.setShowMethod)
export(.updateList)
export(BiocProject)
exportMethods(config)
Expand Down
24 changes: 18 additions & 6 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# BiocProject 0.1.1 - 2019-02-15
# BiocProject 0.1.2 - unreleased

## Added

* the native `show` methods are redefined for the objects returned by `BiocProject::BiocProject` function, so that they display the PEP component of the object `metadata`
* `BiocProject` function now handles the case when multiple data processing functions are defined in the config file. The last one is used if there's no match in `readFunName` and any of the functions sourced from the file specified in `readFunPath`

## Changed

* updates in the vignettes related to changes of metadata keys in the Project config
* when the data processing function function is read from file, it is used within a newly created environment so that it is not left in the `.GlobalEnv` after the `BiocProject` function execution

# BiocProject 0.1.1 - 2019-02-15

## Added

Expand All @@ -11,7 +23,7 @@
* when errors are encountered, BiocProject now returns a PEP (`pepr::Project`) along with the error message in a `S4Vectors::List` object
* the `bioconductor` section of the config file now follows the Bioconductor coding style (`camelCaps`)

# BiocProject 0.1 - 2019-01-28
# BiocProject 0.1 - 2019-01-28

## Added

Expand All @@ -22,22 +34,22 @@

* **complete concept redesign**: no `BiocProject` class. The objects returned by the custom data reading function have to be of class `Annotated` and the `PEP` is inserted as the first element of its `metadata()` list

# BiocProject 0.0.4 - 2019-01-25
# BiocProject 0.0.4 - 2019-01-25

## 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
# BiocProject 0.0.3 - 2018-12-21

## Changed

* the default values for all optional arguments are `NULL`
* change `lambda function` to `anonymous function`

# BiocProject 0.0.2 - 2018-12-01
# BiocProject 0.0.2 - 2018-12-01

## Changed

Expand All @@ -46,7 +58,7 @@
* errors and warnings (if any) are returned instead of the data
* if the object constructor can't find the function file, the message is more informative

# BiocProject 0.0.1 - 2018-11-20
# BiocProject 0.0.1 - 2018-11-20

## Added

Expand Down
84 changes: 53 additions & 31 deletions R/functions.R
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,7 @@
#' @export BiocProject
BiocProject = function(file, subproject = NULL, autoLoad = TRUE, func = NULL,
funcArgs = NULL) {
p = tryCatch(
expr = {
pepr::Project(file=file, subproject=subproject)
},warning = function(w) {
message(w)
stop("There are warnings
associated with the 'Project' object creation.")
}
)
p = pepr::Project(file=file, subproject=subproject)
# prevent PEP (Project object) input. This prevents BiocProject object
# failing when the user provides the Project object
if(is.null(funcArgs)){
Expand Down Expand Up @@ -124,49 +116,69 @@ BiocProject = function(file, subproject = NULL, autoLoad = TRUE, func = NULL,
if(!is.logical(autoLoad)) stop("'autoLoad' argument has to be a logical,
got '", class(autoLoad),"'")
if (autoLoad) {
# check if the config consists of MAIN_SECTION section
# check if the config consists of MAIN_SECTION section
if(!pepr::checkSection(pepr::config(p), MAIN_SECTION)){
message("No data was read. Returning a Project object")
warning("The config YAML is missing the '",
MAIN_SECTION,"' section.")
return(p)
}
funcName = pepr::config(p)[[MAIN_SECTION]][[FUNCTION_NAME]]
# check if the function name was provided
# and if it exists in the environment
funcName = pepr::config(p)[[MAIN_SECTION]][[FUNCTION_NAME]]
# check if the function name was provided
# and if it exists in the environment
if (!is.null(funcName) && exists(funcName)) {
# function from config.yaml in environment
readData = .callBiocFun(funcName, args)
message("Used function ", funcName, " from the environment")
message("Used function '", funcName, "' from the environment")
return(.insertPEP(readData, p))
}else{
if (!is.null(funcName) && length(grep("(\\:){2,3}", funcName)) != 0) {
# trying to access the function from the namespace that
# was specified in the config.yaml FUNCTION_NAME
splitted = strsplit(funcName, ":")[[1]]
nonEmpty = splitted[which(splitted != "")]
funcName = utils::getFromNamespace(x=nonEmpty[2], ns=nonEmpty[1])
readData = .callBiocFun(funcName, args)
message("Used function ", funcName, " from the environment")
funcCode = utils::getFromNamespace(nonEmpty[2], nonEmpty[1])
readData = .callBiocFun(funcCode, args)
message("Used function '", nonEmpty[2],
"' from the package: ", nonEmpty[1])
return(.insertPEP(readData, p))
}
# function from config.yaml in read_fun_name not in environment,
# trying to source the file specified in
# the config.yaml FUNCTION_PATH
# function from config.yaml in FUNCTION_NAME not in environment,
# trying to source the file specified
# in the config.yaml FUNCTION_PATH
funcPath = pepr::.expandPath(
pepr::config(p)[[MAIN_SECTION]][[FUNCTION_PATH]])
if (!is.null(funcPath)){
if (!file.exists(funcPath))
funcPath = .makeAbsPath(funcPath,dirname(p@file))
if(!file.exists(funcPath))
if (!file.exists(funcPath))
stop(
"The function does not exist in the environment and file ",
"The function does not exist in the environment and file '",
funcPath,
" does not exist"
"' does not exist"
)
readFun = source(funcPath)$value
message("Function read from file: ", funcPath)
readData = .callBiocFun(readFun, args)
# Load the sourced objects into a new environment,
# so they are not in the .GlobalEnv after the BiocProject
# function execution
e = new.env()
# only the last defined function is saved into the variable
# below so first we need to check whether the FUNCTION_NAME
# defines a preferred function. If it does not, then use the
# lastFun. This is relevant in case multiple functions are
# defined in the file specified in FUNCTION_PATH.
lastFun = source(funcPath, local=e)$value
# check again for the specified funcion name, maybe it is
# defined in the file which was just sourced
if (!is.null(funcName) && exists(funcName, where=e)) {
message("Function '", funcName,"' read from file '", funcPath, "'")
readData = .callBiocFun(
getFunction(funcName, where=e,mustFind=TRUE), args)
return(.insertPEP(readData, p))
}
# the function indicated in FUNCTION_NAME was not found,
# use the last one in FUNCTION_PATH
message("Multiple functions found in '", funcPath, "'. Using the last one.")
readData = .callBiocFun(lastFun, args)
return(.insertPEP(readData, p))
}else{
warning("Can't find function in the environment and the value for '"
Expand All @@ -189,6 +201,12 @@ BiocProject = function(file, subproject = NULL, autoLoad = TRUE, func = NULL,
#' into the metadata slot of objects that
#' extend the \code{\link[S4Vectors]{Annotated-class}}
#'
#' Additionally, if the object extends the
#' \code{\link[S4Vectors]{Annotated-class}} (or is a list that will be
#' automatically converted to a \code{\link[S4Vectors]{List}}) the show method
#' for its class is redefined to display the \code{\link[pepr]{Project-class}}
#' as the metadata.
#'
#' @param object an object of \code{\link[S4Vectors]{Annotated-class}}
#' @param pep an object of class \code{\link[pepr]{Project-class}}
#'
Expand All @@ -211,14 +229,18 @@ BiocProject = function(file, subproject = NULL, autoLoad = TRUE, func = NULL,
if(!methods::is(pep, "Project"))
stop("the pep argument has to be of class 'Project',
got '", class(pep),"'")
# do we throw a warning/message saying what happens in the next line?
if(methods::is(object, "list"))
object = S4Vectors::List(object)
if(methods::is(object, "Annotated")){
S4Vectors::metadata(object) = list(PEP=pep)
object
}else{
warning("The 'object' argument has to be of class 'Annotated', got '",
class(object),"'")
} else{
warning("BiocProject expects data loading functions to return an 'Annotated' object, but your function returned a '",
class(object),"' object. To use an Annotated, this returned object has been placed in the first slot of a List")
result = S4Vectors::List(result=object)
S4Vectors::metadata(result) = list(PEP=pep)
result
object = result
}
.setShowMethod(object)
object
}
34 changes: 34 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,37 @@
})))
}

#' Redefine the show method of the object
#'
#' Adds the Project objects display to the default show method of an \code{\link[S4Vectors]{Annotated-class}}
#'
#' The method is defined in the environment in which the function was called, see: \code{\link[base]{sys.parent}}
#'
#' @param returnedObject object of \code{\link[S4Vectors]{Annotated-class}}
#'
#' @return \code{FALSE} if the function was not set
#'
#' @export
#'
#' @examples
#' x = S4Vectors::List(c("so","cool"))
#' metadata(x) = list(PEP=pepr::Project())
#' .setShowMethod(x)
#' x
.setShowMethod = function(returnedObject) {
oriClass = class(returnedObject)
if(!is(returnedObject,"Annotated")){
warning("The show method was not redefined for '", oriClass, "'")
return(FALSE)
}
oriShow = selectMethod("show", oriClass)
# the new method is created only if the environment of the original one is locked.
# this way the method will not be redefined over and over again when the BiocProject functon is called.
if(environmentIsLocked(environment(oriShow)))
setMethod("show", signature = oriClass, definition = function(object){
do.call(oriShow, list(object))
pep = getProject(object)
cat("\nmetadata: ")
selectMethod("show","Project")(pep)
}, where = parent.frame())
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
metadata:
sample_annotation: sample_annotation.csv
sample_table: sample_table.csv

bioconductor:
readFunName: readBedFiles
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
metadata:
sample_annotation: sample_annotation.csv
sample_table: sample_table.csv

bioconductor:
readFunName: readBedFiles_resize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ readBedFiles_resize = function(project, resize.width) {
setwd(cwd)
names(result) = sampleNames
return(GenomicRanges::GRangesList(result))
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
metadata:
sample_annotation: sample_annotation.csv
sample_table: sample_table.csv

bioconductor:
readFunName: readBedFilesExceptions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
metadata:
sample_annotation: sample_annotation.csv
sample_table: sample_table.csv

bioconductor:
readFunName: readRemoteData
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
metadata:
sample_annotation: sample_annotation.csv
sample_table: sample_table.csv

bioconductor:
read_fun_name: readRemoteData_resize
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This is a faulty PEP.
# The readFunName and readFunPath values point to function that does not exist
metadata:
sample_annotation: sample_annotation.csv
sample_table: sample_table.csv

bioconductor:
readFunName: readBedFiles_missing
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This is a faulty PEP.
# The bioconductor section does not exist
metadata:
sample_annotation: sample_annotation.csv
sample_table: sample_table.csv
7 changes: 7 additions & 0 deletions man/dot-insertPEP.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions man/dot-setShowMethod.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions tests/testthat/test_all.R
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,6 @@ test_that("BiocProject function throws a warning and returns a Project object
expect_warning(expect_is(BiocProject(configFileNoSection),"Project"))
})

test_that("BiocProject function throws an error
when nonexistent subproject is provided",{
expect_error(expect_warning(BiocProject(configFile, subproject = "test")))
})

context("Test Annotated methods")

test_that("samples returns a correct object", {
Expand Down
Loading

0 comments on commit d5f99cd

Please sign in to comment.