Mark gmxapi 0.3b1.
[alexxy/gromacs.git] / python_packaging / src / gmxapi / version.py
index f08e8a9ee278853e5a887ccd4cb55b80ba29eaaf..87cd592237063b4a905a1bc3a9fc332526191bc3 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # the research papers on the package. Check out http://www.gromacs.org.
 
 """
-Provide version and release information.
+gmxapi version and release information.
 
-Attributes:
-    major (int): gmxapi major version number.
-    minor (int): gmxapi minor version number.
-    patch (int): gmxapi patch level number.
-    release (bool): True if imported gmx module is an officially tagged release, else False.
+The ``gmxapi.__version__`` attribute contains a :pep:`version string <440>`.
+The more general way to access the package version is with the
+:py:mod:`pkg_resources <https://setuptools.readthedocs.io/en/latest/pkg_resources.html>` module::
 
-"""
-import warnings
+    pkg_resources.get_distribution('gmxapi').version
+
+`gmxapi.version` module functions `api_is_at_least()` and `has_feature()`
+support additional convenience and introspection.
+
+.. versionchanged:: 0.2
+
+    This module no longer provides public data attributes.
+    Instead, use the module functions or
+    :py:mod:`packaging.version <https://packaging.pypa.io/en/latest/version/>`.
 
-__version__ = "0.1.0"
+.. seealso::
 
-# TODO: (pending infrastructure and further discussion) Configure with CMake.
-# __version__ = "@PROJECT_VERSION@"
-# major = @PROJECT_VERSION_MAJOR@
-# minor = @PROJECT_VERSION_MINOR@
-# patch = @PROJECT_VERSION_PATCH@
+    Consider https://packaging.pypa.io/en/latest/version/ for programmatic
+    handling of the version string. For example::
+
+        from packaging.version import parse
+        gmxapi_version = pkg_resources.get_distribution('gmxapi').version
+        if parse(gmxapi_version).is_prerelease:
+            print('The early bird gets the worm.')
+
+.. todo:: Use pkg_resources.get_distribution('gmxapi').version and
+          "development installations" instead of relying on or publicizing
+          a __version__ attribute.
+"""
+import warnings
 
-from gmxapi.exceptions import FeatureNotAvailableError
+from .exceptions import FeatureNotAvailableError
 
-major = 0
-minor = 1
-patch = 0
+# TODO: Version management policy and procedures.
+_major = 0
+_minor = 3
+_micro = 0
+_suffix = 'b1'
 
-# Note: this is not automatically updated. See RELEASE.txt and https://github.com/kassonlab/gmxapi/issues/152
-release = True
+# Reference https://www.python.org/dev/peps/pep-0440/
+# and https://packaging.pypa.io/en/latest/version/
+__version__ = '{major}.{minor}.{micro}{suffix}'.format(major=_major,
+                                                       minor=_minor,
+                                                       micro=_micro,
+                                                       suffix=_suffix)
 
 # Features added since the initial gmxapi prototype, targeted for version 0.1.
 _named_features_0_0 = ['fr1', 'fr3', 'fr7', 'fr15']
@@ -77,7 +97,7 @@ _named_features_0_1 = []
 # Bugs and bug fixes may be indicated with names consisting of tracked issue URLs.
 #
 # Features consisting of 'fr' and a numeric suffix are the functional requirements
-# described in roadmap.rst, as described at https://redmine.gromacs.org/issues/2893
+# described in roadmap.rst, as described at https://gitlab.com/gromacs/gromacs/-/issues/2893
 #
 # fr1: wrap importable Python code.
 # fr2: output proxy establishes execution dependency (superseded by fr3)
@@ -119,11 +139,11 @@ def api_is_at_least(major_version, minor_version=0, patch_version=0):
     """
     if not isinstance(major_version, int) or not isinstance(minor_version, int) or not isinstance(patch_version, int):
         raise TypeError('Version levels must be provided as integers.')
-    if major > major_version:
+    if _major > major_version:
         return True
-    elif major == major_version and minor >= minor_version:
+    elif _major == major_version and _minor >= minor_version:
         return True
-    elif major == major_version and minor == minor_version and patch >= patch_version:
+    elif _major == major_version and _minor == minor_version and _micro >= patch_version:
         return True
     else:
         return False
@@ -172,7 +192,8 @@ def has_feature(name='', enable_exception=False) -> bool:
         if name in _named_features_0_0:
             warnings.warn(
                 'Old feature name. Use `api_is_at_least(0, 1)` instead of `has_feature({})`.'.format(name),
-                category=DeprecationWarning
+                category=DeprecationWarning,
+                stacklevel=2
             )
 
     # Check whether the feature is listed in the API specification amendments.