-
-
Notifications
You must be signed in to change notification settings - Fork 644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve type inference for @rule
s
#17947
Conversation
If this was fast enough, I don't even think we'd need the Edit: which I have as POC in this PR now.. :) |
…ds and methods returning awaitables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very, very cool! And I think that it would probably resolve #16763 in a more general manner.
The idea behind #16763 was to allow for stronger @union
-centric APIs, including allowing Field
s to have computable defaults.
@benjyw and @thejcannon have the most experience with the AST APIs, so I'll defer to them.
I'm not groking whats going on from the PR description. Is it still up-to-date? |
I'm terrible at making up examples. Look at the test case, it shows some of the nifty-ness in this. Edit: I've now updated the PR description.
async def _get_source_root(self) -> SourceRoot:
return await Get(
SourceRoot, SourceRootRequest.for_address(self)
) But it's more than just getting rid of @dataclass
class MyData:
def get_request(self) -> SourceRootRequest:
...
def utility() -> MyData:
return MyData(...)
@rule
async def my_rule() -> ...:
my_data = utility() # or where ever my_data comes from..
source_root = await Get(SourceRoot, my_data.get_request())
... the example doesn't do anything sensible, but consider the possibilities that opens up with this syntax :) |
So this allows anything to be a |
The alleged performance hit would have been a non-starter, so I'm glad that's not actually real... |
bumping this.. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't look too closely at the code. If it works it works IMO.
If/when perf for rule-graph collection is a problem, we can always shift the code into Rust and use RustPython or something similar.
Are we deprecating rule_helper
in this PR or another one?
I've not done that in this PR. I think we can use a dedicated PR for the deprecation, so it has it's own changelog entry. |
@benjy do you have any other concerns, or are we good to go here..? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My one thought is that if we allow unannotated async functions, what is to prevent someone trying to await
one in the normal asyncio way. The annotation was a flag for the reader that this is something special and not a regular asyncio thing.
I'm not sure the rule annotations did much to prevent this either to begin with. A bigger question for me is how you'd end up in a world where you have Pants rules along with code using asyncio (or other async library) in the first place? It is a gotcha, but not a big one (as far as I can guess), and it will bite you right off not sneak up as some subtle issue down the line. If we want to safe guard and have hand rails etc, there's things we could do to make it a safer environment to operate in--like adding lists of modules/namespaces to consider when following calls from rules in order to shield off unwanted parts of a code base. As an example, perhaps not a particular good one at that. 🤷🏽 |
Yeah, I'm not super concerned, it's just weird to see a "naked" async function in the Pants codebase... |
Following #17947 the `rule_helper` decorator is no longer needed.
caveat: This does add a lot of extra overhead during rule parsing affecting the Pants scheduler startup time (~12s)--which we need to address. Either by caching the rule-parsing step, or refactoring over to Rust, or something else..Edit: This was based on a
time ..
hunch but turned out to be something else, unrelated to this change.. see benchmarks at the end of this description.This opens up for calling rule helpers more dynamically so we can have rule-logic closer to the classes and not spread out in all the rules, and also
Get
s without having to spell out the input types as long as the type of the input arg is known (which it does more now than before).I think the latter can help reducing the number of imports we need in all rule files as well.
As an example, imagine this simple case using current praxis:
Address
could hide the rule logic as an implementation details instead, so we could do:and the implementation in
get_source_root()
something like:Doesn't maybe look like much for this example, but I can see this opens up a lot of flexibility and I think it'll lower the learning curve for new users as well.
Benchmarks:
Side by side values:
./pants version
./pants --no-pantsd version
async
and awaitable returning methods./pants version
./pants --no-pantsd version
So this seems to have negligible effect on performance, so far (except when parsing more methods not limiting to those decorated with
@rule_helper
).Edit:
With the changes making
@rule_helper
obsolete degrades slightly: