hundreds-father-404
08/19/2021, 7:54 PMpython_library
can also be a lint
and typecheck
. Does that sound right?hundreds-father-404
08/19/2021, 7:55 PMwitty-crayon-22786
08/19/2021, 7:56 PMwitty-crayon-22786
08/19/2021, 7:57 PMaverage-vr-56795
08/19/2021, 7:58 PMaverage-vr-56795
08/19/2021, 7:59 PMwitty-crayon-22786
08/19/2021, 8:00 PMhundreds-father-404
08/19/2021, 8:00 PMHow likely do we think a differing resolve actually affecting those goals is?For MyPy, I could see it being an issue. Imagine your
python_requirement_library
is loose, like Django
. Your python_library
depends on that. One "root" uses Django 2 in its lock, whereas another uses Django 3. Which resolve we use could determine whether the type hints are valid or notwitty-crayon-22786
08/19/2021, 8:01 PMhundreds-father-404
08/19/2021, 8:02 PMi think that my expectation was that we’d find the roots depending on that libraryOkay. A challenge with that is assuming every
python_library
has a root, which might not be try if you just added a new util file w/o tests and no packages /binaries depending on it
I remember you mentioning a default resolve, which possibly could cover thatwitty-crayon-22786
08/19/2021, 8:02 PMhundreds-father-404
08/19/2021, 8:02 PMthat it turns those goals into O(repo) actions rather than O(deps) actionsOh, yeah. Oof,
dependees
code is really slow because it has to create a global dependency map 😕average-vr-56795
08/19/2021, 8:03 PMwitty-crayon-22786
08/19/2021, 8:07 PMwitty-crayon-22786
08/19/2021, 8:08 PMhundreds-father-404
08/19/2021, 8:09 PMaverage-vr-56795
08/19/2021, 8:09 PMlib
, you ask to lint bin
and it will lint lib
for you.
We could choose to only do this if there are root-aware lints registered (so black
can lint lib
fine, but mypy
can't)average-vr-56795
08/19/2021, 8:10 PMhundreds-father-404
08/19/2021, 8:14 PM"libraries don't make sense to typecheck in isolation"I think they do make sense to lint in isolation.
./pants typecheck src/python/pants/util/strutil.py
is totally sensible. In fact, users submitted a patch so it only checks strutil.py
whereas we used to check all transitive deps of it too
only complication is which lockfile to use to set up the run
Radical idea:(thank you for thinking like that! I very much appreciate your feedback and suggestions)
average-vr-56795
08/19/2021, 8:16 PMhundreds-father-404
08/19/2021, 8:20 PMwitty-crayon-22786
08/19/2021, 8:28 PMwitty-crayon-22786
08/19/2021, 9:01 PMFor user lockfiles, I think we may need to be checking that the run’s requirements are compatible, not necessarily identicalyea. and more than that, it might actually represent the same sort of potential optimization… where if the transitive requirements of the library are already a member of exact one resolve, you skip scanning the repo
hundreds-father-404
08/19/2021, 9:02 PMhundreds-father-404
08/19/2021, 9:14 PMpython_requirement_library
for the same dep, and you use explicit deps instead of dep inference to say what you want
This contrived example I had above is a total antipattern and we shouldn't optimize for it:
For MyPy, I could see it being an issue. Imagine your python_requirement_library is loose, like Django. Your python_library depends on that. One "root" uses Django 2 in its lock, whereas another uses Django 3. Which resolve we use could determine whether the type hints are valid or notIn that case, you should have
:django2
and :django3
targets, and force callers to decide which they support. It is not safe to be relying on the pins differing in the lockfilesaverage-vr-56795
08/19/2021, 9:19 PMpython_requirement_library
and refuse to infer for you? Or does it pick a default for you?hundreds-father-404
08/19/2021, 9:21 PM:django2
and :django3
targets is that we detect ambiguity for the django
module, so we print a helpful message asking you to explicitly disambiguate by choosing onewitty-crayon-22786
08/19/2021, 9:22 PMwitty-crayon-22786
08/19/2021, 9:22 PMwitty-crayon-22786
08/19/2021, 9:22 PMwitty-crayon-22786
08/19/2021, 9:23 PMwitty-crayon-22786
08/19/2021, 9:24 PMwitty-crayon-22786
08/19/2021, 9:24 PMhundreds-father-404
08/19/2021, 9:31 PMHow likely do we think a differing resolve actually affecting those goals is?I think this above insight simplifies the answer. Because you should be modeling different versions via multiple
python_requirement_library
targets— rather than lockfile contents for the same targets having different pins—we can assume any of the N resolves for a target's owning roots would be compatible. No need to run MyPy with all the resolves, we only need one of them
If my_util.py
imports django
, it will need to have already disambiguated if that's :django2
vs :django3
. So, all the owning roots will be using the disambiguated version
(sorry, not sure if that makes sense)witty-crayon-22786
08/19/2021, 9:32 PMIfthey’ll be using some disambiguated version… but not necessarily the same oneimportsmy_util.py
, it will need to have already disambiguated if that’sdjango
vs:django2
. So, all the owning roots will be using the disambiguated version:django3
witty-crayon-22786
08/19/2021, 9:34 PMhundreds-father-404
08/19/2021, 9:36 PM:binary1
and :binary2
both depend on :my_util
, which has disambiguated it uses :django2
instead of :django3
. That means the resolves for both the binaries will be Django 2.
So...when we do ./pants typecheck :my_util
, which needs to include Django in the venv, we could use either of the two resolves. Both should have roughly the same version of Django 2. The rest of their deps may differ, but that's fine because we'll extract Django from it using --repository-pex
(There's a risk the pinned versions will be different if Django 2 top-level requirement floats a lot and the resolves were generated at different times. But, the insight is that that's an antipattern. The top-level dep should be pinned enough that the resolves are compatible)hundreds-father-404
08/19/2021, 9:36 PMhundreds-father-404
08/19/2021, 9:38 PMIf ahas multiple roots where >1 resolve is in play, we can choose any of those resolves. No need to build with every one of them.python_library
witty-crayon-22786
08/19/2021, 9:40 PMIf athe point of my “oh… you mean” comment was: that’s only true for direct deps of the library. if the transitive thirdparty deps of the library might matter to whatever task you’re running, then you need to find the right ones.has multiple roots where >1 resolve is in play, we can choose any of those resolves. No need to build with every one of them.python_library
witty-crayon-22786
08/19/2021, 9:41 PMhundreds-father-404
08/19/2021, 9:43 PMpy-constraints
) that allows you to see what lock would be used when running ./pants typecheck my_util.py
witty-crayon-22786
08/19/2021, 9:44 PMrequests
… ie, requests isn’t declared anywhere in the explicit deps below the library. but the version of requests used will float based on what else is in the relevant resolvewitty-crayon-22786
08/19/2021, 9:46 PMhundreds-father-404
08/19/2021, 9:47 PMpython_library
in particular, particularly when running Pylint and MyPy on it (the only two actions that can run on a python_library
and consider 3rd-party deps)
For pex_binary
, of course you want to lock down precisely which version gets used, which you will be setting the resolve
field.
But for the python_library
, I don't think it actually matters. MyPy and Pylint won't consider the transitive dep in their runs, they're only checking your direct importshundreds-father-404
08/19/2021, 9:47 PMi suppose that you could actually use the lockfile(s) to detect whether the reachable dependencies of your library are actually different in the different resolvesPossibly? I was thinking not to do that. Simply choose one of the N possible resolves compatible with that
python_library
, where compatibility is simply that the python_library
is used by a root that generated the resolvewitty-crayon-22786
08/19/2021, 9:48 PMMyPy and Pylint won’t consider the transitive dep in their runs, they’re only checking your direct importsdo we give mypy the transitive deps, or only the direct?
hundreds-father-404
08/19/2021, 9:54 PMwitty-crayon-22786
08/19/2021, 9:56 PMwitty-crayon-22786
08/19/2021, 9:57 PMhundreds-father-404
08/19/2021, 9:58 PMyou can't just install direct depsI mean that pex doesn't let you install a dep w/o its own deps being present:
ERROR: In --require-hashes mode, all requirements must have their versions pinned with ==. These do not:
attrs>=19.2.0
or do you mean we can use the repository pex extraction feature to just get direct deps? interestingwitty-crayon-22786
08/19/2021, 9:59 PMwitty-crayon-22786
08/19/2021, 10:00 PMwitty-crayon-22786
08/19/2021, 10:02 PMrepository.pex
issue: with the graph from the resolve, pants can execute the subsetting itself.hundreds-father-404
08/19/2021, 10:05 PMpython_library
as reported by ./pants dependencies --transitive
, vs. a transitive dep of a 3rd-party requirement as defined by its wheel METADATA
For Pylint, we only need direct dependencies: what you import directly. When installing direct third-party dependencies, their own deps get pulled in via normal pex/pip mechanisms like lockfiles
For MyPy, we need transitive dependencies in the Pants sense. Any of your top-level third-party dependencies—whether direct or transitive deps—need their own deps also installed due to pex/piphundreds-father-404
08/19/2021, 10:11 PM