Comonicon 1.0 release: probably the best CLI generator in Julia

The Comonicon package has been stable for quite a while, and after 64 versions including 12 minor versions and 18 patch versions for the last minor version (v0.12), I believe its public interface and APIs have reached a relatively stable stage.

In the past few years, quite a few early users have been using Comonicon for their own scripts, and CLI tools in various cases, and we have been improving the experience on various Linux platforms and macOS (unfortunately, due to my personal knowledge limitation, the support on Windows will keep be in low priority)

Besides the previous posts (Comonicon: Pre-1.0 release, Comonicon.jl - Fast, Simple and Light weight CLI generator), the new version mainly contains several bug fixes and one new feature worth mentioning

Keyword Argument with option type from Configurations.jl

This feature has been proposed a few times in slack and GitHub, and thanks to @avikpal 's new package SimpleConfig’s inspiration, I finally decide to implement this. You can find more use case description in this package’s README.

In numerical experiments and machine learning tasks, one often encounters the following use case:

  • a configuration file defines some hyperparameter of the experiment that needs to be read by a CLI application
  • one may want to temporarily modify a few hyperparameters defined inside the file from the CLI

Now Comonicon allows you to do the following, if you have a configuration schema defined using @option from Configurations package. Comonicon will understand it and provide a corresponding CLI as following example shows

using Test
using Comonicon
using Configurations

@option struct OptionA

@option struct OptionB

# Options

- `-c, --config <path/to/option/or/specific field>`: config.
@main function run(;config::OptionB)
    @test config == OptionB(OptionA(1, 1), 1)
command --config.c=1 --config.option.a=1 --config.option.b=1
command --config=config.toml
command -c config.toml
command -c config.toml --config.option.b=2 # change a field of config.toml

Lazy Module Loading for Scripts

In scripts, one can avoid huge latency impact by lazily load different module for different commands, this is supported in top-level using @lazyload macro. This feature improves the latency a lot for scripts that use large conditional dependencies such as CUDA, Plots etc (thanks to @GiggleLiu).

using Comonicon

@lazyload using Random @cast function random()
    isdefined(Main, :Random) && println("Random is loaded")
    isdefined(Main, :LinearAlgebra) && println("LinearAlgebra is loaded")

@lazyload using Random, LinearAlgebra @cast function both()
    isdefined(Main, :Random) && println("Random is loaded")
    isdefined(Main, :LinearAlgebra) && println("LinearAlgebra is loaded")

# this will throw an error
@cast function none()
    isdefined(Main, :Random) && println("Random is loaded")
    isdefined(Main, :LinearAlgebra) && println("LinearAlgebra is loaded")


# You will see the following output if you run this script.
# shell> julia --project example/lazyload.jl random
# Random is loaded

# shell> julia --project example/lazyload.jl both
# Random is loaded
# LinearAlgebra is loaded

# shell> julia --project example/lazyload.jl none

Breaking Changes since v0.12

We stop generating -V option as a shorthand for --version based on the discussion here

Finally, I’d like to thank everyone who has been contributing and helping improve this package, the 1.0 release is definitely not an end, but is a start. There are more things that can be done with this and I’m looking forward to having some of them in 1.x and 2.0 (if there are breaks)