summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_support.py
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2010-09-07 21:40:25 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2010-09-07 21:40:25 (GMT)
commitc818ed4d61b12a702b2af813cd0ac4839faf497f (patch)
treeba4a83dcee870d847a7f0f8c2a91200c4b26304a /Lib/test/test_support.py
parentd47a68716e7dfdf79a19129a9a8369b41a173f27 (diff)
downloadcpython-c818ed4d61b12a702b2af813cd0ac4839faf497f.zip
cpython-c818ed4d61b12a702b2af813cd0ac4839faf497f.tar.gz
cpython-c818ed4d61b12a702b2af813cd0ac4839faf497f.tar.bz2
Merged revisions 84597-84599 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r84597 | antoine.pitrou | 2010-09-07 22:42:19 +0200 (mar., 07 sept. 2010) | 5 lines Issue #8574: better implementation of test.support.transient_internet(). Original patch by Victor. ........ r84598 | antoine.pitrou | 2010-09-07 23:05:49 +0200 (mar., 07 sept. 2010) | 6 lines Issue #9792: In case of connection failure, socket.create_connection() would swallow the exception and raise a new one, making it impossible to fetch the original errno, or to filter timeout errors. Now the original error is re-raised. ........ r84599 | antoine.pitrou | 2010-09-07 23:09:09 +0200 (mar., 07 sept. 2010) | 4 lines Improve transient_internet() again to detect more network errors, and use it in test_robotparser. Fixes #8574. ........
Diffstat (limited to 'Lib/test/test_support.py')
-rw-r--r--Lib/test/test_support.py63
1 files changed, 43 insertions, 20 deletions
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index ce2b679..32ff970 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -750,32 +750,55 @@ class TransientResource(object):
raise ResourceDenied("an optional resource is not available")
-_transients = {
- IOError: (errno.ECONNRESET, errno.ETIMEDOUT),
- socket.error: (errno.ECONNRESET,),
- socket.gaierror: [getattr(socket, t)
- for t in ('EAI_NODATA', 'EAI_NONAME')
- if hasattr(socket, t)],
- }
@contextlib.contextmanager
-def transient_internet():
+def transient_internet(resource_name, timeout=30.0, errnos=()):
"""Return a context manager that raises ResourceDenied when various issues
- with the Internet connection manifest themselves as exceptions.
+ with the Internet connection manifest themselves as exceptions."""
+ default_errnos = [
+ ('ECONNREFUSED', 111),
+ ('ECONNRESET', 104),
+ ('ENETUNREACH', 101),
+ ('ETIMEDOUT', 110),
+ ]
+
+ denied = ResourceDenied("Resource '%s' is not available" % resource_name)
+ captured_errnos = errnos
+ if not captured_errnos:
+ captured_errnos = [getattr(errno, name, num)
+ for (name, num) in default_errnos]
+
+ def filter_error(err):
+ if (isinstance(err, socket.timeout) or
+ getattr(err, 'errno', None) in captured_errnos):
+ if not verbose:
+ sys.stderr.write(denied.args[0] + "\n")
+ raise denied
- Errors caught:
- timeout IOError errno = ETIMEDOUT
- socket reset socket.error, IOError errno = ECONNRESET
- dns no data socket.gaierror errno = EAI_NODATA
- dns no name socket.gaierror errno = EAI_NONAME
- """
+ old_timeout = socket.getdefaulttimeout()
try:
+ if timeout is not None:
+ socket.setdefaulttimeout(timeout)
yield
- except tuple(_transients) as err:
- for errtype in _transients:
- if isinstance(err, errtype) and err.errno in _transients[errtype]:
- raise ResourceDenied("could not establish network "
- "connection ({})".format(err))
+ except IOError as err:
+ # urllib can wrap original socket errors multiple times (!), we must
+ # unwrap to get at the original error.
+ while True:
+ a = err.args
+ if len(a) >= 1 and isinstance(a[0], IOError):
+ err = a[0]
+ # The error can also be wrapped as args[1]:
+ # except socket.error as msg:
+ # raise IOError('socket error', msg).with_traceback(sys.exc_info()[2])
+ elif len(a) >= 2 and isinstance(a[1], IOError):
+ err = a[1]
+ else:
+ break
+ filter_error(err)
raise
+ # XXX should we catch generic exceptions and look for their
+ # __cause__ or __context__?
+ finally:
+ socket.setdefaulttimeout(old_timeout)
@contextlib.contextmanager