diff options
-rw-r--r-- | Doc/library/collections.rst | 3 | ||||
-rw-r--r-- | Doc/library/math.rst | 4 | ||||
-rw-r--r-- | Doc/library/stdtypes.rst | 28 | ||||
-rw-r--r-- | Doc/library/tokenize.rst | 10 | ||||
-rw-r--r-- | Lib/collections.py | 4 | ||||
-rw-r--r-- | Lib/test/test_collections.py | 21 | ||||
-rw-r--r-- | Lib/test/test_math.py | 15 | ||||
-rw-r--r-- | Lib/test/test_set.py | 13 | ||||
-rw-r--r-- | Lib/test/test_sys.py | 32 | ||||
-rw-r--r-- | Lib/test/test_urllib2net.py | 24 | ||||
-rw-r--r-- | Modules/mathmodule.c | 49 | ||||
-rw-r--r-- | Objects/setobject.c | 92 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 23 |
13 files changed, 269 insertions, 49 deletions
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 5035ac9..3203ca5 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -519,6 +519,9 @@ Example: if kwds: raise ValueError('Got unexpected field names: %r' % kwds.keys()) return result + <BLANKLINE> + def __getnewargs__(self): + return tuple(self) <BLANKLINE> x = property(itemgetter(0)) y = property(itemgetter(1)) diff --git a/Doc/library/math.rst b/Doc/library/math.rst index 0868e8e..aba6b0e 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -41,6 +41,10 @@ Number-theoretic and representation functions: Return the absolute value of *x*. +.. function:: factorial(x) + + Return *x* factorial. Raises :exc:`ValueError` if *x* is not intergral or + is negative. .. function:: floor(x) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 09549ad..27c3fb4 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1501,16 +1501,22 @@ The constructors for both classes work the same: Test whether the set is a true superset of *other*, that is, ``set >= other and set != other``. - .. method:: union(other) - set | other + .. method:: union(other, ...) + set | other | ... Return a new set with elements from both sets. - .. method:: intersection(other) - set & other + .. versionchanged:: 2.6 + Accepts multiple input iterables. + + .. method:: intersection(other, ...) + set & other & ... Return a new set with elements common to both sets. + .. versionchanged:: 2.6 + Accepts multiple input iterables. + .. method:: difference(other) set - other @@ -1562,16 +1568,22 @@ The constructors for both classes work the same: The following table lists operations available for :class:`set` that do not apply to immutable instances of :class:`frozenset`: - .. method:: update(other) - set |= other + .. method:: update(other, ...) + set |= other | ... Update the set, adding elements from *other*. - .. method:: intersection_update(other) - set &= other + .. versionchanged:: 2.6 + Accepts multiple input iterables. + + .. method:: intersection_update(other, ...) + set &= other & ... Update the set, keeping only elements found in it and *other*. + .. versionchanged:: 2.6 + Accepts multiple input iterables. + .. method:: difference_update(other) set -= other diff --git a/Doc/library/tokenize.rst b/Doc/library/tokenize.rst index bbe73d0..b2caded 100644 --- a/Doc/library/tokenize.rst +++ b/Doc/library/tokenize.rst @@ -1,4 +1,3 @@ - :mod:`tokenize` --- Tokenizer for Python source =============================================== @@ -15,7 +14,6 @@ colorizers for on-screen displays. The primary entry point is a :term:`generator`: - .. function:: tokenize(readline) The :func:`tokenize` generator requires one argument, *readline*, which @@ -28,11 +26,11 @@ The primary entry point is a :term:`generator`: token string; a 2-tuple ``(srow, scol)`` of ints specifying the row and column where the token begins in the source; a 2-tuple ``(erow, ecol)`` of ints specifying the row and column where the token ends in the source; and - the line on which the token was found. The line passed is the *logical* - line; continuation lines are included. + the line on which the token was found. The line passed (the last tuple item) + is the *logical* line; continuation lines are included. - tokenize determines the source encoding of the file by looking for a utf-8 - bom or encoding cookie, according to :pep:`263`. + :func:`tokenize` determines the source encoding of the file by looking for a + UTF-8 BOM or encoding cookie, according to :pep:`263`. All constants from the :mod:`token` module are also exported from diff --git a/Lib/collections.py b/Lib/collections.py index 73fc150..6d439e5 100644 --- a/Lib/collections.py +++ b/Lib/collections.py @@ -87,7 +87,9 @@ def namedtuple(typename, field_names, verbose=False): result = self._make(map(kwds.pop, %(field_names)r, self)) if kwds: raise ValueError('Got unexpected field names: %%r' %% kwds.keys()) - return result \n\n''' % locals() + return result \n + def __getnewargs__(self): + return tuple(self) \n\n''' % locals() for i, name in enumerate(field_names): template += ' %s = property(itemgetter(%d))\n' % (name, i) if verbose: diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 4ed0e24..9289afe 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -3,6 +3,7 @@ import unittest, doctest from test import support from collections import namedtuple +import pickle, copy from collections import Hashable, Iterable, Iterator from collections import Sized, Container, Callable from collections import Set, MutableSet @@ -10,6 +11,7 @@ from collections import Mapping, MutableMapping from collections import Sequence, MutableSequence from collections import ByteString +TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests class TestNamedTuple(unittest.TestCase): @@ -111,7 +113,7 @@ class TestNamedTuple(unittest.TestCase): self.assertEqual(Dot(1)._replace(d=999), (999,)) self.assertEqual(Dot(1)._fields, ('d',)) - # n = 10000 + # n = 5000 n = 254 # SyntaxError: more than 255 arguments: import string, random names = list(set(''.join([random.choice(string.ascii_letters) @@ -134,6 +136,23 @@ class TestNamedTuple(unittest.TestCase): self.assertEqual(b2, tuple(b2_expected)) self.assertEqual(b._fields, tuple(names)) + def test_pickle(self): + p = TestNT(x=10, y=20, z=30) + for module in (pickle,): + loads = getattr(module, 'loads') + dumps = getattr(module, 'dumps') + for protocol in -1, 0, 1, 2: + q = loads(dumps(p, protocol)) + self.assertEqual(p, q) + self.assertEqual(p._fields, q._fields) + + def test_copy(self): + p = TestNT(x=10, y=20, z=30) + for copier in copy.copy, copy.deepcopy: + q = copier(p) + self.assertEqual(p, q) + self.assertEqual(p._fields, q._fields) + class TestOneTrickPonyABCs(unittest.TestCase): def test_Hashable(self): diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index f4c27bb..1eafeba 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -6,6 +6,7 @@ import unittest import math import os import sys +import random eps = 1E-05 NAN = float('nan') @@ -274,6 +275,20 @@ class MathTests(unittest.TestCase): self.ftest('fabs(0)', math.fabs(0), 0) self.ftest('fabs(1)', math.fabs(1), 1) + def testFactorial(self): + def fact(n): + result = 1 + for i in range(1, int(n)+1): + result *= i + return result + values = list(range(10)) + [50, 100, 500] + random.shuffle(values) + for x in range(10): + for cast in (int, float): + self.assertEqual(math.factorial(cast(x)), fact(x), (x, fact(x), math.factorial(x))) + self.assertRaises(ValueError, math.factorial, -1) + self.assertRaises(ValueError, math.factorial, math.pi) + def testFloor(self): self.assertRaises(TypeError, math.floor) self.assertEquals(int, type(math.floor(0.5))) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index d05df3f..ed2db18 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -79,6 +79,7 @@ class TestJointOps(unittest.TestCase): self.assertEqual(self.thetype('abcba').union(C('efgfe')), set('abcefg')) self.assertEqual(self.thetype('abcba').union(C('ccb')), set('abc')) self.assertEqual(self.thetype('abcba').union(C('ef')), set('abcef')) + self.assertEqual(self.thetype('abcba').union(C('ef'), C('fg')), set('abcefg')) def test_or(self): i = self.s.union(self.otherword) @@ -103,6 +104,7 @@ class TestJointOps(unittest.TestCase): self.assertEqual(self.thetype('abcba').intersection(C('efgfe')), set('')) self.assertEqual(self.thetype('abcba').intersection(C('ccb')), set('bc')) self.assertEqual(self.thetype('abcba').intersection(C('ef')), set('')) + self.assertEqual(self.thetype('abcba').intersection(C('cbcf'), C('bag')), set('b')) def test_isdisjoint(self): def f(s1, s2): @@ -410,6 +412,12 @@ class TestSet(TestJointOps): s = self.thetype('abcba') self.assertEqual(s.update(C(p)), None) self.assertEqual(s, set(q)) + for p in ('cdc', 'efgfe', 'ccb', 'ef', 'abcda'): + q = 'ahi' + for C in set, frozenset, dict.fromkeys, str, list, tuple: + s = self.thetype('abcba') + self.assertEqual(s.update(C(p), C(q)), None) + self.assertEqual(s, set(s) | set(p) | set(q)) def test_ior(self): self.s |= set(self.otherword) @@ -431,6 +439,11 @@ class TestSet(TestJointOps): s = self.thetype('abcba') self.assertEqual(s.intersection_update(C(p)), None) self.assertEqual(s, set(q)) + ss = 'abcba' + s = self.thetype(ss) + t = 'cbc' + self.assertEqual(s.intersection_update(C(p), C(t)), None) + self.assertEqual(s, set('abcba')&set(p)&set(t)) def test_iand(self): self.s &= set(self.otherword) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index e9570e9..39ed0ad 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -386,11 +386,14 @@ class SizeofTest(unittest.TestCase): self.file.close() test.support.unlink(test.support.TESTFN) - def check_sizeof(self, o, size): + def check_sizeof(self, o, size, size2=None): + """Check size of o. Possible are size and optionally size2).""" result = sys.getsizeof(o) - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(o), result, size) - self.assertEqual(result, size, msg) + msg = 'wrong size for %s: got %d, expected ' % (type(o), result) + if (size2 != None) and (result != size): + self.assertEqual(result, size2, msg + str(size2)) + else: + self.assertEqual(result, size, msg + str(size)) def align(self, value): mod = value % self.p @@ -486,6 +489,24 @@ class SizeofTest(unittest.TestCase): # list self.check_sizeof([], h + l + p + l) self.check_sizeof([1, 2, 3], h + l + p + l + 3*l) + # unicode + import math + usize = math.log(sys.maxunicode + 1, 2) / 8 + samples = ['', '1'*100] + # we need to test for both sizes, because we don't know if the string + # has been cached + for s in samples: + basicsize = h + l + p + l + l + p + usize * (len(s) + 1) + defenc = bytes(s, 'ascii') + self.check_sizeof(s, basicsize, + size2=basicsize + sys.getsizeof(defenc)) + # trigger caching encoded version as bytes object + try: + getattr(sys, s) + except AttributeError: + pass + finally: + self.check_sizeof(s, basicsize + sys.getsizeof(defenc)) h += l # long @@ -495,9 +516,6 @@ class SizeofTest(unittest.TestCase): self.check_sizeof(32768, h + self.align(2) + 2) self.check_sizeof(32768*32768-1, h + self.align(2) + 2) self.check_sizeof(32768*32768, h + self.align(2) + 4) - # XXX add Unicode support - # self.check_sizeof('', h + l + self.align(i + 1)) - # self.check_sizeof('abc', h + l + self.align(i + 1) + 3) def test_main(): diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py index 752406c..1c4af18 100644 --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -11,19 +11,25 @@ import os import mimetools -def _urlopen_with_retry(host, *args, **kwargs): - # Connecting to remote hosts is flaky. Make it more robust - # by retrying the connection several times. +def _retry_thrice(func, exc, *args, **kwargs): for i in range(3): try: - return urllib2.urlopen(host, *args, **kwargs) - except urllib2.URLError as e: + return func(*args, **kwargs) + except exc as e: last_exc = e continue except: raise raise last_exc +def _wrap_with_retry_thrice(func, exc): + def wrapped(*args, **kwargs): + return _retry_thrice(func, exc, *args, **kwargs) + return wrapped + +# Connecting to remote hosts is flaky. Make it more robust by retrying +# the connection several times. +_urlopen_with_retry = _wrap_with_retry_thrice(urllib2.urlopen, urllib2.URLError) class AuthTests(unittest.TestCase): @@ -114,7 +120,7 @@ class OtherNetworkTests(unittest.TestCase): 'file:'+sanepathname2url(os.path.abspath(TESTFN)), ('file:///nonsensename/etc/passwd', None, urllib2.URLError), ] - self._test_urls(urls, self._extra_handlers(), urllib2.urlopen) + self._test_urls(urls, self._extra_handlers(), retry=True) finally: os.remove(TESTFN) @@ -146,13 +152,15 @@ class OtherNetworkTests(unittest.TestCase): ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) - def _test_urls(self, urls, handlers, urlopen=_urlopen_with_retry): + def _test_urls(self, urls, handlers, retry=True): import socket import time import logging debug = logging.getLogger("test_urllib2").debug - urllib2.install_opener(urllib2.build_opener(*handlers)) + urlopen = urllib2.build_opener(*handlers).open + if retry: + urlopen = _wrap_with_retry_thrice(urlopen, urllib2.URLError) for url in urls: if isinstance(url, tuple): diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 16c829a..f759ada 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -568,6 +568,54 @@ Return an accurate floating point sum of values in the iterable.\n\ Assumes IEEE-754 floating point arithmetic."); static PyObject * +math_factorial(PyObject *self, PyObject *arg) +{ + long i, x; + PyObject *result, *iobj, *newresult; + + if (PyFloat_Check(arg)) { + double dx = PyFloat_AS_DOUBLE((PyFloatObject *)arg); + if (dx != floor(dx)) { + PyErr_SetString(PyExc_ValueError, + "factorial() only accepts integral values"); + return NULL; + } + } + + x = PyLong_AsLong(arg); + if (x == -1 && PyErr_Occurred()) + return NULL; + if (x < 0) { + PyErr_SetString(PyExc_ValueError, + "factorial() not defined for negative values"); + return NULL; + } + + result = (PyObject *)PyLong_FromLong(1); + if (result == NULL) + return NULL; + for (i=1 ; i<=x ; i++) { + iobj = (PyObject *)PyLong_FromLong(i); + if (iobj == NULL) + goto error; + newresult = PyNumber_Multiply(result, iobj); + Py_DECREF(iobj); + if (newresult == NULL) + goto error; + Py_DECREF(result); + result = newresult; + } + return result; + +error: + Py_DECREF(result); + Py_XDECREF(iobj); + return NULL; +} + +PyDoc_STRVAR(math_factorial_doc, "Return n!"); + +static PyObject * math_trunc(PyObject *self, PyObject *number) { static PyObject *trunc_str = NULL; @@ -1022,6 +1070,7 @@ static PyMethodDef math_methods[] = { {"degrees", math_degrees, METH_O, math_degrees_doc}, {"exp", math_exp, METH_O, math_exp_doc}, {"fabs", math_fabs, METH_O, math_fabs_doc}, + {"factorial", math_factorial, METH_O, math_factorial_doc}, {"floor", math_floor, METH_O, math_floor_doc}, {"fmod", math_fmod, METH_VARARGS, math_fmod_doc}, {"frexp", math_frexp, METH_O, math_frexp_doc}, diff --git a/Objects/setobject.c b/Objects/setobject.c index f760b6a..4456ef4 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -959,15 +959,20 @@ set_update_internal(PySetObject *so, PyObject *other) } static PyObject * -set_update(PySetObject *so, PyObject *other) +set_update(PySetObject *so, PyObject *args) { - if (set_update_internal(so, other) == -1) - return NULL; + Py_ssize_t i; + + for (i=0 ; i<PyTuple_GET_SIZE(args) ; i++) { + PyObject *other = PyTuple_GET_ITEM(args, i); + if (set_update_internal(so, other) == -1) + return NULL; + } Py_RETURN_NONE; } PyDoc_STRVAR(update_doc, -"Update a set with the union of itself and another."); +"Update a set with the union of itself and others."); static PyObject * make_new_set(PyTypeObject *type, PyObject *iterable) @@ -1148,35 +1153,53 @@ set_clear(PySetObject *so) PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); static PyObject * -set_union(PySetObject *so, PyObject *other) +set_union(PySetObject *so, PyObject *args) { PySetObject *result; + PyObject *other; + Py_ssize_t i; result = (PySetObject *)set_copy(so); if (result == NULL) return NULL; - if ((PyObject *)so == other) - return (PyObject *)result; - if (set_update_internal(result, other) == -1) { - Py_DECREF(result); - return NULL; + + for (i=0 ; i<PyTuple_GET_SIZE(args) ; i++) { + other = PyTuple_GET_ITEM(args, i); + if ((PyObject *)so == other) + return (PyObject *)result; + if (set_update_internal(result, other) == -1) { + Py_DECREF(result); + return NULL; + } } return (PyObject *)result; } PyDoc_STRVAR(union_doc, - "Return the union of two sets as a new set.\n\ + "Return the union of sets as a new set.\n\ \n\ (i.e. all elements that are in either set.)"); static PyObject * set_or(PySetObject *so, PyObject *other) { + PySetObject *result; + if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } - return set_union(so, other); + + result = (PySetObject *)set_copy(so); + if (result == NULL) + return NULL; + if ((PyObject *)so == other) + return (PyObject *)result; + if (set_update_internal(result, other) == -1) { + Py_DECREF(result); + return NULL; + } + return (PyObject *)result; } static PyObject * @@ -1275,6 +1298,26 @@ set_intersection(PySetObject *so, PyObject *other) return (PyObject *)result; } +static PyObject * +set_intersection_multi(PySetObject *so, PyObject *args) +{ + Py_ssize_t i; + PyObject *result = (PyObject *)so; + + Py_INCREF(so); + for (i=0 ; i<PyTuple_GET_SIZE(args) ; i++) { + PyObject *other = PyTuple_GET_ITEM(args, i); + PyObject *newresult = set_intersection((PySetObject *)result, other); + if (newresult == NULL) { + Py_DECREF(result); + return NULL; + } + Py_DECREF(result); + result = newresult; + } + return result; +} + PyDoc_STRVAR(intersection_doc, "Return the intersection of two sets as a new set.\n\ \n\ @@ -1293,6 +1336,19 @@ set_intersection_update(PySetObject *so, PyObject *other) Py_RETURN_NONE; } +static PyObject * +set_intersection_update_multi(PySetObject *so, PyObject *args) +{ + PyObject *tmp; + + tmp = set_intersection_multi(so, args); + if (tmp == NULL) + return NULL; + set_swap_bodies(so, (PySetObject *)tmp); + Py_DECREF(tmp); + Py_RETURN_NONE; +} + PyDoc_STRVAR(intersection_update_doc, "Update a set with the intersection of itself and another."); @@ -1911,9 +1967,9 @@ static PyMethodDef set_methods[] = { difference_doc}, {"difference_update", (PyCFunction)set_difference_update, METH_O, difference_update_doc}, - {"intersection",(PyCFunction)set_intersection, METH_O, + {"intersection",(PyCFunction)set_intersection_multi, METH_VARARGS, intersection_doc}, - {"intersection_update",(PyCFunction)set_intersection_update, METH_O, + {"intersection_update",(PyCFunction)set_intersection_update_multi, METH_VARARGS, intersection_update_doc}, {"isdisjoint", (PyCFunction)set_isdisjoint, METH_O, isdisjoint_doc}, @@ -1935,9 +1991,9 @@ static PyMethodDef set_methods[] = { {"test_c_api", (PyCFunction)test_c_api, METH_NOARGS, test_c_api_doc}, #endif - {"union", (PyCFunction)set_union, METH_O, + {"union", (PyCFunction)set_union, METH_VARARGS, union_doc}, - {"update", (PyCFunction)set_update, METH_O, + {"update", (PyCFunction)set_update, METH_VARARGS, update_doc}, {NULL, NULL} /* sentinel */ }; @@ -2036,7 +2092,7 @@ static PyMethodDef frozenset_methods[] = { copy_doc}, {"difference", (PyCFunction)set_difference, METH_O, difference_doc}, - {"intersection",(PyCFunction)set_intersection, METH_O, + {"intersection",(PyCFunction)set_intersection_multi, METH_VARARGS, intersection_doc}, {"isdisjoint", (PyCFunction)set_isdisjoint, METH_O, isdisjoint_doc}, @@ -2048,7 +2104,7 @@ static PyMethodDef frozenset_methods[] = { reduce_doc}, {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, symmetric_difference_doc}, - {"union", (PyCFunction)set_union, METH_O, + {"union", (PyCFunction)set_union, METH_VARARGS, union_doc}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 5cd9eb9..db907d6 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8301,6 +8301,28 @@ PyDoc_STRVAR(p_format__doc__, "); static PyObject * +unicode__sizeof__(PyUnicodeObject *v) +{ + PyObject *res = NULL, *defsize = NULL; + + res = PyLong_FromSsize_t(sizeof(PyUnicodeObject) + + sizeof(Py_UNICODE) * (v->length + 1)); + if (v->defenc) { + defsize = PyObject_CallMethod(v->defenc, "__sizeof__", NULL); + if (defsize == NULL) { + Py_DECREF(res); + return NULL; + } + res = PyNumber_Add(res, defsize); + Py_DECREF(defsize); + } + return res; +} + +PyDoc_STRVAR(sizeof__doc__, +"S.__sizeof__() -> size of S in memory, in bytes"); + +static PyObject * unicode_getnewargs(PyUnicodeObject *v) { return Py_BuildValue("(u#)", v->str, v->length); @@ -8357,6 +8379,7 @@ static PyMethodDef unicode_methods[] = { {"_formatter_parser", (PyCFunction) formatter_parser, METH_NOARGS}, {"maketrans", (PyCFunction) unicode_maketrans, METH_VARARGS | METH_STATIC, maketrans__doc__}, + {"__sizeof__", (PyCFunction) unicode__sizeof__, METH_NOARGS, sizeof__doc__}, #if 0 {"capwords", (PyCFunction) unicode_capwords, METH_NOARGS, capwords__doc__}, #endif |