diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst index 0cf69b4ff9f..bc431843d97 100644 --- a/Doc/library/marshal.rst +++ b/Doc/library/marshal.rst @@ -44,12 +44,6 @@ and dictionaries are only supported as long as the values contained therein are themselves supported; and recursive lists and dictionaries should not be written (they will cause infinite loops). -.. warning:: - - Some unsupported types such as subclasses of builtins will appear to marshal - and unmarshal correctly, but in fact, their type will change and the - additional subclass functionality and instance attributes will be lost. - .. warning:: On machines where C's ``long int`` type has more than 32 bits (such as the diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 9073bca763f..d6a853bc69a 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1418,6 +1418,13 @@ operations: Test *x* for non-membership in *s*. +.. method:: set.isdisjoint(other) + + Return True if the set has no elements in common with *other*. + Sets are disjoint if and only if their interesection is the empty set. + + .. versionadded:: 2.6 + .. method:: set.issubset(other) set <= other diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 30adac97489..4226ffdde81 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -507,8 +507,9 @@ list or clear it entirely:: The built-in function :func:`len` also applies to lists:: + >>> a = ['a', 'b', 'c', 'd'] >>> len(a) - 8 + 4 It is possible to nest lists (create lists containing other lists), for example:: diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index cd92511af59..3a24b223a7a 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -588,10 +588,9 @@ def runtest_inner(test, generate, verbose, quiet, abstest = 'test.' + test the_package = __import__(abstest, globals(), locals(), []) the_module = getattr(the_package, test) - # Most tests run to completion simply as a side-effect of - # being imported. For the benefit of tests that can't run - # that way (like test_threaded_import), explicitly invoke - # their test_main() function (if it exists). + # Old tests run to completion simply as a side-effect of + # being imported. For tests based on unittest or doctest, + # explicitly invoke their test_main() function (if it exists). indirect_test = getattr(the_module, "test_main", None) if indirect_test is not None: indirect_test() diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 961369f757c..1ea93bb9ab7 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1984,6 +1984,71 @@ def properties(): p = property(_testcapi.test_with_docstring) +def properties_plus(): + class C: + foo = property(doc="hello") + @foo.getter + def foo(self): + return self._foo + @foo.setter + def foo(self, value): + self._foo = abs(value) + @foo.deleter + def foo(self): + del self._foo + c = C() + assert C.foo.__doc__ == "hello" + assert not hasattr(c, "foo") + c.foo = -42 + assert c.foo == 42 + del c.foo + assert not hasattr(c, "foo") + + class D(C): + @C.foo.deleter + def foo(self): + try: + del self._foo + except AttributeError: + pass + d = D() + d.foo = 24 + assert d.foo == 24 + del d.foo + del d.foo + + class E: + @property + def foo(self): + return self._foo + @foo.setter + def foo (self, value): + raise RuntimeError + @foo.setter + @foo.deleter + def foo(self, value=None): + if value is None: + del self._foo + else: + self._foo = abs(value) + e = E() + e.foo = -42 + assert e.foo == 42 + del e.foo + + class F(E): + @E.foo.deleter + def foo(self): + del self._foo + @foo.setter + def foo(self, value): + self._foo = max(0, value) + f = F() + f.foo = -10 + assert f.foo == 0 + del f.foo + + def supers(): if verbose: print("Testing super...") diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 89c127a29de..56ce722033a 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -236,6 +236,10 @@ class DictTest(unittest.TestCase): self.assertRaises(Exc, baddict2.fromkeys, [1]) + # test fast path for dictionary inputs + d = dict(zip(range(6), range(6))) + self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) + def test_copy(self): d = {1:1, 2:2, 3:3} self.assertEqual(d.copy(), {1:1, 2:2, 3:3}) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 1e3520f97a1..fb70cede0e5 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -188,6 +188,17 @@ class BugsTestCase(unittest.TestCase): last.append([0]) self.assertRaises(ValueError, marshal.dumps, head) + def test_exact_type_match(self): + # Former bug: + # >>> class Int(int): pass + # >>> type(loads(dumps(Int()))) + # + for typ in (int, float, complex, tuple, list, dict, set, frozenset): + # Note: str sublclasses are not tested because they get handled + # by marshal's routines for objects supporting the buffer API. + subtyp = type('subtyp', (typ,), {}) + self.assertRaises(ValueError, marshal.dumps, subtyp()) + def test_main(): test_support.run_unittest(IntTestCase, FloatTestCase, diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 86a56368671..ba5801d7728 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -102,6 +102,20 @@ class TestJointOps(unittest.TestCase): self.assertEqual(self.thetype('abcba').intersection(C('ccb')), set('bc')) self.assertEqual(self.thetype('abcba').intersection(C('ef')), set('')) + def test_isdisjoint(self): + def f(s1, s2): + 'Pure python equivalent of isdisjoint()' + return not set(s1).intersection(s2) + for larg in '', 'a', 'ab', 'abc', 'ababac', 'cdc', 'cc', 'efgfe', 'ccb', 'ef': + s1 = self.thetype(larg) + for rarg in '', 'a', 'ab', 'abc', 'ababac', 'cdc', 'cc', 'efgfe', 'ccb', 'ef': + for C in set, frozenset, dict.fromkeys, str, list, tuple: + s2 = C(rarg) + actual = s1.isdisjoint(s2) + expected = f(s1, s2) + self.assertEqual(actual, expected) + self.assert_(actual is True or actual is False) + def test_and(self): i = self.s.intersection(self.otherword) self.assertEqual(self.s & set(self.otherword), i) @@ -701,6 +715,18 @@ class TestBasicOps(unittest.TestCase): result = empty_set & self.set self.assertEqual(result, empty_set) + def test_self_isdisjoint(self): + result = self.set.isdisjoint(self.set) + self.assertEqual(result, not self.set) + + def test_empty_isdisjoint(self): + result = self.set.isdisjoint(empty_set) + self.assertEqual(result, True) + + def test_isdisjoint_empty(self): + result = empty_set.isdisjoint(self.set) + self.assertEqual(result, True) + def test_self_symmetric_difference(self): result = self.set ^ self.set self.assertEqual(result, empty_set) @@ -879,6 +905,22 @@ class TestBinaryOps(unittest.TestCase): result = self.set & set([8]) self.assertEqual(result, empty_set) + def test_isdisjoint_subset(self): + result = self.set.isdisjoint(set((2, 4))) + self.assertEqual(result, False) + + def test_isdisjoint_superset(self): + result = self.set.isdisjoint(set([2, 4, 6, 8])) + self.assertEqual(result, False) + + def test_isdisjoint_overlap(self): + result = self.set.isdisjoint(set([3, 4, 5])) + self.assertEqual(result, False) + + def test_isdisjoint_non_overlap(self): + result = self.set.isdisjoint(set([8])) + self.assertEqual(result, True) + def test_sym_difference_subset(self): result = self.set ^ set((2, 4)) self.assertEqual(result, set([6])) @@ -1497,11 +1539,14 @@ class TestVariousIteratorArgs(unittest.TestCase): def test_inline_methods(self): s = set('november') for data in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5), 'december'): - for meth in (s.union, s.intersection, s.difference, s.symmetric_difference): + for meth in (s.union, s.intersection, s.difference, s.symmetric_difference, s.isdisjoint): for g in (G, I, Ig, L, R): expected = meth(data) actual = meth(G(data)) - self.assertEqual(sorted(actual, key=repr), sorted(expected, key=repr)) + if isinstance(expected, bool): + self.assertEqual(actual, expected) + else: + self.assertEqual(sorted(actual, key=repr), sorted(expected, key=repr)) self.assertRaises(TypeError, meth, X(s)) self.assertRaises(TypeError, meth, N(s)) self.assertRaises(ZeroDivisionError, meth, E(s)) diff --git a/Misc/developers.txt b/Misc/developers.txt index 32c1c46579a..7fdfb33ff90 100644 --- a/Misc/developers.txt +++ b/Misc/developers.txt @@ -17,6 +17,9 @@ the format to accommodate documentation needs as they arise. Permissions History ------------------- +- Amaury Forgeot d'Arc was given SVN access on 9 November 2007 by MvL, + for general contributions to Python. + - Christian Heimes was given SVN access on 31 October 2007 by MvL, for general contributions to Python. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index a26b572e83f..85709a9c992 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -51,6 +51,10 @@ typedef struct BLOCK { PyObject *data[BLOCKLEN]; } block; +#define MAXFREEBLOCKS 10 +static int numfreeblocks = 0; +static block *freeblocks[MAXFREEBLOCKS]; + static block * newblock(block *leftlink, block *rightlink, int len) { block *b; @@ -66,16 +70,32 @@ newblock(block *leftlink, block *rightlink, int len) { "cannot add more blocks to the deque"); return NULL; } - b = PyMem_Malloc(sizeof(block)); - if (b == NULL) { - PyErr_NoMemory(); - return NULL; + if (numfreeblocks) { + numfreeblocks -= 1; + b = freeblocks[numfreeblocks]; + } else { + b = PyMem_Malloc(sizeof(block)); + if (b == NULL) { + PyErr_NoMemory(); + return NULL; + } } b->leftlink = leftlink; b->rightlink = rightlink; return b; } +void +freeblock(block *b) +{ + if (numfreeblocks < MAXFREEBLOCKS) { + freeblocks[numfreeblocks] = b; + numfreeblocks++; + } else { + PyMem_Free(b); + } +} + typedef struct { PyObject_HEAD block *leftblock; @@ -161,7 +181,7 @@ deque_pop(dequeobject *deque, PyObject *unused) } else { prevblock = deque->rightblock->leftlink; assert(deque->leftblock != deque->rightblock); - PyMem_Free(deque->rightblock); + freeblock(deque->rightblock); prevblock->rightlink = NULL; deque->rightblock = prevblock; deque->rightindex = BLOCKLEN - 1; @@ -198,7 +218,7 @@ deque_popleft(dequeobject *deque, PyObject *unused) } else { assert(deque->leftblock != deque->rightblock); prevblock = deque->leftblock->rightlink; - PyMem_Free(deque->leftblock); + freeblock(deque->leftblock); assert(prevblock != NULL); prevblock->leftlink = NULL; deque->leftblock = prevblock; @@ -559,7 +579,7 @@ deque_dealloc(dequeobject *deque) if (deque->leftblock != NULL) { deque_clear(deque); assert(deque->leftblock != NULL); - PyMem_Free(deque->leftblock); + freeblock(deque->leftblock); } deque->leftblock = NULL; deque->rightblock = NULL; diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 30ba4618b9a..a0fc2170a4d 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1099,6 +1099,60 @@ static PyMemberDef property_members[] = { {0} }; +PyDoc_STRVAR(getter_doc, + "Descriptor to change the getter on a property."); + +PyObject * +property_getter(PyObject *self, PyObject *getter) +{ + Py_XDECREF(((propertyobject *)self)->prop_get); + if (getter == Py_None) + getter = NULL; + Py_XINCREF(getter); + ((propertyobject *)self)->prop_get = getter; + Py_INCREF(self); + return self; +} + +PyDoc_STRVAR(setter_doc, + "Descriptor to change the setter on a property.\n"); + +PyObject * +property_setter(PyObject *self, PyObject *setter) +{ + Py_XDECREF(((propertyobject *)self)->prop_set); + if (setter == Py_None) + setter = NULL; + Py_XINCREF(setter); + ((propertyobject *)self)->prop_set = setter; + Py_INCREF(self); + return self; +} + +PyDoc_STRVAR(deleter_doc, + "Descriptor to change the deleter on a property."); + +PyObject * +property_deleter(PyObject *self, PyObject *deleter) +{ + Py_XDECREF(((propertyobject *)self)->prop_del); + if (deleter == Py_None) + deleter = NULL; + Py_XINCREF(deleter); + ((propertyobject *)self)->prop_del = deleter; + Py_INCREF(self); + return self; +} + + + +static PyMethodDef property_methods[] = { + {"getter", property_getter, METH_O, getter_doc}, + {"setter", property_setter, METH_O, setter_doc}, + {"deleter", property_deleter, METH_O, deleter_doc}, + {0} +}; + static void property_dealloc(PyObject *self) @@ -1251,7 +1305,7 @@ PyTypeObject PyProperty_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + property_methods, /* tp_methods */ property_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 423012581f6..7bff7d8153e 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1175,6 +1175,25 @@ dict_fromkeys(PyObject *cls, PyObject *args) if (d == NULL) return NULL; + if (PyDict_CheckExact(d) && PyDict_CheckExact(seq)) { + PyDictObject *mp = (PyDictObject *)d; + PyObject *oldvalue; + Py_ssize_t pos = 0; + PyObject *key; + long hash; + + if (dictresize(mp, PySet_GET_SIZE(seq))) + return NULL; + + while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash)) { + Py_INCREF(key); + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) + return NULL; + } + return d; + } + if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { PyDictObject *mp = (PyDictObject *)d; Py_ssize_t pos = 0; @@ -1199,19 +1218,24 @@ dict_fromkeys(PyObject *cls, PyObject *args) return NULL; } - for (;;) { - key = PyIter_Next(it); - if (key == NULL) { - if (PyErr_Occurred()) + if (PyDict_CheckExact(d)) { + while ((key = PyIter_Next(it)) != NULL) { + status = PyDict_SetItem(d, key, value); + Py_DECREF(key); + if (status < 0) + goto Fail; + } + } else { + while ((key = PyIter_Next(it)) != NULL) { + status = PyObject_SetItem(d, key, value); + Py_DECREF(key); + if (status < 0) goto Fail; - break; } - status = PyObject_SetItem(d, key, value); - Py_DECREF(key); - if (status < 0) - goto Fail; } + if (PyErr_Occurred()) + goto Fail; Py_DECREF(it); return d; diff --git a/Objects/setobject.c b/Objects/setobject.c index ba7d2c4763a..f6ea441785b 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1314,6 +1314,73 @@ set_iand(PySetObject *so, PyObject *other) return (PyObject *)so; } +static PyObject * +set_isdisjoint(PySetObject *so, PyObject *other) +{ + PyObject *key, *it, *tmp; + + if ((PyObject *)so == other) { + if (PySet_GET_SIZE(so) == 0) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + } + + if (PyAnySet_CheckExact(other)) { + Py_ssize_t pos = 0; + setentry *entry; + + if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) { + tmp = (PyObject *)so; + so = (PySetObject *)other; + other = tmp; + } + while (set_next((PySetObject *)other, &pos, &entry)) { + int rv = set_contains_entry(so, entry); + if (rv == -1) + return NULL; + if (rv) + Py_RETURN_FALSE; + } + Py_RETURN_TRUE; + } + + it = PyObject_GetIter(other); + if (it == NULL) + return NULL; + + while ((key = PyIter_Next(it)) != NULL) { + int rv; + setentry entry; + long hash = PyObject_Hash(key); + + if (hash == -1) { + Py_DECREF(key); + Py_DECREF(it); + return NULL; + } + entry.hash = hash; + entry.key = key; + rv = set_contains_entry(so, &entry); + Py_DECREF(key); + if (rv == -1) { + Py_DECREF(it); + return NULL; + } + if (rv) { + Py_DECREF(it); + Py_RETURN_FALSE; + } + } + Py_DECREF(it); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(isdisjoint_doc, +"Return True if two sets have a null intersection."); + static int set_difference_update_internal(PySetObject *so, PyObject *other) { @@ -1839,6 +1906,8 @@ static PyMethodDef set_methods[] = { intersection_doc}, {"intersection_update",(PyCFunction)set_intersection_update, METH_O, intersection_update_doc}, + {"isdisjoint", (PyCFunction)set_isdisjoint, METH_O, + isdisjoint_doc}, {"issubset", (PyCFunction)set_issubset, METH_O, issubset_doc}, {"issuperset", (PyCFunction)set_issuperset, METH_O, @@ -1960,6 +2029,8 @@ static PyMethodDef frozenset_methods[] = { difference_doc}, {"intersection",(PyCFunction)set_intersection, METH_O, intersection_doc}, + {"isdisjoint", (PyCFunction)set_isdisjoint, METH_O, + isdisjoint_doc}, {"issubset", (PyCFunction)set_issubset, METH_O, issubset_doc}, {"issuperset", (PyCFunction)set_issuperset, METH_O, diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 8761477eec6..2e729ea8219 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -611,6 +611,7 @@ PyString_Repr(PyObject *obj, int smartquotes) if (newsize > PY_SSIZE_T_MAX || (newsize-3) / 4 != length) { PyErr_SetString(PyExc_OverflowError, "bytes object is too large to make repr"); + return NULL; } v = PyUnicode_FromUnicode(NULL, newsize); if (v == NULL) { diff --git a/Python/ceval.c b/Python/ceval.c index c0e0993cf50..b42444da82d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2011,7 +2011,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) PREDICTED_WITH_ARG(JUMP_ABSOLUTE); case JUMP_ABSOLUTE: JUMPTO(oparg); +#if FAST_LOOPS + /* Enabling this path speeds-up all while and for-loops by bypassing + the per-loop checks for signals. By default, this should be turned-off + because it prevents detection of a control-break in tight loops like + "while 1: pass". Compile with this option turned-on when you need + the speed-up and do not need break checking inside tight loops (ones + that contain only instructions ending with goto fast_next_opcode). + */ + goto fast_next_opcode; +#else continue; +#endif case GET_ITER: /* before: [obj]; after [getiter(obj)] */ diff --git a/Python/marshal.c b/Python/marshal.c index a40aecc90f3..3e106c21d49 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -147,7 +147,7 @@ w_object(PyObject *v, WFILE *p) else if (v == Py_True) { w_byte(TYPE_TRUE, p); } - else if (PyLong_Check(v)) { + else if (PyLong_CheckExact(v)) { long x = PyLong_AsLong(v); if ((x == -1) && PyErr_Occurred()) { PyLongObject *ob = (PyLongObject *)v; @@ -175,7 +175,7 @@ w_object(PyObject *v, WFILE *p) } } } - else if (PyFloat_Check(v)) { + else if (PyFloat_CheckExact(v)) { if (p->version > 1) { unsigned char buf[8]; if (_PyFloat_Pack8(PyFloat_AsDouble(v), @@ -196,7 +196,7 @@ w_object(PyObject *v, WFILE *p) } } #ifndef WITHOUT_COMPLEX - else if (PyComplex_Check(v)) { + else if (PyComplex_CheckExact(v)) { if (p->version > 1) { unsigned char buf[8]; if (_PyFloat_Pack8(PyComplex_RealAsDouble(v), @@ -228,7 +228,7 @@ w_object(PyObject *v, WFILE *p) } } #endif - else if (PyString_Check(v)) { + else if (PyString_CheckExact(v)) { w_byte(TYPE_STRING, p); n = PyString_GET_SIZE(v); if (n > INT_MAX) { @@ -240,7 +240,7 @@ w_object(PyObject *v, WFILE *p) w_long((long)n, p); w_string(PyString_AS_STRING(v), (int)n, p); } - else if (PyUnicode_Check(v)) { + else if (PyUnicode_CheckExact(v)) { PyObject *utf8; utf8 = PyUnicode_AsUTF8String(v); if (utf8 == NULL) { @@ -259,7 +259,7 @@ w_object(PyObject *v, WFILE *p) w_string(PyString_AS_STRING(utf8), (int)n, p); Py_DECREF(utf8); } - else if (PyTuple_Check(v)) { + else if (PyTuple_CheckExact(v)) { w_byte(TYPE_TUPLE, p); n = PyTuple_Size(v); w_long((long)n, p); @@ -267,7 +267,7 @@ w_object(PyObject *v, WFILE *p) w_object(PyTuple_GET_ITEM(v, i), p); } } - else if (PyList_Check(v)) { + else if (PyList_CheckExact(v)) { w_byte(TYPE_LIST, p); n = PyList_GET_SIZE(v); w_long((long)n, p); @@ -275,7 +275,7 @@ w_object(PyObject *v, WFILE *p) w_object(PyList_GET_ITEM(v, i), p); } } - else if (PyDict_Check(v)) { + else if (PyDict_CheckExact(v)) { Py_ssize_t pos; PyObject *key, *value; w_byte(TYPE_DICT, p); @@ -287,7 +287,7 @@ w_object(PyObject *v, WFILE *p) } w_object((PyObject *)NULL, p); } - else if (PyAnySet_Check(v)) { + else if (PyAnySet_CheckExact(v)) { PyObject *value, *it; if (PyObject_TypeCheck(v, &PySet_Type))