@@ -787,8 +787,18 @@ def __exit__(self, type_=None, value=None, traceback=None):
787787def transient_internet (resource_name , * , timeout = 30.0 , errnos = ()):
788788 """Return a context manager that raises ResourceDenied when various issues
789789 with the Internet connection manifest themselves as exceptions."""
790+ default_errnos = [
791+ ('ECONNREFUSED' , 111 ),
792+ ('ECONNRESET' , 104 ),
793+ ('ENETUNREACH' , 101 ),
794+ ('ETIMEDOUT' , 110 ),
795+ ]
796+
790797 denied = ResourceDenied ("Resource '%s' is not available" % resource_name )
791- captured_errnos = errnos or (errno .ETIMEDOUT , errno .ECONNRESET )
798+ captured_errnos = errnos
799+ if not captured_errnos :
800+ captured_errnos = [getattr (errno , name , num )
801+ for (name , num ) in default_errnos ]
792802
793803 def filter_error (err ):
794804 if (isinstance (err , socket .timeout ) or
@@ -803,14 +813,20 @@ def filter_error(err):
803813 socket .setdefaulttimeout (timeout )
804814 yield
805815 except IOError as err :
806- # socket.error inherits IOError
816+ # urllib can wrap original socket errors multiple times (!), we must
817+ # unwrap to get at the original error.
818+ while True :
819+ a = err .args
820+ if len (a ) >= 1 and isinstance (a [0 ], IOError ):
821+ err = a [0 ]
822+ # The error can also be wrapped as args[1]:
823+ # except socket.error as msg:
824+ # raise IOError('socket error', msg).with_traceback(sys.exc_info()[2])
825+ elif len (a ) >= 2 and isinstance (a [1 ], IOError ):
826+ err = a [1 ]
827+ else :
828+ break
807829 filter_error (err )
808- # urllib.request wraps the original socket.error with IOerror:
809- #
810- # except socket.error as msg:
811- # raise IOError('socket error', msg).with_traceback(sys.exc_info()[2])
812- if len (err .args ) >= 2 and isinstance (err .args [1 ], socket .error ):
813- filter_error (err .args [1 ])
814830 raise
815831 # XXX should we catch generic exceptions and look for their
816832 # __cause__ or __context__?
0 commit comments