]> granicus.if.org Git - python/commitdiff
Improve transient_internet() again to detect more network errors,
authorAntoine Pitrou <solipsis@pitrou.net>
Tue, 7 Sep 2010 21:09:09 +0000 (21:09 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Tue, 7 Sep 2010 21:09:09 +0000 (21:09 +0000)
and use it in test_robotparser. Fixes #8574.

Lib/test/support.py
Lib/test/test_robotparser.py

index 64c9a86bfbfb905534de06e197df81af0387fc6d..6ce5ebf342c9ccb6eb294eb13806b754ad5fd5e2 100644 (file)
@@ -787,8 +787,18 @@ ioerror_peer_reset = TransientResource(IOError, errno=errno.ECONNRESET)
 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."""
+    default_errnos = [
+        ('ECONNREFUSED', 111),
+        ('ECONNRESET', 104),
+        ('ENETUNREACH', 101),
+        ('ETIMEDOUT', 110),
+    ]
+
     denied = ResourceDenied("Resource '%s' is not available" % resource_name)
-    captured_errnos = errnos or (errno.ETIMEDOUT, errno.ECONNRESET)
+    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
@@ -803,14 +813,20 @@ def transient_internet(resource_name, *, timeout=30.0, errnos=()):
             socket.setdefaulttimeout(timeout)
         yield
     except IOError as err:
-        # socket.error inherits IOError
+        # 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)
-        # urllib.request wraps the original socket.error with IOerror:
-        #
-        #    except socket.error as msg:
-        #        raise IOError('socket error', msg).with_traceback(sys.exc_info()[2])
-        if len(err.args) >= 2 and isinstance(err.args[1], socket.error):
-            filter_error(err.args[1])
         raise
     # XXX should we catch generic exceptions and look for their
     # __cause__ or __context__?
index fd007065e1985c2607f1dd8ee5d445a6515552e0..2a6d047eef5e53e8f485b31e00d0fa2f168d66e9 100644 (file)
@@ -235,23 +235,24 @@ class NetworkTestCase(unittest.TestCase):
 
     def testPasswordProtectedSite(self):
         support.requires('network')
-        # XXX it depends on an external resource which could be unavailable
-        url = 'http://mueblesmoraleda.com'
-        parser = urllib.robotparser.RobotFileParser()
-        parser.set_url(url)
-        try:
-            parser.read()
-        except URLError:
-            self.skipTest('%s is unavailable' % url)
-        self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False)
+        with support.transient_internet('mueblesmoraleda.com'):
+            url = 'http://mueblesmoraleda.com'
+            parser = urllib.robotparser.RobotFileParser()
+            parser.set_url(url)
+            try:
+                parser.read()
+            except URLError:
+                self.skipTest('%s is unavailable' % url)
+            self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False)
 
     def testPythonOrg(self):
         support.requires('network')
-        parser = urllib.robotparser.RobotFileParser(
-            "http://www.python.org/robots.txt")
-        parser.read()
-        self.assertTrue(parser.can_fetch("*",
-                                         "http://www.python.org/robots.txt"))
+        with support.transient_internet('www.python.org'):
+            parser = urllib.robotparser.RobotFileParser(
+                "http://www.python.org/robots.txt")
+            parser.read()
+            self.assertTrue(
+                parser.can_fetch("*", "http://www.python.org/robots.txt"))
 
 def test_main():
     support.run_unittest(NetworkTestCase)