From 4043001f5d84d4919781e34221449047d0690ac8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 22 Oct 2007 20:24:51 +0000 Subject: Make str/str8 comparisons return True/False for !=/==. Code that has been returning str8 becomes much more apparent thanks to this (e.g., struct module returning str8 for all string-related formats or sqlite3 passing in str8 instances when converting objects that had a __conform__ method). One also has to watch out in C code when making a key from char * using PyString in the C code but a str instance in Python code as that will not longer compare equal. Once str8 gains a constructor like the current bytes type then test_modulefinder needs a cleanup as the fix is a little messy in that file. Thanks goes to Thomas Lee for writing the patch for the change giving an initial run-down of why most of the tests were failing. --- Lib/modulefinder.py | 13 +-- Lib/sqlite3/test/types.py | 4 + Lib/test/test_compile.py | 2 +- Lib/test/test_format.py | 249 ++++++++++++++++++++++---------------------- Lib/test/test_str.py | 42 +------- Lib/test/test_struct.py | 38 ++++--- Lib/test/test_subprocess.py | 2 +- Lib/test/test_unicode.py | 4 + Misc/NEWS | 6 ++ Modules/_sqlite/cursor.c | 4 +- Objects/unicodeobject.c | 10 -- 11 files changed, 169 insertions(+), 205 deletions(-) diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py index 1dbc5bb..cd9906c 100644 --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -16,12 +16,13 @@ else: # remain compatible with Python < 2.3 READ_MODE = "r" -LOAD_CONST = chr(dis.opname.index('LOAD_CONST')) -IMPORT_NAME = chr(dis.opname.index('IMPORT_NAME')) -STORE_NAME = chr(dis.opname.index('STORE_NAME')) -STORE_GLOBAL = chr(dis.opname.index('STORE_GLOBAL')) +# XXX Clean up once str8's cstor matches bytes. +LOAD_CONST = str8(chr(dis.opname.index('LOAD_CONST'))) +IMPORT_NAME = str8(chr(dis.opname.index('IMPORT_NAME'))) +STORE_NAME = str8(chr(dis.opname.index('STORE_NAME'))) +STORE_GLOBAL = str8(chr(dis.opname.index('STORE_GLOBAL'))) STORE_OPS = [STORE_NAME, STORE_GLOBAL] -HAVE_ARGUMENT = chr(dis.HAVE_ARGUMENT) +HAVE_ARGUMENT = str8(chr(dis.HAVE_ARGUMENT)) # Modulefinder does a good job at simulating Python's, but it can not # handle __path__ modifications packages make at runtime. Therefore there @@ -367,7 +368,7 @@ class ModuleFinder: consts = co.co_consts LOAD_LOAD_AND_IMPORT = LOAD_CONST + LOAD_CONST + IMPORT_NAME while code: - c = chr(code[0]) + c = str8(chr(code[0])) if c in STORE_OPS: oparg, = unpack(' %d # expected %d" % ( xfmt, n, len(res))) rev = struct.unpack(xfmt, res)[0] + if isinstance(arg, str): + # Strings are returned as str8 since you can't know the encoding of + # the string when packed. + arg = str8(arg) if rev != arg and not asy: raise TestFailed("unpack(%r, %r) -> (%r,) # expected (%r,)" % ( fmt, res, rev, arg)) @@ -424,14 +428,14 @@ for args in [("bB", 1), def test_p_code(): for code, input, expected, expectedback in [ - ('p','abc', '\x00', ''), - ('1p', 'abc', '\x00', ''), - ('2p', 'abc', '\x01a', 'a'), - ('3p', 'abc', '\x02ab', 'ab'), - ('4p', 'abc', '\x03abc', 'abc'), - ('5p', 'abc', '\x03abc\x00', 'abc'), - ('6p', 'abc', '\x03abc\x00\x00', 'abc'), - ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]: + ('p','abc', '\x00', str8('')), + ('1p', 'abc', '\x00', str8('')), + ('2p', 'abc', '\x01a', str8('a')), + ('3p', 'abc', '\x02ab', str8('ab')), + ('4p', 'abc', '\x03abc', str8('abc')), + ('5p', 'abc', '\x03abc\x00', str8('abc')), + ('6p', 'abc', '\x03abc\x00\x00', str8('abc')), + ('1000p', 'x'*1000, '\xff' + 'x'*999, str8('x'*255))]: expected = bytes(expected, "latin-1") got = struct.pack(code, input) if got != expected: @@ -560,20 +564,20 @@ def test_unpack_from(): if verbose: print("test_unpack_from using", cls.__name__) data = cls(test_string) - vereq(s.unpack_from(data), ('abcd',)) - vereq(s.unpack_from(data, 2), ('cd01',)) - vereq(s.unpack_from(data, 4), ('0123',)) + vereq(s.unpack_from(data), (str8('abcd'),)) + vereq(s.unpack_from(data, 2), (str8('cd01'),)) + vereq(s.unpack_from(data, 4), (str8('0123'),)) for i in range(6): - vereq(s.unpack_from(data, i), (data[i:i+4],)) + vereq(s.unpack_from(data, i), (str8(data[i:i+4]),)) for i in range(6, len(test_string) + 1): simple_err(s.unpack_from, data, i) for cls in (str, str8, bytes): # XXX + memoryview data = cls(test_string) - vereq(struct.unpack_from(fmt, data), ('abcd',)) - vereq(struct.unpack_from(fmt, data, 2), ('cd01',)) - vereq(struct.unpack_from(fmt, data, 4), ('0123',)) + vereq(struct.unpack_from(fmt, data), (str8('abcd'),)) + vereq(struct.unpack_from(fmt, data, 2), (str8('cd01'),)) + vereq(struct.unpack_from(fmt, data, 4), (str8('0123'),)) for i in range(6): - vereq(struct.unpack_from(fmt, data, i), (data[i:i+4],)) + vereq(struct.unpack_from(fmt, data, i), (str8(data[i:i+4]),)) for i in range(6, len(test_string) + 1): simple_err(struct.unpack_from, fmt, data, i) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3c92675..fea98dc 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -24,7 +24,7 @@ else: # shutdown time. That frustrates tests trying to check stderr produced # from a spawned Python process. def remove_stderr_debug_decorations(stderr): - return re.sub(r"\[\d+ refs\]\r?\n?$", "", str8(stderr)) + return re.sub(r"\[\d+ refs\]\r?\n?$", "", str(stderr)) class ProcessTestCase(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index d33643a..04dddaa 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -200,6 +200,10 @@ class UnicodeTest( self.checkequalnofix('one@two!three!', 'one!two!three!', 'replace', '!', '@', 1) self.assertRaises(TypeError, 'replace'.replace, "r", 42) + def test_str8_comparison(self): + self.assertEqual('abc' == str8('abc'), False) + self.assertEqual('abc' != str8('abc'), True) + def test_comparison(self): # Comparisons: self.assertEqual('abc', 'abc') diff --git a/Misc/NEWS b/Misc/NEWS index 86c5a59..c0fe108 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,6 +11,12 @@ What's New in Python 3.0a2? Core and Builtins ----------------- +- Comparisons between str and str8 now return False/True for ==/!=. sqlite3 + returns str8 when recreating on object from it's __conform__ value. The + struct module returns str8 for all string-related formats. This was true + before this change, but becomes more apparent thanks to string comparisons + always being False. + - Replaced `PyFile_FromFile()` with `PyFile_FromFd(fd, name. mode, buffer, encoding, newline)` diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 3894ec6..c789faf 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -182,7 +182,7 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self) if (*pos == '[') { type_start = pos + 1; } else if (*pos == ']' && type_start != (const char*)-1) { - key = PyString_FromStringAndSize(type_start, pos - type_start); + key = PyUnicode_FromStringAndSize(type_start, pos - type_start); if (!key) { /* creating a string failed, but it is too complicated * to propagate the error here, we just assume there is @@ -203,7 +203,7 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self) if (decltype) { for (pos = decltype;;pos++) { if (*pos == ' ' || *pos == 0) { - py_decltype = PyString_FromStringAndSize(decltype, pos - decltype); + py_decltype = PyUnicode_FromStringAndSize(decltype, pos - decltype); if (!py_decltype) { return -1; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index fed2ff5..13644b0 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -6224,16 +6224,6 @@ int PyUnicode_Compare(PyObject *left, if (PyUnicode_Check(left) && PyUnicode_Check(right)) return unicode_compare((PyUnicodeObject *)left, (PyUnicodeObject *)right); - if ((PyString_Check(left) && PyUnicode_Check(right)) || - (PyUnicode_Check(left) && PyString_Check(right))) { - if (PyUnicode_Check(left)) - left = _PyUnicode_AsDefaultEncodedString(left, NULL); - if (PyUnicode_Check(right)) - right = _PyUnicode_AsDefaultEncodedString(right, NULL); - assert(PyString_Check(left)); - assert(PyString_Check(right)); - return PyObject_Compare(left, right); - } PyErr_Format(PyExc_TypeError, "Can't compare %.100s and %.100s", left->ob_type->tp_name, -- cgit v0.12