quaint-telephone-89068
06/17/2026, 12:52 PM@rule definitions which are entirely left for the rule author to enforce, such as:
1. Ensuring the `rule`'s input / output types are immutable.
2. Ensuring the attributes of an object return from the rule are calculated deterministically (for example, sorting a tuple constructed from a set before assigning said tuple to an output object's attribute).
3. Ensuring the rule does not produce any side effects.
All of these constraints make sense, but increase the mental load for plugin development. Obviously, we cannot detect all possible kinds of violations of these @rule constraints through static code analysis; however, I believe a large number of common mistakes are detectable through static code analysis.
Proposed Solution
Add a builtin linter and/or type checker specifically for validation of @rule definitions through static analysis, which a user could invoke through something like:
pants lint check path/to/plugin/source_root::
A non-exhaustive list of some issues which this toolset could hypothetically catch and prevent through static analysis:
1. Catches the use of any non-frozen dataclasses as inputs and/or outputs.
2. Catches some cases where output instance attribute construction is potentially non-deterministic, for example, the following could potentially be caught:
@rule
def my_rule(..., ...) -> MyFrozenDataClass:
...
# should be changed to tuple(sorted(unordered_item_set))
return MyFrozenDataClass(items=tuple(unordered_item_set))
3. Catches print statements, and any other very obvious side effect-producing statements in a rule body.
4. Catches any obvious attempts to access the file system through unsafe calls like open or pathlib.Path.read_text(...).
Alternatives Considered
I'm not sure if there is a clear alternative, other than hand-writing some of these checks as a suite of unit tests (which I've already done to some small extent for our org's internal development).
One potential alternative would be to contribute these checks as a new set of `ruff` rules; however, that seems more burdensome for both pantsbuild and ruff maintainers than simply maintaining this tooling within the pantsbuild repo itself.
pantsbuild/pants