[3.8] [3.9] bpo-42789: Don't skip curses tests on non-tty. (GH-24009)… · python/cpython@645174a

@@ -47,37 +47,57 @@ class TestCurses(unittest.TestCase):

47474848

@classmethod

4949

def setUpClass(cls):

50-

if not sys.__stdout__.isatty():

51-

# Temporary skip tests on non-tty

52-

raise unittest.SkipTest('sys.__stdout__ is not a tty')

53-

cls.tmp = tempfile.TemporaryFile()

54-

fd = cls.tmp.fileno()

55-

else:

56-

cls.tmp = None

57-

fd = sys.__stdout__.fileno()

5850

# testing setupterm() inside initscr/endwin

5951

# causes terminal breakage

60-

curses.setupterm(fd=fd)

61-62-

@classmethod

63-

def tearDownClass(cls):

64-

if cls.tmp:

65-

cls.tmp.close()

66-

del cls.tmp

52+

stdout_fd = sys.__stdout__.fileno()

53+

curses.setupterm(fd=stdout_fd)

67546855

def setUp(self):

56+

self.isatty = True

57+

self.output = sys.__stdout__

58+

stdout_fd = sys.__stdout__.fileno()

59+

if not sys.__stdout__.isatty():

60+

# initstr() unconditionally uses C stdout.

61+

# If it is redirected to file or pipe, try to attach it

62+

# to terminal.

63+

# First, save a copy of the file descriptor of stdout, so it

64+

# can be restored after finishing the test.

65+

dup_fd = os.dup(stdout_fd)

66+

self.addCleanup(os.close, dup_fd)

67+

self.addCleanup(os.dup2, dup_fd, stdout_fd)

68+69+

if sys.__stderr__.isatty():

70+

# If stderr is connected to terminal, use it.

71+

tmp = sys.__stderr__

72+

self.output = sys.__stderr__

73+

else:

74+

try:

75+

# Try to open the terminal device.

76+

tmp = open('/dev/tty', 'wb', buffering=0)

77+

except OSError:

78+

# As a fallback, use regular file to write control codes.

79+

# Some functions (like savetty) will not work, but at

80+

# least the garbage control sequences will not be mixed

81+

# with the testing report.

82+

tmp = tempfile.TemporaryFile(mode='wb', buffering=0)

83+

self.isatty = False

84+

self.addCleanup(tmp.close)

85+

self.output = None

86+

os.dup2(tmp.fileno(), stdout_fd)

87+6988

self.save_signals = SaveSignals()

7089

self.save_signals.save()

71-

if verbose:

90+

self.addCleanup(self.save_signals.restore)

91+

if verbose and self.output is not None:

7292

# just to make the test output a little more readable

73-

print()

93+

sys.stderr.flush()

94+

sys.stdout.flush()

95+

print(file=self.output, flush=True)

7496

self.stdscr = curses.initscr()

75-

curses.savetty()

76-77-

def tearDown(self):

78-

curses.resetty()

79-

curses.endwin()

80-

self.save_signals.restore()

97+

if self.isatty:

98+

curses.savetty()

99+

self.addCleanup(curses.endwin)

100+

self.addCleanup(curses.resetty)

8110182102

def test_window_funcs(self):

83103

"Test the methods of windows"

@@ -95,7 +115,7 @@ def test_window_funcs(self):

95115

for meth in [stdscr.clear, stdscr.clrtobot,

96116

stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,

97117

stdscr.deleteln, stdscr.erase, stdscr.getbegyx,

98-

stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,

118+

stdscr.getbkgd, stdscr.getmaxyx,

99119

stdscr.getparyx, stdscr.getyx, stdscr.inch,

100120

stdscr.insertln, stdscr.instr, stdscr.is_wintouched,

101121

win.noutrefresh, stdscr.redrawwin, stdscr.refresh,

@@ -206,6 +226,11 @@ def test_window_funcs(self):

206226

if hasattr(stdscr, 'enclose'):

207227

stdscr.enclose(10, 10)

208228229+

with tempfile.TemporaryFile() as f:

230+

self.stdscr.putwin(f)

231+

f.seek(0)

232+

curses.getwin(f)

233+209234

self.assertRaises(ValueError, stdscr.getstr, -400)

210235

self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)

211236

self.assertRaises(ValueError, stdscr.instr, -2)

@@ -224,16 +249,19 @@ def test_embedded_null_chars(self):

224249

def test_module_funcs(self):

225250

"Test module-level functions"

226251

for func in [curses.baudrate, curses.beep, curses.can_change_color,

227-

curses.cbreak, curses.def_prog_mode, curses.doupdate,

228-

curses.flash, curses.flushinp,

252+

curses.doupdate, curses.flash, curses.flushinp,

229253

curses.has_colors, curses.has_ic, curses.has_il,

230254

curses.isendwin, curses.killchar, curses.longname,

231-

curses.nocbreak, curses.noecho, curses.nonl,

232-

curses.noqiflush, curses.noraw,

233-

curses.reset_prog_mode, curses.termattrs,

234-

curses.termname, curses.erasechar]:

255+

curses.noecho, curses.nonl, curses.noqiflush,

256+

curses.termattrs, curses.termname, curses.erasechar]:

235257

with self.subTest(func=func.__qualname__):

236258

func()

259+

if self.isatty:

260+

for func in [curses.cbreak, curses.def_prog_mode,

261+

curses.nocbreak, curses.noraw,

262+

curses.reset_prog_mode]:

263+

with self.subTest(func=func.__qualname__):

264+

func()

237265

if hasattr(curses, 'filter'):

238266

curses.filter()

239267

if hasattr(curses, 'getsyx'):

@@ -245,13 +273,9 @@ def test_module_funcs(self):

245273

curses.delay_output(1)

246274

curses.echo() ; curses.echo(1)

247275248-

with tempfile.TemporaryFile() as f:

249-

self.stdscr.putwin(f)

250-

f.seek(0)

251-

curses.getwin(f)

252-253276

curses.halfdelay(1)

254-

curses.intrflush(1)

277+

if self.isatty:

278+

curses.intrflush(1)

255279

curses.meta(1)

256280

curses.napms(100)

257281

curses.newpad(50,50)

@@ -260,7 +284,8 @@ def test_module_funcs(self):

260284

curses.nl() ; curses.nl(1)

261285

curses.putp(b'abc')

262286

curses.qiflush()

263-

curses.raw() ; curses.raw(1)

287+

if self.isatty:

288+

curses.raw() ; curses.raw(1)

264289

if hasattr(curses, 'setsyx'):

265290

curses.setsyx(5,5)

266291

curses.tigetflag('hc')

@@ -282,7 +307,7 @@ def test_colors_funcs(self):

282307

curses.init_pair(2, 1,1)

283308

curses.color_content(1)

284309

curses.color_pair(2)

285-

curses.pair_content(curses.COLOR_PAIRS - 1)

310+

curses.pair_content(min(curses.COLOR_PAIRS - 1, 0x7fff))

286311

curses.pair_number(0)

287312288313

if hasattr(curses, 'use_default_colors'):

@@ -354,7 +379,6 @@ def test_resize_term(self):

354379355380

@requires_curses_func('resizeterm')

356381

def test_resizeterm(self):

357-

stdscr = self.stdscr

358382

lines, cols = curses.LINES, curses.COLS

359383

new_lines = lines - 1

360384

new_cols = cols + 1