diff --git a/nose_unit.cfg b/nose_unit.cfg index f67d56d6e4c..8256e7baf41 100644 --- a/nose_unit.cfg +++ b/nose_unit.cfg @@ -6,5 +6,5 @@ nologcapture=1 verbosity=2 where=yt with-timer=1 -ignore-files=(test_load_errors.py|test_load_sample.py|test_commons.py|test_ambiguous_fields.py|test_field_access_pytest.py|test_save.py|test_line_annotation_unit.py|test_eps_writer.py|test_registration.py|test_invalid_origin.py|test_outputs_pytest\.py|test_normal_plot_api\.py|test_load_archive\.py|test_stream_particles\.py|test_file_sanitizer\.py) +ignore-files=(test_load_errors.py|test_load_sample.py|test_commons.py|test_ambiguous_fields.py|test_field_access_pytest.py|test_save.py|test_line_annotation_unit.py|test_eps_writer.py|test_registration.py|test_invalid_origin.py|test_outputs_pytest\.py|test_normal_plot_api\.py|test_load_archive\.py|test_stream_particles\.py|test_file_sanitizer\.py|test_version\.py) exclude-test=yt.frontends.gdf.tests.test_outputs.TestGDF diff --git a/setup.cfg b/setup.cfg index eb841a731c2..08aa0840e0c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = yt -version = 4.1.dev0 +version = 4.1.dev0 # keep in sync with yt/_version.__version__ description = An analysis and visualization toolkit for volumetric data long_description = file: README.md long_description_content_type = text/markdown diff --git a/setup.py b/setup.py index 0ee2c18c7a6..007312f481c 100644 --- a/setup.py +++ b/setup.py @@ -15,8 +15,6 @@ install_ccompiler() -VERSION = "4.1.dev0" - if os.path.exists("MANIFEST"): os.remove("MANIFEST") diff --git a/tests/tests.yaml b/tests/tests.yaml index fcd810a3590..6455995fd01 100644 --- a/tests/tests.yaml +++ b/tests/tests.yaml @@ -201,6 +201,7 @@ other_tests: - "--ignore-files=test_outputs_pytest\\.py" - "--ignore-files=test_normal_plot_api\\.py" - "--ignore-file=test_file_sanitizer\\.py" + - "--ignore-files=test_version\\.py" - "--exclude-test=yt.frontends.gdf.tests.test_outputs.TestGDF" - "--exclude-test=yt.frontends.adaptahop.tests.test_outputs" - "--exclude-test=yt.frontends.stream.tests.test_stream_particles.test_stream_non_cartesian_particles" diff --git a/yt/__init__.py b/yt/__init__.py index 8b9d1cd6ff7..a17faf240df 100644 --- a/yt/__init__.py +++ b/yt/__init__.py @@ -7,8 +7,7 @@ * Contribute: https://github.com/yt-project/yt """ -__version__ = "4.1.dev0" - +from ._version import __version__, version_info # isort: skip import yt.units as units import yt.utilities.physical_constants as physical_constants from yt.data_objects.api import ( diff --git a/yt/_version.py b/yt/_version.py new file mode 100644 index 00000000000..c2826e0cb6e --- /dev/null +++ b/yt/_version.py @@ -0,0 +1,55 @@ +from typing import NamedTuple + +from packaging.version import Version + +__all__ = [ + "__version__", + "version_info", +] + +__version__ = "4.1.dev0" # keep in sync with setup.cfg + + +class VersionTuple(NamedTuple): + """ + A minimal representation of the current version number + that can be used downstream to check the runtime version + simply by comparing with builtin tuples, as can be done with + the runtime Python version using sys.version_info + + https://docs.python.org/3/library/sys.html#sys.version_info + """ + + major: int + minor: int + micro: int + releaselevel: str + serial: int + + +def _parse_to_version_info(version_str: str) -> VersionTuple: + # adapted from matplotlib 3.5 + """ + Parse a version string to a namedtuple analogous to sys.version_info. + See: + https://packaging.pypa.io/en/latest/version.html#packaging.version.parse + https://docs.python.org/3/library/sys.html#sys.version_info + """ + v = Version(version_str) + if v.pre is None and v.post is None and v.dev is None: + return VersionTuple(v.major, v.minor, v.micro, "final", 0) + elif v.dev is not None: + return VersionTuple(v.major, v.minor, v.micro, "alpha", v.dev) + elif v.pre is not None: + releaselevel = {"a": "alpha", "b": "beta", "rc": "candidate"}.get( + v.pre[0], "alpha" + ) + return VersionTuple(v.major, v.minor, v.micro, releaselevel, v.pre[1]) + elif v.post is not None: + # fallback for v.post: guess-next-dev scheme from setuptools_scm + return VersionTuple(v.major, v.minor, v.micro + 1, "alpha", v.post) + else: + return VersionTuple(v.major, v.minor, v.micro + 1, "alpha", 0) + + +version_info = _parse_to_version_info(__version__) diff --git a/yt/tests/test_version.py b/yt/tests/test_version.py new file mode 100644 index 00000000000..79045e78c45 --- /dev/null +++ b/yt/tests/test_version.py @@ -0,0 +1,35 @@ +import pytest + +import yt +from yt._version import VersionTuple, _parse_to_version_info + + +@pytest.mark.parametrize( + "version_str, expected", + ( + ("4.1.0", VersionTuple(4, 1, 0, "final", 0)), + ("6.2.5", VersionTuple(6, 2, 5, "final", 0)), + ("4.1.dev0", VersionTuple(4, 1, 0, "alpha", 0)), + ("4.1.0rc", VersionTuple(4, 1, 0, "candidate", 0)), + ("4.1.0rc1", VersionTuple(4, 1, 0, "candidate", 1)), + ("4.1.0rc2", VersionTuple(4, 1, 0, "candidate", 2)), + ), +) +def test_parse_version_info(version_str, expected): + actual = _parse_to_version_info(version_str) + assert actual == expected + + +def test_version_tuple_comp(): + # exercise comparison with builtin tuples + # comparison results do not matter for this test + + yt.version_info > (4,) # noqa: B015 + yt.version_info > (4, 1) # noqa: B015 + yt.version_info > (4, 1, 0) # noqa: B015 + yt.version_info < (4, 1, 0) # noqa: B015 + yt.version_info <= (4, 1, 0) # noqa: B015 + yt.version_info >= (4, 1, 0) # noqa: B015 + yt.version_info == (4, 1, 0) # noqa: B015 + + assert isinstance(yt.version_info, tuple)