Skip to content

Commit a76e82c

Browse files
authored
fixes for job submissions (#39)
* Update seurat_helpers.R * Update R-CMD-check.yaml * Update schema.R * Update cytetype.R * Update R-CMD-check.yaml * Update R-CMD-check.yaml * Revert "Update cytetype.R" This reverts commit 8add6f3. * Revert "Update seurat_helpers.R" This reverts commit 63e4d5d. * Update schema.R * Update R-CMD-check.yaml * Increment version number to 0.3.2 * fix attr to scalar * rate limit error messages
1 parent b35a2e6 commit a76e82c

8 files changed

Lines changed: 64 additions & 19 deletions

File tree

.github/workflows/R-CMD-check.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,17 @@ jobs:
4040
use-public-rspm: true
4141

4242
- uses: r-lib/actions/setup-r-dependencies@v2
43+
if: matrix.config.r == 'release'
4344
with:
4445
extra-packages: any::rcmdcheck
4546
needs: check
4647

48+
- uses: r-lib/actions/setup-r-dependencies@v2
49+
if: matrix.config.r != 'release'
50+
with:
51+
extra-packages: any::rcmdcheck, cran/ggrepel@0.9.6
52+
needs: check
53+
4754
- uses: r-lib/actions/check-r-package@v2
4855
with:
4956
upload-snapshots: true

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: CyteTypeR
22
Title: CyteType for R
3-
Version: 0.3.1
3+
Version: 0.3.2
44
Description: CyteTypeR is the R version of CyteType python package.
55
Authors@R:
66
person("Nygen Analytics AB", , ,"contact@nygen.io", role = c("aut", "cre"))

R/api.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
))
5454

5555
}, error = function(e) {
56+
.stop_if_rate_limited(e)
57+
5658
# Preserve authentication/authorization errors
5759
if (grepl("Authentication failed|Authorization failed", e$message)) {
5860
stop(e)

R/artifacts.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@
8181
on.exit(rhdf5::H5Fclose(fid), add = TRUE)
8282

8383
rhdf5::h5createGroup(fid, "vars")
84-
rhdf5::h5writeAttribute(as.integer(n_obs), h5obj = out_file, name = "n_obs", h5loc = "vars")
85-
rhdf5::h5writeAttribute(as.integer(n_vars), h5obj = out_file, name = "n_vars", h5loc = "vars")
84+
rhdf5::h5writeAttribute(as.integer(n_obs), h5obj = out_file, name = "n_obs", h5loc = "vars", asScalar = TRUE)
85+
rhdf5::h5writeAttribute(as.integer(n_vars), h5obj = out_file, name = "n_vars", h5loc = "vars", asScalar = TRUE)
8686

8787
# Create extensible datasets (equivalent to maxshape=(None,) in h5py)
8888
max_nnz <- n_obs * n_vars # upper bound

R/client.R

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,15 @@
4141
connection_timeout <- 30L
4242

4343
# Step 1 – Initiate (empty POST; explicit empty body for compatibility)
44-
init_resp <- .make_req(api_url, paste0(file_kind, "/initiate"), auth_token) |>
45-
req_method("POST") |>
46-
httr2::req_body_raw(raw(0), type = "application/json") |>
47-
req_timeout(connection_timeout) |>
48-
req_perform() |>
49-
resp_body_json()
44+
init_resp <- tryCatch(
45+
.make_req(api_url, paste0(file_kind, "/initiate"), auth_token) |>
46+
req_method("POST") |>
47+
httr2::req_body_raw(raw(0), type = "application/json") |>
48+
req_timeout(connection_timeout) |>
49+
req_perform() |>
50+
resp_body_json(),
51+
error = function(e) { .stop_if_rate_limited(e); stop(e) }
52+
)
5053

5154
upload_id <- init_resp$upload_id
5255
chunk_size <- as.integer(init_resp$chunk_size_bytes %||% (5L * 1024L * 1024L))
@@ -86,6 +89,7 @@
8689
req_perform()
8790
list(ok = TRUE)
8891
}, error = function(e) {
92+
.stop_if_rate_limited(e)
8993
list(ok = FALSE, chunk_idx = chunk_idx, message = conditionMessage(e))
9094
})
9195
}
@@ -102,12 +106,15 @@
102106
}
103107
}
104108
# Step 3 – Complete (empty POST; explicit empty body for compatibility)
105-
complete_resp <- .make_req(api_url, paste0(upload_id, "/complete"), auth_token) |>
106-
req_method("POST") |>
107-
httr2::req_body_raw(raw(0), type = "application/json") |>
108-
req_timeout(connection_timeout) |>
109-
req_perform() |>
110-
resp_body_json()
109+
complete_resp <- tryCatch(
110+
.make_req(api_url, paste0(upload_id, "/complete"), auth_token) |>
111+
req_method("POST") |>
112+
httr2::req_body_raw(raw(0), type = "application/json") |>
113+
req_timeout(connection_timeout) |>
114+
req_perform() |>
115+
resp_body_json(),
116+
error = function(e) { .stop_if_rate_limited(e); stop(e) }
117+
)
111118

112119
complete_resp
113120
}
@@ -167,10 +174,8 @@
167174
return(as.character(job_id))
168175

169176
}, error = function(e) {
170-
# Log the error
177+
.stop_if_rate_limited(e)
171178
cat("An error occurred:", conditionMessage(e), "\n")
172-
173-
# Return NA for any error
174179
return(NA_character_)
175180
})
176181
}

R/cytetype.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,5 @@ GetResults <- function(obj = NULL, job_id = NULL, results_prefix = "cytetype", a
482482

483483

484484

485-
486485

487486

R/errors.R

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,27 @@ cytetype_api_error <- function(message, call = NULL) {
1515
print.cytetype_api_error <- function(x, ...) {
1616
cat("CyteType API Error: ", x$message, "\n")
1717
}
18+
19+
.parse_server_error <- function(resp) {
20+
body <- tryCatch(httr2::resp_body_json(resp), error = function(e) NULL)
21+
if (is.null(body)) return(NULL)
22+
if ("detail" %in% names(body) && is.list(body$detail)) body <- body$detail
23+
if (!is.null(body$error_code) && !is.null(body$message)) {
24+
return(list(error_code = body$error_code, message = body$message))
25+
}
26+
NULL
27+
}
28+
29+
.stop_if_rate_limited <- function(e) {
30+
if (inherits(e, "httr2_http") && !is.null(e$resp)) {
31+
parsed <- .parse_server_error(e$resp)
32+
if (!is.null(parsed) && parsed$error_code == "RATE_LIMIT_EXCEEDED") {
33+
stop(
34+
"Rate limit exceeded: ", parsed$message,
35+
"\nUse your own LLM API key via llm_configs to bypass free-tier limits, ",
36+
"or wait before retrying.",
37+
call. = FALSE
38+
)
39+
}
40+
}
41+
}

R/schema.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ LLMModelConfig <- function(provider,
108108
mask_job_details <- if (is.null(nm)) rep(TRUE, length(query_list$input_data)) else !endsWith(nm, "jobDetails")
109109
query_list$input_data <- query_list$input_data[mask_job_details]
110110

111+
# Ensure fields the server expects as JSON objects serialize to {} not []
112+
dict_fields <- c("clusterMetadata", "clusterLabels", "infoTags", "expressionData")
113+
for (field in dict_fields) {
114+
val <- query_list$input_data[[field]]
115+
if (is.list(val) && length(val) == 0 && is.null(names(val))) {
116+
query_list$input_data[[field]] <- setNames(list(), character(0))
117+
}
118+
}
111119

112120
return(query_list)
113121
}

0 commit comments

Comments
 (0)