-
Notifications
You must be signed in to change notification settings - Fork 824
Description
Is your feature request related to a problem?
With PR #3233 merged, we established a new API for AnalysisBase-derived analysis classes: results should be stored in the .results attribute, which is a dict that makes keys available as attributes. Any classes that have not been using results should start using it in a backwards compatible manner.
Describe the solution you'd like
Add .results to all Analysis-classes in such a way that access to the old documented attributes still works for the full 2.x life cycle.
Classes
The following classes should be upgraded (roughly in order of importance) --- raise individual issues and add them here; add more classes to be upgraded as necessary
- BAT (get this done in 2.0.0 since it was added then = no deprecation needed) update analysis.bat.BAT to use .results #3272
- helix_analysis (as above needs, to get done before 2.0.0 gets released) update helix_analysis to use .results #3268
- rms.RMSD PR update analysis.rms to use .results #3274
- rms.RMSF PR update analysis.rms to use .results #3274
- align.AlignTraj and align.AverageStructure Update AlignTraj and AverageStructure to use new .results #3278
- hydrogenbonds.HydrogenBondAnalysis update hydrogenbonds.HydrogenBondAnalysis to use .results #3271
- contacts.ContactAnalysis PR Make contacts.Contacts use the Results class #3264
- density.DensityAnalysis PR Make DensityAnalysis use the Results class #3263
- pca.PCA update PCA analysis to use new .results #3275
- dihedrals.Ramachandran PR Move angles to results.angles for dihedral classes #3266
- dihedrals.Dihedrals PR Move angles to results.angles for dihedral classes #3266
- dihedrals.Janin PR Move angles to results.angles for dihedral classes #3266
- msd.EinsteinMSD PR Moves msd results to use the Results class #3265
- rdf.InterRDF update classes in rdf to use new .results #3276
- rdf.InterRDF_s update classes in rdf to use new .results #3276
- hydrogenbonds.WaterBridgeAnalysis update hydrogenbonds.WaterBridgeAnalysis to use .results #3270
- hole2.HoleAnalysis update hole2 analysis to use .results #3269
- DiffusionMap.DistanceMatrix update diffusionmap.DiffusionMap and DistanceMatrix to use .results #3290
- polymer.PersistenceLength update polymer.PersistenceLength to use .results #3291
- ...
Approach
Generally follow the approach taken for DensityAnalysis in PR #3263
Code
Assume that the old code in a class ExampleAnalysis(AnalysisBase) stored a result in attribute foo.
- change to using
.results:- You do not need to set up
self.results = Results()becauseAnalysisBasedoes it. - You must change any attribute assignments to be in
self.resultsinstead ofself. For example,self.foo = databecomesself.results.foo = data. - Note that
Resultsis really a dict where keys can be accessed as attributes. This can be useful when key access is more convenient than attribute access. - Results may be nested if necessary.
- You do not need to set up
- Required changes to keep access to
foobackward compatible + deprecation warning:
import warnings
class ExampleAnalysis(AnalysisBase):
...
@property
def foo(self):
wmsg = ("The `foo` attribute was deprecated in MDAnalysis 2.0.0 "
"and will be removed in MDAnalysis 3.0.0. Please use "
"`results.foo` instead")
warnings.warn(wmsg, DeprecationWarning)
return self.results.fooDocs
Change all examples in the docs to use the new .results. Pay particular attention to any ``.. attribute::` section and examples. Add a deprecation note in docs directly to the attribute:
.. attribute:: foo
The results of the calculation are stored here.
.. deprecated:: 2.0.0
This attribute will be removed in 3.0.0. Use :attr:`results.foo` instead.Add docs for the results attribute with a versionchanged
.. attribute:: results.foo
The results of the calculation are stored here.
.. versionadded:: 2.0.0 Add a version changed at the bottom of the class docs
.. versionchanged:: 2.0.0
Results are now stored in a :class:`MDAnalysis.analysis.base.Results` instance.If necessary, raise issues for the User Guide if you already know that it needs updating, too.
CHANGELOG
Changes
* `ExampleAnalysis` now uses the `results.foo` attribute for storing
data. The `ExampleAnalysis.foo` attribute is now deprecated
(Issue #xxxx)
Deprecations
* The `foo` attribute of `analysis.example.ExampleAnalysis.foo` is now
deprecated in favour of `results.foo`. It will be removed in 3.0.0
(Issue #xxxx)
Describe alternatives you've considered
Do nothing
Do nothing right now and update as we go along. The downside is that we then miss the opportunity to educate users right from 2.0.0 onwards to use the new API.
Other ways to still make the attributes available
For results that can be stored by reference, it will be sufficient to just assign to self.results.NAME in addition to self.NAME:
class ExampleAnalysis(base.AnalysisBase):
...
def _conclude(self):
# old
# self.data = np.array(self._data)
# new (remove self.data in 3.0.0)
self.results.data = self.data = np.array(self._data)This simple approach has the disadvantage that we eventually have to manually add deprecation warnings that the old attributes will be removed.
If necessary, one could use properties and also add the deprecation warning:
from MDAnalysis.lib.util import deprecate
class ExampleAnalysis(AnalysisBase):
def _conclude(self):
self.results.data = ...
@property
@deprecate(old_name="ExampleAnalysis.data", new_name="ExampleAnalysis.results.data",
release="2.0.0", remove="3.0.0")
def data(self):
return self.results.data
# for full compatibility there should be a setter but I am not sure if really needed
@data.setter
def data(self, value):
self.results.data = value