From: Georg Brandl <georg@python.org>
Date: Tue, 10 Jun 2008 19:20:26 +0000 (+0000)
Subject: Merged revisions 64002-64003,64012,64036-64037,64047,64050-64052,64054-64055,64066... 
X-Git-Tag: v3.0b1~118
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c28e1fa71f61278256887d257e4e7e24b0e7e7ce;p=python

Merged revisions 64002-64003,64012,64036-64037,64047,64050-64052,64054-64055,64066,64071 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r64002 | travis.oliphant | 2008-06-07 00:33:21 +0200 (Sat, 07 Jun 2008) | 1 line

  Add long double check support to configure test.
........
  r64003 | travis.oliphant | 2008-06-07 00:39:47 +0200 (Sat, 07 Jun 2008) | 1 line

  Remove locking part of new buffer protocol.
........
  r64012 | facundo.batista | 2008-06-07 15:36:36 +0200 (Sat, 07 Jun 2008) | 4 lines


  Finished bug #2451.  Fixed the retrying part to make it
  more robust.
........
  r64036 | georg.brandl | 2008-06-08 10:54:40 +0200 (Sun, 08 Jun 2008) | 2 lines

  #3028: tokenize passes the physical line.
........
  r64037 | georg.brandl | 2008-06-08 10:59:38 +0200 (Sun, 08 Jun 2008) | 2 lines

  Argh, I read it wrong. Reverted 64036 and added a clarifying remark.
........
  r64047 | raymond.hettinger | 2008-06-09 03:28:30 +0200 (Mon, 09 Jun 2008) | 1 line

  Issue3065:  Fixed pickling of named tuples.  Added tests.
........
  r64050 | raymond.hettinger | 2008-06-09 08:54:45 +0200 (Mon, 09 Jun 2008) | 1 line

  Issue #2138: Add math.factorial().
........
  r64051 | raymond.hettinger | 2008-06-09 10:33:37 +0200 (Mon, 09 Jun 2008) | 1 line

  Let set.union() and set.update() accept multiple inputs.
........
  r64052 | raymond.hettinger | 2008-06-09 11:29:17 +0200 (Mon, 09 Jun 2008) | 1 line

  Address double-rounding scenarios by setting all variables to long doubles.
........
  r64054 | raymond.hettinger | 2008-06-09 13:24:47 +0200 (Mon, 09 Jun 2008) | 1 line

  Unhappy buildbots.  Revert 64052.  Long doubles have unexpected effects on some builds.
........
  r64055 | raymond.hettinger | 2008-06-09 15:07:27 +0200 (Mon, 09 Jun 2008) | 1 line

  Let set.intersection() and set.intersection_update() take multiple input arguments.
........
  r64066 | robert.schuppenies | 2008-06-10 12:10:31 +0200 (Tue, 10 Jun 2008) | 2 lines

  Issue 3048: Fixed sys.getsizeof for unicode objects.
........
  r64071 | thomas.heller | 2008-06-10 16:07:12 +0200 (Tue, 10 Jun 2008) | 3 lines

  NEWS entry for:
  Add an optional 'offset' parameter to byref, defaulting to zero.
........
---

diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index 5035ac907a..3203ca584a 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 0868e8eb10..aba6b0e529 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 09549ada39..27c3fb4160 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 bbe73d00e9..b2caded0a7 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 73fc150e9a..6d439e5269 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 4ed0e24165..9289afe072 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 f4c27bb389..1eafebad22 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 d05df3f24d..ed2db18e5a 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 e9570e9026..39ed0ad8af 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 752406c446..1c4af18d97 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 16c829ac25..f759adab5b 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -567,6 +567,54 @@ PyDoc_STRVAR(math_sum_doc,
 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)
 {
@@ -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 f760b6a94b..4456ef49d5 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 5cd9eb9f48..db907d6a0e 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -8300,6 +8300,28 @@ PyDoc_STRVAR(p_format__doc__,
 \n\
 ");
 
+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)
 {
@@ -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