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?