Skip to content

Commit

Permalink
refactor: Make parse errors less verbose
Browse files Browse the repository at this point in the history
* The errors raised by `ArgumentParser()$parse_args()` are now of class "argparse_parse_error".

  They are now less verbose when `interactive()` is `FALSE` (#40).

  There may still a trailing "Execution halted" line output by R's default error handler
  (when `interactive()` is `FALSE`).
  This can be silenced by setting a new error handler near the top of your Rscript e.g.

  ```r
  if (!interactive())
      options(error=function(e) quit('no', status = 1, runLast = FALSE))
  ```

closes #40
  • Loading branch information
trevorld committed Jul 17, 2022
1 parent 9185b12 commit 2cf5429
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 16 deletions.
6 changes: 4 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: argparse
Type: Package
Title: Command Line Optional and Positional Argument Parser
Version: 2.1.5
Authors@R: c(person("Trevor L", "Davis", role=c("aut", "cre"),
Version: 2.1.6
Authors@R: c(person("Trevor L", "Davis", role=c("aut", "cre"),
email="[email protected]",
comment = c(ORCID = "0000-0001-6341-4639")),
person("Allen", "Day", role="ctb", comment="Some documentation and examples ported from the getopt package."),
Expand All @@ -16,6 +16,8 @@ Copyright: See file (inst/)COPYRIGHTS.
URL: https://github.com/trevorld/r-argparse
BugReports: https://github.com/trevorld/r-argparse/issues
LazyLoad: yes
Depends:
R (>= 3.6.0)
Imports:
R6,
findpython,
Expand Down
16 changes: 16 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
argparse 2.1.6
==============

* The errors raised by `ArgumentParser()$parse_args()` are now of class "argparse_parse_error".

They are now less verbose when `interactive()` is `FALSE` (#40).

There may still a trailing "Execution halted" line output by R's default error handler
(when `interactive()` is `FALSE`).
This can be silenced by setting a new error handler near the top of your Rscript e.g.

```r
if (!interactive())
options(error=function(e) quit('no', status = 1, runLast = FALSE))
```

argparse 2.1.5
==============

Expand Down
34 changes: 23 additions & 11 deletions R/argparse.R
Original file line number Diff line number Diff line change
Expand Up @@ -202,27 +202,27 @@ parse_args_output <- function(output) {
has_positional_arguments <- any(grepl("^positional arguments:", output))
has_optional_arguments <- any(grepl("^optional arguments:|^options:", output))
if (has_positional_arguments || has_optional_arguments) {
.print_message_and_exit(output, "help requested:")
print_message_and_exit(output, "help requested:")
} else {
.stop(output, "parse error:")
pa_stop(output)
}
} else if (grepl("^Traceback", output[1])) {
.stop(output, "Error: python error")
pa_stop(output)
} else if (any(grepl("^SyntaxError: Non-ASCII character", output))) {
message <- paste("Non-ASCII character detected.",
"If you wish to use Unicode arguments/options",
"please upgrade to Python 3.2+",
"Please see file INSTALL for more details.")
.stop(message, "non-ascii character error:")
pa_stop(message)
} else if (any(grepl("^SyntaxError: positional argument follows keyword argument", output)) ||
grepl("^SyntaxError: non-keyword arg after keyword arg", output[2])) {
message <- "Positional argument following keyword argument."
.stop(message, "syntax error:")
pa_stop(message)
} else if (grepl("^\\{|^\\[", output)) {
args <- jsonlite::fromJSON(paste(output, collapse = ""))
return(args)
} else { # presumably version number request
.print_message_and_exit(output, "version requested:")
print_message_and_exit(output, "version requested:")
}
}

Expand Down Expand Up @@ -358,16 +358,28 @@ find_python_cmd <- function(python_cmd = NULL) {
python_cmd
}

.stop <- function(message, r_note) {
stop(paste(r_note, paste(message, collapse = "\n"), sep = "\n"))
pa_stop <- function(message) {
msg <- paste(c("argparse_parse_error", message), collapse = "\n")
cnd <- errorCondition(msg,
call = "argparse::parse_args_output(output)",
class = "argparse_parse_error")
if (interactive()) {
stop(cnd)
} else {
signalCondition(cnd)
cat(message, sep = "\n", file = stderr())
opt <- options(show.error.messages = FALSE)
on.exit(options(opt))
stop(cnd)
}
}

# Internal function to print message
.print_message_and_exit <- function(message, r_note) {
print_message_and_exit <- function(message, r_note, status = 0) {
if (interactive()) {
.stop(message, r_note)
pa_stop(message, r_note)
} else {
cat(message, sep = "\n")
quit(status = 0)
quit(status = status)
}
}
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ as well as mutually exclusive groups::
$foo
[1] FALSE
> parser$parse_args(c('--foo', '--bar'))
Error in .stop(output, "parse error:") : parse error:
Error in "argparse::parse_args_output(output)" : parse error:
usage: PROG [-h] [--foo | --bar]
PROG: error: argument --bar: not allowed with argument --foo

Expand Down
4 changes: 2 additions & 2 deletions cran-comments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
Rscript) if ``parse_args()`` observes a help flag it will print a usage
message and then call ``quit()``. Additionally if a user specifically adds
a 'version' argument to the command-line parser with `action='version'` then
if ``parse_args()`` also observes a version flag while in a non-interactive
if ``parse_args()`` observes a version flag while in a non-interactive
session then it will print the version number and then call ``quit()``.

* This package has a Python dependency most easily satisfied having (C)Python
3.2 or greater on the PATH. See file INSTALL for more details.

## Test environments

* local (linux), R 4.1.3
* local (linux), R 4.2.1
* win-builder (windows), R devel
* Github Actions (linux), R devel, release, oldrel
* Github Actions (windows), R release
Expand Down

0 comments on commit 2cf5429

Please sign in to comment.