diff -r 9b053d3c74dc Lib/test/test_re.py --- a/Lib/test/test_re.py Wed Nov 16 15:56:50 2016 +0200 +++ b/Lib/test/test_re.py Thu Nov 17 18:19:32 2016 +0100 @@ -1777,6 +1777,39 @@ SUBPATTERN None 0 0 self.assertIn('ASCII', str(re.A)) self.assertIn('DOTALL', str(re.S)) + def test_compare_pattern(self): + pattern1 = re.compile('abc', re.IGNORECASE) + + # equal + re.purge() + pattern2 = re.compile('abc', re.IGNORECASE) + self.assertEqual(pattern2, pattern1) + + # not equal: different pattern + re.purge() + pattern3 = re.compile('abC', re.IGNORECASE) + self.assertNotEqual(pattern3, pattern1) + + # not equal: different flag + re.purge() + pattern4 = re.compile('abC') + self.assertNotEqual(pattern4, pattern1) + + # not equal: pattern of a different types (str vs bytes), + # comparison must not raise a BytesWarning + re.purge() + pattern5 = re.compile(b'abc', re.IGNORECASE) + self.assertNotEqual(pattern5, pattern1) + + # equal: test bytes patterns + re.purge() + pattern6 = re.compile(b'abc', re.IGNORECASE) + self.assertEqual(pattern6, pattern5) + + # only == and != are supported + with self.assertRaises(TypeError): + pattern1 < pattern2 + class PatternReprTests(unittest.TestCase): def check(self, pattern, expected): diff -r 9b053d3c74dc Modules/_sre.c --- a/Modules/_sre.c Wed Nov 16 15:56:50 2016 +0200 +++ b/Modules/_sre.c Thu Nov 17 18:19:32 2016 +0100 @@ -2649,6 +2649,57 @@ pattern_scanner(PatternObject *self, PyO return (PyObject*) scanner; } +static PyObject* +pattern_richcompare(PyObject *lefto, PyObject *righto, int op) +{ + PatternObject *left, *right; + int cmp; + + if (op != Py_EQ && op != Py_NE) { + Py_RETURN_NOTIMPLEMENTED; + } + + if (Py_TYPE(lefto) != &Pattern_Type || Py_TYPE(righto) != &Pattern_Type) { + Py_RETURN_NOTIMPLEMENTED; + } + left = (PatternObject *)lefto; + right = (PatternObject *)righto; + + if (left->isbytes == right->isbytes) { + cmp = PyObject_RichCompareBool(left->pattern, right->pattern, Py_EQ); + if (cmp < 0) { + return NULL; + } + } + else { + /* a pattern is text, the other is bytes: + don't compare to avoid BytesWarning */ + cmp = 0; + } + + if (cmp) { + cmp = (left->flags == right->flags); + } + if (op == Py_NE) { + cmp = !cmp; + } + return PyBool_FromLong(cmp); +} + +static Py_hash_t +pattern_hash(PatternObject *self) +{ + Py_hash_t hash; + + hash = PyObject_Hash(self->pattern); + if (hash == -1) { + return -1; + } + + hash ^= self->flags; + return hash; +} + #include "clinic/_sre.c.h" static PyMethodDef pattern_methods[] = { @@ -2693,7 +2744,7 @@ static PyTypeObject Pattern_Type = { 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)pattern_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ @@ -2703,7 +2754,7 @@ static PyTypeObject Pattern_Type = { pattern_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + pattern_richcompare, /* tp_richcompare */ offsetof(PatternObject, weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */