[tor-commits] [stem/master] Raise DownloadFailed from stem.descriptor.remote

atagar at torproject.org atagar at torproject.org
Sat Aug 17 20:44:27 UTC 2019


commit d52bbea9d3d370e122a4da35a94362ec17523c51
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Aug 4 14:21:21 2019 -0700

    Raise DownloadFailed from stem.descriptor.remote
    
    Ok, now that we have decent test coverage time to use this exception type where
    it matters most: in our remote module.
    
    This will greately simplify exception catchability and provide callers with the
    underlying stacktrace (which at present is getting obscured). I attempted to
    provide this back in commit aebf3e4, which got reverted in 8c61fc8.
---
 stem/__init__.py               |  3 ++-
 stem/descriptor/remote.py      | 44 +++++++++++++++++++++++-------------------
 stem/directory.py              |  2 ++
 stem/manual.py                 |  2 ++
 stem/util/connection.py        |  4 +++-
 test/unit/descriptor/remote.py |  2 +-
 6 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/stem/__init__.py b/stem/__init__.py
index dc8ae2d2..293b2b94 100644
--- a/stem/__init__.py
+++ b/stem/__init__.py
@@ -775,7 +775,8 @@ class DownloadTimeout(DownloadFailed):
   """
 
   def __init__(self, url, error, stacktrace, timeout):
-    super(DownloadTimeout, self).__init__('Failed to download from %s: %0.1f second timeout reached' % (url, timeout))
+    message = 'Failed to download from %s: %0.1f second timeout reached' % (url, timeout)
+    super(DownloadTimeout, self).__init__(url, error, stacktrace, message)
 
 
 Runlevel = stem.util.enum.UppercaseEnum(
diff --git a/stem/descriptor/remote.py b/stem/descriptor/remote.py
index af24f624..4f29a2e5 100644
--- a/stem/descriptor/remote.py
+++ b/stem/descriptor/remote.py
@@ -97,6 +97,7 @@ content. For example...
 
 import io
 import random
+import socket
 import sys
 import threading
 import time
@@ -525,11 +526,8 @@ class Query(object):
       **False**...
 
         * **ValueError** if the descriptor contents is malformed
-        * **socket.timeout** if our request timed out
-        * **urllib2.URLError** for most request failures
-
-      Note that the urllib2 module may fail with other exception types, in
-      which case we'll pass it along.
+        * :class:`~stem.DownloadTimeout` if our request timed out
+        * :class:`~stem.DownloadFailed` if our request fails
     """
 
     return list(self._run(suppress))
@@ -951,11 +949,11 @@ class DescriptorDownloader(object):
       Traceback (most recent call last):
         File "demo.py", line 3, in
           detached_sigs = stem.descriptor.remote.get_detached_signatures().run()[0]
-        File "/home/atagar/Desktop/stem/stem/descriptor/remote.py", line 476, in run
+        File "/home/atagar/Desktop/stem/stem/descriptor/remote.py", line 533, in run
           return list(self._run(suppress))
-        File "/home/atagar/Desktop/stem/stem/descriptor/remote.py", line 487, in _run
+        File "/home/atagar/Desktop/stem/stem/descriptor/remote.py", line 544, in _run
           raise self.error
-      urllib2.HTTPError: HTTP Error 404: Not found
+      stem.DownloadFailed: Failed to download from http://154.35.175.225:80/tor/status-vote/next/consensus-signatures (HTTPError): Not found
 
     .. versionadded:: 1.8.0
 
@@ -1064,20 +1062,26 @@ def _download_from_dirport(url, compression, timeout):
   :returns: two value tuple of the form (data, reply_headers)
 
   :raises:
-    * **socket.timeout** if our request timed out
-    * **urllib2.URLError** for most request failures
+    * :class:`~stem.DownloadTimeout` if our request timed out
+    * :class:`~stem.DownloadFailed` if our request fails
   """
 
-  response = urllib.urlopen(
-    urllib.Request(
-      url,
-      headers = {
-        'Accept-Encoding': ', '.join(map(lambda c: c.encoding, compression)),
-        'User-Agent': stem.USER_AGENT,
-      }
-    ),
-    timeout = timeout,
-  )
+  try:
+    response = urllib.urlopen(
+      urllib.Request(
+        url,
+        headers = {
+          'Accept-Encoding': ', '.join(map(lambda c: c.encoding, compression)),
+          'User-Agent': stem.USER_AGENT,
+        }
+      ),
+      timeout = timeout,
+    )
+  except socket.timeout as exc:
+    raise stem.DownloadTimeout(url, exc, sys.exc_info()[2], timeout)
+  except:
+    exc, stacktrace = sys.exc_info()[1:3]
+    raise stem.DownloadFailed(url, exc, stacktrace)
 
   return _decompress(response.read(), response.headers.get('Content-Encoding')), response.headers
 
diff --git a/stem/directory.py b/stem/directory.py
index 01eca70b..075235c9 100644
--- a/stem/directory.py
+++ b/stem/directory.py
@@ -215,6 +215,8 @@ class Directory(object):
     :raises: **IOError** if unable to retrieve the fallback directories
     """
 
+    # TODO: change IOError to DownloadFailed in stem 2.x
+
     raise NotImplementedError('Unsupported Operation: this should be implemented by the Directory subclass')
 
   def __hash__(self):
diff --git a/stem/manual.py b/stem/manual.py
index 0aef8a48..729fb204 100644
--- a/stem/manual.py
+++ b/stem/manual.py
@@ -296,6 +296,8 @@ def download_man_page(path = None, file_handle = None, url = GITWEB_MANUAL_URL,
   :raises: **IOError** if unable to retrieve the manual
   """
 
+  # TODO: change IOError to DownloadFailed in stem 2.x
+
   if not path and not file_handle:
     raise ValueError("Either the path or file_handle we're saving to must be provided")
   elif not stem.util.system.is_available('a2x'):
diff --git a/stem/util/connection.py b/stem/util/connection.py
index a1f93625..421eb9a3 100644
--- a/stem/util/connection.py
+++ b/stem/util/connection.py
@@ -186,7 +186,9 @@ def download(url, timeout = None, retries = None):
 
   :returns: **bytes** content of the given url
 
-  :raises: :class:`~stem.DownloadFailed` if the download fails
+  :raises:
+    * :class:`~stem.DownloadTimeout` if our request timed out
+    * :class:`~stem.DownloadFailed` if our request fails
   """
 
   if retries is None:
diff --git a/test/unit/descriptor/remote.py b/test/unit/descriptor/remote.py
index 6dbaf43e..8a35216d 100644
--- a/test/unit/descriptor/remote.py
+++ b/test/unit/descriptor/remote.py
@@ -383,7 +383,7 @@ class TestDescriptorDownloader(unittest.TestCase):
     # After two requests we'll have reached our total permissable timeout.
     # Check that we don't make a third.
 
-    self.assertRaises(socket.timeout, query.run)
+    self.assertRaises(stem.DownloadTimeout, query.run)
     self.assertEqual(2, dirport_mock.call_count)
 
   def test_query_with_invalid_endpoints(self):





More information about the tor-commits mailing list