Skip to content

Add PEP 843: Export Statement for DRY Re-exports - #5078

Open
NeilGirdhar wants to merge 1 commit into
python:mainfrom
NeilGirdhar:main
Open

Add PEP 843: Export Statement for DRY Re-exports#5078
NeilGirdhar wants to merge 1 commit into
python:mainfrom
NeilGirdhar:main

Conversation

@NeilGirdhar

Copy link
Copy Markdown
Contributor

Summary

  • Adds a draft PEP proposing from <module> export <name> (plus wildcard export * and lazy export variants) as a single statement that both imports a re-exported name and appends it to __all__, eliminating the duplicate-list / import x as x bookkeeping burden.
  • Grew out of the PEP 842 discussion (https://discuss.python.org/t/108353) and is deliberately narrower than it: no export def/export class forms and no runtime enforcement (ExportWarning or otherwise). See the PEP's "Relationship to PEP 842" and "Non-goals" sections for the reasoning.
  • Grounded in real re-export patterns from NumPy, pandas, polars, Typer, FastAPI, and Plotly rather than a hypothetical example.

Test plan

  • ./build.py renders the PEP without errors

Discussion thread

Points to the existing 842 discussion thread, but please let me know if I should starta new discussion!

@read-the-docs-community

read-the-docs-community Bot commented Aug 5, 2026

Copy link
Copy Markdown

Documentation build overview

📚 pep-previews | 🛠️ Build #33936046 | 📁 Comparing 14dda0d against latest (0475dc3)

  🔍 Preview build  

4 files changed
+ pep-0843/index.html
± index.html
± numerical/index.html
± pep-0000/index.html

Comment thread peps/pep-0843.rst Outdated
* Restrict runtime attribute access to non-exported names, or change
``__getattr__`` semantics. See `Why no runtime enforcement`_.
* Mark a freshly written ``def``, ``class``, or assignment as exported at
its definition site, the way :pep:`829`'s ``atpublic`` package does with

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP 829 and atpublic are really orthogonal. The latter is a package that has decades long use in the real world. The connection is that with the next version (likely atpublic 8.0.0 with an alpha already released), you'll be able to pip install atpublic[install] to get the public() and private() decorators automatically installed into builtins at interpreter startup time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the correction, I'll remove mention of PEP 829!

Comment thread peps/pep-0843.rst
Comment thread peps/pep-0843.rst Outdated
PEP: 843
Title: Export Statement for DRY Re-exports
Author: Neil Girdhar <mistersheik@gmail.com>
Discussions-To: https://discuss.python.org/t/108353

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the 842 thread is fine for the post-history, but you're going to want your own thread for this PEP. Mark this as "Pending" for now; you'll create the thread after merging.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes perfect sense, thank you!

Comment thread peps/pep-0843.rst Outdated
Comment on lines +52 to +53
``__all__`` and triggers an ``ExportWarning`` on access to anything left
out.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably clarify that ExportWarning is specific to 842.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree: the paragraph structure was confusing. I completely separated the commonalities from the PEP 842-specific points for clarity.

Comment thread peps/pep-0843.rst Outdated
Comment on lines +58 to +59
wildcard equivalent to `Wildcard form`_ and no lazy equivalent to `Lazy
exports`_. This PEP takes only that one slice, deliberately leaving out

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP 842 allows lazy imports, as it is in the grammar (though I haven't tested the implementation for it). I clarified that in my draft.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying; I've corrected my exposition.

Comment thread .github/CODEOWNERS Outdated
peps/pep-0838.rst @AlexWaygood
peps/pep-0840.rst @jeremyhylton @gvanrossum
peps/pep-0842.rst @ZeroIntensity
peps/pep-0843.rst @NeilGirdhar

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our (GitHub's?) rule is that you need to be a member of the python organization on GitHub to be listed as a code owner. The core dev sponsor is listed here instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, of course! Removed, thanks!

Comment thread peps/pep-0843.rst
@@ -0,0 +1,623 @@
PEP: 843

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, you typically need a core dev sponsor before assigning a number. I'm open to sponsoring, but I want to see what happens with the new 842 revision first.

@NeilGirdhar NeilGirdhar Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!! No rush on my end. Happy to wait and see how the new PEP 842 revision goes before asking anyone to commit. Thanks for taking the time to look over my PEP so carefully.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can keep this open as a courtesy for a bit, but PEPs from non-core devs do need a sponsor.

Comment thread peps/pep-0843.rst
@@ -0,0 +1,623 @@
PEP: 843

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can keep this open as a courtesy for a bit, but PEPs from non-core devs do need a sponsor.

Comment thread peps/pep-0843.rst Outdated
in sync by hand every time the public layout changes.

The second is the reflexive-alias idiom, ``from x import y as y``. Type
checkers (like mypy even in strict mode) treat it as a signal that the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why "even"? It's a documented part of the type system.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to emphasize the universality of the rule, but it didn't come across.

Comment thread peps/pep-0843.rst Outdated
==========

This section is grounded in existing, widely-used libraries rather than
a hypothetical ``spam`` module.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange wording

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this was a weak start. Grounded in affirmative statements instead.

Comment thread peps/pep-0843.rst Outdated
file: the list of imports (an implementation detail of how the
flattening is wired up) and the declaration of the public API (a promise
to users). The two live in separate statements at different places in
the file, and a reviewer must check them against each other by eye.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or rely on a linter that warns when they're out of sync.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I softened the wording. But often linters do the wrong thing and wipe out the import rather than adding to __all__, so linters aren't a perfect fix.

Comment thread peps/pep-0843.rst Outdated
``atpublic`` works around this with a function-call form,
``public(some_imported_name)``, but that reintroduces the double-write
this PEP removes: the name is written once in the import and again as an
argument to ``public()``. A statement-level ``export`` keyword avoids

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also doesn't work well with aliases

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!!

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

Successfully merging this pull request may close these issues.

4 participants