diff --git a/.github/ISSUE_TEMPLATE/cran-release.yaml b/.github/ISSUE_TEMPLATE/cran-release.yaml new file mode 100644 index 000000000..bab34fcff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/cran-release.yaml @@ -0,0 +1,124 @@ +--- +name: 🎉 CRAN Release +description: Template for release to CRAN +title: "[Release]: " +labels: ["release"] +assignees: + - KlaudiaBB + - cicdguy + - shajoezhu +body: + - type: markdown + attributes: + value: | + ⚠️ Please do not link or mention any internal references in this issue. This includes internal URLs, intellectual property and references. + - type: textarea + id: blocked-by + attributes: + label: Blocked by + description: Any PRs or issues that this release is blocked by. + placeholder: Add a list of blocking PRs or issues here. + value: | + ### PRs + + - [ ] PR 1 + + ### Issues + + - [ ] Issue 1 + validations: + required: true + - type: textarea + id: pre-release + attributes: + label: Pre-release + description: Pre-requisites that must be fulfilled before initiating the release process. + placeholder: Add your list of pre-requisites here. + value: | + - [ ] Make sure you adhere to CRAN submission policy: https://cran.r-project.org/web/packages/submission_checklist.html; https://cran.r-project.org/web/packages/policies.html. + - [ ] Make sure that high priority bugs (label "priority" + "bug") have been resolved before going into the release. + - [ ] Review old/hanging PRs before going into the release (Optional). + - [ ] Revisit R-package's lifecycle badges (Optional). + - [ ] Make sure that all upstream dependencies of this package that need to be submitted to CRAN were accepted before going into release activities. + - [ ] Make sure integration tests are green 2-3 days before the release. Look carefully through logs (check for warnings and notes). + - [ ] Decide what gets merged in before starting release activities. + - type: textarea + id: release + attributes: + label: Release + description: The steps to be taken in order to create a release. + placeholder: Steps to create a release. + value: | + ### Prepare the release + + - [ ] Create a new release candidate branch + `git checkout -b release-candidate-vX.Y.Z` + - [ ] Update NEWS.md file: make sure it reflects a holistic summary of what has changed in the package. + - [ ] Remove the additional fields (`Remotes`) from the DESCRIPTION file where applicable. + - [ ] Make sure that the minimum dependency versions are updated in the DESCRIPTION file for the package and its reverse dependencies (Optional). + - [ ] Increase versioned dependency on {package name} to >=X.Y.Z (Optional). + - [ ] Commit your changes and create the PR on GitHub (add "[skip vbump]" in the PR title). Add all updates, commit, and push changes: + `# Make the necessary modifications to your files + # Stage the changes + git add + # Commit the changes + git commit -m "[skip vbump] " + git push origin release-candidate-vX.Y.Z` + + ### Test the release + + - [ ] Execute the manual tests on Shiny apps that are deployed on various hosting providers (Posit connect and shinyapps.io) - track the results in GitHub issue (Applicable only for frameworks that use Shiny). + - [ ] Monitor integration tests, if integration fails, create priority issues on the board. + - [ ] Execute UAT tests (Optional). + + ### CRAN submission + + - [ ] Tag the update(s) as a release candidate vX.Y.Z-rc (e.g. v0.5.3-rc1) on the release candidate branch (release-candidate-vX.Y.Z). + `# Create rc tag for submission for internal validation + git tag vX.Y.Z-rc + git push origin vX.Y.Z-rc` + - [ ] Build the package locally using the command:`R CMD build .` which will generate a .tar.gz file necessary for the CRAN submission. + - [ ] Submit the package to https://win-builder.r-project.org/upload.aspx for testing, for more details please see "Building and checking R source packages for Windows": https://win-builder.r-project.org/. + - [ ] Once tested, send the package that was built in the previous steps to CRAN via this form: https://cran.r-project.org/submit.html. + - [ ] Address CRAN feedback, tag the package vX.Y.Z-rc(n+1) and repeat the submission to CRAN whenever necessary. + - [ ] Get the package accepted and published on CRAN. + + ### Tag the release + + - [ ] If the additional fields were removed, add them back in a separate PR, and then merge the PR back to main (add "[skip vbump]" in the PR title). If nothing was removed just merge the PR you created in the "Prepare the release" section to 'main'. Note the commit hash of the merged commit. **Note:** additional commits might be added to the `main` branch by a bot or an automation - we do **NOT** want to tag this commit. + + ### Make sure of the following before continuing + + - [ ] CI checks are passing in GH before releasing the package. + - [ ] Shiny apps are deployable and there are no errors/warnings (Applicable only for frameworks that use Shiny). + + - [ ] Create a git tag with the final version set to vX.Y.Z on the main branch. In order to do this: + 1. Checkout the commit hash. + `git checkout ` + 2. Tag the hash with the release version (vX.Y.Z). + `git tag vX.Y.Z` + 3. Push the tag to make the final release. + `git push origin vX.Y.Z` + - [ ] Update downstream package dependencies to (>=X.Y.Z) in {package name}. + Note: Once the release tag is created, the package is automatically published to internal repositories. + - type: textarea + id: post-release + attributes: + label: Post-release + description: The list of activities to be completed after the release. + placeholder: The steps that must be taken after the release. + value: | + - [ ] Ensure that CRAN checks are passing for the package. + - [ ] Make sure that the package is published to internal repositories. + - [ ] Make sure internal documentation is up to date. + - [ ] Review and update installation instructions for the package wherever needed (Optional). + - [ ] Update all integration tests to reference the new release. + - [ ] Announce the release on ________. + - type: textarea + id: decision-tree + attributes: + label: Decision tree + description: Any decision tree(s) that would aid release management + placeholder: Any decision tree(s) that would aid release management. + value: | + Click [here](https://github.com/insightsengineering/.github/blob/main/.github/ISSUE_TEMPLATE/RELEASE_DECISION_TREE.md) to see the release decision tree. diff --git a/DESCRIPTION b/DESCRIPTION index 33bc29311..3beff52a9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -5,12 +5,17 @@ Version: 0.3.0.9033 Date: 2024-01-11 Authors@R: c( person("Dawid", "Kaledkowski", , "dawid.kaledkowski@roche.com", role = c("aut", "cre")), + person("Aleksander", "Chlebowski", , "aleksander.chlebowski@contractors.roche.com", role = "aut"), + person("Marcin", "Kosinski", , "marcin.kosinski.mk1@roche.com", role = "aut"), + person("Andre", "Verissimo", , "andre.verissimo@roche.com", role = "aut"), person("Pawel", "Rucki", , "pawel.rucki@roche.com", role = "aut"), person("Mahmoud", "Hallal", , "mahmoud.hallal@roche.com", role = "aut"), person("Nikolas", "Burkoff", role = "aut"), person("Maciej", "Nasinski", role = "aut"), person("Konrad", "Pagacz", role = "aut"), person("Junlue", "Zhao", role = "aut"), + person("Chendi", "Liao", , "chendi.liao@roche.com", role = "rev"), + person("Dony", "Unardi", , "unardid@gene.com", role = "rev"), person("F. Hoffmann-La Roche AG", role = c("cph", "fnd")) ) Description: Utilities for data transformations compatible with 'teal' @@ -21,7 +26,7 @@ URL: https://insightsengineering.github.io/teal.data/, BugReports: https://github.com/insightsengineering/teal.data/issues Depends: R (>= 4.0), - teal.code (>= 0.4.1.9009) + teal.code (>= 0.5.0) Imports: checkmate (>= 2.1.0), lifecycle (>= 0.2.0), @@ -47,3 +52,29 @@ Language: en-US LazyData: true Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 +Collate: + 'cdisc_data.R' + 'data.R' + 'default_cdisc_join_keys.R' + 'formatters_var_labels.R' + 'deprecated.R' + 'dummy_function.R' + 'join_key.R' + 'join_keys-c.R' + 'join_keys-extract.R' + 'join_keys-names.R' + 'join_keys-parents.R' + 'join_keys-print.R' + 'join_keys-utils.R' + 'join_keys.R' + 'teal.data.R' + 'teal_data-class.R' + 'teal_data-datanames.R' + 'teal_data-get_code.R' + 'teal_data-show.R' + 'teal_data.R' + 'testhat-helpers.R' + 'topological_sort.R' + 'utils-get_code_dependency.R' + 'verify.R' + 'zzz.R' diff --git a/NEWS.md b/NEWS.md index fc1f8b936..717cceb0f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -41,8 +41,8 @@ * Transferred data hashing step in `TealDataset` and `MAETealDataset` to `teal`. * Removed `CDISCTealData` class and updated `TealData` to account for the removed functionality. * Added datasets parents information to `JoinKeys` class. -* Updated `cdisc_data` and `teal_data` wrappers to handle join_keys creation and updating instead of `CDISCTealData` and `TealData`. -* Removed join_keys methods from `TealDataset`, `TealDatasetConnector`. +* Updated `cdisc_data` and `teal_data` wrappers to handle `join_keys` creation and updating instead of `CDISCTealData` and `TealData`. +* Removed `join_keys` methods from `TealDataset`, `TealDatasetConnector`. # teal.data 0.1.2 diff --git a/R/cdisc_data.R b/R/cdisc_data.R index 50a9ca5c4..c732ebb01 100644 --- a/R/cdisc_data.R +++ b/R/cdisc_data.R @@ -1,18 +1,16 @@ -#' Data input for teal app +#' Data input for `teal` app #' #' @description `r lifecycle::badge("stable")` #' Function is a wrapper around [teal_data()] and guesses `join_keys` #' for given datasets whose names match ADAM datasets names. #' #' @inheritParams teal_data -#' @param join_keys (`join_keys`) or a single (`join_key_set`)\cr +#' @param join_keys (`join_keys`) object or a single (`join_key_set`) object\cr #' (optional) object with datasets column names used for joining. #' If empty then it would be automatically derived basing on intersection of datasets primary keys. #' For ADAM datasets it would be automatically derived. #' -#' @return -#' - a `TealData` object when `TealDataset` `TealDatasetConnector`, `TealDataConnector` is provided, -#' - a `teal_data` object otherwise. +#' @return A `teal_data` object. #' #' @details This function checks if there were keys added to all data sets #' @@ -26,8 +24,8 @@ #' ) #' #' data <- within(data, { -#' ADSL <- teal.data::example_cdisc_data("ADSL") -#' ADTTE <- teal.data::example_cdisc_data("ADTTE") +#' ADSL <- example_cdisc_data("ADSL") +#' ADTTE <- example_cdisc_data("ADTTE") #' }) #' cdisc_data <- function(..., diff --git a/R/data.R b/R/data.R index 3f3fc4cbd..cd935f485 100644 --- a/R/data.R +++ b/R/data.R @@ -1,6 +1,6 @@ #' Random adverse events #' -#' @description Random adverse events +#' @description Random adverse events. #' @docType data #' #' @usage rADAE @@ -11,9 +11,9 @@ #' @name rADAE "rADAE" -#' Random Concomitant Medications +#' Random concomitant medications #' -#' @description Random Concomitant Medications +#' @description Random concomitant medications. #' @docType data #' #' @usage rADCM @@ -26,7 +26,7 @@ #' Random response #' -#' @description Random Exposure +#' @description Random exposure. #' @docType data #' #' @usage rADEX @@ -39,7 +39,7 @@ #' Random lab analysis #' -#' @description Random lab analysis +#' @description Random lab analysis. #' @docType data #' #' @usage rADLB @@ -52,7 +52,7 @@ #' Random response #' -#' @description Random response +#' @description Random response. #' @docType data #' #' @usage rADRS @@ -65,7 +65,7 @@ #' Random patient listing #' -#' @description Random patient listing +#' @description Random patient listing. #' @docType data #' #' @usage rADSL @@ -78,7 +78,7 @@ #' Random data `rADTR` #' -#' @description Random data `rADTR` +#' @description Random data `rADTR`. #' @docType data #' #' @usage rADTR @@ -89,9 +89,9 @@ #' @name rADTR "rADTR" -#' Random Time to Event Analysis Dataset +#' Random time to event analysis dataset #' -#' @description Random Time to Event Analysis Dataset +#' @description Random time to event analysis dataset. #' @docType data #' #' @usage rADTTE @@ -104,7 +104,7 @@ #' Random data `rADVS` #' -#' @description Random data `rADVS` +#' @description Random data `rADVS`. #' @docType data #' #' @usage rADVS diff --git a/R/default_cdisc_join_keys.R b/R/default_cdisc_join_keys.R index 8ccd11cfe..e4181e978 100644 --- a/R/default_cdisc_join_keys.R +++ b/R/default_cdisc_join_keys.R @@ -1,4 +1,4 @@ -#' List containing the default `CDISC` join keys +#' List containing default joining keys for `CDISC` datasets #' #' @details #' This data object is created at loading time from `cdisc_datasets/cdisc_datasets.yaml`. diff --git a/R/deprecated.R b/R/deprecated.R index a6b119319..14a342635 100644 --- a/R/deprecated.R +++ b/R/deprecated.R @@ -1,351 +1,342 @@ #' Deprecated `TealData` class and related functions #' #' @description `r lifecycle::badge("deprecated")`\cr -#' This function has been deprecated. Please see [teal_data()] and [cdisc_data()] instead. -#' Find more information on \href{https://github.com/insightsengineering/teal/discussions/945}{Migration guide}. +#' The `TealData` class and associated functions have been deprecated. Use [teal_data()] instead. +#' See the [Migration guide](https://github.com/insightsengineering/teal/discussions/945) for details. #' #' @name TealData #' #' @param ... any argument supported in `TealData` related functions. #' #' @return nothing +#' @seealso [cdisc_data()] , [join_keys()] #' NULL -.deprecate_teal_data <- function(what) { +.deprecate_function <- function(what, details) { lifecycle::deprecate_stop( when = "0.3.1", what = what, - details = "Find more information on https://github.com/insightsengineering/teal/discussions/945" + details = details ) } +deprecation_detail <- "Find more information on https://github.com/insightsengineering/teal/discussions/945" + #' @rdname TealData #' @export as_cdisc <- function(...) { - .deprecate_teal_data("as_cdisc()") + .deprecate_function("as_cdisc()", deprecation_detail) } #' @rdname TealData #' @export callable_code <- function(...) { - .deprecate_teal_data("callable_code()") + .deprecate_function("callable_code()", deprecation_detail) } #' @rdname TealData #' @export callable_function <- function(...) { - .deprecate_teal_data("callable_function()") + .deprecate_function("callable_function()", deprecation_detail) } #' @rdname TealData #' @export code_dataset_connector <- function(...) { - .deprecate_teal_data("code_dataset_connector()") + .deprecate_function("code_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export code_cdisc_dataset_connector <- function(...) { - .deprecate_teal_data("code_cdisc_dataset_connector()") + .deprecate_function("code_cdisc_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export csv_dataset_connector <- function(...) { - .deprecate_teal_data("csv_dataset_connector()") + .deprecate_function("csv_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export csv_cdisc_dataset_connector <- function(...) { - .deprecate_teal_data("csv_cdisc_dataset_connector()") + .deprecate_function("csv_cdisc_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export python_code <- function(...) { - .deprecate_teal_data("python_code()") + .deprecate_function("python_code()", deprecation_detail) } #' @rdname TealData #' @export python_dataset_connector <- function(...) { - .deprecate_teal_data("python_dataset_connector()") + .deprecate_function("python_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export python_cdisc_dataset_connector <- function(...) { - .deprecate_teal_data("python_cdisc_dataset_connector()") + .deprecate_function("python_cdisc_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export cdisc_data_connector <- function(...) { - .deprecate_teal_data("cdisc_data_connector()") + .deprecate_function("cdisc_data_connector()", deprecation_detail) } #' @rdname TealData #' @export cdisc_dataset <- function(...) { - .deprecate_teal_data("cdisc_dataset()") + .deprecate_function("cdisc_dataset()", deprecation_detail) } #' @rdname TealData #' @export cdisc_dataset_connector <- function(...) { - .deprecate_teal_data("cdisc_dataset_connector()") + .deprecate_function("cdisc_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export cdisc_dataset_connector_file <- function(...) { - .deprecate_teal_data("cdisc_dataset_connector_file()") + .deprecate_function("cdisc_dataset_connector_file()", deprecation_detail) } #' @rdname TealData #' @export cdisc_dataset_file <- function(...) { - .deprecate_teal_data("cdisc_dataset_file()") + .deprecate_function("cdisc_dataset_file()", deprecation_detail) } #' @rdname TealData #' @export dataset <- function(...) { - .deprecate_teal_data("dataset()") + .deprecate_function("dataset()", deprecation_detail) } #' @rdname TealData #' @export dataset_connector <- function(...) { - .deprecate_teal_data("dataset_connector()") + .deprecate_function("dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export dataset_connector_file <- function(...) { - .deprecate_teal_data("dataset_connector_file()") + .deprecate_function("dataset_connector_file()", deprecation_detail) } #' @rdname TealData #' @export dataset_file <- function(...) { - .deprecate_teal_data("dataset_file()") + .deprecate_function("dataset_file()", deprecation_detail) } #' @rdname TealData #' @export data_connection <- function(...) { - .deprecate_teal_data("data_connection()") + .deprecate_function("data_connection()", deprecation_detail) } #' @rdname TealData #' @export fun_dataset_connector <- function(...) { - .deprecate_teal_data("fun_dataset_connector()") + .deprecate_function("fun_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export fun_cdisc_dataset_connector <- function(...) { - .deprecate_teal_data("fun_cdisc_dataset_connector()") + .deprecate_function("fun_cdisc_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export relational_data_connector <- function(...) { - .deprecate_teal_data("relational_data_connector()") + .deprecate_function("relational_data_connector()", deprecation_detail) } #' @rdname TealData #' @export mae_dataset <- function(...) { - .deprecate_teal_data("mae_dataset()") + .deprecate_function("mae_dataset()", deprecation_detail) } #' @rdname TealData #' @export get_attrs <- function(...) { - .deprecate_teal_data("get_attrs()") + .deprecate_function("get_attrs()", deprecation_detail) } #' @rdname TealData #' @export get_dataset_label <- function(...) { - .deprecate_teal_data("get_dataset_label()") + .deprecate_function("get_dataset_label()", deprecation_detail) } #' @rdname TealData #' @export get_dataset <- function(...) { - .deprecate_teal_data("get_dataset()") + .deprecate_function("get_dataset()", deprecation_detail) } #' @rdname TealData #' @export get_datasets <- function(...) { - .deprecate_teal_data("get_datasets()") + .deprecate_function("get_datasets()", deprecation_detail) } #' @rdname TealData #' @export get_dataname <- function(...) { - .deprecate_teal_data("get_dataname()") + .deprecate_function("get_dataname()", deprecation_detail) } #' @rdname TealData #' @export get_key_duplicates <- function(...) { - .deprecate_teal_data("get_key_duplicates()") + .deprecate_function("get_key_duplicates()", deprecation_detail) } #' @rdname TealData #' @export get_keys <- function(...) { - .deprecate_teal_data("get_keys()") + .deprecate_function("get_keys()", deprecation_detail) } #' @rdname TealData #' @export get_raw_data <- function(...) { - .deprecate_teal_data("get_raw_data()") + .deprecate_function("get_raw_data()", deprecation_detail) } #' @rdname TealData #' @export is_pulled <- function(...) { - .deprecate_teal_data("is_pulled()") + .deprecate_function("is_pulled()", deprecation_detail) } #' @rdname TealData #' @export load_dataset <- function(...) { - .deprecate_teal_data("load_dataset()") + .deprecate_function("load_dataset()", deprecation_detail) } #' @rdname TealData #' @export load_datasets <- function(...) { - .deprecate_teal_data("load_datasets()") + .deprecate_function("load_datasets()", deprecation_detail) } #' @rdname TealData #' @export mutate_data <- function(...) { - .deprecate_teal_data("mutate_data()") + .deprecate_function("mutate_data()", deprecation_detail) } #' @rdname TealData #' @export mutate_dataset <- function(...) { - .deprecate_teal_data("mutate_dataset()") + .deprecate_function("mutate_dataset()", deprecation_detail) } #' @rdname TealData #' @export set_args <- function(...) { - .deprecate_teal_data("set_args()") + .deprecate_function("set_args()", deprecation_detail) } #' @rdname TealData #' @export rds_dataset_connector <- function(...) { - .deprecate_teal_data("rds_dataset_connector()") + .deprecate_function("rds_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export rds_cdisc_dataset_connector <- function(...) { - .deprecate_teal_data("rds_cdisc_dataset_connector()") + .deprecate_function("rds_cdisc_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export script_dataset_connector <- function(...) { - .deprecate_teal_data("script_dataset_connector()") + .deprecate_function("script_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export script_cdisc_dataset_connector <- function(...) { - .deprecate_teal_data("script_cdisc_dataset_connector()") + .deprecate_function("script_cdisc_dataset_connector()", deprecation_detail) } #' @rdname TealData #' @export set_keys <- function(...) { - .deprecate_teal_data("set_keys()") + .deprecate_function("set_keys()", deprecation_detail) } #' @rdname TealData #' @export read_script <- function(...) { - .deprecate_teal_data("read_script()") + .deprecate_function("read_script()", deprecation_detail) } #' @rdname TealData #' @export to_relational_data <- function(...) { - .deprecate_teal_data("to_relational_data()") + .deprecate_function("to_relational_data()", deprecation_detail) } #' @rdname TealData #' @export validate_metadata <- function(...) { - .deprecate_teal_data("validate_metadata()") + .deprecate_function("validate_metadata()", deprecation_detail) } #' @rdname TealData #' @export get_cdisc_keys <- function(...) { - .deprecate_teal_data("get_cdisc_keys()") + .deprecate_function("get_cdisc_keys()", deprecation_detail) } #' @rdname TealData #' @export cdisc_data_file <- function(...) { - .deprecate_teal_data("cdisc_data_file()") + .deprecate_function("cdisc_data_file()", deprecation_detail) } #' @rdname TealData #' @export teal_data_file <- function(...) { - .deprecate_teal_data("teal_data_file()") + .deprecate_function("teal_data_file()", deprecation_detail) } -#' Function to get join keys from a `` object -#' @param data `` - object to extract the join keys -#' @return Either `join_keys` object or `NULL` if no join keys +#' @rdname TealData #' @export -get_join_keys <- function(data) { - lifecycle::deprecate_stop( - when = " 0.3.1", - what = "get_join_keys(data)", - details = "Use `join_keys(data)` instead." - ) +get_join_keys <- function(...) { + .deprecate_function("get_join_keys()", "Use `join_keys(data)` instead.") } -#' @rdname get_join_keys -#' @inheritParams join_key +#' @rdname TealData #' @param value value to assign #' @export -`get_join_keys<-` <- function(data, dataset_1, dataset_2 = NULL, value) { - lifecycle::deprecate_stop( - when = " 0.3.1", - what = "`get_join_keys<-`()", - details = "Use `join_keys(x) <- ...`" - ) +`get_join_keys<-` <- function(..., value) { + .deprecate_function("`get_join_keys<-`()", "Use `join_keys(x) <- ...`") } #' @rdname col_labels -#' @inheritParams col_labels -#' @param data a data.frame object -#' @export -get_labels <- function(data, fill = TRUE) { - lifecycle::deprecate_stop( - when = " 0.3.1", - what = "get_labels(data)", - details = "Use col_labels(data)" - ) +#' @include formatters_var_labels.R +#' @details +#' `r lifecycle::badge("deprecated")`\cr +#' In previous versions of `teal.data` labels were managed with `get_labels()`. +#' This function is deprecated as of `0.3.1`, use `col_labels` instead. +#' @export +get_labels <- function(...) { + .deprecate_function("get_labels()", "Use col_labels(data)") } diff --git a/R/dummy_function.R b/R/dummy_function.R index 5ffcbb3a6..98ebbaab4 100644 --- a/R/dummy_function.R +++ b/R/dummy_function.R @@ -1,25 +1,16 @@ -#' This function returns a dummy dataset for testing examples and should only be used within `teal.data`. +#' Generate sample `CDISC` datasets #' -#' It is not meant to retrieve the `SCDA` dataset, and the dataset itself is not maintained here. +#' Retrieves example `CDISC` datasets for use in examples and testing. #' -#' This function creates a copy of the `SCDA` data for testing purposes. +#' This function returns a dummy dataset and should only be used within `teal.data`. +#' Note that the datasets are not created and maintained in `teal.data`, they are retrieved its dependencies. #' -#' `CDISC` data includes `ADSL`, `ADAE`, `ADLB`, `ADCM`, `ADEX`, `ADRS`, `ADTR` and `ADTTE`. +#' @param dataname (`character(1)`) name of a `CDISC` dataset #' -#' @param dataname name of the `CDISC` dataset -#' -#' @return `cdisc_data` +#' @return A `CDISC` dataset as a `data.frame`. #' #' @export -example_cdisc_data <- function(dataname) { - # Define the available datasets - datasets <- c("ADSL", "ADAE", "ADLB", "ADCM", "ADEX", "ADRS", "ADTR", "ADTTE", "ADVS") - - # Check if the provided dataname is valid - if (dataname %in% datasets) { - dataset <- get(paste0("r", dataname)) - return(dataset) - } else { - stop("Invalid dataname. Please provide one of the following: ", paste(datasets, collapse = ", ")) - } +example_cdisc_data <- function(dataname = c("ADSL", "ADAE", "ADLB", "ADCM", "ADEX", "ADRS", "ADTR", "ADTTE", "ADVS")) { + dataname <- sprintf("r%s", match.arg(dataname)) + dynGet(dataname, ifnotfound = stop(dataname, " not found"), inherits = TRUE) } diff --git a/R/formatters_var_labels.R b/R/formatters_var_labels.R index eb970a9fd..0ce4e2b2b 100644 --- a/R/formatters_var_labels.R +++ b/R/formatters_var_labels.R @@ -1,155 +1,97 @@ -#' Get Label Attributes of Variables in a \code{data.frame} +#' Variable labels #' -#' Variable labels can be stored as a \code{label} attribute for each variable. -#' This functions returns a named character vector with the variable labels -#' (empty sting if not specified) +#' Get or set variable labels in a `data.frame`. #' -#' @param x a \code{data.frame} object -#' @param fill boolean in case the \code{label} attribute does not exist if -#' \code{TRUE} the variable names is returned, otherwise \code{NA} +#' @details Variable labels can be stored as a `label` attribute set on individual variables. +#' These functions get or set this attribute, either on all (`col_labels`) or some variables (`col_relabel`). #' -#' @source This function was taken 1-1 from -#' \href{https://cran.r-project.org/package=formatters}{formatters} package, to reduce the complexity of -#' the dependency tree. +#' @param x (`data.frame` or `DataFrame`) data object +#' @param fill (`logical(1)`) specifying what to return if variable has no label +#' @param value (`character`) vector of variable labels of length equal to number of columns in `x`; +#' if named, names must match variable names in `x` and will be used as key to set labels; +#' use `NA` to remove label from variable +#' @param ... name-value pairs, where name corresponds to a variable name in `x` +#' and value is the new variable label #' -#' @seealso [col_relabel()] [`col_labels<-`] -#' -#' @return a named character vector with the variable labels, the names -#' correspond to the variable names -#' -#' @export +#' @return +#' For `col_labels`, named character vector of variable labels, the names being the corresponding variable names. +#' If the `label` attribute is missing, the vector elements will be +#' the variable names themselves if `fill = TRUE` and `NA` if `fill = FALSE`.\cr +#' For `col_labels<-` and `col_relabel`, copy of `x` with variable labels modified. #' #' @examples #' x <- iris #' col_labels(x) #' col_labels(x) <- paste("label for", names(iris)) #' col_labels(x) +#' y <- col_relabel(x, Sepal.Length = "Sepal Length of iris flower") +#' col_labels(y) +#' +#' @source These functions were taken from +#' [formatters](https://cran.r-project.org/package=formatters) package, to reduce the complexity of +#' the dependency tree and rewritten. +#' +#' @rdname col_labels +#' @export +#' col_labels <- function(x, fill = FALSE) { - checkmate::assert_data_frame(x) + checkmate::test_multi_class(x, c("data.frame", "DataFrame")) checkmate::assert_flag(fill) - if (NCOL(x) == 0) { - return(character()) + if (ncol(x) == 0L) { + return(character(0L)) } - y <- Map(function(col, colname) { - label <- attr(col, "label") + labels <- lapply(x, attr, "label") - if (is.null(label)) { + nulls <- vapply(labels, is.null, logical(1L)) + if (any(nulls)) { + labels[nulls] <- if (fill) { - colname + colnames(x)[nulls] } else { NA_character_ } - } else { - if (!is.character(label) && !(length(label) == 1)) { - stop("label for variable ", colname, "is not a character string") - } - as.vector(label) - } - }, x, colnames(x)) - - labels <- unlist(y, recursive = FALSE, use.names = TRUE) + } - if (!is.character(labels)) { - stop("label extraction failed") + not_char <- !vapply(labels, checkmate::test_string, logical(1L), na.ok = TRUE) + if (any(not_char)) { + stop("labels for variables ", toString(names(not_char[not_char])), "are not character strings") } - labels + unlist(labels, recursive = FALSE) } -#' Set Label Attributes of All Variables in a \code{data.frame} -#' -#' Variable labels can be stored as a \code{label} attribute for each variable. -#' This functions sets all non-missing (non-NA) variable labels in a \code{data.frame} -#' -#' @inheritParams col_labels -#' @param value new variable labels, \code{NA} removes the variable label -#' -#' @source This function was taken 1-1 from -#' \href{https://cran.r-project.org/package=formatters}{formatters} package, to reduce the complexity of -#' the dependency tree. -#' -#' @seealso [col_labels()] [col_relabel()] -#' -#' @return modifies the variable labels of \code{x} -#' +#' @rdname col_labels #' @export -#' -#' @examples -#' x <- iris -#' col_labels(x) -#' col_labels(x) <- paste("label for", names(iris)) -#' col_labels(x) -#' -#' if (interactive()) { -#' View(x) # in RStudio data viewer labels are displayed -#' } `col_labels<-` <- function(x, value) { - checkmate::assert_data_frame(x) + checkmate::test_multi_class(x, c("data.frame", "DataFrame")) checkmate::assert_character(value) checkmate::assert_true( ncol(x) == length(value), .var.name = "Length of value is equal to the number of columns" ) - theseq <- if (!is.null(names(value))) names(value) else seq_along(x) - # across columns of x - for (j in theseq) { - attr(x[[j]], "label") <- if (!is.na(value[j])) { - value[j] - } else { - NULL - } + if (is.null(names(value))) { + names(value) <- names(x) } - + x[names(value)] <- mapply(`attr<-`, x = x[names(value)], which = "label", value = value, SIMPLIFY = FALSE) x } -#' Copy and Change Variable Labels of a \code{data.frame} -#' -#' Relabel a subset of the variables -#' -#' @inheritParams col_labels<- -#' @param ... name-value pairs, where name corresponds to a variable name in -#' \code{x} and the value to the new variable label -#' -#' @return a copy of \code{x} with changed labels according to \code{...} -#' -#' @source This function was taken 1-1 from -#' \href{https://cran.r-project.org/package=formatters}{formatters} package, to reduce the complexity of -#' the dependency tree. -#' -#' @seealso [col_labels()] [`col_labels<-`] -#' +#' @rdname col_labels #' @export -#' -#' @examples -#' x <- col_relabel(iris, Sepal.Length = "Sepal Length of iris flower") -#' col_labels(x) -#' col_relabel <- function(x, ...) { - checkmate::assert_data_frame(x) + checkmate::test_multi_class(x, c("data.frame", "DataFrame")) if (missing(...)) { return(x) } dots <- list(...) varnames <- names(dots) - checkmate::assert_character(varnames, null.ok = FALSE) - - map_varnames <- match(varnames, colnames(x)) - if (any(is.na(map_varnames))) { - stop("variables: ", paste(varnames[is.na(map_varnames)], collapse = ", "), " not found") - } - - if (any(vapply(dots, Negate(is.character), logical(1)))) { - stop("all variable labels must be of type character") - } - - for (i in seq_along(map_varnames)) { - attr(x[[map_varnames[[i]]]], "label") <- dots[[i]] - } + checkmate::assert_subset(varnames, names(x), .var.name = "names of ...") + lapply(dots, checkmate::assert_string, .var.name = "element of ...") + x[varnames] <- mapply(`attr<-`, x = x[varnames], which = "label", value = dots, SIMPLIFY = FALSE, USE.NAMES = FALSE) x } diff --git a/R/join_keys-c.R b/R/join_keys-c.R index 70167b1fb..2dce5ef9c 100644 --- a/R/join_keys-c.R +++ b/R/join_keys-c.R @@ -4,7 +4,7 @@ #' #' @examples #' -#' # Merging multiple `join_keys` --- +#' # Merging multiple `join_keys` objects --- #' #' jk_merged <- c( #' jk, diff --git a/R/join_keys-extract.R b/R/join_keys-extract.R index 987b8ef9d..c77595465 100644 --- a/R/join_keys-extract.R +++ b/R/join_keys-extract.R @@ -126,7 +126,7 @@ #' - `x[i] <- value`: This (without `j` parameter) **is not** a supported #' operation for `join_keys`. #' - `join_keys(x)[i, j] <- value`: Assignment to `join_keys` object stored in `x`, -#' such as a `teal_data` or `join_keys` itself. +#' such as a `teal_data` object or `join_keys` object itself. #' #' @export #' @examples @@ -181,7 +181,7 @@ #' @rdname join_keys #' #' @order 1000 -#' @usage ## Prefered method is x[i, j] <- value +#' @usage ## Preferred method is x[i, j] <- value #' x[[i]][[j]] <- value #' #' @section Functions: diff --git a/R/join_keys-names.R b/R/join_keys-names.R index 0a550bd4a..f2853da32 100644 --- a/R/join_keys-names.R +++ b/R/join_keys-names.R @@ -1,4 +1,4 @@ -#' The Names of an `join_keys` Object +#' The names of a `join_keys` object #' @inheritParams base::`names<-` #' @export `names<-.join_keys` <- function(x, value) { diff --git a/R/join_keys-parents.R b/R/join_keys-parents.R index 7ae70b68b..1ae7dd3cf 100644 --- a/R/join_keys-parents.R +++ b/R/join_keys-parents.R @@ -1,15 +1,15 @@ -#' Getter and setter functions for parents attribute of `join_keys` +#' Get and set parents in `join_keys` object #' #' @description #' `parents()` facilitates the creation of dependencies between datasets by #' assigning a parent-child relationship. #' -#' Each element is defined by a list element, where `list("child" = "parent")`. +#' Each element is defined by a `list` element, where `list("child" = "parent")`. #' #' @param x (`join_keys` or `teal_data`) object that contains "parents" information #' to retrieve or manipulate. #' -#' @return a list of `character` representing the parents. +#' @return a `list` of `character` representing the parents. #' #' @export #' @seealso [join_keys()] @@ -35,9 +35,9 @@ parents.join_keys <- function(x) { #' # Get parents of join_keys inside teal_data object --- #' #' td <- teal_data( -#' ADSL = teal.data::rADSL, -#' ADTTE = teal.data::rADTTE, -#' ADRS = teal.data::rADRS, +#' ADSL = rADSL, +#' ADTTE = rADTTE, +#' ADRS = rADRS, #' join_keys = default_cdisc_join_keys[c("ADSL", "ADTTE", "ADRS")] #' ) #' parents(td) @@ -58,7 +58,7 @@ parents.teal_data <- function(x) { #' @export #' @examples #' -#' # Assigment of parents --- +#' # Assignment of parents --- #' #' jk <- join_keys( #' join_key("ds1", "ds2", "id"), @@ -111,7 +111,7 @@ parents.teal_data <- function(x) { #' @export #' @examples #' -#' # Assigment of parents of join_keys inside teal_data object --- +#' # Assignment of parents of join_keys inside teal_data object --- #' #' parents(td) <- list("ADTTE" = "ADSL") # replace existing #' parents(td)["ADRS"] <- "ADSL" # add new parent @@ -120,7 +120,7 @@ parents.teal_data <- function(x) { x } -#' @describeIn parents Getter for individual parent +#' @describeIn parents Getter for individual parent. #' #' @param dataset_name (`character(1)`) Name of dataset to query on their parent. #' diff --git a/R/join_keys-utils.R b/R/join_keys-utils.R index 0696610bd..82cd7399f 100644 --- a/R/join_keys-utils.R +++ b/R/join_keys-utils.R @@ -1,6 +1,6 @@ #' Helper function to assert if two key sets contain incompatible keys #' -#' return TRUE if compatible, throw error otherwise +#' @return Returns `TRUE` if successful, otherwise raises error. #' @keywords internal assert_compatible_keys <- function(join_key_1, join_key_2) { stop_message <- function(dataset_1, dataset_2) { @@ -70,6 +70,10 @@ assert_parent_child <- function(x) { invisible(x) } +#' Helper function to ensuring compatibility between two sets of keys +#' +#' @return Returns `TRUE` if successful, otherwise raises error. +#' @keywords internal assert_compatible_keys2 <- function(x, y) { # Helper to flatten join_keys / join_key_set flatten_join_key_sets <- function(value) { @@ -97,7 +101,7 @@ assert_compatible_keys2 <- function(x, y) { TRUE } -#' Updates the keys of the datasets based on the parents. +#' Updates the keys of the datasets based on the parents #' #' @param x (`join_keys`) object to update the keys. #' diff --git a/R/join_keys.R b/R/join_keys.R index a48c8452e..b64c692b8 100644 --- a/R/join_keys.R +++ b/R/join_keys.R @@ -19,11 +19,11 @@ #' @section Methods (by class): #' - `join_keys()`: Returns an empty `join_keys` object when called without arguments. #' - `join_keys(join_keys)`: Returns itself. -#' - `join_keys(teal_data)`: Returns the `join_keys` object contained in `teal_data`. +#' - `join_keys(teal_data)`: Returns the `join_keys` object contained in `teal_data` object. #' - `join_keys(...)`: Creates a new object with one or more `join_key_set` parameters. #' #' @param ... (optional)\cr -#' either `teal_data` or `join_keys` to extract `join_keys`, \cr +#' either `teal_data` or `join_keys` object to extract `join_keys`, \cr #' or any number of `join_key_set` objects to create `join_keys`, \cr #' or nothing to create an empty `join_keys` #' @param value For `x[i, j, directed = TRUE)] <- value` (named/unnamed `character`) diff --git a/R/teal.data.R b/R/teal.data.R index 5e8635439..309c0ec71 100644 --- a/R/teal.data.R +++ b/R/teal.data.R @@ -1,4 +1,4 @@ -#' teal.data: Reproducible data model for `teal` applications +#' `teal.data`: Reproducible data model for `teal` applications #' #' This package extends `teal` applications by module which #' stores the data with they relationships (keys) and reproducible diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 76a01031c..26bd71999 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -1,6 +1,6 @@ setOldClass("join_keys") -#' Reproducible data. +#' Reproducible data #' #' Reproducible data container class. Inherits code tracking behavior from [`teal.code::qenv-class`]. #' @@ -50,7 +50,7 @@ setClass( #' Initialize `teal_data` object. #' @name new_teal_data #' -#' @param data (`named list`) List of data. +#' @param data (`named list`) of data objects. #' @param code (`character` or `language`) code to reproduce the `data`. #' Accepts and stores comments also. #' @param join_keys (`join_keys`) object diff --git a/R/teal_data-datanames.R b/R/teal_data-datanames.R index 37b59e102..929f09eb1 100644 --- a/R/teal_data-datanames.R +++ b/R/teal_data-datanames.R @@ -1,4 +1,4 @@ -#' Names of Data Sets in `teal_data` Object +#' Names of data sets in `teal_data` object #' #' Get or set the value of the `datanames` slot. #' @@ -11,13 +11,15 @@ #' @param x (`teal_data`) object to access or modify #' @param value (`character`) new value for `@datanames`; all elements must be names of variables existing in `@env` #' -#' @return The contents of `@datanames` or `teal_data` with updated `@datanames`. +#' @return The contents of `@datanames` or `teal_data` object with updated `@datanames`. #' #' @examples #' td <- teal_data(iris = iris) #' td <- within(td, mtcars <- mtcars) #' datanames(td) +#' #' datanames(td) <- c("iris", "mtcars") +#' datanames(td) #' #' @name datanames #' @aliases datanames,teal_data-method diff --git a/R/teal_data-get_code.R b/R/teal_data-get_code.R index bd9878100..2e8e9914c 100644 --- a/R/teal_data-get_code.R +++ b/R/teal_data-get_code.R @@ -1,4 +1,4 @@ -#' Get Code from `teal_data` +#' Get code from `teal_data` object #' #' Retrieve code from `teal_data` object. #' @@ -14,8 +14,10 @@ #' @param datanames `r lifecycle::badge("experimental")` (`character`) vector of data set names to return the code for. #' @param deparse (`logical`) flag specifying whether to return code as `character` (`deparse = TRUE`) or as #' `expression` (`deparse = FALSE`). +#' #' @return #' Either string or an expression representing code used to create the requested data sets. +#' #' @examples #' #' tdata1 <- teal_data() diff --git a/R/teal_data-show.R b/R/teal_data-show.R index ad175954b..540214671 100644 --- a/R/teal_data-show.R +++ b/R/teal_data-show.R @@ -1,6 +1,6 @@ #' Show `teal_data` object #' -#' Prints `teal_data` object +#' Prints `teal_data` object. #' @param object (`teal_data`) #' @return Input `teal_data` object. #' @importFrom methods show diff --git a/R/teal_data.R b/R/teal_data.R index f9cbacaf8..2a9191c7c 100644 --- a/R/teal_data.R +++ b/R/teal_data.R @@ -1,12 +1,10 @@ -#' Teal Data +#' Comprehensive data integration function for `teal` applications #' #' @description `r lifecycle::badge("stable")` #' Universal function to pass data to teal application. #' -#' @param ... (`TealDataConnector`, `TealDataset`, `TealDatasetConnector`, `any`)\cr -#' Either 1) an object of a `Teal*` class, which is deprecated and will be removed in next release, -#' or 2) any number of any objects provided as `name = value` pairs, which is available from version `0.4.0`. -#' @param join_keys (`join_keys`) or a single (`join_key_set`)\cr +#' @param ... any number of objects (presumably data objects) provided as `name = value` pairs. +#' @param join_keys (`join_keys`) object or a single (`join_key_set`) object\cr #' (optional) object with dataset column relationships used for joining. #' If empty then no joins between pairs of objects #' @param code (`character`, `language`) code to reproduce the datasets. @@ -14,9 +12,7 @@ #' code included in the object definitions actually produces those objects. #' If `check` is true and preprocessing code is empty an error will be thrown. #' -#' @return -#' If old data classes are provided (`TealDataset` `TealDatasetConnector`, `TealDataConnector`), a `TealData` object. -#' Otherwise a `teal_data` object. +#' @return A `teal_data` object. #' #' @export #' diff --git a/R/testhat-helpers.R b/R/testhat-helpers.R index 46e5ec1e2..569fbfb62 100644 --- a/R/testhat-helpers.R +++ b/R/testhat-helpers.R @@ -1,11 +1,11 @@ -#' Test if Two Objects are (Nearly) Equal +#' Test if two objects are (nearly) equal #' #' `all.equal(target, current)` is a utility to compare `join_keys` objects target #' and current testing `near equality`. #' #' If they are different, comparison is still made to some extent, and a report #' of the differences is returned. -#' Do not use all.equal directly in if expressions—either use `isTRUE(all.equal(....))` +#' Do not use `all.equal` directly in if expressions—either use `isTRUE(all.equal(....))` #' or identical if appropriate. #' #' @inheritParams base::all.equal diff --git a/R/topological_sort.R b/R/topological_sort.R index 12be4caa1..413878373 100644 --- a/R/topological_sort.R +++ b/R/topological_sort.R @@ -1,17 +1,12 @@ #' Topological graph sort #' -#' Graph is a list which for each node contains a vector of child nodes +#' Graph is a `list` which for each node contains a vector of child nodes #' in the returned list, parents appear before their children. #' #' Implementation of `Kahn` algorithm with a modification to maintain the order of input elements. #' -#' @param graph (named `list`) list with node vector elements +#' @param graph (`named list`) with node vector elements #' @keywords internal -#' -#' @examples -#' teal.data:::topological_sort(list(A = c(), B = c("A"), C = c("B"), D = c("A"))) -#' teal.data:::topological_sort(list(D = c("A"), A = c(), B = c("A"), C = c("B"))) -#' teal.data:::topological_sort(list(D = c("A"), B = c("A"), C = c("B"), A = c())) topological_sort <- function(graph) { # compute in-degrees in_degrees <- list() diff --git a/R/utils-get_code_dependency.R b/R/utils-get_code_dependency.R index 25e981266..647c67f7c 100644 --- a/R/utils-get_code_dependency.R +++ b/R/utils-get_code_dependency.R @@ -1,6 +1,6 @@ # get_code_dependency ---- -#' Get Code Dependency of an Object +#' Get code dependency of an object #' #' Extract subset of code required to reproduce specific object(s), including code producing side-effects. #' @@ -70,6 +70,8 @@ extract_calls <- function(pd) { fix_comments(calls) } +#' @keywords internal +#' @noRd get_children <- function(pd, parent) { idx_children <- abs(pd$parent) == parent children <- pd[idx_children, c("token", "text", "id", "parent")] @@ -82,6 +84,8 @@ get_children <- function(pd, parent) { } } +#' @keywords internal +#' @noRd fix_comments <- function(calls) { # If the first token is a COMMENT, then it belongs to the previous call. if (length(calls) >= 2) { @@ -97,7 +101,7 @@ fix_comments <- function(calls) { # code_graph ---- -#' Create Object Dependencies Graph Within Parsed Code +#' Create object dependencies graph within parsed code #' #' @description #' Builds dependency graph that identifies dependencies between objects in parsed code. @@ -125,7 +129,7 @@ code_graph <- function(calls_pd) { mapply(function(x, y) unique(c(x, y)), side_effects, cooccurrence, SIMPLIFY = FALSE) } -#' Extract Object Occurrence +#' Extract object occurrence #' #' @description Extracts objects occurrence within calls passed by `calls_pd`. #' Also detects which objects depend on which within a call. @@ -206,7 +210,7 @@ extract_occurrence <- function(calls_pd) { ) } -#' Extract Side Effects +#' Extract side effects #' #' @description Extracts all object names from the code that are marked with `@linksto` tag. #' @@ -277,7 +281,7 @@ graph_parser <- function(x, graph) { # default_side_effects -------------------------------------------------------------------------------------------- -#' Detect Library Calls +#' Detect library calls #' #' Detects `library()` and `require()` function calls. #' diff --git a/R/verify.R b/R/verify.R index ad54cfc69..cfc1618a5 100644 --- a/R/verify.R +++ b/R/verify.R @@ -1,6 +1,6 @@ -#' Verify Code Reproducibility +#' Verify code reproducibility #' -#' Checks whether code in `teal_data` reproduces the stored objects. +#' Checks whether code in `teal_data` object reproduces the stored objects. #' #' If objects created by code in the `@code` slot of `x` are `all_equal` to the contents of the `@env` slot, #' the function updates the `@verified` slot to `TRUE` in the returned `teal_data` object. Once verified, the slot @@ -24,12 +24,11 @@ #' verify(tdata2)@verified #' tdata2@verified #' -#' \dontrun{ #' tdata3 <- teal_data() #' tdata3 <- within(tdata3, { #' stop("error") #' }) -#' verify(tdata3) +#' try(verify(tdata3)) # fails #' #' #' a <- 1 @@ -38,17 +37,13 @@ #' d <- 5 #' tdata4 <- teal_data( #' a = a, b = b, c = c, d = d, -#' code = -#' " -#' a <- 1 -#' b <- a -#' c <- list(x = 2) -#' e <- 1 -#' " +#' code = "a <- 1 +#' b <- a +#' c <- list(x = 2) +#' e <- 1" #' ) #' tdata4 -#' verify(tdata4) -#' } +#' try(verify(tdata4)) # fails #' #' @name verify #' @rdname verify diff --git a/README.md b/README.md index a0c6040c4..c91d3bbc4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ # teal.data +[![CRAN Version](https://www.r-pkg.org/badges/version/teal.data?color=green)](https://cran.r-project.org/package=teal.data) +[![Total Downloads](http://cranlogs.r-pkg.org/badges/grand-total/teal.data?color=green)](https://cran.r-project.org/package=teal.data) +[![Last Month Downloads](http://cranlogs.r-pkg.org/badges/last-month/teal.data?color=green)](https://cran.r-project.org/package=teal.data) +[![Last Week Downloads](http://cranlogs.r-pkg.org/badges/last-week/teal.data?color=green)](https://cran.r-project.org/package=teal.data) + [![Check 🛠](https://github.com/insightsengineering/teal.data/actions/workflows/check.yaml/badge.svg)](https://insightsengineering.github.io/teal.data/main/unit-test-report/) [![Docs 📚](https://github.com/insightsengineering/teal.data/actions/workflows/docs.yaml/badge.svg)](https://insightsengineering.github.io/teal.data/) [![Code Coverage 📔](https://raw.githubusercontent.com/insightsengineering/teal.data/_xml_coverage_reports/data/main/badge.svg)](https://insightsengineering.github.io/teal.data/main/coverage-report/) @@ -36,7 +41,7 @@ This package provides: ```r # stable versions -install.packages('teal.data', repos = c('https://insightsengineering.r-universe.dev', getOption('repos'))) +install.packages('teal.data') # install.packages("pak") pak::pak("insightsengineering/teal.data@*release") @@ -64,41 +69,54 @@ library(teal.data) ```r # quick start for clinical trial data -adsl <- teal.data::example_cdisc_data("ADSL") -adtte <- teal.data::example_cdisc_data("ADTTE") - my_data <- cdisc_data( - cdisc_dataset("ADSL", adsl), - cdisc_dataset("ADTTE", adtte) + ADSL = example_cdisc_data("ADSL"), + ADTTE = example_cdisc_data("ADTTE"), + code = quote({ + ADSL <- example_cdisc_data("ADSL") + ADTTE <- example_cdisc_data("ADTTE") + }) ) + +# or + +my_data <- within(teal_data(), { + ADSL <- example_cdisc_data("ADSL") + ADTTE <- example_cdisc_data("ADTTE") +}) +datanames <- c("ADSL", "ADTTE") +datanames(my_data) <- datanames +join_keys(my_data) <- default_cdisc_join_keys[datanames] ``` ```r # quick start for general data -my_general_data <- teal_data( - dataset("iris", iris), - dataset("mtcars", mtcars) -) +my_general_data <- within(teal_data(), { + iris <- iris + mtcars <- mtcars +}) ``` ```r # reproducibility check -data <- teal_data(dataset("iris", iris, code = "iris <- mtcars"), check = TRUE) -#> Error in x$check_reproducibility() : Reproducibility check failed. +data <- teal_data(iris = iris, code = "iris <- mtcars") +verify(data) +#> Error: Code verification failed. +#> Object(s) recreated with code that have different structure in data: +#> • iris ``` ```r # code extraction -iris2 <- iris[1:6, ] -iris2_data <- teal_data(dataset("iris2", iris2, code = "iris2 <- iris[1:6, ]")) -iris2_data$get_code() +iris2_data <- within(teal_data(), {iris2 <- iris[1:6, ]}) +get_code(iris2_data) #> "iris2 <- iris[1:6, ]" ``` ## Getting help -If you encounter a bug or you have a feature request - please file an issue. For questions, discussions and staying up to date, please use the "teal" channel in the [`pharmaverse` slack workspace](https://pharmaverse.slack.com). +If you encounter a bug or have a feature request, please file an issue. For questions, discussions, and staying up to date, please use the `teal` channel in the [`pharmaverse` slack workspace](https://pharmaverse.slack.com). ## Stargazers and Forkers diff --git a/_pkgdown.yml b/_pkgdown.yml index a39a66c65..c2006a2be 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -21,8 +21,8 @@ navbar: href: https://github.com/insightsengineering/teal.data articles: - - title: Getting Started - navbar: Getting Started + - title: Get started + navbar: Get started contents: - teal-data - teal-data-reproducibility @@ -36,7 +36,6 @@ reference: - datanames - datanames<- - get_code,teal_data-method - - get_join_keys - join_key - join_keys - join_keys<- @@ -54,7 +53,7 @@ reference: - col_labels<- - col_relabel - example_cdisc_data - - title: Deprecated functions and methods - desc: Functions deprecated in teal.data v0.3.1 + - title: Deprecated contents: - TealData + - get_labels diff --git a/man/TealData.Rd b/man/TealData.Rd index 158f413f2..a8a1c174f 100644 --- a/man/TealData.Rd +++ b/man/TealData.Rd @@ -51,6 +51,8 @@ \alias{get_cdisc_keys} \alias{cdisc_data_file} \alias{teal_data_file} +\alias{get_join_keys} +\alias{get_join_keys<-} \title{Deprecated \code{TealData} class and related functions} \usage{ as_cdisc(...) @@ -150,15 +152,24 @@ get_cdisc_keys(...) cdisc_data_file(...) teal_data_file(...) + +get_join_keys(...) + +get_join_keys(...) <- value } \arguments{ \item{...}{any argument supported in \code{TealData} related functions.} + +\item{value}{value to assign} } \value{ nothing } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}}\cr -This function has been deprecated. Please see \code{\link[=teal_data]{teal_data()}} and \code{\link[=cdisc_data]{cdisc_data()}} instead. -Find more information on \href{https://github.com/insightsengineering/teal/discussions/945}{Migration guide}. +The \code{TealData} class and associated functions have been deprecated. Use \code{\link[=teal_data]{teal_data()}} instead. +See the \href{https://github.com/insightsengineering/teal/discussions/945}{Migration guide} for details. +} +\seealso{ +\code{\link[=cdisc_data]{cdisc_data()}} , \code{\link[=join_keys]{join_keys()}} } diff --git a/man/all.equal.join_keys.Rd b/man/all.equal.join_keys.Rd index fb68b3941..813654397 100644 --- a/man/all.equal.join_keys.Rd +++ b/man/all.equal.join_keys.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/testhat-helpers.R \name{all.equal.join_keys} \alias{all.equal.join_keys} -\title{Test if Two Objects are (Nearly) Equal} +\title{Test if two objects are (nearly) equal} \usage{ \method{all}{equal.join_keys}(target, current, ...) } @@ -20,7 +20,7 @@ and current testing \verb{near equality}. \details{ If they are different, comparison is still made to some extent, and a report of the differences is returned. -Do not use all.equal directly in if expressions—either use \code{isTRUE(all.equal(....))} +Do not use \code{all.equal} directly in if expressions—either use \code{isTRUE(all.equal(....))} or identical if appropriate. The parents attribute comparison tolerates \code{NULL} and empty lists and will find diff --git a/man/assert_compatible_keys.Rd b/man/assert_compatible_keys.Rd index 1ede2e575..18ae8baaa 100644 --- a/man/assert_compatible_keys.Rd +++ b/man/assert_compatible_keys.Rd @@ -6,7 +6,10 @@ \usage{ assert_compatible_keys(join_key_1, join_key_2) } +\value{ +Returns \code{TRUE} if successful, otherwise raises error. +} \description{ -return TRUE if compatible, throw error otherwise +Helper function to assert if two key sets contain incompatible keys } \keyword{internal} diff --git a/man/assert_compatible_keys2.Rd b/man/assert_compatible_keys2.Rd new file mode 100644 index 000000000..b546d0127 --- /dev/null +++ b/man/assert_compatible_keys2.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/join_keys-utils.R +\name{assert_compatible_keys2} +\alias{assert_compatible_keys2} +\title{Helper function to ensuring compatibility between two sets of keys} +\usage{ +assert_compatible_keys2(x, y) +} +\value{ +Returns \code{TRUE} if successful, otherwise raises error. +} +\description{ +Helper function to ensuring compatibility between two sets of keys +} +\keyword{internal} diff --git a/man/cdisc_data.Rd b/man/cdisc_data.Rd index 15d5afcf2..47c502206 100644 --- a/man/cdisc_data.Rd +++ b/man/cdisc_data.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/cdisc_data.R \name{cdisc_data} \alias{cdisc_data} -\title{Data input for teal app} +\title{Data input for \code{teal} app} \usage{ cdisc_data( ..., @@ -12,11 +12,9 @@ cdisc_data( ) } \arguments{ -\item{...}{(\code{TealDataConnector}, \code{TealDataset}, \code{TealDatasetConnector}, \code{any})\cr -Either 1) an object of a \verb{Teal*} class, which is deprecated and will be removed in next release, -or 2) any number of any objects provided as \code{name = value} pairs, which is available from version \verb{0.4.0}.} +\item{...}{any number of objects (presumably data objects) provided as \code{name = value} pairs.} -\item{join_keys}{(\code{join_keys}) or a single (\code{join_key_set})\cr +\item{join_keys}{(\code{join_keys}) object or a single (\code{join_key_set}) object\cr (optional) object with datasets column names used for joining. If empty then it would be automatically derived basing on intersection of datasets primary keys. For ADAM datasets it would be automatically derived.} @@ -28,10 +26,7 @@ code included in the object definitions actually produces those objects. If \code{check} is true and preprocessing code is empty an error will be thrown.} } \value{ -\itemize{ -\item a \code{TealData} object when \code{TealDataset} \code{TealDatasetConnector}, \code{TealDataConnector} is provided, -\item a \code{teal_data} object otherwise. -} +A \code{teal_data} object. } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} @@ -49,8 +44,8 @@ data <- cdisc_data( ) data <- within(data, { - ADSL <- teal.data::example_cdisc_data("ADSL") - ADTTE <- teal.data::example_cdisc_data("ADTTE") + ADSL <- example_cdisc_data("ADSL") + ADTTE <- example_cdisc_data("ADTTE") }) } diff --git a/man/col_labels-set.Rd b/man/col_labels-set.Rd deleted file mode 100644 index 0de07aed1..000000000 --- a/man/col_labels-set.Rd +++ /dev/null @@ -1,38 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/formatters_var_labels.R -\name{col_labels<-} -\alias{col_labels<-} -\title{Set Label Attributes of All Variables in a \code{data.frame}} -\source{ -This function was taken 1-1 from -\href{https://cran.r-project.org/package=formatters}{formatters} package, to reduce the complexity of -the dependency tree. -} -\usage{ -col_labels(x) <- value -} -\arguments{ -\item{x}{a \code{data.frame} object} - -\item{value}{new variable labels, \code{NA} removes the variable label} -} -\value{ -modifies the variable labels of \code{x} -} -\description{ -Variable labels can be stored as a \code{label} attribute for each variable. -This functions sets all non-missing (non-NA) variable labels in a \code{data.frame} -} -\examples{ -x <- iris -col_labels(x) -col_labels(x) <- paste("label for", names(iris)) -col_labels(x) - -if (interactive()) { - View(x) # in RStudio data viewer labels are displayed -} -} -\seealso{ -\code{\link[=col_labels]{col_labels()}} \code{\link[=col_relabel]{col_relabel()}} -} diff --git a/man/col_labels.Rd b/man/col_labels.Rd index efa9fc052..5c68df2bc 100644 --- a/man/col_labels.Rd +++ b/man/col_labels.Rd @@ -1,42 +1,60 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/deprecated.R, R/formatters_var_labels.R -\name{get_labels} -\alias{get_labels} +% Please edit documentation in R/formatters_var_labels.R, R/deprecated.R +\name{col_labels} \alias{col_labels} -\title{Get Label Attributes of Variables in a \code{data.frame}} +\alias{col_labels<-} +\alias{col_relabel} +\alias{get_labels} +\title{Variable labels} \source{ -This function was taken 1-1 from +These functions were taken from \href{https://cran.r-project.org/package=formatters}{formatters} package, to reduce the complexity of -the dependency tree. +the dependency tree and rewritten. } \usage{ -get_labels(data, fill = TRUE) - col_labels(x, fill = FALSE) + +col_labels(x) <- value + +col_relabel(x, ...) + +get_labels(...) } \arguments{ -\item{data}{a data.frame object} +\item{x}{(\code{data.frame} or \code{DataFrame}) data object} -\item{fill}{boolean in case the \code{label} attribute does not exist if -\code{TRUE} the variable names is returned, otherwise \code{NA}} +\item{fill}{(\code{logical(1)}) specifying what to return if variable has no label} -\item{x}{a \code{data.frame} object} +\item{value}{(\code{character}) vector of variable labels of length equal to number of columns in \code{x}; +if named, names must match variable names in \code{x} and will be used as key to set labels; +use \code{NA} to remove label from variable} + +\item{...}{name-value pairs, where name corresponds to a variable name in \code{x} +and value is the new variable label} } \value{ -a named character vector with the variable labels, the names -correspond to the variable names +For \code{col_labels}, named character vector of variable labels, the names being the corresponding variable names. +If the \code{label} attribute is missing, the vector elements will be +the variable names themselves if \code{fill = TRUE} and \code{NA} if \code{fill = FALSE}.\cr +For \verb{col_labels<-} and \code{col_relabel}, copy of \code{x} with variable labels modified. } \description{ -Variable labels can be stored as a \code{label} attribute for each variable. -This functions returns a named character vector with the variable labels -(empty sting if not specified) +Get or set variable labels in a \code{data.frame}. +} +\details{ +Variable labels can be stored as a \code{label} attribute set on individual variables. +These functions get or set this attribute, either on all (\code{col_labels}) or some variables (\code{col_relabel}). + +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}}\cr +In previous versions of \code{teal.data} labels were managed with \code{get_labels()}. +This function is deprecated as of \verb{0.3.1}, use \code{col_labels} instead. } \examples{ x <- iris col_labels(x) col_labels(x) <- paste("label for", names(iris)) col_labels(x) -} -\seealso{ -\code{\link[=col_relabel]{col_relabel()}} \code{\link{col_labels<-}} +y <- col_relabel(x, Sepal.Length = "Sepal Length of iris flower") +col_labels(y) + } diff --git a/man/col_relabel.Rd b/man/col_relabel.Rd deleted file mode 100644 index d454a9c11..000000000 --- a/man/col_relabel.Rd +++ /dev/null @@ -1,33 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/formatters_var_labels.R -\name{col_relabel} -\alias{col_relabel} -\title{Copy and Change Variable Labels of a \code{data.frame}} -\source{ -This function was taken 1-1 from -\href{https://cran.r-project.org/package=formatters}{formatters} package, to reduce the complexity of -the dependency tree. -} -\usage{ -col_relabel(x, ...) -} -\arguments{ -\item{x}{a \code{data.frame} object} - -\item{...}{name-value pairs, where name corresponds to a variable name in -\code{x} and the value to the new variable label} -} -\value{ -a copy of \code{x} with changed labels according to \code{...} -} -\description{ -Relabel a subset of the variables -} -\examples{ -x <- col_relabel(iris, Sepal.Length = "Sepal Length of iris flower") -col_labels(x) - -} -\seealso{ -\code{\link[=col_labels]{col_labels()}} \code{\link{col_labels<-}} -} diff --git a/man/datanames.Rd b/man/datanames.Rd index 013dae456..4908979a2 100644 --- a/man/datanames.Rd +++ b/man/datanames.Rd @@ -7,7 +7,7 @@ \alias{datanames,qenv.error-method} \alias{datanames<-,qenv.error,character-method} \alias{datanames<-} -\title{Names of Data Sets in \code{teal_data} Object} +\title{Names of data sets in \code{teal_data} object} \usage{ datanames(x) @@ -19,7 +19,7 @@ datanames(x) <- value \item{value}{(\code{character}) new value for \verb{@datanames}; all elements must be names of variables existing in \verb{@env}} } \value{ -The contents of \verb{@datanames} or \code{teal_data} with updated \verb{@datanames}. +The contents of \verb{@datanames} or \code{teal_data} object with updated \verb{@datanames}. } \description{ Get or set the value of the \code{datanames} slot. @@ -35,6 +35,8 @@ Use this function to update the slot. td <- teal_data(iris = iris) td <- within(td, mtcars <- mtcars) datanames(td) + datanames(td) <- c("iris", "mtcars") +datanames(td) } diff --git a/man/default_cdisc_join_keys.Rd b/man/default_cdisc_join_keys.Rd index da8539e1f..29364fbed 100644 --- a/man/default_cdisc_join_keys.Rd +++ b/man/default_cdisc_join_keys.Rd @@ -3,9 +3,9 @@ \docType{data} \name{default_cdisc_join_keys} \alias{default_cdisc_join_keys} -\title{List containing the default \code{CDISC} join keys} +\title{List containing default joining keys for \code{CDISC} datasets} \description{ -List containing the default \code{CDISC} join keys +List containing default joining keys for \code{CDISC} datasets } \details{ This data object is created at loading time from \code{cdisc_datasets/cdisc_datasets.yaml}. diff --git a/man/example_cdisc_data.Rd b/man/example_cdisc_data.Rd index 4af27596a..743f1e4c5 100644 --- a/man/example_cdisc_data.Rd +++ b/man/example_cdisc_data.Rd @@ -2,21 +2,22 @@ % Please edit documentation in R/dummy_function.R \name{example_cdisc_data} \alias{example_cdisc_data} -\title{This function returns a dummy dataset for testing examples and should only be used within \code{teal.data}.} +\title{Generate sample \code{CDISC} datasets} \usage{ -example_cdisc_data(dataname) +example_cdisc_data( + dataname = c("ADSL", "ADAE", "ADLB", "ADCM", "ADEX", "ADRS", "ADTR", "ADTTE", "ADVS") +) } \arguments{ -\item{dataname}{name of the \code{CDISC} dataset} +\item{dataname}{(\code{character(1)}) name of a \code{CDISC} dataset} } \value{ -\code{cdisc_data} +A \code{CDISC} dataset as a \code{data.frame}. } \description{ -It is not meant to retrieve the \code{SCDA} dataset, and the dataset itself is not maintained here. +Retrieves example \code{CDISC} datasets for use in examples and testing. } \details{ -This function creates a copy of the \code{SCDA} data for testing purposes. - -\code{CDISC} data includes \code{ADSL}, \code{ADAE}, \code{ADLB}, \code{ADCM}, \code{ADEX}, \code{ADRS}, \code{ADTR} and \code{ADTTE}. +This function returns a dummy dataset and should only be used within \code{teal.data}. +Note that the datasets are not created and maintained in \code{teal.data}, they are retrieved its dependencies. } diff --git a/man/get_code-teal_data-method.Rd b/man/get_code-teal_data-method.Rd index 4500b0963..1d56aaf83 100644 --- a/man/get_code-teal_data-method.Rd +++ b/man/get_code-teal_data-method.Rd @@ -3,7 +3,7 @@ \name{get_code,teal_data-method} \alias{get_code,teal_data-method} \alias{get_code} -\title{Get Code from \code{teal_data}} +\title{Get code from \code{teal_data} object} \usage{ \S4method{get_code}{teal_data}(object, deparse = TRUE, datanames = NULL) } diff --git a/man/get_code_dependency.Rd b/man/get_code_dependency.Rd index e3591a556..8db40903d 100644 --- a/man/get_code_dependency.Rd +++ b/man/get_code_dependency.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/utils-get_code_dependency.R \name{get_code_dependency} \alias{get_code_dependency} -\title{Get Code Dependency of an Object} +\title{Get code dependency of an object} \usage{ get_code_dependency(code, names, check_names = TRUE) } diff --git a/man/get_join_keys.Rd b/man/get_join_keys.Rd deleted file mode 100644 index 70449feb1..000000000 --- a/man/get_join_keys.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/deprecated.R -\name{get_join_keys} -\alias{get_join_keys} -\alias{get_join_keys<-} -\title{Function to get join keys from a `` object} -\usage{ -get_join_keys(data) - -get_join_keys(data, dataset_1, dataset_2 = NULL) <- value -} -\arguments{ -\item{data}{`` - object to extract the join keys} - -\item{dataset_1, dataset_2}{(\code{character(1)}) Dataset names. When \code{dataset_2} is omitted, -a primary key for \code{dataset_1} is created.} - -\item{value}{value to assign} -} -\value{ -Either \code{join_keys} object or \code{NULL} if no join keys -} -\description{ -Function to get join keys from a `` object -} diff --git a/man/is_dag.Rd b/man/is_dag.Rd index eecadb5c8..21887c8c0 100644 --- a/man/is_dag.Rd +++ b/man/is_dag.Rd @@ -7,7 +7,7 @@ is_dag(graph) } \arguments{ -\item{graph}{(named \code{list}) list with node vector elements} +\item{graph}{(\verb{named list}) with node vector elements} } \value{ \code{logical(1)} \code{TRUE} if the graph is a \code{DAG}; \code{FALSE} otherwise diff --git a/man/join_keys.Rd b/man/join_keys.Rd index c3c2bde37..61488ebd6 100644 --- a/man/join_keys.Rd +++ b/man/join_keys.Rd @@ -46,7 +46,7 @@ join_keys(x) <- value } \arguments{ \item{...}{(optional)\cr -either \code{teal_data} or \code{join_keys} to extract \code{join_keys}, \cr +either \code{teal_data} or \code{join_keys} object to extract \code{join_keys}, \cr or any number of \code{join_key_set} objects to create \code{join_keys}, \cr or nothing to create an empty \code{join_keys}} @@ -91,7 +91,7 @@ in a parent-child relationship and the mapping is automatically mirrored between \itemize{ \item \code{join_keys()}: Returns an empty \code{join_keys} object when called without arguments. \item \code{join_keys(join_keys)}: Returns itself. -\item \code{join_keys(teal_data)}: Returns the \code{join_keys} object contained in \code{teal_data}. +\item \code{join_keys(teal_data)}: Returns the \code{join_keys} object contained in \code{teal_data} object. \item \code{join_keys(...)}: Creates a new object with one or more \code{join_key_set} parameters. } } @@ -112,7 +112,7 @@ including implicit keys inferred from their relationship with a parent. \item \code{x[i] <- value}: This (without \code{j} parameter) \strong{is not} a supported operation for \code{join_keys}. \item \code{join_keys(x)[i, j] <- value}: Assignment to \code{join_keys} object stored in \code{x}, -such as a \code{teal_data} or \code{join_keys} itself. +such as a \code{teal_data} object or \code{join_keys} object itself. } @@ -158,7 +158,7 @@ jk["ds1", "ds4"] <- c("pk1" = "pk4") jk["ds5", "ds5"] <- NULL -# Merging multiple `join_keys` --- +# Merging multiple `join_keys` objects --- jk_merged <- c( jk, diff --git a/man/names-set-.join_keys.Rd b/man/names-set-.join_keys.Rd index 4d276845f..ddcf09ecf 100644 --- a/man/names-set-.join_keys.Rd +++ b/man/names-set-.join_keys.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/join_keys-names.R \name{names<-.join_keys} \alias{names<-.join_keys} -\title{The Names of an \code{join_keys} Object} +\title{The names of a \code{join_keys} object} \usage{ \method{names}{join_keys}(x) <- value } @@ -13,5 +13,5 @@ \code{NULL}.} } \description{ -The Names of an \code{join_keys} Object +The names of a \code{join_keys} object } diff --git a/man/new_teal_data.Rd b/man/new_teal_data.Rd index 5b1557ec2..2f8d24b75 100644 --- a/man/new_teal_data.Rd +++ b/man/new_teal_data.Rd @@ -12,7 +12,7 @@ new_teal_data( ) } \arguments{ -\item{data}{(\verb{named list}) List of data.} +\item{data}{(\verb{named list}) of data objects.} \item{code}{(\code{character} or \code{language}) code to reproduce the \code{data}. Accepts and stores comments also.} diff --git a/man/parents.Rd b/man/parents.Rd index ace27bd46..0d9846564 100644 --- a/man/parents.Rd +++ b/man/parents.Rd @@ -8,7 +8,7 @@ \alias{parents<-.join_keys} \alias{parents<-.teal_data} \alias{parent} -\title{Getter and setter functions for parents attribute of \code{join_keys}} +\title{Get and set parents in \code{join_keys} object} \usage{ parents(x) @@ -33,7 +33,7 @@ to retrieve or manipulate.} \item{dataset_name}{(\code{character(1)}) Name of dataset to query on their parent.} } \value{ -a list of \code{character} representing the parents. +a \code{list} of \code{character} representing the parents. For \code{parent(x, dataset_name)} returns \code{NULL} if parent does not exist. } @@ -41,7 +41,7 @@ For \code{parent(x, dataset_name)} returns \code{NULL} if parent does not exist. \code{parents()} facilitates the creation of dependencies between datasets by assigning a parent-child relationship. -Each element is defined by a list element, where \code{list("child" = "parent")}. +Each element is defined by a \code{list} element, where \code{list("child" = "parent")}. } \section{Methods (by class)}{ \itemize{ @@ -58,7 +58,7 @@ Each element is defined by a list element, where \code{list("child" = "parent")} \item \code{parents(teal_data) <- value}: Assignment of parents of \code{join_keys} inside \code{teal_data} object. -\item \code{parent()}: Getter for individual parent +\item \code{parent()}: Getter for individual parent. }} \examples{ @@ -70,14 +70,14 @@ parents(jk) # Get parents of join_keys inside teal_data object --- td <- teal_data( - ADSL = teal.data::rADSL, - ADTTE = teal.data::rADTTE, - ADRS = teal.data::rADRS, + ADSL = rADSL, + ADTTE = rADTTE, + ADRS = rADRS, join_keys = default_cdisc_join_keys[c("ADSL", "ADTTE", "ADRS")] ) parents(td) -# Assigment of parents --- +# Assignment of parents --- jk <- join_keys( join_key("ds1", "ds2", "id"), @@ -92,7 +92,7 @@ parents(jk) <- list(ds2 = "ds1") parents(jk)["ds6"] <- "ds5" parents(jk)["ds7"] <- "ds6" -# Assigment of parents of join_keys inside teal_data object --- +# Assignment of parents of join_keys inside teal_data object --- parents(td) <- list("ADTTE" = "ADSL") # replace existing parents(td)["ADRS"] <- "ADSL" # add new parent diff --git a/man/rADAE.Rd b/man/rADAE.Rd index 6e57b7d7a..b8bbb3254 100644 --- a/man/rADAE.Rd +++ b/man/rADAE.Rd @@ -14,7 +14,7 @@ internal rADAE } \description{ -Random adverse events +Random adverse events. } \keyword{datasets} \keyword{internal} diff --git a/man/rADCM.Rd b/man/rADCM.Rd index edab43251..f1a15141e 100644 --- a/man/rADCM.Rd +++ b/man/rADCM.Rd @@ -3,7 +3,7 @@ \docType{data} \name{rADCM} \alias{rADCM} -\title{Random Concomitant Medications} +\title{Random concomitant medications} \format{ An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 3685 rows and 83 columns. } @@ -14,7 +14,7 @@ internal rADCM } \description{ -Random Concomitant Medications +Random concomitant medications. } \keyword{datasets} \keyword{internal} diff --git a/man/rADEX.Rd b/man/rADEX.Rd index 8c2475850..dbffbce48 100644 --- a/man/rADEX.Rd +++ b/man/rADEX.Rd @@ -14,7 +14,7 @@ internal rADEX } \description{ -Random Exposure +Random exposure. } \keyword{datasets} \keyword{internal} diff --git a/man/rADLB.Rd b/man/rADLB.Rd index a5430d325..0c30df9b8 100644 --- a/man/rADLB.Rd +++ b/man/rADLB.Rd @@ -14,7 +14,7 @@ internal rADLB } \description{ -Random lab analysis +Random lab analysis. } \keyword{datasets} \keyword{internal} diff --git a/man/rADRS.Rd b/man/rADRS.Rd index b25c99888..fedada780 100644 --- a/man/rADRS.Rd +++ b/man/rADRS.Rd @@ -14,7 +14,7 @@ internal rADRS } \description{ -Random response +Random response. } \keyword{datasets} \keyword{internal} diff --git a/man/rADSL.Rd b/man/rADSL.Rd index 1b09ee22a..a04ad5f6c 100644 --- a/man/rADSL.Rd +++ b/man/rADSL.Rd @@ -14,7 +14,7 @@ internal rADSL } \description{ -Random patient listing +Random patient listing. } \keyword{datasets} \keyword{internal} diff --git a/man/rADTR.Rd b/man/rADTR.Rd index 176308a02..f888e52ea 100644 --- a/man/rADTR.Rd +++ b/man/rADTR.Rd @@ -14,7 +14,7 @@ internal rADTR } \description{ -Random data \code{rADTR} +Random data \code{rADTR}. } \keyword{datasets} \keyword{internal} diff --git a/man/rADTTE.Rd b/man/rADTTE.Rd index 56d859833..961b0172a 100644 --- a/man/rADTTE.Rd +++ b/man/rADTTE.Rd @@ -3,7 +3,7 @@ \docType{data} \name{rADTTE} \alias{rADTTE} -\title{Random Time to Event Analysis Dataset} +\title{Random time to event analysis dataset} \format{ An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 2000 rows and 67 columns. } @@ -14,7 +14,7 @@ internal rADTTE } \description{ -Random Time to Event Analysis Dataset +Random time to event analysis dataset. } \keyword{datasets} \keyword{internal} diff --git a/man/rADVS.Rd b/man/rADVS.Rd index a567f538d..8957d03b3 100644 --- a/man/rADVS.Rd +++ b/man/rADVS.Rd @@ -14,7 +14,7 @@ internal rADVS } \description{ -Random data \code{rADVS} +Random data \code{rADVS}. } \keyword{datasets} \keyword{internal} diff --git a/man/show-teal_data-method.Rd b/man/show-teal_data-method.Rd index be52b21bf..ec86e67df 100644 --- a/man/show-teal_data-method.Rd +++ b/man/show-teal_data-method.Rd @@ -13,7 +13,7 @@ Input \code{teal_data} object. } \description{ -Prints \code{teal_data} object +Prints \code{teal_data} object. } \examples{ teal_data() diff --git a/man/teal.data-package.Rd b/man/teal.data-package.Rd index c012325bf..5aa95a20e 100644 --- a/man/teal.data-package.Rd +++ b/man/teal.data-package.Rd @@ -4,7 +4,7 @@ \name{teal.data-package} \alias{teal.data} \alias{teal.data-package} -\title{teal.data: Reproducible data model for \code{teal} applications} +\title{\code{teal.data}: Reproducible data model for \code{teal} applications} \description{ This package extends \code{teal} applications by module which stores the data with they relationships (keys) and reproducible @@ -25,6 +25,9 @@ Useful links: Authors: \itemize{ + \item Aleksander Chlebowski \email{aleksander.chlebowski@contractors.roche.com} + \item Marcin Kosinski \email{marcin.kosinski.mk1@roche.com} + \item Andre Verissimo \email{andre.verissimo@roche.com} \item Pawel Rucki \email{pawel.rucki@roche.com} \item Mahmoud Hallal \email{mahmoud.hallal@roche.com} \item Nikolas Burkoff @@ -35,6 +38,8 @@ Authors: Other contributors: \itemize{ + \item Chendi Liao \email{chendi.liao@roche.com} [reviewer] + \item Dony Unardi \email{unardid@gene.com} [reviewer] \item F. Hoffmann-La Roche AG [copyright holder, funder] } diff --git a/man/teal_data-class.Rd b/man/teal_data-class.Rd index 38b6c9a45..ef1c1decb 100644 --- a/man/teal_data-class.Rd +++ b/man/teal_data-class.Rd @@ -3,7 +3,7 @@ \docType{class} \name{teal_data-class} \alias{teal_data-class} -\title{Reproducible data.} +\title{Reproducible data} \description{ Reproducible data container class. Inherits code tracking behavior from \code{\link[teal.code:qenv-class]{teal.code::qenv}}. } diff --git a/man/teal_data.Rd b/man/teal_data.Rd index dbb065aed..a44773219 100644 --- a/man/teal_data.Rd +++ b/man/teal_data.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/teal_data.R \name{teal_data} \alias{teal_data} -\title{Teal Data} +\title{Comprehensive data integration function for \code{teal} applications} \usage{ teal_data( ..., @@ -12,11 +12,9 @@ teal_data( ) } \arguments{ -\item{...}{(\code{TealDataConnector}, \code{TealDataset}, \code{TealDatasetConnector}, \code{any})\cr -Either 1) an object of a \verb{Teal*} class, which is deprecated and will be removed in next release, -or 2) any number of any objects provided as \code{name = value} pairs, which is available from version \verb{0.4.0}.} +\item{...}{any number of objects (presumably data objects) provided as \code{name = value} pairs.} -\item{join_keys}{(\code{join_keys}) or a single (\code{join_key_set})\cr +\item{join_keys}{(\code{join_keys}) object or a single (\code{join_key_set}) object\cr (optional) object with dataset column relationships used for joining. If empty then no joins between pairs of objects} @@ -27,8 +25,7 @@ code included in the object definitions actually produces those objects. If \code{check} is true and preprocessing code is empty an error will be thrown.} } \value{ -If old data classes are provided (\code{TealDataset} \code{TealDatasetConnector}, \code{TealDataConnector}), a \code{TealData} object. -Otherwise a \code{teal_data} object. +A \code{teal_data} object. } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} diff --git a/man/topological_sort.Rd b/man/topological_sort.Rd index 11d94bbe0..adaffc087 100644 --- a/man/topological_sort.Rd +++ b/man/topological_sort.Rd @@ -7,18 +7,13 @@ topological_sort(graph) } \arguments{ -\item{graph}{(named \code{list}) list with node vector elements} +\item{graph}{(\verb{named list}) with node vector elements} } \description{ -Graph is a list which for each node contains a vector of child nodes +Graph is a \code{list} which for each node contains a vector of child nodes in the returned list, parents appear before their children. } \details{ Implementation of \code{Kahn} algorithm with a modification to maintain the order of input elements. } -\examples{ -teal.data:::topological_sort(list(A = c(), B = c("A"), C = c("B"), D = c("A"))) -teal.data:::topological_sort(list(D = c("A"), A = c(), B = c("A"), C = c("B"))) -teal.data:::topological_sort(list(D = c("A"), B = c("A"), C = c("B"), A = c())) -} \keyword{internal} diff --git a/man/update_keys_given_parents.Rd b/man/update_keys_given_parents.Rd index 704a4b548..98a74a837 100644 --- a/man/update_keys_given_parents.Rd +++ b/man/update_keys_given_parents.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/join_keys-utils.R \name{update_keys_given_parents} \alias{update_keys_given_parents} -\title{Updates the keys of the datasets based on the parents.} +\title{Updates the keys of the datasets based on the parents} \usage{ update_keys_given_parents(x) } @@ -13,6 +13,6 @@ update_keys_given_parents(x) (\code{self}) invisibly for chaining } \description{ -Updates the keys of the datasets based on the parents. +Updates the keys of the datasets based on the parents } \keyword{internal} diff --git a/man/verify.Rd b/man/verify.Rd index 6a54bdf7e..afe4516e1 100644 --- a/man/verify.Rd +++ b/man/verify.Rd @@ -4,7 +4,7 @@ \alias{verify} \alias{verify,teal_data-method} \alias{verify,qenv.error-method} -\title{Verify Code Reproducibility} +\title{Verify code reproducibility} \usage{ verify(x) } @@ -15,7 +15,7 @@ verify(x) Input \code{teal_data} object or error. } \description{ -Checks whether code in \code{teal_data} reproduces the stored objects. +Checks whether code in \code{teal_data} object reproduces the stored objects. } \details{ If objects created by code in the \verb{@code} slot of \code{x} are \code{all_equal} to the contents of the \verb{@env} slot, @@ -37,12 +37,11 @@ verify(tdata2) verify(tdata2)@verified tdata2@verified -\dontrun{ tdata3 <- teal_data() tdata3 <- within(tdata3, { stop("error") }) -verify(tdata3) +try(verify(tdata3)) # fails a <- 1 @@ -51,16 +50,12 @@ c <- list(x = 2) d <- 5 tdata4 <- teal_data( a = a, b = b, c = c, d = d, - code = - " - a <- 1 - b <- a - c <- list(x = 2) - e <- 1 - " + code = "a <- 1 + b <- a + c <- list(x = 2) + e <- 1" ) tdata4 -verify(tdata4) -} +try(verify(tdata4)) # fails } diff --git a/teal.data.Rproj b/teal.data.Rproj index cba1b6b7a..0ee12cdee 100644 --- a/teal.data.Rproj +++ b/teal.data.Rproj @@ -18,4 +18,5 @@ StripTrailingWhitespace: Yes BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source +PackageCheckArgs: --as-cran PackageRoxygenize: rd,collate,namespace diff --git a/tests/testthat/test-formatters_var_labels.R b/tests/testthat/test-formatters_var_labels.R new file mode 100644 index 000000000..000bcf99e --- /dev/null +++ b/tests/testthat/test-formatters_var_labels.R @@ -0,0 +1,42 @@ +testthat::test_that("col_labels accepts an empty data.frame", { + testthat::expect_no_error(col_labels(data.frame())) +}) + +testthat::test_that("col_labels returns empty character vector for a data.frame with no columns", { + testthat::expect_equal(col_labels(data.frame()[1:5, ], fill = TRUE), character(0)) +}) + +testthat::test_that("col_labels returns a named vector of NA when fill = FALSE and there are no labels", { + testthat::expect_equal( + col_labels(iris, fill = FALSE), + stats::setNames(rep(NA_character_, times = ncol(iris)), nm = colnames(iris)) + ) +}) + +testthat::test_that("col_labels returns a vector of column names when fill = TRUE and there are no labels", { + testthat::expect_equal( + col_labels(iris, fill = TRUE), + stats::setNames(colnames(iris), nm = colnames(iris)) + ) +}) + +test_that("col_relabel correctly changes column labels in a data frame", { + iris_df <- iris + iris_df <- col_relabel(iris_df, Sepal.Length = "Sepal Length of iris flower") + testthat::expect_identical( + col_labels(iris_df), + stats::setNames(c("Sepal Length of iris flower", rep(NA, 4)), nm = names(iris_df)) + ) +}) + +test_that("col_relabel throws an error for non-existent columns", { + testthat::expect_error( + col_relabel(iris, NonExistentColumn = "Label"), + "Must be a subset of \\{.*\\}, but has additional elements \\{'NonExistentColumn'\\}" + ) +}) + +test_that("col_relabel returns the original data.frame when no new labels are specified", { + iris_df <- col_relabel(iris) + testthat::expect_equal(iris_df, iris) +}) diff --git a/tests/testthat/test-join_keys.R b/tests/testthat/test-join_keys.R index cb305947f..5deca7f98 100644 --- a/tests/testthat/test-join_keys.R +++ b/tests/testthat/test-join_keys.R @@ -3,6 +3,24 @@ testthat::test_that("join_keys creates empty join_keys object by default", { testthat::expect_s3_class(join_keys(), "join_keys") }) +testthat::test_that("join_keys only accepts teal_data and join_key arguments", { + key <- join_key("a", "b", "test") + testthat::expect_no_error(join_keys(key)) + testthat::expect_no_error(join_keys(teal_data())) + testthat::expect_error( + join_keys("a"), + "Assertion .* failed: May only contain the following types:" + ) +}) + +testthat::test_that("join_keys doesn't accept a list which is identical to output of join_key function", { + key <- join_key("a", "b", "test") + testthat::expect_error( + join_keys(unclass(key)), + "Assertion .* failed: May only contain the following types:" + ) +}) + testthat::test_that("join_keys.join_key creates join_keys", { testthat::expect_s3_class( join_keys( @@ -13,6 +31,18 @@ testthat::test_that("join_keys.join_key creates join_keys", { ) }) +testthat::test_that("join_keys accepts duplicated join_key", { + testthat::expect_no_error( + join_keys(join_key("d1", "d2", "a"), join_key("d1", "d2", "a")) + ) +}) + +testthat::test_that("join_keys accepts duplicated join_key (undirected)", { + testthat::expect_no_error( + join_keys(join_key("d1", "d2", "a", directed = FALSE), join_key("d1", "d2", "a", directed = FALSE)) + ) +}) + testthat::test_that("join_keys is a collection of join_key, ie named list with named list with named char vector", { key1 <- join_key("d1", keys = "test") key2 <- join_key("d2", keys = "test") @@ -68,27 +98,6 @@ testthat::test_that("join_keys.join_keys returns itself", { testthat::expect_identical(obj, join_keys(obj)) }) -testthat::test_that("join_keys accepts duplicated join_key", { - testthat::expect_no_error( - join_keys(join_key("d1", "d2", "a"), join_key("d1", "d2", "a")) - ) -}) - -testthat::test_that("join_keys accepts duplicated join_key (undirected)", { - testthat::expect_no_error( - join_keys(join_key("d1", "d2", "a", directed = FALSE), join_key("d1", "d2", "a", directed = FALSE)) - ) -}) - -testthat::test_that("join_keys doesn't accept other objects than teal_data, TealData and join_key", { - testthat::expect_error(join_keys("a")) # todo: add expected error message -}) - -testthat::test_that("join_keys doesn't accept a list which is identical to output of join_key function", { - key <- join_key("a", "b", "test") - testthat::expect_error(join_keys(unclass(key))) -}) - testthat::test_that("join_keys constructor adds symmetric keys on given (unnamed) foreign key", { my_keys <- join_keys(join_key("d1", "d2", "a")) expected_keys <- join_keys(join_key("d2", "d1", "a", directed = FALSE)) diff --git a/vignettes/join-keys.Rmd b/vignettes/join-keys.Rmd index 662b13104..69a0da48b 100644 --- a/vignettes/join-keys.Rmd +++ b/vignettes/join-keys.Rmd @@ -27,10 +27,10 @@ Refer to the section ["Joining Keys with `ADaM` Datasets"](#join-keys-in-adam-da The primary function of the `join_keys` class in `teal` applications is to facilitate the seamless [merging of datasets](https://insightsengineering.github.io/teal.transform/latest-tag/articles/data-merge.html) using `teal.transform`. -Additionally, it plays a role on the data filtering using the _[Filter Panel](https://insightsengineering.github.io/teal/main/articles/filter-panel.html)_ in a `teal` application. +Additionally, it plays a role in the data filtering using the _[Filter Panel](https://insightsengineering.github.io/teal/latest-tag/articles/filter-panel.html)_ in a `teal` application. The filters applied to a (parent) dataset are also applied to their children. -## Anatomy of Join Keys +## Anatomy of `join_keys` The `join_keys` object contains information about the foreign/primary keys of multiple datasets. Each key is represented by a pair of datasets (by name reference) and a named character vector that encodes the column name mapping between the two datasets. @@ -53,12 +53,12 @@ As the _Constructor_ it is used to specify a collection of multiple individual k Specifies a primary key or a relationship between two datasets. - `dataset_1`, `dataset_2`: names of the datasets (if `dataset_2` is the same as `dataset_1` or is omitted, it creates a primary key); -- `key` (optional): named vector of column names; -- `parent` (optional): indicates which dataset (`"dataset_1"` or `"dataset_2"`) is the parent in a _parent-child_ relationship, or `"none"` for an undirected relationship. +- `key`: named `character` vector of column name mapping between datasets (unnamed vector assumes column names between datasets are the same); +- `directed` (optional): flag that indicates whether there is a _parent-child_ directed relationship between `dataset_2` to `dataset_1` (latter as a parent). Note that join keys are assumed to be symmetric, i.e., `join_key("ds1", "ds2", c("ds1_col" = "ds2_col"))` establishes a relationship from "x" to "y" and vice versa. -By default the new joining key will set the `dataset_1` as the parent. +By default, the new joining key will set the `dataset_1` as the parent. ##### Example & Output @@ -108,7 +108,7 @@ The _subset_ operator with 2 indices (`x[i, j]`) is used to retrieve the primary Both indices must be a string denoting the dataset name. ```{r} -# Using the jk object defined on "Anatomy of Join Keys" +# Using the jk object defined in "Anatomy of Join Keys" jk # Getting primary key of "ds1" @@ -128,18 +128,18 @@ jk["ds5", "ds4"] When only 1 argument is used this operator will return a `join_keys` object that is filtered accordingly. ```{r} -# Using the jk object defined on "Anatomy of Join Keys" +# Using the jk object defined in "Anatomy of Join Keys" jk # Getting primary key of "ds1" -jk["ds1"] +jk["ds1", "ds1"] # Getting keys of "ds1" and "ds2" jk[c("ds1", "ds2")] ``` Modifying or adding a key uses the same notation with the assignment operator `<-`. -A symmetric relationship will be created automatically, where the parent (by default) will be the dataset defined on the first index. +A symmetric relationship will be created automatically, where the parent (by default) will be the dataset defined in the first index. Assigning `NULL` value will delete the relationship. ```{r} @@ -150,6 +150,26 @@ jk["ds1", "ds5"] <- "a_column" jk["ds4", "ds5"] <- NULL ``` +## Merging Join Keys + +The combining of multiple _joining keys_ is achieved using the `c()` generic function, which generates a symmetric and valid `join_keys` object. When encountering identical relationship pairs, this operation retains the last occurrence of the pair within the specified argument order. + +For added convenience, the function also accommodates `join_key_set` objects created through the `join_key` function. These objects can be provided as the initial argument or in any other position as needed. + +```{r} +jk1 <- join_keys(join_key("ds1", "ds1", "col_1")) +jk2 <- join_keys(join_key("ds2", "ds2", "col_1"), join_key("ds1", "ds2", "col_1")) + +# Merging +c(jk1, jk2) + +# Keeping last occurence +c(jk1, jk2, join_keys(join_key("ds2", "ds2", "col_2"), join_key("ds1", "ds2", c("col_1" = "col_2")))) + +# Merges join_key and join_key_set objects (from join_key function) +c(jk1, join_key("ds3", "ds3", "col_3")) +``` + ## Join Keys Relationships There are 2 types of relationships encoded with _joining keys_ that are described in the following sections. The _primary_ and _foreign_ keys are created explicitly using the constructor for individual keys (`join_key`).