Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error message when calling AtmGroup.unwrap() without bonds #4642

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions package/MDAnalysis/core/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -1874,9 +1874,13 @@ def unwrap(self, compound='fragments', reference='com', inplace=True):
"""
atoms = self.atoms
# bail out early if no bonds in topology:
if not hasattr(atoms, 'bonds'):
raise NoDataError("{}.unwrap() not available; this requires Bonds"
"".format(self.__class__.__name__))
if not hasattr(atoms, 'bonds'):
raise NoDataError(
f"{self.__class__.__name__}.unwrap() not available; this AtomGroup lacks defined bonds. "
"To resolve this, you can either:\n"
"1. Guess the bonds at universe creation using `guess_bonds = True`, or\n"
"2. Create a universe using a topology format where bonds are pre-defined."
orbeckst marked this conversation as resolved.
Show resolved Hide resolved
)
unique_atoms = atoms.unsorted_unique

# Parameter sanity checking
Expand Down
37 changes: 23 additions & 14 deletions testsuite/MDAnalysisTests/core/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -1434,46 +1434,52 @@ def test_component_set_plural(self, attr, groupname):
setattr(comp, attr, 24)

class TestAttributeGetting(object):

@staticmethod
@pytest.fixture()
def universe():
return make_Universe(extras=('masses', 'altLocs'))

@staticmethod
@pytest.fixture()
def atoms():
u = make_Universe(extras=("masses",), size=(3, 1, 1))
return u.atoms

@pytest.mark.parametrize('attr', ['masses', 'altLocs'])
def test_get_present_topattr_group(self, universe, attr):
values = getattr(universe.atoms, attr)
assert values is not None

@pytest.mark.parametrize('attr', ['mass', 'altLoc'])
def test_get_present_topattr_component(self, universe, attr):
value = getattr(universe.atoms[0], attr)
assert value is not None

@pytest.mark.parametrize('attr,singular', [
('masses', 'mass'),
('masses', 'mass'),
('altLocs', 'altLoc')])
def test_get_plural_topattr_from_component(self, universe, attr, singular):
with pytest.raises(AttributeError) as exc:
getattr(universe.atoms[0], attr)
assert ('Do you mean ' + singular) in str(exc.value)

@pytest.mark.parametrize('attr,singular', [
('masses', 'mass'),
('masses', 'mass'),
('altLocs', 'altLoc')])
def test_get_sing_topattr_from_group(self, universe, attr, singular):
with pytest.raises(AttributeError) as exc:
getattr(universe.atoms, singular)
assert ('Do you mean '+attr) in str(exc.value)
assert ('Do you mean ' + attr) in str(exc.value)

@pytest.mark.parametrize('attr,singular', [
('elements', 'element'),
('elements', 'element'),
('tempfactors', 'tempfactor'),
('bonds', 'bonds')])
def test_get_absent_topattr_group(self, universe, attr, singular):
with pytest.raises(NoDataError) as exc:
getattr(universe.atoms, attr)
assert 'does not contain '+singular in str(exc.value)
assert 'does not contain ' + singular in str(exc.value)

def test_get_non_topattr(self, universe):
with pytest.raises(AttributeError) as exc:
Expand All @@ -1483,9 +1489,13 @@ def test_get_non_topattr(self, universe):
def test_unwrap_without_bonds(self, universe):
with pytest.raises(NoDataError) as exc:
universe.atoms.unwrap()
err = ('AtomGroup.unwrap() not available; '
'this requires Bonds')
assert str(exc.value) == err
expected_message = (
"AtomGroup.unwrap() not available; this AtomGroup lacks defined bonds. "
"To resolve this, you can either:\n"
"1. Guess the bonds at universe creation using `guess_bonds = True`, or\n"
"2. Create a universe using a topology format where bonds are pre-defined."
)
assert str(exc.value) == expected_message
laksh-krishna-sharma marked this conversation as resolved.
Show resolved Hide resolved

def test_get_absent_attr_method(self, universe):
with pytest.raises(NoDataError) as exc:
Expand All @@ -1512,7 +1522,7 @@ def test_attrmethod_wrong_group(self, universe):
universe.atoms[0].center_of_mass()
err = ('center_of_mass() is a method of AtomGroup, not Atom')
assert str(exc.value) == err

@pytest.mark.parametrize('attr', ['altlocs', 'alt_Locs'])
def test_wrong_name(self, universe, attr):
with pytest.raises(AttributeError) as exc:
Expand All @@ -1521,7 +1531,6 @@ def test_wrong_name(self, universe, attr):
'Did you mean altLocs?').format(attr)
assert str(exc.value) == err


class TestInitGroup(object):
@staticmethod
@pytest.fixture(
Expand Down
9 changes: 8 additions & 1 deletion testsuite/MDAnalysisTests/core/test_unwrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787
#
import numpy as np
import re
from numpy.testing import (assert_raises, assert_almost_equal,
assert_array_equal)
import pytest
Expand Down Expand Up @@ -336,7 +337,13 @@ def test_unwrap_no_bonds_exception_safety(self, level, compound, reference):
group = group.segments
# store original positions:
orig_pos = group.atoms.positions
with pytest.raises(NoDataError):
error_message = (
f"{group.__class__.__name__}.unwrap() not available; this AtomGroup lacks defined bonds. "
"To resolve this, you can either:\n"
"1. Guess the bonds at universe creation using `guess_bonds = True`, or\n"
"2. Create a universe using a topology format where bonds are pre-defined."
)
with pytest.raises(NoDataError, match=re.escape(error_message)):
group.unwrap(compound=compound, reference=reference, inplace=True)
# make sure atom positions are unchanged:
assert_array_equal(group.atoms.positions, orig_pos)
Expand Down
Loading