Merge branch 'release-2019' into master
[alexxy/gromacs.git] / python_packaging / src / gmxapi / version.py
1 #
2 # This file is part of the GROMACS molecular simulation package.
3 #
4 # Copyright (c) 2019, by the GROMACS development team, led by
5 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 # and including many others, as listed in the AUTHORS file in the
7 # top-level source directory and at http://www.gromacs.org.
8 #
9 # GROMACS is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public License
11 # as published by the Free Software Foundation; either version 2.1
12 # of the License, or (at your option) any later version.
13 #
14 # GROMACS is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Lesser General Public License for more details.
18 #
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with GROMACS; if not, see
21 # http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23 #
24 # If you want to redistribute modifications to GROMACS, please
25 # consider that scientific software is very special. Version
26 # control is crucial - bugs must be traceable. We will be happy to
27 # consider code for inclusion in the official distribution, but
28 # derived work must not be called official GROMACS. Details are found
29 # in the README & COPYING files - if they are missing, get the
30 # official version at http://www.gromacs.org.
31 #
32 # To help us fund GROMACS development, we humbly ask that you cite
33 # the research papers on the package. Check out http://www.gromacs.org.
34
35 """
36 Provide version and release information.
37
38 Attributes:
39     major (int): gmxapi major version number.
40     minor (int): gmxapi minor version number.
41     patch (int): gmxapi patch level number.
42     release (bool): True if imported gmx module is an officially tagged release, else False.
43
44 """
45 import warnings
46
47 __version__ = "0.1.0-dev3"
48
49 # TODO: (pending infrastructure and further discussion) Configure with CMake.
50 # __version__ = "@PROJECT_VERSION@"
51 # major = @PROJECT_VERSION_MAJOR@
52 # minor = @PROJECT_VERSION_MINOR@
53 # patch = @PROJECT_VERSION_PATCH@
54
55 from gmxapi.exceptions import FeatureNotAvailableError
56
57 major = 0
58 minor = 1
59 patch = 0
60
61 # Note: this is not automatically updated. See RELEASE.txt and https://github.com/kassonlab/gmxapi/issues/152
62 release = False
63
64 # Features added since the initial gmxapi prototype, targeted for version 0.1.
65 _named_features_0_0 = ['fr1', 'fr3']
66 # Features named since the finalization of the 0.1 specification with GROMACS 2020.
67 _named_features_0_1 = []
68 # Named features describe functionality or behavior introduced since the last
69 # major release, and should be described in gmxapi documentation or issue
70 # tracking system. Note that, as features become part of the specification,
71 # conditionals depending on them should be phased out of the package source. At
72 # major releases, the named feature list should be reset to empty. Optionally,
73 # we could raise a DeprecationWarning for calls to has_feature() for features
74 # that have become part of the specification, at least for a few minor release or
75 # a few years, to avoid introducing errors to client code.
76 #
77 # Features consisting of 'fr' and a numeric suffix are the functional requirements
78 # described in roadmap.rst, as described at https://redmine.gromacs.org/issues/2893
79 #
80 # Bugs and bug fixes may be indicated with names consisting of tracked issue URLs.
81
82
83 def api_is_at_least(major_version, minor_version=0, patch_version=0):
84     """Allow client to check whether installed module supports the requested API level.
85
86     Arguments:
87         major_version (int): gmxapi major version number.
88         minor_version (int): optional gmxapi minor version number (default: 0).
89         patch_version (int): optional gmxapi patch level number (default: 0).
90
91     Returns:
92         True if installed gmx package is greater than or equal to the input level
93
94     Note that if gmxapi.version.release is False, the package is not guaranteed to correctly or
95     fully support the reported API level.
96     """
97     if not isinstance(major_version, int) or not isinstance(minor_version, int) or not isinstance(patch_version, int):
98         raise TypeError('Version levels must be provided as integers.')
99     if major > major_version:
100         return True
101     elif major == major_version and minor >= minor_version:
102         return True
103     elif major == major_version and minor == minor_version and patch >= patch_version:
104         return True
105     else:
106         return False
107
108
109 def has_feature(name='', enable_exception=False):
110     """Query whether a named feature is available in the installed package.
111
112     Between updates to the API specification, new features or experimental aspects
113     may be introduced into the package and need to be detectable. This function
114     is intended to facilitate code testing and resolving differences between
115     development branches. Users should refer to the documentation for the package
116     modules and API level.
117
118     The primary use case is, in conjunction with api_is_at_least(), to allow
119     client code to robustly identify expected behavior and API support through
120     conditional execution and branching. Note that behavior is strongly
121     specified by the API major version number. Features that have become part of
122     the specification and bug-fixes referring to previous major versions should
123     not be checked with *has_feature()*. Using *has_feature()* with old feature
124     names will produce a DeprecationWarning for at least one major version, and
125     client code should be updated to avoid logic errors in future versions.
126
127     For convenience, setting *enable_exception=True* causes the function to
128     instead raise a gmxapi.exceptions.FeatureNotAvailableError for unrecognized feature names.
129     This allows extension code to cleanly produce a gmxapi exception instead of
130     first performing a boolean check. Also, some code may be unexecutable for
131     more than one reason, and sometimes it is cleaner to catch all
132     gmxapi.exceptions.Error exceptions for a code block, rather than to
133     construct complex conditionals.
134
135     Returns:
136         True if named feature is recognized by the installed package, else False.
137
138     Raises:
139         gmxapi.exceptions.FeatureNotAvailableError if `enable_exception == True` and feature is not found.
140
141     """
142     # First, issue a warning if the feature name is subject to removal because
143     # of the history of the API specification.
144     if api_is_at_least(0, 2):
145         # For sufficiently advanced API versions, we want to warn that old
146         # feature checks lose meaning and should no longer be checked.
147         # We provide a suggestion with the API version that absorbed their
148         # specification.
149         if name in _named_features_0_0:
150             warnings.warn(
151                 'Old feature name. Use `api_is_at_least(0, 1)` instead of `has_feature({})`.'.format(name),
152                 category=DeprecationWarning
153             )
154
155     # Check whether the feature is listed in the API specification amendments.
156     if name in _named_features_0_0 + _named_features_0_1:
157         return True
158     else:
159         if enable_exception:
160             raise FeatureNotAvailableError('Feature {} not available.'.format(str(name)))
161         return False