diff --git a/DESCRIPTION b/DESCRIPTION index 5c18ec8..49501ed 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: pm Title: Project and Analysis Manager -Version: 0.1.10 +Version: 0.1.11 Authors@R: person("Alon", "Alexander", , "alon008@gmail.com", role = c("aut", "cre")) Description: Enforces and supports a standardized folder structure for research diff --git a/NEWS.md b/NEWS.md index bb13d6f..9c798e7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +# pm 0.1.11 + +## New Features + +- Support subfolders in `PMAnalysis$get_output_path` +- Support subfolders in `PMAnalysis$list_outputs` +- Support subfolders in `get_artifact` (both `PMAnalysis` and `PmProject`) + # pm 0.1.10 ## New Features diff --git a/R/analysis.R b/R/analysis.R index 623ca69..71c7a24 100644 --- a/R/analysis.R +++ b/R/analysis.R @@ -241,31 +241,23 @@ PMAnalysis <- R6Class("PMAnalysis", } # Get all files in the directory - files <- list.files(outputs_dir, full.names = TRUE) + files <- list.files(outputs_dir, full.names = FALSE, recursive = TRUE) if (length(files) == 0) { return(list()) } - # Filter to only files (not directories) using vectorized approach - file_info <- file.info(files) - is_file <- !is.na(file_info$isdir) & !file_info$isdir - files_only <- files[is_file] - - if (length(files_only) == 0) { - return(list()) - } - # Create PMData objects using lapply - file_ids <- tools::file_path_sans_ext(basename(files_only)) - file_paths <- normalizePath(files_only, mustWork = FALSE) + file_ids <- gsub("\\", "/", tools::file_path_sans_ext(files), fixed = TRUE) + file_paths <- normalizePath(file.path(outputs_dir, files), mustWork = FALSE) - lapply(seq_along(files_only), function(i) { + lapply(seq_along(files), function(i) { PMData$new(id = file_ids[i], path = file_paths[i]) }) }, #' @description #' Get output path for a file, returning a PMData object. + #' Supports also subfolders using both unix-style and windows-style delimeteres ("/" and "\\"). #' #' @param name Character. Name of the output file (with or without extension). #' @param type Character. Optional type of output (table, object, image, figure, parquet, csv). @@ -291,6 +283,11 @@ PMAnalysis <- R6Class("PMAnalysis", #' intermediate <- analysis$get_output_path("temp_data", type = "table", intermediate = TRUE) #' intermediate$id # "temp_data" #' intermediate$path # full path to temp_data.parquet in intermediate/ + #' + #' # Get output path with nested folders + #' output2 <- analysis$get_output_path("unique\\complex\\structure.rds") + #' output2$id # "unique/complex/structure" + #' output2$path get_output_path = function(name, type = NULL, intermediate = FALSE) { # Store original name for ID (without extension) original_name <- name @@ -332,7 +329,9 @@ PMAnalysis <- R6Class("PMAnalysis", folder <- if (intermediate) constants$ANALYSIS_INTERMEDIATE_DIR else constants$ANALYSIS_OUTPUT_DIR - full_path <- normalizePath(file.path(self$path, folder, name), mustWork = FALSE) + name <- strsplit(name, "\\\\|/") + full_path_raw <- do.call(file.path, as.list(c(self$path, folder, unlist(name)))) + full_path <- normalizePath(full_path_raw, mustWork = FALSE) PMData$new(id = id, path = full_path) }, diff --git a/R/data.R b/R/data.R index 461fa76..7a8b54d 100644 --- a/R/data.R +++ b/R/data.R @@ -31,7 +31,7 @@ PMData <- R6Class("PMData", chk::chk_scalar(path) chk::chk_character(path) self$id <- id - self$path <- path + self$path <- normalizePath(path, mustWork = FALSE) }, #' @description @@ -101,6 +101,9 @@ PMData <- R6Class("PMData", #' data_rdata$write(obj1, obj2, obj3 = 42) #' }) write = function(x, ...) { + # Create the folder in case it doesn't exist + dir.create(dirname(self$path), showWarnings = FALSE, recursive = TRUE) + # For RData files, we need to preserve object names from the original call ext <- tolower(tools::file_ext(self$path)) if (ext %in% c("rdata", "rda")) { @@ -129,7 +132,7 @@ PMData <- R6Class("PMData", obj_names <- c(obj_names, obj_name) } } - + # Call pm_write_file with explicit object names pm_write_file(self$path, x, ..., object_names = obj_names) } else { diff --git a/R/data_utils.R b/R/data_utils.R index b04cc39..4904ced 100644 --- a/R/data_utils.R +++ b/R/data_utils.R @@ -744,4 +744,3 @@ pm_write_file <- function(file, x, ..., object_names = NULL) { invisible(file) } - diff --git a/R/project.R b/R/project.R index 32804fc..e6dfce7 100644 --- a/R/project.R +++ b/R/project.R @@ -275,6 +275,10 @@ PMProject <- R6Class("PMProject", chk::chk_scalar(id) chk::chk_character(id) + # Normalize (subfolder) id + prev_id = id + id <- gsub("\\", "/", id, fixed = TRUE) + # Determine which analyses to search if (!is.null(analysis_name)) { chk::chk_scalar(analysis_name) diff --git a/docs/404.html b/docs/404.html index 0f7810a..2d2cbc1 100644 --- a/docs/404.html +++ b/docs/404.html @@ -20,7 +20,7 @@ pm - 0.1.10 + 0.1.11