From 72ee24db6522a6c68cad0d1dee06bc9b10623f7e Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 24 Oct 2024 09:14:01 +0200 Subject: [PATCH 1/7] Add check_requires() function --- R/utils.R | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 R/utils.R diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..e257f76 --- /dev/null +++ b/R/utils.R @@ -0,0 +1,33 @@ +#' Check required packages +#' +#' Check that required packages are available and give a nice error message with +#' install instructions if not +#' +#' @param what A message stating what the packages are required for. Used at the +#' start of the error message e.g. "{what} requires...". +#' @param requires Character vector of required package names +#' +#' @return `TRUE` invisibly if all packages are available, otherwise calls +#' [cli::cli_abort()] +#' @noRd +check_requires <- function(what, requires) { + + is_available <- purrr::map_lgl(requires, requireNamespace, quietly = TRUE) + + if (any(!is_available)) { + missing <- requires[!is_available] + missing_str <- paste0("'", paste(missing, collapse = "', '"), "'") + cli_abort( + c( + "{what} requires the {.pkg {missing}} package{?s}", + "i" = paste( + "To continue, install {cli::qty(missing)}{?it/them} using", + "{.code install.packages(c({missing_str}))}" + ) + ), + call = rlang::caller_env() + ) + } + + invisible(TRUE) +} From 43823984bd22d0056918917a8c90ffb95f06e30a Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 24 Oct 2024 09:37:42 +0200 Subject: [PATCH 2/7] Add tests for check_requires() --- tests/testthat/test-utils.R | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/testthat/test-utils.R diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R new file mode 100644 index 0000000..ea58623 --- /dev/null +++ b/tests/testthat/test-utils.R @@ -0,0 +1,7 @@ +test_that("check_requires works", { + expect_true(check_requires("Imported packages", "cli")) + expect_error( + check_requires("Missing packages", "a_missing_package"), + regexp = "Missing packages requires" + ) +}) From 1d27bb209bdca9087684fcef75244d3f8f9fdaa6 Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 24 Oct 2024 09:42:12 +0200 Subject: [PATCH 3/7] Replace requireNamespace() with check_requires() --- R/Artifact.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/Artifact.R b/R/Artifact.R index 1536c6d..5fa5770 100644 --- a/R/Artifact.R +++ b/R/Artifact.R @@ -19,7 +19,7 @@ ArtifactRecord <- R6::R6Class( # nolint object_name_linter file_path <- self$cache() if (artifact_accessor == "AnnData") { - requireNamespace("anndata", quietly = TRUE) + check_requires("Loading AnnData objects", "anndata") anndata::read_h5ad(file_path) } else { cli_abort(paste0("Unsupported accessor: ", artifact_accessor)) @@ -37,7 +37,7 @@ ArtifactRecord <- R6::R6Class( # nolint object_name_linter artifact_key <- private$get_value("key") if (artifact_storage$type == "s3") { - requireNamespace("s3", quietly = TRUE) + check_requires("Caching artifacts from s3", "s3") root_dir <- file.path(Sys.getenv("HOME"), ".cache", "lamindb") s3::s3_get( paste0(artifact_storage$root, "/", artifact_key), From 249b7520b3edcc1ce0cd443e8bfac204d1fa3c25 Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 24 Oct 2024 10:03:39 +0200 Subject: [PATCH 4/7] Add suggested dependencies to installation docs --- README.md | 13 ++++++++++--- README.qmd | 6 ++++++ vignettes/usage.Rmd | 32 +++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dd3c6ce..ca4ce49 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,13 @@ Install the development version from GitHub: remotes::install_github("laminlabs/laminr") ``` +To install all suggested dependencies required for some functionality, +use: + +``` r +remotes::install_github("laminlabs/laminr", dependencies = TRUE) +``` + You will also need to install `lamindb`: ``` bash @@ -90,7 +97,7 @@ You can print the record: artifact ``` - Artifact(uid='KBW89Mf7IGcekja2hADu', description='Myeloid compartment', key='cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad', storage_id=2, _accessor='AnnData', version='2024-07-01', id=3659, size=691757462, transform_id=22, is_latest=TRUE, type='dataset', n_observations=51552, created_by_id=1, _hash_type='md5-n', created_at='2024-07-12T12:34:10.345829+00:00', suffix='.h5ad', updated_at='2024-07-12T12:40:48.837026+00:00', _key_is_virtual=FALSE, visibility=1, run_id=27, hash='SZ5tB0T4YKfiUuUkAL09ZA') + Artifact(uid='KBW89Mf7IGcekja2hADu', description='Myeloid compartment', key='cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad', created_by_id=1, run_id=27, suffix='.h5ad', created_at='2024-07-12T12:34:10.345829+00:00', hash='SZ5tB0T4YKfiUuUkAL09ZA', _hash_type='md5-n', storage_id=2, version='2024-07-01', _accessor='AnnData', id=3659, is_latest=TRUE, _key_is_virtual=FALSE, transform_id=22, n_observations=51552, size=691757462, visibility=1, updated_at='2024-07-12T12:40:48.837026+00:00', type='dataset') Or call the `$describe()` method to get a summary: @@ -98,7 +105,7 @@ Or call the `$describe()` method to get a summary: artifact$describe() ``` - Artifact(uid='KBW89Mf7IGcekja2hADu', description='Myeloid compartment', key='cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad', storage_id=2, _accessor='AnnData', version='2024-07-01', id=3659, size=691757462, transform_id=22, is_latest=TRUE, type='dataset', n_observations=51552, created_by_id=1, _hash_type='md5-n', created_at='2024-07-12T12:34:10.345829+00:00', suffix='.h5ad', updated_at='2024-07-12T12:40:48.837026+00:00', _key_is_virtual=FALSE, visibility=1, run_id=27, hash='SZ5tB0T4YKfiUuUkAL09ZA') + Artifact(uid='KBW89Mf7IGcekja2hADu', description='Myeloid compartment', key='cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad', created_by_id=1, run_id=27, suffix='.h5ad', created_at='2024-07-12T12:34:10.345829+00:00', hash='SZ5tB0T4YKfiUuUkAL09ZA', _hash_type='md5-n', storage_id=2, version='2024-07-01', _accessor='AnnData', id=3659, is_latest=TRUE, _key_is_virtual=FALSE, transform_id=22, n_observations=51552, size=691757462, visibility=1, updated_at='2024-07-12T12:40:48.837026+00:00', type='dataset') Provenance $storage = 's3://cellxgene-data-public' $transform = 'Census release 2024-07-01 (LTS)' @@ -127,7 +134,7 @@ You can directly load the artifact to access its data: artifact$load() ``` - ℹ 's3://cellxgene-data-public/cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad' already exists at '/home/rcannood/.cache/lamindb/cellxgene-data-public/cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad' + ℹ 's3://cellxgene-data-public/cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad' already exists at '/home/luke/.cache/lamindb/cellxgene-data-public/cell-census/2024-07-01/h5ads/fe52003e-1460-4a65-a213-2bb1a508332f.h5ad' AnnData object with n_obs × n_vars = 51552 × 36398 obs: 'donor_id', 'Predicted_labels_CellTypist', 'Majority_voting_CellTypist', 'Manually_curated_celltype', 'assay_ontology_term_id', 'cell_type_ontology_term_id', 'development_stage_ontology_term_id', 'disease_ontology_term_id', 'self_reported_ethnicity_ontology_term_id', 'is_primary_data', 'organism_ontology_term_id', 'sex_ontology_term_id', 'tissue_ontology_term_id', 'suspension_type', 'tissue_type', 'cell_type', 'assay', 'disease', 'organism', 'sex', 'tissue', 'self_reported_ethnicity', 'development_stage', 'observation_joinid' diff --git a/README.qmd b/README.qmd index e51a2da..9d7fa56 100644 --- a/README.qmd +++ b/README.qmd @@ -24,6 +24,12 @@ Install the development version from GitHub: remotes::install_github("laminlabs/laminr") ``` +To install all suggested dependencies required for some functionality, use: + +```R +remotes::install_github("laminlabs/laminr", dependencies = TRUE) +``` + You will also need to install `lamindb`: ```bash diff --git a/vignettes/usage.Rmd b/vignettes/usage.Rmd index 2db22b6..09d0ae3 100644 --- a/vignettes/usage.Rmd +++ b/vignettes/usage.Rmd @@ -20,18 +20,44 @@ This vignette will show you how to use the `laminr` package to interact with Lam ## Initial setup -As part of a first-time set up, you will need to install `laminr`, the Python `lamin-cli` package, and set up an instance for first use. +### Python package + +As part of a first-time set up, you will need to install the Python `lamin-cli` package, and set up an instance for first use. ```bash pip install lamin-cli lamin connect laminlabs/cellxgene ``` -```R -install.packages("remotes") +### R package + +You will also need to install the `laminr` R package. + +```{r install, eval = FALSE} +# Install the remotes package if needed +if (!requireMethods("remotes", quiety = TRUE)) { + install.packages("remotes") +} remotes::install_github("laminlabs/laminr") ``` +#### Suggested dependencies + +Some functionality requires additional suggested dependencies. +You will be prompted to install these packages when needed, or you can install them in advance. +Setting `dependencies = TRUE` will install all suggested packages. + +```{r install-suggested, eval = FALSE} +remotes::install_github("laminlabs/laminr", dependencies = TRUE) +``` + +Or individual suggested packages can be installed with `install.packages()`. + +Suggested dependecies: + +- [anndata](https://cran.r-project.org/package=anndata) - Loading and saving `AnnData` objects +- [s3](https://cran.r-project.org/package=s3) - Caching objects to/from S3 storage + ## Connect to a LaminDB instance This vignette uses the [`laminlabs/cellxgene`](https://lamin.ai/laminlabs/cellxgene) instance, which is a LaminDB instance that interfaces the CELLxGENE data. From 5aacab473b1e71b0b0a7821c628b71af647b7654 Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 24 Oct 2024 10:15:17 +0200 Subject: [PATCH 5/7] Add rlang to Imports Also tidy DESCRIPTION with `usethis::use_tidy_description()` --- DESCRIPTION | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index c663b59..41eee79 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,26 +1,18 @@ Package: laminr Title: 'LaminDB' Interface in R Version: 0.1.0 -Authors@R: - c(person("Robrecht", "Cannoodt", - role = c("aut", "cre"), - email = "robrecht@data-intuitive.com", - comment = c(ORCID = "0000-0003-3641-729X", github = "rcannood") - ), - person( - "Luke", "Zappia", - role = "aut", - email = "luke@data-intuitive.com", - comment = c(ORCID = "0000-0001-7744-8565", github = "lazappi") - ), - person("Data Intuitive", email = "info@data-intuitive.com", role = c("aut")), - person("Lamin Labs", email = "open-source@lamin.ai", role = c("aut", "cph"))) -Description: Interact with 'LaminDB' from R. 'LaminDB' is an open-source data framework for biology. - This package allows you to query and download data from 'LaminDB' instances. +Authors@R:c( + person("Robrecht", "Cannoodt", , "robrecht@data-intuitive.com", role = c("aut", "cre"), + comment = c(ORCID = "0000-0003-3641-729X", github = "rcannood")), + person("Luke", "Zappia", , "luke@data-intuitive.com", role = "aut", + comment = c(ORCID = "0000-0001-7744-8565", github = "lazappi")), + person("Data Intuitive", , , "info@data-intuitive.com", role = "aut"), + person("Lamin Labs", , , "open-source@lamin.ai", role = c("aut", "cph")) + ) +Description: Interact with 'LaminDB' from R. 'LaminDB' is an open-source + data framework for biology. This package allows you to query and + download data from 'LaminDB' instances. License: Apache License (>= 2) -Encoding: UTF-8 -Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 URL: https://laminr.lamin.ai, https://github.com/laminlabs/laminr BugReports: https://github.com/laminlabs/laminr/issues Depends: @@ -30,12 +22,17 @@ Imports: httr, jsonlite, purrr, - R6 + R6, + rlang Suggests: anndata, quarto, s3 (>= 1.1.0), testthat (>= 3.0.0), withr -VignetteBuilder: quarto +VignetteBuilder: + quarto Config/testthat/edition: 3 +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.2 From f39a16e70b852bbe68a83c4d74a4a1c35e95f687 Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 24 Oct 2024 10:17:55 +0200 Subject: [PATCH 6/7] Style and lint --- R/utils.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/R/utils.R b/R/utils.R index e257f76..31fd711 100644 --- a/R/utils.R +++ b/R/utils.R @@ -11,14 +11,13 @@ #' [cli::cli_abort()] #' @noRd check_requires <- function(what, requires) { - is_available <- purrr::map_lgl(requires, requireNamespace, quietly = TRUE) if (any(!is_available)) { missing <- requires[!is_available] - missing_str <- paste0("'", paste(missing, collapse = "', '"), "'") + missing_str <- paste0("'", paste(missing, collapse = "', '"), "'") # nolint object_usage_linter cli_abort( - c( + c( "{what} requires the {.pkg {missing}} package{?s}", "i" = paste( "To continue, install {cli::qty(missing)}{?it/them} using", From 0983e4de2a40e6cdc0595b91a0f4ae03906607d3 Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Fri, 25 Oct 2024 13:13:12 +0200 Subject: [PATCH 7/7] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b40afb..4a371ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,8 @@ For more information, please visit the [package website](https://laminr.lamin.ai * Define a current user and current instance with lamin-cli prior to testing and generating documentation in the CI (PR #23). +* Improve checking for suggested packages and provide installation instructions if missing (PR #56) + ## TESTING * Add a simple unit test which queries laminlabs/lamindata (PR #27). @@ -64,6 +66,8 @@ For more information, please visit the [package website](https://laminr.lamin.ai * Set Python requirements to `lamindb[aws]` for now (PR #33). Will be changed to `lamin_cli` once [laminlabs/lamin-cli#90](https://github.com/laminlabs/lamin-cli/issues/90) is solved. + +* Improve documentation for installing suggested dependencies and what they are requrire for (PR #56) ## BUG FIXES