Use six.reraise for the greater good

In Python2, `raise exc` obliterates the stack trace. That's no good.

Fortunately, six has a useful syntax that works across Python versions.
It does have the downside of adding `reraise` to the stacktrace, but
otherwise, this should be better.
This commit is contained in:
Wayne Werner 2019-05-20 19:20:06 -05:00
parent 3d53067c6f
commit a1c6bcff6e
No known key found for this signature in database
GPG key ID: C36D3A8D5BEF0935
32 changed files with 112 additions and 78 deletions

View file

@ -58,8 +58,9 @@ Tested on:
from __future__ import absolute_import, print_function, unicode_literals
import logging
import uuid
import os
import sys
import uuid
from xml.etree import ElementTree
@ -465,10 +466,10 @@ def create(vm_):
)
return ret
except Exception as e: # pylint: disable=broad-except
except Exception: # pylint: disable=broad-except
do_cleanup(cleanup)
# throw the root cause after cleanup
raise e
six.reraise(*sys.exc_info())
def do_cleanup(cleanup):

View file

@ -7,11 +7,12 @@ The core behaviors used by minion and master
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import os
import time
import random
import logging
import itertools
import logging
import os
import random
import sys
import time
from collections import deque
from _socket import gaierror
@ -402,7 +403,7 @@ class SaltRaetRoadStackJoiner(ioflo.base.deeding.Deed):
except gaierror as ex:
log.warning("Unable to connect to master %s: %s", mha, ex)
if self.opts.value.get('master_type') not in ('failover', 'distributed'):
raise ex
six.reraise(*sys.exc_info())
if not stack.remotes:
raise ex

View file

@ -7,21 +7,24 @@ IoFlo behaviors for running a ZeroMQ based master
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import os
import logging
import hashlib
import multiprocessing
import errno
import hashlib
import logging
import multiprocessing
import os
import sys
# Import ioflo libs
import ioflo.base.deeding
# Import third party libs
from salt.utils.zeromq import zmq
import salt.master
import salt.crypt
import salt.daemons.masterapi
import salt.payload
import salt.utils.stringutils
from salt.ext import six
from salt.utils.zeromq import zmq
log = logging.getLogger(__name__)
@ -110,7 +113,7 @@ class ZmqRet(multiprocessing.Process):
except zmq.ZMQError as exc:
if exc.errno == errno.EINTR:
continue
raise exc
six.reraise(*sys.exc_info())
class SaltZmqCrypticleSetup(ioflo.base.deeding.Deed):
@ -215,7 +218,7 @@ class SaltZmqPublisher(ioflo.base.deeding.Deed):
except zmq.ZMQError as exc:
if exc.errno == errno.EINTR:
return
raise exc
six.reraise(*sys.exc_info())
class SaltZmqWorker(ioflo.base.deeding.Deed):

View file

@ -716,7 +716,7 @@ class MinionBase(object):
if attempts == tries:
# Exhausted all attempts. Return exception.
self.connected = False
raise exc
six.reraise(*sys.exc_info())
def _discover_masters(self):
'''

View file

@ -119,7 +119,7 @@ def _wait_for_sync(change, conn, tries=10, sleep=20):
if e.response.get('Error', {}).get('Code') == 'Throttling':
log.debug('Throttled by AWS API.')
else:
raise e
six.reraise(*sys.exc_info())
if status == 'INSYNC':
return True
time.sleep(sleep)
@ -793,7 +793,7 @@ def get_resource_records(HostedZoneId=None, Name=None, StartRecordName=None,
log.debug('Throttled by AWS API.')
time.sleep(3)
continue
raise e
six.reraise(*sys.exc_info())
def change_resource_record_sets(HostedZoneId=None, Name=None,

View file

@ -267,7 +267,7 @@ def export_distributions(region=None, key=None, keyid=None, profile=None):
except botocore.exceptions.ClientError as err:
# Raise an exception, as this is meant to be user-invoked at the CLI
# as opposed to being called from execution or state modules
raise err
six.reraise(*sys.exc_info())
dumper = __utils__['yaml.get_dumper']('IndentedSafeOrderedDumper')
return __utils__['yaml.dump'](

View file

@ -279,7 +279,7 @@ def zone_exists(zone, region=None, key=None, keyid=None, profile=None,
time.sleep(3)
error_retries -= 1
continue
raise e
six.reraise(*sys.exc_info())
def create_zone(zone, private=False, vpc_id=None, vpc_region=None, region=None,
@ -528,7 +528,7 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
time.sleep(3)
error_retries -= 1
continue
raise e
six.reraise(*sys.exc_info())
if _record:
ret['name'] = _decode_name(_record.name)
@ -603,7 +603,7 @@ def add_record(name, value, zone, record_type, identifier=None, ttl=None,
time.sleep(3)
error_retries -= 1
continue
raise e
six.reraise(*sys.exc_info())
_value = _munge_value(value, _type)
while error_retries > 0:
@ -624,7 +624,7 @@ def add_record(name, value, zone, record_type, identifier=None, ttl=None,
time.sleep(3)
error_retries -= 1
continue
raise e
six.reraise(*sys.exc_info())
def update_record(name, value, zone, record_type, identifier=None, ttl=None,
@ -686,7 +686,7 @@ def update_record(name, value, zone, record_type, identifier=None, ttl=None,
time.sleep(3)
error_retries -= 1
continue
raise e
six.reraise(*sys.exc_info())
def delete_record(name, zone, record_type, identifier=None, all_records=False,
@ -747,7 +747,7 @@ def delete_record(name, zone, record_type, identifier=None, all_records=False,
time.sleep(3)
error_retries -= 1
continue
raise e
six.reraise(*sys.exc_info())
def _try_func(conn, func, **args):

View file

@ -12,9 +12,11 @@ from __future__ import absolute_import, print_function, unicode_literals
# Import python libs
import logging
import sys
# Import salt libs
from salt.exceptions import SaltInvocationError
from salt.ext import six
log = logging.getLogger(__name__)
@ -106,5 +108,5 @@ def run_task(task_name, args=None, kwargs=None, broker=None, backend=None, wait_
except TimeoutError as ex:
log.error('Waiting for the result of a celery task execution timed out.')
if raise_timeout:
raise ex
six.reraise(*sys.exc_info())
return False

View file

@ -52,6 +52,7 @@ Module to provide Elasticsearch compatibility to Salt
# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
import sys
# Import Salt Libs
from salt.exceptions import CommandExecutionError, SaltInvocationError
@ -171,7 +172,7 @@ def ping(allow_failure=False, hosts=None, profile=None):
_get_instance(hosts, profile)
except CommandExecutionError as e:
if allow_failure:
raise e
six.reraise(*sys.exc_info())
return False
return True

View file

@ -18,6 +18,7 @@ from __future__ import absolute_import, print_function, unicode_literals
# Import python libs
import logging
import re
import sys
# Import salt libs
import salt.utils.json
@ -83,7 +84,7 @@ def _to_dict(objects):
objects = salt.utils.json.loads(objects)
except ValueError as err:
log.error("Could not parse objects: %s", err)
raise err
six.reraise(*sys.exc_info())
return objects

View file

@ -96,7 +96,7 @@ def display_output(data, out=None, opts=None, **kwargs):
display_data = try_printout(data, out, opts, **kwargs)
output_filename = opts.get('output_file', None)
log.trace('data = {0}'.format(data))
log.trace('data = %s', data)
try:
# output filename can be either '' or None
if output_filename:
@ -129,7 +129,7 @@ def display_output(data, out=None, opts=None, **kwargs):
except IOError as exc:
# Only raise if it's NOT a broken pipe
if exc.errno != errno.EPIPE:
raise exc
six.reraise(*sys.exc_info())
def get_printout(out, opts=None, **kwargs):
@ -193,7 +193,10 @@ def get_printout(out, opts=None, **kwargs):
# Since the grains outputter was removed we don't need to fire this
# error when old minions are asking for it
if out != 'grains':
log.error('Invalid outputter {0} specified, fall back to nested'.format(out))
log.error(
'Invalid outputter %s specified, fall back to nested',
out,
)
return outputters['nested']
return outputters[out]

View file

@ -95,7 +95,7 @@ def _conn(commit=False):
error = err.args
sys.stderr.write(six.text_type(error))
cursor.execute("ROLLBACK")
raise err
six.reraise(*sys.exc_info())
else:
if commit:
cursor.execute("COMMIT")

View file

@ -265,7 +265,7 @@ def _get_serv(ret=None, commit=False):
error = err.args
sys.stderr.write(six.text_type(error))
cursor.execute("ROLLBACK")
raise err
six.reraise(*sys.exc_info())
else:
if commit:
cursor.execute("COMMIT")

View file

@ -249,7 +249,7 @@ def _get_serv(ret=None, commit=False):
error = err.args
sys.stderr.write(six.text_type(error))
cursor.execute("ROLLBACK")
raise err
six.reraise(*sys.exc_info())
else:
if commit:
cursor.execute("COMMIT")

View file

@ -210,7 +210,7 @@ def _get_serv(ret=None, commit=False):
error = err.args
sys.stderr.write(six.text_type(error))
cursor.execute("ROLLBACK")
raise err
six.reraise(*sys.exc_info())
else:
if commit:
cursor.execute("COMMIT")

View file

@ -11,11 +11,12 @@ from __future__ import absolute_import, print_function, unicode_literals
import errno
import logging
import msgpack
import socket
import os
import weakref
import socket
import sys
import time
import traceback
import weakref
# Import Salt Libs
import salt.crypt
@ -564,7 +565,7 @@ class TCPReqServerChannel(salt.transport.mixins.auth.AESReqServerMixin, salt.tra
# Ignore this condition and continue.
pass
else:
raise exc
six.reraise(*sys.exc_info())
self._socket.close()
self._socket = None
if hasattr(self.req_server, 'stop'):

View file

@ -555,7 +555,7 @@ class ZeroMQReqServerChannel(salt.transport.mixins.auth.AESReqServerMixin,
except zmq.ZMQError as exc:
if exc.errno == errno.EINTR:
continue
raise exc
six.reraise(*sys.exc_info())
except (KeyboardInterrupt, SystemExit):
break
@ -873,7 +873,7 @@ class ZeroMQPubServerChannel(salt.transport.server.PubServerChannel):
except zmq.ZMQError as exc:
if exc.errno == errno.EINTR:
continue
raise exc
six.reraise(*sys.exc_info())
except KeyboardInterrupt:
log.trace('Publish daemon caught Keyboard interupt, tearing down')

View file

@ -5,9 +5,12 @@ Helpers/utils for working with tornado asynchronous stuff
from __future__ import absolute_import, print_function, unicode_literals
import sys
import tornado.ioloop
import tornado.concurrent
import contextlib
from salt.ext import six
from salt.utils import zeromq
@ -53,7 +56,7 @@ class SyncWrapper(object):
return object.__getattribute__(self, key)
except AttributeError as ex:
if key == 'asynchronous':
raise ex
six.reraise(*sys.exc_info())
attr = getattr(self.asynchronous, key)
if hasattr(attr, '__call__'):
def wrap(*args, **kwargs):

View file

@ -5,23 +5,24 @@ Utility functions for salt.cloud
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import errno
import os
import stat
import codecs
import shutil
import copy
import errno
import hashlib
import logging
import msgpack
import multiprocessing
import os
import pipes
import re
import shutil
import socket
import stat
import subprocess
import sys
import tempfile
import time
import subprocess
import multiprocessing
import logging
import pipes
import msgpack
import traceback
import copy
import re
import uuid
@ -1860,7 +1861,7 @@ def scp_file(dest_path, contents=None, kwargs=None, local_file=None):
os.close(tmpfd)
except OSError as exc:
if exc.errno != errno.EBADF:
raise exc
six.reraise(*sys.exc_info())
log.debug('Uploading %s to %s', dest_path, kwargs['hostname'])
@ -1959,7 +1960,7 @@ def scp_file(dest_path, contents=None, kwargs=None, local_file=None):
os.remove(file_to_upload)
except OSError as exc:
if exc.errno != errno.ENOENT:
raise exc
six.reraise(*sys.exc_info())
return retcode
@ -1996,7 +1997,7 @@ def sftp_file(dest_path, contents=None, kwargs=None, local_file=None):
os.close(tmpfd)
except OSError as exc:
if exc.errno != errno.EBADF:
raise exc
six.reraise(*sys.exc_info())
if local_file is not None:
file_to_upload = local_file
@ -2089,7 +2090,7 @@ def sftp_file(dest_path, contents=None, kwargs=None, local_file=None):
os.remove(file_to_upload)
except OSError as exc:
if exc.errno != errno.ENOENT:
raise exc
six.reraise(*sys.exc_info())
return retcode

View file

@ -260,7 +260,7 @@ class _DeprecationDecorator(object):
'Unhandled exception occurred in function "%s: %s',
self._function.__name__, error
)
raise error
six.reraise(*sys.exc_info())
else:
raise CommandExecutionError("Function is deprecated, but the successor function was not found.")

View file

@ -5,8 +5,8 @@ Classes which provide the shared base for GitFS, git_pillar, and winrepo
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import copy
import contextlib
import copy
import errno
import fnmatch
import glob
@ -17,6 +17,7 @@ import shlex
import shutil
import stat
import subprocess
import sys
import time
import tornado.ioloop
import weakref
@ -823,7 +824,7 @@ class GitProvider(object):
'by another master.')
log.warning(msg)
if failhard:
raise exc
six.reraise(*sys.exc_info())
return
elif pid and pid_exists(pid):
log.warning('Process %d has a %s %s lock (%s)',
@ -2819,7 +2820,7 @@ class GitFS(GitBase):
return _add_file_stat(fnd, blob_mode)
except IOError as exc:
if exc.errno != errno.ENOENT:
raise exc
six.reraise(*sys.exc_info())
with salt.utils.files.fopen(lk_fn, 'w'):
pass
@ -2901,13 +2902,13 @@ class GitFS(GitBase):
return ret
except IOError as exc:
if exc.errno != errno.ENOENT:
raise exc
six.reraise(*sys.exc_info())
try:
os.makedirs(os.path.dirname(hashdest))
except OSError as exc:
if exc.errno != errno.EEXIST:
raise exc
six.reraise(*sys.exc_info())
ret['hsum'] = salt.utils.hashutils.get_hash(path, self.opts['hash_type'])
with salt.utils.files.fopen(hashdest, 'w+') as fp_:

View file

@ -8,6 +8,7 @@ from __future__ import absolute_import, unicode_literals
# Import Python libs
import json # future lint: blacklisted-module
import logging
import sys
# Import Salt libs
import salt.utils.data
@ -95,7 +96,7 @@ def loads(s, **kwargs):
if six.PY3 and isinstance(s, bytes):
return json_module.loads(s.decode(__salt_system_encoding__), **kwargs)
else:
raise exc
six.reraise(*sys.exc_info())
def dump(obj, fp, **kwargs):

View file

@ -162,7 +162,7 @@ def wrap_tmpl_func(render_str):
tmplsrc, exc,
exc_info_on_loglevel=logging.DEBUG
)
raise exc
six.reraise(*sys.exc_info())
else: # assume tmplsrc is file-like.
tmplstr = tmplsrc.read()
tmplsrc.close()

View file

@ -949,7 +949,7 @@ def get_mors_with_properties(service_instance, object_type, property_list=None,
content = get_content(*content_args, **content_kwargs)
except IOError as e:
if e.errno != errno.EPIPE:
raise e
six.reraise(*sys.exc_info())
content = get_content(*content_args, **content_kwargs)
object_list = []

View file

@ -805,7 +805,7 @@ class Terminal(object):
'else call waitpid() on our process?'
)
else:
raise err
six.reraise(*sys.exc_info())
# I have to do this twice for Solaris.
# I can't even believe that I figured this out...
@ -824,7 +824,7 @@ class Terminal(object):
'someone else call waitpid() on our process?'
)
else:
raise
six.reraise(*sys.exc_info())
# If pid is still 0 after two calls to waitpid() then the
# process really is alive. This seems to work on all platforms,

View file

@ -6,6 +6,7 @@ Custom YAML loading in Salt
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import re
import sys
import warnings
import yaml # pylint: disable=blacklisted-import
@ -19,6 +20,9 @@ except Exception:
import salt.utils.stringutils
# Import 3rd-party libs
from salt.ext import six
__all__ = ['SaltYamlSafeLoader', 'load', 'safe_load']
@ -167,7 +171,7 @@ class SaltYamlSafeLoader(yaml.SafeLoader):
self.column = problem_column
self.pointer = problem_pointer
# Raise the caught exception
raise exc
six.reraise(*sys.exc_info())
def flatten_mapping(self, node):
merge = []

View file

@ -9,6 +9,7 @@ import os
import textwrap
import tempfile
import time
import sys
# Import Salt Testing libs
from tests.support.case import ModuleCase
@ -19,6 +20,9 @@ from tests.support.mixins import SaltReturnAssertsMixin
import salt.utils.files
import salt.utils.platform
# Import 3rd-party libs
from salt.ext import six
IS_WINDOWS = salt.utils.platform.is_windows()
@ -71,7 +75,7 @@ class CMDRunRedirectTest(ModuleCase, SaltReturnAssertsMixin):
os.close(fd)
except OSError as exc:
if exc.errno != errno.EBADF:
raise exc
six.reraise(*sys.exc_info())
# Create the testfile and release the handle
fd, self.test_tmp_path = tempfile.mkstemp()
@ -79,7 +83,7 @@ class CMDRunRedirectTest(ModuleCase, SaltReturnAssertsMixin):
os.close(fd)
except OSError as exc:
if exc.errno != errno.EBADF:
raise exc
six.reraise(*sys.exc_info())
super(CMDRunRedirectTest, self).setUp()

View file

@ -4,11 +4,13 @@ Integration tests for the docker_container states
'''
# Import Python Libs
from __future__ import absolute_import, print_function, unicode_literals
import errno
import functools
import logging
import os
import subprocess
import sys
import tempfile
# Import Salt Testing Libs
@ -943,7 +945,7 @@ class DockerContainerTestCase(ModuleCase, SaltReturnAssertsMixin):
os.close(fd)
except OSError as exc:
if exc.errno != errno.EBADF:
raise exc
six.reraise(*sys.exc_info())
else:
self.addCleanup(os.remove, ret)
return ret

View file

@ -3920,7 +3920,7 @@ class RemoteFileTest(ModuleCase, SaltReturnAssertsMixin):
os.remove(self.name)
except OSError as exc:
if exc.errno != errno.ENOENT:
raise exc
six.reraise(*sys.exc_info())
def run_state(self, *args, **kwargs):
ret = super(RemoteFileTest, self).run_state(*args, **kwargs)

View file

@ -5,8 +5,10 @@ Test the ssh_known_hosts states
# Import python libs
from __future__ import absolute_import, unicode_literals, print_function
import os
import shutil
import sys
# Import Salt Testing libs
from tests.support.case import ModuleCase
@ -14,6 +16,9 @@ from tests.support.mixins import SaltReturnAssertsMixin
from tests.support.runtests import RUNTIME_VARS
from tests.support.helpers import skip_if_binaries_missing
# Import 3rd-party libs
from salt.ext import six
KNOWN_HOSTS = os.path.join(RUNTIME_VARS.TMP, 'known_hosts')
GITHUB_FINGERPRINT = '9d:38:5b:83:a9:17:52:92:56:1a:5e:c4:d4:81:8e:0a:ca:51:a2:64:f1:74:20:11:2e:f8:8a:c3:a1:39:49:8f'
GITHUB_IP = '192.30.253.113'
@ -54,8 +59,7 @@ class SSHKnownHostsStateTest(ModuleCase, SaltReturnAssertsMixin):
)
self.skipTest('Unable to receive remote host key')
except AssertionError:
# raise initial assertion error
raise err
six.reraise(*sys.exc_info())
self.assertSaltStateChangesEqual(
ret, GITHUB_FINGERPRINT, keys=('new', 0, 'fingerprint')
@ -82,7 +86,7 @@ class SSHKnownHostsStateTest(ModuleCase, SaltReturnAssertsMixin):
)
self.skipTest('Unable to receive remote host key')
except AssertionError:
raise err
six.reraise(*sys.exc_info())
# record for every host must be available
ret = self.run_function(

View file

@ -12,7 +12,6 @@ import sys
import time
import warnings
import collections
TESTS_DIR = os.path.dirname(os.path.normpath(os.path.abspath(__file__)))
if os.name == 'nt':
TESTS_DIR = TESTS_DIR.replace('\\', '\\\\')
@ -43,6 +42,8 @@ except ImportError:
pass
# Import salt libs
from salt.ext import six
try:
from tests.support.paths import TMP, SYS_TMP_DIR, INTEGRATION_TEST_DIR
from tests.support.paths import CODE_DIR as SALT_ROOT
@ -56,7 +57,7 @@ except ImportError as exc:
print('Current sys.path:')
import pprint
pprint.pprint(sys.path)
raise exc
six.reraise(*sys.exc_info())
from tests.integration import TestDaemon # pylint: disable=W0403
import salt.utils.platform

View file

@ -209,7 +209,7 @@ def flaky(caller=None, condition=True):
return caller(cls)
except Exception as exc:
if attempt >= 3:
raise exc
six.reraise(*sys.exc_info())
backoff_time = attempt ** 2
log.info(
'Found Exception. Waiting %s seconds to retry.',