[tor-commits] [stem/master] Include the originating stacktrace in stem.descriptor.remote exceptions
atagar at torproject.org
atagar at torproject.org
Tue Jan 1 00:29:39 UTC 2019
commit cc43a6ca90e3943a542258b2b4d8466ae9a4ac36
Author: Damian Johnson <atagar at torproject.org>
Date: Sun Dec 30 12:19:10 2018 -0800
Include the originating stacktrace in stem.descriptor.remote exceptions
Our remote module needs to retain then later rethrow exceptions, which makes
stacktraces less than helpful.
Both python 2.x and 3.x have mechanisms for preserving stacktraces but they
both rely on language syntax rather than libraries, so we cannot use either
without breaking compatibility with the other version.
As such opting for the least bad option I can think of which is to encode
the original stacktrace within our message.
As mentioned in the code's comment we'll opt for something better when we
drop python 2.x support.
---
stem/descriptor/remote.py | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/stem/descriptor/remote.py b/stem/descriptor/remote.py
index 13882ba7..8a2877fa 100644
--- a/stem/descriptor/remote.py
+++ b/stem/descriptor/remote.py
@@ -97,6 +97,7 @@ import random
import sys
import threading
import time
+import traceback
import zlib
import stem
@@ -465,6 +466,13 @@ class Query(object):
Blocks until our request is complete then provides the descriptors. If we
haven't yet started our request then this does so.
+ .. versionchanged:: 1.8.0
+ Overwriting exceptions to include the originating traceback.
+
+ In Stem 2.x (when we no longer need Python 2.x compatibility) this will
+ revert back to re-raising the originating exception, but with its
+ stacktrace preserved.
+
:param bool suppress: avoids raising exceptions if **True**
:returns: list for the requested :class:`~stem.descriptor.__init__.Descriptor` instances
@@ -474,6 +482,7 @@ class Query(object):
**False**...
* **ValueError** if the descriptor contents is malformed
+ * **stem.ProtocolError** if unable to parse an ORPort response
* **socket.timeout** if our request timed out
* **urllib2.URLError** for most request failures
@@ -492,7 +501,27 @@ class Query(object):
if suppress:
return
- raise self.error
+ # TODO: Unfortunately the proper way to retain a stacktrace differs
+ # between python 2.x and 3.x in a syntactic way...
+ #
+ # Python 2.x
+ #
+ # raise exc_type, exc_value, exc_traceback
+ #
+ # Python 3.x
+ #
+ # raise WrapperException('foo') from exc_value
+ #
+ # Because this is syntactic we cannot do an 'if python2, else python3'
+ # for this. As such re-encoding the stacktrace as part of the message.
+ #
+ # When we drop python 2.x support we should replace this with the
+ # 'raise from' option above.
+
+ exc_type, exc_value, exc_traceback = self.error
+ stacktrace = 'Original traceback:\n' + ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)[1:])
+
+ raise exc_type(str(exc_value) + '\n\n' + stacktrace)
else:
if self.content is None:
if suppress:
@@ -523,7 +552,7 @@ class Query(object):
for desc in results:
yield desc
except ValueError as exc:
- self.error = exc # encountered a parsing error
+ self.error = sys.exc_info() # encountered a parsing error
if suppress:
return
@@ -577,7 +606,7 @@ class Query(object):
return self._download_descriptors(retries - 1, timeout)
else:
log.debug("Unable to download descriptors from '%s': %s" % (self.download_url, exc))
- self.error = exc
+ self.error = sys.exc_info()
finally:
self.is_done = True
More information about the tor-commits
mailing list