From e0d73be06f671943c062c3f0a2e2ef0ee2524b29 Mon Sep 17 00:00:00 2001 From: Carlo Baldassi Date: Mon, 20 Jan 2020 21:35:57 +0100 Subject: [PATCH 1/4] Default to not exiting julia from REPL Change defaults so that when isinteractive() is true we don't call exit() and the package can be used from the REPL. Fix #79 Fix #83 --- src/parsing.jl | 8 ++++++-- src/settings.jl | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/parsing.jl b/src/parsing.jl index f5ea25f..a3fe5a3 100644 --- a/src/parsing.jl +++ b/src/parsing.jl @@ -280,7 +280,7 @@ end show_help(settings::ArgParseSettings; kw...) = show_help(stdout, settings; kw...) -function show_help(io::IO, settings::ArgParseSettings; exit_when_done = true) +function show_help(io::IO, settings::ArgParseSettings; exit_when_done = !isinteractive()) lc_len_limit = 24 lc_left_indent = 2 @@ -369,7 +369,7 @@ end show_version(settings::ArgParseSettings; kw...) = show_version(stdout, settings; kw...) -function show_version(io::IO, settings::ArgParseSettings; exit_when_done = true) +function show_version(io::IO, settings::ArgParseSettings; exit_when_done = !isinteractive()) println(io, settings.version) exit_when_done && exit(0) return @@ -379,6 +379,10 @@ has_cmd(settings::ArgParseSettings) = any(is_cmd, settings.args_table.fields) # parse_args & friends function default_handler(settings::ArgParseSettings, err, err_code::Int = 1) + isinteractive() ? debug_handler(settings, err) : cmdline_handler(settings, err, err_code) +end + +function cmdline_handler(settings::ArgParseSettings, err, err_code::Int = 1) println(stderr, err.text) println(stderr, usage_string(settings)) exit(err_code) diff --git a/src/settings.jl b/src/settings.jl index 2c3f602..0cbb843 100644 --- a/src/settings.jl +++ b/src/settings.jl @@ -171,21 +171,24 @@ This is the list of general settings currently available: * `exc_handler` (default = `ArgParse.default_handler`): this is a function which is invoked when an error is detected during parsing (e.g. an option is not recognized, a required argument is not passed etc.). It takes two arguments: the `settings::ArgParseSettings` object and the - `err::ArgParseError` exception. The default handler prints the error text and the usage screen on - standard error and exits with error code 1: + `err::ArgParseError` exception. The default handler behaves differently depending on whether it's + invoked from a script or in an interactive environment (e.g. REPL/IJulia). In non-interactive + (script) mode, it calls `ArgParse.cmdline_handler`, which prints the error text and the usage + screen on standard error and exits Julia with error code 1: ```julia - function default_handler(settings::ArgParseSettings, err, err_code::Int = 1) + function cmdline_handler(settings::ArgParseSettings, err, err_code::Int = 1) println(stderr, err.text) println(stderr, usage_string(settings)) exit(err_code) end ``` - The module also provides a function `ArgParse.debug_handler` (not exported) which will just - rethrow the error. -* `exit_after_help` (default = `true`): exits Julia (with error code `0`) when the `:show_help` or - `:show_version` actions are triggered. If `false`, those actions will just stop the parsing and - make `parse_args` return `nothing`. + + In interactive mode instead it calls the function `ArgParse.debug_handler`, which just rethrows + the error. +* `exit_after_help` (default = `!isinteractive()`): exit Julia (with error code `0`) when the + `:show_help` or `:show_version` actions are triggered. If `false`, those actions will just stop + the parsing and make `parse_args` return `nothing`. Here is a usage example: @@ -259,7 +262,7 @@ mutable struct ArgParseSettings exc_handler::Function = default_handler, preformatted_description::Bool = false, preformatted_epilog::Bool = false, - exit_after_help::Bool = true + exit_after_help::Bool = !isinteractive() ) fromfile_prefix_chars = check_prefix_chars(fromfile_prefix_chars) return new( From 20b252e9ed74062916fee973449aea6ec77d1e4d Mon Sep 17 00:00:00 2001 From: Carlo Baldassi Date: Mon, 20 Jan 2020 23:45:41 +0100 Subject: [PATCH 2/4] Renamed import_settings -> import_settings! --- README.md | 1 + src/ArgParse.jl | 2 +- src/settings.jl | 19 +++++++++++++------ test/argparse_test04.jl | 6 +++--- test/argparse_test05.jl | 2 +- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7c994e4..eea3b66 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ See also the examples in the [examples directory](examples). ## Changes in release 1.0.0 * Drop support for Julia versions v0.6/v0.7 +* Renamed function `import_settings` → `import_settings!` ## Changes in release 0.6.2 diff --git a/src/ArgParse.jl b/src/ArgParse.jl index 8a36f5d..136ce4f 100644 --- a/src/ArgParse.jl +++ b/src/ArgParse.jl @@ -23,7 +23,7 @@ export @add_arg_table, add_arg_group, set_default_arg_group, - import_settings, + import_settings!, usage_string, parse_args diff --git a/src/settings.jl b/src/settings.jl index 0cbb843..e3b2506 100644 --- a/src/settings.jl +++ b/src/settings.jl @@ -1153,7 +1153,7 @@ function set_default_arg_group(settings::ArgParseSettings, name::Union{AbstractS return end -# import_settings & friends +# import_settings! & friends function override_conflicts_with_commands(settings::ArgParseSettings, new_cmd::AbstractString) ids0 = Int[] for ia in 1:length(settings.args_table.fields) @@ -1273,8 +1273,15 @@ function fix_commands_fields(fields::Vector{ArgParseField}) end end +# TODO: remove after minor version bump +export import_settings +function import_settings(args...; kw...) + @warn "`import_settings` is depreacted, use `import_settings!`" + import_settings!(args...; kw...) +end + """ - import_settings(settings, other_settings [,args_only]) + import_settings!(settings, other_settings [,args_only]) Imports `other_settings` into `settings`, where both are [`ArgParseSettings`](@ref) objects. If `args_only` is `true` (this is the default), only the argument table will be imported; otherwise, @@ -1296,9 +1303,9 @@ will not have any effect on `settings`. This function can be used at any time. """ -function import_settings(settings::ArgParseSettings, - other::ArgParseSettings, - args_only::Bool = true) +function import_settings!(settings::ArgParseSettings, + other::ArgParseSettings, + args_only::Bool = true) check_settings_are_compatible(settings, other) fields = settings.args_table.fields @@ -1359,7 +1366,7 @@ function import_settings(settings::ArgParseSettings, elseif !isempty(cmd_prog_hint) settings[subk].prog = "$(settings.prog) $cmd_prog_hint" end - import_settings(settings[subk], subs, args_only) + import_settings!(settings[subk], subs, args_only) end return settings end diff --git a/test/argparse_test04.jl b/test/argparse_test04.jl index 97c4382..e8b80ad 100644 --- a/test/argparse_test04.jl +++ b/test/argparse_test04.jl @@ -25,7 +25,7 @@ function ap_settings4() error_on_conflict = false, # do not error-out when trying to override an option exc_handler = ArgParse.debug_handler) - import_settings(s, s0) # now s has all of s0 arguments (except help/version) + import_settings!(s, s0) # now s has all of s0 arguments (except help/version) @add_arg_table s begin "-o" # this will partially override s0's --parent-flag @@ -69,7 +69,7 @@ function ap_settings4b() s = ArgParseSettings("Test 4 for ArgParse.jl", version = "Version 1.0") - import_settings(s, s0, false) # args_only set to false + import_settings!(s, s0, false) # args_only set to false @add_arg_table s begin "-o" @@ -172,7 +172,7 @@ end let s = ap_settings4_base() for s0 = [ap_settings4_conflict1(), ap_settings4_conflict2()] - @ee_test_throws import_settings(s, s0) + @ee_test_throws import_settings!(s, s0) end end diff --git a/test/argparse_test05.jl b/test/argparse_test05.jl index 19dfac7..e811778 100644 --- a/test/argparse_test05.jl +++ b/test/argparse_test05.jl @@ -259,7 +259,7 @@ function ap_settings5b() action = :store_true end - import_settings(s, s0) + import_settings!(s, s0) return s end From 3d1890ccdbe269a10b5c688f45c5de745f231ced Mon Sep 17 00:00:00 2001 From: Carlo Baldassi Date: Tue, 21 Jan 2020 00:22:51 +0100 Subject: [PATCH 3/4] Small cosmetic fixes --- src/parsing.jl | 6 +++--- src/settings.jl | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/parsing.jl b/src/parsing.jl index a3fe5a3..d349b48 100644 --- a/src/parsing.jl +++ b/src/parsing.jl @@ -115,9 +115,9 @@ function usage_string(settings::ArgParseSettings) lc_len_limit = 24 - cmd_lst = Any[] - pos_lst = Any[] - opt_lst = Any[] + cmd_lst = String[] + pos_lst = String[] + opt_lst = String[] for f in settings.args_table.fields if is_cmd(f) if !isempty(f.short_opt_name) diff --git a/src/settings.jl b/src/settings.jl index e3b2506..7ea420e 100644 --- a/src/settings.jl +++ b/src/settings.jl @@ -280,8 +280,8 @@ ArgParseSettings(desc::AbstractString; kw...) = ArgParseSettings(; description = function show(io::IO, s::ArgParseSettings) println(io, "ArgParseSettings(") - for f in setdiff(fieldnames(ArgParseSettings), ) - f ∈ [:args_groups, :args_table] && continue + for f in fieldnames(ArgParseSettings) + f ∈ (:args_groups, :args_table) && continue println(io, " ", f, "=", getfield(s, f)) end println(io, " >> ", usage_string(s)) From 424cf87e83b641571adace1d3e34bb5dd07ced40 Mon Sep 17 00:00:00 2001 From: Carlo Baldassi Date: Tue, 21 Jan 2020 18:50:00 +0100 Subject: [PATCH 4/4] Updated README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index eea3b66..4cfc6af 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ See also the examples in the [examples directory](examples). ## Changes in release 1.0.0 * Drop support for Julia versions v0.6/v0.7 +* Parsing does not exit julia by default when in interactive mode now * Renamed function `import_settings` → `import_settings!` ## Changes in release 0.6.2