-
Notifications
You must be signed in to change notification settings - Fork 50
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
Improve backend loading from backend-path
#165
Conversation
caa16c6
to
2219922
Compare
backend-path
backend-path
spec = _find_spec_in_path(module_name, pathitems) | ||
module = module_from_spec(spec) | ||
sys.modules[module_name] = module | ||
spec.loader.exec_module(module) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will execute the module with sys.meta_path
unmodified. Even if you fixed loading this particular module from the right place, modules it imports during execution will be found by the loaders in sys.meta_path
, which is even more dangerous than loading the specified backend module from the wrong place IMO.
# Parent packages need to be imported to ensure everything comes from pathitems.
Exactly, but children and packages with a different top-level name too!
IMO the correct way to handle this is to simply prepend your PathFinder
to sys.meta_path
while we perform the build, and just import as normal, instead of this custom import hack 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for the review, Filipe.
In f14e5df I tried to implement the suggested approach. Please let me know if I misunderstood your comment (I can always revert and try something different).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, thanks @abravalheri!
Hi @takluyver, I was wondering if you could review this PR (if you have the time) or share your thoughts about the issue. I don't know if there would be time for a |
Previously `_in_process` would only modify `sys.path`, use `importlib.import_module` and hope the backend is loaded from the right path. This would lead to misleading error messages in some cases when the environment isolation is not perfect. This change modifies the behavior by using `importlib.machinery.PathFinder.find_spec` to locate the backend module within a set of path entries.
… when error regards import problems.
This should address review comments and increase the robustness of the solution.
4224f9b
to
0177e3d
Compare
@pradyunsg, I rebased the PR on top of the latest changes in main. Please let me know if any other changes are necessary. |
Hello @pypa/pyproject-hooks-committers, I wonder if this direction for solving the issue is something that the project would be interested, or if it would be better for me to close the PR and assume that the issue would be handled with a different approach. |
I always find it tough to understand the various bits of custom import machinery, so I don't relish trying to understand either the problem or the solution here (and I'm too tired to tackle it right now, when I happen to have a few minutes to look at it). I see you've added tests, and @FFY00 was happy with it, so I'll give people a few more days to make any comments, and if there are none, I'll trust you and merge this. Feel free to ping me again in a week or so if I forget (which is all too possible 😉 ) |
src/pyproject_hooks/_impl.py
Outdated
self.traceback = traceback | ||
super().__init__(message or "Error while importing backend") | ||
|
||
|
||
class BackendInvalid(Exception): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this exception, since this is no longer being caught and used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for the review @pradyunsg.
I was considering that removing BackendInvalid
would cause backward compatibility problems (e.g. it seems to be in __init__.py
's __all__
, some folks might consider that public API, so it might break someone's script if they do a from pyproject_hooks import BackendInvalid
).
I am happy to remove the class if the project is OK with taking the (potential) backwards incompatibility. Alternative, also happy to change the docstring to "deprecated" or something like that. What is your take on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added 7bb74e2 in response to this review comment.
But I am also happy to completely remove the class or do something different.
Just let me know and I will implement the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So... I don't see anyone using this on GitHub so it seems reasonably safe to remove.
We can bump the major version since this is backwards-incompatible (and version numbers are cheap), and then we don't have to bother with having dead code in the codebase that no one relies on. The fix from the users' perspective is relatively straightforward here too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems to be in
__init__.py
's__all__
, some folks might consider that public API,
FWIW, I'd be surprised if anyone doesn't consider it public API. 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problems, in a318f8e, I removed the unused exception class.
In the case a deprecation cycle is preferred we can just revert this commit.
This definitely closes that, no? I'll let you edit the description, but my reading is that it definitely does change this behaviour. |
Perfect, I updated the description. Thank you very much for the confirmation @pradyunsg. |
backend-path
backend-path
I have updated the PR to take into consideration external feedback I received about Luckily, importlib machinery is smart enough to find nested modules based on the parent's path. |
Thanks @abravalheri! ^.^ |
Closes #164
Closes #45
My understanding is that these changes are worth implementing (to increase robustness) even if
pip
improves its environment isolation.Approach
Instead of changing
sys.path
and relying onimportlib.import_module
to do the right thing, this PR proposes to useimportlib.machinery.PathFinder.find_spec
to actively restrict the paths to be searched when looking for the backend.Other details
Since the description of
BackendUnavailable
1 seems more appropriate than the description forBackendInvalid
2 for the circumstances described in the #164, I modified (in a backwards compatible way) how the errors are reported. I think this makes sense with the rest of the alterations...Footnotes
docstring:
Will be raised if the backend cannot be imported in the hook process.
↩docstring:
Will be raised if the backend is invalid.
↩