From e2d2268bc5c4dd5557334f0ed611493a1d2bbec5 Mon Sep 17 00:00:00 2001 From: Jamie McClymont Date: Wed, 27 Nov 2019 03:25:37 +1300 Subject: [PATCH] Provide hints when an invalid license id is input --- poetry/spdx/__init__.py | 31 ++++++++++++++++++++++++++++++- tests/spdx/test_main.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/poetry/spdx/__init__.py b/poetry/spdx/__init__.py index 80a2a67d736..3d6cc433f15 100644 --- a/poetry/spdx/__init__.py +++ b/poetry/spdx/__init__.py @@ -17,7 +17,36 @@ def license_by_id(identifier): id = identifier.lower() if id not in _licenses: - raise ValueError("Invalid license id: {}".format(identifier)) + err = "Invalid license id: {}\nPoetry uses SPDX license identifiers: https://spdx.org/licenses/".format( + identifier + ) + + # Covers the licenses listed as common for python packages in https://snyk.io/blog/over-10-of-python-packages-on-pypi-are-distributed-without-any-license/ + # MIT/WTFPL/Unlicense are excluded as their ids are simply their name - if someone types "mit", they've already found the license they were looking for + + common_strings = ["agpl", "lgpl", "gpl", "bsd", "apache", "mpl", "cc0"] + for str in common_strings: + if str in id: + + err += "\n" + err += "Did you mean one of the following?" + + matches = sorted( + { + license.id + for license in _licenses.values() + if license.id.lower().startswith(str) + and not license.is_deprecated + } + ) + + for license in matches: + err += "\n * {}".format(license) + + # Don't match agpl for "gpl" + break + + raise ValueError(err) return _licenses[id] diff --git a/tests/spdx/test_main.py b/tests/spdx/test_main.py index 00e0910044d..ef941458c89 100644 --- a/tests/spdx/test_main.py +++ b/tests/spdx/test_main.py @@ -41,3 +41,38 @@ def test_license_by_id_with_full_name(): def test_license_by_id_invalid(): with pytest.raises(ValueError): license_by_id("invalid") + + +def test_license_by_id_invalid_gpl(): + with pytest.raises(ValueError) as exc_info: + license_by_id("gpl") + + assert "Did you mean" in str(exc_info.value) + assert " GPL-3.0-only" in str(exc_info.value) + assert " AGPL-3.0-only" not in str(exc_info.value) + + +def test_license_by_id_invalid_agpl(): + with pytest.raises(ValueError) as exc_info: + license_by_id("agpl") + + assert "Did you mean" in str(exc_info.value) + assert " GPL-3.0-only" not in str(exc_info.value) + assert " AGPL-3.0-only" in str(exc_info.value) + + +def test_license_by_id_invalid_agpl_versioned(): + with pytest.raises(ValueError) as exc_info: + license_by_id("gnu agpl v3+") + + assert "Did you mean" in str(exc_info.value) + assert " GPL-3.0-only" not in str(exc_info.value) + assert " AGPL-3.0-only" in str(exc_info.value) + + +def test_license_by_id_invalid_unpopular(): + with pytest.raises(ValueError) as exc_info: + license_by_id("not-a-well-known-license") + + assert "spdx.org" in str(exc_info.value) + assert "Did you mean" not in str(exc_info.value)