The sys module has a couple of global properties that I'm interested in: sys.stdout and sys.stderr.
I'm building a module of my own, that (among other things), replaces sys.stdout and sys.stderr with its own wrappers that intercept attempted output, modify it, and then forward it to the originals. My method for doing so is something like this:
_orig_stdout = sys.stdout
_orig_stderr = sys.stderr
sys.stdout = MyFakeStdoutClass()
sys.stderr = MyFaleStderrClass()
This works as expected - at any time after my module is imported, trying to do anything with sys.stdout or sys.stderr goes through my class instead.
Now, my module has a vested interest in making sure that this arrangement stays how it is now - it wants to keep control of sys.stdout and sys.stderr permanently. Other modules can reassign sys.stdout the same way that my module did, and my module doesn't want them to be able to do that. Instead, my module wants to intercept their attempt to do so.
For a regular class, doing this would be easy - I'd just have to overwrite the class's __setattr__() method:
_orig_setattr = OtherClass.__setattr__
def my_setattr(obj, name, value):
if name != "stdout":
_orig_setattr(obj, name, value)
OtherClass.__setattr__ = my_setattr
However, I've tried doing this for the sys module itself, and it doesn't work (even after I do sys.__setattr__ = my_setattr, I find that my_setattr never gets called).
Additionally, while other answers point out the possible solution of making my own wrapper class for the sys module and assigning it to sys.modules['sys'], this won't work - if sys was imported in another module before my module is imported by that module (which is likely), then my change won't stick.
Furthermore, setting sys.stdout = property(stdout_getter, stdout_setter) with some helper methods to return/modify my _orig_stdout variable didn't work either. Even later in the same file, I could just do sys.stdout = sys.__stdout__, and it was back to normal. I don't want this to be possible.
Is there a good way around this limitation?