-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
PEP 726: Support defining __setattr__() and __delattr__() in a module #106016
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
Comments
Currently, it's possible to implement this feature by overriding the module in # regular module code
attr = 123
def func():
print("called func()")
# override the module in sys.modules to implement __setattr__()
class FakeModule:
def __init__(self, ns):
vars(self).update(ns)
def __setattr__(self, name, value):
print("setting %s=%s" % (name, value))
object.__setattr__(self, name, value)
import sys
sys.modules[__name__] = FakeModule(globals()) Example:
But this approach doesn't work for C extensions (which is what I care about here) ;-) I found the code (that I updated for Python 3) in an old comp.lang.python discussion (2010) about overriding This feature was also requested recently: https://discuss.python.org/t/extend-pep-562-with-setattr-for-modules/25506 |
Feature or bug? ;) |
Feature request :-) |
Since, module |
I did a draft PEP, with Let me know if it does make sense to extend this effort. |
… __setattr__/__delattr__
* Move Python scripts related to test_module to this new directory: good_getattr.py and bad_getattrX.py scripts. * Move Lib/test/test_module.py to Lib/test/test_module/__init__.py.
* Move Python scripts related to test_module to this new directory: good_getattr.py and bad_getattrX.py scripts. * Move Lib/test/test_module.py to Lib/test/test_module/__init__.py.
* Move Python scripts related to test_module to this new directory: good_getattr.py and bad_getattrX.py scripts. * Move Lib/test/test_module.py to Lib/test/test_module/__init__.py. (cherry picked from commit adfc118) Co-authored-by: Victor Stinner <[email protected]>
* Move Python scripts related to test_module to this new directory: good_getattr.py and bad_getattrX.py scripts. * Move Lib/test/test_module.py to Lib/test/test_module/__init__.py. (cherry picked from commit adfc118)
… __setattr__/__delattr__
…08304) gh-106016: Add Lib/test/test_module/ directory (GH-108293) * Move Python scripts related to test_module to this new directory: good_getattr.py and bad_getattrX.py scripts. * Move Lib/test/test_module.py to Lib/test/test_module/__init__.py. (cherry picked from commit adfc118) Co-authored-by: Victor Stinner <[email protected]>
Hi. I see there is a PEP for this There is a use case I've encountered recently which would require a proper efficient support for setattr and that is the warnings module. Fixing that would require changing how catch_warnings() and filters work, so that no monkeypatching happens. However, that is very non-backwards compatible if 3rd parties are trying to do the same. A way to fix that would be to detect attributes being set in the module and issue an deprecation warning. Later fail with an error. And that requires a module.setattr. However, adding a class for such an important module could perhaps represent other performance or compatibility problems. |
@joaoe, I think this scenario at least partially mentioned in the discussion thread: https://discuss.python.org/t/32640/19. And also in the PEP (the last paragraph of the "Discussion" section), let me know if you feel this should be rephrased somehow. I'm going to submit a SC issue to ask for final decision. Practical benefits for package or module maintainers are very important (see https://discuss.python.org/t/32640/17) to the fate of PEP. So, I'm suggesting to share your thoughts in the discussion thread. |
The decision is now in the hands of the Steering Council: python/steering-council#216 For now, I prefer to close this issue. Another issue can be opened once the PEP will be approved. |
The Python stdlib
sys
module 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.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 respectsys
changes. Recently, I discovered thatPyImport_AddModule()
uses a "copy" ofsys.modules
(a reference to the dict). Overridingsys.modules
has no effect: it still changes the originalsys.modules
dict. 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 criticalsys
attributes which makes the code more complicated. For example, code usingsys.stderr
has to check if the attribute exists and if it's notNone
. Currently, it's possible to remove anysys
attribute, including functions:Notice the
sys.excepthook is missing
error 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.path
list. For example, it was proposed to deprecate or disallow adding bytes strings tosys.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 text was updated successfully, but these errors were encountered: