From 5580f31c56e6f90909bdceddda077504cc2d18b0 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Sat, 10 Aug 2024 21:16:34 +0200 Subject: [PATCH] gh-115808: Add ``is_none`` and ``is_not_none`` to ``operator`` (#115814) Co-authored-by: Kirill Podoprigora --- Doc/library/operator.rst | 18 +++++++++++ Doc/whatsnew/3.14.rst | 9 ++++++ Lib/operator.py | 12 ++++++-- Lib/test/test_operator.py | 20 +++++++++++++ ...-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst | 1 + Modules/_operator.c | 30 +++++++++++++++++++ Modules/clinic/_operator.c.h | 20 ++++++++++++- 7 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index a9a6026af40..e8e71068dd9 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -80,6 +80,20 @@ truth tests, identity tests, and boolean operations: Return ``a is not b``. Tests object identity. +.. function:: is_none(a) + + Return ``a is None``. Tests object identity. + + .. versionadded:: 3.14 + + +.. function:: is_not_none(a) + + Return ``a is not None``. Tests object identity. + + .. versionadded:: 3.14 + + The mathematical and bitwise operations are the most numerous: @@ -405,6 +419,10 @@ Python syntax and the functions in the :mod:`operator` module. +-----------------------+-------------------------+---------------------------------------+ | Identity | ``a is not b`` | ``is_not(a, b)`` | +-----------------------+-------------------------+---------------------------------------+ +| Identity | ``a is None`` | ``is_none(a)`` | ++-----------------------+-------------------------+---------------------------------------+ +| Identity | ``a is not None`` | ``is_not_none(a)`` | ++-----------------------+-------------------------+---------------------------------------+ | Indexed Assignment | ``obj[k] = v`` | ``setitem(obj, k, v)`` | +-----------------------+-------------------------+---------------------------------------+ | Indexed Deletion | ``del obj[k]`` | ``delitem(obj, k)`` | diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index b975f6a4f8a..a7c817c47d6 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -124,6 +124,15 @@ Add notes for JSON serialization errors that allow to identify the source of the error. (Contributed by Serhiy Storchaka in :gh:`122163`.) +operator +-------- + +* Two new functions ``operator.is_none`` and ``operator.is_not_none`` + have been added, such that ``operator.is_none(obj)`` is equivalent + to ``obj is None`` and ``operator.is_not_none(obj)`` is equivalent + to ``obj is not None``. + (Contributed by Raymond Hettinger and Nico Mexis in :gh:`115808`.) + os -- diff --git a/Lib/operator.py b/Lib/operator.py index 6d2a762bc95..1b765522f85 100644 --- a/Lib/operator.py +++ b/Lib/operator.py @@ -14,8 +14,8 @@ __all__ = ['abs', 'add', 'and_', 'attrgetter', 'call', 'concat', 'contains', 'co 'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand', 'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul', 'index', 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift', - 'is_', 'is_not', 'isub', 'itemgetter', 'itruediv', 'ixor', 'le', - 'length_hint', 'lshift', 'lt', 'matmul', 'methodcaller', 'mod', + 'is_', 'is_none', 'is_not', 'is_not_none', 'isub', 'itemgetter', 'itruediv', + 'ixor', 'le', 'length_hint', 'lshift', 'lt', 'matmul', 'methodcaller', 'mod', 'mul', 'ne', 'neg', 'not_', 'or_', 'pos', 'pow', 'rshift', 'setitem', 'sub', 'truediv', 'truth', 'xor'] @@ -66,6 +66,14 @@ def is_not(a, b): "Same as a is not b." return a is not b +def is_none(a): + "Same as a is None." + return a is None + +def is_not_none(a): + "Same as a is not None." + return a is not None + # Mathematical/Bitwise Operations *********************************************# def abs(a): diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py index f8eac8dc002..812d46482e2 100644 --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -347,6 +347,26 @@ class OperatorTestCase: self.assertFalse(operator.is_not(a, b)) self.assertTrue(operator.is_not(a,c)) + def test_is_none(self): + operator = self.module + a = 'xyzpdq' + b = '' + c = None + self.assertRaises(TypeError, operator.is_none) + self.assertFalse(operator.is_none(a)) + self.assertFalse(operator.is_none(b)) + self.assertTrue(operator.is_none(c)) + + def test_is_not_none(self): + operator = self.module + a = 'xyzpdq' + b = '' + c = None + self.assertRaises(TypeError, operator.is_not_none) + self.assertTrue(operator.is_not_none(a)) + self.assertTrue(operator.is_not_none(b)) + self.assertFalse(operator.is_not_none(c)) + def test_attrgetter(self): operator = self.module class A: diff --git a/Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst b/Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst new file mode 100644 index 00000000000..0fe6a336bdf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst @@ -0,0 +1 @@ +Add :func:`operator.is_none` and :func:`operator.is_not_none` functions. diff --git a/Modules/_operator.c b/Modules/_operator.c index 793a2d0dfc6..7e0d1f3df87 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -728,6 +728,34 @@ _operator_is_not_impl(PyObject *module, PyObject *a, PyObject *b) return Py_NewRef(result); } +/*[clinic input] +_operator.is_none = _operator.neg + +Same as a is None. +[clinic start generated code]*/ + +static PyObject * +_operator_is_none(PyObject *module, PyObject *a) +/*[clinic end generated code: output=07159cc102261dec input=0448b38af7b8533d]*/ +{ + PyObject *result = Py_IsNone(a) ? Py_True : Py_False; + return Py_NewRef(result); +} + +/*[clinic input] +_operator.is_not_none = _operator.neg + +Same as a is not None. +[clinic start generated code]*/ + +static PyObject * +_operator_is_not_none(PyObject *module, PyObject *a) +/*[clinic end generated code: output=b0168a51451d9140 input=7587f38ebac51688]*/ +{ + PyObject *result = Py_IsNone(a) ? Py_False : Py_True; + return Py_NewRef(result); +} + /* compare_digest **********************************************************/ /* @@ -916,6 +944,8 @@ static struct PyMethodDef operator_methods[] = { _OPERATOR_COUNTOF_METHODDEF _OPERATOR_IS__METHODDEF _OPERATOR_IS_NOT_METHODDEF + _OPERATOR_IS_NONE_METHODDEF + _OPERATOR_IS_NOT_NONE_METHODDEF _OPERATOR_INDEX_METHODDEF _OPERATOR_ADD_METHODDEF _OPERATOR_SUB_METHODDEF diff --git a/Modules/clinic/_operator.c.h b/Modules/clinic/_operator.c.h index 08615d69092..48a8ea8c337 100644 --- a/Modules/clinic/_operator.c.h +++ b/Modules/clinic/_operator.c.h @@ -1393,6 +1393,24 @@ exit: return return_value; } +PyDoc_STRVAR(_operator_is_none__doc__, +"is_none($module, a, /)\n" +"--\n" +"\n" +"Same as a is None."); + +#define _OPERATOR_IS_NONE_METHODDEF \ + {"is_none", (PyCFunction)_operator_is_none, METH_O, _operator_is_none__doc__}, + +PyDoc_STRVAR(_operator_is_not_none__doc__, +"is_not_none($module, a, /)\n" +"--\n" +"\n" +"Same as a is not None."); + +#define _OPERATOR_IS_NOT_NONE_METHODDEF \ + {"is_not_none", (PyCFunction)_operator_is_not_none, METH_O, _operator_is_not_none__doc__}, + PyDoc_STRVAR(_operator_length_hint__doc__, "length_hint($module, obj, default=0, /)\n" "--\n" @@ -1489,4 +1507,4 @@ _operator__compare_digest(PyObject *module, PyObject *const *args, Py_ssize_t na exit: return return_value; } -/*[clinic end generated code: output=ddbba2cd943571eb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=972e2543c4fcf1ba input=a9049054013a1b77]*/