From cdb4805122b5f1fffa8e6fd284d93da2f7ac616d Mon Sep 17 00:00:00 2001 From: Sylvain MARIE Date: Wed, 24 Feb 2021 13:19:05 +0100 Subject: [PATCH] Prerelease version strings such as `1.0.0-rc1` were incorrectly returned as `1.0.0rc1` (without dash) because of an issue with `setuptools_scm` due to `pkg_resources` removing the dash of prerelease versions. Fixes #10 --- getversion/plugin_setuptools_scm.py | 50 +++++++++++++++++++++++++++-- getversion/tests/test_issues.py | 40 +++++++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 getversion/tests/test_issues.py diff --git a/getversion/plugin_setuptools_scm.py b/getversion/plugin_setuptools_scm.py index 2d82888..df5a574 100644 --- a/getversion/plugin_setuptools_scm.py +++ b/getversion/plugin_setuptools_scm.py @@ -27,9 +27,54 @@ def __str__(self): try: from setuptools_scm import get_version + from setuptools_scm.version import guess_next_dev_version from setuptools_scm.utils import has_command has_git_command = has_command('git') + + def fixed_version_scheme(version): + """ + A fix for https://github.com/smarie/python-getversion/issues/10 + until this is fixed in setuptools_scm or in pkg_resources + so that the dash is not removed when a pre-release version is present (e.g. 1.0.0-rc1) + """ + # This is the bugged string would be used by the default scheme (for reference) + # str(version.tag) + + # modify the 'pre' part only if needed + do_hack = version.tag.is_prerelease + if do_hack: + # make a backup + _version_bak = version.tag._version + + # get the various parts + parts = _version_bak._asdict() + + # make sure we understand what we do by doing a simple copy + clone = type(_version_bak)(**parts) + assert clone == _version_bak, "Internal error with this version of `pkg_resources`, please report" + + # now do a mod + parts['pre'] = ("-",) + parts['pre'] + _version_mod = type(_version_bak)(**parts) + + # and apply it + version.tag._version = _version_mod + + # we can check that the string has been fixed correctly + # str(version.tag) + + # create the version string as usual by applying setuptools_scm's default version scheme + # note that despite the name, this does not increment anything if the tag is exact (no local mod) + res = guess_next_dev_version(version) + + # undo our hack if needed + if do_hack: + version.tag._version = _version_bak # noqa + + return res + + def scm_get_version_recursive_root(abs_path, initial_path): """ Recursively climbs the parent folders, searching for a git root @@ -38,7 +83,7 @@ def scm_get_version_recursive_root(abs_path, initial_path): :return: """ try: - return get_version(abs_path) + res = get_version(abs_path, version_scheme=fixed_version_scheme) except LookupError as e: parent_dir = dirname(abs_path) if parent_dir == abs_path: @@ -47,7 +92,8 @@ def scm_get_version_recursive_root(abs_path, initial_path): else: # recurse return scm_get_version_recursive_root(parent_dir, initial_path=initial_path) - + else: + return res def get_version_using_setuptools_scm(module # type: ModuleType ): diff --git a/getversion/tests/test_issues.py b/getversion/tests/test_issues.py new file mode 100644 index 0000000..d4e7778 --- /dev/null +++ b/getversion/tests/test_issues.py @@ -0,0 +1,40 @@ +from os.path import join, pardir + +from setuptools_scm import _do_parse, Configuration, format_version +from getversion.plugin_setuptools_scm import fixed_version_scheme + +from pkg_resources import parse_version as pkg_parse_version + + +def test_issue_10(): + # version with a prerelease + version_str = "1.0.0-rc1" + + # Parse with pkg_resource and make sure that the issue is still there (see #10) + pkg_res_version = pkg_parse_version(version_str) + assert str(pkg_res_version) == '1.0.0rc1' + + # use setuptools_scm to get a version object that we can modify to introduce the bug + config = Configuration(root=join(__file__, pardir, pardir, pardir)) + s_version = _do_parse(config) + # --make sure that internals of `setuptools_scm` have not changed: the .tag object is a pkg_resource Version + assert isinstance(s_version.tag, type(pkg_res_version)) + # --now lets modify the version object so as to inject the issue + s_version.tag = pkg_res_version + + # make sure that setuptools_scm did not fix the issue yet + pb_ver = format_version( + s_version, + version_scheme=config.version_scheme, + local_scheme=config.local_scheme, + ) + assert str(pb_ver) != version_str + assert str(pb_ver).startswith("1.0.0rc") # dash removed + + # make sure that with our fixed version scheme (used in our plugin) it works + fixed_vers = format_version( + s_version, + version_scheme=fixed_version_scheme, + local_scheme=config.local_scheme, + ) + assert str(fixed_vers).startswith("1.0.0-rc") # with the dash