-
Notifications
You must be signed in to change notification settings - Fork 131
Add support for version compare and for checking for version part argument #20
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
base: master
Are you sure you want to change the base?
Conversation
ekohl
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just an superficial review. I didn't look into all the details yet.
| if not isinstance(other, Version): | ||
| return False | ||
| try: | ||
| return all(v == other[k] for k, v in self.items()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this ignore the case there len(self.items()) < len(other.items())?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, we could do a len compare first to make sure both have the same number of parts. I will add this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a second thought, I think equality should be strict, that is: 1.4 != 1.4.0, by assuming they are the same we ignore the version pattern defined by parse and serialize. If both versions where generated by bumpversion then this highlights that the user has an error in the part configuration.
bumpversion/__init__.py
Outdated
| for vals in ((v, other[k]) for k, v in self.items()): | ||
| if vals[0] == vals[1]: | ||
| continue | ||
| if method(vals[0], vals[1]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be return method(vals[0], vals[1]) but then I also prefer to rewrite it a bit:
if vals[0] != vals[1]:
return method(vals[0], vals[1])There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, cant really remember why did I do a if to return true/false.
bumpversion/version_part.py
Outdated
| return hash(self.value) | ||
|
|
||
| def _compare(self, other, method): | ||
| if self.config.function_cls is not other.config.function_cls: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Odd indenting here
|
Sorry for the delay on this. Have pushed the requested changes, except for the equals (see my comments). |
ekohl
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took a while to get back to this. Some inline comments.
bumpversion/__init__.py
Outdated
| def __repr__(self): | ||
| return '<bumpversion.Version:{}>'.format(keyvaluestring(self._values)) | ||
| by_part = ", ".join("{}={}".format(k, v) for k, v in self.items()) | ||
| return '<bumpversion.Version:{}>'.format(by_part) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably cleaner to use self.__class__ to show the class name rather than hardcoding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. Do notice that this is how it was done in the past, I just added the by_part line ;)
bumpversion/__init__.py
Outdated
| return not self.__eq__(other) | ||
|
|
||
| def __le__(self, other): | ||
| return self._compare(other, lambda s, o: o > s, False) # Note the change of order in operands |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also use operator.lt instead of the lambda. There's also operator.gt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
| def __hash__(self): | ||
| return hash(tuple((k, v) for k, v in self.items())) | ||
|
|
||
| def _compare(self, other, method, strict=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is really hard to understand at first sight. The strict parameter should be named something clearer, perhaps allow_equal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, I have changed the logic and improved the docs so the intent is more clear
bumpversion/__init__.py
Outdated
| class Version(object): | ||
|
|
||
| def __init__(self, values, original=None): | ||
| def __init__(self, values, config, original=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of the config here. It doesn't feel very logical that a version has a config, especially if it's only used for order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, will only use the order
bumpversion/__init__.py
Outdated
| def __init__(self, values, original=None): | ||
| def __init__(self, values, config, original=None): | ||
| self._values = dict(values) | ||
| self.config = config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is IMHO an internal property so should be named self._config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Config is now the order and it has to be public because when comparing we first compare the orders cause if they are different the versions can not be comapred
bumpversion/version_part.py
Outdated
|
|
||
| def __eq__(self, other): | ||
| return self.value == other.value | ||
| return self._compare(other, lambda s, o: s == o) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have a look at the operator module here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
bumpversion/version_part.py
Outdated
| return self._compare(other, lambda s, o: s > o) | ||
|
|
||
| def __ne__(self, other): | ||
| return self._compare(other, lambda s, o: s != o) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be simplified to return not self == other? See https://stackoverflow.com/questions/4352244/python-should-i-implement-ne-operator-based-on-eq#30676267 as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
bumpversion/__init__.py
Outdated
| try: | ||
| for vals in ((v, other[k]) for k, v in self.items()): | ||
| if vals[0] == vals[1]: | ||
| continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO it's cleaner to use avoid continue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous comment on this method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a second pass I can not find a way to avoid the continue :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arcanefoam Since the only purpose of the continue is to prevent calling return, you can just invert the logic. Instead of
for vals in ((v, other[k]) for k, v in self.items()):
if vals[0] == vals[1]:
continue
return method(vals[0], vals[1])
Do
for vals in ((v, other[k]) for k, v in self.items()):
if vals[0] != vals[1]:
return method(vals[0], vals[1])
I would also improve the readability by changing this to
for key, value in self.items():
other_value = other[key]
if value != other_value:
return method(value, other_value)
bumpversion/__init__.py
Outdated
| raise TypeError("Versions use different parts, cant compare them.") | ||
|
|
||
| def __ne__(self, other): | ||
| return not self.__eq__(other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://stackoverflow.com/questions/4352244/python-should-i-implement-ne-operator-based-on-eq#30676267 recommends avoiding this but rather write it as return not self == other. This is the default in Python 3 (but not 2).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
|
@arcanefoam any movement here? |
|
This branch needs a rebase. |
Version compare is important for other scripts that use bumpversion as a library, e.g. in my big osgi project I want to make sure all projects are at the same version, find which ones are ahead/behind.
I also took another approach to checking the version part argument. My implementation checks against the current VersionConfiguration (not hardcoded to specific names).
Both changes have proper tests (I think) in place.