diff --git a/CHANGES b/CHANGES index 3298acbd247..3ffc7d7e0d0 100644 --- a/CHANGES +++ b/CHANGES @@ -42,6 +42,7 @@ Bugs fixed * #9649: HTML search: when objects have the same name but in different domains, return all of them as result instead of just one. * #9678: linkcheck: file extension was shown twice in warnings +* #9708: needs_extension failed to check double-digit version correctly Testing -------- diff --git a/sphinx/extension.py b/sphinx/extension.py index 7ec6c8518c3..34bf7763ad7 100644 --- a/sphinx/extension.py +++ b/sphinx/extension.py @@ -10,6 +10,8 @@ from typing import TYPE_CHECKING, Any, Dict +from packaging.version import InvalidVersion, Version + from sphinx.config import Config from sphinx.errors import VersionRequirementError from sphinx.locale import __ @@ -51,7 +53,18 @@ def verify_needs_extensions(app: "Sphinx", config: Config) -> None: 'but it is not loaded.'), extname) continue - if extension.version == 'unknown version' or reqversion > extension.version: + fulfilled = True + if extension.version == 'unknown version': + fulfilled = False + else: + try: + if Version(reqversion) > Version(extension.version): + fulfilled = False + except InvalidVersion: + if reqversion > extension.version: + fulfilled = False + + if not fulfilled: raise VersionRequirementError(__('This project needs the extension %s at least in ' 'version %s and therefore cannot be built with ' 'the loaded version (%s).') % diff --git a/tests/test_extension.py b/tests/test_extension.py new file mode 100644 index 00000000000..00080ef04b4 --- /dev/null +++ b/tests/test_extension.py @@ -0,0 +1,32 @@ +""" + test_extension + ~~~~~~~~~~~~~~ + + Test sphinx.extesion module. + + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import pytest + + +from sphinx.errors import VersionRequirementError +from sphinx.extension import Extension, verify_needs_extensions + + +def test_needs_extensions(app): + # empty needs_extensions + assert app.config.needs_extensions == {} + verify_needs_extensions(app, app.config) + + # needs_extensions fulfilled + app.config.needs_extensions = {'test.extension': '3.9'} + app.extensions['test.extension'] = Extension('test.extension', 'test.extension', version='3.10') + verify_needs_extensions(app, app.config) + + # needs_extensions not fulfilled + app.config.needs_extensions = {'test.extension': '3.11'} + app.extensions['test.extension'] = Extension('test.extension', 'test.extension', version='3.10') + with pytest.raises(VersionRequirementError): + verify_needs_extensions(app, app.config)