Skip to content

gh-77391: Say what walk_packages' prefix does to the imports - #158138

Open
v0ropaev wants to merge 1 commit into
python:mainfrom
v0ropaev:gh-77391-walk-packages-prefix
Open

v0ropaev wants to merge 1 commit into
python:mainfrom
v0ropaev:gh-77391-walk-packages-prefix

Conversation

@v0ropaev

@v0ropaev v0ropaev commented Sep 24, 2026 •

Copy link
Copy Markdown

Closes #77391, the documentation half of it.

@ncoghlan split the issue in two back in 2018:

The documentation issue is the one you've reported: in order for the recursive descent to work in walk_packages given the current algorithm, then the combination of the given prefix, and the current global import configuration must allow that package to actually be imported. While there is a note about that limitation, it's currently thoroughly unclear.

The docs describe prefix as something prepended to the names on output, which reads as cosmetic. It is also the name each package gets imported under during the descent, and that has consequences a reader has no way to guess. Three of them, all on a tree where realpkg/sub/leaf.py exists and other/sub/wrongleaf.py is a decoy:

>>> [m.name for m in pkgutil.walk_packages(["…/realpkg"])]
['sub']

No prefix, so sub is imported by bare name, that fails, and leaf is silently missing — nothing in the result says a subtree was skipped.

>>> [m.name for m in pkgutil.walk_packages(["…/realpkg"], "realpkg.")]
['realpkg.sub', 'realpkg.sub.leaf']

With the right prefix the descent works.

>>> [m.name for m in pkgutil.walk_packages(["…/realpkg"], "other.")]
['other.sub', 'other.sub.wrongleaf']

The path pointed at realpkg, but the prefix made it import other.sub, so what came back is the content of a package that was never on the given path.

The wording now says that, and says the thing a caller actually needs: pass a package's __path__ together with its __name__ and a trailing dot. Same text in the docstring, since that is where most people read it.

Doc and docstring only, no behaviour change. The functional half @ncoghlan described is untouched.

The docs describe prefix as "a string to output on the front of every
module name on output". That is accurate for iter_modules(), but it
leaves out the part that catches people in walk_packages(): the same
string goes into the name each package is imported under while the walk
descends, so the descent only reaches a package when prefix + name
resolves to the very package that was found on path. When it resolves to
something else, that other package is walked instead. When importing it
raises ImportError, the submodules are absent and nothing in the results
says so.

Walking ctypes.__path__ with no prefix on the current main lists six
names and quietly loses the three modules under ctypes.macholib; with
ctypes.__name__ + '.' it lists all nine. Passing onerror does not make
up for it, which is easy to assume from the old wording: it reports
macholib, and the output is still the same six names.

Only the wording changes, in the rst and in the docstring that repeats
it. The implementation problem Nick Coghlan described on the same
report, that the descent goes through a name-based __import__ instead of
loading the package from the file it has already found, is left alone
here; pull request python#11956 is already open for it.
@read-the-docs-community

read-the-docs-community Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #34756842 | 📁 Comparing 4679de7 against main (a5b03fa)

  🔍 Preview build  

2 files changed
± library/pkgutil.html
± whatsnew/changelog.html

@v0ropaev

Copy link
Copy Markdown
Author

Closing this myself. @picnixz pointed out on #158152 that I have been opening too many at once and that old issues nobody has revived are the wrong ones to pick up unasked — this is one of those, so it should not be sitting in the queue. The branch stays on my fork if the issue ever comes back to life.

@v0ropaev v0ropaev closed this Sep 25, 2026
@v0ropaev v0ropaev reopened this Sep 25, 2026
@v0ropaev

v0ropaev commented Sep 25, 2026 •

Copy link
Copy Markdown
Author

Reopened. Closing this was my own overreaction to being told I had too many open, not something anyone asked for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pkgutil.walk_packages "prefix" option docs are misleading

1 participant