merge heads

This commit is contained in:
Benjamin Peterson 2011-12-21 11:22:02 -06:00
commit 059226b8ec
18 changed files with 371 additions and 171 deletions

View File

@ -1669,6 +1669,24 @@ with the :class:`Pool` class.
returned iterator should be considered arbitrary. (Only when there is returned iterator should be considered arbitrary. (Only when there is
only one worker process is the order guaranteed to be "correct".) 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() .. method:: close()
Prevents any more tasks from being submitted to the pool. Once all the Prevents any more tasks from being submitted to the pool. Once all the

View File

@ -445,6 +445,14 @@ Constants
.. versionadded:: 3.3 .. 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 .. data:: HAS_SNI
Whether the OpenSSL library has built-in support for the *Server Name Whether the OpenSSL library has built-in support for the *Server Name
@ -711,6 +719,8 @@ to speed up repeated connections from the same clients.
This setting doesn't apply to client sockets. You can also use the This setting doesn't apply to client sockets. You can also use the
:data:`OP_SINGLE_ECDH_USE` option to further improve security. :data:`OP_SINGLE_ECDH_USE` option to further improve security.
This method is not available if :data:`HAS_ECDH` is False.
.. versionadded:: 3.3 .. versionadded:: 3.3
.. seealso:: .. seealso::

View File

@ -96,47 +96,55 @@ A number of browser types are predefined. This table gives the type names that
may be passed to the :func:`get` function and the corresponding instantiations may be passed to the :func:`get` function and the corresponding instantiations
for the controller classes, all defined in this module. for the controller classes, all defined in this module.
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| Type Name | Class Name | Notes | | Type Name | Class Name | Notes |
+=======================+=========================================+=======+ +========================+=========================================+=======+
| ``'mozilla'`` | :class:`Mozilla('mozilla')` | | | ``'mozilla'`` | :class:`Mozilla('mozilla')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'firefox'`` | :class:`Mozilla('mozilla')` | | | ``'firefox'`` | :class:`Mozilla('mozilla')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'netscape'`` | :class:`Mozilla('netscape')` | | | ``'netscape'`` | :class:`Mozilla('netscape')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'galeon'`` | :class:`Galeon('galeon')` | | | ``'galeon'`` | :class:`Galeon('galeon')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'epiphany'`` | :class:`Galeon('epiphany')` | | | ``'epiphany'`` | :class:`Galeon('epiphany')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'skipstone'`` | :class:`BackgroundBrowser('skipstone')` | | | ``'skipstone'`` | :class:`BackgroundBrowser('skipstone')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'kfmclient'`` | :class:`Konqueror()` | \(1) | | ``'kfmclient'`` | :class:`Konqueror()` | \(1) |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'konqueror'`` | :class:`Konqueror()` | \(1) | | ``'konqueror'`` | :class:`Konqueror()` | \(1) |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'kfm'`` | :class:`Konqueror()` | \(1) | | ``'kfm'`` | :class:`Konqueror()` | \(1) |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'mosaic'`` | :class:`BackgroundBrowser('mosaic')` | | | ``'mosaic'`` | :class:`BackgroundBrowser('mosaic')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'opera'`` | :class:`Opera()` | | | ``'opera'`` | :class:`Opera()` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'grail'`` | :class:`Grail()` | | | ``'grail'`` | :class:`Grail()` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'links'`` | :class:`GenericBrowser('links')` | | | ``'links'`` | :class:`GenericBrowser('links')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'elinks'`` | :class:`Elinks('elinks')` | | | ``'elinks'`` | :class:`Elinks('elinks')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'lynx'`` | :class:`GenericBrowser('lynx')` | | | ``'lynx'`` | :class:`GenericBrowser('lynx')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'w3m'`` | :class:`GenericBrowser('w3m')` | | | ``'w3m'`` | :class:`GenericBrowser('w3m')` | |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'windows-default'`` | :class:`WindowsDefault` | \(2) | | ``'windows-default'`` | :class:`WindowsDefault` | \(2) |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'internet-config'`` | :class:`InternetConfig` | \(3) | | ``'internet-config'`` | :class:`InternetConfig` | \(3) |
+-----------------------+-----------------------------------------+-------+ +------------------------+-----------------------------------------+-------+
| ``'macosx'`` | :class:`MacOSX('default')` | \(4) | | ``'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: Notes:

View File

@ -249,7 +249,8 @@ Miscellaneous options
Force the binary layer of the stdin, stdout and stderr streams (which is 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 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`. See also :envvar:`PYTHONUNBUFFERED`.

View File

@ -301,6 +301,12 @@ changed.
There is no longer any need for using the encoding-aware streams There is no longer any need for using the encoding-aware streams
in the :mod:`codecs` module. 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. * Filenames are passed to and returned from APIs as (Unicode) strings.
This can present platform-specific problems because on some This can present platform-specific problems because on some
platforms filenames are arbitrary byte strings. (On the other hand, platforms filenames are arbitrary byte strings. (On the other hand,
@ -511,9 +517,7 @@ consulted for longer descriptions.
produces a literal of type :class:`bytes`. produces a literal of type :class:`bytes`.
* :ref:`pep-3116`. The :mod:`io` module is now the standard way of * :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`, doing file I/O. The built-in :func:`open` function is now an
:data:`sys.stdout` and :data:`sys.stderr` are now instances of
:class:`io.TextIOBase`. The built-in :func:`open` function is now an
alias for :func:`io.open` and has additional keyword arguments alias for :func:`io.open` and has additional keyword arguments
*encoding*, *errors*, *newline* and *closefd*. Also note that an *encoding*, *errors*, *newline* and *closefd*. Also note that an
invalid *mode* argument now raises :exc:`ValueError`, not invalid *mode* argument now raises :exc:`ValueError`, not

View File

@ -99,11 +99,11 @@ def ismethoddescriptor(object):
tests return false from the ismethoddescriptor() test, simply because tests return false from the ismethoddescriptor() test, simply because
the other tests promise more -- you can, e.g., count on having the the other tests promise more -- you can, e.g., count on having the
__func__ attribute (etc) when an object passes ismethod().""" __func__ attribute (etc) when an object passes ismethod()."""
return (hasattr(object, "__get__") if isclass(object) or ismethod(object) or isfunction(object):
and not hasattr(object, "__set__") # else it's a data descriptor # mutual exclusion
and not ismethod(object) # mutual exclusion return False
and not isfunction(object) tp = type(object)
and not isclass(object)) return hasattr(tp, "__get__") and not hasattr(tp, "__set__")
def isdatadescriptor(object): def isdatadescriptor(object):
"""Return true if the object is a data descriptor. """Return true if the object is a data descriptor.
@ -113,7 +113,11 @@ def isdatadescriptor(object):
Typically, data descriptors will also have __name__ and __doc__ attributes Typically, data descriptors will also have __name__ and __doc__ attributes
(properties, getsets, and members have both of these attributes), but this (properties, getsets, and members have both of these attributes), but this
is not guaranteed.""" 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'): if hasattr(types, 'MemberDescriptorType'):
# CPython and equivalent # CPython and equivalent
@ -253,12 +257,23 @@ def isabstract(object):
def getmembers(object, predicate=None): def getmembers(object, predicate=None):
"""Return all members of an object as (name, value) pairs sorted by name. """Return all members of an object as (name, value) pairs sorted by name.
Optionally, only return members that satisfy a given predicate.""" Optionally, only return members that satisfy a given predicate."""
if isclass(object):
mro = (object,) + getmro(object)
else:
mro = ()
results = [] results = []
for key in dir(object): for key in dir(object):
try: # First try to get the value via __dict__. Some descriptors don't
value = getattr(object, key) # like calling their __get__ (see bug #1785).
except AttributeError: for base in mro:
continue 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): if not predicate or predicate(value):
results.append((key, value)) results.append((key, value))
results.sort() results.sort()
@ -294,30 +309,21 @@ def classify_class_attrs(cls):
names = dir(cls) names = dir(cls)
result = [] result = []
for name in names: 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 # Getting an obj from the __dict__ sometimes reveals more than
# using getattr. Static and class methods are dramatic examples. # using getattr. Static and class methods are dramatic examples.
if name in cls.__dict__: # Furthermore, some objects may raise an Exception when fetched with
obj = cls.__dict__[name] # 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: else:
obj = getattr(cls, name) obj = getattr(cls, name)
homecls = getattr(obj, "__objclass__", homecls)
# 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)
# Classify the object. # Classify the object.
if isinstance(obj, staticmethod): if isinstance(obj, staticmethod):
@ -326,11 +332,18 @@ def classify_class_attrs(cls):
kind = "class method" kind = "class method"
elif isinstance(obj, property): elif isinstance(obj, property):
kind = "property" kind = "property"
elif (isfunction(obj_via_getattr) or elif ismethoddescriptor(obj):
ismethoddescriptor(obj_via_getattr)):
kind = "method" kind = "method"
else: elif isdatadescriptor(obj):
kind = "data" kind = "data"
else:
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)) result.append(Attribute(name, kind, homecls, obj))

View File

@ -1066,11 +1066,12 @@ ArrayProxy = MakeProxyType('ArrayProxy', (
PoolProxy = MakeProxyType('PoolProxy', ( PoolProxy = MakeProxyType('PoolProxy', (
'apply', 'apply_async', 'close', 'imap', 'imap_unordered', 'join', 'apply', 'apply_async', 'close', 'imap', 'imap_unordered', 'join',
'map', 'map_async', 'terminate' 'map', 'map_async', 'starmap', 'starmap_async', 'terminate'
)) ))
PoolProxy._method_to_typeid_ = { PoolProxy._method_to_typeid_ = {
'apply_async': 'AsyncResult', 'apply_async': 'AsyncResult',
'map_async': 'AsyncResult', 'map_async': 'AsyncResult',
'starmap_async': 'AsyncResult',
'imap': 'Iterator', 'imap': 'Iterator',
'imap_unordered': 'Iterator' 'imap_unordered': 'Iterator'
} }

View File

@ -64,6 +64,9 @@ job_counter = itertools.count()
def mapstar(args): def mapstar(args):
return list(map(*args)) return list(map(*args))
def starmapstar(args):
return list(itertools.starmap(args[0], args[1]))
# #
# Code run by worker processes # Code run by worker processes
# #
@ -248,7 +251,25 @@ class Pool(object):
in a list that is returned. in a list that is returned.
''' '''
assert self._state == RUN 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): def imap(self, func, iterable, chunksize=1):
''' '''
@ -302,6 +323,13 @@ class Pool(object):
Asynchronous version of `map()` method. Asynchronous version of `map()` method.
''' '''
assert self._state == RUN 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__'): if not hasattr(iterable, '__len__'):
iterable = list(iterable) iterable = list(iterable)
@ -315,7 +343,7 @@ class Pool(object):
task_batches = Pool._get_tasks(func, iterable, chunksize) task_batches = Pool._get_tasks(func, iterable, chunksize)
result = MapResult(self._cache, chunksize, len(iterable), callback, result = MapResult(self._cache, chunksize, len(iterable), callback,
error_callback=error_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)) for i, x in enumerate(task_batches)), None))
return result return result

View File

@ -748,8 +748,15 @@ class HTMLDoc(Doc):
hr.maybe() hr.maybe()
push(msg) push(msg)
for name, kind, homecls, value in ok: for name, kind, homecls, value in ok:
push(self.document(getattr(object, name), name, mod, try:
funcs, classes, mdict, object)) 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') push('\n')
return attrs return attrs
@ -790,7 +797,12 @@ class HTMLDoc(Doc):
mdict = {} mdict = {}
for key, kind, homecls, value in attrs: for key, kind, homecls, value in attrs:
mdict[key] = anchor = '#' + name + '-' + key 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: try:
# The value may not be hashable (e.g., a data attr with # The value may not be hashable (e.g., a data attr with
# a dict or list value). # a dict or list value).
@ -1177,8 +1189,15 @@ location listed above.
hr.maybe() hr.maybe()
push(msg) push(msg)
for name, kind, homecls, value in ok: for name, kind, homecls, value in ok:
push(self.document(getattr(object, name), try:
name, mod, object)) 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 return attrs
def spilldescriptors(msg, attrs, predicate): def spilldescriptors(msg, attrs, predicate):

View File

@ -86,7 +86,7 @@ from _ssl import (
SSL_ERROR_EOF, SSL_ERROR_EOF,
SSL_ERROR_INVALID_ERROR_CODE, SSL_ERROR_INVALID_ERROR_CODE,
) )
from _ssl import HAS_SNI from _ssl import HAS_SNI, HAS_ECDH
from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23, from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23,
PROTOCOL_TLSv1) PROTOCOL_TLSv1)
from _ssl import _OPENSSL_API_VERSION from _ssl import _OPENSSL_API_VERSION

View File

@ -104,8 +104,9 @@ class ImportTests(unittest.TestCase):
try: try:
fname = TESTFN + os.extsep + "py" fname = TESTFN + os.extsep + "py"
create_empty_file(fname) create_empty_file(fname)
__import__(TESTFN)
fn = imp.cache_from_source(fname) fn = imp.cache_from_source(fname)
unlink(fn)
__import__(TESTFN)
if not os.path.exists(fn): if not os.path.exists(fn):
self.fail("__import__ did not result in creation of " self.fail("__import__ did not result in creation of "
"either a .pyc or .pyo file") "either a .pyc or .pyo file")

View File

@ -425,10 +425,37 @@ class TestNoEOL(GetSourceBase):
def test_class(self): def test_class(self):
self.assertSourceEqual(self.fodderModule.X, 1, 2) 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. # Helper for testing classify_class_attrs.
def attrs_wo_objs(cls): def attrs_wo_objs(cls):
return [t[:3] for t in inspect.classify_class_attrs(cls)] return [t[:3] for t in inspect.classify_class_attrs(cls)]
class TestClassesAndFunctions(unittest.TestCase): class TestClassesAndFunctions(unittest.TestCase):
def test_newstyle_mro(self): def test_newstyle_mro(self):
# The same w/ new-class MRO. # The same w/ new-class MRO.
@ -525,6 +552,9 @@ class TestClassesAndFunctions(unittest.TestCase):
datablob = '1' datablob = '1'
dd = _BrokenDataDescriptor()
md = _BrokenMethodDescriptor()
attrs = attrs_wo_objs(A) attrs = attrs_wo_objs(A)
self.assertIn(('s', 'static method', A), attrs, 'missing static method') self.assertIn(('s', 'static method', A), attrs, 'missing static method')
self.assertIn(('c', 'class method', A), attrs, 'missing class method') self.assertIn(('c', 'class method', A), attrs, 'missing class method')
@ -533,6 +563,8 @@ class TestClassesAndFunctions(unittest.TestCase):
'missing plain method: %r' % attrs) 'missing plain method: %r' % attrs)
self.assertIn(('m1', 'method', A), attrs, 'missing plain method') self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data') 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): class B(A):
@ -545,6 +577,8 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('m', 'method', B), attrs, 'missing plain method') self.assertIn(('m', 'method', B), attrs, 'missing plain method')
self.assertIn(('m1', 'method', A), attrs, 'missing plain method') self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data') 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): class C(A):
@ -559,6 +593,8 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('m', 'method', C), attrs, 'missing plain method') self.assertIn(('m', 'method', C), attrs, 'missing plain method')
self.assertIn(('m1', 'method', A), attrs, 'missing plain method') self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data') 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): class D(B, C):
@ -571,6 +607,49 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('m', 'method', B), attrs, 'missing plain method') self.assertIn(('m', 'method', B), attrs, 'missing plain method')
self.assertIn(('m1', 'method', D), attrs, 'missing plain method') self.assertIn(('m1', 'method', D), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data') 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): class TestGetcallargsFunctions(unittest.TestCase):

View File

@ -8,6 +8,7 @@ import unittest
import queue as pyqueue import queue as pyqueue
import time import time
import io import io
import itertools
import sys import sys
import os import os
import gc import gc
@ -1125,6 +1126,9 @@ def sqr(x, wait=0.0):
time.sleep(wait) time.sleep(wait)
return x*x return x*x
def mul(x, y):
return x*y
class _TestPool(BaseTestCase): class _TestPool(BaseTestCase):
def test_apply(self): def test_apply(self):
@ -1138,6 +1142,20 @@ class _TestPool(BaseTestCase):
self.assertEqual(pmap(sqr, list(range(100)), chunksize=20), self.assertEqual(pmap(sqr, list(range(100)), chunksize=20),
list(map(sqr, list(range(100))))) 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): def test_map_chunksize(self):
try: try:
self.pool.map_async(sqr, [], chunksize=1).get(timeout=TIMEOUT1) self.pool.map_async(sqr, [], chunksize=1).get(timeout=TIMEOUT1)

View File

@ -103,6 +103,7 @@ class BasicSocketTests(unittest.TestCase):
if ssl.OPENSSL_VERSION_INFO >= (1, 0): if ssl.OPENSSL_VERSION_INFO >= (1, 0):
ssl.OP_NO_COMPRESSION ssl.OP_NO_COMPRESSION
self.assertIn(ssl.HAS_SNI, {True, False}) self.assertIn(ssl.HAS_SNI, {True, False})
self.assertIn(ssl.HAS_ECDH, {True, False})
def test_random(self): def test_random(self):
v = ssl.RAND_status() v = ssl.RAND_status()
@ -561,6 +562,7 @@ class ContextTests(unittest.TestCase):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.set_default_verify_paths() ctx.set_default_verify_paths()
@unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
def test_set_ecdh_curve(self): def test_set_ecdh_curve(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.set_ecdh_curve("prime256v1") ctx.set_ecdh_curve("prime256v1")
@ -984,6 +986,14 @@ else:
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.daemon = True 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): def start(self, flag=None):
self.flag = flag self.flag = flag
threading.Thread.start(self) threading.Thread.start(self)
@ -1095,6 +1105,20 @@ else:
def __str__(self): def __str__(self):
return "<%s %s>" % (self.__class__.__name__, self.server) 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): def start (self, flag=None):
self.flag = flag self.flag = flag
threading.Thread.start(self) threading.Thread.start(self)
@ -1122,12 +1146,7 @@ else:
certreqs=ssl.CERT_REQUIRED, certreqs=ssl.CERT_REQUIRED,
cacerts=CERTFILE, chatty=False, cacerts=CERTFILE, chatty=False,
connectionchatty=False) connectionchatty=False)
flag = threading.Event() with server:
server.start(flag)
# wait for it to start
flag.wait()
# try to connect
try:
try: try:
with socket.socket() as sock: with socket.socket() as sock:
s = ssl.wrap_socket(sock, s = ssl.wrap_socket(sock,
@ -1147,9 +1166,6 @@ else:
sys.stdout.write("\IOError is %s\n" % str(x)) sys.stdout.write("\IOError is %s\n" % str(x))
else: else:
raise AssertionError("Use of invalid cert should have failed!") 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", def server_params_test(client_context, server_context, indata=b"FOO\n",
chatty=True, connectionchatty=False): chatty=True, connectionchatty=False):
@ -1160,12 +1176,7 @@ else:
server = ThreadedEchoServer(context=server_context, server = ThreadedEchoServer(context=server_context,
chatty=chatty, chatty=chatty,
connectionchatty=False) connectionchatty=False)
flag = threading.Event() with server:
server.start(flag)
# wait for it to start
flag.wait()
# try to connect
try:
s = client_context.wrap_socket(socket.socket()) s = client_context.wrap_socket(socket.socket())
s.connect((HOST, server.port)) s.connect((HOST, server.port))
for arg in [indata, bytearray(indata), memoryview(indata)]: for arg in [indata, bytearray(indata), memoryview(indata)]:
@ -1193,9 +1204,6 @@ else:
} }
s.close() s.close()
return stats return stats
finally:
server.stop()
server.join()
def try_protocol_combo(server_protocol, client_protocol, expect_success, def try_protocol_combo(server_protocol, client_protocol, expect_success,
certsreqs=None, server_options=0, client_options=0): certsreqs=None, server_options=0, client_options=0):
@ -1264,12 +1272,7 @@ else:
context.load_verify_locations(CERTFILE) context.load_verify_locations(CERTFILE)
context.load_cert_chain(CERTFILE) context.load_cert_chain(CERTFILE)
server = ThreadedEchoServer(context=context, chatty=False) server = ThreadedEchoServer(context=context, chatty=False)
flag = threading.Event() with server:
server.start(flag)
# wait for it to start
flag.wait()
# try to connect
try:
s = context.wrap_socket(socket.socket()) s = context.wrap_socket(socket.socket())
s.connect((HOST, server.port)) s.connect((HOST, server.port))
cert = s.getpeercert() cert = s.getpeercert()
@ -1292,9 +1295,6 @@ else:
after = ssl.cert_time_to_seconds(cert['notAfter']) after = ssl.cert_time_to_seconds(cert['notAfter'])
self.assertLess(before, after) self.assertLess(before, after)
s.close() s.close()
finally:
server.stop()
server.join()
def test_empty_cert(self): def test_empty_cert(self):
"""Connecting with an empty cert file""" """Connecting with an empty cert file"""
@ -1454,13 +1454,8 @@ else:
starttls_server=True, starttls_server=True,
chatty=True, chatty=True,
connectionchatty=True) connectionchatty=True)
flag = threading.Event()
server.start(flag)
# wait for it to start
flag.wait()
# try to connect
wrapped = False wrapped = False
try: with server:
s = socket.socket() s = socket.socket()
s.setblocking(1) s.setblocking(1)
s.connect((HOST, server.port)) s.connect((HOST, server.port))
@ -1507,9 +1502,6 @@ else:
conn.close() conn.close()
else: else:
s.close() s.close()
finally:
server.stop()
server.join()
def test_socketserver(self): def test_socketserver(self):
"""Using a SocketServer to create and manage SSL connections.""" """Using a SocketServer to create and manage SSL connections."""
@ -1545,12 +1537,7 @@ else:
indata = b"FOO\n" indata = b"FOO\n"
server = AsyncoreEchoServer(CERTFILE) server = AsyncoreEchoServer(CERTFILE)
flag = threading.Event() with server:
server.start(flag)
# wait for it to start
flag.wait()
# try to connect
try:
s = ssl.wrap_socket(socket.socket()) s = ssl.wrap_socket(socket.socket())
s.connect(('127.0.0.1', server.port)) s.connect(('127.0.0.1', server.port))
if support.verbose: if support.verbose:
@ -1571,15 +1558,6 @@ else:
s.close() s.close()
if support.verbose: if support.verbose:
sys.stdout.write(" client: connection closed.\n") 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): def test_recv_send(self):
"""Test recv(), send() and friends.""" """Test recv(), send() and friends."""
@ -1592,19 +1570,14 @@ else:
cacerts=CERTFILE, cacerts=CERTFILE,
chatty=True, chatty=True,
connectionchatty=False) connectionchatty=False)
flag = threading.Event() with server:
server.start(flag) s = ssl.wrap_socket(socket.socket(),
# wait for it to start server_side=False,
flag.wait() certfile=CERTFILE,
# try to connect ca_certs=CERTFILE,
s = ssl.wrap_socket(socket.socket(), cert_reqs=ssl.CERT_NONE,
server_side=False, ssl_version=ssl.PROTOCOL_TLSv1)
certfile=CERTFILE, s.connect((HOST, server.port))
ca_certs=CERTFILE,
cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_TLSv1)
s.connect((HOST, server.port))
try:
# helper methods for standardising recv* method signatures # helper methods for standardising recv* method signatures
def _recv_into(): def _recv_into():
b = bytearray(b"\0"*100) b = bytearray(b"\0"*100)
@ -1700,9 +1673,6 @@ else:
s.write(b"over\n") s.write(b"over\n")
s.close() s.close()
finally:
server.stop()
server.join()
def test_handshake_timeout(self): def test_handshake_timeout(self):
# Issue #5103: SSL handshake must respect the socket timeout # Issue #5103: SSL handshake must respect the socket timeout
@ -1766,19 +1736,14 @@ else:
cacerts=CERTFILE, cacerts=CERTFILE,
chatty=True, chatty=True,
connectionchatty=False) connectionchatty=False)
flag = threading.Event() with server:
server.start(flag) s = ssl.wrap_socket(socket.socket(),
# wait for it to start server_side=False,
flag.wait() certfile=CERTFILE,
# try to connect ca_certs=CERTFILE,
s = ssl.wrap_socket(socket.socket(), cert_reqs=ssl.CERT_NONE,
server_side=False, ssl_version=ssl.PROTOCOL_TLSv1)
certfile=CERTFILE, s.connect((HOST, server.port))
ca_certs=CERTFILE,
cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_TLSv1)
s.connect((HOST, server.port))
try:
# get the data # get the data
cb_data = s.get_channel_binding("tls-unique") cb_data = s.get_channel_binding("tls-unique")
if support.verbose: if support.verbose:
@ -1817,9 +1782,6 @@ else:
self.assertEqual(peer_data_repr, self.assertEqual(peer_data_repr,
repr(new_cb_data).encode("us-ascii")) repr(new_cb_data).encode("us-ascii"))
s.close() s.close()
finally:
server.stop()
server.join()
def test_compression(self): def test_compression(self):
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

View File

@ -299,6 +299,18 @@ class Galeon(UnixBrowser):
background = True 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): class Opera(UnixBrowser):
"Launcher class for Opera browser." "Launcher class for Opera browser."
@ -466,6 +478,11 @@ def register_X_browsers():
if _iscommand("skipstone"): if _iscommand("skipstone"):
register("skipstone", None, BackgroundBrowser("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 # Opera, quite popular
if _iscommand("opera"): if _iscommand("opera"):
register("opera", None, Opera("opera")) register("opera", None, Opera("opera"))

View File

@ -878,6 +878,7 @@ Michael Scharf
Andreas Schawo Andreas Schawo
Neil Schemenauer Neil Schemenauer
David Scherer David Scherer
Hynek Schlawack
Bob Schmertz Bob Schmertz
Gregor Schmid Gregor Schmid
Ralf Schmitt Ralf Schmitt

View File

@ -419,6 +419,14 @@ Core and Builtins
Library 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 - Issue #13637: "a2b" functions in the binascii module now accept ASCII-only
unicode strings. unicode strings.

View File

@ -2006,6 +2006,7 @@ set_default_verify_paths(PySSLContext *self, PyObject *unused)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
#ifndef OPENSSL_NO_ECDH
static PyObject * static PyObject *
set_ecdh_curve(PySSLContext *self, PyObject *name) set_ecdh_curve(PySSLContext *self, PyObject *name)
{ {
@ -2032,6 +2033,7 @@ set_ecdh_curve(PySSLContext *self, PyObject *name)
EC_KEY_free(key); EC_KEY_free(key);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
#endif
static PyGetSetDef context_getsetlist[] = { static PyGetSetDef context_getsetlist[] = {
{"options", (getter) get_options, {"options", (getter) get_options,
@ -2054,8 +2056,10 @@ static struct PyMethodDef context_methods[] = {
METH_NOARGS, NULL}, METH_NOARGS, NULL},
{"set_default_verify_paths", (PyCFunction) set_default_verify_paths, {"set_default_verify_paths", (PyCFunction) set_default_verify_paths,
METH_NOARGS, NULL}, METH_NOARGS, NULL},
#ifndef OPENSSL_NO_ECDH
{"set_ecdh_curve", (PyCFunction) set_ecdh_curve, {"set_ecdh_curve", (PyCFunction) set_ecdh_curve,
METH_O, NULL}, METH_O, NULL},
#endif
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
@ -2523,6 +2527,14 @@ PyInit__ssl(void)
Py_INCREF(r); Py_INCREF(r);
PyModule_AddObject(m, "HAS_TLS_UNIQUE", 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 */ /* OpenSSL version */
/* SSLeay() gives us the version of the library linked against, /* SSLeay() gives us the version of the library linked against,
which could be different from the headers version. which could be different from the headers version.