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
The Python stdlib
sysmodule implements multiple API with simple attributes likesys.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:
If
sys.modulesis set to an invalid type,importstops working and produces an error which makes no sense.Another problem is that the internals of Python have a copy of
sysattributes and so don't respectsyschanges. Recently, I discovered thatPyImport_AddModule()uses a "copy" ofsys.modules(a reference to the dict). Overridingsys.moduleshas no effect: it still changes the originalsys.modulesdict. See #105998 (comment) for technical details.Supporting
__setattr__()would allow to update the internal reference tosys.modules(PyInterpreterState.imports.modules).Adding
__delattr__()would help prevent to delete criticalsysattributes which makes the code more complicated. For example, code usingsys.stderrhas to check if the attribute exists and if it's notNone. Currently, it's possible to remove anysysattribute, including functions:Notice the
sys.excepthook is missingerror mesage.In Python 3.7, support for
__getattr__()anddir()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.pathlist. For example, it was proposed to deprecate or disallow adding bytes strings tosys.path. For this,sys.pathshould use a different type (such as a list subclass): it's not directly related to this issue.Linked PRs