diff options
Diffstat (limited to 'Lib/test/test_support.py')
| -rw-r--r-- | Lib/test/test_support.py | 63 |
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 |
