From f9c08c2015c6f4ca1042de43842dd5528591c1fe Mon Sep 17 00:00:00 2001 From: Aishwary Dongre <87765118+aishwary-dongre@users.noreply.github.com> Date: Mon, 21 Sep 2026 15:44:20 +0530 Subject: [PATCH] Point at licensedcode-data when no built-in licenses load The built-in license data ships in its own licensedcode-data package, so a plain scancode-toolkit install without it leaves the built-in licenses directory empty. load_licenses() then failed with only "Check to see if the license data files are available at ", which does not hint at the actual cause and sent at least one user hunting through the install before finding that licensedcode-data was missing. Mention the package and how to install it. The hint is added only when the directory being loaded is the built-in one, since a caller-supplied licenses_data_dir has nothing to do with how the built-in data is packaged. Reference: https://github.com/aboutcode-org/scancode-toolkit/issues/5053 Signed-off-by: Aishwary Dongre <87765118+aishwary-dongre@users.noreply.github.com> --- src/licensedcode/models.py | 10 ++++++ tests/licensedcode/test_license_models.py | 38 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/licensedcode/models.py b/src/licensedcode/models.py index 9947607d51c..a3d4205e322 100644 --- a/src/licensedcode/models.py +++ b/src/licensedcode/models.py @@ -852,6 +852,16 @@ def load_licenses( 'No licenses were loaded. Check to see if the license data files ' f'are available at "{licenses_data_dir}".' ) + if licenses_data_dir == join(data_dir, 'licenses'): + # The built-in license data ships in its own package, so the most + # likely cause here is that this package is not installed. + msg += ( + ' The built-in license data is published in a separate ' + '"licensedcode-data" package: install it with ' + '"pip install licensedcode-data", or install ' + '"scancode-toolkit[licenses]" to also get the prebuilt ' + 'license index.' + ) raise InvalidLicense(msg) return licenses diff --git a/tests/licensedcode/test_license_models.py b/tests/licensedcode/test_license_models.py index bbbe9253755..f29d8f9414c 100644 --- a/tests/licensedcode/test_license_models.py +++ b/tests/licensedcode/test_license_models.py @@ -10,6 +10,8 @@ import os from unittest import TestCase as TestCaseClass +import pytest + from commoncode.testcase import FileBasedTesting from licensedcode import index @@ -660,3 +662,39 @@ def test_get_key_phrases_ignores_nested_key_phrase_markup(self): raise Exception('Exception should be raised') except InvalidRuleRequiredPhrase: pass + + +class TestLoadLicensesFailure(object): + + def test_load_licenses_failure_mentions_licensedcode_data_for_builtin_dir( + self, tmp_path, monkeypatch + ): + # Point the built-in data dir at an empty tree, as it would be when the + # licensedcode-data package is not installed. + data_dir = tmp_path / 'data' + builtin_licenses_dir = data_dir / 'licenses' + builtin_licenses_dir.mkdir(parents=True) + monkeypatch.setattr(models, 'data_dir', str(data_dir)) + + with pytest.raises(models.InvalidLicense) as excinfo: + models.load_licenses(licenses_data_dir=str(builtin_licenses_dir)) + + message = str(excinfo.value) + assert 'No licenses were loaded' in message + assert 'licensedcode-data' in message + + def test_load_licenses_failure_omits_package_hint_for_other_dirs( + self, tmp_path, monkeypatch + ): + # A caller-provided directory has nothing to do with the packaging of + # the built-in license data, so the hint must not be added there. + monkeypatch.setattr(models, 'data_dir', str(tmp_path / 'data')) + custom_licenses_dir = tmp_path / 'custom-licenses' + custom_licenses_dir.mkdir() + + with pytest.raises(models.InvalidLicense) as excinfo: + models.load_licenses(licenses_data_dir=str(custom_licenses_dir)) + + message = str(excinfo.value) + assert 'No licenses were loaded' in message + assert 'licensedcode-data' not in message