captum icon indicating copy to clipboard operation
captum copied to clipboard

Improve version checking

Open ProGamerGov opened this issue 3 years ago • 11 comments

Without the packaging library, statements like: "1.8.0" > "1.10.0" will be equal to True, despite v1.10 being a later version that v1.8.0.

The packaging library will in some cases not be already installed on a user's device, so I've also added it the setup.py file. It's one of the core libraries from the Python Packaging Authority, but it's not included with the base Python installation: https://packaging.python.org/en/latest/key_projects/#pypa-projects

This wasn't an issue in https://github.com/pytorch/captum/pull/940 as one the libraries in dev install has packaging as a dependency. So, there's no error when the tests are using the packaging library.

ProGamerGov avatar Jul 27 '22 17:07 ProGamerGov

@ProGamerGov if you rebase from master #1000 will hopefully fix failing conda issue

NarineK avatar Jul 28 '22 04:07 NarineK

@NarineK It worked on this PR, but I tried it on #985 and it's still running after 3 and half hours.

Edit: It finally passed after just under 4 hours.

ProGamerGov avatar Jul 28 '22 18:07 ProGamerGov

@ProGamerGov, would it be possible to use something like this:

def versiontuple(v):
    return tuple(map(int, (v.split("."))))

Especially because pytorch's versioning is non-complicated and follows the same pattern. We usually avoid adding new dependancies to Captum if there is another possible solution without additional dependancies. I understand the advantage of package over tuple comparison but in this case pytorch's versioning is pretty straightforward and non-complex.

https://stackoverflow.com/questions/11887762/how-do-i-compare-version-numbers-in-python

NarineK avatar Aug 02 '22 00:08 NarineK

@NarineK That solution fails for nightly builds:

def versiontuple(v):
    return tuple(map(int, (v.split("."))))

output = versiontuple("1.12.0.dev20201109")
print(output)
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

[<ipython-input-2-32fcc066bf69>](https://localhost:8080/#) in <module>()
      4 
      5 
----> 6 output = versiontuple("1.12.0.dev20201109")
      7 print(output)

[<ipython-input-2-32fcc066bf69>](https://localhost:8080/#) in versiontuple(v)
      1 def versiontuple(v):
----> 2     return tuple(map(int, (v.split("."))))
      3 
      4 
      5 

ValueError: invalid literal for int() with base 10: 'dev20201109'

Though I suppose we could find a way to make it work. Are the other PyTorch libraries like Torchtext using the same versioning pattern?

The packaging library is also already essentially a package dependency of Captum as it is installed as a dependency during the dev install, which is why I'm suggesting it.

Edit:

This might work for PyTorch versions (and hopefully other PyTorch library versions as well):

from typing import Tuple

def parse_version(v: str) -> Tuple[int, int, int]:
    """
    Parse version strings into tuples for comparison.
    """
    v = v.split(".")
    v = [n for n in v if n.isdigit()]
    v += ([0] * (3 - len(v)))
    assert len(v) == 3
    return tuple(map(int, v))

output = parse_version("1.12.0.dev20201109")
print(output)

ProGamerGov avatar Aug 02 '22 00:08 ProGamerGov

@NarineK Is captum/_utils/common.py where we'd add the version parsing function?

from typing import Tuple, Optional

def _parse_version(v: str, length: Optional[int] = 3) -> Tuple[int, int, int]:
    """
    Parse version strings into tuples for comparison.
    
    Versions should be in the form of "<major>.<minor>.<patch>", "<major>.<minor>",
    or "<major>". The "dev", "post" and other letter portions of the given version will
    be ignored.
    
    Args:

        v (str): A version string.
        length (int, optional): The expected length of the output tuple. If the output
            is less than the expected length, then it will be padded with 0 values. Set
            to None for no padding or length checks.
            Default: 3

    Returns:
        version_tuple (tuple of int): A tuple of 3 integer values to use for version
            comparison.
    """
    v = [n for n in v.split(".") if n.isdigit()]
    if length is not None:
        v += ([0] * (length - len(v)))
        assert len(v) == length
    return tuple(map(int, v))

ProGamerGov avatar Aug 02 '22 00:08 ProGamerGov

@NarineK I've implemented the _parse_version function and supporting tests.

ProGamerGov avatar Aug 08 '22 21:08 ProGamerGov

@ProGamerGov, thank you for making the changes. I was looking into the dependency graph of the libs and I noticed that mathplotlib already depends on packaging if that's the right packaging library that I'm looking into.

Is there need to add it here ? We already have the dependency in the non-dev setting as well ?

install_requires=["matplotlib", "numpy", "packaging", "torch>=1.6"],
Screen Shot 2022-08-13 at 11 56 30 PM

https://github.com/matplotlib/matplotlib/blob/bfec1db0d595ccd1e14cccc0473a50a90ce26a8a/lib/matplotlib/testing/decorators.py#L12

NarineK avatar Aug 14 '22 06:08 NarineK

@NarineK I just tested installing Captum & Matplotlib, and neither installed the packaging library. Its listed in Matplotlib's setup.py, but not their setupext.py (which I think is used for the general user version of the package). They also use it for testing and some of the optional modules it looks like: https://github.com/matplotlib/matplotlib/search?p=1&q=packaging

ProGamerGov avatar Aug 14 '22 14:08 ProGamerGov

@NarineK I just tested installing Captum & Matplotlib, and neither installed the packaging library. Its listed in Matplotlib's setup.py, but not their setupext.py (which I think is used for the general user version of the package). They also use it for testing and some of the optional modules it looks like: https://github.com/matplotlib/matplotlib/search?p=1&q=packaging

Thank you for checking @ProGamerGov, makes sense! I added a question related to the _parse_version function ?

NarineK avatar Aug 15 '22 01:08 NarineK

@NarineK I've answered your question! The packaging library is downloaded as a dependency in the Captum dev install, but I'm not sure which package uses it as a dependency. So, we only need the _parse_version function for non test related code

ProGamerGov avatar Aug 15 '22 01:08 ProGamerGov

@NarineK has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

facebook-github-bot avatar Aug 15 '22 01:08 facebook-github-bot