commit 980022bb0dab1daf35f23b681121dce125301c28 Author: Damian Johnson atagar@torproject.org Date: Tue Jun 16 09:24:47 2015 -0700
Don't obscure tracebacks by re-raising exceptions
Interesting! If you call just 'raise' in a catch block you can re-raise the caught exception with the original stracktrace...
https://stackoverflow.com/questions/4825234/exception-traceback-is-hidden-if...
Perfect! This is especially useful for our @with_default decorator. --- docs/change_log.rst | 1 + stem/connection.py | 12 ++++++------ stem/control.py | 30 +++++++++++++++--------------- stem/descriptor/__init__.py | 8 ++++---- stem/interpreter/commands.py | 2 +- stem/socket.py | 8 ++++---- stem/util/proc.py | 2 +- stem/util/system.py | 4 +++- 8 files changed, 35 insertions(+), 32 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst index aea62a2..a6529fd 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -48,6 +48,7 @@ The following are only available within Stem's `git repository * :func:`~stem.connection.connect` and :func:`~stem.control.Controller.from_port` now connect to both port 9051 (relay's default) and 9151 (Tor Browser's default) (:trac:`16075`) * Added `support for NETWORK_LIVENESS events <api/response.html#stem.response.events.NetworkLivenessEvent>`_ (:spec:`44aac63`) * IPv6 addresses could trigger errors in :func:`~stem.control.Controller.get_listeners`, :class:`~stem.response.events.ORConnEvent`, and quite a few other things (:trac:`16174`) + * Don't obscure stacktraces, most notably :class:`~stem.control.Controller` getter methods with default values
* **Descriptors**
diff --git a/stem/connection.py b/stem/connection.py index 30d7b41..53bfc5d 100644 --- a/stem/connection.py +++ b/stem/connection.py @@ -665,7 +665,7 @@ def authenticate_none(controller, suppress_ctl_errors = True): pass
if not suppress_ctl_errors: - raise exc + raise else: raise OpenAuthRejected('Socket failed (%s)' % exc)
@@ -735,7 +735,7 @@ def authenticate_password(controller, password, suppress_ctl_errors = True): pass
if not suppress_ctl_errors: - raise exc + raise else: raise PasswordAuthRejected('Socket failed (%s)' % exc)
@@ -825,7 +825,7 @@ def authenticate_cookie(controller, cookie_path, suppress_ctl_errors = True): pass
if not suppress_ctl_errors: - raise exc + raise else: raise CookieAuthRejected('Socket failed (%s)' % exc, cookie_path, False)
@@ -922,7 +922,7 @@ def authenticate_safecookie(controller, cookie_path, suppress_ctl_errors = True) pass
if not suppress_ctl_errors: - raise exc + raise else: raise AuthChallengeFailed('Socket failed (%s)' % exc, cookie_path, True)
@@ -930,7 +930,7 @@ def authenticate_safecookie(controller, cookie_path, suppress_ctl_errors = True) stem.response.convert('AUTHCHALLENGE', authchallenge_response) except stem.ProtocolError as exc: if not suppress_ctl_errors: - raise exc + raise else: raise AuthChallengeFailed('Unable to parse AUTHCHALLENGE response: %s' % exc, cookie_path)
@@ -954,7 +954,7 @@ def authenticate_safecookie(controller, cookie_path, suppress_ctl_errors = True) pass
if not suppress_ctl_errors: - raise exc + raise else: raise CookieAuthRejected('Socket failed (%s)' % exc, cookie_path, True, auth_response)
diff --git a/stem/control.py b/stem/control.py index 8b0363f..f08a455 100644 --- a/stem/control.py +++ b/stem/control.py @@ -409,11 +409,11 @@ def with_default(yields = False): def wrapped(self, *args, **kwargs): try: return func(self, *args, **kwargs) - except Exception as exc: + except: default = get_default(func, args, kwargs)
if default == UNDEFINED: - raise exc + raise else: return default else: @@ -422,11 +422,11 @@ def with_default(yields = False): try: for val in func(self, *args, **kwargs): yield val - except Exception as exc: + except: default = get_default(func, args, kwargs)
if default == UNDEFINED: - raise exc + raise else: if default is not None: for val in default: @@ -572,14 +572,14 @@ class BaseController(object): self._post_authentication()
return response - except stem.SocketClosed as exc: + except stem.SocketClosed: # If the recv() thread caused the SocketClosed then we could still be # in the process of closing. Calling close() here so that we can # provide an assurance to the caller that when we raise a SocketClosed # exception we are shut down afterward for realz.
self.close() - raise exc + raise
def is_alive(self): """ @@ -1125,7 +1125,7 @@ class Controller(BaseController):
log.debug('GETINFO %s (failed: %s)' % (' '.join(params), exc))
- raise exc + raise
@with_default() def get_version(self, default = UNDEFINED): @@ -1545,7 +1545,7 @@ class Controller(BaseController): if str(exc).startswith('GETINFO request contained unrecognized keywords:'): raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) else: - raise exc + raise
if not desc_content: raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') @@ -1653,7 +1653,7 @@ class Controller(BaseController): if str(exc).startswith('GETINFO request contained unrecognized keywords:'): raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) else: - raise exc + raise
if not desc_content: raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') @@ -1663,7 +1663,7 @@ class Controller(BaseController): if not self._is_server_descriptors_available(): raise ValueError(SERVER_DESCRIPTORS_UNSUPPORTED)
- raise exc + raise
@with_default(yields = True) def get_server_descriptors(self, default = UNDEFINED): @@ -1775,7 +1775,7 @@ class Controller(BaseController): if str(exc).startswith('GETINFO request contained unrecognized keywords:'): raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) else: - raise exc + raise
if not desc_content: raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') @@ -2090,7 +2090,7 @@ class Controller(BaseController): if default != UNDEFINED: return dict((param, default) for param in params) else: - raise exc + raise
def _get_conf_dict_to_response(self, config_dict, default, multiple): """ @@ -2280,7 +2280,7 @@ class Controller(BaseController): (time.time() - start_time)) except stem.ControllerError as exc: log.debug('GETCONF HiddenServiceOptions (failed: %s)' % exc) - raise exc + raise
service_dir_map = OrderedDict() directory = None @@ -2579,14 +2579,14 @@ class Controller(BaseController): result += self.get_info('onions/current').split('\n') except stem.ProtocolError as exc: if 'No onion services of the specified type.' not in str(exc): - raise exc + raise
if detached: try: result += self.get_info('onions/detached').split('\n') except stem.ProtocolError as exc: if 'No onion services of the specified type.' not in str(exc): - raise exc + raise
return result
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py index e8b581e..719ee84 100644 --- a/stem/descriptor/__init__.py +++ b/stem/descriptor/__init__.py @@ -489,9 +489,9 @@ class Descriptor(object): line += '\n%s' % block_contents
self._unrecognized_lines.append(line) - except ValueError as exc: + except ValueError: if validate: - raise exc + raise
def _set_path(self, path): self._path = path @@ -821,11 +821,11 @@ def _get_descriptor_components(raw_contents, validate, extra_keywords = ()): block_type, block_contents = block_attr else: block_type, block_contents = None, None - except ValueError as exc: + except ValueError: if not validate: continue
- raise exc + raise
if keyword in extra_keywords: extra_entries.append('%s %s' % (keyword, value)) diff --git a/stem/interpreter/commands.py b/stem/interpreter/commands.py index ffca9ab..368a81e 100644 --- a/stem/interpreter/commands.py +++ b/stem/interpreter/commands.py @@ -345,7 +345,7 @@ class ControlInterpretor(code.InteractiveConsole): output = format(self._controller.msg(command).raw_content().strip(), *STANDARD_OUTPUT) except stem.ControllerError as exc: if isinstance(exc, stem.SocketClosed): - raise exc + raise else: output = format(str(exc), *ERROR_OUTPUT)
diff --git a/stem/socket.py b/stem/socket.py index b2b960f..1592786 100644 --- a/stem/socket.py +++ b/stem/socket.py @@ -122,14 +122,14 @@ class ControlSocket(object): raise stem.SocketClosed()
send_message(self._socket_file, message, raw) - except stem.SocketClosed as exc: + except stem.SocketClosed: # if send_message raises a SocketClosed then we should properly shut # everything down
if self.is_alive(): self.close()
- raise exc + raise
def recv(self): """ @@ -154,7 +154,7 @@ class ControlSocket(object): raise stem.SocketClosed()
return recv_message(socket_file) - except stem.SocketClosed as exc: + except stem.SocketClosed: # If recv_message raises a SocketClosed then we should properly shut # everything down. However, there's a couple cases where this will # cause deadlock... @@ -174,7 +174,7 @@ class ControlSocket(object): self.close() self._send_lock.release()
- raise exc + raise
def is_alive(self): """ diff --git a/stem/util/proc.py b/stem/util/proc.py index a03b83b..b67b011 100644 --- a/stem/util/proc.py +++ b/stem/util/proc.py @@ -508,7 +508,7 @@ def _get_lines(file_path, line_prefixes, parameter): return results except IOError as exc: _log_failure(parameter, exc) - raise exc + raise
def _log_runtime(parameter, proc_location, start_time): diff --git a/stem/util/system.py b/stem/util/system.py index eb7b9ad..4f74f81 100644 --- a/stem/util/system.py +++ b/stem/util/system.py @@ -953,6 +953,8 @@ def files_with_suffix(base_path, suffix):
def call(command, default = UNDEFINED, ignore_exit_status = False): """ + call(command, default = UNDEFINED, ignore_exit_status = False) + Issues a command in a subprocess, blocking until completion and returning the results. This is not actually ran in a shell so pipes and other shell syntax are not permitted. @@ -1007,7 +1009,7 @@ def call(command, default = UNDEFINED, ignore_exit_status = False): if default != UNDEFINED: return default else: - raise exc + raise
def get_process_name():