Skip to content

Commit d603ed9

Browse files
committed
Improve error handling and code style in R functions
Refactored multiple R scripts to use more robust tryCatch error handling, improved code formatting, and enhanced user feedback for error cases. These changes increase reliability and maintainability across gen_docs, gen_image, gen_tests, setEnv, setAPI, vertex, and utility functions.
1 parent b9a821b commit d603ed9

File tree

8 files changed

+226
-189
lines changed

8 files changed

+226
-189
lines changed

R/gemini_narrative.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ gemini_narrative <- function(input, type = "table", prompt = NULL, ...) {
4040
input,
4141
format = "pipe",
4242
col.names = colnames(input)
43-
), collapse = '\n')
43+
), collapse = "\n")
4444
# Use user prompt if provided, otherwise use default
4545
if (is.null(prompt)) {
4646
# Default prompt for table with a newline before the table
@@ -58,8 +58,8 @@ gemini_narrative <- function(input, type = "table", prompt = NULL, ...) {
5858
} else if (type == "figure") {
5959
# Check if input is a valid image file path and a scalar string
6060
if (!is.character(input) || length(input) != 1 ||
61-
!file.exists(input) ||
62-
!(tools::file_ext(input) %in% c("png", "jpeg", "jpg", "webp", "heic", "heif"))) {
61+
!file.exists(input) ||
62+
!(tools::file_ext(input) %in% c("png", "jpeg", "jpg", "webp", "heic", "heif"))) {
6363
stop("Input must be a single valid image file path (png, jpeg, jpg, webp, heic, heif) when type is 'figure'.")
6464
}
6565
# Determine image type

R/gen_docs.R

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
#' @description Generates Roxygen2 documentation for an R function based on the currently selected code.
44
#'
55
#' @param prompt A character string specifying additional instructions for the LLM. Defaults to a prompt requesting Roxygen2 documentation without the original code.
6-
#'
6+
#'
77
#' @return Invisibly returns the generated documentation string, but primarily inserts the text into the RStudio console.
88
#' @examples
99
#' \dontrun{
1010
#' # Select your function code in the editor, then run:
1111
#' gen_docs()
12-
#'
12+
#'
1313
#' # For custom instructions:
1414
#' gen_docs("Generate minimal Roxygen docs for this function")
1515
#' }
16-
#'
16+
#'
1717
#' @importFrom rstudioapi getActiveDocumentContext executeCommand insertText
1818
#' @importFrom cli cli_alert_danger cli_status cli_status_clear
1919
#' @export
@@ -30,7 +30,7 @@ gen_docs <- function(prompt = NULL) {
3030

3131
context <- getActiveDocumentContext()
3232
selectedCode <- context$selection[[1]]$text
33-
33+
3434
# Check if code is selected
3535
if (nchar(trim(selectedCode)) == 0) {
3636
cli_alert_danger("No code selected. Please select an R function to document.")
@@ -39,42 +39,44 @@ gen_docs <- function(prompt = NULL) {
3939

4040
# Show status message
4141
sb <- cli_status("Generating Roxygen documentation...")
42-
42+
4343
# API call and error handling
44-
description <- tryCatch({
45-
result <- gemini(
46-
prompt = paste0(
47-
prompt,
48-
"\n---",
49-
selectedCode
44+
description <- tryCatch(
45+
{
46+
result <- gemini(
47+
prompt = paste0(
48+
prompt,
49+
"\n---",
50+
selectedCode
51+
)
5052
)
51-
)
52-
53-
if (is.null(result) || length(result) == 0 || nchar(trim(result)) == 0) {
53+
54+
if (is.null(result) || length(result) == 0 || nchar(trim(result)) == 0) {
55+
cli_status_clear(id = sb)
56+
cli_alert_danger("Failed to generate documentation or received empty response.")
57+
return(invisible(NULL))
58+
}
59+
60+
result
61+
},
62+
error = function(e) {
5463
cli_status_clear(id = sb)
55-
cli_alert_danger("Failed to generate documentation or received empty response.")
64+
cli_alert_danger(paste0("Error generating documentation: ", e$message))
5665
return(invisible(NULL))
5766
}
58-
59-
result
60-
},
61-
error = function(e) {
62-
cli_status_clear(id = sb)
63-
cli_alert_danger(paste0("Error generating documentation: ", e$message))
64-
return(invisible(NULL))
65-
})
66-
67+
)
68+
6769
# Early exit if error occurred
6870
if (is.null(description)) {
6971
return(invisible(NULL))
7072
}
71-
73+
7274
cli_status_clear(id = sb)
73-
75+
7476
# Insert result into console if available
7577
executeCommand("activateConsole")
7678
insertText(text = description)
77-
79+
7880
# Return generated documentation invisibly
7981
return(invisible(description))
8082
}

R/gen_image.R

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ gen_image <- function(prompt, filename = "gemini_image.png", overwrite = TRUE,
3333
if (!validate_params(prompt, model, temperature, topP, topK, seed, api_key = TRUE)) {
3434
return(NULL)
3535
}
36-
36+
3737
# Check if the model is for image generation
3838
if (model != "2.0-flash-exp-image-generation") {
3939
cli_alert_danger("Error: For image generation, model must be '2.0-flash-exp-image-generation'")
@@ -48,59 +48,65 @@ gen_image <- function(prompt, filename = "gemini_image.png", overwrite = TRUE,
4848

4949
# Generate the image
5050
sb <- cli_status("Generating image with Gemini...")
51-
51+
5252
# 2. Add error handling for response
53-
response <- tryCatch({
54-
gemini(
55-
prompt = prompt,
56-
model = model,
57-
temperature = temperature,
58-
maxOutputTokens = maxOutputTokens,
59-
topK = topK,
60-
topP = topP,
61-
seed = seed
62-
)
63-
}, error = function(e) {
64-
cli_status_clear(id = sb)
65-
cli_alert_danger(paste("Error generating image:", e$message))
66-
return(NULL)
67-
})
68-
53+
response <- tryCatch(
54+
{
55+
gemini(
56+
prompt = prompt,
57+
model = model,
58+
temperature = temperature,
59+
maxOutputTokens = maxOutputTokens,
60+
topK = topK,
61+
topP = topP,
62+
seed = seed
63+
)
64+
},
65+
error = function(e) {
66+
cli_status_clear(id = sb)
67+
cli_alert_danger(paste("Error generating image:", e$message))
68+
return(NULL)
69+
}
70+
)
71+
6972
# 3. Handle case when response is NULL
7073
if (is.null(response)) {
7174
cli_status_clear(id = sb)
7275
cli_alert_danger("Failed to generate image - no response received")
7376
return(NULL)
7477
}
75-
78+
7679
cli_status_clear(id = sb)
7780

7881
# 4. Add validation for response structure
7982
if (length(response) < 2) {
8083
cli_alert_danger("Invalid response format - missing image data")
8184
return(NULL)
8285
}
83-
86+
8487
# 5. Improve error handling for file saving
85-
tryCatch({
86-
# Extract image data part (second element)
87-
base64_data <- response[2]
88-
89-
# Add check for empty data
90-
if (is.null(base64_data) || nchar(base64_data) == 0) {
91-
cli_alert_danger("Empty image data received")
88+
tryCatch(
89+
{
90+
# Extract image data part (second element)
91+
base64_data <- response[2]
92+
93+
# Add check for empty data
94+
if (is.null(base64_data) || nchar(base64_data) == 0) {
95+
cli_alert_danger("Empty image data received")
96+
return(NULL)
97+
}
98+
99+
# Base64 decode
100+
image_data <- base64enc::base64decode(base64_data)
101+
102+
# Write file
103+
writeBin(image_data, filename)
104+
cli_alert_success(paste("Image saved to", filename))
105+
return(filename)
106+
},
107+
error = function(e) {
108+
cli_alert_danger(paste("Error saving image:", e$message))
92109
return(NULL)
93110
}
94-
95-
# Base64 decode
96-
image_data <- base64enc::base64decode(base64_data)
97-
98-
# Write file
99-
writeBin(image_data, filename)
100-
cli_alert_success(paste("Image saved to", filename))
101-
return(filename)
102-
}, error = function(e) {
103-
cli_alert_danger(paste("Error saving image:", e$message))
104-
return(NULL)
105-
})
111+
)
106112
}

R/gen_tests.R

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#' \dontrun{
1212
#' # Select your function code in the editor, then run:
1313
#' gen_tests()
14-
#'
14+
#'
1515
#' # For custom instructions:
1616
#' gen_tests("Generate comprehensive testthat tests with edge cases")
1717
#' }
@@ -32,19 +32,22 @@ gen_tests <- function(prompt = NULL) {
3232
}
3333

3434
# Get selected code from the editor
35-
context <- tryCatch({
36-
getActiveDocumentContext()
37-
}, error = function(e) {
38-
cli_alert_danger("Failed to get active document context: ", e$message)
39-
return(NULL)
40-
})
41-
35+
context <- tryCatch(
36+
{
37+
getActiveDocumentContext()
38+
},
39+
error = function(e) {
40+
cli_alert_danger("Failed to get active document context: ", e$message)
41+
return(NULL)
42+
}
43+
)
44+
4245
if (is.null(context)) {
4346
return(invisible(NULL))
4447
}
45-
48+
4649
selectedCode <- context$selection[[1]]$text
47-
50+
4851
# Check if code is selected
4952
if (is.null(selectedCode) || nchar(trim(selectedCode)) == 0) {
5053
cli_alert_danger("No code selected. Please select an R function to generate tests for.")
@@ -53,46 +56,51 @@ gen_tests <- function(prompt = NULL) {
5356

5457
# Show status message
5558
sb <- cli_status("Generating unit tests...")
56-
59+
5760
# API call and error handling
58-
test_code <- tryCatch({
59-
result <- gemini(
60-
prompt = paste0(
61-
prompt,
62-
"\n---\n",
63-
selectedCode
61+
test_code <- tryCatch(
62+
{
63+
result <- gemini(
64+
prompt = paste0(
65+
prompt,
66+
"\n---\n",
67+
selectedCode
68+
)
6469
)
65-
)
66-
67-
if (is.null(result) || length(result) == 0 || nchar(trim(result)) == 0) {
70+
71+
if (is.null(result) || length(result) == 0 || nchar(trim(result)) == 0) {
72+
cli_status_clear(id = sb)
73+
cli_alert_danger("Failed to generate test code or received empty response.")
74+
return(invisible(NULL))
75+
}
76+
77+
result
78+
},
79+
error = function(e) {
6880
cli_status_clear(id = sb)
69-
cli_alert_danger("Failed to generate test code or received empty response.")
81+
cli_alert_danger(paste0("Error generating test code: ", e$message))
7082
return(invisible(NULL))
7183
}
72-
73-
result
74-
},
75-
error = function(e) {
76-
cli_status_clear(id = sb)
77-
cli_alert_danger(paste0("Error generating test code: ", e$message))
78-
return(invisible(NULL))
79-
})
80-
84+
)
85+
8186
# Early exit if error occurred
8287
if (is.null(test_code)) {
8388
return(invisible(NULL))
8489
}
85-
90+
8691
cli_status_clear(id = sb)
87-
92+
8893
# Insert test code into the console
89-
tryCatch({
90-
executeCommand("activateConsole")
91-
insertText(text = test_code)
92-
}, error = function(e) {
93-
cli_alert_danger(paste0("Failed to insert text into console: ", e$message))
94-
})
95-
94+
tryCatch(
95+
{
96+
executeCommand("activateConsole")
97+
insertText(text = test_code)
98+
},
99+
error = function(e) {
100+
cli_alert_danger(paste0("Failed to insert text into console: ", e$message))
101+
}
102+
)
103+
96104
# Return generated test code invisibly
97105
return(invisible(test_code))
98106
}

R/setAPI.R

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ setAPI <- function(api_key) {
1919
cli_alert_danger("API key must be a non-empty string.")
2020
return(invisible())
2121
}
22-
22+
2323
# Check typical API key length (Google API keys are usually 39 characters)
2424
if (nchar(api_key) < 10) {
2525
cli_alert_danger("API key seems too short. Please verify your key.")
2626
return(invisible())
2727
}
28-
28+
2929
# Safely display only the last part of the API key
3030
last_chars <- 4
3131
if (nchar(api_key) > last_chars) {
@@ -34,7 +34,7 @@ setAPI <- function(api_key) {
3434
# If the API key is too short, show only the last character
3535
last <- substr(api_key, nchar(api_key), nchar(api_key))
3636
}
37-
37+
3838
# Set environment variable
3939
Sys.setenv(GEMINI_API_KEY = api_key)
4040

@@ -44,6 +44,6 @@ setAPI <- function(api_key) {
4444
cli_end()
4545

4646
cli_alert("You may try {.run gemini_chat('What is CRAN?')}")
47-
47+
4848
return(invisible())
4949
}

0 commit comments

Comments
 (0)