Skip to content

Commit d751a47

Browse files
committed
Fix build errors.
1 parent 59fd3d4 commit d751a47

1 file changed

Lines changed: 30 additions & 24 deletions

File tree

peps/pep-0842.rst

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Abstract
1414
========
1515

1616
This PEP proposes an ``__export__`` variable that modules can define to
17-
express intent behind visibility to variables from outside the module.
17+
express intent about the visibility of variables from outside the module.
1818

1919
For example:
2020

@@ -52,8 +52,8 @@ Motivation
5252
==========
5353

5454

55-
Module names need privacy
56-
-------------------------
55+
Module-level names need privacy
56+
-------------------------------
5757

5858
A developer is writing a Python module. The module is intended to have one
5959
"public" class -- a class that is intended for users of the module -- called
@@ -105,7 +105,7 @@ convention; even if this PEP is accepted, it's expected that "underscored"
105105
names (names prefixed with a leading ``_``) will remain a staple of Python
106106
for years to come. The purpose of this PEP is not to eliminate the need for
107107
``_`` in module-level names, but instead to clear up corner cases where a
108-
private name is ambigious or tempting. In other words, this PEP is intended
108+
private name is ambiguous or tempting. In other words, this PEP is intended
109109
to improve expressiveness and clarity with private APIs, *not* to add brand
110110
new functionality.
111111

@@ -145,6 +145,8 @@ The solution to this is to also prefix every imported name with ``_``:
145145
import tabnanny as _tabnanny
146146
147147
148+
But, again, this sprinkles the code with even more underscored names.
149+
148150

149151
.. _pep-842-prefixed-public:
150152

@@ -167,15 +169,15 @@ compatibility policy, but contain a leading underscore. For example:
167169
This sends the wrong message to consumers of the API. When seeing things like
168170
this in a codebase, it makes it seem like the code is opting out of backwards
169171
compatibility, or that an underscored name does not mean "private" in the
170-
module. In both cases, consumers are inclined to reach for more private names,
171-
making this problem worse.
172+
module. In both cases, consumers are inclined to reach for more private names
173+
(because there's no apparent consequence for doing so), making this problem worse.
172174

173175

174176
We want to be nice to users, not shrug them away
175177
------------------------------------------------
176178

177179
When a user decides to use a private API, accidentally or not, they will
178-
inevitably be broken by the library author(s). In many cases, this results
180+
inevitably be broken by the library author. In many cases, this results
179181
in a bug report asking for the API to be fixed or restored to prevent
180182
downstream breakage. In this case, the library maintainer has to make a decision:
181183

@@ -204,31 +206,32 @@ is named and placed well, then a user often won't need to reach for the
204206
documentation. Python is no exception to this.
205207

206208
When prototyping, it's typical for someone to use :func:`dir` or :func:`help`
207-
in Python's interactive :term:`REPL` to look for attributes or methods that
208-
are useful to them. In this case, if something is intuitive enough for the
209-
user, they will simply reach for it without checking the documentation first.
210-
In a language as dynamic as Python, the way people consume APIs is also dynamic.
209+
in Python's interactive :term:`REPL` to look for attributes that are useful to
210+
them. In this case, if something is intuitive enough for the user, they will
211+
simply reach for it without checking the documentation first. In a language
212+
as dynamic as Python, the way people consume APIs is also dynamic.
211213

212214

213215
``__all__`` is only a convention
214216
--------------------------------
215217

216218
The fundamental issue here is that Python has no way to express which names
217-
in a module are "private" or "public" -- or, in other words, which names are
218-
designed to be stable APIs for users. Prefixing is an option, but given the
219+
in a module are "private" or "public". Prefixing is an option, but given the
219220
reasons above, it's not always a bulletproof (or nice) solution for library
220221
authors.
221222

222-
Currently, the convention for expressing which names are public is done through
223-
a module's :attr:`__all__` variable. This has two major downsides:
223+
Currently, the other convention for expressing which names are public is
224+
done through a module's ``__all__`` variable. This has two major downsides:
224225

225226
1. ``__all__`` often gets out of sync, because as developers add, change, or
226227
remove names from their module, there is often nothing pushing them towards
227228
changing ``__all__``, because again, using it to list public names is only
228-
a *convention* and not enforced by anything.
229+
a convention and not enforced by anything.
229230
2. ``__all__`` is not always exhaustive. See the :ref:`rejected ideas
230231
<pep-842-all-for-exports>` for examples on where the items in ``__all__``
231-
might only be a subset of the "public" names in a module.
232+
might only be a subset of the "public" names in a module. In short, it can
233+
be difficult to control namespace pollution and declare all public names in
234+
``__all__`` simultaneously.
232235

233236
This PEP intends to solve both of these problems with a new ``__export__`` variable.
234237

@@ -294,7 +297,7 @@ Module attribute access
294297
When ``__export__`` is present in a module's globals, all access to attributes
295298
present on the module object will also check if the attribute name is present
296299
in ``__export__`` (via ``__contains__`` or through iteration, as specified previously).
297-
If the attribute name is not present in ``__export__``, then an :exc:`RuntimeWarning`
300+
If the attribute name is not present in ``__export__``, then a :exc:`RuntimeWarning`
298301
is emitted. For example:
299302

300303
.. code-block:: python
@@ -311,7 +314,7 @@ is emitted. For example:
311314
>>> spam.a
312315
42
313316
>>> spam.b
314-
<python-input-4>:1: RuntimeWarning: 'b' is not exported by 'spam'
317+
<python-input-2>:1: RuntimeWarning: 'b' is not exported by 'spam'
315318
24
316319
317320
@@ -492,11 +495,13 @@ following code:
492495

493496
.. code-block:: python
494497
495-
__all__ = __export__
498+
if "__all__" not in globals():
499+
__all__ = __export__
496500
497501
def _is_dunder_name(name):
498502
return (len(name) > 4) and name.startswith("__") and name.endswith("__")
499503
504+
# Attributes not in the __dict__ fall back to the normal lookup
500505
def __getattribute__(name):
501506
try:
502507
value = globals()[name]
@@ -584,7 +589,7 @@ A reference implementation of this PEP can be found
584589
`here <https://github.com/python/cpython/compare/main...ZeroIntensity:cpython:experiments/module-exports>`__.
585590

586591
Performance
587-
***********
592+
-----------
588593

589594
The reference implementation does not currently implement any optimizations
590595
to reduce the overhead of the ``__export__`` lookup or iteration, meaning
@@ -682,10 +687,11 @@ behind this PEP.
682687
Change History
683688
==============
684689

685-
- 01-Aug-2026:
686-
* Accessing an unexported attribute now emits a :exc:`RuntimeWarning` instead
690+
* 01-Aug-2026
691+
692+
- Accessing an unexported attribute now emits a :exc:`RuntimeWarning` instead
687693
of raising an :exc:`ImportError`.
688-
* Significantly overhauled the motivation section.
694+
- Significantly overhauled the motivation section.
689695

690696

691697
Copyright

0 commit comments

Comments
 (0)