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
bpo-32225: Implementation of PEP 562 #4731
Changes from all commits
119edbe
c2ec3c1
f657a7e
8aa052f
32d092f
68703f0
4fa4b1b
d1ada11
a9f7d4a
f93b168
c720cfd
fd2f02f
e4b53d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1512,6 +1512,51 @@ access (use of, assignment to, or deletion of ``x.name``) for class instances. | |
returned. :func:`dir` converts the returned sequence to a list and sorts it. | ||
|
||
|
||
Customizing module attribute access | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. index:: | ||
single: __getattr__ (module attribute) | ||
single: __dir__ (module attribute) | ||
single: __class__ (module attribute) | ||
|
||
Special names ``__getattr__`` and ``__dir__`` can be also used to customize | ||
access to module attributes. The ``__getattr__`` function at the module level | ||
should accept one argument which is the name of an attribute and return the | ||
computed value or raise an :exc:`AttributeError`. If an attribute is | ||
not found on a module object through the normal lookup, i.e. | ||
:meth:`object.__getattribute__`, then ``__getattr__`` is searched in | ||
the module ``__dict__`` before raising an :exc:`AttributeError`. If found, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be nice to make a reference to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure if it is possible. The sub-section "Modules" itself refers to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is an index entry for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe you can you use
Where the
and then where you want to link:
As you mentioned, this may require fixing other links for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this is applicable here. In any case we can experiment with this in a separate issue. I prefer to keep the current markup for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I also think it can be deferred to a separate issue. IIUC the only thing remaining here is to get an OK from @ncoghlan |
||
it is called with the attribute name and the result is returned. | ||
|
||
The ``__dir__`` function should accept no arguments, and return a list of | ||
strings that represents the names accessible on module. If present, this | ||
function overrides the standard :func:`dir` search on a module. | ||
|
||
For a more fine grained customization of the module behavior (setting | ||
attributes, properties, etc.), one can set the ``__class__`` attribute of | ||
a module object to a subclass of :class:`types.ModuleType`. For example:: | ||
|
||
import sys | ||
from types import ModuleType | ||
|
||
class VerboseModule(ModuleType): | ||
def __repr__(self): | ||
return f'Verbose {self.__name__}' | ||
|
||
def __setattr__(self, attr, value): | ||
print(f'Setting {attr}...') | ||
setattr(self, attr, value) | ||
|
||
sys.modules[__name__].__class__ = VerboseModule | ||
|
||
.. note:: | ||
Defining module ``__getattr__`` and setting module ``__class__`` only | ||
affect lookups made using the attribute access syntax -- directly accessing | ||
the module globals (whether by code within the module, or via a reference | ||
to the module's globals dictionary) is unaffected. | ||
|
||
|
||
.. _descriptors: | ||
|
||
Implementing Descriptors | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
x = 1 | ||
|
||
__getattr__ = "Surprise!" | ||
__dir__ = "Surprise again!" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
def __getattr__(): | ||
"Bad one" | ||
|
||
x = 1 | ||
|
||
def __dir__(bad_sig): | ||
return [] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
def __getattr__(name): | ||
if name != 'delgetattr': | ||
raise AttributeError | ||
del globals()['__getattr__'] | ||
raise AttributeError |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
x = 1 | ||
|
||
def __dir__(): | ||
return ['a', 'b', 'c'] | ||
|
||
def __getattr__(name): | ||
if name == "yolo": | ||
raise AttributeError("Deprecated, use whatever instead") | ||
return f"There is {name}" | ||
|
||
y = 2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
PEP 562: Add support for module ``__getattr__`` and ``__dir__``. Implemented by Ivan | ||
Levkivskyi. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the index entries: