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

BUG: _compare_version backward incompat #10404

Closed
larsoner opened this issue Feb 28, 2022 · 12 comments · Fixed by #10406
Closed

BUG: _compare_version backward incompat #10404

larsoner opened this issue Feb 28, 2022 · 12 comments · Fixed by #10406
Labels
Milestone

Comments

@larsoner
Copy link
Member

cc @hoechenberger:

>>> import mne
>>> mne.fixes._compare_version('1.0.dev0', '>=', '1.0')
False
>>> from distutils.version import LooseVersion
>>> LooseVersion('1.0.dev0') >= LooseVersion('1.0')
<stdin>:1: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
True

This is a problem because we usually want the second result :(

The git grep check_version | wc -l count is 67 and git grep _compare_version | wc -l is 26, I'd rather not have to change all of these to allow for .dev0 extensions. Plus other submodules like mne-nirs that already use this (where I saw the problem actually!) will not work properly...

I'm tempted to change this to cut off any .dev from the end to make life easy, but then we depart from standard. But it seems a bit like the lesser of two evils here.

@larsoner larsoner added the BUG label Feb 28, 2022
@larsoner larsoner added this to the 1.0 milestone Feb 28, 2022
@hoechenberger
Copy link
Member

I believe there were some relatively recent changes by @cbrnr if I'm not mistaken (cannot check right now), could you have a look at the history of that function and see if this problem maybe only started showing up after these changes?

@cbrnr
Copy link
Contributor

cbrnr commented Mar 1, 2022

This is a bit unfortunate and maybe even a bug? They are explicitly recommending to switch to packaging.version.parse, but it doesn't behave identically. I've open an issue.

@hoechenberger
Copy link
Member

I have to say that IMHO the new behavior is more correct than the old one though. 1.0 is newer than 1.0dev0. So the version comparison should be >=1.0dev0, no? I think this is how conda behaves too if I'm not mistaken.

@cbrnr
Copy link
Contributor

cbrnr commented Mar 1, 2022

Technically yes, dev0 is a prerelease, so it is less than the final release. However, speaking of semantic versioning, I think we're not using those prerelease tags correctly, because they should be separated by a hyphen (e.g. 1.0.0-dev0).

@cbrnr
Copy link
Contributor

cbrnr commented Mar 1, 2022

As @hoechenberger suspected this is expected behavior, and distutils.version was doing its own thing. I'd change the comparisons in our code. Alternatively, we could vendor the old versioning code, but I'd rather not do that.

@hoechenberger
Copy link
Member

Let's change our code to make it more consistent with my thinking 😅🥴😁

@larsoner
Copy link
Member Author

larsoner commented Mar 1, 2022

I'd rather add a loose=True that prunes the dev. Most of the time if a person is using 1.0.dev0, they probably have what's needed and if they don't they know how to update. Plus it's backward compatible this way. And it's much easier than changing 100+ places we use (and think about) these comparisons.

@cbrnr
Copy link
Contributor

cbrnr commented Mar 1, 2022

So this would basically affect equality comparisons, right? Using loose=True would mean that 1.0.dev0 >= 1.0, 1.0.dev0 <= 1.0, and 1.0.dev0 == 1.0 are all True. Does this make sense? I don't really understand why we rely on such strange comparisons.

@larsoner
Copy link
Member Author

larsoner commented Mar 1, 2022

I can document this inaccuracy with == and loose=True. In practice we (almost?) never use ==. To me practicality -- and backward compat for other libs and even users that make use of check_version (and have only recently silently been getting the wrong result with parse, at least according to how check_version has behaved for the last 9 years) -- beats purity here by a long shot.

@cbrnr
Copy link
Contributor

cbrnr commented Mar 1, 2022

Even if documented just stripping the dev0 suffix doesn't make sense – this doesn't restore the old behavior, which is:

>>>  LooseVersion("1.0.dev0") >= LooseVersion("1.0")
True
>>>  LooseVersion("1.0.dev0") <= LooseVersion("1.0")
False
>>>  LooseVersion("1.0.dev0") == LooseVersion("1.0")
False

So the difference is that a dev0 version was newer previously, but is now considered older.

@larsoner
Copy link
Member Author

larsoner commented Mar 1, 2022

The most important thing is that it restores the behavior of check_version. This uses _compare_version under the hood with a < operator to say if something is not okay:

if _compare_version(version, '<', min_version):

So for example:

>>> LooseVersion('1.0.dev0') < LooseVersion('1.0')
False
>>> mne.fixes._compare_version('1.0.dev0', '<', '1.0')
True

So I think it should work. So maybe we should add loose=True to check_version, do the stripping there, and not change _compare_version (and just fix the way fewer of those we use, where needed).

@cbrnr
Copy link
Contributor

cbrnr commented Mar 1, 2022

So maybe we should add loose=True to check_version, do the stripping there, and not change _compare_version (and just fix the way fewer of those we use, where needed).

This sounds good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants