diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 8b05d2df10b3436..91dbd163423aa61 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1023,6 +1023,20 @@ def test_env_queries(self): self.assertIsInstance(c, bytes) self.assertEqual(len(c), 1) + def test_termattrs_is_not_negative(self): + # A_ITALIC is the topmost bit of a 32-bit attribute mask, so termattrs() + # only tells a signed result from an unsigned one on a terminal that + # advertises it. 3.15 lacks the newterm()/pty harness used on main, so + # exercise the current screen: skip when the top bit is not advertised. + attrs = curses.termattrs() + italic = getattr(curses, 'A_ITALIC', 0) + if not italic or not attrs & italic: + self.skipTest('the terminal advertises no attribute in the top bit') + self.assertGreaterEqual(attrs, 0) + # termattrs() exists to be passed back to the attribute functions, + # which reject a negative mask. + self.stdscr.attrset(attrs) + def test_output_options(self): stdscr = self.stdscr diff --git a/Misc/NEWS.d/next/Library/2026-07-29-11-58-17.gh-issue-154874.NAPdBp.rst b/Misc/NEWS.d/next/Library/2026-07-29-11-58-17.gh-issue-154874.NAPdBp.rst new file mode 100644 index 000000000000000..61ba4f7374b3184 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-29-11-58-17.gh-issue-154874.NAPdBp.rst @@ -0,0 +1,3 @@ +Fix :func:`curses.termattrs` returning a negative value on a terminal that +supports :const:`curses.A_ITALIC`, which left its result unusable as an +attribute mask. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 82c8e642a51154f..bed06737dfad17a 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4959,7 +4959,11 @@ Return a logical OR of all video attributes supported by the terminal. static PyObject * _curses_termattrs_impl(PyObject *module) /*[clinic end generated code: output=b06f437fce1b6fc4 input=0559882a04f84d1d]*/ -NoArgReturnIntFunctionBody(termattrs) +{ + PyCursesStatefulInitialised(module); + + return PyLong_FromUnsignedLong((unsigned long)(chtype)termattrs()); +} /*[clinic input] @permit_long_summary