Index: Lib/test/pickletester.py =================================================================== --- Lib/test/pickletester.py (revision 82908) +++ Lib/test/pickletester.py (working copy) @@ -65,9 +65,15 @@ def __eq__(self, other): return self.__dict__ == other.__dict__ +class D(C): + def __init__(self, arg): + pass + import __main__ __main__.C = C C.__module__ = "__main__" +__main__.D = D +D.__module__ = "__main__" class myint(int): def __init__(self, x): @@ -425,6 +431,63 @@ def test_load_from_data2(self): self.assertEqual(self._testdata, self.loads(DATA2)) + def test_load_classic_instance(self): + # See issue5180. Test loading 2.x pickles that + # contain an instance of old style class. + for X, args in [(C, ()), (D, ('x',))]: + xname = X.__name__.encode('ascii') + # Protocol 0 (text mode pickle): + """ + 0: ( MARK + 1: i INST '__main__ X' (MARK at 0) + 15: p PUT 0 + 18: ( MARK + 19: d DICT (MARK at 18) + 20: p PUT 1 + 23: b BUILD + 24: . STOP + """ + pickle0 = (b"(i__main__\n" + b"X\n" + b"p0\n" + b"(dp1\nb.").replace(b'X', xname) + self.assertEqual(X(*args), self.loads(pickle0)) + + # Protocol 1 (binary mode pickle) + """ + 0: ( MARK + 1: c GLOBAL '__main__ X' + 15: q BINPUT 0 + 17: o OBJ (MARK at 0) + 18: q BINPUT 1 + 20: } EMPTY_DICT + 21: q BINPUT 2 + 23: b BUILD + 24: . STOP + """ + pickle1 = (b'(c__main__\n' + b'X\n' + b'q\x00oq\x01}q\x02b.').replace(b'X', xname) + self.assertEqual(X(*args), self.loads(pickle1)) + + # Protocol 2 (pickle2 = b'\x80\x02' + pickle1) + """ + 0: \x80 PROTO 2 + 2: ( MARK + 3: c GLOBAL '__main__ Bug' + 17: q BINPUT 0 + 19: o OBJ (MARK at 2) + 20: q BINPUT 1 + 22: } EMPTY_DICT + 23: q BINPUT 2 + 25: b BUILD + 26: . STOP + """ + pickle2 = (b'\x80\x02(c__main__\n' + b'X\n' + b'q\x00oq\x01}q\x02b.').replace(b'X', xname) + self.assertEqual(X(*args), self.loads(pickle2)) + # There are gratuitous differences between pickles produced by # pickle and cPickle, largely because cPickle starts PUT indices at # 1 and pickle starts them at 0. See XXX comment in cPickle's put2() -- Index: Lib/pickle.py =================================================================== --- Lib/pickle.py (revision 82908) +++ Lib/pickle.py (working copy) @@ -1038,8 +1038,7 @@ if (not args and isinstance(klass, type) and not hasattr(klass, "__getinitargs__")): - value = _EmptyClass() - value.__class__ = klass + value = klass.__new__(klass) instantiated = True if not instantiated: try: @@ -1239,15 +1238,8 @@ raise _Stop(value) dispatch[STOP[0]] = load_stop -# Helper class for load_inst/load_obj +# Encode/decode longs. -class _EmptyClass: - pass - -# Encode/decode longs in linear time. - -import binascii as _binascii - def encode_long(x): r"""Encode a long to a two's complement little-endian binary string. Note that 0 is a special case, returning an empty string, to save a Index: Modules/_pickle.c =================================================================== --- Modules/_pickle.c (revision 82908) +++ Modules/_pickle.c (working copy) @@ -3467,28 +3467,16 @@ instantiate(PyObject *cls, PyObject *args) { PyObject *r = NULL; + Py_ssize_t len = PyObject_Size(args); + if (len == -1) + return NULL; + if (len != 0 || !PyType_Check(cls) || + PyObject_HasAttrString(cls, "__getinitargs__")) + r = PyObject_CallObject(cls, args); + else + r = PyObject_CallMethod(cls, "__new__", "O", cls); - /* XXX: The pickle.py module does not create instances this way when the - args tuple is empty. See Unpickler._instantiate(). */ - if ((r = PyObject_CallObject(cls, args))) - return r; - - /* XXX: Is this still nescessary? */ - { - PyObject *tp, *v, *tb, *tmp_value; - - PyErr_Fetch(&tp, &v, &tb); - tmp_value = v; - /* NULL occurs when there was a KeyboardInterrupt */ - if (tmp_value == NULL) - tmp_value = Py_None; - if ((r = PyTuple_Pack(3, tmp_value, cls, args))) { - Py_XDECREF(v); - v = r; - } - PyErr_Restore(tp, v, tb); - } - return NULL; + return r; } static int @@ -3547,7 +3535,7 @@ if (len < 2) return bad_readline(); class_name = PyUnicode_DecodeASCII(s, len - 1, "strict"); - if (class_name == NULL) { + if (class_name != NULL) { cls = find_class(self, module_name, class_name); Py_DECREF(class_name); } @@ -4276,7 +4264,7 @@ return -1; PDATA_POP(self->stack, callable); if (callable) { - obj = instantiate(callable, argtup); + obj = PyObject_CallObject(callable, argtup); Py_DECREF(callable); } Py_DECREF(argtup);