-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Due to limitation, static analysis don't support import hook used in editable install v64+ #3518
Comments
Hi @JacobHayes thank you very much for bringing this topic up. A different way of describing the issue would be stating that tools doing static analysis do not support import hooks (which is a very fair limitation, it makes total sense). Please note that this is not specific to The links you shared in your example repository are very relevant (specially the email thread). In addition to that I would also mention:
Looking on a way forward on how to handle these circumstances, I believe that first we need to design a solution having inputs and buy-in from both sides (packaging and static analysis). One of the solutions proposed in the email thread (a To pursue this topic further in the setuptools side we would need consensus on such mechanism. This should probably come as a packaging PEP. I don't know if the setuptools issue tracker is the right forum for proceeding with this discussion, since there is no clear action point for setuptools to take. For the time being, if you need to integrate type checking and editable installations, you can try out the |
Why move forward with the install hooks if it was known there was no consensus yet?
I'll test this out within the next couple days. Is there any reason this isn't the default, to reduce the number of breaking workflows by default?
Can you elaborate on this? I think the example repro repo I linked is in -- Thanks for your work on setuptools, I know packages like this in particular are in a hard spot in regards to feature evolution. |
There is consensus in terms of packaging. This is expressed in terms of PEP 660, which was debated over and over again in the community. The PEP's text recognizes import hooks as perfectly valid implementation strategy. Import hooks have been part of Python's feature list for a long time. There are even other built-in behaviours (e.g. zip imports) that rely on these dynamics. Just because they are features that static analysis tools have problems to deal with, it does not mean that they are invalid. As an anecdote: The lack of consensus that I describe is in what Python's package ecosystem can do to make it easier for static analysis tools to deal such kind of implementation.
The To offer a "minimal surprise" experience, the default editable installation tries to be a bit more "lenient"...
It is very definitely almost what I would expect for a When you type The following change may make what you want possible: diff --git i/pkg1/setup.py w/pkg1/setup.py
index 406504e..5097881 100644
--- i/pkg1/setup.py
+++ w/pkg1/setup.py
@@ -3,7 +3,7 @@ from setuptools import find_namespace_packages, setup
setup(
name="org-pkg1",
version="0.0.1",
- packages=find_namespace_packages(include=["org.*"], where="src"),
+ packages=find_namespace_packages(include=["org*"], where="src"),
package_dir={"": "src"},
package_data={"org.pkg1": ["py.typed"]},
python_requires=">=3.9",
diff --git i/pkg2/setup.py w/pkg2/setup.py
index 5ee4648..a48c94f 100644
--- i/pkg2/setup.py
+++ w/pkg2/setup.py
@@ -3,7 +3,7 @@ from setuptools import find_namespace_packages, setup
setup(
name="org-pkg2",
version="0.0.1",
- packages=find_namespace_packages(include=["org.*"], where="src"),
+ packages=find_namespace_packages(include=["org*"], where="src"),
package_dir={"": "src"},
package_data={"org.pkg2": ["py.typed"]},
python_requires=">=3.9", (or just removing |
Hatch does not by default for this reason https://hatch.pypa.io/latest/config/build/#dev-mode |
If that is the reason, does it mean that you would also be supportive of the solution proposed in the email thread (a JSON file that would support static analysis tools to find the modules handled by import hooks)? |
Sure 🙂 |
We're running into similar issues with A small summary: This find the package and returns a On The |
Hi @DanielNoord thank you very much for reaching out.
Please feel free to open a new issue if you can isolate the problematic behaviour and you think it is different than the one discussed here.
Does it mean that
The link seems to point out that previously you were using a However going forward in version > 65 the As you confirmed that |
I think we technically could, but are not doing so right now. Do these import hooks still work on the newer versions? That might be something to explore for us.
Yeah, this is what we do as well. Although I don't think our support for custom import hooks is complete yet. I'll try to see if I can get it to work with the ones you are referring to. Edit: Sorry for the confusion. Seems like we did not support custom import hooks, I was messing up some terms. I have created a PR that does support them and correctly finds the new editable packages. However, since other linters are seemingly hesitant to add support for custom import hooks I'm wary of supporting them in Anyway, I guess for |
No problems, this is one of the most confusing aspect of Python 🤣 I suppose this means that this issue already captures the challenges with
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 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: If users want to use flat-layout, they can circumvent the limitations by using the strict mode. |
If that works for other tools it should for us as well. That said, |
Can we specify more what .pth file lacks that json approach would support? Is the main one being able to import/include specific files and not whole directories? Main question is a new source of import information easier tooling change then a change to .pth file format? |
Updating setuptools to address a [CVE](https://cwe.mitre.org/data/definitions/1333.html). setuptools version >=64 had some breaking changes that require editable_mode to be set to `strict`. See [this issue](pypa/setuptools#3518) for more details. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0
Is there a way to achieve |
Hi @abravalheri,
Is there any update on the removal of compat mode? Has there been any decision on keeping it around permanently or has the "grace-period" simply been pushed back? Thanks! |
Hi @cswartzvi it's been pushed back. I believe that 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 pfmoore/editables#21 (comment)). Of course, this needs a PoC implementation + a round of discussion in the community. |
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". |
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. |
* CI: Enable testing with Python 3.12 * SETUPTOOLS_ENABLE_FEATURES=legacy-editable * pre-commit default_language_version Need to use `SETUPTOOLS_ENABLE_FEATURES=legacy-editable` due to setuptools v64 changes: pypa/setuptools#3518
fixes: #868 this appears to be a known issue stemming from the use of import hooks to comply with pep 660 - see for example python/mypy#13392 and pypa/setuptools#3518. What's happening is that for editable installs `setuptools` creates files like `.../site-packages/__editable__.general_superstaq-0.5.5.pth` which are supposed to point python to the source directory. Previously these would just be text files containing a single path, e.g. ``` /<...>/client-superstaq/general-superstaq ``` but after switching to pyproject.toml it becomes an executable hook, e.g. ```python import __editable___general_superstaq_0_5_5_finder; __editable___general_superstaq_0_5_5_finder.install() ``` where `__editable___general_superstaq_0_5_5_finder.py` is another file saved in the site-packages directory. this breaks static analysis tools because they won't execute the required code afaict this pr seems to be the cleanest workaround - after these changes setuptools seems to generate the old-style `.pth` files (i.e. text files containing paths to the source directories), and `mypy` behaves as expected (at least for me)
Djblets has historically been a setuptools-based project, relying heavily on the dynamic ability of `setup.py`. Over the years, the Python ecosystem has moved to `pyproject.toml` files, with pluggable build backends. This has reached a point of maturity, and `pip` will soon remove support for installing either production or editable installs from a legacy source tree. In theory, modernization requires just providing a `pyproject.toml` that specifies `setuptools` as a build backend. A project can still use `setup.py` for the project definition and dynamic capabilities. However, since packages are also now built in a virtualenv, it's become clear that we needed to address about our packaging. We now use `pyproject.toml` to define most of the metadata of the package. The build backend is then a specialization of `setuptools.build_meta`, living in `build-backend.py` at the root of the tree. This specializes a few things about our build process: 1. It uses all of Djblets's dependencies as build-system dependencies, needed in order to build static media for the package. 2. It builds the static media, including them in both sdist and wheel distributions. 3. It writes out a `package-requirements.txt` at build time with the dependencies from `djblets/dependencies.py`, which setuptools can then consume. This is also bundled in the sdist. With this, we no longer need `setup.py`, and constrain all custom logic to `build-backend.py`. Some things to note: 1. `python -m build .` will default to building an sdist and then a wheel from that sdist, whereas `build . -w` will build a wheel straight from the tree. Due to differences in the prep stages, and what's built from what, we need to micromanage some state (like `package-requirements.txt`) in different places. 2. Other build backends (hatch, PDM, flit, and poetry) were evaluated and discarded. These are great backends, but don't solve the core problems we've had to work around out of the box, and sort of want to manage more of the development and build process. `setuptools` is a known entity for us, and will be needed for extension packaging anyway, so we're sticking with it. 3. `Makefile` installs the package in editable-compat mode. This uses standard `.pth` files instead of newer `setuptools`-based import hooks, in order to allow `mypy` and `pyright` to find type definitions. See python/mypy#13392 and pypa/setuptools#3518. Testing Done: Tested isolated builds in the following setups: * `python -m build .` (builds sdist, then a wheel from the sdist) * `python -m build . -s` (builds sdist) * `python -m build . -w` (builds wheel) Tested isolated editable installs using `pip install -e .` and non-isolated editable installs using `pip install -e --no-build-isolation` and with `make develop`. Performed full tree diffs of generated wheels from `./setup.py bdist_wheel` (prior to this change) and both wheel-producing `python -m build` methods. Verified that all content was identical, with the exception of differences in source map paths and some modern metadata for the package. Reviewed at https://reviews.reviewboard.org/r/14137/
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 thepy.typed
files when checking a codebase importing/referencing the editable installed package.This was opened as a mypy issue in python/mypy#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
The text was updated successfully, but these errors were encountered: