Skip to content

Use packaging to do version comparisons. #20437

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

Merged
merged 1 commit into from
Jun 19, 2021
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 .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ jobs:

# Install dependencies from PyPI.
python -m pip install --upgrade $PRE \
cycler kiwisolver numpy pillow pyparsing python-dateutil setuptools-scm \
cycler kiwisolver numpy packaging pillow pyparsing python-dateutil \
setuptools-scm \
-r requirements/testing/all.txt \
${{ matrix.extra-requirements }}

Expand Down
4 changes: 2 additions & 2 deletions examples/units/basic_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

"""

from distutils.version import LooseVersion
import math

import numpy as np
from packaging.version import parse as parse_version

import matplotlib.units as units
import matplotlib.ticker as ticker
Expand Down Expand Up @@ -155,7 +155,7 @@ def __str__(self):
def __len__(self):
return len(self.value)

if LooseVersion(np.__version__) >= '1.20':
if parse_version(np.__version__) >= parse_version('1.20'):
def __getitem__(self, key):
return TaggedValue(self.value[key], self.unit)

Expand Down
24 changes: 12 additions & 12 deletions lib/matplotlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
from collections import namedtuple
from collections.abc import MutableMapping
import contextlib
from distutils.version import LooseVersion
import functools
import importlib
import inspect
Expand All @@ -103,6 +102,7 @@
import warnings

import numpy
from packaging.version import parse as parse_version

# cbook must import matplotlib only within function
# definitions, so it is safe to import from it here.
Expand Down Expand Up @@ -165,9 +165,9 @@ def _check_versions():
("pyparsing", "2.2.1"),
]:
module = importlib.import_module(modname)
if LooseVersion(module.__version__) < minver:
raise ImportError("Matplotlib requires {}>={}; you have {}"
.format(modname, minver, module.__version__))
if parse_version(module.__version__) < parse_version(minver):
raise ImportError(f"Matplotlib requires {modname}>={minver}; "
f"you have {module.__version__}")


_check_versions()
Expand Down Expand Up @@ -274,8 +274,7 @@ def _get_executable_info(name):
-------
tuple
A namedtuple with fields ``executable`` (`str`) and ``version``
(`distutils.version.LooseVersion`, or ``None`` if the version cannot be
determined).
(`packaging.Version`, or ``None`` if the version cannot be determined).

Raises
------
Expand Down Expand Up @@ -305,8 +304,8 @@ def impl(args, regex, min_ver=None, ignore_exit_code=False):
raise ExecutableNotFoundError(str(_ose)) from _ose
match = re.search(regex, output)
if match:
version = LooseVersion(match.group(1))
if min_ver is not None and version < min_ver:
version = parse_version(match.group(1))
if min_ver is not None and version < parse_version(min_ver):
raise ExecutableNotFoundError(
f"You have {args[0]} version {version} but the minimum "
f"version supported by Matplotlib is {min_ver}")
Expand Down Expand Up @@ -367,17 +366,18 @@ def impl(args, regex, min_ver=None, ignore_exit_code=False):
else:
path = "convert"
info = impl([path, "--version"], r"^Version: ImageMagick (\S*)")
if info.version == "7.0.10-34":
if info.version == parse_version("7.0.10-34"):
# https://github.com/ImageMagick/ImageMagick/issues/2720
raise ExecutableNotFoundError(
f"You have ImageMagick {info.version}, which is unsupported")
return info
elif name == "pdftops":
info = impl(["pdftops", "-v"], "^pdftops version (.*)",
ignore_exit_code=True)
if info and not ("3.0" <= info.version
# poppler version numbers.
or "0.9" <= info.version <= "1.0"):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the <= 1.0 was an incorrect conversion from 32ed5bd

if info and not (
3 <= info.version.major or
# poppler version numbers.
parse_version("0.9") <= info.version < parse_version("1.0")):
raise ExecutableNotFoundError(
f"You have pdftops version {info.version} but the minimum "
f"version supported by Matplotlib is 3.0")
Expand Down
7 changes: 4 additions & 3 deletions lib/matplotlib/backends/qt_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
- otherwise, use whatever the rcParams indicate.
"""

from distutils.version import LooseVersion
import os
import platform
import sys

from packaging.version import parse as parse_version

import matplotlib as mpl


Expand Down Expand Up @@ -102,8 +103,8 @@ def _isdeleted(obj): return not shiboken2.isValid(obj)
# Fixes issues with Big Sur
# https://bugreports.qt.io/browse/QTBUG-87014, fixed in qt 5.15.2
if (sys.platform == 'darwin' and
LooseVersion(platform.mac_ver()[0]) >= LooseVersion("10.16") and
LooseVersion(QtCore.qVersion()) < LooseVersion("5.15.2") and
parse_version(platform.mac_ver()[0]) >= parse_version("10.16") and
parse_version(QtCore.qVersion()) < parse_version("5.15.2") and
"QT_MAC_WANTS_LAYER" not in os.environ):
os.environ["QT_MAC_WANTS_LAYER"] = "1"

Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/testing/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def encode_and_escape(name):

class _SVGConverter(_Converter):
def __call__(self, orig, dest):
old_inkscape = mpl._get_executable_info("inkscape").version < "1"
old_inkscape = mpl._get_executable_info("inkscape").version.major < 1
terminator = b"\n>" if old_inkscape else b"> "
if not hasattr(self, "_tmpdir"):
self._tmpdir = TemporaryDirectory()
Expand Down
15 changes: 8 additions & 7 deletions lib/matplotlib/testing/decorators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import contextlib
from distutils.version import StrictVersion
import functools
import inspect
import os
Expand All @@ -10,6 +9,8 @@
import unittest
import warnings

from packaging.version import parse as parse_version

import matplotlib.style
import matplotlib.units
import matplotlib.testing
Expand Down Expand Up @@ -92,20 +93,20 @@ def check_freetype_version(ver):

if isinstance(ver, str):
ver = (ver, ver)
ver = [StrictVersion(x) for x in ver]
found = StrictVersion(ft2font.__freetype_version__)
ver = [parse_version(x) for x in ver]
found = parse_version(ft2font.__freetype_version__)

return ver[0] <= found <= ver[1]


def _checked_on_freetype_version(required_freetype_version):
import pytest
reason = ("Mismatched version of freetype. "
"Test requires '%s', you have '%s'" %
(required_freetype_version, ft2font.__freetype_version__))
return pytest.mark.xfail(
not check_freetype_version(required_freetype_version),
reason=reason, raises=ImageComparisonFailure, strict=False)
reason=f"Mismatched version of freetype. "
f"Test requires '{required_freetype_version}', "
f"you have '{ft2font.__freetype_version__}'",
raises=ImageComparisonFailure, strict=False)


def remove_ticks_and_titles(figure):
Expand Down
4 changes: 3 additions & 1 deletion lib/matplotlib/tests/test_backend_pgf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import shutil

import numpy as np
from packaging.version import parse as parse_version
import pytest

import matplotlib as mpl
Expand Down Expand Up @@ -88,7 +89,8 @@ def test_xelatex():


try:
_old_gs_version = mpl._get_executable_info('gs').version < '9.50'
_old_gs_version = \
mpl._get_executable_info('gs').version < parse_version('9.50')
except mpl.ExecutableNotFoundError:
_old_gs_version = True

Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/tests/tinypages/conf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sphinx
from distutils.version import LooseVersion
from packaging.version import parse as parse_version

# -- General configuration ------------------------------------------------

Expand All @@ -16,7 +16,7 @@

# -- Options for HTML output ----------------------------------------------

if LooseVersion(sphinx.__version__) >= LooseVersion('1.3'):
if parse_version(sphinx.__version__) >= parse_version('1.3'):
html_theme = 'classic'
else:
html_theme = 'default'
Expand Down
4 changes: 3 additions & 1 deletion lib/matplotlib/texmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from tempfile import TemporaryDirectory

import numpy as np
from packaging.version import parse as parse_version

import matplotlib as mpl
from matplotlib import _api, cbook, dviread, rcParams
Expand Down Expand Up @@ -270,8 +271,9 @@ def make_png(self, tex, fontsize, dpi):
# dvipng 1.16 has a bug (fixed in f3ff241) that breaks --freetype0
# mode, so for it we keep FreeType enabled; the image will be
# slightly off.
bad_ver = parse_version("1.16")
if (getattr(mpl, "_called_from_pytest", False)
and mpl._get_executable_info("dvipng").version != "1.16"):
and mpl._get_executable_info("dvipng").version != bad_ver):
cmd.insert(1, "--freetype0")
self._run_checked_subprocess(cmd, tex)
return pngfile
Expand Down
1 change: 1 addition & 0 deletions requirements/testing/minver.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
cycler==0.10
kiwisolver==1.0.1
numpy==1.17.0
packaging==20.0
pillow==6.2.0
pyparsing==2.2.1
python-dateutil==2.7
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ def make_release_tree(self, base_dir, files):
"cycler>=0.10",
"kiwisolver>=1.0.1",
"numpy>=1.17",
"packaging>=20.0",
"pillow>=6.2.0",
"pyparsing>=2.2.1",
"python-dateutil>=2.7",
Expand Down