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
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

View File

@ -445,6 +445,14 @@ Constants
.. 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 @@ to speed up repeated connections from the same clients.
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::

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
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:

View File

@ -249,7 +249,8 @@ Miscellaneous options
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`.

View File

@ -301,6 +301,12 @@ changed.
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 @@ consulted for longer descriptions.
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

View File

@ -99,11 +99,11 @@ def ismethoddescriptor(object):
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 @@ def isdatadescriptor(object):
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 isabstract(object):
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 @@ def classify_class_attrs(cls):
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 @@ def classify_class_attrs(cls):
kind = "class method"
elif isinstance(obj, property):
kind = "property"
elif (isfunction(obj_via_getattr) or
ismethoddescriptor(obj_via_getattr)):
elif ismethoddescriptor(obj):
kind = "method"
else:
elif isdatadescriptor(obj):
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))

View File

@ -1066,11 +1066,12 @@ ArrayProxy = MakeProxyType('ArrayProxy', (
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'
}

View File

@ -64,6 +64,9 @@ job_counter = itertools.count()
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 @@ class Pool(object):
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 @@ class Pool(object):
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 @@ class Pool(object):
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

View File

@ -748,8 +748,15 @@ class HTMLDoc(Doc):
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 @@ class HTMLDoc(Doc):
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 @@ location listed above.
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):

View File

@ -86,7 +86,7 @@ from _ssl import (
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

View File

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

View File

@ -425,10 +425,37 @@ class TestNoEOL(GetSourceBase):
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 @@ class TestClassesAndFunctions(unittest.TestCase):
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 @@ class TestClassesAndFunctions(unittest.TestCase):
'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 @@ class TestClassesAndFunctions(unittest.TestCase):
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 @@ class TestClassesAndFunctions(unittest.TestCase):
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 @@ class TestClassesAndFunctions(unittest.TestCase):
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):

View File

@ -8,6 +8,7 @@ import unittest
import queue as pyqueue
import time
import io
import itertools
import sys
import os
import gc
@ -1125,6 +1126,9 @@ def sqr(x, wait=0.0):
time.sleep(wait)
return x*x
def mul(x, y):
return x*y
class _TestPool(BaseTestCase):
def test_apply(self):
@ -1138,6 +1142,20 @@ class _TestPool(BaseTestCase):
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)

View File

@ -103,6 +103,7 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class ContextTests(unittest.TestCase):
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
}
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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 @@ else:
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)

View File

@ -299,6 +299,18 @@ class Galeon(UnixBrowser):
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 @@ def register_X_browsers():
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"))

View File

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

View File

@ -419,6 +419,14 @@ Core and Builtins
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.

View File

@ -2006,6 +2006,7 @@ set_default_verify_paths(PySSLContext *self, PyObject *unused)
Py_RETURN_NONE;
}
#ifndef OPENSSL_NO_ECDH
static PyObject *
set_ecdh_curve(PySSLContext *self, PyObject *name)
{
@ -2032,6 +2033,7 @@ set_ecdh_curve(PySSLContext *self, PyObject *name)
EC_KEY_free(key);
Py_RETURN_NONE;
}
#endif
static PyGetSetDef context_getsetlist[] = {
{"options", (getter) get_options,
@ -2054,8 +2056,10 @@ static struct PyMethodDef context_methods[] = {
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 @@ PyInit__ssl(void)
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.