Problem
There are several unique constraints and expectations for @rule definitions which are entirely left for the rule author to enforce, such as:
- Ensuring the
rule's input / output types are immutable.
- 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).
- 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:
- Catches the use of any non-frozen dataclasses as inputs and/or outputs.
- 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))
- Catches
print statements, and any other very obvious side effect-producing statements in a rule body.
- 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.
Problem
There are several unique constraints and expectations for
@ruledefinitions which are entirely left for the rule author to enforce, such as:rule's input / output types are immutable.ruleare calculated deterministically (for example, sorting atupleconstructed from asetbefore assigning said tuple to an output object's attribute).ruledoes 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
@ruleconstraints 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
@ruledefinitions through static analysis, which a user could invoke through something like:A non-exhaustive list of some issues which this toolset could hypothetically catch and prevent through static analysis:
printstatements, and any other very obvious side effect-producing statements in arulebody.openorpathlib.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
ruffrules; however, that seems more burdensome for both pantsbuild and ruff maintainers than simply maintaining this tooling within the pantsbuild repo itself.