Skip to content

gh-148672: Document namespace subpackages inside regular packages#150056

Open
Taeknology wants to merge 1 commit into
python:mainfrom
Taeknology:gh-148672-document-subpackage-namespaces
Open

gh-148672: Document namespace subpackages inside regular packages#150056
Taeknology wants to merge 1 commit into
python:mainfrom
Taeknology:gh-148672-document-subpackage-namespaces

Conversation

@Taeknology
Copy link
Copy Markdown

@Taeknology Taeknology commented May 19, 2026

This documents the long-standing behaviour where a subdirectory of a
regular package that does not contain an __init__.py file is imported
as a namespace subpackage of that regular package, per
PEP 420.

The reference docs (Doc/reference/import.rst) currently describe
"Regular packages" and "Namespace packages" as two disjoint categories,
and do not mention that a namespace package can also be nested inside a
regular package. The behaviour is intentional (PEP 420 Specification;
implemented in Lib/importlib/_bootstrap_external.py
FileFinder.find_spec), but is undocumented.

This PR adds:

  1. A short cross-reference paragraph at the end of the "Regular packages"
    section pointing to the namespace package definition.
  2. A paragraph in the "Namespace packages" section explicitly stating
    that namespace packages may also be nested inside a regular package.

Verified locally (Python 3.12.11)

I reproduced the documented behaviour against a CPython interpreter to
make sure the new wording matches what the import system actually does:

$ tree /tmp/test/
/tmp/test/
└── myreg/
    ├── __init__.py        # regular package
    └── empty_sub/         # no __init__.py
        └── deeper/        # no __init__.py

$ python3 -c "
import sys; sys.path.insert(0, '/tmp/test')
import myreg
import myreg.empty_sub
import myreg.empty_sub.deeper
print(repr(myreg))
print(repr(myreg.empty_sub))
print(repr(myreg.empty_sub.deeper))
"
<module 'myreg' from '/tmp/test/myreg/__init__.py'>
<module 'myreg.empty_sub' (namespace) from ['/tmp/test/myreg/empty_sub']>
<module 'myreg.empty_sub.deeper' (namespace) from ['/tmp/test/myreg/empty_sub/deeper']>

The interpreter's own repr labels myreg.empty_sub and
myreg.empty_sub.deeper as (namespace), confirming this is the
intended behaviour and not a bug, which is what the new paragraphs
document.

No code change. No Misc/NEWS.d entry (docs-only).

Fixes #148672

The import system already creates implicit namespace packages for any
subdirectory of a regular package that lacks an ``__init__.py`` file,
per :pep:`420`.  Document this behaviour in Doc/reference/import.rst
so readers do not have to infer it from the PEP and from importlib
internals.
@read-the-docs-community
Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #32751712 | 📁 Comparing 74e6528 against main (517d3d2)

  🔍 Preview build  

1 file changed
± reference/import.html

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

Labels

awaiting review docs Documentation in the Doc dir skip news

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Document the unexpected importing of sub-namespaces inside normal python packages/namespaces

1 participant