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
Add dependencies on conftest and init files via inference #10441
Add dependencies on conftest and init files via inference #10441
Conversation
The commits are useful to review independently, but this is currently a draft for two reasons:
|
I tend to agree that we should nuke our own |
Re separate toggles - possibly, yes, otherwise we're requiring people to write manual deps on parent |
Well, see my second point above: I think that this inference rule should be on by default (since we effectively already turned it on by default by landing the "inject" stuff). But also, because this a file-level dependency, 1) it won't drag in any more files than you need, 2) it won't cause cycles because of #10409.
Or not have them at all. In our case, there is zero need for them post PEP 420 (afaict: will confirm before landing). If that's true, we can delete all of them in a followup. EDIT: It looks like |
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.
How would you feel about keeping the prior behavior for __init__.py
and pytest_runner.py
in addition to your change? The way AncestorFiles
is implemented, if you have dep inference, we won't end up trying to re-find those missing files because they are already in prepared_sources.snapshot
. So, dep inference will behave the same as you're intending.
For people not using dep inference, they'll get the injection. This avoids the problems Benjy is concerned about, like having to create lots of new targets and having new cycles.
That wouldn't fix the bug I don't think: see the Problem description. Basically, injecting the I think that The thing that would feel cleanest to me would be to have inference of both |
I don't think this works - if the |
This seems reasonable to me. |
Not so sure about there being zero need for For example, various parts of Django choke on namespace packages in your code. |
This is reviewable. The commits are still useful to look at independently. |
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. Good idea to have 3 new options.
class PythonInference(Subsystem): | ||
"""Options controlling which dependencies will be inferred for Python targets.""" | ||
|
||
options_scope = "python-infer" |
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 think generally we have subsystems be nouns. I'd recommend python-inference
.
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 idea to have a dedicated subsystem, btw.
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 started with that, but the option names were so much nicer with the verb... --python-infer-imports
, --no-python-infer-imports
, etc. Should I change the option names as well?
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.
True, but this gets to Benjy's point that 90% of options are only ever set in pants.toml
. I strongly suspect this will only be set in pants.toml
, outside of a codebase admin experimenting with things.
So, it would read:
[python-inference]
imports = true
inits = true
conftests = 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 kinda like [python-infer]
even in config TBH
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.
Leaning toward leaving it then.
src/python/pants/backend/python/dependency_inference/module_mapper.py
Outdated
Show resolved
Hide resolved
src/python/pants/backend/python/typecheck/mypy/rules_integration_test.py
Show resolved
Hide resolved
0e4b382
to
55b9a54
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.
Thank you. I have no idea what happened to isort for you?
src/python/pants/backend/python/dependency_inference/module_mapper_test.py
Show resolved
Hide resolved
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.
Great work!
@@ -740,8 +763,8 @@ async def resolve_dependencies( | |||
) | |||
|
|||
inference_request_types = union_membership.get(InferDependenciesRequest) | |||
inferred = InferredDependencies() | |||
if global_options.options.dependency_inference and inference_request_types: | |||
inferred: Tuple[InferredDependencies, ...] = (InferredDependencies(),) |
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. It's fine to fix this in a followup, I know we're trying to land this for the release.
inferred: Tuple[InferredDependencies, ...] = (InferredDependencies(),) | |
inferred = () |
python_library( | ||
name='lib', | ||
sources = ['__init__.py'], | ||
tags = {"nolint"}, | ||
) |
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.
Ohhh I see the bug now! So, the __init__
inference rule found that there is indeed an owner of this file, but that owner isn't an actual Python target. It would be more robust if we instead had the inference rule filter out all the resulting owners to check that .has_field(PythonSources)
is true.
Without this target definition added, we would have wanted the __init__.py
inference rule to error that there is no Python owner of this file.
--
It's fine to fix this in a followup, imo, so long as we do fix it.
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.
Hm, do note that this may result in far more dependencies being pulled in than previously if you are not using I'm not really sure what the remedy would be here. I'm glad that there is an escape hatch with turning off this feature. |
The only solution that is robust in this case is to have a separate target for |
7437cce
to
d12ffd7
Compare
Keep in mind too that under inference, the dep lists of most targets in BUILD files should be nearly empty: in that case, the effect of this change would be getting only the |
Yes, agreed. I am describing the case where you are not using import inference. Mostly V1 users upgrading to V2. |
d12ffd7
to
fccb6b3
Compare
[ci skip-rust-tests]
[ci skip-rust-tests]
[ci skip-rust-tests]
…n-infer subsystem. [ci skip-rust-tests]
[ci skip-rust-tests]
# Rust tests will be skipped. Delete if not intended. [ci skip-rust-tests]
# Rust tests will be skipped. Delete if not intended. [ci skip-rust-tests]
fccb6b3
to
2a409be
Compare
@@ -4,9 +4,6 @@ | |||
from dataclasses import dataclass |
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.
The docstring is out of date in this file. It should remove all mention of __init__.py
.
) ### Problem #10441 caused a performance regression from about 10s to run `./pants dependencies --transitive ::` with inference enabled, to about 22s. ### Solution Make independent owners requests per file we'd like to find owners, which allows the lookups for each file to be memoized independently. ### Result `./pants dependencies --transitive ::` takes 15s. Although we are doing more work than before (before #10441, conftest discovery would only happen at `test` time), this is not ideal, and we should do further optimization before launch. But there are a few variables that will impact this soon that make it not the best time to optimize: 1) an intrinisic `PathGlobs->Paths` operation, 2) possibly enabling inference by default, allowing all of the strategies to use the module_mapper. [ci skip-rust-tests]
Problem
When attempting to release
dev5
internally, manyconftest.py
files were being included without their dependencies by thepytest_runner
conftest.py
injection that was added in #10378.Because that injection was not actually declaring dependencies on those files, it 1) wasn't locating owning targets, or 2) triggering dep inference on those files. This meant that even though we could successfully infer the deps of the
conftest.py
files, we weren't... just including them verbatim.Solution
Move to inferring dependencies on
conftest.py
and__init__.py
files, which will cause the dependencies of those files to be included, and cause them to be reported in our graph introspection goals.Each thing that we can infer is provided by a separate inference
@rule
in@union InferDependenciesRequest
, so this change also enables multiple inference rules per type of Sources.Result
conftest.py
files are included along with their dependencies, fixing all known test failures indev5
.