diff --git a/.gitignore b/.gitignore index 67f2bf4528e..41890f3f8a1 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ MDAnalysis.log authors.py # Ignore the .DS_Store file in the osx file system *.DS_Store +# ignore files from tests +.hypothesis/ diff --git a/package/AUTHORS b/package/AUTHORS index d5518c72874..04aceff1398 100644 --- a/package/AUTHORS +++ b/package/AUTHORS @@ -124,6 +124,7 @@ Chronological list of authors - Rocco Meli - Lily Wang - Matthijs Tadema + - Joao Miguel Correia Teixeira External code ------------- diff --git a/package/CHANGELOG b/package/CHANGELOG index c9a8f2db3a1..cf626b8b3a1 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -13,7 +13,8 @@ The rules for this file: * release numbers follow "Semantic Versioning" http://semver.org ------------------------------------------------------------------------------ -mm/dd/yy richardjgowers, kain88-de, lilyminium, p-j-smith, bdice + +mm/dd/yy richardjgowers, kain88-de, lilyminium, p-j-smith, bdice, joaomcteixeira * 0.21.0 @@ -25,6 +26,9 @@ Fixes * PDBQTParser now gives icode TopologyAttrs (Issue #2361) Enhancements + * Uniforms exception handling between Python 2.7 and Python 3: raised exceptions + do not contain previous exceptions traceback. Uses six package to handle + py27 and py3 compatibility (PR #2357) * Expanded selection wildcards to the start and middle of strings (Issue #2370) * Added type checking and conversion to Connection TopologyAttrs (Issue #2373) * New analysis.hydrogenbonds.HydrogenBondAnalysis class for the analysis of diff --git a/package/MDAnalysis/analysis/align.py b/package/MDAnalysis/analysis/align.py index 7c94a1a07cd..0c75d925ce9 100644 --- a/package/MDAnalysis/analysis/align.py +++ b/package/MDAnalysis/analysis/align.py @@ -190,7 +190,7 @@ import logging from six.moves import range, zip, zip_longest -from six import string_types +from six import raise_from, string_types import numpy as np @@ -507,8 +507,12 @@ def alignto(mobile, reference, select="all", weights=None, # treat subselection as AtomGroup mobile_atoms = subselection.atoms except AttributeError: - raise TypeError("subselection must be a selection string, an" - " AtomGroup or Universe or None") + raise_from( + TypeError( + "subselection must be a selection string, an" + " AtomGroup or Universe or None" + ), + None) # _fit_to DOES subtract center of mass, will provide proper min_rmsd mobile_atoms, new_rmsd = _fit_to(mobile_coordinates, ref_coordinates, @@ -1167,7 +1171,7 @@ def get_atoms_byres(g, match_mask=np.logical_not(mismatch_mask)): "Try to improve your selections for mobile and reference.").format( ag1.n_atoms, ag2.n_atoms) logger.error(errmsg) - raise SelectionError(errmsg) + raise_from(SelectionError(errmsg), None) if np.any(mass_mismatches): # Test 2 failed. diff --git a/package/MDAnalysis/analysis/density.py b/package/MDAnalysis/analysis/density.py index bd8f213d80f..b9fc724a6f2 100644 --- a/package/MDAnalysis/analysis/density.py +++ b/package/MDAnalysis/analysis/density.py @@ -161,7 +161,7 @@ from __future__ import print_function, division, absolute_import from six.moves import range, zip -from six import string_types +from six import raise_from, string_types import numpy as np import sys @@ -373,11 +373,14 @@ def _check_set_unit(self, u): units.conversion_factor[unit_type][value] self.units[unit_type] = value except KeyError: - raise ValueError('Unit ' + str(value) + ' of type ' + str(unit_type) + ' is not recognized.') + raise_from( + ValueError('Unit ' + str(value) + ' of type ' + str(unit_type) + ' is not recognized.'), + None, + ) except AttributeError: errmsg = '"unit" must be a dictionary with keys "length" and "density.' logger.fatal(errmsg) - raise ValueError(errmsg) + raise_from(ValueError(errmsg), None) # need at least length and density (can be None) if 'length' not in self.units: raise ValueError('"unit" must contain a unit for "length".') @@ -486,7 +489,10 @@ def convert_density(self, unit='Angstrom'): self.grid *= units.get_conversion_factor('density', self.units['density'], unit) except KeyError: - raise ValueError("The name of the unit ({0!r} supplied) must be one of:\n{1!r}".format(unit, units.conversion_factor['density'].keys())) + raise_from( + ValueError("The name of the unit ({0!r} supplied) must be one of:\n{1!r}".format(unit, units.conversion_factor['density'].keys())), + None, + ) self.units['density'] = unit def __repr__(self): @@ -527,13 +533,13 @@ def _set_user_grid(gridcenter, xdim, ydim, zdim, smin, smax): try: gridcenter = np.asarray(gridcenter, dtype=np.float32) except ValueError: - raise ValueError("Non-number values assigned to gridcenter") + raise_from(ValueError("Non-number values assigned to gridcenter"), None) if gridcenter.shape != (3,): raise ValueError("gridcenter must be a 3D coordinate") try: xyzdim = np.array([xdim, ydim, zdim], dtype=np.float32) except ValueError: - raise ValueError("xdim, ydim, and zdim must be numbers") + raise_from(ValueError("xdim, ydim, and zdim must be numbers"), None) # Set min/max by shifting by half the edge length of each dimension umin = gridcenter - xyzdim/2 diff --git a/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py b/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py index ebb2933c317..63579f8183c 100644 --- a/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py +++ b/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py @@ -206,6 +206,7 @@ """ from __future__ import division, absolute_import from six.moves import zip +from six import raise_from import numpy as np import scipy.optimize @@ -300,8 +301,8 @@ def __init__(self, universe, # check that slicing is possible try: self.u.trajectory[0] - except: - raise ValueError("Trajectory must support slicing") + except Exception: + raise_from(ValueError("Trajectory must support slicing"), None) self.h = hydrogens self.a = acceptors diff --git a/package/MDAnalysis/analysis/hole.py b/package/MDAnalysis/analysis/hole.py index c617de56581..baca0f723eb 100644 --- a/package/MDAnalysis/analysis/hole.py +++ b/package/MDAnalysis/analysis/hole.py @@ -1030,7 +1030,7 @@ def create_vmd_surface(self, filename="hole.vmd", **kwargs): except subprocess.CalledProcessError as err: os.unlink(tmp_sos) logger.fatal("sph_process failed ({0})".format(err.returncode)) - raise OSError(err.returncode, "sph_process failed") + six.raise_from(OSError(err.returncode, "sph_process failed"), None) except: os.unlink(tmp_sos) raise @@ -1045,7 +1045,7 @@ def create_vmd_surface(self, filename="hole.vmd", **kwargs): stderr=FNULL) except subprocess.CalledProcessError as err: logger.fatal("sos_triangle failed ({0})".format(err.returncode)) - raise OSError(err.returncode, "sos_triangle failed") + six.raise_from(OSError(err.returncode, "sos_triangle failed"), None) finally: os.unlink(tmp_sos) diff --git a/package/MDAnalysis/analysis/nuclinfo.py b/package/MDAnalysis/analysis/nuclinfo.py index 05b9f07c580..72ba4f5da90 100644 --- a/package/MDAnalysis/analysis/nuclinfo.py +++ b/package/MDAnalysis/analysis/nuclinfo.py @@ -107,6 +107,7 @@ import numpy as np from math import pi, sin, cos, atan2, sqrt, pow +from six import raise_from from MDAnalysis.lib import mdamath @@ -711,8 +712,15 @@ def hydroxyl(universe, seg, i): try: hydr = h.dihedral.value() % 360 except ValueError: - raise ValueError("Resid {0} does not contain atoms C1', C2', O2', H2' but atoms {1}" - .format(i, str(list(h.atoms)))) + raise_from( + ValueError( + ( + "Resid {0} does not contain atoms C1', C2', O2', H2' " + "but atoms {1}" + ).format(i, str(list(h.atoms))) + ), + None) + return hydr diff --git a/package/MDAnalysis/analysis/polymer.py b/package/MDAnalysis/analysis/polymer.py index 642297da2fe..e699628c38b 100644 --- a/package/MDAnalysis/analysis/polymer.py +++ b/package/MDAnalysis/analysis/polymer.py @@ -62,6 +62,7 @@ """ from __future__ import division, absolute_import from six.moves import range +from six import raise_from import numpy as np import scipy.optimize @@ -248,7 +249,7 @@ def _perform_fit(self): try: self.results except AttributeError: - raise NoDataError("Use the run method first") + raise_from(NoDataError("Use the run method first"), None) self.x = np.arange(len(self.results)) * self.lb self.lp = fit_exponential_decay(self.x, self.results) diff --git a/package/MDAnalysis/analysis/psa.py b/package/MDAnalysis/analysis/psa.py index d0d8d36d3d6..9cb45008b5d 100644 --- a/package/MDAnalysis/analysis/psa.py +++ b/package/MDAnalysis/analysis/psa.py @@ -215,7 +215,7 @@ import six from six.moves import range, cPickle, zip -from six import string_types +from six import raise_from, string_types import os import warnings @@ -266,9 +266,14 @@ def get_path_metric_func(name): try: return path_metrics[name] except KeyError as key: - raise KeyError('Path metric "{}" not found. Valid selections: {}' - ''.format(key, " ".join('"{}"'.format(n) - for n in path_metrics.keys()))) + raise_from( + KeyError( + 'Path metric "{}" not found. Valid selections: {}'.format( + key, + " ".join('"{}"'.format(n) for n in path_metrics.keys()) + ) + ), + None) def sqnorm(v, axis=None): @@ -1865,7 +1870,7 @@ def plot_annotated_heatmap(self, filename=None, linkage='ward', \ try: import seaborn.apionly as sns except ImportError: - raise ImportError( + raise_from(ImportError( """ERROR --- The seaborn package cannot be found! The seaborn API could not be imported. Please install it first. @@ -1880,7 +1885,9 @@ def plot_annotated_heatmap(self, filename=None, linkage='ward', \ and install in the usual manner. """ - ) + ), + None, + ) if self.D is None: raise ValueError( @@ -1974,7 +1981,7 @@ def plot_nearest_neighbors(self, filename=None, idx=0, \ try: import seaborn.apionly as sns except ImportError: - raise ImportError( + raise_from(ImportError( """ERROR --- The seaborn package cannot be found! The seaborn API could not be imported. Please install it first. @@ -1989,7 +1996,9 @@ def plot_nearest_neighbors(self, filename=None, idx=0, \ and install in the usual manner. """ - ) + ), + None, + ) colors = sns.xkcd_palette(["cherry", "windows blue"]) diff --git a/package/MDAnalysis/analysis/rms.py b/package/MDAnalysis/analysis/rms.py index aabd8ae8866..049f242a08a 100644 --- a/package/MDAnalysis/analysis/rms.py +++ b/package/MDAnalysis/analysis/rms.py @@ -136,7 +136,7 @@ from __future__ import division, absolute_import from six.moves import zip -from six import string_types +from six import raise_from, string_types import numpy as np @@ -287,16 +287,24 @@ def process_selection(select): try: select = {'mobile': select[0], 'reference': select[1]} except IndexError: - raise IndexError("select must contain two selection strings " - "(reference, mobile)") + raise_from(IndexError( + "select must contain two selection strings " + "(reference, mobile)"), + None, + ) elif type(select) is dict: # compatability hack to use new nomenclature try: select['mobile'] select['reference'] except KeyError: - raise KeyError("select dictionary must contain entries for keys " - "'mobile' and 'reference'.") + raise_from( + KeyError( + "select dictionary must contain entries for keys " + "'mobile' and 'reference'." + ), + None, + ) else: raise TypeError("'select' must be either a string, 2-tuple, or dict") select['mobile'] = asiterable(select['mobile']) diff --git a/package/MDAnalysis/auxiliary/XVG.py b/package/MDAnalysis/auxiliary/XVG.py index c1847509bdf..c99ef1e635b 100644 --- a/package/MDAnalysis/auxiliary/XVG.py +++ b/package/MDAnalysis/auxiliary/XVG.py @@ -69,6 +69,7 @@ from __future__ import absolute_import from six.moves import range +from six import raise_from import numbers import os @@ -149,8 +150,13 @@ def _select_data(self, key): try: return self._data[key] except IndexError: - raise ValueError('{} not a valid index for data with {} ' - 'columns'.format(key, len(self._data))) + raise_from( + ValueError( + '{} not a valid index for data with {} ' + 'columns'.format(key, len(self._data)) + ), + None + ) else: return np.array([self._select_data(i) for i in key]) diff --git a/package/MDAnalysis/auxiliary/core.py b/package/MDAnalysis/auxiliary/core.py index 3c3f2c918ae..2f05a8c1d59 100644 --- a/package/MDAnalysis/auxiliary/core.py +++ b/package/MDAnalysis/auxiliary/core.py @@ -30,7 +30,7 @@ """ from __future__ import absolute_import -from six import string_types +from six import raise_from, string_types from . import _AUXREADERS from ..lib import util @@ -75,13 +75,19 @@ def get_auxreader_for(auxdata=None, format=None): try: return _AUXREADERS[format] except KeyError: - raise ValueError("Unknown auxiliary data format for auxdata: " - "{0}".format(auxdata)) + raise_from( + ValueError( + "Unknown auxiliary data format for auxdata: " + "{0}".format(auxdata)), + None + ) else: try: return _AUXREADERS[format] except KeyError: - raise ValueError("Unknown auxiliary data format {0}".format(format)) + raise_from( + ValueError("Unknown auxiliary data format {0}".format(format)), + None) def auxreader(auxdata, format=None, **kwargs): """ Return an auxiliary reader instance for *auxdata*. diff --git a/package/MDAnalysis/coordinates/CRD.py b/package/MDAnalysis/coordinates/CRD.py index 0d3e4de5ab0..cbcdf69057c 100644 --- a/package/MDAnalysis/coordinates/CRD.py +++ b/package/MDAnalysis/coordinates/CRD.py @@ -32,6 +32,7 @@ from __future__ import absolute_import from six.moves import zip, range +from six import raise_from import itertools import numpy as np @@ -80,9 +81,13 @@ def _read_first_frame(self): coords_list.append(np.array(line[45:100].split()[0:3], dtype=float)) else: coords_list.append(np.array(line[20:50].split()[0:3], dtype=float)) - except: - raise ValueError("Check CRD format at line {0}: {1}" - "".format(linenum, line.rstrip())) + except Exception: + raise_from( + ValueError( + "Check CRD format at line {0}: {1}" + "".format(linenum, line.rstrip())), + None + ) self.n_atoms = len(coords_list) diff --git a/package/MDAnalysis/coordinates/GRO.py b/package/MDAnalysis/coordinates/GRO.py index 25f42c409f3..723da8927ed 100644 --- a/package/MDAnalysis/coordinates/GRO.py +++ b/package/MDAnalysis/coordinates/GRO.py @@ -106,6 +106,8 @@ from __future__ import absolute_import from six.moves import range, zip +from six import raise_from + import itertools import warnings @@ -370,7 +372,7 @@ def write(self, obj): if isinstance(obj, base.Timestep): ag_or_ts = obj.copy() else: - raise TypeError("No Timestep found in obj argument") + raise_from(TypeError("No Timestep found in obj argument"), None) try: velocities = ag_or_ts.velocities diff --git a/package/MDAnalysis/coordinates/GSD.py b/package/MDAnalysis/coordinates/GSD.py index 60088912d12..e5968e32d34 100644 --- a/package/MDAnalysis/coordinates/GSD.py +++ b/package/MDAnalysis/coordinates/GSD.py @@ -46,6 +46,7 @@ """ from __future__ import absolute_import, division +from six import raise_from import numpy as np import os @@ -101,8 +102,8 @@ def _reopen(self): def _read_frame(self, frame): try : myframe = self._file[frame] - except IndexError : - raise IOError + except IndexError: + raise_from(IOError, None) # set frame number self._frame = frame diff --git a/package/MDAnalysis/coordinates/LAMMPS.py b/package/MDAnalysis/coordinates/LAMMPS.py index cd1fe002198..5f152b9902e 100644 --- a/package/MDAnalysis/coordinates/LAMMPS.py +++ b/package/MDAnalysis/coordinates/LAMMPS.py @@ -124,6 +124,7 @@ from __future__ import absolute_import from six.moves import zip, range, map +from six import raise_from import os import numpy as np @@ -161,7 +162,9 @@ def __init__(self, *args, **kwargs): if units.unit_types[unit] != unit_type: raise TypeError("LAMMPS DCDWriter: wrong unit {0!r} for unit type {1!r}".format(unit, unit_type)) except KeyError: - raise ValueError("LAMMPS DCDWriter: unknown unit {0!r}".format(unit)) + raise_from( + ValueError("LAMMPS DCDWriter: unknown unit {0!r}".format(unit)), + None) super(DCDWriter, self).__init__(*args, **kwargs) @@ -341,9 +344,10 @@ def _write_bonds(self, bonds): self.f.write('{:d} {:d} '.format(i, int(bond.type))+\ ' '.join((bond.atoms.indices + 1).astype(str))+'\n') except TypeError: - raise TypeError('LAMMPS DATAWriter: Trying to write bond, ' + raise_from(TypeError('LAMMPS DATAWriter: Trying to write bond, ' 'but bond type {} is not ' - 'numerical.'.format(bond.type)) + 'numerical.'.format(bond.type)), + None) def _write_dimensions(self, dimensions): """Convert dimensions to triclinic vectors, convert lengths to native @@ -402,8 +406,11 @@ def write(self, selection, frame=None): try: atoms.types.astype(np.int32) except ValueError: - raise ValueError('LAMMPS.DATAWriter: atom types must be '+ - 'convertible to integers') + raise_from( + ValueError( + 'LAMMPS.DATAWriter: atom types must be ' + 'convertible to integers'), + None) try: velocities = atoms.velocities diff --git a/package/MDAnalysis/coordinates/MOL2.py b/package/MDAnalysis/coordinates/MOL2.py index 948ef58b7e2..67d9fa67b71 100644 --- a/package/MDAnalysis/coordinates/MOL2.py +++ b/package/MDAnalysis/coordinates/MOL2.py @@ -112,6 +112,7 @@ """ from __future__ import absolute_import +from six import raise_from import numpy as np @@ -219,8 +220,9 @@ def _read_frame(self, frame): try: block = self.frames[frame] except IndexError: - raise IOError("Invalid frame {0} for trajectory with length {1}" - "".format(frame, len(self))) + raise_from(IOError("Invalid frame {0} for trajectory with length {1}" + "".format(frame, len(self))), + None) sections, coords = self.parse_block(block) @@ -314,8 +316,9 @@ def encode_block(self, obj): try: molecule = ts.data['molecule'] except KeyError: - raise NotImplementedError( - "MOL2Writer cannot currently write non MOL2 data") + raise_from(NotImplementedError( + "MOL2Writer cannot currently write non MOL2 data"), + None) # Need to remap atom indices to 1 based in this selection mapping = {a: i for i, a in enumerate(obj.atoms, start=1)} diff --git a/package/MDAnalysis/coordinates/PDB.py b/package/MDAnalysis/coordinates/PDB.py index ffb275ce3ec..ef530e8b4f7 100644 --- a/package/MDAnalysis/coordinates/PDB.py +++ b/package/MDAnalysis/coordinates/PDB.py @@ -143,7 +143,7 @@ from __future__ import absolute_import from six.moves import range, zip -from six import StringIO, BytesIO +from six import raise_from, StringIO, BytesIO import io import os @@ -367,7 +367,7 @@ def _read_frame(self, frame): start = self._start_offsets[frame] stop = self._stop_offsets[frame] except IndexError: # out of range of known frames - raise IOError + raise_from(IOError, None) pos = 0 occupancy = np.ones(self.n_atoms) @@ -836,8 +836,12 @@ def write_next_timestep(self, ts=None, **kwargs): try: ts = self.ts except AttributeError: - raise NoDataError("PBDWriter: no coordinate data to write to " - "trajectory file") + raise_from( + NoDataError( + "PBDWriter: no coordinate data to write to " + "trajectory file" + ), + None) self._check_pdb_coordinates() self._write_timestep(ts, **kwargs) diff --git a/package/MDAnalysis/coordinates/TRJ.py b/package/MDAnalysis/coordinates/TRJ.py index 7ff3f15d495..d926d286b26 100644 --- a/package/MDAnalysis/coordinates/TRJ.py +++ b/package/MDAnalysis/coordinates/TRJ.py @@ -154,6 +154,8 @@ """ from __future__ import (absolute_import, division, print_function, unicode_literals) +from six import raise_from + import scipy.io.netcdf import numpy as np import warnings @@ -498,7 +500,7 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): errmsg = "NCDF trajectory {0} is missing Conventions".format( self.filename) logger.fatal(errmsg) - raise ValueError(errmsg) + raise_from(ValueError(errmsg), None) # AMBER NetCDF files should also have a ConventionVersion try: @@ -512,7 +514,7 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): except AttributeError: errmsg = "NCDF trajectory {0} is missing ConventionVersion".format( self.filename) - raise ValueError(errmsg) + raise_from(ValueError(errmsg), None) # The AMBER NetCDF standard enforces 64 bit offsets if not self.trjfile.version_byte == 2: @@ -531,7 +533,7 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): raise TypeError(errmsg) except KeyError: errmsg = "NCDF trajectory does not contain spatial dimension" - raise ValueError(errmsg) + raise_from(ValueError(errmsg), None) # AMBER NetCDF specs require program and programVersion. Warn users # if those attributes do not exist @@ -553,7 +555,7 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): except KeyError: errmsg = ("NCDF trajectory {0} does not contain atom " "information".format(self.filename)) - raise ValueError(errmsg) + raise_from(ValueError(errmsg), None) try: self.n_frames = self.trjfile.dimensions['frame'] @@ -565,9 +567,12 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): if self.n_frames is None: self.n_frames = self.trjfile.variables['time'].shape[0] except KeyError: - errmsg = ("NCDF trajectory {0} does not contain frame " - "information".format(self.filename)) - raise ValueError(errmsg) + raise_from( + ValueError( + ("NCDF trajectory {0} does not contain frame " + "information").format(self.filename) + ), + None) try: self.remarks = self.trjfile.title @@ -709,7 +714,7 @@ def _read_next_timestep(self, ts=None): try: return self._read_frame(self._current_frame + 1) except IndexError: - raise IOError + raise_from(IOError, None) def _get_dt(self): t1 = self.trjfile.variables['time'][1] diff --git a/package/MDAnalysis/coordinates/TRZ.py b/package/MDAnalysis/coordinates/TRZ.py index a469ee09aba..752fdf60dcf 100644 --- a/package/MDAnalysis/coordinates/TRZ.py +++ b/package/MDAnalysis/coordinates/TRZ.py @@ -270,7 +270,7 @@ def _read_next_timestep(self, ts=None): ts._forces[:, 1] = data['fy'] ts._forces[:, 2] = data['fz'] except IndexError: # Raises indexerror if data has no data (EOF) - raise IOError + six.raise_from(IOError, None) else: # Convert things read into MDAnalysis' native formats (nm -> angstroms) if self.convert_units: diff --git a/package/MDAnalysis/coordinates/TXYZ.py b/package/MDAnalysis/coordinates/TXYZ.py index c8c7dc379a3..7103fe9210b 100644 --- a/package/MDAnalysis/coordinates/TXYZ.py +++ b/package/MDAnalysis/coordinates/TXYZ.py @@ -47,6 +47,7 @@ """ from __future__ import absolute_import, division from six.moves import range +from six import raise_from import numpy as np import os @@ -154,7 +155,7 @@ def _read_next_timestep(self, ts=None): ts.frame += 1 return ts except (ValueError, IndexError) as err: - raise EOFError(err) + raise_from(EOFError(err), None) def _reopen(self): self.close() diff --git a/package/MDAnalysis/coordinates/XYZ.py b/package/MDAnalysis/coordinates/XYZ.py index 149467f5c04..470f8fecb3b 100644 --- a/package/MDAnalysis/coordinates/XYZ.py +++ b/package/MDAnalysis/coordinates/XYZ.py @@ -204,7 +204,7 @@ def write(self, obj): if isinstance(obj, base.Timestep): ts = obj else: - raise TypeError("No Timestep found in obj argument") + six.raise_from(TypeError("No Timestep found in obj argument"), None) else: if hasattr(obj, 'universe'): # For AtomGroup and children (Residue, ResidueGroup, Segment) @@ -376,7 +376,7 @@ def _read_next_timestep(self, ts=None): ts.frame += 1 return ts except (ValueError, IndexError) as err: - raise EOFError(err) + six.raise_from(EOFError(err), None) def _reopen(self): self.close() diff --git a/package/MDAnalysis/coordinates/base.py b/package/MDAnalysis/coordinates/base.py index d29b741fd75..4a5023d311f 100644 --- a/package/MDAnalysis/coordinates/base.py +++ b/package/MDAnalysis/coordinates/base.py @@ -508,23 +508,33 @@ def copy_slice(self, sel): except NoDataError: # It's cool if there's no Data, we'll live pos = None - except: - raise TypeError("Selection type must be compatible with slicing" - " the coordinates") + except Exception: + six.raise_from( + TypeError( + "Selection type must be compatible with slicing" + " the coordinates" + ), + None) try: vel = self.velocities[sel, :] except NoDataError: vel = None - except: - raise TypeError("Selection type must be compatible with slicing" - " the coordinates") + except Exception: + six.raise_from( + TypeError("Selection type must be compatible with slicing" + " the coordinates"), + None) try: force = self.forces[sel, :] except NoDataError: force = None - except: - raise TypeError("Selection type must be compatible with slicing" - " the coordinates") + except Exception: + six.raise_from( + TypeError( + "Selection type must be compatible with slicing" + " the coordinates" + ), + None) new_TS = self.__class__.from_coordinates( positions=pos, @@ -1408,7 +1418,7 @@ def next(self): ts = self._read_next_timestep() except (EOFError, IOError): self.rewind() - raise StopIteration + six.raise_from(StopIteration, None) else: for auxname in self.aux_list: ts = self._auxs[auxname].update_ts(ts) @@ -1592,8 +1602,11 @@ def _sliced_iter(self, start, stop, step): yield self._read_frame_with_aux(i) self.rewind() except TypeError: # if _read_frame not implemented - raise TypeError("{0} does not support slicing." - "".format(self.__class__.__name__)) + six.raise_from( + TypeError( + "{0} does not support slicing." + "".format(self.__class__.__name__)), + None) def check_slice_indices(self, start, stop, step): """Check frame indices are valid and clip to fit trajectory. @@ -2012,7 +2025,11 @@ def add_transformations(self, *transformations): try: self.transformations = transformations except ValueError: - raise ValueError("Can't add transformations again. Please create new Universe object") + six.raise_from( + ValueError( + "Can't add transformations again. " + "Please create new Universe object"), + None) else: self.ts = self._apply_transformations(self.ts) @@ -2176,7 +2193,7 @@ def write(self, obj): # special case: can supply a Universe, too... ts = obj.trajectory.ts except AttributeError: - raise TypeError("No Timestep found in obj argument") + six.raise_from(TypeError("No Timestep found in obj argument"), None) return self.write_next_timestep(ts) def __del__(self): diff --git a/package/MDAnalysis/coordinates/core.py b/package/MDAnalysis/coordinates/core.py index 8f3c0b8aea4..47d05b110bb 100644 --- a/package/MDAnalysis/coordinates/core.py +++ b/package/MDAnalysis/coordinates/core.py @@ -84,8 +84,14 @@ def reader(filename, format=None, **kwargs): try: return Reader(filename, **kwargs) except ValueError: - raise TypeError('Unable to read {fn} with {r}.'.format(fn=filename, - r=Reader)) + six.raise_from( + TypeError( + 'Unable to read {fn} with {r}.'.format( + fn=filename, + r=Reader + ) + ), + None) def writer(filename, n_atoms=None, **kwargs): diff --git a/package/MDAnalysis/coordinates/memory.py b/package/MDAnalysis/coordinates/memory.py index 2ce79adf93a..75add35f419 100644 --- a/package/MDAnalysis/coordinates/memory.py +++ b/package/MDAnalysis/coordinates/memory.py @@ -185,6 +185,7 @@ """ from __future__ import absolute_import +from six import raise_from import logging import errno import numpy as np @@ -315,10 +316,11 @@ def __init__(self, coordinate_array, order='fac', try: if coordinate_array.ndim == 2 and coordinate_array.shape[1] == 3: coordinate_array = coordinate_array[np.newaxis, :, :] - except AttributeError as e: - raise TypeError("The input has to be a numpy.ndarray that " + except AttributeError: + raise_from(TypeError("The input has to be a numpy.ndarray that " "corresponds to the layout specified by the " - "'order' keyword.") + "'order' keyword."), + None) self.set_array(coordinate_array, order) self.n_frames = \ @@ -330,8 +332,10 @@ def __init__(self, coordinate_array, order='fac', try: velocities = np.asarray(velocities, dtype=np.float32) except ValueError: - raise TypeError("'velocities' must be array-like got {}" - "".format(type(velocities))) + raise_from( + TypeError("'velocities' must be array-like got {}" + "".format(type(velocities))), + None) # if single frame, make into array of 1 frame if velocities.ndim == 2: velocities = velocities[np.newaxis, :, :] @@ -348,8 +352,9 @@ def __init__(self, coordinate_array, order='fac', try: forces = np.asarray(forces, dtype=np.float32) except ValueError: - raise TypeError("'forces' must be array like got {}" - "".format(type(forces))) + raise_from(TypeError("'forces' must be array like got {}" + "".format(type(forces))), + None) if forces.ndim == 2: forces = forces[np.newaxis, :, :] if not forces.shape == self.coordinate_array.shape: @@ -377,8 +382,9 @@ def __init__(self, coordinate_array, order='fac', try: dimensions = np.asarray(dimensions, dtype=np.float32) except ValueError: - raise TypeError("'dimensions' must be array-like got {}" - "".format(type(dimensions))) + raise_from(TypeError("'dimensions' must be array-like got {}" + "".format(type(dimensions))), + None) if dimensions.shape == (6,): # single box, tile this to trajectory length # allows modifying the box of some frames diff --git a/package/MDAnalysis/core/__init__.py b/package/MDAnalysis/core/__init__.py index e6065f9d0e6..04ec4affb5a 100644 --- a/package/MDAnalysis/core/__init__.py +++ b/package/MDAnalysis/core/__init__.py @@ -265,7 +265,10 @@ def set(self, value): try: self.value = self.mapping[value] except KeyError: - raise ValueError("flag must be None or one of " + str(self.mapping.keys())) + six.raise_from( + ValueError("flag must be None or one of " + str(self.mapping.keys())), + None) + return self.get() def prop(self): diff --git a/package/MDAnalysis/core/_get_readers.py b/package/MDAnalysis/core/_get_readers.py index ecb19739f3d..971a9d98a66 100644 --- a/package/MDAnalysis/core/_get_readers.py +++ b/package/MDAnalysis/core/_get_readers.py @@ -20,6 +20,7 @@ """ from __future__ import absolute_import +from six import raise_from import copy import inspect @@ -97,7 +98,7 @@ def get_reader_for(filename, format=None): try: return _READERS[format] except KeyError: - raise ValueError( + raise_from(ValueError( "Unknown coordinate trajectory format '{0}' for '{1}'. The FORMATs \n" " {2}\n" " are implemented in MDAnalysis.\n" @@ -105,7 +106,8 @@ def get_reader_for(filename, format=None): " Use the format keyword to explicitly set the format: 'Universe(...,format=FORMAT)'\n" " For missing formats, raise an issue at " "http://issues.mdanalysis.org".format( - format, filename, _READERS.keys())) + format, filename, _READERS.keys())), + None) def get_writer_for(filename, format=None, multiframe=None): @@ -168,8 +170,10 @@ def get_writer_for(filename, format=None, multiframe=None): # be manipulated as a string. # A TypeError is raised in py3.6 # "TypeError: expected str, bytes or os.PathLike object" - raise ValueError('File format could not be guessed from "{0}"' - .format(filename)) + raise_from( + ValueError('File format could not be guessed from "{0}"' + .format(filename)), + None) else: format = util.check_compressed_format(root, ext) format = format.upper() @@ -192,7 +196,7 @@ def get_writer_for(filename, format=None, multiframe=None): try: return options[format] except KeyError: - raise TypeError(errmsg.format(format)) + raise_from(TypeError(errmsg.format(format)), None) def get_parser_for(filename, format=None): @@ -231,7 +235,8 @@ def get_parser_for(filename, format=None): try: rdr = get_reader_for(filename) except ValueError: - raise ValueError( + raise_from( + ValueError( "'{0}' isn't a valid topology format, nor a coordinate format\n" " from which a topology can be minimally inferred.\n" " You can use 'Universe(topology, ..., topology_format=FORMAT)'\n" @@ -240,6 +245,7 @@ def get_parser_for(filename, format=None): " {1}\n" " See https://docs.mdanalysis.org/documentation_pages/topology/init.html#supported-topology-formats\n" " For missing formats, raise an issue at \n" - " http://issues.mdanalysis.org".format(format, _PARSERS.keys())) + " http://issues.mdanalysis.org".format(format, _PARSERS.keys())), + None) else: return _PARSERS['MINIMAL'] diff --git a/package/MDAnalysis/core/groups.py b/package/MDAnalysis/core/groups.py index e8fadce077f..95e38e600a3 100644 --- a/package/MDAnalysis/core/groups.py +++ b/package/MDAnalysis/core/groups.py @@ -90,7 +90,7 @@ """ from __future__ import absolute_import, division from six.moves import zip -from six import string_types +from six import raise_from, string_types from collections import namedtuple import numpy as np @@ -122,11 +122,16 @@ def _unpickle(uhash, ix): except KeyError: # doesn't provide as nice an error message as before as only hash of universe is stored # maybe if we pickled the filename too we could do better... - raise RuntimeError( - "Couldn't find a suitable Universe to unpickle AtomGroup onto " - "with Universe hash '{}'. Available hashes: {}" - "".format(uhash, ', '.join([str(k) - for k in _ANCHOR_UNIVERSES.keys()]))) + raise_from( + RuntimeError( + "Couldn't find a suitable Universe to unpickle AtomGroup onto " + "with Universe hash '{}'. Available hashes: {}" + "".format( + uhash, + ', '.join([str(k) for k in _ANCHOR_UNIVERSES.keys()]) + ) + ), + None) return u.atoms[ix] def _unpickle_uag(basepickle, selections, selstrs): @@ -319,9 +324,12 @@ def __new__(cls, *args, **kwargs): u = arg.universe break else: - raise TypeError("No universe, or universe-containing " - "object passed to the initialization of " - "{}".format(cls.__name__)) + raise_from( + TypeError( + "No universe, or universe-containing " + "object passed to the initialization of " + "{}".format(cls.__name__)), + None) try: return object.__new__(u._classes[cls]) except KeyError: @@ -331,11 +339,12 @@ def __new__(cls, *args, **kwargs): for parent in cls.mro() if parent in u._class_bases) except StopIteration: - raise TypeError("Attempted to instantiate class '{}' but " + raise_from(TypeError("Attempted to instantiate class '{}' but " "none of its parents are known to the " "universe. Currently possible parent " "classes are: {}".format(cls.__name__, - str(sorted(u._class_bases.keys())))) + str(sorted(u._class_bases.keys())))), + None) newcls = u._classes[cls] = parent_cls._mix(cls) return object.__new__(newcls) @@ -457,11 +466,12 @@ def __init__(self, *args): ix, u = args except (AttributeError, # couldn't find ix/universe TypeError): # couldn't iterate the object we got - raise TypeError( + raise_from(TypeError( "Can only initialise a Group from an iterable of Atom/Residue/" "Segment objects eg: AtomGroup([Atom1, Atom2, Atom3]) " "or an iterable of indices and a Universe reference " - "eg: AtomGroup([0, 5, 7, 8], u).") + "eg: AtomGroup([0, 5, 7, 8], u)."), + None) # indices for the objects I hold self._ix = np.asarray(ix, dtype=np.intp) @@ -774,14 +784,14 @@ def center(self, weights, pbc=None, compound='group', unwrap=False): try: compound_indices = atoms.molnums except AttributeError: - raise NoDataError("Cannot use compound='molecules': " - "No molecule information in topology.") + raise_from(NoDataError("Cannot use compound='molecules': " + "No molecule information in topology."), None) elif comp == 'fragments': try: compound_indices = atoms.fragindices except NoDataError: - raise NoDataError("Cannot use compound='fragments': " - "No bond information in topology.") + raise_from(NoDataError("Cannot use compound='fragments': " + "No bond information in topology."), None) else: raise ValueError("Unrecognized compound definition: {}\nPlease use" " one of 'group', 'residues', 'segments', " @@ -984,14 +994,18 @@ def accumulate(self, attribute, function=np.sum, compound='group'): try: compound_indices = atoms.molnums except AttributeError: - raise NoDataError("Cannot use compound='molecules': " - "No molecule information in topology.") + raise_from( + NoDataError("Cannot use compound='molecules': " + "No molecule information in topology."), + None) elif comp == 'fragments': try: compound_indices = atoms.fragindices except NoDataError: - raise NoDataError("Cannot use compound='fragments': " - "No bond information in topology.") + raise_from( + NoDataError("Cannot use compound='fragments': " + "No bond information in topology."), + None) else: raise ValueError("Unrecognized compound definition: '{}'. Please " "use one of 'group', 'residues', 'segments', " @@ -1479,14 +1493,16 @@ def wrap(self, compound="atoms", center="com", box=None, inplace=True): try: compound_indices = atoms.molnums except AttributeError: - raise NoDataError("Cannot use compound='molecules', " - "this requires molnums.") + raise_from(NoDataError("Cannot use compound='molecules', " + "this requires molnums."), None) else: # comp == 'fragments' try: compound_indices = atoms.fragindices except NoDataError: - raise NoDataError("Cannot use compound='fragments', " - "this requires bonds.") + raise_from( + NoDataError("Cannot use compound='fragments', " + "this requires bonds."), + None) # compute required shifts: if ctr == 'com': @@ -1641,8 +1657,8 @@ def unwrap(self, compound='fragments', reference='com', inplace=True): try: compound_indices = unique_atoms.molnums except AttributeError: - raise NoDataError("Cannot use compound='molecules', this " - "requires molnums.") + raise_from(NoDataError("Cannot use compound='molecules', this " + "requires molnums."), None) # Now process every compound: unique_compound_indices = unique_int_1d(compound_indices) positions = unique_atoms.positions @@ -2326,11 +2342,11 @@ def residues(self, new): try: r_ix = [r.resindex for r in new] except AttributeError: - raise TypeError("Can only set AtomGroup residues to Residue " + raise_from(TypeError("Can only set AtomGroup residues to Residue " "or ResidueGroup not {}".format( ', '.join(type(r) for r in new if not isinstance(r, Residue)) - )) + )), None) if not isinstance(r_ix, itertools.cycle) and len(r_ix) != len(self): raise ValueError("Incorrect size: {} for AtomGroup of size: {}" "".format(len(new), len(self))) @@ -2503,7 +2519,7 @@ def velocities(self): try: return np.array(ts.velocities[self.ix]) except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain velocities") + raise_from(NoDataError("Timestep does not contain velocities"), None) @velocities.setter def velocities(self, values): @@ -2511,7 +2527,7 @@ def velocities(self, values): try: ts.velocities[self.ix, :] = values except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain velocities") + raise_from(NoDataError("Timestep does not contain velocities"), None) @property def forces(self): @@ -2537,7 +2553,7 @@ def forces(self): try: return ts.forces[self.ix] except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain forces") + raise_from(NoDataError("Timestep does not contain forces"), None) @forces.setter def forces(self, values): @@ -2545,7 +2561,7 @@ def forces(self, values): try: ts.forces[self.ix, :] = values except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain forces") + raise_from(NoDataError("Timestep does not contain forces"), None) @property def ts(self): @@ -2883,13 +2899,18 @@ def split(self, level): try: levelindices = getattr(self, accessors[level]) except AttributeError: - raise AttributeError('This universe does not have {} ' + raise_from(AttributeError('This universe does not have {} ' 'information. Maybe it is not provided in the ' - 'topology format in use.'.format(level)) + 'topology format in use.'.format(level)), + None) except KeyError: - raise ValueError("level = '{0}' not supported, " - "must be one of {1}".format(level, - accessors.keys())) + raise_from( + ValueError( + ( + "level = '{0}' not supported, " + "must be one of {1}").format(level, accessors.keys()) + ), + None) return [self[levelindices == index] for index in unique_int_1d(levelindices)] @@ -3243,11 +3264,15 @@ def segments(self, new): try: s_ix = [s.segindex for s in new] except AttributeError: - raise TypeError("Can only set ResidueGroup segments to Segment " - "or SegmentGroup, not {}".format( - ', '.join(type(r) for r in new + raise_from( + TypeError( + "Can only set ResidueGroup segments to Segment " + "or SegmentGroup, not {}".format( + ', '.join(type(r) for r in new if not isinstance(r, Segment)) - )) + ) + ), + None) if not isinstance(s_ix, itertools.cycle) and len(s_ix) != len(self): raise ValueError("Incorrect size: {} for ResidueGroup of size: {}" "".format(len(new), len(self))) @@ -3648,7 +3673,7 @@ def velocity(self): try: return ts.velocities[self.ix].copy() except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain velocities") + raise_from(NoDataError("Timestep does not contain velocities"), None) @velocity.setter def velocity(self, values): @@ -3656,7 +3681,7 @@ def velocity(self, values): try: ts.velocities[self.ix, :] = values except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain velocities") + raise_from(NoDataError("Timestep does not contain velocities"), None) @property def force(self): @@ -3679,7 +3704,7 @@ def force(self): try: return ts.forces[self.ix].copy() except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain forces") + raise_from(NoDataError("Timestep does not contain forces"), None) @force.setter def force(self, values): @@ -3687,7 +3712,7 @@ def force(self, values): try: ts.forces[self.ix, :] = values except (AttributeError, NoDataError): - raise NoDataError("Timestep does not contain forces") + raise_from(NoDataError("Timestep does not contain forces"), None) class Residue(ComponentBase): diff --git a/package/MDAnalysis/core/selection.py b/package/MDAnalysis/core/selection.py index 2d0e84c94a7..34f0b748e48 100644 --- a/package/MDAnalysis/core/selection.py +++ b/package/MDAnalysis/core/selection.py @@ -489,7 +489,9 @@ def __init__(self, parser, tokens): try: self.grp = parser.selgroups[grpname] except KeyError: - raise ValueError("Failed to find group: {0}".format(grpname)) + six.raise_from( + ValueError("Failed to find group: {0}".format(grpname)), + None) def apply(self, group): mask = np.in1d(group.indices, self.grp.indices) @@ -504,7 +506,9 @@ def __init__(self, parser, tokens): try: self.grp = parser.selgroups[grpname] except KeyError: - raise ValueError("Failed to find group: {0}".format(grpname)) + six.raise_from( + ValueError("Failed to find group: {0}".format(grpname)), + None) @deprecate(old_name='fullgroup', new_name='global group', message=' This will be removed in v0.15.0') @@ -641,8 +645,8 @@ def apply(self, group): # if no icodes and icodes are part of selection, cause a fuss if (any(v[1] for v in self.uppers) or any(v[1] for v in self.lowers)): - raise ValueError("Selection specified icodes, while the " - "topology doesn't have any.") + six.raise_from(ValueError("Selection specified icodes, while the " + "topology doesn't have any."), None) if not icodes is None: mask = self._sel_with_icodes(vals, icodes) @@ -730,8 +734,8 @@ def __init__(self, parser, tokens): # check if in appropriate format 'lower:upper' or 'lower-upper' selrange = re.match("(\d+)[:-](\d+)", val) if not selrange: - raise ValueError( - "Failed to parse number: {0}".format(val)) + six.raise_from(ValueError( + "Failed to parse number: {0}".format(val)), None) lower, upper = np.int64(selrange.groups()) lowers.append(lower) @@ -1001,9 +1005,10 @@ def __init__(self, parser, tokens): try: self.operator = self.ops[oper] except KeyError: - raise ValueError( + six.raise_from(ValueError( "Invalid operator : '{0}' Use one of : '{1}'" - "".format(oper, self.ops.keys())) + "".format(oper, self.ops.keys())), + None) self.value = float(value) def apply(self, group): @@ -1015,9 +1020,9 @@ def apply(self, group): elif self.prop == 'charge': values = group.charges else: - raise SelectionError( + six.raise_from(SelectionError( "Expected one of : {0}" - "".format(['x', 'y', 'z', 'mass', 'charge'])) + "".format(['x', 'y', 'z', 'mass', 'charge'])), None) else: values = group.positions[:, col] @@ -1190,9 +1195,13 @@ def _parse_subexp(self): try: return _SELECTIONDICT[op](self, self.tokens) except KeyError: - raise SelectionError("Unknown selection token: '{0}'".format(op)) + six.raise_from( + SelectionError("Unknown selection token: '{0}'".format(op)), + None) except ValueError as e: - raise SelectionError("Selection failed: '{0}'".format(e)) + six.raise_from( + SelectionError("Selection failed: '{0}'".format(e)), + None) # The module level instance diff --git a/package/MDAnalysis/core/topologyattrs.py b/package/MDAnalysis/core/topologyattrs.py index 532e91eeb1e..60b49998df7 100644 --- a/package/MDAnalysis/core/topologyattrs.py +++ b/package/MDAnalysis/core/topologyattrs.py @@ -487,8 +487,10 @@ def getattr__(atomgroup, name): try: return atomgroup._get_named_atom(name) except selection.SelectionError: - raise AttributeError("'{0}' object has no attribute '{1}'".format( - atomgroup.__class__.__name__, name)) + six.raise_from( + AttributeError("'{0}' object has no attribute '{1}'".format( + atomgroup.__class__.__name__, name)), + None) def _get_named_atom(group, name): """Get all atoms with name *name* in the current AtomGroup. @@ -1347,8 +1349,10 @@ def getattr__(residuegroup, resname): try: return residuegroup._get_named_residue(resname) except selection.SelectionError: - raise AttributeError("'{0}' object has no attribute '{1}'".format( - residuegroup.__class__.__name__, resname)) + six.raise_from( + AttributeError("'{0}' object has no attribute '{1}'".format( + residuegroup.__class__.__name__, resname)), + None) transplants[ResidueGroup].append(('__getattr__', getattr__)) # This transplant is hardcoded for now to allow for multiple getattr things @@ -1481,9 +1485,9 @@ def sequence(self, **kwargs): try: sequence = "".join([convert_aa_code(r) for r in self.residues.resnames]) except KeyError as err: - raise ValueError("AtomGroup contains a residue name '{0}' that " + six.raise_from(ValueError("AtomGroup contains a residue name '{0}' that " "does not have a IUPAC protein 1-letter " - "character".format(err.message)) + "character".format(err.message)), None) if format == "string": return sequence seq = Bio.Seq.Seq(sequence, alphabet=Bio.Alphabet.IUPAC.protein) @@ -1589,8 +1593,10 @@ def getattr__(segmentgroup, segid): try: return segmentgroup._get_named_segment(segid) except selection.SelectionError: - raise AttributeError("'{0}' object has no attribute '{1}'".format( - segmentgroup.__class__.__name__, segid)) + six.raise_from( + AttributeError("'{0}' object has no attribute '{1}'".format( + segmentgroup.__class__.__name__, segid)), + None) transplants[SegmentGroup].append( ('__getattr__', getattr__)) diff --git a/package/MDAnalysis/core/topologyobjects.py b/package/MDAnalysis/core/topologyobjects.py index 0475cf432f6..d41c0b30cc0 100644 --- a/package/MDAnalysis/core/topologyobjects.py +++ b/package/MDAnalysis/core/topologyobjects.py @@ -31,6 +31,7 @@ from __future__ import print_function, absolute_import, division from six.moves import zip +from six import raise_from import numbers import numpy as np import functools @@ -812,8 +813,11 @@ def atom3(self): return self._ags[2] except IndexError: nvert = _BTYPE_TO_SHAPE[self.btype] - raise IndexError("TopologyGroup of {}s only has {} vertical AtomGroups" - "".format(self.btype, nvert)) + raise_from( + IndexError( + "TopologyGroup of {}s only has {} vertical AtomGroups".format( + self.btype, nvert)), + None) @property def atom4(self): @@ -822,8 +826,11 @@ def atom4(self): return self._ags[3] except IndexError: nvert = _BTYPE_TO_SHAPE[self.btype] - raise IndexError("TopologyGroup of {}s only has {} vertical AtomGroups" - "".format(self.btype, nvert)) + raise_from( + IndexError( + "TopologyGroup of {}s only has {} vertical AtomGroups".format( + self.btype, nvert)), + None) # Distance calculation methods below # "Slow" versions exist as a way of testing the Cython implementations diff --git a/package/MDAnalysis/core/universe.py b/package/MDAnalysis/core/universe.py index 5594ce4a209..b631d75a41a 100644 --- a/package/MDAnalysis/core/universe.py +++ b/package/MDAnalysis/core/universe.py @@ -300,15 +300,16 @@ def __init__(self, *args, **kwargs): six.reraise(*sys.exc_info()) else: # Runs when the parser fails - raise IOError( + six.raise_from(IOError( "Failed to load from the topology file {0}" " with parser {1}.\n" - "Error: {2}".format(self.filename, parser, err)) + "Error: {2}".format(self.filename, parser, err)), + None) except (ValueError, NotImplementedError) as err: - raise ValueError( + six.raise_from(ValueError( "Failed to construct topology from file {0}" " with parser {1}.\n" - "Error: {2}".format(self.filename, parser, err)) + "Error: {2}".format(self.filename, parser, err)), None) # generate and populate Universe version of each class self._generate_from_topology() @@ -509,7 +510,7 @@ def __getattr__(self, key): try: segment = self._instant_selectors[key] except KeyError: - raise AttributeError('No attribute "{}".'.format(key)) + six.raise_from(AttributeError('No attribute "{}".'.format(key)), None) else: warnings.warn("Instant selector Universe. " "is deprecated and will be removed in 1.0. " @@ -860,13 +861,13 @@ def add_TopologyAttr(self, topologyattr, values=None): try: tcls = _TOPOLOGY_ATTRS[topologyattr] except KeyError: - raise ValueError( + six.raise_from(ValueError( "Unrecognised topology attribute name: '{}'." " Possible values: '{}'\n" "To raise an issue go to: http://issues.mdanalysis.org" "".format( - topologyattr, ', '.join(sorted(_TOPOLOGY_ATTRS.keys()))) - ) + topologyattr, ', '.join(sorted(_TOPOLOGY_ATTRS.keys())))), + None) else: topologyattr = tcls.from_blank( n_atoms=self._topology.n_atoms, diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index 5a3ba55fb30..df599be5810 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -68,6 +68,7 @@ """ from __future__ import division, absolute_import from six.moves import range +from six import raise_from import numpy as np from numpy.lib.utils import deprecate @@ -99,8 +100,11 @@ def _run(funcname, args=None, kwargs=None, backend="serial"): try: func = getattr(_distances[backend], funcname) except KeyError: - raise ValueError("Function {0} not available with backend {1}; try one " - "of: {2}".format(funcname, backend, _distances.keys())) + raise_from( + ValueError( + "Function {0} not available with backend {1}; try one " + "of: {2}".format(funcname, backend, _distances.keys())), + None) return func(*args, **kwargs) # serial versions are always available (and are typically used within diff --git a/package/MDAnalysis/lib/util.py b/package/MDAnalysis/lib/util.py index 18627e859d1..8103457de84 100644 --- a/package/MDAnalysis/lib/util.py +++ b/package/MDAnalysis/lib/util.py @@ -852,7 +852,9 @@ def fileno(self): return self.stream.fileno() except AttributeError: # IOBase.fileno does not raise IOError as advertised so we do this here - raise IOError("This NamedStream does not use a file descriptor.") + six.raise_from( + IOError("This NamedStream does not use a file descriptor."), + None) def readline(self): try: @@ -955,9 +957,11 @@ def check_compressed_format(root, ext): if ext.lower() in ("bz2", "gz"): try: root, ext = get_ext(root) - except: - raise TypeError("Cannot determine coordinate format for '{0}.{1}'" - "".format(root, ext)) + except Exception: + six.raise_from( + TypeError("Cannot determine coordinate format for '{0}.{1}'" + "".format(root, ext)), + None) return ext.upper() @@ -980,11 +984,12 @@ def format_from_filename_extension(filename): """ try: root, ext = get_ext(filename) - except: - raise TypeError( + except Exception: + six.raise_from(TypeError( "Cannot determine file format for file '{0}'.\n" " You can set the format explicitly with " - "'Universe(..., format=FORMAT)'.".format(filename)) + "'Universe(..., format=FORMAT)'.".format(filename)), + None) format = check_compressed_format(root, ext) return format @@ -1022,8 +1027,10 @@ def guess_format(filename): format = format_from_filename_extension(filename.name) except AttributeError: # format is None so we need to complain: - raise ValueError("guess_format requires an explicit format specifier " - "for stream {0}".format(filename)) + six.raise_from( + ValueError("guess_format requires an explicit format specifier " + "for stream {0}".format(filename)), + None) else: # iterator, list, filename: simple extension checking... something more # complicated is left for the ambitious. @@ -1110,7 +1117,11 @@ def read(self, line): try: return self.convertor(line[self.start:self.stop]) except ValueError: - raise ValueError("{0!r}: Failed to read&convert {1!r}".format(self, line[self.start:self.stop])) + six.raise_from( + ValueError( + "{0!r}: Failed to read&convert {1!r}".format( + self, line[self.start:self.stop])), + None) def __len__(self): """Length of the field in columns (stop - start)""" @@ -1344,7 +1355,9 @@ def get_weights(atoms, weights): try: weights = atoms.masses except AttributeError: - raise TypeError("weights='mass' selected but atoms.masses is missing") + six.raise_from( + TypeError("weights='mass' selected but atoms.masses is missing"), + None) if iterable(weights): if len(np.asarray(weights).shape) != 1: @@ -1424,7 +1437,11 @@ def convert_aa_code(x): try: return d[x.upper()] except KeyError: - raise ValueError("No conversion for {0} found (1 letter -> 3 letter or 3/4 letter -> 1 letter)".format(x)) + six.raise_from( + ValueError( + "No conversion for {0} found (1 letter -> 3 letter or 3/4 letter -> 1 letter)".format(x) + ), + None) #: Regular expression to match and parse a residue-atom selection; will match @@ -1674,8 +1691,8 @@ def __getattr__(self, key): try: return dict.__getitem__(self, key) except KeyError: - raise AttributeError('"{}" is not known in the namespace.' - .format(key)) + six.raise_from(AttributeError('"{}" is not known in the namespace.' + .format(key)), None) def __setattr__(self, key, value): dict.__setitem__(self, key, value) @@ -1684,8 +1701,10 @@ def __delattr__(self, key): try: dict.__delitem__(self, key) except KeyError: - raise AttributeError('"{}" is not known in the namespace.' - .format(key)) + six.raise_from( + AttributeError('"{}" is not known in the namespace.' + .format(key)), + None) def __eq__(self, other): try: @@ -1991,8 +2010,11 @@ def _check_coords(coords, argname): try: coords = coords.astype(np.float32, order='C', copy=enforce_copy) except ValueError: - raise TypeError("{}(): {}.dtype must be convertible to float32," - " got {}.".format(fname, argname, coords.dtype)) + six.raise_from( + TypeError( + "{}(): {}.dtype must be convertible to float32," + " got {}.".format(fname, argname, coords.dtype)), + None) return coords, is_single @wraps(func) diff --git a/package/MDAnalysis/selections/__init__.py b/package/MDAnalysis/selections/__init__.py index 1ac7c2630a8..146252a9963 100644 --- a/package/MDAnalysis/selections/__init__.py +++ b/package/MDAnalysis/selections/__init__.py @@ -45,6 +45,7 @@ .. autofunction:: get_writer """ from __future__ import absolute_import +from six import raise_from import os.path @@ -85,6 +86,7 @@ def get_writer(filename, defaultformat): try: return _SELECTION_WRITERS[format] except KeyError: - raise NotImplementedError( + raise_from(NotImplementedError( "Writing as {0!r} is not implemented;" - " only {1!r} will work.".format(format, _SELECTION_WRITERS.keys())) + " only {1!r} will work.".format(format, _SELECTION_WRITERS.keys())), + None) diff --git a/package/MDAnalysis/tests/datafiles.py b/package/MDAnalysis/tests/datafiles.py index a24be633838..68f2af8000e 100644 --- a/package/MDAnalysis/tests/datafiles.py +++ b/package/MDAnalysis/tests/datafiles.py @@ -37,6 +37,7 @@ http://pypi.python.org/pypi/MDAnalysisTests and installed. """ from __future__ import print_function, absolute_import +from six import raise_from try: from MDAnalysisTests.datafiles import * @@ -50,4 +51,4 @@ print() print("and download and install the `MDAnalysisTests-x.y.z.tar.gz'") print("that matches your MDAnalysis release.") - raise ImportError("MDAnalysisTests package not installed.") + raise_from(ImportError("MDAnalysisTests package not installed."), None) diff --git a/package/MDAnalysis/topology/CRDParser.py b/package/MDAnalysis/topology/CRDParser.py index c841d2bba65..fa2e287a0e0 100644 --- a/package/MDAnalysis/topology/CRDParser.py +++ b/package/MDAnalysis/topology/CRDParser.py @@ -46,6 +46,7 @@ """ from __future__ import absolute_import +from six import raise_from import numpy as np @@ -121,9 +122,10 @@ def parse(self, **kwargs): try: (serial, resnum, resName, name, x, y, z, segid, resid, tempFactor) = r.read(line) - except: - raise ValueError("Check CRD format at line {0}: {1}" - "".format(linenum + 1, line.rstrip())) + except Exception: + raise_from(ValueError("Check CRD format at line {0}: {1}" + "".format(linenum + 1, line.rstrip())), + None) atomids.append(serial) atomnames.append(name) diff --git a/package/MDAnalysis/topology/DMSParser.py b/package/MDAnalysis/topology/DMSParser.py index 93715a920cb..ef5f2b99aba 100644 --- a/package/MDAnalysis/topology/DMSParser.py +++ b/package/MDAnalysis/topology/DMSParser.py @@ -41,6 +41,7 @@ """ from __future__ import absolute_import +from six import raise_from import numpy as np import sqlite3 @@ -141,8 +142,9 @@ def dict_factory(cursor, row): ''.format(attrname)) vals = cur.fetchall() except sqlite3.DatabaseError: - raise IOError( - "Failed reading the atoms from DMS Database") + raise_from( + IOError("Failed reading the atoms from DMS Database"), + None) else: attrs[attrname] = np.array(vals, dtype=dt) @@ -151,7 +153,9 @@ def dict_factory(cursor, row): cur.execute('SELECT * FROM bond') bonds = cur.fetchall() except sqlite3.DatabaseError: - raise IOError("Failed reading the bonds from DMS Database") + raise_from( + IOError("Failed reading the bonds from DMS Database"), + None) else: bondlist = [] bondorder = {} diff --git a/package/MDAnalysis/topology/GROParser.py b/package/MDAnalysis/topology/GROParser.py index 3bfaf930449..3cddcdc114e 100644 --- a/package/MDAnalysis/topology/GROParser.py +++ b/package/MDAnalysis/topology/GROParser.py @@ -48,6 +48,7 @@ import numpy as np from six.moves import range +from six import raise_from from ..lib.util import openany from ..core.topologyattrs import ( @@ -103,9 +104,11 @@ def parse(self, **kwargs): names[i] = line[10:15].strip() indices[i] = int(line[15:20]) except (ValueError, TypeError): - raise IOError( + raise_from( + IOError(( "Couldn't read the following line of the .gro file:\n" - "{0}".format(line)) + "{0}").format(line)), + None) # Check all lines had names if not np.all(names): missing = np.where(names == '') diff --git a/package/MDAnalysis/topology/LAMMPSParser.py b/package/MDAnalysis/topology/LAMMPSParser.py index 0ecb42f27d5..4f36621e7d2 100644 --- a/package/MDAnalysis/topology/LAMMPSParser.py +++ b/package/MDAnalysis/topology/LAMMPSParser.py @@ -80,6 +80,7 @@ from __future__ import absolute_import, print_function from six.moves import range +from six import raise_from import numpy as np import logging @@ -285,12 +286,13 @@ def parse(self, **kwargs): try: top = self._parse_atoms(sects['Atoms'], masses) - except: - raise ValueError( + except Exception: + raise_from(ValueError( "Failed to parse atoms section. You can supply a description " "of the atom_style as a keyword argument, " "eg mda.Universe(..., atom_style='id resid x y z')" - ) + ), + None) # create mapping of id to index (ie atom id 10 might be the 0th atom) mapping = {atom_id: i for i, atom_id in enumerate(top.ids.values)} @@ -336,7 +338,9 @@ def read_DATA_timestep(self, n_atoms, TS_class, TS_kwargs, try: positions, ordering = self._parse_pos(sects['Atoms']) except KeyError as err: - raise IOError("Position information not found: {}".format(err)) + raise_from( + IOError("Position information not found: {}".format(err)), + None) if 'Velocities' in sects: velocities = self._parse_vel(sects['Velocities'], ordering) diff --git a/package/MDAnalysis/topology/PSFParser.py b/package/MDAnalysis/topology/PSFParser.py index 798c5f22591..92b74f62735 100644 --- a/package/MDAnalysis/topology/PSFParser.py +++ b/package/MDAnalysis/topology/PSFParser.py @@ -45,6 +45,7 @@ """ from __future__ import absolute_import, division from six.moves import range +from six import raise_from import logging import functools @@ -280,7 +281,7 @@ def _parseatoms(self, lines, atoms_per, numlines): err = ("{0} is not valid PSF file" "".format(self.filename)) logger.error(err) - raise ValueError(err) + raise_from(ValueError(err), None) try: vals = set_type(atom_parser(line)) except ValueError: diff --git a/package/MDAnalysis/topology/TOPParser.py b/package/MDAnalysis/topology/TOPParser.py index 10968b9850c..c3cd99785fb 100644 --- a/package/MDAnalysis/topology/TOPParser.py +++ b/package/MDAnalysis/topology/TOPParser.py @@ -81,6 +81,7 @@ from __future__ import absolute_import, division from six.moves import range, zip +from six import raise_from import numpy as np import functools from math import ceil @@ -234,9 +235,11 @@ def next_getter(): try: next_section = line.split("%FLAG")[1].strip() except IndexError: - msg = ("%FLAG section not found, formatting error " - "for PARM7 file {0} ".format(self.filename)) - raise IndexError(msg) + raise_from( + IndexError(( + "%FLAG section not found, formatting error " + "for PARM7 file {0} ").format(self.filename)), + None) # strip out a few values to play with them n_atoms = len(attrs['name']) diff --git a/package/MDAnalysis/transformations/fit.py b/package/MDAnalysis/transformations/fit.py index 63ee6213544..53dd142d139 100644 --- a/package/MDAnalysis/transformations/fit.py +++ b/package/MDAnalysis/transformations/fit.py @@ -33,6 +33,7 @@ """ from __future__ import absolute_import +from six import raise_from import numpy as np from functools import partial @@ -90,18 +91,20 @@ def fit_translation(ag, reference, plane=None, weights=None): try: plane = axes[plane] except (TypeError, KeyError): - raise ValueError('{} is not a valid plane'.format(plane)) + raise_from(ValueError('{} is not a valid plane'.format(plane)), None) try: if ag.atoms.n_residues != reference.atoms.n_residues: raise ValueError("{} and {} have mismatched number of residues".format(ag,reference)) except AttributeError: - raise AttributeError("{} or {} is not valid Universe/AtomGroup".format(ag,reference)) + raise_from( + AttributeError("{} or {} is not valid Universe/AtomGroup".format(ag,reference)), + None) ref, mobile = align.get_matching_atoms(reference.atoms, ag.atoms) try: weights = align.get_weights(ref.atoms, weights=weights) except (ValueError, TypeError): - raise ValueError("weights must be {'mass', None} or an iterable of the " - "same size as the atomgroup.") + raise_from(ValueError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup."), None) ref_com = np.asarray(ref.center(weights), np.float32) @@ -169,18 +172,18 @@ def fit_rot_trans(ag, reference, plane=None, weights=None): try: plane = axes[plane] except (TypeError, KeyError): - raise ValueError('{} is not a valid plane'.format(plane)) + raise_from(ValueError('{} is not a valid plane'.format(plane)), None) try: if ag.atoms.n_residues != reference.atoms.n_residues: raise ValueError("{} and {} have mismatched number of residues".format(ag,reference)) except AttributeError: - raise AttributeError("{} or {} is not valid Universe/AtomGroup".format(ag,reference)) + raise_from(AttributeError("{} or {} is not valid Universe/AtomGroup".format(ag,reference)), None) ref, mobile = align.get_matching_atoms(reference.atoms, ag.atoms) try: weights = align.get_weights(ref.atoms, weights=weights) except (ValueError, TypeError): - raise ValueError("weights must be {'mass', None} or an iterable of the " - "same size as the atomgroup.") + raise_from(ValueError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup."), None) ref_com = ref.center(weights) ref_coordinates = ref.atoms.positions - ref_com diff --git a/package/MDAnalysis/transformations/rotate.py b/package/MDAnalysis/transformations/rotate.py index 4d0cb29cc08..694aec606e2 100644 --- a/package/MDAnalysis/transformations/rotate.py +++ b/package/MDAnalysis/transformations/rotate.py @@ -32,6 +32,7 @@ """ from __future__ import absolute_import +from six import raise_from import math import numpy as np @@ -113,7 +114,9 @@ def rotateby(angle, direction, point=None, ag=None, weights=None, wrap=False): raise ValueError('{} is not a valid direction'.format(direction)) direction = direction.reshape(3, ) except ValueError: - raise ValueError('{} is not a valid direction'.format(direction)) + raise_from( + ValueError('{} is not a valid direction'.format(direction)), + None) if point is not None: point = np.asarray(point, np.float32) if point.shape != (3, ) and point.shape != (1, 3): @@ -123,13 +126,15 @@ def rotateby(angle, direction, point=None, ag=None, weights=None, wrap=False): try: atoms = ag.atoms except AttributeError: - raise ValueError('{} is not an AtomGroup object'.format(ag)) + raise_from(ValueError('{} is not an AtomGroup object'.format(ag)), None) else: try: weights = get_weights(atoms, weights=weights) except (ValueError, TypeError): - raise TypeError("weights must be {'mass', None} or an iterable of the " - "same size as the atomgroup.") + raise_from( + TypeError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup."), + None) center_method = partial(atoms.center, weights, pbc=wrap) else: raise ValueError('A point or an AtomGroup must be specified') diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index bdcc16870f0..77950d4bab3 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -37,6 +37,7 @@ """ from __future__ import absolute_import, division +from six import raise_from import numpy as np from functools import partial @@ -126,9 +127,11 @@ def center_in_box(ag, center='geometry', point=None, wrap=False): raise ValueError('{} is not a valid argument for center'.format(center)) except AttributeError: if center == 'mass': - raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) + raise_from( + AttributeError('{} is not an AtomGroup object with masses'.format(ag)), + None) else: - raise ValueError('{} is not an AtomGroup object'.format(ag)) + raise_from(ValueError('{} is not an AtomGroup object'.format(ag)), None) def wrapped(ts): if point is None: diff --git a/package/MDAnalysis/units.py b/package/MDAnalysis/units.py index ab317c568ce..40e7f24ec47 100644 --- a/package/MDAnalysis/units.py +++ b/package/MDAnalysis/units.py @@ -166,7 +166,8 @@ """ -from __future__ import unicode_literals, division +from __future__ import absolute_import, unicode_literals, division +from six import raise_from #: `Avogadro's constant`_ in mol**-1. #: @@ -364,13 +365,22 @@ def convert(x, u1, u2): try: ut1 = unit_types[u1] except KeyError: - raise ValueError("unit '{0}' not recognized.\n" - "It must be one of {1}.".format(u1, ", ".join(unit_types))) + raise_from( + ValueError( + ("unit '{0}' not recognized.\n" + "It must be one of {1}.").format(u1, ", ".join(unit_types)) + ), + None) + try: ut2 = unit_types[u2] except KeyError: - raise ValueError("unit '{0}' not recognized.\n" - "It must be one of {1}.".format(u2, ", ".join(unit_types))) + raise_from( + ValueError( + ("unit '{0}' not recognized.\n" + "It must be one of {1}.").format(u2, ", ".join(unit_types)) + ), + None) if ut1 != ut2: raise ValueError("Cannot convert between unit types " "{0} --> {1}".format(u1, u2)) diff --git a/package/MDAnalysis/visualization/streamlines.py b/package/MDAnalysis/visualization/streamlines.py index 23f91575200..70dbe78ecbf 100644 --- a/package/MDAnalysis/visualization/streamlines.py +++ b/package/MDAnalysis/visualization/streamlines.py @@ -44,6 +44,7 @@ """ from __future__ import absolute_import from six.moves import zip +from six import raise_from import multiprocessing @@ -54,10 +55,14 @@ import matplotlib import matplotlib.path except ImportError: - raise ImportError( - '2d streamplot module requires: matplotlib.path for its path.Path.contains_points method. The installation ' - 'instructions for the matplotlib module can be found here: ' - 'http://matplotlib.org/faq/installing_faq.html?highlight=install') + raise_from( + ImportError(( + '2d streamplot module requires: matplotlib.path for its ' + 'path.Path.contains_points method. The installation ' + 'instructions for the matplotlib module can be found here: ' + 'http://matplotlib.org/faq/installing_faq.html?highlight=install' + )), + None) import MDAnalysis