[Python-checkins] cpython (merge default -> default): merge heads

benjamin.peterson python-checkins at python.org
Wed Dec 21 18:22:36 CET 2011


http://hg.python.org/cpython/rev/9c897817abde
changeset: 74120:9c897817abde
parent: 74119:56b70a81eee7
parent: 74116:f3041e7f535d
user: Benjamin Peterson <benjamin at python.org>
date: Wed Dec 21 11:22:02 2011 -0600
summary:
 merge heads
files:
 Doc/library/multiprocessing.rst | 18 ++
 Doc/library/ssl.rst | 10 +
 Doc/library/webbrowser.rst | 90 +++++++------
 Doc/using/cmdline.rst | 3 +-
 Doc/whatsnew/3.0.rst | 10 +-
 Lib/inspect.py | 79 ++++++----
 Lib/multiprocessing/managers.py | 3 +-
 Lib/multiprocessing/pool.py | 32 ++++-
 Lib/pydoc.py | 29 +++-
 Lib/ssl.py | 2 +-
 Lib/test/test_import.py | 3 +-
 Lib/test/test_inspect.py | 79 +++++++++++
 Lib/test/test_multiprocessing.py | 18 ++
 Lib/test/test_ssl.py | 128 ++++++------------
 Lib/webbrowser.py | 17 ++
 Misc/ACKS | 1 +
 Misc/NEWS | 8 +
 Modules/_ssl.c | 12 +
 18 files changed, 371 insertions(+), 171 deletions(-)
diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
--- a/Doc/library/multiprocessing.rst
+++ b/Doc/library/multiprocessing.rst
@@ -1669,6 +1669,24 @@
 returned iterator should be considered arbitrary. (Only when there is
 only one worker process is the order guaranteed to be "correct".)
 
+ .. method:: starmap(func, iterable[, chunksize])
+
+ Like :meth:`map` except that the elements of the `iterable` are expected
+ to be iterables that are unpacked as arguments.
+
+ Hence an `iterable` of `[(1,2), (3, 4)]` results in `[func(1,2),
+ func(3,4)]`.
+
+ .. versionadded:: 3.3
+
+ .. method:: starmap_async(func, iterable[, chunksize[, callback[, error_back]]])
+
+ A combination of :meth:`starmap` and :meth:`map_async` that iterates over
+ `iterable` of iterables and calls `func` with the iterables unpacked.
+ Returns a result object.
+
+ .. versionadded:: 3.3
+
 .. method:: close()
 
 Prevents any more tasks from being submitted to the pool. Once all the
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -445,6 +445,14 @@
 
 .. versionadded:: 3.3
 
+.. data:: HAS_ECDH
+
+ Whether the OpenSSL library has built-in support for Elliptic Curve-based
+ Diffie-Hellman key exchange. This should be true unless the feature was
+ explicitly disabled by the distributor.
+
+ .. versionadded:: 3.3
+
 .. data:: HAS_SNI
 
 Whether the OpenSSL library has built-in support for the *Server Name
@@ -711,6 +719,8 @@
 This setting doesn't apply to client sockets. You can also use the
 :data:`OP_SINGLE_ECDH_USE` option to further improve security.
 
+ This method is not available if :data:`HAS_ECDH` is False.
+
 .. versionadded:: 3.3
 
 .. seealso::
diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst
--- a/Doc/library/webbrowser.rst
+++ b/Doc/library/webbrowser.rst
@@ -96,47 +96,55 @@
 may be passed to the :func:`get` function and the corresponding instantiations
 for the controller classes, all defined in this module.
 
-+-----------------------+-----------------------------------------+-------+
-| Type Name | Class Name | Notes |
-+=======================+=========================================+=======+
-| ``'mozilla'`` | :class:`Mozilla('mozilla')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'firefox'`` | :class:`Mozilla('mozilla')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'netscape'`` | :class:`Mozilla('netscape')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'galeon'`` | :class:`Galeon('galeon')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'epiphany'`` | :class:`Galeon('epiphany')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'skipstone'`` | :class:`BackgroundBrowser('skipstone')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'kfmclient'`` | :class:`Konqueror()` | \(1) |
-+-----------------------+-----------------------------------------+-------+
-| ``'konqueror'`` | :class:`Konqueror()` | \(1) |
-+-----------------------+-----------------------------------------+-------+
-| ``'kfm'`` | :class:`Konqueror()` | \(1) |
-+-----------------------+-----------------------------------------+-------+
-| ``'mosaic'`` | :class:`BackgroundBrowser('mosaic')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'opera'`` | :class:`Opera()` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'grail'`` | :class:`Grail()` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'links'`` | :class:`GenericBrowser('links')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'elinks'`` | :class:`Elinks('elinks')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'lynx'`` | :class:`GenericBrowser('lynx')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'w3m'`` | :class:`GenericBrowser('w3m')` | |
-+-----------------------+-----------------------------------------+-------+
-| ``'windows-default'`` | :class:`WindowsDefault` | \(2) |
-+-----------------------+-----------------------------------------+-------+
-| ``'internet-config'`` | :class:`InternetConfig` | \(3) |
-+-----------------------+-----------------------------------------+-------+
-| ``'macosx'`` | :class:`MacOSX('default')` | \(4) |
-+-----------------------+-----------------------------------------+-------+
++------------------------+-----------------------------------------+-------+
+| Type Name | Class Name | Notes |
++========================+=========================================+=======+
+| ``'mozilla'`` | :class:`Mozilla('mozilla')` | |
++------------------------+-----------------------------------------+-------+
+| ``'firefox'`` | :class:`Mozilla('mozilla')` | |
++------------------------+-----------------------------------------+-------+
+| ``'netscape'`` | :class:`Mozilla('netscape')` | |
++------------------------+-----------------------------------------+-------+
+| ``'galeon'`` | :class:`Galeon('galeon')` | |
++------------------------+-----------------------------------------+-------+
+| ``'epiphany'`` | :class:`Galeon('epiphany')` | |
++------------------------+-----------------------------------------+-------+
+| ``'skipstone'`` | :class:`BackgroundBrowser('skipstone')` | |
++------------------------+-----------------------------------------+-------+
+| ``'kfmclient'`` | :class:`Konqueror()` | \(1) |
++------------------------+-----------------------------------------+-------+
+| ``'konqueror'`` | :class:`Konqueror()` | \(1) |
++------------------------+-----------------------------------------+-------+
+| ``'kfm'`` | :class:`Konqueror()` | \(1) |
++------------------------+-----------------------------------------+-------+
+| ``'mosaic'`` | :class:`BackgroundBrowser('mosaic')` | |
++------------------------+-----------------------------------------+-------+
+| ``'opera'`` | :class:`Opera()` | |
++------------------------+-----------------------------------------+-------+
+| ``'grail'`` | :class:`Grail()` | |
++------------------------+-----------------------------------------+-------+
+| ``'links'`` | :class:`GenericBrowser('links')` | |
++------------------------+-----------------------------------------+-------+
+| ``'elinks'`` | :class:`Elinks('elinks')` | |
++------------------------+-----------------------------------------+-------+
+| ``'lynx'`` | :class:`GenericBrowser('lynx')` | |
++------------------------+-----------------------------------------+-------+
+| ``'w3m'`` | :class:`GenericBrowser('w3m')` | |
++------------------------+-----------------------------------------+-------+
+| ``'windows-default'`` | :class:`WindowsDefault` | \(2) |
++------------------------+-----------------------------------------+-------+
+| ``'internet-config'`` | :class:`InternetConfig` | \(3) |
++------------------------+-----------------------------------------+-------+
+| ``'macosx'`` | :class:`MacOSX('default')` | \(4) |
++------------------------+-----------------------------------------+-------+
+| ``'google-chrome'`` | :class:`Chrome('google-chrome')` | |
++------------------------+-----------------------------------------+-------+
+| ``'chrome'`` | :class:`Chrome('chrome')` | |
++------------------------+-----------------------------------------+-------+
+| ``'chromium'`` | :class:`Chromium('chromium')` | |
++------------------------+-----------------------------------------+-------+
+| ``'chromium-browser'`` | :class:`Chromium('chromium-browser')` | |
++------------------------+-----------------------------------------+-------+
 
 Notes:
 
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -249,7 +249,8 @@
 
 Force the binary layer of the stdin, stdout and stderr streams (which is
 available as their ``buffer`` attribute) to be unbuffered. The text I/O
- layer will still be line-buffered.
+ layer will still be line-buffered if writing to the console, or
+ block-buffered if redirected to a non-interactive file.
 
 See also :envvar:`PYTHONUNBUFFERED`.
 
diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst
--- a/Doc/whatsnew/3.0.rst
+++ b/Doc/whatsnew/3.0.rst
@@ -301,6 +301,12 @@
 There is no longer any need for using the encoding-aware streams
 in the :mod:`codecs` module.
 
+* The initial values of :data:`sys.stdin`, :data:`sys.stdout` and
+ :data:`sys.stderr` are now unicode-only text files (i.e., they are
+ instances of :class:`io.TextIOBase`). To read and write bytes data
+ with these streams, you need to use their :data:`io.TextIOBase.buffer`
+ attribute.
+
 * Filenames are passed to and returned from APIs as (Unicode) strings.
 This can present platform-specific problems because on some
 platforms filenames are arbitrary byte strings. (On the other hand,
@@ -511,9 +517,7 @@
 produces a literal of type :class:`bytes`.
 
 * :ref:`pep-3116`. The :mod:`io` module is now the standard way of
- doing file I/O, and the initial values of :data:`sys.stdin`,
- :data:`sys.stdout` and :data:`sys.stderr` are now instances of
- :class:`io.TextIOBase`. The built-in :func:`open` function is now an
+ doing file I/O. The built-in :func:`open` function is now an
 alias for :func:`io.open` and has additional keyword arguments
 *encoding*, *errors*, *newline* and *closefd*. Also note that an
 invalid *mode* argument now raises :exc:`ValueError`, not
diff --git a/Lib/inspect.py b/Lib/inspect.py
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -99,11 +99,11 @@
 tests return false from the ismethoddescriptor() test, simply because
 the other tests promise more -- you can, e.g., count on having the
 __func__ attribute (etc) when an object passes ismethod()."""
- return (hasattr(object, "__get__")
- and not hasattr(object, "__set__") # else it's a data descriptor
- and not ismethod(object) # mutual exclusion
- and not isfunction(object)
- and not isclass(object))
+ if isclass(object) or ismethod(object) or isfunction(object):
+ # mutual exclusion
+ return False
+ tp = type(object)
+ return hasattr(tp, "__get__") and not hasattr(tp, "__set__")
 
 def isdatadescriptor(object):
 """Return true if the object is a data descriptor.
@@ -113,7 +113,11 @@
 Typically, data descriptors will also have __name__ and __doc__ attributes
 (properties, getsets, and members have both of these attributes), but this
 is not guaranteed."""
- return (hasattr(object, "__set__") and hasattr(object, "__get__"))
+ if isclass(object) or ismethod(object) or isfunction(object):
+ # mutual exclusion
+ return False
+ tp = type(object)
+ return hasattr(tp, "__set__") and hasattr(tp, "__get__")
 
 if hasattr(types, 'MemberDescriptorType'):
 # CPython and equivalent
@@ -253,12 +257,23 @@
 def getmembers(object, predicate=None):
 """Return all members of an object as (name, value) pairs sorted by name.
 Optionally, only return members that satisfy a given predicate."""
+ if isclass(object):
+ mro = (object,) + getmro(object)
+ else:
+ mro = ()
 results = []
 for key in dir(object):
- try:
- value = getattr(object, key)
- except AttributeError:
- continue
+ # First try to get the value via __dict__. Some descriptors don't
+ # like calling their __get__ (see bug #1785).
+ for base in mro:
+ if key in base.__dict__:
+ value = base.__dict__[key]
+ break
+ else:
+ try:
+ value = getattr(object, key)
+ except AttributeError:
+ continue
 if not predicate or predicate(value):
 results.append((key, value))
 results.sort()
@@ -294,30 +309,21 @@
 names = dir(cls)
 result = []
 for name in names:
- # Get the object associated with the name.
+ # Get the object associated with the name, and where it was defined.
 # Getting an obj from the __dict__ sometimes reveals more than
 # using getattr. Static and class methods are dramatic examples.
- if name in cls.__dict__:
- obj = cls.__dict__[name]
+ # Furthermore, some objects may raise an Exception when fetched with
+ # getattr(). This is the case with some descriptors (bug #1785).
+ # Thus, we only use getattr() as a last resort.
+ homecls = None
+ for base in (cls,) + mro:
+ if name in base.__dict__:
+ obj = base.__dict__[name]
+ homecls = base
+ break
 else:
 obj = getattr(cls, name)
-
- # Figure out where it was defined.
- homecls = getattr(obj, "__objclass__", None)
- if homecls is None:
- # search the dicts.
- for base in mro:
- if name in base.__dict__:
- homecls = base
- break
-
- # Get the object again, in order to get it from the defining
- # __dict__ instead of via getattr (if possible).
- if homecls is not None and name in homecls.__dict__:
- obj = homecls.__dict__[name]
-
- # Also get the object via getattr.
- obj_via_getattr = getattr(cls, name)
+ homecls = getattr(obj, "__objclass__", homecls)
 
 # Classify the object.
 if isinstance(obj, staticmethod):
@@ -326,11 +332,18 @@
 kind = "class method"
 elif isinstance(obj, property):
 kind = "property"
- elif (isfunction(obj_via_getattr) or
- ismethoddescriptor(obj_via_getattr)):
+ elif ismethoddescriptor(obj):
 kind = "method"
+ elif isdatadescriptor(obj):
+ kind = "data"
 else:
- kind = "data"
+ obj_via_getattr = getattr(cls, name)
+ if (isfunction(obj_via_getattr) or
+ ismethoddescriptor(obj_via_getattr)):
+ kind = "method"
+ else:
+ kind = "data"
+ obj = obj_via_getattr
 
 result.append(Attribute(name, kind, homecls, obj))
 
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -1066,11 +1066,12 @@
 
 PoolProxy = MakeProxyType('PoolProxy', (
 'apply', 'apply_async', 'close', 'imap', 'imap_unordered', 'join',
- 'map', 'map_async', 'terminate'
+ 'map', 'map_async', 'starmap', 'starmap_async', 'terminate'
 ))
 PoolProxy._method_to_typeid_ = {
 'apply_async': 'AsyncResult',
 'map_async': 'AsyncResult',
+ 'starmap_async': 'AsyncResult',
 'imap': 'Iterator',
 'imap_unordered': 'Iterator'
 }
diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py
--- a/Lib/multiprocessing/pool.py
+++ b/Lib/multiprocessing/pool.py
@@ -64,6 +64,9 @@
 def mapstar(args):
 return list(map(*args))
 
+def starmapstar(args):
+ return list(itertools.starmap(args[0], args[1]))
+
 #
 # Code run by worker processes
 #
@@ -248,7 +251,25 @@
 in a list that is returned.
 '''
 assert self._state == RUN
- return self.map_async(func, iterable, chunksize).get()
+ return self._map_async(func, iterable, mapstar, chunksize).get()
+
+ def starmap(self, func, iterable, chunksize=None):
+ '''
+ Like `map()` method but the elements of the `iterable` are expected to
+ be iterables as well and will be unpacked as arguments. Hence
+ `func` and (a, b) becomes func(a, b).
+ '''
+ assert self._state == RUN
+ return self._map_async(func, iterable, starmapstar, chunksize).get()
+
+ def starmap_async(self, func, iterable, chunksize=None, callback=None,
+ error_callback=None):
+ '''
+ Asynchronous version of `starmap()` method.
+ '''
+ assert self._state == RUN
+ return self._map_async(func, iterable, starmapstar, chunksize,
+ callback, error_callback)
 
 def imap(self, func, iterable, chunksize=1):
 '''
@@ -302,6 +323,13 @@
 Asynchronous version of `map()` method.
 '''
 assert self._state == RUN
+ return self._map_async(func, iterable, mapstar, chunksize)
+
+ def _map_async(self, func, iterable, mapper, chunksize=None, callback=None,
+ error_callback=None):
+ '''
+ Helper function to implement map, starmap and their async counterparts.
+ '''
 if not hasattr(iterable, '__len__'):
 iterable = list(iterable)
 
@@ -315,7 +343,7 @@
 task_batches = Pool._get_tasks(func, iterable, chunksize)
 result = MapResult(self._cache, chunksize, len(iterable), callback,
 error_callback=error_callback)
- self._taskqueue.put((((result._job, i, mapstar, (x,), {})
+ self._taskqueue.put((((result._job, i, mapper, (x,), {})
 for i, x in enumerate(task_batches)), None))
 return result
 
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -748,8 +748,15 @@
 hr.maybe()
 push(msg)
 for name, kind, homecls, value in ok:
- push(self.document(getattr(object, name), name, mod,
- funcs, classes, mdict, object))
+ try:
+ value = getattr(object, name)
+ except Exception:
+ # Some descriptors may meet a failure in their __get__.
+ # (bug #1785)
+ push(self._docdescriptor(name, value, mod))
+ else:
+ push(self.document(value, name, mod,
+ funcs, classes, mdict, object))
 push('\n')
 return attrs
 
@@ -790,7 +797,12 @@
 mdict = {}
 for key, kind, homecls, value in attrs:
 mdict[key] = anchor = '#' + name + '-' + key
- value = getattr(object, key)
+ try:
+ value = getattr(object, name)
+ except Exception:
+ # Some descriptors may meet a failure in their __get__.
+ # (bug #1785)
+ pass
 try:
 # The value may not be hashable (e.g., a data attr with
 # a dict or list value).
@@ -1177,8 +1189,15 @@
 hr.maybe()
 push(msg)
 for name, kind, homecls, value in ok:
- push(self.document(getattr(object, name),
- name, mod, object))
+ try:
+ value = getattr(object, name)
+ except Exception:
+ # Some descriptors may meet a failure in their __get__.
+ # (bug #1785)
+ push(self._docdescriptor(name, value, mod))
+ else:
+ push(self.document(value,
+ name, mod, object))
 return attrs
 
 def spilldescriptors(msg, attrs, predicate):
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -86,7 +86,7 @@
 SSL_ERROR_EOF,
 SSL_ERROR_INVALID_ERROR_CODE,
 )
-from _ssl import HAS_SNI
+from _ssl import HAS_SNI, HAS_ECDH
 from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23,
 PROTOCOL_TLSv1)
 from _ssl import _OPENSSL_API_VERSION
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -104,8 +104,9 @@
 try:
 fname = TESTFN + os.extsep + "py"
 create_empty_file(fname)
+ fn = imp.cache_from_source(fname)
+ unlink(fn)
 __import__(TESTFN)
- fn = imp.cache_from_source(fname)
 if not os.path.exists(fn):
 self.fail("__import__ did not result in creation of "
 "either a .pyc or .pyo file")
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -425,10 +425,37 @@
 def test_class(self):
 self.assertSourceEqual(self.fodderModule.X, 1, 2)
 
+
+class _BrokenDataDescriptor(object):
+ """
+ A broken data descriptor. See bug #1785.
+ """
+ def __get__(*args):
+ raise AssertionError("should not __get__ data descriptors")
+
+ def __set__(*args):
+ raise RuntimeError
+
+ def __getattr__(*args):
+ raise AssertionError("should not __getattr__ data descriptors")
+
+
+class _BrokenMethodDescriptor(object):
+ """
+ A broken method descriptor. See bug #1785.
+ """
+ def __get__(*args):
+ raise AssertionError("should not __get__ method descriptors")
+
+ def __getattr__(*args):
+ raise AssertionError("should not __getattr__ method descriptors")
+
+
 # Helper for testing classify_class_attrs.
 def attrs_wo_objs(cls):
 return [t[:3] for t in inspect.classify_class_attrs(cls)]
 
+
 class TestClassesAndFunctions(unittest.TestCase):
 def test_newstyle_mro(self):
 # The same w/ new-class MRO.
@@ -525,6 +552,9 @@
 
 datablob = '1'
 
+ dd = _BrokenDataDescriptor()
+ md = _BrokenMethodDescriptor()
+
 attrs = attrs_wo_objs(A)
 self.assertIn(('s', 'static method', A), attrs, 'missing static method')
 self.assertIn(('c', 'class method', A), attrs, 'missing class method')
@@ -533,6 +563,8 @@
 'missing plain method: %r' % attrs)
 self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
+ self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
+ self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
 
 class B(A):
 
@@ -545,6 +577,8 @@
 self.assertIn(('m', 'method', B), attrs, 'missing plain method')
 self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
+ self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
+ self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
 
 
 class C(A):
@@ -559,6 +593,8 @@
 self.assertIn(('m', 'method', C), attrs, 'missing plain method')
 self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
+ self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
+ self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
 
 class D(B, C):
 
@@ -571,6 +607,49 @@
 self.assertIn(('m', 'method', B), attrs, 'missing plain method')
 self.assertIn(('m1', 'method', D), attrs, 'missing plain method')
 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
+ self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
+ self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
+
+ def test_classify_builtin_types(self):
+ # Simple sanity check that all built-in types can have their
+ # attributes classified.
+ for name in dir(__builtins__):
+ builtin = getattr(__builtins__, name)
+ if isinstance(builtin, type):
+ inspect.classify_class_attrs(builtin)
+
+ def test_getmembers_descriptors(self):
+ class A(object):
+ dd = _BrokenDataDescriptor()
+ md = _BrokenMethodDescriptor()
+
+ def pred_wrapper(pred):
+ # A quick'n'dirty way to discard standard attributes of new-style
+ # classes.
+ class Empty(object):
+ pass
+ def wrapped(x):
+ if '__name__' in dir(x) and hasattr(Empty, x.__name__):
+ return False
+ return pred(x)
+ return wrapped
+
+ ismethoddescriptor = pred_wrapper(inspect.ismethoddescriptor)
+ isdatadescriptor = pred_wrapper(inspect.isdatadescriptor)
+
+ self.assertEqual(inspect.getmembers(A, ismethoddescriptor),
+ [('md', A.__dict__['md'])])
+ self.assertEqual(inspect.getmembers(A, isdatadescriptor),
+ [('dd', A.__dict__['dd'])])
+
+ class B(A):
+ pass
+
+ self.assertEqual(inspect.getmembers(B, ismethoddescriptor),
+ [('md', A.__dict__['md'])])
+ self.assertEqual(inspect.getmembers(B, isdatadescriptor),
+ [('dd', A.__dict__['dd'])])
+
 
 class TestGetcallargsFunctions(unittest.TestCase):
 
diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py
--- a/Lib/test/test_multiprocessing.py
+++ b/Lib/test/test_multiprocessing.py
@@ -8,6 +8,7 @@
 import queue as pyqueue
 import time
 import io
+import itertools
 import sys
 import os
 import gc
@@ -1125,6 +1126,9 @@
 time.sleep(wait)
 return x*x
 
+def mul(x, y):
+ return x*y
+
 class _TestPool(BaseTestCase):
 
 def test_apply(self):
@@ -1138,6 +1142,20 @@
 self.assertEqual(pmap(sqr, list(range(100)), chunksize=20),
 list(map(sqr, list(range(100)))))
 
+ def test_starmap(self):
+ psmap = self.pool.starmap
+ tuples = list(zip(range(10), range(9,-1, -1)))
+ self.assertEqual(psmap(mul, tuples),
+ list(itertools.starmap(mul, tuples)))
+ tuples = list(zip(range(100), range(99,-1, -1)))
+ self.assertEqual(psmap(mul, tuples, chunksize=20),
+ list(itertools.starmap(mul, tuples)))
+
+ def test_starmap_async(self):
+ tuples = list(zip(range(100), range(99,-1, -1)))
+ self.assertEqual(self.pool.starmap_async(mul, tuples).get(),
+ list(itertools.starmap(mul, tuples)))
+
 def test_map_chunksize(self):
 try:
 self.pool.map_async(sqr, [], chunksize=1).get(timeout=TIMEOUT1)
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -103,6 +103,7 @@
 if ssl.OPENSSL_VERSION_INFO >= (1, 0):
 ssl.OP_NO_COMPRESSION
 self.assertIn(ssl.HAS_SNI, {True, False})
+ self.assertIn(ssl.HAS_ECDH, {True, False})
 
 def test_random(self):
 v = ssl.RAND_status()
@@ -561,6 +562,7 @@
 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
 ctx.set_default_verify_paths()
 
+ @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
 def test_set_ecdh_curve(self):
 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
 ctx.set_ecdh_curve("prime256v1")
@@ -984,6 +986,14 @@
 threading.Thread.__init__(self)
 self.daemon = True
 
+ def __enter__(self):
+ self.start(threading.Event())
+ self.flag.wait()
+
+ def __exit__(self, *args):
+ self.stop()
+ self.join()
+
 def start(self, flag=None):
 self.flag = flag
 threading.Thread.start(self)
@@ -1095,6 +1105,20 @@
 def __str__(self):
 return "<%s %s>" % (self.__class__.__name__, self.server)
 
+ def __enter__(self):
+ self.start(threading.Event())
+ self.flag.wait()
+
+ def __exit__(self, *args):
+ if support.verbose:
+ sys.stdout.write(" cleanup: stopping server.\n")
+ self.stop()
+ if support.verbose:
+ sys.stdout.write(" cleanup: joining server thread.\n")
+ self.join()
+ if support.verbose:
+ sys.stdout.write(" cleanup: successfully joined.\n")
+
 def start (self, flag=None):
 self.flag = flag
 threading.Thread.start(self)
@@ -1122,12 +1146,7 @@
 certreqs=ssl.CERT_REQUIRED,
 cacerts=CERTFILE, chatty=False,
 connectionchatty=False)
- flag = threading.Event()
- server.start(flag)
- # wait for it to start
- flag.wait()
- # try to connect
- try:
+ with server:
 try:
 with socket.socket() as sock:
 s = ssl.wrap_socket(sock,
@@ -1147,9 +1166,6 @@
 sys.stdout.write("\IOError is %s\n" % str(x))
 else:
 raise AssertionError("Use of invalid cert should have failed!")
- finally:
- server.stop()
- server.join()
 
 def server_params_test(client_context, server_context, indata=b"FOO\n",
 chatty=True, connectionchatty=False):
@@ -1160,12 +1176,7 @@
 server = ThreadedEchoServer(context=server_context,
 chatty=chatty,
 connectionchatty=False)
- flag = threading.Event()
- server.start(flag)
- # wait for it to start
- flag.wait()
- # try to connect
- try:
+ with server:
 s = client_context.wrap_socket(socket.socket())
 s.connect((HOST, server.port))
 for arg in [indata, bytearray(indata), memoryview(indata)]:
@@ -1193,9 +1204,6 @@
 }
 s.close()
 return stats
- finally:
- server.stop()
- server.join()
 
 def try_protocol_combo(server_protocol, client_protocol, expect_success,
 certsreqs=None, server_options=0, client_options=0):
@@ -1264,12 +1272,7 @@
 context.load_verify_locations(CERTFILE)
 context.load_cert_chain(CERTFILE)
 server = ThreadedEchoServer(context=context, chatty=False)
- flag = threading.Event()
- server.start(flag)
- # wait for it to start
- flag.wait()
- # try to connect
- try:
+ with server:
 s = context.wrap_socket(socket.socket())
 s.connect((HOST, server.port))
 cert = s.getpeercert()
@@ -1292,9 +1295,6 @@
 after = ssl.cert_time_to_seconds(cert['notAfter'])
 self.assertLess(before, after)
 s.close()
- finally:
- server.stop()
- server.join()
 
 def test_empty_cert(self):
 """Connecting with an empty cert file"""
@@ -1454,13 +1454,8 @@
 starttls_server=True,
 chatty=True,
 connectionchatty=True)
- flag = threading.Event()
- server.start(flag)
- # wait for it to start
- flag.wait()
- # try to connect
 wrapped = False
- try:
+ with server:
 s = socket.socket()
 s.setblocking(1)
 s.connect((HOST, server.port))
@@ -1507,9 +1502,6 @@
 conn.close()
 else:
 s.close()
- finally:
- server.stop()
- server.join()
 
 def test_socketserver(self):
 """Using a SocketServer to create and manage SSL connections."""
@@ -1545,12 +1537,7 @@
 
 indata = b"FOO\n"
 server = AsyncoreEchoServer(CERTFILE)
- flag = threading.Event()
- server.start(flag)
- # wait for it to start
- flag.wait()
- # try to connect
- try:
+ with server:
 s = ssl.wrap_socket(socket.socket())
 s.connect(('127.0.0.1', server.port))
 if support.verbose:
@@ -1571,15 +1558,6 @@
 s.close()
 if support.verbose:
 sys.stdout.write(" client: connection closed.\n")
- finally:
- if support.verbose:
- sys.stdout.write(" cleanup: stopping server.\n")
- server.stop()
- if support.verbose:
- sys.stdout.write(" cleanup: joining server thread.\n")
- server.join()
- if support.verbose:
- sys.stdout.write(" cleanup: successfully joined.\n")
 
 def test_recv_send(self):
 """Test recv(), send() and friends."""
@@ -1592,19 +1570,14 @@
 cacerts=CERTFILE,
 chatty=True,
 connectionchatty=False)
- flag = threading.Event()
- server.start(flag)
- # wait for it to start
- flag.wait()
- # try to connect
- s = ssl.wrap_socket(socket.socket(),
- server_side=False,
- certfile=CERTFILE,
- ca_certs=CERTFILE,
- cert_reqs=ssl.CERT_NONE,
- ssl_version=ssl.PROTOCOL_TLSv1)
- s.connect((HOST, server.port))
- try:
+ with server:
+ s = ssl.wrap_socket(socket.socket(),
+ server_side=False,
+ certfile=CERTFILE,
+ ca_certs=CERTFILE,
+ cert_reqs=ssl.CERT_NONE,
+ ssl_version=ssl.PROTOCOL_TLSv1)
+ s.connect((HOST, server.port))
 # helper methods for standardising recv* method signatures
 def _recv_into():
 b = bytearray(b"0円"*100)
@@ -1700,9 +1673,6 @@
 
 s.write(b"over\n")
 s.close()
- finally:
- server.stop()
- server.join()
 
 def test_handshake_timeout(self):
 # Issue #5103: SSL handshake must respect the socket timeout
@@ -1766,19 +1736,14 @@
 cacerts=CERTFILE,
 chatty=True,
 connectionchatty=False)
- flag = threading.Event()
- server.start(flag)
- # wait for it to start
- flag.wait()
- # try to connect
- s = ssl.wrap_socket(socket.socket(),
- server_side=False,
- certfile=CERTFILE,
- ca_certs=CERTFILE,
- cert_reqs=ssl.CERT_NONE,
- ssl_version=ssl.PROTOCOL_TLSv1)
- s.connect((HOST, server.port))
- try:
+ with server:
+ s = ssl.wrap_socket(socket.socket(),
+ server_side=False,
+ certfile=CERTFILE,
+ ca_certs=CERTFILE,
+ cert_reqs=ssl.CERT_NONE,
+ ssl_version=ssl.PROTOCOL_TLSv1)
+ s.connect((HOST, server.port))
 # get the data
 cb_data = s.get_channel_binding("tls-unique")
 if support.verbose:
@@ -1817,9 +1782,6 @@
 self.assertEqual(peer_data_repr,
 repr(new_cb_data).encode("us-ascii"))
 s.close()
- finally:
- server.stop()
- server.join()
 
 def test_compression(self):
 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
--- a/Lib/webbrowser.py
+++ b/Lib/webbrowser.py
@@ -299,6 +299,18 @@
 background = True
 
 
+class Chrome(UnixBrowser):
+ "Launcher class for Google Chrome browser."
+
+ remote_args = ['%action', '%s']
+ remote_action = ""
+ remote_action_newwin = "--new-window"
+ remote_action_newtab = ""
+ background = True
+
+Chromium = Chrome
+
+
 class Opera(UnixBrowser):
 "Launcher class for Opera browser."
 
@@ -466,6 +478,11 @@
 if _iscommand("skipstone"):
 register("skipstone", None, BackgroundBrowser("skipstone"))
 
+ # Google Chrome/Chromium browsers
+ for browser in ("google-chrome", "chrome", "chromium", "chromium-browser"):
+ if _iscommand(browser):
+ register(browser, None, Chrome(browser))
+
 # Opera, quite popular
 if _iscommand("opera"):
 register("opera", None, Opera("opera"))
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -878,6 +878,7 @@
 Andreas Schawo
 Neil Schemenauer
 David Scherer
+Hynek Schlawack
 Bob Schmertz
 Gregor Schmid
 Ralf Schmitt
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -419,6 +419,14 @@
 Library
 -------
 
+- Issue #13620: Support for Chrome browser in webbrowser.py Patch contributed
+ by Arnaud Calmettes.
+
+- Issue #12708: Add starmap() and starmap_async() methods (similar to
+ itertools.starmap()) to multiprocessing.Pool. Patch by Hynek Schlawack.
+
+- Issue #1785: Fix inspect and pydoc with misbehaving descriptors.
+
 - Issue #13637: "a2b" functions in the binascii module now accept ASCII-only
 unicode strings.
 
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2006,6 +2006,7 @@
 Py_RETURN_NONE;
 }
 
+#ifndef OPENSSL_NO_ECDH
 static PyObject *
 set_ecdh_curve(PySSLContext *self, PyObject *name)
 {
@@ -2032,6 +2033,7 @@
 EC_KEY_free(key);
 Py_RETURN_NONE;
 }
+#endif
 
 static PyGetSetDef context_getsetlist[] = {
 {"options", (getter) get_options,
@@ -2054,8 +2056,10 @@
 METH_NOARGS, NULL},
 {"set_default_verify_paths", (PyCFunction) set_default_verify_paths,
 METH_NOARGS, NULL},
+#ifndef OPENSSL_NO_ECDH
 {"set_ecdh_curve", (PyCFunction) set_ecdh_curve,
 METH_O, NULL},
+#endif
 {NULL, NULL} /* sentinel */
 };
 
@@ -2523,6 +2527,14 @@
 Py_INCREF(r);
 PyModule_AddObject(m, "HAS_TLS_UNIQUE", r);
 
+#ifdef OPENSSL_NO_ECDH
+ r = Py_False;
+#else
+ r = Py_True;
+#endif
+ Py_INCREF(r);
+ PyModule_AddObject(m, "HAS_ECDH", r);
+
 /* OpenSSL version */
 /* SSLeay() gives us the version of the library linked against,
 which could be different from the headers version.
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /