-
-
Notifications
You must be signed in to change notification settings - Fork 652
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
Mark certain types as "side-effecting" #8922
Conversation
7522955
to
20d0ea0
Compare
Great idea! In #8917 I want to actually use the The two things we most often want uncacheably in a
|
Yeah this commit explicitly marks this Part of the point of this work is to link (conceptually as well as in code) the notion of a side-effecting type to a I don't think it's a problem to use "subclass of a class I'm not sure if we need to implement mutex access for |
20d0ea0
to
9f2b605
Compare
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.
Do you know what impact this would have on the new V2 python_test_runner
integration tests for testing debug_python_test
? https://github.com/pantsbuild/pants/pull/8924/files#r364545904. Would it possible for those self.request_single_product()
-style tests to run the InteractiveProcessRequest
even though the tests are not console rules?
Regardless, I think this is a good change but, hopefully, it will still be possible to test that debug_python_test
works properly.
|
||
result = runner.run_local_interactive_process(run_request) | ||
return TestDebugResult(result.process_exit_code) | ||
return TestDebugRequest(run_request) |
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.
Good change.
src/python/pants/engine/rules.py
Outdated
return _make_rule(return_type, parameter_types, cacheable=cacheable, name=name)(func) | ||
|
||
|
||
def validate_parameter_types(func_id: str, parameter_types: Tuple[Type, ...], cacheable: bool): |
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.
Nit: return type is -> None
.
@@ -95,6 +95,20 @@ def test_run_rule_console_rule_generator(self): | |||
) | |||
self.assertEquals(res, Example(0)) | |||
|
|||
def test_side_effecting_inputs(self) -> None: |
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.
Thanks for the type hint :)
src/python/pants/engine/fs.py
Outdated
@@ -212,6 +212,7 @@ class UrlToFetch: | |||
@dataclass(frozen=True) | |||
class Workspace: | |||
"""Abstract handle for operations that touch the real local filesystem.""" | |||
side_effecting = True |
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'm curious, did you consider inheritance?
I strongly prefer using a class field as you do here because multiple inheritance confuses me and inheritance opens up a can of worms of the superclass being able to add methods. But, I want to stress test this decision.
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.
cf. #8922 (comment) , I don't think marking this property via subclassing gets us anything marking it with a class variable doesn't
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.
Either an annotation (@sideeffecting
) or a marker trait would be more self-documenting... someone seeing this property in isolation would not have anything to reference to figure out what it does, whereas with either of those alternatives they could go and inspect the docs on the type/annotation.
Another consideration would be: if we do decide to allow types to be uncacheable
, would we want to have a merged annotation to capture the fact that "sideeffecting, uncacheable, neither" is closer to being an enum? Or could that be handled with inheritance of the marker trait? etc.
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.
+1 to a class decorator. I agree with the benefits of the decorator being more formalized, such as being able to jump to the definition, whereas this field would require grepping for side_effecting
to try to piece together what this does.
Ftr, the decorator could simply add the class property side_effecting = True
. Your validation code would stay the same, only the call sites would be updated.
-1 on a trait mixin per my above comments on inheritance.
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.
After a discussion with @benjyw yesterday about side-effecting process executions (which we can't currently prevent without banning network access), I'm left uncertain about whether annotations will be sufficient. Because without deep sandboxing of processes, there will always be ExecuteProcessRequests that are potentially sideeffecting, and marking them using this annotation probably isn't feasible. Additionally, the foreground
flag (which I'd like to try and finish implementing this weekend) would benefit from the ability not to be cached.
I think that it would be good to think through how an annotation like this would interact with #6598, which I still think that we will need to do, for the above reasons. In particular: rather than a "side-effecting" flag, should this be "uncacheable"? And if it is uncacheable, is the restriction on location something that we can evolve into a usage of #6598?
Right, I don't expect ExecuteProcessRequest to be a formally side-effecting type; we use it deep within
I don't think it's important whether we call this flag "uncacheable" or "side_effecting". The important thing is that we have a way to mark types that can only be requested by rules that permit side effects in a way that the engine actually checks. Right now, that's only If we had #6598 implemented, I don't think we would need console rules at all, and that means that this commit that formalizes the notion of behavior restricted to So in sum, I think this commit makes sense if we want to continue to have a notion of separate |
a07ba20
to
08ecb24
Compare
08ecb24
to
d51a060
Compare
d51a060
to
d77ac95
Compare
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 looks good to me, although probably want to wait for Stu to re-review.
d77ac95
to
e7d4498
Compare
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.
Thanks!
The semantics of this are well understood. It might be worth taking one last look at the API to use here (property/annotation/marker-trait), but the meaning is clear.
src/python/pants/engine/fs.py
Outdated
@@ -212,6 +212,7 @@ class UrlToFetch: | |||
@dataclass(frozen=True) | |||
class Workspace: | |||
"""Abstract handle for operations that touch the real local filesystem.""" | |||
side_effecting = True |
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.
Either an annotation (@sideeffecting
) or a marker trait would be more self-documenting... someone seeing this property in isolation would not have anything to reference to figure out what it does, whereas with either of those alternatives they could go and inspect the docs on the type/annotation.
Another consideration would be: if we do decide to allow types to be uncacheable
, would we want to have a merged annotation to capture the fact that "sideeffecting, uncacheable, neither" is closer to being an enum? Or could that be handled with inheritance of the marker trait? etc.
e3c2fb5
to
34e4854
Compare
Problem
Pants occasionally needs to perform some side-effecting operation that do not work well with the normal caching semantics provided by
@rule
s. For instance, writing build artifacts to disk, or running a binary locally and interactively.Over the course of discussing how to go about implementing these kinds of side-effecting operations, we've created a pattern: create a new python type that implements one of these side-effecting operations, and request it as the input to a
@goal_rule
. Right now,@goal_rule
s are top-level rules associated with a pants goal that also have the property of being marked as non-cacheable, so it is okay for side-effecting behavior to happen in this subset of rules.Solution
This commit formalizes the notion of an side-effecting rule input type by giving the category a name - "side-effecting" - and establishing a check at rule registration time that only non-cacheable
@rule
s are trying to request these types. Right now, the only type of@rule
that is non-cacheable is a rule declared as a@goal_rule
, but this might change in the future (and would require a corresponding update to the logic of this check).