Skip to content

Commit

Permalink
Removed instant selectors (Fixes Issue #1377)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardjgowers committed Feb 16, 2020
1 parent ae4b516 commit ee1acc0
Show file tree
Hide file tree
Showing 13 changed files with 27 additions and 523 deletions.
2 changes: 2 additions & 0 deletions package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ Enhancements
* Improve the distance search in water bridge analysis with capped_distance (PR #2480)

Changes
* Removed instant selectors on Universe and Group objects (e.g. AtomGroup.C,
Segment.r1, Universe.s4AKE). Use select_atoms instead (Issue #1377)
* Calling Universe() now raises a TypeError advising you to use Universe.empty.
Universe.empty() now no longer has n_atoms=0 as default. (Issue #2527)
* deprecated `start`, `stop`, and `step` keywords have been removed from `__init__`
Expand Down
85 changes: 13 additions & 72 deletions package/MDAnalysis/core/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -2203,55 +2203,19 @@ class AtomGroup(GroupBase):
:class:`AtomGroup` instances are always bound to a
:class:`MDAnalysis.core.universe.Universe`. They cannot exist in isolation.
.. rubric:: Deprecated functionality
*Instant selectors* will be removed in the 1.0 release. See issue `#1377
<https://github.com/MDAnalysis/mdanalysis/issues/1377>`_ for more details.
:class:`Atoms<Atom>` can also be accessed in a Pythonic fashion by using the
:class:`Atom` name as an attribute. For instance, ::
ag.CA
will provide an :class:`AtomGroup` of all CA :class:`Atoms<Atom>` in the
group. These *instant selector* attributes are auto-generated for
each atom name encountered in the group.
Notes
-----
The name-attribute instant selector access to :class:`Atoms<Atom>` is mainly
meant for quick interactive work. Thus it either returns a single
:class:`Atom` if there is only one matching :class:`Atom`, *or* a
new :class:`AtomGroup` for multiple matches. This makes it difficult to use
the feature consistently in scripts.
See Also
--------
:class:`MDAnalysis.core.universe.Universe`
.. deprecated:: 0.16.2
*Instant selectors* of :class:`AtomGroup` will be removed in the 1.0
release. See :ref:`Instant selectors <instance-selectors>` for details
and alternatives.
release.
.. versionchanged:: 1.0
Removed instant selectors, use select_atoms('name ...') to select
atoms by name.
"""
def __getitem__(self, item):
# DEPRECATED in 0.16.2
# REMOVE in 1.0
#
# u.atoms['HT1'] access, otherwise default
if isinstance(item, string_types):
try:
return self._get_named_atom(item)
except (AttributeError, selection.SelectionError):
pass
return super(AtomGroup, self).__getitem__(item)

def __getattr__(self, attr):
# DEPRECATED in 0.16.2
# REMOVE in 1.0
#
# is this a known attribute failure?
# TODO: Generalise this to cover many attributes
if attr in ('fragments', 'fragindices', 'n_fragments', 'unwrap'):
Expand All @@ -2260,12 +2224,6 @@ def __getattr__(self, attr):
# raise NDE(_ATTR_ERRORS[attr])
raise NoDataError("AtomGroup.{} not available; this requires Bonds"
"".format(attr))
elif hasattr(self.universe._topology, 'names'):
# Ugly hack to make multiple __getattr__s work
try:
return self._get_named_atom(attr)
except selection.SelectionError:
pass
raise AttributeError("{cls} has no attribute {attr}".format(
cls=self.__class__.__name__, attr=attr))

Expand Down Expand Up @@ -3256,8 +3214,8 @@ class ResidueGroup(GroupBase):
.. deprecated:: 0.16.2
*Instant selectors* of Segments will be removed in the 1.0 release.
See :ref:`Instant selectors <instance-selectors>` for details and
alternatives.
.. versionchanged:: 1.0
Removed instant selectors
"""

@property
Expand Down Expand Up @@ -3419,8 +3377,8 @@ class SegmentGroup(GroupBase):
.. deprecated:: 0.16.2
*Instant selectors* of Segments will be removed in the 1.0 release.
See :ref:`Instant selectors <instance-selectors>` for details and
alternatives.
.. versionchanged:: 1.0
Removed instant selectors
"""

@property
Expand Down Expand Up @@ -3841,8 +3799,11 @@ class Segment(ComponentBase):
.. deprecated:: 0.16.2
*Instant selectors* of :class:`Segments<Segment>` will be removed in the
1.0 release. See :ref:`Instant selectors <instance-selectors>` for
details and alternatives.
1.0 release.
.. versionchanged:: 1.0
Removed instant selectors, use either segment.residues[...] to select
residue by number, or segment.residues[segment.residue.resnames = ...]
to select by resname.
"""
def __repr__(self):
me = '<Segment'
Expand Down Expand Up @@ -3870,26 +3831,6 @@ def residues(self):
rg._cache['unique'] = rg
return rg

def __getattr__(self, attr):
# DEPRECATED in 0.16.2
# REMOVE in 1.0
#
# Segment.r1 access
if attr.startswith('r') and attr[1:].isdigit():
resnum = int(attr[1:])
rg = self.residues[resnum - 1] # convert to 0 based
warnings.warn("Instant selectors Segment.r<N> will be removed in "
"1.0. Use Segment.residues[N-1] instead.",
DeprecationWarning)
return rg
# Resname accesss
if hasattr(self.residues, 'resnames'):
try:
return self.residues._get_named_residue(attr)
except selection.SelectionError:
pass
raise AttributeError("{cls} has no attribute {attr}"
"".format(cls=self.__class__.__name__, attr=attr))

# Accessing these attrs doesn't trigger an update. The class and instance
# methods of UpdatingAtomGroup that are used during __init__ must all be
Expand Down
169 changes: 0 additions & 169 deletions package/MDAnalysis/core/topologyattrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import numpy as np
import warnings

from numpy.lib.utils import deprecate

from ..lib.util import (cached, convert_aa_code, iterable, warn_if_not_unique,
unique_int_1d)
Expand Down Expand Up @@ -481,63 +480,6 @@ class Atomnames(AtomAttr):
def _gen_initial_values(na, nr, ns):
return np.array(['' for _ in range(na)], dtype=object)

def getattr__(atomgroup, name):
try:
return atomgroup._get_named_atom(name)
except selection.SelectionError:
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.
For more than one atom it returns a list of :class:`Atom`
instance. A single :class:`Atom` is returned just as such. If
no atoms are found, a :exc:`SelectionError` is raised.
.. versionadded:: 0.9.2
.. deprecated:: 0.16.2
*Instant selectors* will be removed in the 1.0 release.
Use ``AtomGroup.select_atoms('name <name>')`` instead.
See issue `#1377
<https://github.com/MDAnalysis/mdanalysis/issues/1377>`_ for
more details.
"""
# There can be more than one atom with the same name
atomlist = group.atoms.unique[group.atoms.unique.names == name]
if len(atomlist) == 0:
raise selection.SelectionError(
"No atoms with name '{0}'".format(name))
elif len(atomlist) == 1:
# XXX: keep this, makes more sense for names
atomlist = atomlist[0]
warnings.warn("Instant selector AtomGroup['<name>'] or AtomGroup.<name> "
"is deprecated and will be removed in 1.0. "
"Use AtomGroup.select_atoms('name <name>') instead.",
DeprecationWarning)
return atomlist

# AtomGroup already has a getattr
# transplants[AtomGroup].append(
# ('__getattr__', getattr__))

transplants[Residue].append(
('__getattr__', getattr__))

# this is also getitem for a residue
transplants[Residue].append(
('__getitem__', getattr__))

transplants[AtomGroup].append(
('_get_named_atom', _get_named_atom))

transplants[Residue].append(
('_get_named_atom', _get_named_atom))

def phi_selection(residue):
"""AtomGroup corresponding to the phi protein backbone dihedral
C'-N-CA-C.
Expand Down Expand Up @@ -1383,63 +1325,6 @@ class Resnames(ResidueAttr):
def _gen_initial_values(na, nr, ns):
return np.array(['' for _ in range(nr)], dtype=object)

def getattr__(residuegroup, resname):
try:
return residuegroup._get_named_residue(resname)
except selection.SelectionError:
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
#transplants[Segment].append(('__getattr__', getattr__))

def _get_named_residue(group, resname):
"""Get all residues with name *resname* in the current ResidueGroup
or Segment.
For more than one residue it returns a
:class:`MDAnalysis.core.groups.ResidueGroup` instance. A single
:class:`MDAnalysis.core.group.Residue` is returned for a single match.
If no residues are found, a :exc:`SelectionError` is raised.
.. versionadded:: 0.9.2
.. deprecated:: 0.16.2
*Instant selectors* will be removed in the 1.0 release.
Use ``ResidueGroup[ResidueGroup.resnames == '<name>']``
or ``Segment.residues[Segment.residues == '<name>']``
instead.
See issue `#1377
<https://github.com/MDAnalysis/mdanalysis/issues/1377>`_ for
more details.
"""
# There can be more than one residue with the same name
residues = group.residues.unique[
group.residues.unique.resnames == resname]
if len(residues) == 0:
raise selection.SelectionError(
"No residues with resname '{0}'".format(resname))
warnings.warn("Instant selector ResidueGroup.<name> "
"or Segment.<name> "
"is deprecated and will be removed in 1.0. "
"Use ResidueGroup[ResidueGroup.resnames == '<name>'] "
"or Segment.residues[Segment.residues == '<name>'] "
"instead.",
DeprecationWarning)
if len(residues) == 1:
# XXX: keep this, makes more sense for names
return residues[0]
else:
# XXX: but inconsistent (see residues and Issue 47)
return residues

transplants[ResidueGroup].append(
('_get_named_residue', _get_named_residue))

def sequence(self, **kwargs):
"""Returns the amino acid sequence.
Expand Down Expand Up @@ -1627,60 +1512,6 @@ class Segids(SegmentAttr):
def _gen_initial_values(na, nr, ns):
return np.array(['' for _ in range(ns)], dtype=object)

def getattr__(segmentgroup, segid):
try:
return segmentgroup._get_named_segment(segid)
except selection.SelectionError:
six.raise_from(
AttributeError("'{0}' object has no attribute '{1}'".format(
segmentgroup.__class__.__name__, segid)),
None)

transplants[SegmentGroup].append(
('__getattr__', getattr__))

def _get_named_segment(group, segid):
"""Get all segments with name *segid* in the current SegmentGroup.
For more than one residue it returns a
:class:`MDAnalysis.core.groups.SegmentGroup` instance. A single
:class:`MDAnalysis.core.group.Segment` is returned for a single match.
If no residues are found, a :exc:`SelectionError` is raised.
.. versionadded:: 0.9.2
.. deprecated:: 0.16.2
*Instant selectors* will be removed in the 1.0 release.
Use ``SegmentGroup[SegmentGroup.segids == '<name>']`` instead.
See issue `#1377
<https://github.com/MDAnalysis/mdanalysis/issues/1377>`_ for
more details.
"""
# Undo adding 's' if segid started with digit
if segid.startswith('s') and len(segid) >= 2 and segid[1].isdigit():
segid = segid[1:]

# There can be more than one segment with the same name
segments = group.segments.unique[
group.segments.unique.segids == segid]
if len(segments) == 0:
raise selection.SelectionError(
"No segments with segid '{0}'".format(segid))
warnings.warn("Instant selector SegmentGroup.<name> "
"is deprecated and will be removed in 1.0. "
"Use SegmentGroup[SegmentGroup.segids == '<name>'] "
"instead.",
DeprecationWarning)
if len(segments) == 1:
# XXX: keep this, makes more sense for names
return segments[0]
else:
# XXX: but inconsistent (see residues and Issue 47)
return segments

transplants[SegmentGroup].append(
('_get_named_segment', _get_named_segment))

def _check_connection_values(func):
"""
Expand Down
Loading

0 comments on commit ee1acc0

Please sign in to comment.