PEP 660: Editable installs for PEP-517 style build backends

I was actually about to create a post here that was set to be a wiki to make it easier for people to coordinate/write together (I’m not an editable install user, so I was doing it just to help focus energy towards an end result). But using a wiki post might alleviate the load if you want help in writing the PEP.

As a long time vocal open source person I think I know exactly how Paul G feels, but I think the argument for PEP 660 is clear. Hopefully no one else is emotionally invested in preventing the mechanism. Thanks for engaging on this issue, so I can finally pip install -e . in my little experimental build system without mocking setup.py.

I’ll add a couple of final points here, just as summary/feedback.

  1. An editable install by definition means that the user has the ability to change the project source. So it’s perfectly plausible to ask the user to add configuration like setuptools.editable_style = "pth". to pyproject.toml if they want to select a particular type of editable install. So while I agree that it’s possible users may want control over the style of editable mechanism, I don’t think PEP 660 precludes that.
  2. It should be possible to write a PEP 660 backend that “wraps” an existing backend, adding the build_wheel_for_editable hook and communicating with the underlying backend in any way it chooses. In particular, it could communicate with the underlying backend using the “virtual wheel” approach. So that implies that anything the “virtual wheel” approach offers is also possible via PEP 660, with the addition of a little bit of integration boilerplate.

I’m wary of characterising either approach as a “strict superset” of the other, but as one of the arguments for “virtual wheels” is that it can do pretty much everything that PEP 660 can, I thought it would be worth making these points for contrast.

PS I’ll also note that I’m only an occasional user of editable installs myself, so I have no vested interest in either solution over the other. My interest comes mainly from wanting to be able to give an answer to pip users who want to know why pip install -e is limited to legacy setuptools projects. So yes, I do have an interest in getting something sorted sooner rather than later - but conversely I’d like to see the solution done right, so we don’t have to keep revisiting this subject as users find edge cases we didn’t consider.

1 Like

But we willing to end it to break all the world?

In my view the most important benefit of PEP 660 compared to virtual wheels is that it allows for easier experimentation and innovation.

It seems quite clear that the community has a wide range of theoretical and practical expectations about editable installs. The reality is that the only one there is wide experience with is path insertion via .pth (i.e. what setup.py develop does). editables is a very promising approach, yet it has been mentioned it does not cover all use cases.

With PEP 660, several approaches are possible without any change to the specification nor to frontends. For example these only require backend variations:

All these would require additional wording in a virtual wheel specification, plus specific frontend support, in addition to backend support.

So, in my opinion the additional specification and implementation complexity of virtual wheels is real, and would certainly cause more delay.

While I do understand and appreciate the argument that the choice of “editable style” should be left to the frontend/developer, I think it is not worth the additional complexity, especially knowing that this choice can still be passed to a PEP 660 backend via config settings [1] or another environmental mechanism.

I plan to add wording like this in the rejected ideas section of PEP 660 that refers to virtual wheels. I hope it captures the essence of the discussion.

If there are other ideas that were mentioned elsewhere that people feel should be mentioned in PEP 660, just let me know.

[1] config settings have not been implemented because they lack concrete use cases and no-one has really asked for them so far

4 Likes

Hey folks, I’ve wrote up the competing PEP under TBD: Editable installs by gaborbernat · Pull Request #1977 · python/peps · GitHub (if you’re a core dev and like what it’s proposing please ping me if you wish to sponsor it). Feedback welcome, hope is moderately readable though.

Discussion on proposal moved to Discuss TBD: Editable installs by gaborbernat

I think PEP 609 -- PyPA Governance | Python.org means you don’t need an explicit sponsor since you are already a member of the PyPA. But having a core dev does make things easier for marking someone in CODEOWNERS as being in charge of merging PRs for your PEP.

2 Likes

One option that is not supported is a set of symlinks, the way flit currently implements editable installs. This is because the wheel format doesn’t support symlinks. There has been talk about adding symlink support to wheel, but at this moment, that wouldn’t be an option.

I don’t have an opinion as to whether this is a major issue. Maybe @takluyver could confirm whether flit is OK with changing its editable install approach?

I’ll see to add a mention about symlinks in the text.

Note that flit does support .pth too, and the flit POC linked in the initial post is based on that. It works just fine, especially with the src layout that flit now supports too.

As a side note I do have a requirement to use symlinks in a custom backend and I could implement it with PEP 660 by generating the symlinks on interpreter startup (via an executable .pth that is put in the wheel by the backend). It is a not particularly elegant, but I just wanted to note that it is possible today.

1 Like

I mean, it’s a general purpose computer, so you could get it to do whatever you want. My point is that changing the project configuration is not usually the right way to specify things that change between use cases.

Consider the case of someone who is working on a project in an IDE and also running console scripts in a terminal. Their IDE may want to do an editable install into one virtual environment using a mechanism that allows the IDE to interactively rebuild certain things, or that makes different trade-offs (e.g. the IDE knows when you add files because it’s doing the file adding, so it may want the stricter approach), while for the purposes of the use of the terminal, you’d want to use pip or some other tool that does things a different way. In the “backend config” model, you’d have to toggle the configuration for the whole project depending on which tool you are using, and you are using them simultaneously.

Consider also that most backends will not implement multiple different editable install modes, so it won’t be a simple matter of just changing .editable_style somewhere, it will often be the case that if you want a different editable style you need to switch your build backend, which is a lot of lift for a configuration change.

So yes, usually the person doing the configuration also can change backend configuration, but from a UX perspective it’s best to assume that all changes to backend configuration are project-wide and long term while front-end configuration is per-invocation.

I’m sorry but there really is an asymmetry here because of the information that the standard exposes. In PEP 660, the only information that the front-end is transmitting to the back-end is “This should be an editable install”. The back-end then changes what goes in the wheel in an arbitrary and unspecified way, opaque to the front-end. Theoretically a front-end could be aware of all the mechanisms that every backend uses, introspect the wheel and attempt to reverse engineer how to expose the right files, but I think we’d all be comfortable saying that this approach is not going to be supported.

In the “virtual wheel” proposal (note: the wheel doesn’t have to be virtual, it could be an actual wheel file with a file ↔ file mapping in text or something), the front-end still communicates the same information to the back-end, because it’s still letting the back-end know that it needs to build an editable wheel. The difference is that the back-end now communicates more information to the front-end, namely it’s telling the front-end enough information to expose the right files in the right places, which is something that only the back-end knows, and is basically the raison d’être of a back-end. I don’t think it would be prudent for the back-end to build a completely different thing when build_editable is called, but if there’s any problem that only the backend can solve because of something specific to the project or the nature of the backend, the backend has all the information it needs to solve that problem, and the only difference is that any files it was going to generate and put in the “editable wheel” file needs to be a file that exists locally on disk.

That is why I say that my proposal is a strict superset of the PEP 660 proposal, because the back-end has all the same information it gets in PEP 660, but in my proposal the front-end gets more information and in most cases (basically every case that I can think of), it gets enough information to create an editable install that is as good or better than what we have now.

I’m not clear why you think these are not possible in a virtual wheel specification. None of these require special handling in a “virtual wheel” (though it may be misleading to call it a “virtual wheel” because the fact that there’s no file on disk is not the salient part of the proposal — the important part is that what’s transmitted from the backend to the frontend is a mapping from location on disk to install-time layout).

When building a wheel, a backend needs to take resources on disk and translate them into an install-time layout. Right now it does that by copying them, but if instead of copying them it were to just record the mapping and expose that to the front-end, the front-end can, instead of copying, make those files directly available to the interpreter. The front-end then has the option to:

  1. Use .pth files to insert all directories containing the relevant files into the Python path (à la .pth).
  2. Generate a wrapper file that exposes only the files listed in the mapping (à la editables)
  3. Use symlinks to directly implement the mapping
  4. Something else of its choosing.

And importantly, this choice will be up to the person running the install, and not a per-project setting. Since we’re talking about a mapping (e.g. {'/path/to/source/src/myproject/__init__.py': 'myproject/__init__.py'}), the backend still defines how the input and output structures map onto one another, so it would not be a problem to have a different installed layout from the source layout.

I did not say they are not possible. I’m not going to rehash my argument, please re-read my post.

I have re-read it and I still don’t understand why you think it would be any more complex. What about my description of how to achieve those things makes you think any additional complexity is needed? No special support is required from backends for any of those things, they just implement the spec as normal. The complexity that was on the backend (implementing the editable installs) moves to the front-end, which is more qualified to implement it anyway (since front-ends can specialize to specific platforms, etc, and in general they know more about the system they are installing into).

I genuinely want to know why you think these things are more difficult to achieve or require more complexity in my proposal, because I suspect it means I haven’t adequately explained what I’m proposing or I’m missing something fundamental.

Another note here. PEP 660 says

Build backends may use different techniques to achive the goals of an editable install. This section provides examples and is not normative.

in what to put in the wheel. In theory, a backend could put any old junk in the wheel and claim to be compliant. While I don’t want to open up the question of “do we define what it means to be an editable install?” again, can we at least say something like

Build backends must populate the generated wheel with files that when installed will result in an editable install. Backends may use different techniques…

That way we’re being explicit that it is the backend’s responsibility to achieve the effect of an editable install.

This PEP does not cover at all how would this work for C-extensions. Namely, when within the wheel you’d have pyd/so files, data, scripts or include. The way editables package is today only handles pure python files. What should a backend do when it would generate data/scripts/include files into the wheel?

I’m extremely perplexed by this question, which makes me think I’m missing something fundamental.

If editables exposes /path/to/foo as package foo, and you have built .(pyd|so) files properly within said path, what is the issue?

Consider this example project GitHub - gaborbernat/pi-approx How would an editable install work with PEP-660? There’s no source file to link, just a binary module. Would you expose the project root? Can editables handle this today? Can we ensure that we only expose the pyd file and nothing else?

Yes, and yes via the add_to_path method. This is how namespaced packages are supported btw

Unsure, but why not put it in a package?

If you add the root folder to the path wouldn’t that make setup.py import-able?

Because then it would not be an editable install. Generally editable installs link the artefacts inline, no? So that if I recompile the pyd|so I can use it without needing to reinstall the editable wheel?

Note this use case could be solved via a simple symlink between the source trees pyd file and the target interpreters platlib folder. Not sure how this work though in a PEP-660 world.

I meant put it in src/foo and expose src or put it directly in src