Options and subsystems¶
Defining options¶
As explained in Options, options are partitioned into named scopes, like [test] and [isort]. Each of these scopes corresponds to a subsystem.
To add new options:
- Define a subclass of
Subsystemfrompants.subsystem.subsystem. - Set the class property
options_scopewith the name of the subsystem.- This value will be prepended to all options in the subsystem, e.g.
--skipwill become--shellcheck-skip.
- This value will be prepended to all options in the subsystem, e.g.
- Set the class property
help, which is used bypants help. - Add new options through
pants.options.option_typesclass attributes. - Register the
SubsystemwithSubsystem.rules()andregister.py. - You don't need
Subsystem.rules()if theSubsystemis used in an@rulebecausecollect_rules()will recognize it. It doesn't hurt to keep this around, though.
from pants.option.option_types import BoolOption
from pants.option.subsystem import Subsystem
class ShellcheckSubsystem(Subsystem):
options_scope = "shellcheck"
help = "The Shellcheck linter."
config_discovery = BoolOption(
default=True,
advanced=True,
help="Whether Pants should...",
)
def rules():
return [*ShellcheckSubsystem.rules()]
from example import shellcheck
def rules():
return [*shellcheck.rules()]
The subsystem should now show up when you run pants help shellcheck.
GoalSubsystem
As explained in Goal rules, goals use a subclass of Subsystem: GoalSubsystem from pants.engine.goal.
GoalSubsystem behaves the same way as a normal subsystem, except that you set the class property name rather than options_scope. The name will auto-populate the options_scope.
Option types¶
These classes correspond to the option types at Options.
Every option type requires that you set the keyword argument help.
Most types require that you set default. You can optionally set advanced=True with every option
for it to only show up with help-advanced.
The option name will default to the class attribute name, e.g. my_opt = StrOption() will default to --my-opt.
You can instead pass a string positional argument, e.g. my_opt = StrOption("--different-name").
| Class name | Notes |
|---|---|
StrOption |
Must set default to a str or None. |
BoolOption |
Must set default to a bool or None. TODO Reminder when choosing a flag name: Pants will recognize the command line argument --no-my-flag-name as equivalent to --my-flag-name=false. |
IntOption |
Must set default to an int or None. |
FloatOption |
Must set default to a float or None. |
EnumOption |
This is like StrOption, but with the valid choices constrained to your enum. To use, define an enum.Enum. The values of your enum will be what users can type, e.g. 'kale' and 'spinach' below: python<br>class LeafyGreens(Enum):<br> KALE = "kale"<br> SPINACH = "spinach"<br>You must either set default to a value from your enum or None. If you set default=None, you must set enum_type. title=" |
| List options: - StrListOption- BoolListOption- IntListOption- FloatListOption- EnumListOption |
Default is [] if default is not set. For EnumListOption, you must set the keyword argument enum_type. |
DictOption |
Default is {} if default is not set. Currently, Pants does not offer any validation of the dictionary entries, e.g. dict[str, str] vs dict[str, list[str]]. (Although per TOML specs, the key should always be str.) You may want to add eager validation that users are inputting options the correct way. |
ArgsListOption |
Adds an --args option, e.g. --isort-args. This type is extra useful because it uses a special shell_str that lets users type the arguments as a single string with spaces, which Pants will shlex for them. That is, --args='arg1 arg2' gets converted to ['arg1', 'arg2']. You must set the keyword argument example, e.g. '--arg1 arg2'. You must also set tool_name: str, e.g. 'Black'. You can optionally set passthrough=True if the user should be able to use the style pants my-goal :: -- --arg1, i.e. arguments after --. |
Using options in rules¶
To use a Subsystem or GoalSubsystem in your rule, request it as a parameter. Then, use the class attributes to access the option value.
from pants.engine.rules import rule
...
@rule
async def demo(shellcheck: Shellcheck) -> LintResults:
if shellcheck.skip:
return LintResults()
config_discovery = shellcheck.config_discovery
...
Name clashing
When adding custom options, make sure their name does not start with an existing goal name. For instance, passing a boolean option named check_foobar as --check-foobar in the command line would fail since Pants would think you are trying to pass the --foobar flag in the built-in check goal scope.