import json import tempfile import unittest from pathlib import Path from types import SimpleNamespace from unittest.mock import patch from host.python_packages import validate_metadata from host.updates import resolve_packages class PythonPackageLicenseTests(unittest.TestCase): def test_permissive_and_weak_copyleft_metadata_is_accepted(self): validate_metadata([{"name": "yt-dlp", "license_expression": "Unlicense"}, {"name": "certifi", "license_expression": "MPL-2.0"}, {"name": "library", "license_expression": "MIT"}, {"name": "library", "license_expression": "LGPL-2.1-or-later"}]) def test_strong_copyleft_is_rejected_using_expression_or_classifiers(self): for metadata in [{"name": "mutagen"}, {"name": "dependency", "license_expression": "GPL-3.0-or-later"}, {"name": "dependency", "license_expression": "AGPL-3.0-only"}, {"name": "dependency", "classifier": ["License :: OSI Approved :: GNU General Public License v2 (GPLv2)"]}]: with self.subTest(metadata=metadata), self.assertRaises(ValueError): validate_metadata([metadata]) def test_incompatible_resolution_does_not_delete_the_existing_packages(self): with tempfile.TemporaryDirectory() as temporary: stage = Path(temporary) / "stage" packages = stage / "runtime/python/Lib/site-packages" packages.mkdir(parents=True) sentinel = packages / "existing.py" sentinel.write_text("original package", encoding="utf8") work = Path(temporary) / "work" work.mkdir() def resolve(command, **kwargs): report = Path(command[command.index("--report") + 1]) report.write_text(json.dumps({"install": [{"metadata": { "name": "mutagen", "license_expression": "GPL-2.0-or-later"}}]}), encoding="utf8") self.assertNotIn("yt-dlp[default]", command) return SimpleNamespace(returncode=0) response = {"urls": [{"filename": "pip-1-py3-none-any.whl", "url": "https://files.pythonhosted.org/pip.whl", "digests": {"sha256": "a" * 64}}]} with patch("host.updates.get", return_value=SimpleNamespace(json=lambda: response)), \ patch("host.updates.fetch"), patch("host.updates.subprocess.run", side_effect=resolve): with self.assertRaisesRegex(ValueError, "mutagen"): resolve_packages(stage, work, lambda *args: None) self.assertEqual(sentinel.read_text(), "original package") if __name__ == "__main__": unittest.main()