Skip to content
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

The _check_module script's find does not work correctly with namespace packages #522

Open
johnfb opened this issue Feb 7, 2025 · 0 comments

Comments

@johnfb
Copy link

johnfb commented Feb 7, 2025

For personal tools I will often use a namespace package to put my packages into my own namespace.

For example, I might write a command line tool to help with containers, so I make something like johnfb.container, where johnfb is a namespace package. Then I register a console script with something like johnfb.container.__main__:main.

The issue basically comes down to the line here

    names = name.split(".")
    spec = find_spec(names[0])

This returns the spec for the namespace package johnfb which does not exist and spec.has_location is false.

But if I pass find_spec the full package path johnfb.container then I get a spec back where has_location is true and everything works as I would expect it to.

I am not sure why some of the things in that find function do what they do but if I apply the following diff everything works for me:

--- a/_check_module.py	2025-02-07 15:15:35.837493599 -0600
+++ b/_check_module.py	2025-02-07 15:21:26.801972338 -0600
@@ -42,18 +42,19 @@
 
 def find(name, return_package=False):
     names = name.split(".")
-    spec = find_spec(names[0])
+    package = ".".join(names[:-1])
+    spec = find_spec(package)
     if spec is None:
-        raise ArgcompleteMarkerNotFound('no module named "{}"'.format(names[0]))
+        raise ArgcompleteMarkerNotFound('no module named "{}"'.format(package))
     if not spec.has_location:
         raise ArgcompleteMarkerNotFound("cannot locate file")
     if spec.submodule_search_locations is None:
         if len(names) != 1:
-            raise ArgcompleteMarkerNotFound("{} is not a package".format(names[0]))
+            raise ArgcompleteMarkerNotFound("{} is not a package".format(package))
         return spec.origin
     if len(spec.submodule_search_locations) != 1:
         raise ArgcompleteMarkerNotFound("expecting one search location")
-    path = os.path.join(spec.submodule_search_locations[0], *names[1:])
+    path = os.path.join(spec.submodule_search_locations[0], names[-1])
     if os.path.isdir(path):
         filename = "__main__.py"
         if return_package:

My read of the original is that it makes the assumption name is formatted as package.file, and this change then makes the assumption package.subpackage1[.subpackageN].file There may be other things that this breaks because I don't know all the differences between different python versions and how they have changed the importlib metadata loading and spec finding. There may be a better way to solve this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant