Skip to content

Commit abe7920

Browse files
author
Shoshana Berleant
committed
Merge pull request #1490 from shoshber/raise_from
WIP/REF/FIX: Don't throw away exception stack traces
2 parents 124a850 + 620910c commit abe7920

File tree

13 files changed

+101
-53
lines changed

13 files changed

+101
-53
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ install:
4545
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then conda install --yes vtk; fi
4646
- pip install python-coveralls
4747
- pip install nose-cov
48+
- pip install mock
4849
# Add tvtk (PIL is required by blockcanvas)
4950
# Install mayavi (see https://github.com/enthought/mayavi/issues/271)
5051
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then

circle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ dependencies:
2121
# Set up python environment
2222
- pip install --upgrade pip
2323
- pip install -e .
24-
- pip install matplotlib sphinx ipython boto coverage dipy
24+
- pip install matplotlib sphinx ipython boto coverage dipy mock
2525
# Add tvtk
2626
- pip install http://effbot.org/downloads/Imaging-1.1.7.tar.gz
2727
- pip install -e git+https://github.com/enthought/etsdevtools.git#egg=etsdevtools

nipype/algorithms/misc.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from __future__ import division
1616
from builtins import zip
1717
from builtins import range
18+
from future.utils import raise_from
1819

1920
import os
2021
import os.path as op
@@ -857,9 +858,9 @@ def __init__(self, infields=None, force_run=True, **kwargs):
857858
def _run_interface(self, runtime):
858859
try:
859860
import pandas as pd
860-
except ImportError:
861-
raise ImportError(('This interface requires pandas '
862-
'(http://pandas.pydata.org/) to run.'))
861+
except ImportError as e:
862+
raise_from(ImportError('This interface requires pandas '
863+
'(http://pandas.pydata.org/) to run.'), e)
863864

864865
try:
865866
import lockfile as pl

nipype/external/six.py

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929
import types
3030

3131
__author__ = "Benjamin Peterson <benjamin@python.org>"
32-
__version__ = "1.9.0"
32+
__version__ = "1.10.0"
3333

3434

3535
# Useful for very coarse version differentiation.
3636
PY2 = sys.version_info[0] == 2
3737
PY3 = sys.version_info[0] == 3
38+
PY34 = sys.version_info[0:2] >= (3, 4)
3839

3940
if PY3:
4041
string_types = str,
@@ -57,6 +58,7 @@
5758
else:
5859
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
5960
class X(object):
61+
6062
def __len__(self):
6163
return 1 << 31
6264
try:
@@ -160,6 +162,7 @@ def _resolve(self):
160162

161163

162164
class _SixMetaPathImporter(object):
165+
163166
"""
164167
A meta path importer to import six.moves and its submodules.
165168
@@ -224,6 +227,7 @@ def get_code(self, fullname):
224227

225228

226229
class _MovedItems(_LazyModule):
230+
227231
"""Lazy loading of moved objects"""
228232
__path__ = [] # mark as package
229233

@@ -235,8 +239,10 @@ class _MovedItems(_LazyModule):
235239
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
236240
MovedAttribute("intern", "__builtin__", "sys"),
237241
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
242+
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
243+
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
238244
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
239-
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
245+
MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
240246
MovedAttribute("reduce", "__builtin__", "functools"),
241247
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
242248
MovedAttribute("StringIO", "StringIO", "io"),
@@ -246,7 +252,6 @@ class _MovedItems(_LazyModule):
246252
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
247253
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
248254
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
249-
250255
MovedModule("builtins", "__builtin__"),
251256
MovedModule("configparser", "ConfigParser"),
252257
MovedModule("copyreg", "copy_reg"),
@@ -293,8 +298,13 @@ class _MovedItems(_LazyModule):
293298
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
294299
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
295300
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
296-
MovedModule("winreg", "_winreg"),
297301
]
302+
# Add windows specific modules.
303+
if sys.platform == "win32":
304+
_moved_attributes += [
305+
MovedModule("winreg", "_winreg"),
306+
]
307+
298308
for attr in _moved_attributes:
299309
setattr(_MovedItems, attr.name, attr)
300310
if isinstance(attr, MovedModule):
@@ -308,6 +318,7 @@ class _MovedItems(_LazyModule):
308318

309319

310320
class Module_six_moves_urllib_parse(_LazyModule):
321+
311322
"""Lazy loading of moved objects in six.moves.urllib_parse"""
312323

313324

@@ -347,6 +358,7 @@ class Module_six_moves_urllib_parse(_LazyModule):
347358

348359

349360
class Module_six_moves_urllib_error(_LazyModule):
361+
350362
"""Lazy loading of moved objects in six.moves.urllib_error"""
351363

352364

@@ -366,6 +378,7 @@ class Module_six_moves_urllib_error(_LazyModule):
366378

367379

368380
class Module_six_moves_urllib_request(_LazyModule):
381+
369382
"""Lazy loading of moved objects in six.moves.urllib_request"""
370383

371384

@@ -415,6 +428,7 @@ class Module_six_moves_urllib_request(_LazyModule):
415428

416429

417430
class Module_six_moves_urllib_response(_LazyModule):
431+
418432
"""Lazy loading of moved objects in six.moves.urllib_response"""
419433

420434

@@ -435,6 +449,7 @@ class Module_six_moves_urllib_response(_LazyModule):
435449

436450

437451
class Module_six_moves_urllib_robotparser(_LazyModule):
452+
438453
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
439454

440455

@@ -452,6 +467,7 @@ class Module_six_moves_urllib_robotparser(_LazyModule):
452467

453468

454469
class Module_six_moves_urllib(types.ModuleType):
470+
455471
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
456472
__path__ = [] # mark as package
457473
parse = _importer._get_module("moves.urllib_parse")
@@ -522,6 +538,9 @@ def get_unbound_function(unbound):
522538

523539
create_bound_method = types.MethodType
524540

541+
def create_unbound_method(func, cls):
542+
return func
543+
525544
Iterator = object
526545
else:
527546
def get_unbound_function(unbound):
@@ -530,6 +549,9 @@ def get_unbound_function(unbound):
530549
def create_bound_method(func, obj):
531550
return types.MethodType(func, obj, obj.__class__)
532551

552+
def create_unbound_method(func, cls):
553+
return types.MethodType(func, None, cls)
554+
533555
class Iterator(object):
534556

535557
def next(self):
@@ -568,16 +590,16 @@ def iterlists(d, **kw):
568590
viewitems = operator.methodcaller("items")
569591
else:
570592
def iterkeys(d, **kw):
571-
return iter(d.iterkeys(**kw))
593+
return d.iterkeys(**kw)
572594

573595
def itervalues(d, **kw):
574-
return iter(d.itervalues(**kw))
596+
return d.itervalues(**kw)
575597

576598
def iteritems(d, **kw):
577-
return iter(d.iteritems(**kw))
599+
return d.iteritems(**kw)
578600

579601
def iterlists(d, **kw):
580-
return iter(d.iterlists(**kw))
602+
return d.iterlists(**kw)
581603

582604
viewkeys = operator.methodcaller("viewkeys")
583605

@@ -600,21 +622,22 @@ def b(s):
600622
def u(s):
601623
return s
602624
unichr = chr
603-
if sys.version_info[1] <= 1:
604-
def int2byte(i):
605-
return bytes((i,))
606-
else:
607-
# This is about 2x faster than the implementation above on 3.2+
608-
int2byte = operator.methodcaller("to_bytes", 1, "big")
625+
import struct
626+
int2byte = struct.Struct(">B").pack
627+
del struct
609628
byte2int = operator.itemgetter(0)
610629
indexbytes = operator.getitem
611630
iterbytes = iter
612631
import io
613632
StringIO = io.StringIO
614633
BytesIO = io.BytesIO
615634
_assertCountEqual = "assertCountEqual"
616-
_assertRaisesRegex = "assertRaisesRegex"
617-
_assertRegex = "assertRegex"
635+
if sys.version_info[1] <= 1:
636+
_assertRaisesRegex = "assertRaisesRegexp"
637+
_assertRegex = "assertRegexpMatches"
638+
else:
639+
_assertRaisesRegex = "assertRaisesRegex"
640+
_assertRegex = "assertRegex"
618641
else:
619642
def b(s):
620643
return s
@@ -780,6 +803,7 @@ def with_metaclass(meta, *bases):
780803
# metaclass for one level of class instantiation that replaces itself with
781804
# the actual metaclass.
782805
class metaclass(meta):
806+
783807
def __new__(cls, name, this_bases, d):
784808
return meta(name, bases, d)
785809
return type.__new__(metaclass, 'temporary_class', (), {})

nipype/interfaces/afni/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
from sys import platform
77
from builtins import object
8+
from future.utils import raise_from
89

910
from ... import logging
1011
from ...utils.filemanip import split_filename
@@ -82,9 +83,9 @@ def outputtype_to_ext(cls, outputtype):
8283

8384
try:
8485
return cls.ftypes[outputtype]
85-
except KeyError:
86+
except KeyError as e:
8687
msg = 'Invalid AFNIOUTPUTTYPE: ', outputtype
87-
raise KeyError(msg)
88+
raise_from(KeyError(msg), e)
8889

8990
@classmethod
9091
def outputtype(cls):

nipype/pipeline/plugins/ipython.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
from future import standard_library
77
standard_library.install_aliases()
8+
from future.utils import raise_from
9+
810
from pickle import dumps
911

1012
import sys
@@ -62,19 +64,20 @@ def run(self, graph, config, updatehash=False):
6264
name = 'ipyparallel'
6365
__import__(name)
6466
self.iparallel = sys.modules[name]
65-
except ImportError:
66-
raise ImportError("ipyparallel not found. Parallel execution "
67-
"will be unavailable")
67+
except ImportError as e:
68+
raise_from(ImportError("ipyparallel not found. Parallel execution "
69+
"will be unavailable"), e)
6870
try:
6971
self.taskclient = self.iparallel.Client()
7072
except Exception as e:
7173
if isinstance(e, TimeoutError):
72-
raise Exception("No IPython clients found.")
74+
raise_from(Exception("No IPython clients found."), e)
7375
if isinstance(e, IOError):
74-
raise Exception("ipcluster/ipcontroller has not been started")
76+
raise_from(Exception("ipcluster/ipcontroller has not been started"), e)
7577
if isinstance(e, ValueError):
76-
raise Exception("Ipython kernel not installed")
77-
raise e
78+
raise_from(Exception("Ipython kernel not installed"), e)
79+
else:
80+
raise e
7881
return super(IPythonPlugin, self).run(graph, config, updatehash=updatehash)
7982

8083
def _get_result(self, taskid):

nipype/pipeline/plugins/ipythonx.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
import sys
7+
from future.utils import raise_from
78

89
from ...interfaces.base import LooseVersion
910
IPython_not_loaded = False
@@ -44,16 +45,16 @@ def run(self, graph, config, updatehash=False):
4445
name = 'IPython.kernel.client'
4546
__import__(name)
4647
self.ipyclient = sys.modules[name]
47-
except ImportError:
48-
raise ImportError("Ipython kernel not found. Parallel execution "
49-
"will be unavailable")
48+
except ImportError as e:
49+
raise_from(ImportError("Ipython kernel not found. Parallel execution "
50+
"will be unavailable"), e)
5051
try:
5152
self.taskclient = self.ipyclient.TaskClient()
5253
except Exception as e:
5354
if isinstance(e, ConnectionRefusedError):
54-
raise Exception("No IPython clients found.")
55+
raise_from(Exception("No IPython clients found."), e)
5556
if isinstance(e, ValueError):
56-
raise Exception("Ipython kernel not installed")
57+
raise_from(Exception("Ipython kernel not installed"), e)
5758
return super(IPythonXPlugin, self).run(graph, config, updatehash=updatehash)
5859

5960
def _get_result(self, taskid):

nipype/testing/tests/test_utils.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
import os
77
import warnings
8+
import subprocess
9+
from mock import patch, MagicMock
810
from nipype.testing.utils import TempFATFS
9-
from nose.tools import assert_true
11+
from nose.tools import assert_true, assert_raises
1012

1113

1214
def test_tempfatfs():
@@ -17,3 +19,12 @@ def test_tempfatfs():
1719
else:
1820
with fatfs as tmpdir:
1921
yield assert_true, os.path.exists(tmpdir)
22+
23+
@patch('subprocess.check_call', MagicMock(
24+
side_effect=subprocess.CalledProcessError('','')))
25+
def test_tempfatfs_calledprocesserror():
26+
yield assert_raises, IOError, TempFATFS
27+
28+
@patch('subprocess.Popen', MagicMock(side_effect=OSError()))
29+
def test_tempfatfs_oserror():
30+
yield assert_raises, IOError, TempFATFS

nipype/testing/utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from tempfile import mkdtemp
1313
from ..utils.misc import package_check
1414
from nose import SkipTest
15-
15+
from future.utils import raise_from
1616

1717
def skip_if_no_package(*args, **kwargs):
1818
"""Raise SkipTest if package_check fails
@@ -62,15 +62,15 @@ def __init__(self, size_in_mbytes=8, delay=0.5):
6262
try:
6363
subprocess.check_call(args=mkfs_args, stdout=self.dev_null,
6464
stderr=self.dev_null)
65-
except subprocess.CalledProcessError:
66-
raise IOError("mkfs.vfat failed")
65+
except subprocess.CalledProcessError as e:
66+
raise_from(IOError("mkfs.vfat failed"), e)
6767

6868
try:
6969
self.fusefat = subprocess.Popen(args=mount_args,
7070
stdout=self.dev_null,
7171
stderr=self.dev_null)
72-
except OSError:
73-
raise IOError("fusefat is not installed")
72+
except OSError as e:
73+
raise_from(IOError("fusefat is not installed"), e)
7474

7575
time.sleep(self.delay)
7676

0 commit comments

Comments
 (0)