Description
The Python stdlib sys
module implements multiple API with simple attributes like sys.path
, sys.modules
, etc. Converting these APIs to getter and setter functions would be an annoying and expensive migration, a lot of code expect these attributes and access them directly.
It's not possible to execute code before or after a module attribute is set to validate inputs or to update internal states.
Example:
$ python3.12
>>> import sys
>>> sys.modules = 123
>>> import asyncio
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<frozen importlib._bootstrap>", line 1260, in _find_and_load
AttributeError: 'int' object has no attribute 'get'
If sys.modules
is set to an invalid type, import
stops working and produces an error which makes no sense.
Another problem is that the internals of Python have a copy of sys
attributes and so don't respect sys
changes. Recently, I discovered that PyImport_AddModule()
uses a "copy" of sys.modules
(a reference to the dict). Overriding sys.modules
has no effect: it still changes the original sys.modules
dict. See #105998 (comment) for technical details.
Supporting __setattr__()
would allow to update the internal reference to sys.modules
(PyInterpreterState.imports.modules
).
Adding __delattr__()
would help prevent to delete critical sys
attributes which makes the code more complicated. For example, code using sys.stderr
has to check if the attribute exists and if it's not None
. Currently, it's possible to remove any sys
attribute, including functions:
$ python3.12
>>> import sys
>>> del sys.excepthook
>>> 1+
sys.excepthook is missing
File "<stdin>", line 1
1+
^
SyntaxError: invalid syntax
Notice the sys.excepthook is missing
error mesage.
In Python 3.7, support for __getattr__()
and dir()
was added to modules by PEP 562 – Module __getattr__ and __dir__.
This change alone doesn't allow to validate changes of mutable objects like sys.path
list. For example, it was proposed to deprecate or disallow adding bytes strings to sys.path
. For this, sys.path
should use a different type (such as a list subclass): it's not directly related to this issue.
Linked PRs
- gh-106016: Support customizing of module attributes access with __setattr__/__delattr__ (PEP 726) #108261
- gh-106016: Add Lib/test/test_module/ directory #108293
- [3.11] gh-106016: Add Lib/test/test_module/ directory (GH-108293) #108304
- [3.12] gh-106016: Add Lib/test/test_module/ directory (#108293) #108306