Skip to main content
Version: 2.7 (deprecated)

Plugin upgrade guide

How to adjust for changes made to the Plugin API.


PrimitiveField and AsyncField are removed (2.2.0.dev0)

Rather than subclassing PrimitiveField, subclass Field directly. Field now behaves like PrimitiveField used to, and PrimitiveField was removed for simplicity.

Rather than subclassing AsyncField or AsyncStringSequenceField, subclass Field or a template like StringField and also subclass AsyncFieldMixin:

from import AsyncFieldMixin, StringField)

class MyField(StringField, AsyncFieldMixin):
alias = "my_field"
help = "Description."

Async fields now access the raw value with the property .value, rather than .sanitized_raw_value. To override the eager validation, override compute_value(), rather than sanitize_raw_value(). Both these changes bring async fields into alignment with non-async fields.

Set the property help with Subsystems, Targets, and Fields (2.2.0.dev3)

Previously, you were supposed to set the class's docstring for the ./pants help message. Instead, now set a class property help, like this:

class MyField(StringField):
alias = "my_field"
help = "A summary.\n\nOptional extra information."

Pants will now properly wrap strings and preserve newlines. You may want to run ./pants help ${target/subsystem} to verify things render properly.


See for the changelog.

SourcesSnapshot is now SpecsSnapshot (2.1.0rc0)

The type was renamed for clarity. Still import it from pants.engine.fs.


See for the changelog.

Use TransitiveTargetsRequest as input for resolving TransitiveTargets (2.0.0rc0)

Rather than await Get(TransitiveTargets, Addresses([addr1])), use await Get(TransitiveTargets, TransitiveTargetsRequest([addr1])), from

It's no longer possible to include TransitiveTargets in your @rule signature in order to get the transitive closure of what the user specified on the command. Instead, put Addresses in your rule's signature, and use await Get(TransitiveTargets, TransitiveTargetsRequest(addresses)).

Codegen implementations: use DependenciesRequestLite and TransitiveTargetsLite (2.0.0rc0)

Due to a new cycle in the rule graph, for any codegen implementations, you must use DependenciesRequestLite instead of DependenciesRequest, and TransitiveTargetsLite instead of TransitiveTargetsRequest. Both imports are still from

These behave identically, except that they do not include dependency inference in the results. Unless you are generating for input = PythonSources, this should be fine, as dependency inference is currently only used with Python.

This is tracked by

Dependencies-like fields have more robust support (2.0.0rc0)

If you have any custom fields that act like the dependencies field, but do not subclass Dependencies, there are two new mechanisms for better support.

  1. Instead of subclassing StringSequenceField, subclass SpecialCasedDependencies from This will ensure that the dependencies show up with ./pants dependencies and ./pants dependees.
  2. You can use UnparsedAddressInputs from pants.engine.addresses to resolve the addresses:
from pants.engine.addresses import Address, Addresses, UnparsedAddressedInputs
from import Targets


addresses = await Get(Addresses, UnparsedAddressedInputs(["//:addr1", "project/addr2"], owning_address=None)

# Or, use this.
targets = await Get(
UnparsedAddressedInputs(["//:addr1", "project/addr2"], owning_address=Address("project", target_name="original")

If you defined a subclass of SpecialCasedDependencies, you can use await Get(Addresses | Targets, UnparsedAddressInputs, my_tgt[MyField].to_unparsed_address_inputs()).

(Why would you ever do this? If you have dependencies that you don't treat like normal—e.g. that you will call the equivalent of ./pants package on those deps—it's often helpful to call out this magic through a dedicated field. For example, Pants's archive target type has the fields files and packages, rather than dependencies.)

package implementations may want to add the field output_path (2.0.0rc0)

All of Pants's target types that can be built via ./pants package now have an output_path field, which allows the user to override the path used for the created asset.

You optionally may want to add this output_path field to your custom target type for consistency:

  1. Include OutputPathField from pants.core.goals.package in your target's core_fields class property.
  2. In your PackageFieldSet subclass, include output_path: OutputPathField.
  3. When computing the filename in your rule, use my_package_field_set.output_path.value_or_default(field_set.address, file_ending="my_ext").