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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent file stream from being incorrectly wrapped on Pycharm #164
Conversation
|
colorama/ansitowin32.py
Outdated
@@ -18,7 +18,7 @@ def is_stream_closed(stream): | |||
|
|||
|
|||
def is_a_tty(stream): | |||
if 'PYCHARM_HOSTED' in os.environ: | |||
if 'PYCHARM_HOSTED' in os.environ and (stream is sys.__stdout__ or stream is sys.__stderr__): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to check against the __
versions of stdout
and stderr
instead of using sys.stdout
and sys.stderr
? If there was another redirection (so the values of the "regular" sys streams changed), we would still want to return "True" under PyCharm for these streams, no? Since init
uses sys.stdout
and sys.stderr
directly, it makes sense to check against these streams. Perhaps I'm missing something though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reasoning was the following: the stdout
and stderr
under Pycharm are inherently bugged. These two streams are unambiguously accessible through __stdout__
and __stderr__
. If the user happens to override sys.stdout
, then we do not have much information about the stream that will replace it (it could be a file
or a StringIO
), so we should not assume that the replacing stream is bugged too, instead we should check as usual using stream.isatty()
.
Basically, the edge case is an user replacing sys.stdout
with a non-tty stream on Pycharm. In such a case, colorama.is_a_tty(sys.stdout)
should return False
, but this would not be the case if the check is made using stream is sys.stdout
.
Does it make sense to you? I do not exclude having missed something too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I understand (a user custom sys.stdout
may not be the real "PyCharm terminal" and so may need to be treated as "not a tty"). The problem is that after "colorama.init", sys.stdout
will be replaced by colorama and then colorama.is_a_tty(sys.stdout)
will return False (in PyCharm) although it is a simple wrapper of the "original". Maybe we should check for both? i.e. something like
... and (stream in (sys.__stdout__, sys.__stderr__, sys.stdout, sys.stderr))
?
If I understand correctly, the problem is generally only when using the PyCharm interactive console, and shouldn't affect scripts running outside of the IDE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you are right, I did not even think of it, thanks for pointing this out...
But I do not see how checking for stream in ...
will prevent the edge case of user replacing sys.stderr
with a non-tty stream (on Pycharm). 馃槙
In my opinion, as we are wrapping a broken sys.__stderr__
stream, we should take the opportunity to fix it. Something like this:
class StreamWrapper(object):
...
def isatty(self):
return is_a_tty(self.__wrapped)
It seems to fix all the edge cases we discussed, what do you think?
Thanks for your answer! I am not much worried about My use case is actually a logging function which accept any stream object for the handler (and later call I am planning to do something like this: if colorama.is_a_tty(stream):
stream = AnsiToWin23(stream).stream But I think I will be facing an edge case on Pycharm. |
Hey @wiggin15! I just updated my PR and added a bunch of unit tests to check Quick summary, assuming a Pycharm environment with broken
|
This looks ok, I guess. If I understand correctly, this shouldn't have an effect outside of PyCharm IDE, right? |
colorama/ansitowin32.py
Outdated
@@ -41,6 +42,8 @@ def __getattr__(self, name): | |||
def write(self, text): | |||
self.__convertor.write(text) | |||
|
|||
def isatty(self): | |||
return is_a_tty(self.__wrapped) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting. Maybe we don't even need the functions is_a_tty
and is_stream_closed
above, and they should instead be methods of StreamWrapper
, so that calling these methods will return what colorama "thinks" instead of the original. i.e. put the code here instead, and call the methods instead of the functions later in the code. What do you think?
Absolutely, apart from Pycharm the behavior remains the same (a simple call to the
I think this would be much more elegant indeed! I do not see why this would be a problem, I implemented your suggestion. |
Thanks! |
Hi.
This is related to a comment I left some days ago: #163 (comment)
I think this is quite important to only wrap
stdout
andstderr
on Pycharm, rather than any stream. Think for example of a logging module which relies oncolorama
to wrap arbitrary handler's stream. 馃槈