Before creating a new target type, the first step is to create all of the target type's fields.
## Defining a Field
To define a new field:
Subclass one of the below field templates, like `
IntField
` or `BoolField
`; or, subclass an existing field, like `SingleSourceField
`.Set the class property `
alias
`. This is the symbol that people use in BUILD files.Set the class property `
help
`. This is used by `./pants help
`.
For example:
### `default
`
The `default
` is used whenever a user does not explicitly specify the field in a BUILD file.
If you don't override this property, `default
` will be set to `None
`, which signals that the value was undefined.
### `required
`
Set `required = True
` to require explicitly defining the field.
If you set `required = True
`, the `default
` will be ignored.
Reminder: subclass existing fields to modify their behavior
If you want to change how an existing field behaves, you should subclass the original field. For example, if you want to change a default value, subclass the original field. When doing this, you only need to override the properties you want to change.
See [Concepts](🔗) for how subclassing plays a key role in the Target API.
## Adding custom validation
The field templates will validate that users are using the correct _types_, like ints or strings. But you may want to add additional validation, such as banning certain values.
To do this, override the classmethod `compute_value
`:
Be careful to use the same type hint for the parameter `raw_value
` as used in the template. This is used to generate the documentation in `./pants help my_target
`.
Cannot use new type hint syntax with `
compute_value()
` and `default
`You cannot use the [new type hint syntax](🔗) with the Target API, i.e. `
list[str] | None
` instead of `Optional[List[str]]
`. The new syntax breaks `./pants help
`.Otherwise, it's safe to use the new syntax when writing plugins.
## Available templates
All templates are defined in `pants.engine.target
`.
### `BoolField
`
Use this when the option is a boolean toggle. You must either set `required = True
` or set `default
` to `False
` or `True
`.
### `TriBoolField
`
This is like `BoolField
`, but allows you to use `None
` to represent a third state. You do not have to set `required = True
` or `default
`, as the field template defaults to `None
` already.
### `IntField
`
Use this when you expect an integer. This will reject floats.
### `FloatField
`
Use this when you expect a float. This will reject integers.
### `StringField
`
Use this when you expect a single string.
`
StringField
` can be like an enumYou can set the class property `
valid_choices
` to limit what strings are acceptable. This class property can either be a tuple of strings or an `enum.Enum
`.For example:
or:
### `StringSequenceField
`
Use this when you expect 0-n strings.
The user may use a tuple, set, or list in their BUILD file; Pants will convert the value to an immutable tuple.
### `SequenceField
`
Use this when you expect a homogenous sequence of values other than strings, such as a sequence of integers.
The user may use a tuple, set, or list in their BUILD file; Pants will convert the value to an immutable tuple.
You must set the class properties `expected_element_type
` and `expected_type_description
`. You should also change the type signature of the classmethod `compute_value
` so that Pants can show the correct types when running `./pants help $target_type
`.
### `DictStringToStringField
`
Use this when you expect a dictionary of string keys with strings values, such as `{"k": "v"}
`.
The user may use a normal Python dictionary in their BUILD file. Pants will convert this into an instance of `pants.util.frozendict.FrozenDict
`, which is a lightweight wrapper around the native `dict
` type that simply removes all mechanisms to mutate the dictionary.
### `DictStringToStringSequenceField
`
Use this when you expect a dictionary of string keys with a sequence of strings values, such as `{"k": ["v1", "v2"]}
`.
The user may use a normal Python dictionary in their BUILD file, and they may use a tuple, set, or list for the dictionary values. Pants will convert this into an instance of `pants.util.frozendict.FrozenDict
`, which is a lightweight wrapper around the native `dict
` type that simply removes all mechanisms to mutate the dictionary. Pants will also convert the values into immutable tuples, resulting in a type hint of `FrozenDict[str, Tuple[str, ...]]
`.
### `Field
` - the fallback class
If none of these templates work for you, you can subclass `Field
`, which is the superclass of all of these templates.
You must give a type hint for `value
`, define the classmethod `compute_value
`, and either set `required = True
` or define the class property `default
`.
For example, we could define a `StringField
` explicitly like this:
Asking for help
Have a tricky field you're trying to write? We would love to help! See [Getting Help](🔗).