SF patch #670423: Add missing identity tests to operator.c
diff --git a/Doc/lib/liboperator.tex b/Doc/lib/liboperator.tex
index f3f0980..7bd66ea 100644
--- a/Doc/lib/liboperator.tex
+++ b/Doc/lib/liboperator.tex
@@ -48,7 +48,7 @@
 
 
 The logical operations are also generally applicable to all objects,
-and support truth tests and Boolean operations:
+and support truth tests, identity tests, and Boolean operations:
 
 \begin{funcdesc}{not_}{o}
 \funcline{__not__}{o}
@@ -64,6 +64,14 @@
 constructor.
 \end{funcdesc}
 
+\begin{funcdesc}{is_}{a, b}
+Return \code{\var{a} is \var{b}}.  Tests object identity.
+\end{funcdesc}
+
+\begin{funcdesc}{is_not}{a, b}
+Return \code{\var{a} is not \var{b}}.  Tests object identity.
+\end{funcdesc}
+
 
 The mathematical and bitwise operations are the most numerous:
 
diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py
index 611e427..422a3cb 100644
--- a/Lib/test/test_operator.py
+++ b/Lib/test/test_operator.py
@@ -215,6 +215,17 @@
     def test_bitwise_xor(self):
         self.failUnless(operator.xor(0xb, 0xc) == 0x7)
 
+    def test_is(self):
+        a = b = 'xyzpdq'
+        c = a[:3] + b[3:]
+        self.failUnless(operator.is_(a, b))
+        self.failIf(operator.is_(a,c))
+
+    def test_is_not(self):
+        a = b = 'xyzpdq'
+        c = a[:3] + b[3:]
+        self.failIf(operator.is_not(a, b))
+        self.failUnless(operator.is_not(a,c))
 
 def test_main():
     test_support.run_unittest(OperatorTestCase)
diff --git a/Misc/NEWS b/Misc/NEWS
index 30b4902..349712f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -517,6 +517,11 @@
 Extension modules
 -----------------
 
+- Added three operators to the operator module:
+    operator.pow(a,b) which is equivalent to:  a**b.
+    operator.is_(a,b) which is equivalent to:  a is b.
+    operator.is_not(a,b) which is equivalent to:  a is not b.
+
 - posix.openpty now works on all systems that have /dev/ptmx.
 
 - A module zipimport exists to support importing code from zip
@@ -733,8 +738,6 @@
   or when you need to use sets as dict keys, and a class BaseSet which
   is the base class of the two.
 
-- Added operator.pow(a,b) which is equivalent to a**b.
-
 - Added random.sample(population,k) for random sampling without replacement.
   Returns a k length list of unique elements chosen from the population.
 
diff --git a/Modules/operator.c b/Modules/operator.c
index 5371b95..7638fb8 100644
--- a/Modules/operator.c
+++ b/Modules/operator.c
@@ -108,6 +108,28 @@
 }
 
 static PyObject*
+is_(PyObject *s, PyObject *a)
+{
+	PyObject *a1, *a2, *result = NULL;
+	if (PyArg_UnpackTuple(a,"is_", 2, 2, &a1, &a2)) {
+		result = (a1 == a2) ? Py_True : Py_False;
+		Py_INCREF(result);
+	}
+	return result;
+}
+
+static PyObject*
+is_not(PyObject *s, PyObject *a)
+{
+	PyObject *a1, *a2, *result = NULL;
+	if (PyArg_UnpackTuple(a,"is_not", 2, 2, &a1, &a2)) {
+		result = (a1 != a2) ? Py_True : Py_False;
+		Py_INCREF(result);
+	}
+	return result;
+}
+
+static PyObject*
 op_getslice(PyObject *s, PyObject *a)
 {
         PyObject *a1;
@@ -182,6 +204,8 @@
 spam1o(isMappingType,
  "isMappingType(a) -- Return True if a has a mapping type, False otherwise.")
 
+spam1(is_, "is_(a, b) -- Same as a is b.")
+spam1(is_not, "is_not(a, b) -- Same as a is not b.")
 spam2(add,__add__, "add(a, b) -- Same as a + b.")
 spam2(sub,__sub__, "sub(a, b) -- Same as a - b.")
 spam2(mul,__mul__, "mul(a, b) -- Same as a * b.")