From beba24cd4ce8a96d815f9c4bd5cfea3b63902cd6 Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Sat, 29 Jan 2022 18:05:16 -0500 Subject: [PATCH] #39: Streamline code and add more tests --- CHANGELOG.md | 2 ++ dunamai/__init__.py | 70 ++++++++++++++++---------------------- tests/unit/test_dunamai.py | 23 ++++++++++++- 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129bfd4..8f40e9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ * Changed `Version.serialize`'s `format` argument to support passing a callback. ([Contributed by marnikow](https://github.com/mtkennerly/dunamai/pull/40)) +* Added `ignore` option to `get_version()`. + ([Contributed by marnikow](https://github.com/mtkennerly/dunamai/pull/39)) ## v1.8.0 (2022-01-27) diff --git a/dunamai/__init__.py b/dunamai/__init__.py index f3f69b1..1dc6507 100644 --- a/dunamai/__init__.py +++ b/dunamai/__init__.py @@ -171,6 +171,12 @@ def _blank(value: Optional[_T], default: _T) -> _T: return value if value is not None else default +def _equal_if_set(x: _T, y: Optional[_T], unset: Sequence[Any] = (None,)) -> bool: + if y in unset: + return True + return x == y + + def _detect_vcs(expected_vcs: Vcs = None) -> Vcs: checks = OrderedDict( [ @@ -375,36 +381,24 @@ def __eq__(self, other: Any) -> bool: and self.epoch == other.epoch ) - def equals_ignored_version(self, ignored_version: "Version") -> bool: + def _matches_partial(self, other: "Version") -> bool: """ - Compare this version to another version but ignore None values in the ignored version. - :param ignored_version: The version to compare to. - :return: True if this version equals the ignored version. + Compare this version to another version, but ignore None values in the other version. + Distance is also ignored when `other.distance == 0`. + + :param other: The version to compare to. + :return: True if this version equals the other version. """ - if self.base != ignored_version.base: - return False - if ignored_version.stage is not None: - if self.stage != ignored_version.stage: - return False - if ignored_version.revision is not None: - if self.revision != ignored_version.revision: - return False - if ignored_version.distance is not None: - if self.distance != ignored_version.distance: - return False - if ignored_version.commit is not None: - if self.commit != ignored_version.commit: - return False - if ignored_version.dirty is not None: - if self.dirty != ignored_version.dirty: - return False - if ignored_version.tagged_metadata is not None: - if self.tagged_metadata != ignored_version.tagged_metadata: - return False - if ignored_version.epoch is not None: - if self.epoch != ignored_version.epoch: - return False - return True + return ( + _equal_if_set(self.base, other.base) + and _equal_if_set(self.stage, other.stage) + and _equal_if_set(self.revision, other.revision) + and _equal_if_set(self.distance, other.distance, unset=[None, 0]) + and _equal_if_set(self.commit, other.commit) + and _equal_if_set(self.dirty, other.dirty) + and _equal_if_set(self.tagged_metadata, other.tagged_metadata) + and _equal_if_set(self.epoch, other.epoch) + ) def __lt__(self, other: Any) -> bool: if not isinstance(other, Version): @@ -1047,11 +1041,15 @@ def get_version( :param fallback: If no other matches found, use this version. :param ignore: Ignore a found version if it is part of this list. When comparing the found version to an ignored one, fields with None in the ignored - version are not taken into account. + version are not taken into account. If the ignored version has distance=0, + then that field is also ignored. """ + if ignore is None: + ignore = [] + if first_choice: first_ver = first_choice() - if first_ver and not _version_in_list_of_ignored_versions(first_ver, ignore): + if first_ver and not any(first_ver._matches_partial(v) for v in ignore): return first_ver try: @@ -1060,14 +1058,14 @@ def get_version( import importlib_metadata as ilm # type: ignore try: ilm_version = Version(ilm.version(name)) - if not _version_in_list_of_ignored_versions(ilm_version, ignore): + if not any(ilm_version._matches_partial(v) for v in ignore): return ilm_version except ilm.PackageNotFoundError: pass if third_choice: third_ver = third_choice() - if third_ver and not _version_in_list_of_ignored_versions(third_ver, ignore): + if third_ver and not any(third_ver._matches_partial(v) for v in ignore): return third_ver return fallback @@ -1209,12 +1207,4 @@ def _parse_git_timestamp_iso_strict(raw: str) -> dt.datetime: return dt.datetime.strptime(compat, "%Y-%m-%dT%H:%M:%S%z") -def _version_in_list_of_ignored_versions(version: Version, ignore: Optional[Sequence[Version]]): - if ignore: - for ignored_version in ignore: - if version.equals_ignored_version(ignored_version): - return True - return False - - __version__ = get_version("dunamai").serialize() diff --git a/tests/unit/test_dunamai.py b/tests/unit/test_dunamai.py index 3c09aa6..a64e9de 100644 --- a/tests/unit/test_dunamai.py +++ b/tests/unit/test_dunamai.py @@ -1,5 +1,5 @@ import os -import pkg_resources # type: ignore +import pkg_resources import re from contextlib import contextmanager from pathlib import Path @@ -500,6 +500,27 @@ def test__get_version__first_choice__ignore() -> None: ) +def test__get_version__first_choice__ignore_with_distance() -> None: + assert ( + get_version( + "dunamai_nonexistent_test", + first_choice=lambda: Version("1", distance=2), + ignore=[Version("1")], + fallback=Version("2"), + ) + == Version("2") + ) + assert ( + get_version( + "dunamai_nonexistent_test", + first_choice=lambda: Version("1"), + ignore=[Version("1", distance=2)], + fallback=Version("2"), + ) + != Version("2") + ) + + def test__get_version__first_choice__ignore__with_commit() -> None: assert ( get_version(