diff --git a/package/CHANGELOG b/package/CHANGELOG index c4f2e4afa85..1914638f6d6 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -20,6 +20,8 @@ mm/dd/yy richardjgowers, kain88-de, lilyminium, p-j-smith, bdice, joaomcteixeira * 0.21.0 Fixes + * Handle exception when PDBWriter is trying to remove an invalid StringIO + (Issue #2512) * Clarifies density_from_Universe docs and adds user warning (Issue #2372) * Fix upstream deprecation of `matplotlib.axis.Tick` attributes in `MDAnalysis.analysis.psa` diff --git a/package/MDAnalysis/coordinates/PDB.py b/package/MDAnalysis/coordinates/PDB.py index cf3208d87ef..4466b002c4d 100644 --- a/package/MDAnalysis/coordinates/PDB.py +++ b/package/MDAnalysis/coordinates/PDB.py @@ -653,6 +653,10 @@ def _check_pdb_coordinates(self): coordinates and closes the file. Raises :exc:`ValueError` if the coordinates fail the check. + + .. versionchanged: 1.0.0 + Check if :attr:`filename` is `StringIO` when attempting to remove + a PDB file with invalid coordinates (Issue #2512) """ atoms = self.obj.atoms # make sure to use atoms (Issue 46) # can write from selection == Universe (Issue 49) @@ -678,6 +682,14 @@ def _check_pdb_coordinates(self): except OSError as err: if err.errno == errno.ENOENT: pass + else: + raise + except TypeError: + if isinstance(self.filename, StringIO): + pass + else: + raise + raise ValueError("PDB files must have coordinate values between " "{0:.3f} and {1:.3f} Angstroem: file writing was " "aborted.".format(self.pdb_coor_limits["min"], diff --git a/testsuite/MDAnalysisTests/coordinates/test_pdb.py b/testsuite/MDAnalysisTests/coordinates/test_pdb.py index c9557d3c437..1bec2eb05f2 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_pdb.py +++ b/testsuite/MDAnalysisTests/coordinates/test_pdb.py @@ -185,6 +185,10 @@ def universe(self): def universe2(self): return mda.Universe(PSF, DCD) + @pytest.fixture + def universe3(self): + return mda.Universe(PDB) + @pytest.fixture def outfile(self, tmpdir): return str(tmpdir.mkdir("PDBWriter").join('primitive-pdb-writer' + self.ext)) @@ -362,6 +366,26 @@ def test_segid_chainid(self, universe2, outfile): u_pdb = mda.Universe(outfile) assert u_pdb.segments.chainIDs[0][0] == ref_id + def test_stringio_outofrange(self, universe3): + """ + Check that when StringIO is used, the correct out-of-range error for + coordinates is raised (instead of failing trying to remove StringIO + as a file). + """ + + u = universe3 + + u.atoms.translate([-9999, -9999, -9999]) + + outstring = StringIO() + + errmsg = "PDB files must have coordinate values between" + + with pytest.raises(ValueError, match=errmsg): + with mda.coordinates.PDB.PDBWriter(outstring) as writer: + writer.write(u.atoms) + + class TestMultiPDBReader(object): @staticmethod @pytest.fixture(scope='class')