-
Notifications
You must be signed in to change notification settings - Fork 69
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
Add support for editable wheels #47
Comments
I'm not sure what this means exactly, can you elaborate? The files needed for a working package are split between in-tree and build-dir. My understanding was that you planned to write out an install directory with symlinks for all files, with those symlinks pointing back to both directories. |
Not really, if I have an install directory, we'd have to run Does that make sense to you? Is there anything you want me to clarify? |
Ah, do you mean put symlinks into the build dir, pointing back at |
No, the editable wheel would include symlinks to the build directory or source tree, depending if the file is generated or not. The current approach for normal wheels is to run The issue is that we would depend on the build directory existing, but I don't think it is that big of a deal since we already depend on the source tree anyway. An alternative would be to maintain our own build directory, but that has a couple issues which I can go into more detail if you want. |
Ah, now I get it. I thought there was an issue with this, that's why I didn't make the connection that the symlinks would be in the wheel. Found the discussion now: cupy/cupy#6261 (comment). It says " when generating a wheel all symlinks are "materialized"". Not sure if that applies here or not - I guess not, because the root cause is the What I had expected was writing directly a separate directory of symlinks, and then use a Okay, sounds like this should work and if it does, seems like a good plan to me.
Agreed, that's perfectly fine I'd say. |
That would be a bit tricky, and is not really needed since we can include symlinks in the wheel. I think long term my plan would probably be to add an import hook, which would do the same job as a |
Now I'm a little confused again - if the wheel contains all the symlinks we need, why do we also need an import hook? Or are these two unrelated points? |
That is just a future plan, which would be similar to what you described initially with the |
I am confused. The madness about wheel support is you can't do this. |
Yeah, I was looking into that. The issue is that pypa/wheel does not support extracting symlinks, making this approach unusable, as most projects use it to extract wheels. We will have to go with the more complex approach of using a |
Implemented in #87, we will go through a pre-release before a proper release with the new feature. |
🎉. Let's close this then |
(If you prefer a different place to discuss this, I'm happy to post there!) Hey, thanks everyone for working on this in #87! I've just tested this with the current However, I also noticed that this is not (yet) a drop-in replacement for the behavior of old-style editable installs: as far as I understand it the approach implemented in #87 doesn't actually use the source files of a project but maintains a copy in Unfortunately, the current behavior does not provide the main feature of an editable install that I had hoped for: that executed .py files are identical with the source files in a project. I would rather call the current implementation an "syncing or updating install" rather than an editable one. IDEs / debuggers (e.g. PyCharm) execute the code in I also noticed that the current trigger mechanism also doesn't play well with ipython's autoreload magic Sorry, for not providing this feedback earlier, I did not really understand the approach that was suggested here. I also realize that this is a "but it breaks my workflow". 😉 However, I imagine that many other developers will face similar problems. So I thought I'd bring this up in the hope that there's a solution. At this point, I'm also wondering how you guys solve this use case for yourselves. Are you using tools that make this issue go away or do you just rarely use a debugger? |
@lagru thanks for your feedback! Before diving into possible design improvements, let's first detail out the usage issues a bit more. Using the debugger seems like the key issue (also brought up for SciPy).
This is only an issue when there's an observable difference. If there's an auto-sync on every relevant user action, it should not matter.
I have to say that I'm not using a debugger on a daily basis, but when I do use one then here are the ways I use it:
That should work fine (auto-syncing will copy that |
Moving part of the discussion we had on SciPy's issue tracker. If I use Pytest from the CLI and ask it to discover SciPy's test or start an interpreter and import SciPy, it's working. The issue is that it uses files from
This is a problem as with the IDE's if you put a breakpoint or ask to run a specific test, it's doing this in the original file. It has no knowledge of And when trying to use the IDE to launch a test (you have the original file open, and click on one test to make it run), it complains about an import mismatch:
The current workaround is to open in the IDE files in |
I wonder if a custom loader built on top of the |
Good call and gladly! A very common use case is the following: I want to test the behavior of a Python snippet, either to reproduce a bug report or test some other functionality. I'll paste that into PyCharm's IPython console, enable the debugger, navigate to the appropriate source file(s) in the IDE to set a breakpoint and then execute the prompt. For the navigation part I can use all the bell's an whistles the IDE provides, usually I just search for the function I need or click on a file path in a provided traceback (the last bit works with #87 too). This approach allows for fast iteration, as I can easily repeat the prompt with different inputs, modify breakpoints and try different patches in the same place. With #87, the code I step through during debugging and the code I try patches on is in two different places. #87 helps in synchronizing in one direction but I doesn't help with having to open the duplicated file in the IDE twice and keeping in mind which is which. And it doesn't help that the executed part is nested several directories deep. I hope this explanation makes it a lot clearer for you. Thanks for pointing out ipdb, I'll give it a whirl! However, ideally I would hope that meson-python would play nice out of the box with as much developer tooling out there as possible. Which brings me to the next part.
There is an observable difference: the location in the file tree is different. This results in a lot of issues because it's an assumption made by most dev tools in Python land: e.g. pytest as pointed out by @tupui, debuggers, autoreload, ... and many we are not aware of (yet). The synchronization solves only one part of the problem, and does so under the big assumption that a fresh import has been made beforehand (e.g. not true for workflows staying / iterating in an active shell).
This would only solve the problem for one tool out there, wouldn't it? Patching or accommodating dev tools out there (or expecting them to do it) sounds like a significant additional maintenance burden to me. Earlier I mentioned pointing |
It seems to me that symlinks will still be the right way to solve this. That way the IDE code navigation will end up opening the right files for sure; pdb should also work then I'd hope (but not 100% sure of that). Once wheels support symlinks, that should be the way to go imho. Moving that symlink support along is good for other reasons as well.
That's not great I think. Having the source tree be completely unchanged is a natural and nice property of out of tree builds. For example, it makes it unnecessary to maintain elaborate |
Would
That is indeed a really nice behavior to have in a build system and I completely agree with this as a worthwhile goal. |
Yes indeed. That was our original idea, and it seems like the most obvious one. The blocker was/is that the wheel format does not support symlinks.
This fs.copyfile('_conftest.py', 'conftest.py', install: true, install_dir: py3.get_install_dir() / 'scipy') then I suspect that things will work fine. Same as things being already fine if you have your |
@rgommers I needed to do Now it's going a bit further but fails with another mismatch (this is what I launch a test from the UI, clicking a green arrow):
|
Ah, that's a problem. I'm not sure there's a way around that |
The only reasonable solution I can think of right now is to skip the |
Would implementing a custom I haven't played with this aspect of Python before, but if the import mechanism can be made to load code from a zip file, it can be probably be taught to load code from arbitrary paths. What would need to be done is to use the install path data provided by meson to construct a "virtual" module hierarchy of the package content and traverse it to find the file to load for a given module name. I'll try to have a look to whether this is a viable solution later today. Update: re-reading the comments in #87, I think the approach taken by @FFY00 initially was similar to what is proposed here. IIUC implementing support for package resources (in the |
Yes, I believe that it would, but we would only know for sure until we try it. But for now, what I mentioned above should be enough, if having a symlink is enough to trick IDEs into working properly. The plan was always to eventually shift into a custom import loader approach. |
Just a note: on v0.13.0rc0 I replaced the |
The last thing preventing this from being adopted in the wild is probably the missing support for editable wheels.
For the implementation, the idea is simple, create an editable wheel with the files from the build directory. The editable install would always need to be tied down to the build directory, which is the most annoying thing with this approach, but doing it other way would be more difficult, and very likely require some more work from the build system users.
The main worries with the implementation is that we might need to fix up some RPATHs, but I am hoping we won't, as that would bring in more complexity.
We will also likely need to do some code refactoring to re-use the logic from the normal wheel building, but I suspect that might end being too complex and not worth it. In which case, we might be better off with a little bit of code duplication. The jury's still out on that, we need to investigate and then make a call.
@rgommers does this sound reasonable to you?
The text was updated successfully, but these errors were encountered: