summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_support.py
diff options
context:
space:
mode:
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