setuptools: Due to limitation, static analysis don't support import hook used in editable install v64+
setuptools version
setuptools==64.0.2
Python version
3.10
OS
macOS, Linux
Additional environment information
No response
Description
After installing editable packages (with a pyproject.toml
) with setuptools >=64, mypy
is no longer able to find the py.typed
files when checking a codebase importing/referencing the editable installed package.
This was opened as a mypy issue in https://github.com/python/mypy/issues/13392, but they recommended we open an issue here. I’m guessing there will be some further discussion on both sides, but just getting the ball rolling.
Expected behavior
Editable installs are still discoverable by static type checkers.
How to Reproduce
See the README in https://github.com/JacobHayes/editable-install-hooks-repro
Output
$ mypy --namespace-packages --explicit-package-bases src
src/org/pkg2/__init__.py:1: error: Cannot find implementation or library stub for module named "org.pkg1"
src/org/pkg2/__init__.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
Found 1 error in 1 file (checked 1 source file)
$ pylint src/
************* Module org.pkg2
src/org/pkg2/__init__.py:2:0: E0611: No name 'pkg1' in module 'org' (no-name-in-module)
-----------------------------------
Your code has been rated at 0.00/10
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 27
- Comments: 24 (13 by maintainers)
Commits related to this issue
- chore: update dependencies (#3944) Updating setuptools to address a [CVE](https://cwe.mitre.org/data/definitions/1333.html). setuptools version >=64 had some breaking changes that require editable_m... — committed to aws/jsii by corymhall a year ago
- CI: Enable testing with Python 3.12 (#478) * CI: Enable testing with Python 3.12 * SETUPTOOLS_ENABLE_FEATURES=legacy-editable * pre-commit default_language_version Need to use `SETUPTOOLS_ENABLE... — committed to typeddjango/djangorestframework-stubs by intgr 9 months ago
- use empty package-dir in pyproject.toml (#715) fixes: #868 this appears to be a known issue stemming from the use of import hooks to comply with pep 660 - see for example https://github.com/pyth... — committed to Infleqtion/client-superstaq by richrines1 6 months ago
Hatch does not by default for this reason https://hatch.pypa.io/latest/config/build/#dev-mode
It’s worth noting that ‘static analysis tools’ also include the tools used to provide rich editing experiences in modern editors; in particular, type inference and thus auto-completion suggestions and hover information rely heavily on static analysis. This goes way beyond type checkers.
Thank you @abravalheri that is helpful - I will watch this space for updates.
Perhaps you can help me with a conceptual question (that also might be related to @s-banach’s comment about the docs). What is the default editable install mode? I can see in the code that the default is called “lenient” but how does that differ from ‘compat’? Forgive me if this is a naïve question, even though I have been using python for a long time this is still all very - confusing.
I just came here to leave a comment on the language in https://setuptools.pypa.io/en/latest/userguide/development_mode.html
The way it’s currently worded feels like “we either don’t know or don’t care about the issue with type checking”. If the documentation is changed to say “
compat
is a temporary solution until we reach some agreement with the static type checkers on how to handle editable installs”, people like me might not show up here to rant and rave.Hi @cswartzvi it’s been pushed back. I believe that
compat
is not the final solution for this problem, but I haven’t had the time to investigate and propose something more permanent yet.As a general concept I believe that it would be possible to come up with a static file (e.g. JSON) describing editable package locations that could at the same time feed static analysis tools and a MetaPathFinder/PathEntryFinder (I briefly mentioned it in https://github.com/pfmoore/editables/issues/21#issuecomment-1227059911). Of course, this needs a PoC implementation + a round of discussion in the community.
When we analyse the problem from the optics of type-checking this seems reasonable.
However there are other things in play: there is a series of setuptools issues that cannot be fixed with the previous implementation. Moreover, import-hooks help us to that match more closely a regular installation, and this is also very helpful to identify bugs before packages are published.
The TLDR is that an explicit opt-in mitigates some problems but re-open other ones.
Please also note that there is already a series of compromises and trade-offs in place: whenever “safe” setuptools will not use import-hooks.
There is also quite a few scape hatches for the case users are more concerned with type-checking than the other packaging problems, so they can “opt-out”.
pdm also requires users to explicitly opt-in to the import hook approach – https://pdm.fming.dev/latest/pyproject/build/#editable-build-backend
Maybe setuptools should do something similar? Solving this issue “the right way” (ex. new file consumed by tools) is going to take a while (many months). Requiring users to opt-in could mitigate the problem in the meantime.
No problems, this is one of the most confusing aspect of Python 🤣
I suppose this means that this issue already captures the challenges with
pylint
interoperability and we don’t need to create a new one.In the mailing list pointed out by @JacobHayes, there is a suggestion that could work as a more long-term/stable approach (probably as a packaging standard/PEP). In summary the suggestion is to have a JSON file placed somewhere in the site-packages directory, containing static paths and metadata for modules in the editable installation.
Do you think that would be a better (or more acceptable) approach for
pylint
?I have been a bit short of time lately, but I think I could work with that… I also think that other people in PyPA would be supportive of this approach.
Meanwhile, this information may be relevant:
setuptools
will try to use static.pth
files as much as possible. Projects that use the so calledsrc
-layout should be available without the need of import hooks.If users want to use flat-layout, they can circumvent the limitations by using the strict mode.
We’re running into similar issues with
pylint
although I’m not sure it is exactly the same issue. We do support import hooks and try to resolve those so it might be better to open a standalone issue for our problem. If preferred, please let me know.A small summary:
pylint
usesastroid
to generate theast
tree of python files with some additional nice-to-haves to help use perform the analysis.astroid
tries to mimc Python import behaviour with itsinterpreter._import
module: https://github.com/PyCQA/astroid/tree/d033fe2f4c575d45a1706c52988dbcdf50645c5c/astroid/interpreter/_import Onsetuptools<63
we were able to discover editable installs throughsys.path
and looking for the__init__.py
file. The code that is responsible for this is: https://github.com/PyCQA/astroid/blob/d033fe2f4c575d45a1706c52988dbcdf50645c5c/astroid/interpreter/_import/spec.py#L135-L145This find the package and returns a
ModuleSpec
which resembles aimportlib.ModuleSpec
.On
setuptools>=64
this no longer works. I assume it is because there is a difference in the effectpip install -e
has onsys.path
but I’m not sure. Does anybody who is knowledgable about the neweditable
system see how we should resolve imports to editable packages?The
pylint
issue that tracks this is https://github.com/PyCQA/pylint/issues/7306. Feel free to continue the discussion there if you want to keep this focused on the original issue.Sure 🙂