-
-
Notifications
You must be signed in to change notification settings - Fork 30.5k
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
Clarification about how to implement namespace packages (as in PEP 420) via import hooks for PEP 660 use case #92054
Comments
I'm going to preface all of this with @ericvsmith is the namespace package expert. 😅
I don't think so. Easiest way to check is to search for
As in that exact call signature for
The language spec just says it "works" without giving details in how. I think there are two possible ways to solve this (and we probably want both long-term). One, you register a custom finder that effectively re-implements namespace packages the way you need it to work. Two, we develop whatever APIs, etc. you need to make this as pluggable as possible. |
Thank you very much for the clarifications @brettcannon. I agree with your conclusions, if there were APIs officially supported for implementing the namespace packages using a custom finders, I would be more than happy to use them. The main problem that I am facing right now is the impression that things work "accidentally". I think it is also worth a shot considering the importance of editable installs in the community. |
Yep, this is just pushing up against the niche nature of namespace packages. All of the hard-coded locations of using namespace-related classes seem to be: cpython/Lib/importlib/_bootstrap_external.py Lines 1496 to 1499 in a91ffcf
cpython/Lib/importlib/_bootstrap_external.py Lines 1514 to 1519 in a91ffcf
cpython/Lib/importlib/_bootstrap.py Lines 505 to 512 in f4c0348
The first two are all in But the latter is deep in the import system, and so that would require something on This is also assuming I didn't miss a spot. 😅 |
Would this entry also be relevant? cpython/Lib/importlib/_bootstrap_external.py Lines 1409 to 1411 in 605e9c6
It also seems that in 3.11 It would seem that the existing behaviour is highly dependent on |
Yep.
Correct. We purposefully didn't over-expose an API we would have to support for a decade or more when no one had really asked for access previously. |
Please let me know if there is anything I can do to help with this. As I previously mentioned, approach B seems to work right now across the major active versions of CPython (tested in setuptools), and it does not involve using soon-to-be-deprecated functionality as Brainstoming of alternatives/complementary approaches
|
More free time or get @warsaw , @ericvsmith , or @ericsnowcurrently to weigh in. |
TBH, I'd totally forgotten about that language in the PEP. @ericvsmith, I don't remember why this was added. That said, while I can understand that there might be some usefulness to this in deployed code, I'm not sure how useful it is in the same environments where you'd want editable installs (during the development process, right?). I personally can't remember any time where I or a package I've used relied on this behavior.
The one place folks seem to have missed is in importlib.resources.reader. There's a shallow dependency on the
I've thought about exposing |
Thank you very much for the comments @warsaw.
As long as developers are allowed to create and publish namespace packages, editable installs will be relevant during the development process of those packages. I don't know how many namespace packages are published in PyPI, but I would not be surprised if their authors/maintainers use an editable install when implementing changes/bugfixes/features etc. As an anecdote (that might not be representative of the general tendencies), when I asked about feedback from the community about setuptools candidate implementation of PEP 660, one of the few responses I got back was about a package using namespaces1. Footnotes
|
I should have been more clear in my comment. In fact, I'm an author of several packages in the |
The dynamic path calculation is the only aspect of namespace packages that is problematic (as far as I can tell, it's been a while since I looked at the code) and to be perfectly honest I'm not completely sure what the use cases are for that feature. In general, we don't try to guarantee what will happen in a running Python process if new packages are installed "in the background", so most of the cases I've been able to come up with for the dynamic path feature feel like things I wouldn't recommend doing anyway... Can anyone explain what the intended use of the dynamic path feature is? If there's no use cases that we actually want to support, would it be easier to simply deprecate the feature? |
I can't. As I said, I didn't even remember that being part of the PEP! 😆
WFM. Or maybe another way to frame the question is, has anybody been asking for this feature? |
IIRC, Nick and PJE wanted the feature. /me checks … https://peps.python.org/pep-0420/#id8 mentions it, and links to where it was discussed. PJE talks about it here: https://mail.python.org/pipermail/python-dev/2012-May/119603.html I think this was included so we could interoperate with legacy namespace packages in setuptools. That use case is probably long gone. |
Cool. So what would be involved in deprecating that behaviour? Would it need a PEP? For the purposes of editable installs we could just not support it, citing this discussion and any subsequent deprecation as the reason, but it would be good to formally deprecate and then remove the feature, to avoid confusion. |
Thank you very much, I will rework the exiting implementation taking this discussion into consideration. Should I also be worried about using the constructor of |
The problem is that we know why the feature was originally added, but we don't know who is relying on it for other reasons. I think this would need a wide discussion, and probably a PEP. |
On reflection, I'm not sure deprecation is the right thing to do here. Having re-read the PEP, the So I think we probably should retain the current behaviour, and ideally make it easier for custom importers to hook into the namespace path mechanism. |
+1
+1 This is where my mind went pretty quickly. 😄 Clearly there's a meaningful case for hooking into/duplicating the namespace path logic. It seems like helpers in importlib.util and/or importlib.machinery (exposing or derived from the existing _bootstrap*.py code) would meet the need here. FWIW, every time I look in _bootstrap*.py and bump into the special-casing for namespace packages, I wonder if there might be a less special-case-y way to get there. At the least, having no public API to replicate the functionality has always seemed off to me. (That said, there is value, of course, in not providing public API until actually needed. 😄) |
Agreed. I'm still wondering, short of deprecating this feature, are there users who are asking for support for this with editable installs? |
I'm not aware of any. My library |
I just recently invited the community to start experimenting with the new editables support, and the current implementation does try its best to be compatible with the dynamic path computation (I am using the approach B discussed above). So I also don't have any input about that. I could try to modify the implementation to not support dynamic path computation and see what would be the reaction of the user base, if that is the core team recommendation. (I imagine if someone were to complain, we are just going to find out after the feature is included in a stable release for |
This is a follow up of 2 previous discussions in the Python discourse and an issue in
pypa/packaging-problems
:Summary
One of the popular ways of implementing PEP 660 is via import hooks (since other alternatives like
symlinking
package folders are not available in all platforms).However the reference implementation
editables
currently does not support namespaces.Specifically the dynamic path computation aspect of PEP 420 is a challenge.
After inspecting the implementation for
importlib._bootstrap_external
, I may have managed to find 2 solutions for this problem, described in the detail in this discourse post and demonstrated as a PoC in this gist:_NamespacePath
behaviour.PathEntryFinder
and add a “bogus” entry tosys.path
just to trigger it (implicitly relying thatimportlib.machinery.PathFinder
will take care of setting__path__
to_NamespacePath
object under the hood).However, the problem is that I don't know if these approaches are reliable in the long run and in accordance with the language specification.
Open Questions
Questions like the following are still not clear to me:
__path__
uses a custom class instead of_NamespacePath
even if the behaviour described in PEP 420 is observed?ModuleSpec("name", None, is_package=True)
?pkgutil
(and particularlypkgutil.extend_path
) still considered first class citizen of the standard library or is it better to avoid it when writing new code?sys.path_hooks
+importlib.machinery.PathFinder
to createModuleSpec
objects for namespaces that will automatically perform dynamic path computation? Or is this an internal implementation detail that can change in the future?If the discussed approaches are not recommended, how can we support namespace packages using import hooks and deliver a complete solution for PEP 660?
The text was updated successfully, but these errors were encountered: