The default sources
for conftest.py
and *_test.pyi
now belong to new target generator python_test_utils
, not python_tests
#13299
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Part 1 of #13238.
Why we need to fix this
Currently,
python_tests
includesconftest.py
and*_test.pyi
in itssources
field, and it generatespython_test
targets for those. We special case our Pytest code to ignore running tests on those generated targets:pants/src/python/pants/backend/python/subsystems/pytest.py
Lines 50 to 57 in e865418
This will not work with lockfiles #13238:
conftest.py
and*_test.pyi
both must be modeled by apython_source
target, notpython_test
. Apython_test
target has the fieldresolve: str
, whereaspython_source
hascompatible_resolves: list[str]
. Theresolve
says which exact resolve to use, and then we validate the transitive closure is compatible with that one. Because aconftest.py
can be a dependency of manypython_test
targets, it's important that it participates in thiscompatible_resolves
mechanism.Solution
Add a new
python_test_utils
target generator, which generatespython_source
targets. It behaves identically to thepython_sources
target generator, except that it has the defaultsources
ofconftest.py
and*_test.pyi
.Why a new target that behaves identically to
python_sources
? This modeling reduces the risk of folks unintentionally including test support files likeconftest.py
in production, such as in apex_binary
andpython_distribution
. Forpython_distribution
, it's very common to add a dependency on apython_sources
target generator, rather than a generatedpython_source
target, i.e.:lib
instead offoo.py:lib
. We want to avoid the gotcha of:lib
includingconftest.py
because that's how the defaultsources
work, and we don't want users to have to be aware of this gotcha and to do set arithmetic in thesources
fields of twopython_sources
to make sure there aren't duplicate owners of the sameconftest.py
.A new target also dramatically minimizes the breaking changes of this PR. Now, the risk is that some files will be unowned, whereas before there was the risk that they'd be owned by a different target generator than before, so might inherit different metadata like
dependencies
and might be included in unexpected places like apython_distribution
depending on:lib
.--
This PR does not deprecate the special casing in
pytest.py
that allows for apython_test
target to be used withconftest.py
and*_test.pyi
. That special casing will be deprecated in a followup.Alternatives considered
python_tests
generatespython_source
targetsThis is technically feasible, but really clunky and confusing to document. For example, the
conftest.py
python_source
target would presumably default to the globalcompatible_resolves
option (configured in[python-setup]
). To change it, we'd either need to add a field topython_tests
likeconftest_compatible_resolves
, or the user would have to know to use theoverrides
mechanism from #13270. Not intuitive!Deprecating having a default
sources
field forpython_tests
andpython_sources
Users would have to either explicitly use the new defaults or stick to the old defaults. Once we're confident people aren't using a default, we can safely change it without breaking anyone.
However, this would require a ludicrous amount of churn for a problem that most users don't even have. Even if we automated this change with
./pants update-build-files
, it is still extremely disruptive.Also, this isn't very feasible because of how we validate that each glob in the
sources
field matches. When it's the field'sdefault
, we only require any glob to match. When it's explicitly declared in a BUILD file, we require all globs to match. So, a user could not safely set["*_test.py", "test_*.py", "tests.py"]
in a BUILD file unless they had all those files, which is unlikely.A global option to change the default
I don't think this is technically feasible. The Target API is intentionally shielded from the Rules API. There's no way for an option to change the default of a field. It would require a ludicrous amount of special casing in
engine/internals/graph.py
etc to have our Rules code that consumes these fields to change behavior of things like hydrating sources based on the option.Impact
Our dependency inference rule for
conftest.py
requires that there be an owning target:pants/src/python/pants/backend/python/dependency_inference/rules.py
Lines 231 to 235 in a9af04d
So,, unless you have explicitly put
conftest.py
into apython_sources
orpython_tests
target'ssources
field, then you'll get this error when upgrading to Pants 2.8:It violates our deprecation policy to error here, but we don't think there's a way to gracefully deprecate. Hopefully folks will run
./pants tailor
after encountering this and getpython_test_utils
targets added.When a new
python_test_utils
target is added, the user may need to update its metadata like itsdependencies
to work properly. That might not be very intuitive, so we should document it in upgrade notes. Fortunately, the risk is mostly that users' tests will fail: there is far less risk this will break production code.[ci skip-rust]
[ci skip-build-wheels]