Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into use-api
Browse files Browse the repository at this point in the history
* origin/main:
  Add printing to remaining classes (#31)
  Improve error messages (#30)
  Update documentation (#29)
  Return `NULL` when a record's related field is empty (#28)
  minor fix in usage vignette (#32)
  Add usage vignette (#18)
  Add a simple unit test which queries laminlabs/lamindata (#27)
  bump action from v4.5.0 to v4 (#26)
  • Loading branch information
lazappi committed Oct 14, 2024
2 parents 5dd2611 + bca4137 commit 6e3e7ae
Show file tree
Hide file tree
Showing 24 changed files with 893 additions and 114 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ jobs:

- name: Install lamindb
run: |
pip install lamindb[bionty]
pip install lamindb[bionty,wetlab]
- name: Log in to Lamin
run: |
lamin login
- name: Set cellxgene as default instance
run: |
lamin load laminlabs/cellxgene
lamin connect laminlabs/cellxgene
- uses: r-lib/actions/setup-r-dependencies@v2
with:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,23 @@ jobs:

- name: Install lamindb
run: |
pip install lamindb[bionty]
pip install lamindb[bionty,wetlab]
- name: Log in to Lamin
run: |
lamin login
- name: Set cellxgene as default instance
run: |
lamin load laminlabs/cellxgene
lamin connect laminlabs/cellxgene
- name: Build site
run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}

- name: Deploy to GitHub pages 🚀
if: github.event_name != 'pull_request'
uses: JamesIves/github-pages-deploy-action@v4.5.0
uses: JamesIves/github-pages-deploy-action@v4
with:
clean: false
branch: gh-pages
Expand Down
32 changes: 25 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

* Read user settings from env file created by lamin Python package (PR #2, PR #8).

* Render a pkgdown website (PR #13).
* Add `to_string()` and `print()` methods to the `Record` class and (incomplete) `describe()` method to the `Artifact()` class (PR #22).

* Add `to_string()` and `print()` methods to the `Record` class and (incomplete) `describe()` method to the `Artifact()` class (PR #22)
* Add `to_string()` and `print()` methods to remaining classes (PR #31)

## MAJOR CHANGES

Expand All @@ -19,26 +19,44 @@
- Linting action.
- Commands for roxygenizing (`/document`) and restyling the source code (`/style`).

* Allow unauthenticated users to connect to an instance if they ran `lamin load <instance>` beforehand (PR #19).
* Allow unauthenticated users to connect to an instance if they ran `lamin connect <instance>` beforehand (PR #19).

## MINOR CHANGES

* Update `README` with new set up instructions and simplify (PR #14).

* Do not complain when foreign keys are not found in a record, but also do not complain when they are (PR #13).

* Further simplify the `README`, and move the detailed usage description to a separate vignette (PR #13).
* Define a current user and current instance with lamin-cli prior to testing and generating documentation in the CI (PR #23).

## TESTING

* Add a simple unit test which queries laminlabs/lamindata (PR #27).

* Added unit test for the InstanceAPI class (PR #30).

## DOCUMENTATION

* Update `README` with new set up instructions and simplify (PR #14).

* Add a `pkgdown` website to the project (PR #13).

* Further simplify the `README`, and move the detailed usage description to a separate vignette (PR #13).

* Generate vignettes using Quarto (PR #13).

* Define a current user and current instance with lamin-cli prior to testing and generating documentation in the CI (PR #23).
* Add vignette to showcase laminr usage (PR #18).

* Replace all mentions of `lamin load` with `lamin connect` (PR #29).

* Improve the `README` (PR #29).

## BUG FIXES

* Fixed the parsing of the env files in `~/.lamin` due to changes in the lamindb-setup Python package (PR #12).

* Return `NULL` when a record's related field is empty (PR #28).

* Add alternative error message when no message is returned from the API (PR #30).

# laminr v0.0.1

Initial POC implementation of the LaminDB API client for R.
Expand Down
5 changes: 4 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ Imports:
Suggests:
anndata,
quarto,
s3 (>= 1.1.0)
s3 (>= 1.1.0),
testthat (>= 3.0.0),
withr
VignetteBuilder: quarto
Config/testthat/edition: 3
14 changes: 8 additions & 6 deletions R/Artifact.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ ArtifactRecord <- R6::R6Class( # nolint object_name_linter
"ArtifactRecord",
inherit = Record,
public = list(
#' Load the artifact into memory
#'
#' @description
#' This currently only supports AnnData artifacts.
#' Load the artifact into memory. This currently only supports AnnData
#' artifacts.
#'
#' @return The artifact
load = function() {
Expand All @@ -26,10 +25,9 @@ ArtifactRecord <- R6::R6Class( # nolint object_name_linter
cli_abort(paste0("Unsupported accessor: ", artifact_accessor))
}
},
#' Cache the artifact to the local filesystem
#'
#' @description
#' This currently only supports S3 storage.
#' Cache the artifact to the local filesystem. This currently only supports
#' S3 storage.
#'
#' @return The path to the cached artifact
cache = function() {
Expand All @@ -50,6 +48,10 @@ ArtifactRecord <- R6::R6Class( # nolint object_name_linter
cli_abort(paste0("Unsupported storage type: ", artifact_storage$type))
}
},
#' @description
#' Print a more detailed description of an `ArtifactRecord`
#'
#' @param style Logical, whether the output is styled using ANSI codes
describe = function(style = TRUE) {
provenance_fields <- c(
storage = "root",
Expand Down
33 changes: 33 additions & 0 deletions R/Field.R
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,39 @@ Field <- R6::R6Class( # nolint object_name_linter
private$.related_field_name <- related_field_name
private$.related_registry_name <- related_registry_name
private$.related_module_name <- related_module_name
},
#' @description
#' Print a `Field`
#'
#' @param style Logical, whether the output is styled using ANSI codes
print = function(style = TRUE) {
cli::cat_line(self$to_string(style))
},
#' @description
#' Create a string representation of a `Field`
#'
#' @param style Logical, whether the output is styled using ANSI codes
#'
#' @return A `cli::cli_ansi_string` if `style = TRUE` or a character vector
to_string = function(style = FALSE) {
field_strings <- make_key_value_strings(
self,
c(
"field_name",
"column_name",
"type",
"registry_name",
"module_name",
"through",
"is_link_table",
"relation_type",
"related_field_name",
"related_registry_name",
"related_module_name"
)
)

make_class_string("Field", field_strings, style = style)
}
),
private = list(
Expand Down
108 changes: 108 additions & 0 deletions R/Instance.R
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,114 @@ Instance <- R6::R6Class( # nolint object_name_linter
#' Get the names of the modules. Example: `c("core", "bionty")`.
get_module_names = function() {
names(private$.module_classes)
},
#' Get instance settings.
get_settings = function() {
private$.settings
},
#' Get instance API.
get_api = function() {
private$.api
},
#' @description
#' Print an `Instance`
#'
#' @param style Logical, whether the output is styled using ANSI codes
print = function(style = TRUE) {

registries <- self$get_module("core")$get_registries()

is_link_table <- purrr::map(registries, "is_link_table") |>
unlist()

standard_lines <- purrr::map_chr(
names(registries)[!is_link_table],
function(.registry) {
cli::col_blue(paste0(" $", registries[[.registry]]$class_name))
}
)

link_lines <- purrr::map_chr(
names(registries)[is_link_table],
function(.registry) {
cli::col_blue(paste0(" ", .registry))
}
)

lines <- c(
cli::style_bold(cli::col_green(private$.settings$name)),
cli::style_italic(cli::col_magenta(" Core registries")),
standard_lines,
cli::style_italic(cli::col_magenta(" Core link tables")),
link_lines
)

module_names <- self$get_module_names()
module_names <- module_names[module_names != "core"]

if (length(module_names) > 0) {
lines <- c(
lines,
cli::style_italic(cli::col_magenta(" Additional modules")),
cli::col_blue(paste0(" ", module_names))
)
}

if (isFALSE(style)) {
lines <- cli::ansi_strip(lines)
}

purrr::walk(lines, cli::cat_line)
},
#' @description
#' Create a string representation of an `Instance`
#'
#' @param style Logical, whether the output is styled using ANSI codes
#'
#' @return A `cli::cli_ansi_string` if `style = TRUE` or a character vector
to_string = function(style = FALSE) {
registries <- self$get_module("core")$get_registries()

is_link_table <- purrr::map(registries, "is_link_table") |>
unlist()

mapping <- list(
"CoreRegistries" = paste0(
"[",
paste(
paste0(
"$",
purrr::map_chr(registries[!is_link_table], "class_name")
),
collapse = ", "
),
"]"
),
"CoreLinkTables" = paste0(
"[",
paste(names(registries[is_link_table]), collapse = ", "),
"]"
)
)

module_names <- self$get_module_names()
module_names <- module_names[module_names != "core"]

if (length(module_names) > 0) {
mapping["AdditionalModules"] <- paste0(
"[",
paste(module_names, collapse = ", "),
"]"
)
}

key_value_strings <- make_key_value_strings(
mapping, quote_strings = FALSE
)

make_class_string(
private$.settings$name, key_value_strings, style = style
)
}
),
private = list(
Expand Down
39 changes: 36 additions & 3 deletions R/InstanceAPI.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter
private$.api_client <- laminr.api::ApiClient$new(instance_settings$api_url)
private$.default_api <- laminr.api::DefaultApi$new(private$.api_client)
},
#' @description
#' Get the schema for the instance.
get_schema = function(id) {
schema <- try(
Expand All @@ -35,7 +36,9 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter

return(schema)
},
#' @description
#' Get a record from the instance.
#'
#' @importFrom jsonlite toJSON
get_record = function(module_name,
registry_name,
Expand Down Expand Up @@ -87,12 +90,42 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter
))
}

return(record)
content
}
),
private = list(
.instance_settings = NULL,
.api_client = NULL,
.default_api = NULL
process_response = function(response, request_type) {
content <- httr::content(response)
if (httr::http_error(response)) {
if (is.list(content) && "detail" %in% names(content)) {
cli_abort(content$detail)
} else {
cli_abort("Failed to {request_type} from instance. Output: {content}")
}
}

content
},
#' @description
#' Print an `API`
#'
#' @param style Logical, whether the output is styled using ANSI codes
print = function(style = TRUE) {
cli::cat_line(self$to_string(style))
},
#' @description
#' Create a string representation of an `API`
#'
#' @param style Logical, whether the output is styled using ANSI codes
#'
#' @return A `cli::cli_ansi_string` if `style = TRUE` or a character vector
to_string = function(style = FALSE) {
field_strings <- make_key_value_strings(
private$.instance_settings, c("api_url", "id", "schema_id")
)

make_class_string("API", field_strings, style = style)
}
)
)
Loading

0 comments on commit 6e3e7ae

Please sign in to comment.