Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add diff method to AwesomeVersion to list out changes between 2 objects #185

Merged
merged 6 commits into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion awesomeversion/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Initialize the AwesomeVersion package."""
from .awesomeversion import AwesomeVersion
from .awesomeversion import AwesomeVersion, AwesomeVersionDiff
from .exceptions import (
AwesomeVersionCompareException,
AwesomeVersionException,
Expand All @@ -10,6 +10,7 @@
__all__ = [
"AwesomeVersion",
"AwesomeVersionCompareException",
"AwesomeVersionDiff",
"AwesomeVersionException",
"AwesomeVersionStrategy",
"AwesomeVersionStrategyException",
Expand Down
64 changes: 62 additions & 2 deletions awesomeversion/awesomeversion.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""AwesomeVersion."""
from __future__ import annotations

from typing import Any
from typing import TYPE_CHECKING, Any, Dict
from warnings import warn

from .comparehandlers.container import compare_handler_container
Expand All @@ -15,7 +15,6 @@
AwesomeVersionStrategy,
AwesomeVersionStrategyDescription,
)
from .typing import EnsureStrategyIterableType, EnsureStrategyType, VersionType
from .utils.regex import (
RE_DIGIT,
RE_MODIFIER,
Expand All @@ -24,6 +23,9 @@
generate_full_string_regex,
)

if TYPE_CHECKING:
from .typing import EnsureStrategyIterableType, EnsureStrategyType, VersionType


class _AwesomeVersionBase(str):
"""Base class for AwesomeVersion to allow the usage of the default JSON encoder."""
Expand Down Expand Up @@ -202,6 +204,25 @@ def __le__(self, compareto: object) -> bool:
def __ge__(self, compareto: object) -> bool:
return self.__eq__(compareto) or self.__gt__(compareto)

def __sub__(self, compareto: object) -> AwesomeVersionDiff:
return self.diff(compareto)

def diff(self, compareto: VersionType) -> AwesomeVersionDiff:
"""Return a dictionary with differences between 2 AwesomeVersion objects."""
if isinstance(compareto, (str, float, int)):
compareto = AwesomeVersion(compareto)
if not isinstance(compareto, AwesomeVersion):
raise AwesomeVersionCompareException("Not a valid AwesomeVersion object")
return AwesomeVersionDiff(
{
"major": self.major != compareto.major,
"minor": self.minor != compareto.minor,
"patch": self.patch != compareto.patch,
"modifier": self.modifier != compareto.modifier,
"strategy": self.strategy != compareto.strategy,
}
)

def section(self, idx: int) -> int:
"""Return the value of the specified section of the version."""
if self.sections >= (idx + 1):
Expand Down Expand Up @@ -430,3 +451,42 @@ def simple(self) -> bool:
generate_full_string_regex(RE_SIMPLE).match(self.string) is not None
)
return self._simple


class AwesomeVersionDiff:
"""Structured output of AwesomeVersion.diff"""

def __init__(self, changes: Dict[str, bool]) -> None:
"""Initialize the AwesomeVersionDiff."""
self._changes = changes

def __repr__(self) -> str:
return (
f"AwesomeVersionDiff(major={self.major}, minor={self.minor}, "
f"patch={self.patch}, modifier={self.modifier}, strategy={self.strategy})"
)

@property
def major(self) -> bool:
"""Return True if the major version has changed."""
return self._changes["major"]

@property
def minor(self) -> bool:
"""Return True if the minor version has changed."""
return self._changes["minor"]

@property
def patch(self) -> bool:
"""Return True if the patch version has changed."""
return self._changes["patch"]

@property
def modifier(self) -> bool:
"""Return True if the modifier version has changed."""
return self._changes["modifier"]

@property
def strategy(self) -> bool:
"""Return True if the strategy has changed."""
return self._changes["strategy"]
24 changes: 24 additions & 0 deletions tests/test_awesomeversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
AwesomeVersionStrategy,
AwesomeVersionStrategyException,
)
from awesomeversion.exceptions import AwesomeVersionException
from awesomeversion.strategy import COMPARABLE_STRATEGIES
from awesomeversion.typing import VersionType

Expand Down Expand Up @@ -222,3 +223,26 @@ def test_find_first_match_exception() -> None:
assert "Can not use find_first_match without ensure_strategy" in str(
warning_list[-1].message
)


def test_diff() -> None:
"""Test .diff"""
version = AwesomeVersion("2020.12.1")

assert version.diff("2021.12.1").major
assert not version.diff("2021.12.1").minor
assert not version.diff("2021.12.1").patch
assert not version.diff("2021.12.1").modifier
assert not version.diff("2021.12.1").strategy

assert version.diff("2021.11.1").minor
assert version.diff("2021.12.2").patch
assert version.diff("2021.12.1dev2").modifier
assert version.diff("2.11.1").strategy

diff = version - "2021.12.1"
assert diff.major
assert diff.__repr__().startswith("AwesomeVersionDiff(")

with pytest.raises(AwesomeVersionException):
version.diff(None)