-
-
Notifications
You must be signed in to change notification settings - Fork 631
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
MyPy third-party requirements support is broken for Python 2 #10819
Comments
Put up a failing test at #10820. Taking a step back..that makes sense. How would MyPy—which uses >=3.5—load a Python 2-only wheel? It can parse Python 2 code using the I think that this could suggest one of two things:
#1 might be adequate, but it does raise some concerns I have when we're purely talking about Python 3. Imagine you resolve your requirements with Py36, but run MyPy with Py35. Now, none of your requirements will load. Yes, we can use -- Instead, what I think this is suggesting is that for Py3-only, the tool Pex and requirement Pex need to have the same constraints. Perhaps we need to use something like we do with iPython to determine the constraints: pants/src/python/pants/backend/python/goals/repl.py Lines 56 to 64 in dadbcc5
Iff we're using Python 2, we set |
So this makes sense, but I feel like if this was true, it would make it really difficult for people to use mypy on py2-only projects in general! I know pip was py2-compatible for a while, but it also vendored everything it needed. I'm going to see if I can find an example of a project that:
|
Ok, so after continuing your awesome work at pex-tool/pex#1032, I think this line was more insightful than I realized at first:
Could we perhaps just unconditionally unzip the requirements pex? And in fact, even better: instead of adding complex round-trip logic to extract requirements out of a pex file after the We could make this a separate rule which uses a script that works in isolation, without being able to import anything else from pants -- just like the fabled ipex launcher at https://github.com/pantsbuild/pants/blob/1.25.x-twtr/src/python/pants/backend/python/subsystems/ipex/ipex_launcher.py. That script could call This would be much faster (I think) than creating a whole pex file from the dependencies, in addition to avoiding complex work to extract anything out of the pex format. I'll look to extend #10820 now or tomorrow with this idea. |
It looks like we might be able to remove this lengthy comment and the monkey-patching here too! pants/src/python/pants/backend/python/typecheck/mypy/rules.py Lines 71 to 73 in 18c0a56
|
Hmmmm. Before I get too much further into this, I think this might be a duplicate of #9206! |
I think it's a little different than #9206, although that would be half the battle. In that case, we just needed to shade requirements from tools. In this case, I'm not sure (like @Eric-Arellano mentioned above) whether mypy is able to load python 2 dists even if they're on the However, I want to note that if we can make the current method work, we should be able to generalize it into a solution for #9206, which would be cool. |
Closes #10819. Turns out that when using `--pex-path` with PEX, it will expect for every requirement to have a wheel that is compatible with the current interpreter, unless you set `PEX_IGNORE_ERRORS`. This means that it is naively not safe to resolve requirements with Python 2, but run MyPy with Python 3.5+. Likewise, it is not safe to resolve requirements with Python 3.6 but run MyPy with Python 3.7. Instead, we generally use the same interpreter constraints for the requirements when creating the tool pex. However, if the requirements have any Python 2 code—or the user set `--mypy-interpreter-constraints`—then we will let the two sets diverge, and we'll set `PEX_IGNORE_ERRORS`.
### Problem The wheels used by third-party code might not use the same constraints as what the MyPy Pex uses. This was causing errors (#10819), which we fixed in #10820. However, that fix was not perfect. Even if there were valid typed Python 2 wheels, we would ignore them. WIth Python 3, we had to be careful that `mypy.pex` used the exact same constraints as `requirements.pex`, so that, for example, we don't run MyPy with Py36 but resolve requirements with Py37. ### Solution Stop using `--pex-path` to join the `requirements.pex`, which has the effect of the wheels being put on `PYTHONPATH`. (We were then teaching MyPy to read from this PYTHONPATH through a custom launcher script.) Instead, we extract the wheel folders from `requirements.pex`, and teach our custom launcher script to look in these extracted `.deps/` folders through a new `EXTRACTED_WHEELS` env var. MyPy will use this to resolve the requirements, without us actually including the wheels in the final PEX or modifying PYTHONPATH. ### Result Our Python 2 test now fully works, even though one of the wheels is not compatible with Python 3. We no longer need to align `mypy.pex` with `requirements.pex`. #### Caveat: MyPy plugins must be installed with `--mypy-extra-requirements` An initial implementation did not use `EXTRACTED_WHEELS` and instead loaded the wheels via `PYTHONPATH`. This allowed for you to specify MyPy plugins via normal dependencies on `python_requirement_library` targets, because that requirement would get loaded via PYTHONPATH. Now, you cannot do this; you must specify the requirement via `--mypy-extra-requirements`. This caveat seems acceptable. For Pytest, it's convenient that we allow you to load plugins via normal requirements, as it allows you to only sometimes use the plugin. MyPy is much more uniform, however; MyPy runs in a single batch over the entire transitive closure, unlike Pytest running one test file at-a-time. Likewise, without Pants, it's hard to imagine how you could only sometimes use a MyPy plugin, given that MyPy only works with a single config file.
Right now, we expect for the interpreter constraints to be different for the
tool_pex
andrunner_pex
than they are for therequirements_pex
. This is because MyPy must run with Python 3.5, but the user's code may be anything, including Py27.We use
--pex-path
to join all the PEXes. However, this results in error messages like this:It appears that whatever interpreter is used to run the runner PEX, it expects for every requirement to be compatible with it. So, running MyPy with Py36 complains when it can only find Py27 wheels.
Instead of using
--pex-path
to join therequirements.pex
, we need a mechanism to get the distributions out of the PEX and treat them like normal data. Then, in our MyPy code, we can load up those dists.Alternatively, we can set
PEX_IGNORE_ERRORS
...this fixes the issue, but I'm not sure if it's safe to do.The text was updated successfully, but these errors were encountered: