# Help testing PEP 660 support in setuptools

**URL:** <https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904>\
**Category:** Packaging\
**Created:** [June 28, 2022, 8:58pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904 "2022-06-28T20:58:41Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 3, 2022, 10:04am UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/23 "2022-07-03T10:04:57Z")

</div>

> [@sbidoul](#):
>
> As mentioned in the limitations it does not work, due to the editable install using `_TopLevelFinder`.

Does the `strict` behaviour works well for your use case?  
(Despite the fact that it is not very handy for incrementally adding/splitting/renaming/removing files).

---

<div class="post-metadata">

**Author:** ![sbidoul](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/sbidoul/32/244_2.png) [@sbidoul](https://discuss.python.org/u/sbidoul)\
**Post date:** [July 3, 2022, 2:21pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/24 "2022-07-03T14:21:41Z")

</div>

> [@abravalheri](#):
>
> Is this project that you are working with open source? (I could try to have a look and understand better if there is a different way)

Yes, it’s [Odoo](https://github.com/odoo/odoo). The main project has a ` __init__.py` that does the [pkgutil.extend\_path](https://github.com/odoo/odoo/blob/09f85a5f9472c3fff70283332c4eb0f8077a8b2c/odoo/ __init__.py#L13-L16) dance. This automatically detects addon modules that the community distributes on pypi (those have no ` __init__.py` in their `odoo` directory, [example](https://pypi.org/project/odoo-addon-mis-builder/)). This mechanism is somehow broken by `_TopLevelFinder` - I have not investigated why precisely yet. Feel free to PM me if you’d like to dig further, as the details of how Odoo works may not be of interest to followers of this thread.

I assume other projects which use this approach for distributing and locating plugins may suffer of the same problem. I don’t know how prevalent they are, though.

> If we introduce a new option, we have to move very carefully to not re-ignite discussions in which we don’t have consensus.

Yes, I’am aware to the complex nature of this topic. I also understand that setuptools would take this opportunity to use a better default than the static pth approach.

> Meanwhile, I added `SETUPTOOLS_ENABLE_FEATURES=legacy-editable` (env var) as a escape hatch to recover the `python setup.py develop` behaviour.

Thanks!

> Does the `strict` behaviour works well for your use case?

Not entirely. The pkgutil.extend\_path addon detection mechanism works, as expected. But in editable mode Odoo relies on the presence of an `addons` directory next to the `odoo` directory, which does not exist in the strict link farm. So that would require some tweaks too. BTW, would there be a mechanism for an in-tree backend to customize or override the link farm construction ?

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 3, 2022, 3:44pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/25 "2022-07-03T15:44:40Z")

</div>

Thank you very much @sbidoul, I will try to have a look on this.

> [@sbidoul](#):
>
> Yes, I’am aware to the complex nature of this topic. I also understand that setuptools would take this opportunity to use a better default than the static pth approach.

That said I am very open to explore solutions to support the majority of use cases that currently work well with `python setup.py develop` (I just want to avoid growing even more in complexity, it seems that every time I implement a PEP in setuptools the amount of lines of code just grow a lot 😅).

> [@sbidoul](#):
>
> But in editable mode Odoo relies on the presence of an `addons` directory next to the `odoo` directory, which does not exist in the strict link farm.

Do you have any hint for me why that is not the case? I had a look on the [example](https://github.com/OCA/mis-builder/tree/15.0/setup/mis_builder/odoo/addons) and it seems that it does have a directory, but maybe because of the symlinks something I haven’t considered is happening…

> [@sbidoul](#):
>
> BTW, would there be a mechanism for an in-tree backend to customize or override the link farm construction ?

Uuummm, I haven’t developed the feature considering the users would like to piggyback directly into the link farm generation… However, I added [some ways](https://setuptools--3429.org.readthedocs.build/en/3429/userguide/extension.html#supporting-sdists-and-editable-installs-in-build-sub-commands) of _influencing_ it if the package uses a custom build step (or overwrites `build_py`/`build_ext`). It is possible to add a [`get_output_mapping()`](https://github.com/pypa/setuptools/blob/156a75f880ec28755fa43ff95d7bd6166b4c76f7/setuptools/command/build.py#L138-L146) method to a `build` subcommand (this is not 100% future proof yet, I just thought it would be useful for plugin developers, so I also appreciate any feedbacks).

---

<div class="post-metadata">

**Author:** ![sbidoul](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/sbidoul/32/244_2.png) [@sbidoul](https://discuss.python.org/u/sbidoul)\
**Post date:** [July 3, 2022, 3:57pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/26 "2022-07-03T15:57:19Z")

</div>

> [@abravalheri](#):
>
> That said I am very open to explore solutions to support the majority of use cases that currently work well with `python setup.py develop` (I just want to avoid growing even more in complexity, it seems that every time I implement a PEP in setuptools the amount of lines of code just grow a lot 😅).

I totally understand what you mean 🙂 That said, in this case setuptools is growing three different ways to implement editable installs so I guess the code size increase is unavoidable.

My naive suggestion would be to expose the 3 modes to users via the config setting and document the tradeoffs of each, as well as when each becomes the default. That would grow the docs a little bit, but probably not that much the code size.

> [@abravalheri](#):
>
> Do you have any hint for me why that is not the case? I had a look on the [example](https://github.com/OCA/mis-builder/tree/15.0/setup/mis_builder/odoo/addons) and it seems that it does have a directory, but maybe because of the symlinks something I haven’t considered is happening…

Ah yes, that is not a bug, don’t worry. It’s simply because, for historical reasons, the addons directory is outside of the main Odoo package and not known to `setup.py`. Not much you can do here, and that’s not related to the core of the issue I raised here.

> get\_output\_mapping

That sounds very useful, I’ll investigate that too.

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 4, 2022, 1:23pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/27 "2022-07-04T13:23:42Z")

</div>

Thank you very much @sbidoul. Before I dive into adding another option to force the static `.pth` file, I would like to understand a bit better why the `strict` mode is not working for this use case (in theory the `strict` mode should work identically to a regular installation in a different “portion” of `sys.path`, right? So it should work for all the scenarios, including `pkgutil` namespaces, as long as the file system support _either_ symlinks or hard links, which should cover almost everything).

I tried to investigate directly with `odoo` but it is not as trivial to install as I would have hopped, so I decided to try a very simplified experiment as shown bellow:

```bash
rm -rf /tmp/staging
mkdir -p /tmp/staging/base/pkg

cat <<EOF > /tmp/staging/base/pkg/ __init__.py
import pkgutil
import os.path
__path__ = [
    os.path.abspath(path)
    for path in pkgutil.extend_path( __path__ , __name__ )
]
EOF

cat <<EOF > /tmp/staging/base/pyproject.toml
[build-system]
requires = ["setuptools @ git+https://github.com/pypa/setuptools@feature/pep660"]
build-backend = "setuptools.build_meta"
EOF

mkdir -p /tmp/staging/addon1/pkg/addons/addon1
cp /tmp/staging/base/pyproject.toml /tmp/staging/addon1/pyproject.toml
echo -e "[project]\nname = 'addon1'\nversion = '0.42'" >> /tmp/staging/addon1/pyproject.toml
cp /tmp/staging/base/pkg/ __init__.py /tmp/staging/addon1/pkg/ __init__.py
cp /tmp/staging/base/pkg/ __init__.py /tmp/staging/addon1/pkg/addons/ __init__.py
echo "addon = 1" > /tmp/staging/addon1/pkg/addons/addon1/ __init__.py

mkdir -p /tmp/staging/addon2/pkg/addons/addon2
cp /tmp/staging/base/pyproject.toml /tmp/staging/addon2/pyproject.toml
echo -e "[project]\nname = 'addon2'\nversion = '0.42'" >> /tmp/staging/addon2/pyproject.toml
cp /tmp/staging/base/pkg/ __init__.py /tmp/staging/addon2/pkg/ __init__.py
cp /tmp/staging/base/pkg/ __init__.py /tmp/staging/addon2/pkg/addons/ __init__.py
echo "addon = 2" > /tmp/staging/addon2/pkg/addons/addon2/ __init__.py

cd /tmp/staging
virtualenv -p py38 .venv
.venv/bin/python -m pip install -U 'pip==22.1.2'
.venv/bin/python -m pip install base
.venv/bin/python -m pip install -e addon1 --config-setting editable-mode=strict
.venv/bin/python -m pip install -e addon2 --config-setting editable-mode=strict

cd /tmp
/tmp/staging/.venv/bin/python -I -c 'import pkg.addons.addon1; print(pkg.addons.addon1.addon)' # => 1
/tmp/staging/.venv/bin/python -I -c 'import pkg.addons.addon2; print(pkg.addons.addon2.addon)' # => 2
/tmp/staging/.venv/bin/python -I -c 'import pkg.addons; print(pkg.addons. __path__ )'
# ['/tmp/staging/addon1/build/ __editable__.addon1-0.42-cp38-cp38-linux_x86_64/pkg/addons',
# '/tmp/staging/addon2/build/ __editable__.addon2-0.42-cp38-cp38-linux_x86_64/pkg/addons']

```

In this example it does not matter if the original `base` project has a `addons` folder or not (with the corresponding `pkgutil` trick in ` __init__.py`)… Everything seems to be working fine… Am I missing some details?

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 4, 2022, 1:34pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/28 "2022-07-04T13:34:05Z")

</div>

> [@sbidoul](#):
>
> But in editable mode Odoo relies on the presence of an `addons` directory next to the `odoo` directory, which does not exist in the strict link farm

That would also be the case with static `.pth` files, wouldn’t it?

(Unless we add support for links inside wheels as mentioned by Paul, I think that would be a limitation of all forms of editable installs we have available nowadays).

---

<div class="post-metadata">

**Author:** ![saaketp](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/saaketp/32/6703_2.png) [@saaketp](https://discuss.python.org/u/saaketp)\
**Post date:** [July 4, 2022, 2:37pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/29 "2022-07-04T14:37:13Z")

</div>

Looks like the stable version 63.x also has PEP 660 support now, so this still works.  
I didn’t see it mentioned in the [changelog](https://setuptools.pypa.io/en/latest/history.html), but it probably should be?

My experience is mostly like what others have said already.  
I converted some simple projects from setup.cfg + setup.py to pyproject.toml only, and it worked perfectly well (the only non-standard thing was setuptools\_scm and package\_data).  
I only tried the “normal” non-strict editable install and it works as expected.

The only thing I don’t like is that it still puts the egg-info folder beside the package folder when doing editable install, but that was a problem in the old way too and probably unrelated to the PEP 660 support.

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 4, 2022, 2:50pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/30 "2022-07-04T14:50:03Z")

</div>

Sorry @saaketp, I think the stable version 63 does not include PEP 660 support. In my calculations there would be no breaking change in setuptools until we landed editable support, but during the weekend there was another change that got in first, requiring a major bump.

Since setuptools uses an automatic version bump system, sometimes it is a but hard to precise when a feature under development will be able to get in. When PEP 660 finally lands, there will be an entry in the changelog.

---

<div class="post-metadata">

**Author:** ![saaketp](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/saaketp/32/6703_2.png) [@saaketp](https://discuss.python.org/u/saaketp)\
**Post date:** [July 4, 2022, 2:57pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/31 "2022-07-04T14:57:39Z")

</div>

Hmm, okay it does fail now when I try in a new venv, not sure what was wrong in the other venv when I tried it earlier, but that time editable install worked with `requires = ["setuptools>=63.0"]`.

So now we need `requires = ["setuptools==63.0.0b1"]` in the `[build-system]` section, `>=` gets the stable one and fails.

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 4, 2022, 2:59pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/32 "2022-07-04T14:59:51Z")

</div>

Sorry for the disruption

I think that for test purposes, the best would be to stick with `"setuptools @ git+https://github.com/pypa/setuptools@feature/pep660"` for now, this way we avoid any problems with eventual intermediary releases.

---

<div class="post-metadata">

**Author:** ![sbidoul](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/sbidoul/32/244_2.png) [@sbidoul](https://discuss.python.org/u/sbidoul)\
**Post date:** [July 5, 2022, 8:31am UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/33 "2022-07-05T08:31:41Z")

</div>

> [@abravalheri](#):
>
> I would like to understand a bit better why the `strict` mode is not working for this use case

The `strict` mode does work perfectly with regards to pkgutil.extends\_path. No worries about that - sorry if I was unclear previously.

> [@abravalheri](#):
>
> > [@sbidoul](#):
> >
> > But in editable mode Odoo relies on the presence of an `addons` directory next to the `odoo` directory, which does not exist in the strict link farm
> 
> That would also be the case with static `.pth` files, wouldn’t it?

Odoo is basically trying to locate. `Path( __file__ ).parent.parent / "addons"` as a convenience when running from a git checkout. In `strict` editable mode it would have to do `Path( __file__ ).parent.parent.parent / "addons"`, or resolve the symlink.

That’s a subtle side effect of importing symlinked code.

Note that that would _not_ be a problem case with the static .pth.

For the case of Odoo I used for testing, there are workarounds. An in-tree backend is needed anyway and it can enforce the use of the strict mode as well as doing other tweaks.

So, to sum up, there are two separate and independent topics here:

- pkgutil not compatible with the top level finder mode (as alluded to in the limitations, and forcing to use src layout or strict mode)
- the fact the code is imported from a symlink farm may leak through one way or another

I’ll leave it up to you, of course, to decide whether these are worth further clarifying in the documentation, or whether the issues would be prevalent enough to warrant exposing the 3 modes via the config setting to provide more control to users.

Thanks again for this effort!

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 6, 2022, 8:27am UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/34 "2022-07-06T08:27:25Z")

</div>

Hi @sbidoul, I think I understand a little bit better now, thank you very much for the explanation. Sorry for being so persistent, I really wanted to have a clear idea on what are the shortcomings of the selected approaches 😅.

We definitely need to improve the documentation and I will work on that\[1\].

> [@sbidoul](#):
>
> the fact the code is imported from a symlink farm may leak through one way or another

Would this be a general problem, or would it only happen when the project make assumptions on how the package is installed without considering all possibilities offered by `importlib`? In the example from last comment, it looks like some parts of the code are relying on circumstances external to the editable installation _per se_, but I don’t think PEP 660 guarantees anything about the specific installation layout\[2\].

* * *

As long as one of the supported approaches can work for the use cases that don’t make assumptions external to PEP 660, I would prefer keeping only `editable_mode=strict` (or any bike-shedding equivalent names) as user facing interface\[3\]. But I don’t feel like I should make this decision alone.

Would you like to create a discussion on setuptools repo and try to involve the other maintainers? I would also welcome any opinions of the other members of the community that have more experience on this topic.

* * *

1. In my mind, something that would really help here is if we could display some warnings to the users after `pip install -e .` (not all the backend logs, I understand they might be very verbose, but only the warnings).  
In the implementation for all editable strategies, I added a short paragraph trying to express the their main limitations (that can be expanded to cover `pkgutil` namespaces). But currently these messages are hidden by default… I am not sure what would be the best UI for this and I also understand that this is difficult to implement from `pip`’s point of view. 

2. _Could this be considered a backwards incompatible change in `setuptools`?_ Under Hyrum’s law, probably. But I don’t think `setuptools` make many explicit promises about `setup.py develop` (the existing docs do mention `.egg-link` and `links to your project’s source code` but the specifics on how this work are left for the user’s imagination - the only guarantee seems to be that the package will be available on `sys.path`). Nevertheless the existence of a new PEP should be a good reason to introduce some level of backward incompatibility (which I wish to minimise as much as possible). 

3. My interpretation of everything I read when working on this, is that there is some level of consensus in the PEP 660 discussions: in general people seem to agree that simply adding the root project folder to `sys.path` is not the best idea (understandably, because it leads to effectively installing unintentional packages like `docs`, `tests`, `examples`, or single modules like `noxfile`, `tasks`, `setup` as a side effect), and that a `MetaPathFinder` or links (as long as they work on Windows) are the way to go.

---

<div class="post-metadata">

**Author:** ![jenshnielsen](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jenshnielsen/32/8277_2.png) [@jenshnielsen](https://discuss.python.org/u/jenshnielsen)\
**Post date:** [August 1, 2022, 8:35am UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/35 "2022-08-01T08:35:56Z")

</div>

I have tried testing this on a project where I use [versioningit](https://pypi.org/project/versioningit/) along with its [onbuild feature](https://versioningit.readthedocs.io/en/stable/runtime-version.html)

The onbuild feature is meant to update a version string in the package when building a wheel/sdist but not when performing an editable install. When performing the editable install I expect the code to remain unchanged and ` __version__ ` to be assigned the output of a function that calls git describe under the hood to get the version from git tags and hashes. E.g. my code contains ` __version__ = _get_version()` which should be overwritten with ` __version__ = 0.0.1` or similar when installing the package (except as an editable install)

The feature is implemented using cmdclass with a setup.py that looks like this:

```auto
from setuptools import setup
from versioningit import get_cmdclasses

if __name__ == " __main__":
    setup(
        cmdclass=get_cmdclasses(),
    )

```

This works fine with the legacy editable install but with this branch I am seeing an error when installing as editable. (Also works as expected using build to produce sdist/bdist and using `pip install .`

```auto
❯ pip install -e .
Obtaining file:///C:/Users/jenielse/source/repos/debugproject
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Installing backend dependencies ... done
  Preparing editable metadata (pyproject.toml) ... done
Requirement already satisfied: versioningit>=1.1.0 in c:\users\jenielse\miniconda3\envs\qcodespip38\lib\site-packages (from debugproject==0.0.1.post3+g1aea130) (2.0.0)
Requirement already satisfied: tomli<3.0,>=1.2 in c:\users\jenielse\miniconda3\envs\qcodespip38\lib\site-packages (from versioningit>=1.1.0->debugproject==0.0.1.post3+g1aea130) (2.0.1)
Requirement already satisfied: packaging>=17.1 in c:\users\jenielse\miniconda3\envs\qcodespip38\lib\site-packages (from versioningit>=1.1.0->debugproject==0.0.1.post3+g1aea130) (21.3)
Requirement already satisfied: importlib-metadata>=3.6 in c:\users\jenielse\miniconda3\envs\qcodespip38\lib\site-packages (from versioningit>=1.1.0->debugproject==0.0.1.post3+g1aea130) (4.12.0)
Requirement already satisfied: zipp>=0.5 in c:\users\jenielse\miniconda3\envs\qcodespip38\lib\site-packages (from importlib-metadata>=3.6->versioningit>=1.1.0->debugproject==0.0.1.post3+g1aea130) (3.8.1)
Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in c:\users\jenielse\miniconda3\envs\qcodespip38\lib\site-packages (from packaging>=17.1->versioningit>=1.1.0->debugproject==0.0.1.post3+g1aea130) (3.0.9)
Building wheels for collected packages: debugproject
  Building editable for debugproject (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Building editable for debugproject (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [68 lines of output]
      running editable_wheel
      creating C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info
      writing C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info\PKG-INFO
      writing dependency_links to C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info\dependency_links.txt
      writing requirements to C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info\requires.txt
      writing top-level names to C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info\top_level.txt
      writing manifest file 'C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info\SOURCES.txt'
      reading manifest file 'C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info\SOURCES.txt'
      adding license file 'LICENSE'
      writing manifest file 'C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject.egg-info\SOURCES.txt'
      creating 'C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject-0.0.1.post3+g1aea130.dist-info'
      adding license file "LICENSE" (matched pattern "LICEN[CS]E*")
      creating C:\Users\jenielse\AppData\Local\Temp\pip-wheel-g3c7z1_y\tmppzq2ikd2\debugproject-0.0.1.post3+g1aea130.dist-info\WHEEL
      running build
      running build_py
      C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\normal\Lib\site-packages\wheel\bdist_wheel.py:80: RuntimeWarning: Config variable 'Py_DEBUG' is unset, Python ABI tag may be incorrect
        if get_flag('Py_DEBUG',
      C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\command\install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
        warnings.warn(
      Traceback (most recent call last):
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\command\editable_wheel.py", line 101, in run
          self._create_wheel_file(bdist_wheel)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\command\editable_wheel.py", line 247, in _create_wheel_file
          files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\command\editable_wheel.py", line 220, in _run_build_commands
          self.run_command("build")
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\_distutils\cmd.py", line 317, in run_command
          self.distribution.run_command(command)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\dist.py", line 1217, in run_command
          super().run_command(command)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\_distutils\dist.py", line 987, in run_command
          cmd_obj.run()
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\command\build.py", line 33, in run
          super().run()
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\_distutils\command\build.py", line 131, in run
          self.run_command(cmd_name)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\_distutils\cmd.py", line 317, in run_command
          self.distribution.run_command(command)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\dist.py", line 1217, in run_command
          super().run_command(command)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\setuptools\_distutils\dist.py", line 987, in run_command
          cmd_obj.run()
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\versioningit\cmdclasses.py", line 69, in run
          run_onbuild(
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\versioningit\core.py", line 593, in run_onbuild
          vgit.do_onbuild(
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\versioningit\core.py", line 442, in do_onbuild
          self.onbuild(
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\versioningit\methods.py", line 160, in __call__
          return self.method(params=self.params, **kwargs)
        File "C:\Users\jenielse\AppData\Local\Temp\pip-build-env-0x_b5npw\overlay\Lib\site-packages\versioningit\onbuild.py", line 64, in replace_version_onbuild
          lines = path.read_text(encoding=encoding).splitlines(keepends=True)
        File "C:\Users\jenielse\Miniconda3\envs\qcodespip38\lib\pathlib.py", line 1236, in read_text
          with self.open(mode='r', encoding=encoding, errors=errors) as f:
        File "C:\Users\jenielse\Miniconda3\envs\qcodespip38\lib\pathlib.py", line 1222, in open
          return io.open(self, mode, buffering, encoding, errors, newline,
        File "C:\Users\jenielse\Miniconda3\envs\qcodespip38\lib\pathlib.py", line 1078, in _opener
          return self._accessor.open(self, flags, mode)
      FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\jenielse\\AppData\\Local\\Temp\\tmp_asga1s0.build-lib\\debugproject\\_version.py'
      error: Support for editable installs via PEP 660 was recently introduced
      in `setuptools`. If you are seeing this error, please report to:

      https://github.com/pypa/setuptools/issues

      Meanwhile you can try the legacy behavior by setting an
      environment variable and trying to install again:

      SETUPTOOLS_ENABLE_FEATURES="legacy-editable"
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building editable for debugproject
Failed to build debugproject
ERROR: Could not build wheels for debugproject, which is required to install pyproject.toml-based projects

```

I am unsure if this is a bug or a feature that is no longer supported (cmdclass).

Ideally an editable install should not try to perform this replace at all and should not care that `_version.py` cannot be found.

A sample project showing the error can be seen [here](https://github.com/jenshnielsen/debugproject/tree/test_editable_install)

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [August 1, 2022, 3:04pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/36 "2022-08-01T15:04:16Z")

</div>

Thank you very much for the feedback @jenshnielsen, I [have contacted the plugin author](https://github.com/jwodder/versioningit/pull/38) to discuss what can be done to solve this issue.

The TLDR for why this is happening is the following:

- Previously the `develop` command in setuptools would only run `build_ext` and not `build_py`. `versioningit` seems to be taking advantage of this behaviour.
- In the changes I have implemented in [`pypa/setuptools@feature/pep660`](https://github.com/pypa/setuptools/blob/49e21527f9e59ca881dab360e125bb2b17280694/setuptools/command/build_py.py#L56), every build command (this generalisation includes `build_py`) has the chance to decide to run (or not) on editable installs\[1\]. This happens inside the `run` method, which is overwritten by `versioningit`.

My proposal for `versioningit` is based on [this procedure](https://setuptools--3429.org.readthedocs.build/en/3429/userguide/extension.html#supporting-sdists-and-editable-installs-in-build-sub-commands) for implementing custom build steps.

* * *

1. The motivation for this is to improve support for custom build steps.

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [August 1, 2022, 4:22pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/37 "2022-08-01T16:22:41Z")

</div>

Hi @jenshnielsen, it seems that [versioningit v2.0.1](https://github.com/jwodder/versioningit/releases/tag/v2.0.1) is out now and it should support your use case with PEP 660.

---

<div class="post-metadata">

**Author:** ![jenshnielsen](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jenshnielsen/32/8277_2.png) [@jenshnielsen](https://discuss.python.org/u/jenshnielsen)\
**Post date:** [August 1, 2022, 6:28pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/38 "2022-08-01T18:28:49Z")

</div>

> [@abravalheri](#):
>
> r

Thanks a lot @abravalheri for the quick response. I can confirm that this resolves the issue.

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [August 4, 2022, 6:13pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/39 "2022-08-04T18:13:24Z")

</div>

Hi @sbidoul, sorry for the delay in getting back to this topic.

After some discussion about the topic, I have [implemented](https://github.com/pypa/setuptools/tree/feature/pep660) a `compat` mode that is meant as a temporary workaround during the transition period, so people have time to adapt to the changes. I am currently considering a period of 6 months, after which I would like to remove this `compat` mode.

The compat mode will try to emulate the behaviour of the existing `develop` command (i.e. use a static `.pth` file).

I have also updated the docs with a more detailed list of limitations and a brief summary of how the editable installation is performed:

[https://setuptools--3485.org.readthedocs.build/en/3485/userguide/development\_mode.html](https://setuptools--3485.org.readthedocs.build/en/3485/userguide/development_mode.html)

I hope this is useful.

---

<div class="post-metadata">

**Author:** ![jenshnielsen](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jenshnielsen/32/8277_2.png) [@jenshnielsen](https://discuss.python.org/u/jenshnielsen)\
**Post date:** [August 5, 2022, 12:27pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/40 "2022-08-05T12:27:03Z")

</div>

**Mypy does not find py.typed in non-strict mode**

While testing the new pep660 feature I have found that mypy does not work as expected. This seems to be a regression compared to the legacy mode.

In short, I have a project in a flat layout containing a py.typed file within the toplevel folder of the source  
e.g. `debugproject\debugproject\` contains ` __init__.py` `foo.py` and an empty `py.typed` file.

The file is included as package data with the following config in setup.cfg

```auto
[options]
zip_safe = False
packages = find:

[options.package_data]
* =
    py.typed

```

I have verified that the `py.typed` file gets installed as expected using `pip install .` and is a part of the bdist/sdists produced by `python -m build`

Now I run mypy a simple script that imports a class from this project.

```auto
mypy .\test.py

```

where test.py contains a single import

```auto
from debugproject.foo import Foo

```

This raises an error when the package is installed in editable mode using the default non strict config.

```auto
test.py:1: error: Cannot find implementation or library stub for module named "debugproject.foo"
test.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)

```

With legacy editable install this type checks correctly.  
The same is true using the `compat` and `strict` mode.

A sample project with this issue can be found [here](https://github.com/jenshnielsen/debugproject/tree/test_editable_install) (Updated compared to my last comment)

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [August 5, 2022, 1:45pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/41 "2022-08-05T13:45:08Z")

</div>

> [@jenshnielsen](#):
>
> While testing the new pep660 feature I have found that mypy does not work as expected. This seems to be a regression compared to the legacy mode.

Thank you very much for the help testing Jens, and the well thought reproducer.

I checked your example and I think I have an idea what is going on:

It would seem that `mypy` is not taking into consideration the existence of [finders](https://docs.python.org/3/glossary.html#term-finder) defined outside of the stdlib.

Maybe I am wrong here, but I reached this conclusion after running `importlib_resources.files(debugproject).glob("*")` and checking that `py.typed` is indeed listed as part of `debugproject`.

I believe that this limitation is closely related to the [discussion in a different topic](https://discuss.python.org/t/pep-660-support-and-ides/13878) about PEP 660, IDEs and static code analysis. If we look at that thread and replace the occurrences of “IDE” with “static code analysis tool”, everything is pretty much applicable for this use case.

The TL;DR that I got from this other thread is that the packaging community is open to discuss different mechanisms to facilitate interoperating with static analysis tools, but this topic of conversation has not been explored yet.

* * *

On the bright side, if you install your project using the `strict` mode, mypy seems to work well:

```bash
pip install -e . --config-settings editable-mode=strict
echo "from debugproject.foo import Foo" > test.py
.venv/bin/mypy test.py
# Success: no issues found in 1 source file

```

I also believe that projects using the `src`-layout should work as normally.

---

<div class="post-metadata">

**Author:** ![jenshnielsen](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jenshnielsen/32/8277_2.png) [@jenshnielsen](https://discuss.python.org/u/jenshnielsen)\
**Post date:** [August 5, 2022, 2:00pm UTC](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904/42 "2022-08-05T14:00:05Z")

</div>

Thanks @abravalheri I also just discovered [Add support for PEP-610 editable packages (#12313) by hashstat · Pull Request #12315 · python/mypy · GitHub](https://github.com/python/mypy/pull/12315) / [Support finding "editable" type annotated packages made editable through direct\_url.json · Issue #12313 · python/mypy · GitHub](https://github.com/python/mypy/pull/12313) which looks like it may be trying to solve the issue from the mypy side.

I can also confirm that strict mode does indeed resolve the issue.

[Previous page](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904.md?page=1)

[Next page](https://discuss.python.org/t/help-testing-pep-660-support-in-setuptools/16904.md?page=3)
