diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst index 6942b9d62cb8f2..ae33236a6cf604 100644 --- a/Doc/deprecations/pending-removal-in-future.rst +++ b/Doc/deprecations/pending-removal-in-future.rst @@ -11,7 +11,6 @@ although there is currently no date scheduled for their removal. * :mod:`builtins`: - * ``~bool``, bitwise inversion on bool. * ``bool(NotImplemented)``. * Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)`` signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead, diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 01121feb2b2311..96b4d3b6a271cc 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -865,10 +865,10 @@ return a bool equivalent to the logical operations "and", "or", "xor". However, the logical operators ``and``, ``or`` and ``!=`` should be preferred over ``&``, ``|`` and ``^``. -.. deprecated:: 3.12 +.. versionchanged:: 3.14 - The use of the bitwise inversion operator ``~`` is deprecated and will - raise an error in Python 3.14. + The use of the bitwise inversion operator ``~`` is prohibited and raises + a :exc:`TypeError` now. :class:`bool` is a subclass of :class:`int` (see :ref:`typesnumeric`). In many numeric contexts, ``False`` and ``True`` behave like the integers 0 and 1, respectively. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index b975f6a4f8a931..56c810af5413ab 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -270,6 +270,12 @@ asyncio (Contributed by Kumar Aditya in :gh:`120804`.) +builtins +-------- + +* Bitwise inversion (``~``) is prohibited for :data:`True` and :data:`False` + which had previously raised a :exc:`DeprecationWarning` since Python 3.12. + collections.abc --------------- diff --git a/Lib/test/test_bool.py b/Lib/test/test_bool.py index 34ecb45f161dfe..fbb975d3d6ba56 100644 --- a/Lib/test/test_bool.py +++ b/Lib/test/test_bool.py @@ -58,22 +58,32 @@ def test_math(self): self.assertEqual(-True, -1) self.assertEqual(abs(True), 1) self.assertIsNot(abs(True), True) - with self.assertWarns(DeprecationWarning): - # We need to put the bool in a variable, because the constant - # ~False is evaluated at compile time due to constant folding; - # consequently the DeprecationWarning would be issued during - # module loading and not during test execution. - false = False - self.assertEqual(~false, -1) - with self.assertWarns(DeprecationWarning): - # also check that the warning is issued in case of constant - # folding at compile time - self.assertEqual(eval("~False"), -1) - with self.assertWarns(DeprecationWarning): - true = True - self.assertEqual(~true, -2) - with self.assertWarns(DeprecationWarning): - self.assertEqual(eval("~True"), -2) + + # Bitwise inversion is prohibited on bool type. + with self.assertRaises(TypeError): + ~True + with self.assertRaises(TypeError): + ~False + + true = True + false = False + with self.assertRaises(TypeError): + ~true + with self.assertRaises(TypeError): + ~false + with self.assertRaises(TypeError): + eval("~True") + with self.assertRaises(TypeError): + eval("~False") + with self.assertRaises(TypeError): + true.__invert__() + with self.assertRaises(TypeError): + false.__invert__() + + with self.assertRaisesRegex(TypeError, r"Did you mean 'not' instead of '~'\?"): + ~true + with self.assertRaisesRegex(TypeError, r"Did you mean 'not' instead of '~'\?"): + ~false self.assertEqual(False+2, 2) self.assertEqual(True+2, 3) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-13-21-40-20.gh-issue-122982.JSLp1k.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-13-21-40-20.gh-issue-122982.JSLp1k.rst new file mode 100644 index 00000000000000..7972bcdc5023a8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-08-13-21-40-20.gh-issue-122982.JSLp1k.rst @@ -0,0 +1 @@ +Bitwise inversion (``~``) is prohibited for :data:`True` and :data:`False`. diff --git a/Objects/boolobject.c b/Objects/boolobject.c index fb48dcbeca7850..77a39a56adc3e8 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -70,17 +70,11 @@ bool_vectorcall(PyObject *type, PyObject * const*args, static PyObject * bool_invert(PyObject *v) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Bitwise inversion '~' on bool is deprecated. This " - "returns the bitwise inversion of the underlying int " - "object and is usually not what you expect from negating " - "a bool. Use the 'not' operator for boolean negation or " - "~int(x) if you really want the bitwise inversion of the " - "underlying int.", - 1) < 0) { - return NULL; - } - return PyLong_Type.tp_as_number->nb_invert(v); + PyErr_SetString( + PyExc_TypeError, + "bad operand type for unary ~: 'bool'. Did you mean 'not' instead of '~'?" + ); + return NULL; } static PyObject *