Skip to content
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

Merged
merged 2 commits into from
Sep 12, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion colorama/ansitowin32.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def is_stream_closed(stream):

def is_a_tty(stream):
if 'PYCHARM_HOSTED' in os.environ:
return True
if stream is not None and (stream is sys.__stdout__ or stream is sys.__stderr__):
return True
return (hasattr(stream, 'isatty') and stream.isatty())


Expand All @@ -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)
Copy link
Collaborator

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?


class AnsiToWin32(object):
'''
Expand Down
6 changes: 3 additions & 3 deletions colorama/tests/initialise_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from ..ansitowin32 import StreamWrapper
from ..initialise import init
from .utils import osname, redirected_output, replace_by_none
from .utils import osname, redirected_output, replace_by

orig_stdout = sys.stdout
orig_stderr = sys.stderr
Expand Down Expand Up @@ -55,9 +55,9 @@ def testInitDoesntWrapOnNonWindows(self):
self.assertNotWrapped()

def testInitDoesntWrapIfNone(self):
with replace_by_none():
with replace_by(None):
init()
# We can't use assertNotWrapped here because replace_by_none
# We can't use assertNotWrapped here because replace_by(None)
# changes stdout/stderr already.
self.assertIsNone(sys.stdout)
self.assertIsNone(sys.stderr)
Expand Down
54 changes: 54 additions & 0 deletions colorama/tests/isatty_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import sys
from unittest import TestCase, main

from ..ansitowin32 import is_a_tty, AnsiToWin32
from .utils import pycharm, replace_by, replace_original_by, StreamTTY, StreamNonTTY


class IsattyTest(TestCase):

def test_TTY(self):
tty = StreamTTY()
self.assertTrue(is_a_tty(tty))
with pycharm():
self.assertTrue(is_a_tty(tty))

def test_nonTTY(self):
non_tty = StreamNonTTY()
self.assertFalse(is_a_tty(non_tty))
with pycharm():
self.assertFalse(is_a_tty(non_tty))

def test_withPycharm(self):
with pycharm():
self.assertTrue(is_a_tty(sys.stderr))
self.assertTrue(is_a_tty(sys.stdout))

def test_withPycharmTTYOverride(self):
tty = StreamTTY()
with pycharm(), replace_by(tty):
self.assertTrue(is_a_tty(tty))

def test_withPycharmNonTTYOverride(self):
non_tty = StreamNonTTY()
with pycharm(), replace_by(non_tty):
self.assertFalse(is_a_tty(non_tty))

def test_withPycharmNoneOverride(self):
with pycharm():
with replace_by(None), replace_original_by(None):
self.assertFalse(is_a_tty(None))
self.assertFalse(is_a_tty(StreamNonTTY()))
self.assertTrue(is_a_tty(StreamTTY()))

def test_withPycharmStreamWrapped(self):
with pycharm():
self.assertTrue(is_a_tty(AnsiToWin32(StreamTTY()).stream))
self.assertFalse(is_a_tty(AnsiToWin32(StreamNonTTY()).stream))
self.assertTrue(is_a_tty(AnsiToWin32(sys.stdout).stream))
self.assertTrue(is_a_tty(AnsiToWin32(sys.stderr).stream))


if __name__ == '__main__':
main()
33 changes: 30 additions & 3 deletions colorama/tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
from contextlib import contextmanager
from io import StringIO
import sys
import os

from mock import Mock

class StreamTTY(StringIO):
def isatty(self):
return True

class StreamNonTTY(StringIO):
def isatty(self):
return False

@contextmanager
def osname(name):
orig = os.name
Expand All @@ -21,11 +30,29 @@ def redirected_output():
sys.stdout = orig

@contextmanager
def replace_by_none():
def replace_by(stream):
orig_stdout = sys.stdout
orig_stderr = sys.stderr
sys.stdout = None
sys.stderr = None
sys.stdout = stream
sys.stderr = stream
yield
sys.stdout = orig_stdout
sys.stderr = orig_stderr

@contextmanager
def replace_original_by(stream):
orig_stdout = sys.__stdout__
orig_stderr = sys.__stderr__
sys.__stdout__ = stream
sys.__stderr__ = stream
yield
sys.__stdout__ = orig_stdout
sys.__stderr__ = orig_stderr

@contextmanager
def pycharm():
os.environ["PYCHARM_HOSTED"] = "1"
non_tty = StreamNonTTY()
with replace_by(non_tty), replace_original_by(non_tty):
yield
del os.environ["PYCHARM_HOSTED"]