diff --git a/Lib/test/test_py3kwarn.py b/Lib/test/test_py3kwarn.py index 61de7a22bde..cdb10384497 100644 --- a/Lib/test/test_py3kwarn.py +++ b/Lib/test/test_py3kwarn.py @@ -50,6 +50,35 @@ class TestPy3KWarnings(unittest.TestCase): with catch_warning() as w: self.assertWarning(cell0 < cell1, w, expected) + def test_code_inequality_comparisons(self): + expected = 'code inequality comparisons not supported in 3.x.' + def f(x): + pass + def g(x): + pass + with catch_warning() as w: + self.assertWarning(f.func_code < g.func_code, w, expected) + with catch_warning() as w: + self.assertWarning(f.func_code <= g.func_code, w, expected) + with catch_warning() as w: + self.assertWarning(f.func_code >= g.func_code, w, expected) + with catch_warning() as w: + self.assertWarning(f.func_code > g.func_code, w, expected) + + def test_builtin_function_or_method_comparisons(self): + expected = ('builtin_function_or_method ' + 'inequality comparisons not supported in 3.x.') + func = eval + meth = {}.get + with catch_warning() as w: + self.assertWarning(func < meth, w, expected) + with catch_warning() as w: + self.assertWarning(func > meth, w, expected) + with catch_warning() as w: + self.assertWarning(meth <= func, w, expected) + with catch_warning() as w: + self.assertWarning(meth >= func, w, expected) + def assertWarning(self, _, warning, expected_message): self.assertEqual(str(warning.message), expected_message) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index e75ab94e10f..57cd2e62644 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -327,6 +327,72 @@ code_compare(PyCodeObject *co, PyCodeObject *cp) return 0; } +static PyObject * +code_richcompare(PyObject *self, PyObject *other, int op) +{ + PyCodeObject *co, *cp; + int eq; + PyObject *res; + + if ((op != Py_EQ && op != Py_NE) || + !PyCode_Check(self) || + !PyCode_Check(other)) { + + /* Py3K warning if types are not equal and comparison isn't == or != */ + if (Py_Py3kWarningFlag && PyErr_Warn(PyExc_DeprecationWarning, + "code inequality comparisons not supported in 3.x.") < 0) { + return NULL; + } + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + co = (PyCodeObject *)self; + cp = (PyCodeObject *)other; + + eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ); + if (eq <= 0) goto unequal; + eq = co->co_argcount == cp->co_argcount; + if (!eq) goto unequal; + eq = co->co_nlocals == cp->co_nlocals; + if (!eq) goto unequal; + eq = co->co_flags == cp->co_flags; + if (!eq) goto unequal; + eq = co->co_firstlineno == cp->co_firstlineno; + if (!eq) goto unequal; + eq = PyObject_RichCompareBool(co->co_code, cp->co_code, Py_EQ); + if (eq <= 0) goto unequal; + eq = PyObject_RichCompareBool(co->co_consts, cp->co_consts, Py_EQ); + if (eq <= 0) goto unequal; + eq = PyObject_RichCompareBool(co->co_names, cp->co_names, Py_EQ); + if (eq <= 0) goto unequal; + eq = PyObject_RichCompareBool(co->co_varnames, cp->co_varnames, Py_EQ); + if (eq <= 0) goto unequal; + eq = PyObject_RichCompareBool(co->co_freevars, cp->co_freevars, Py_EQ); + if (eq <= 0) goto unequal; + eq = PyObject_RichCompareBool(co->co_cellvars, cp->co_cellvars, Py_EQ); + if (eq <= 0) goto unequal; + + if (op == Py_EQ) + res = Py_True; + else + res = Py_False; + goto done; + + unequal: + if (eq < 0) + return NULL; + if (op == Py_NE) + res = Py_True; + else + res = Py_False; + + done: + Py_INCREF(res); + return res; +} + static long code_hash(PyCodeObject *co) { @@ -377,7 +443,7 @@ PyTypeObject PyCode_Type = { code_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + code_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/methodobject.c b/Objects/methodobject.c index d661c475006..5b9a3643aa5 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -223,6 +223,40 @@ meth_compare(PyCFunctionObject *a, PyCFunctionObject *b) return 1; } +static PyObject * +meth_richcompare(PyObject *self, PyObject *other, int op) +{ + PyCFunctionObject *a, *b; + PyObject *res; + int eq; + + if ((op != Py_EQ && op != Py_NE) || + !PyCFunction_Check(self) || + !PyCFunction_Check(other)) + { + /* Py3K warning if types are not equal and comparison isn't == or != */ + if (Py_Py3kWarningFlag && PyErr_Warn(PyExc_DeprecationWarning, + "builtin_function_or_method " + "inequality comparisons not supported in 3.x.") < 0) { + return NULL; + } + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + a = (PyCFunctionObject *)self; + b = (PyCFunctionObject *)other; + eq = a->m_self == b->m_self; + if (eq) + eq = a->m_ml->ml_meth == b->m_ml->ml_meth; + if (op == Py_EQ) + res = eq ? Py_True : Py_False; + else + res = eq ? Py_False : Py_True; + Py_INCREF(res); + return res; +} + static long meth_hash(PyCFunctionObject *a) { @@ -268,7 +302,7 @@ PyTypeObject PyCFunction_Type = { 0, /* tp_doc */ (traverseproc)meth_traverse, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + meth_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */