From 3b8334b7e97fcd481f8adaf9b6f48e7f1020693c Mon Sep 17 00:00:00 2001 From: Guillem Serra Cazorla Date: Fri, 5 Jun 2026 15:04:09 +0100 Subject: [PATCH 1/2] Add support for PEP 751 pylock.toml lockfiles Add a PylockTomlHandler (datasource_id pypi_pylock_toml) that parses pylock.toml and pylock..toml files into resolved PyPI dependencies with versions, hashes, sources and dependency edges. Reference: https://github.com/aboutcode-org/scancode-toolkit/issues/4962 Signed-off-by: Guillem Serra Cazorla --- CHANGELOG.rst | 6 + src/packagedcode/__init__.py | 1 + src/packagedcode/pypi.py | 174 +++++++++ .../data/pypi/pylock/named/pylock.dev.toml | 9 + .../sample-package-assembly-expected.json | 20 + .../pylock/sample-pylock.toml-expected.json | 368 ++++++++++++++++++ .../data/pypi/pylock/sample/pylock.toml | 43 ++ tests/packagedcode/test_pypi.py | 34 ++ 8 files changed, 655 insertions(+) create mode 100644 tests/packagedcode/data/pypi/pylock/named/pylock.dev.toml create mode 100644 tests/packagedcode/data/pypi/pylock/sample-package-assembly-expected.json create mode 100644 tests/packagedcode/data/pypi/pylock/sample-pylock.toml-expected.json create mode 100644 tests/packagedcode/data/pypi/pylock/sample/pylock.toml diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9a5a6b402..85ee2f09a9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,12 @@ Next release ``licensedcode-data``. https://github.com/aboutcode-org/scancode-toolkit/pull/5056 +- Add support for PEP 751 ``pylock.toml`` standardized Python lockfiles. A new + ``pypi_pylock_toml`` package datafile handler parses ``pylock.toml`` and + ``pylock..toml`` files into resolved PyPI dependencies with their + versions, hashes and sources. + https://github.com/aboutcode-org/scancode-toolkit/issues/4962 + v33.0.0rc1 - 2026-05-14 ------------------------ diff --git a/src/packagedcode/__init__.py b/src/packagedcode/__init__.py index fc1e490eef..6d2b9799a2 100644 --- a/src/packagedcode/__init__.py +++ b/src/packagedcode/__init__.py @@ -176,6 +176,7 @@ pypi.PoetryLockHandler, pypi.UvPyprojectTomlHandler, pypi.UvLockHandler, + pypi.PylockTomlHandler, pypi.PythonEditableInstallationPkgInfoFile, pypi.PythonEggPkgInfoFile, pypi.PythonInstalledWheelMetadataFile, diff --git a/src/packagedcode/pypi.py b/src/packagedcode/pypi.py index dcfd237590..17b62a830a 100644 --- a/src/packagedcode/pypi.py +++ b/src/packagedcode/pypi.py @@ -1126,6 +1126,180 @@ def parse(cls, location, package_only=False): yield models.PackageData.from_data(package_data, package_only) +class PylockTomlHandler(models.DatafileHandler): + datasource_id = 'pypi_pylock_toml' + path_patterns = ('*pylock.toml', '*pylock.*.toml',) + default_package_type = 'pypi' + default_primary_language = 'Python' + description = 'PEP 751 pylock.toml Python lockfile' + documentation_url = 'https://peps.python.org/pep-0751/' + + @classmethod + def parse(cls, location, package_only=False): + with open(location, "rb") as fp: + toml_data = tomllib.load(fp) + + # PEP 751 uses a top-level ``packages`` array (note: plural, unlike the + # ``package`` key used by uv.lock and poetry.lock). + packages = toml_data.get('packages') + if not packages: + return + + dependencies = [] + for package in packages: + name = package.get('name') + if not name: + continue + version = package.get('version') + + # ``[[packages.dependencies]]`` are edges referencing other locked + # packages by name (the resolved dependency graph). + dependencies_for_resolved = [] + for dep in (package.get('dependencies') or []): + dep_name = dep.get('name') + if not dep_name: + continue + dep_purl = PackageURL(type=cls.default_package_type, name=dep_name) + dependencies_for_resolved.append( + models.DependentPackage( + purl=dep_purl.to_string(), + extracted_requirement=None, + scope='dependencies', + is_runtime=True, + is_optional=False, + is_direct=True, + is_pinned=False, + ).to_dict() + ) + + # PEP 751 package sources are mutually exclusive: an ``index`` + # (with ``sdist`` and/or ``wheels``), ``vcs``, ``directory`` or + # ``archive``. Unlike uv.lock, hashes are stored as a table keyed + # by algorithm (e.g. ``hashes.sha256``) rather than a + # ``"sha256:"`` string. + download_url = None + sha256 = None + file_name = None + vcs_url = None + extra_data = {} + + sdist = package.get('sdist') + wheels = package.get('wheels') + archive = package.get('archive') + vcs = package.get('vcs') + directory = package.get('directory') + index = package.get('index') + + if isinstance(sdist, dict): + download_url = sdist.get('url') + sha256 = (sdist.get('hashes') or {}).get('sha256') + elif wheels: + first_wheel = wheels[0] or {} + download_url = first_wheel.get('url') + sha256 = (first_wheel.get('hashes') or {}).get('sha256') + elif isinstance(archive, dict): + download_url = archive.get('url') + sha256 = (archive.get('hashes') or {}).get('sha256') + extra_data['source_type'] = 'archive' + elif isinstance(vcs, dict): + vcs_url = vcs.get('url') + extra_data['source_type'] = 'vcs' + commit_id = vcs.get('commit-id') + if commit_id: + extra_data['vcs_commit_id'] = commit_id + elif isinstance(directory, dict): + extra_data['source_type'] = 'directory' + dir_path = directory.get('path') + if dir_path: + extra_data['directory'] = dir_path + + if index: + extra_data['index'] = index + + marker = package.get('marker') + if marker: + extra_data['marker'] = marker + + if download_url: + file_name = posixpath.basename(download_url) or None + + # Only synthesize PyPI URLs for packages actually sourced from a + # PyPI-style index. For ``vcs``, ``directory`` or ``archive`` + # sources we record only what the lock file provides (e.g. the + # archive ``url`` as the download URL, the git URL in ``vcs_url``) + # rather than inventing a pypi.org URL that does not exist. + if index or isinstance(sdist, dict) or wheels: + urls = get_pypi_urls(name, version) + if download_url: + # prefer the exact artifact URL recorded in the lock file + urls['repository_download_url'] = download_url + else: + urls = dict( + repository_homepage_url=None, + repository_download_url=download_url, + api_data_url=None, + ) + + qualifiers = {} + if file_name: + # per purl-spec PyPI definition the artifact ``file_name`` is + # carried as a purl qualifier so the purl identifies the + # specific artifact recorded in the lock file. + qualifiers['file_name'] = file_name + + resolved_package_data = dict( + datasource_id=cls.datasource_id, + type=cls.default_package_type, + primary_language='Python', + name=name, + version=version, + qualifiers=qualifiers, + sha256=sha256, + vcs_url=vcs_url, + is_virtual=True, + dependencies=dependencies_for_resolved, + extra_data=extra_data, + **urls, + ) + resolved_package = models.PackageData.from_data(resolved_package_data, package_only) + + dependencies.append( + models.DependentPackage( + purl=resolved_package.purl, + extracted_requirement=None, + scope=None, + is_runtime=True, + is_optional=False, + is_direct=False, + is_pinned=bool(version), + resolved_package=resolved_package.to_dict(), + ).to_dict() + ) + + extra_data = {} + lock_version = toml_data.get('lock-version') + if lock_version is not None: + extra_data['lock_version'] = lock_version + requires_python = toml_data.get('requires-python') + if requires_python: + extra_data['python_requires'] = requires_python + created_by = toml_data.get('created-by') + if created_by: + extra_data['created_by'] = created_by + environments = toml_data.get('environments') + if environments: + extra_data['environments'] = environments + + package_data = dict( + datasource_id=cls.datasource_id, + type=cls.default_package_type, + primary_language='Python', + extra_data=extra_data, + dependencies=dependencies, + ) + yield models.PackageData.from_data(package_data, package_only) + + class PipInspectDeplockHandler(models.DatafileHandler): datasource_id = 'pypi_inspect_deplock' path_patterns = ('*pip-inspect.deplock',) diff --git a/tests/packagedcode/data/pypi/pylock/named/pylock.dev.toml b/tests/packagedcode/data/pypi/pylock/named/pylock.dev.toml new file mode 100644 index 0000000000..eab725a4d6 --- /dev/null +++ b/tests/packagedcode/data/pypi/pylock/named/pylock.dev.toml @@ -0,0 +1,9 @@ +lock-version = "1.0" +requires-python = ">=3.9" +created-by = "pip" + +[[packages]] +name = "click" +version = "8.1.7" +index = "https://pypi.org/simple" +sdist = {name = "click-8.1.7.tar.gz", url = "https://files.pythonhosted.org/packages/source/c/click/click-8.1.7.tar.gz", hashes = {sha256 = "ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}} diff --git a/tests/packagedcode/data/pypi/pylock/sample-package-assembly-expected.json b/tests/packagedcode/data/pypi/pylock/sample-package-assembly-expected.json new file mode 100644 index 0000000000..734e4e5dd1 --- /dev/null +++ b/tests/packagedcode/data/pypi/pylock/sample-package-assembly-expected.json @@ -0,0 +1,20 @@ +{ + "packages": [], + "dependencies": [], + "files": [ + { + "path": "sample", + "type": "directory", + "package_data": [], + "for_packages": [], + "scan_errors": [] + }, + { + "path": "sample/pylock.toml", + "type": "file", + "package_data": [], + "for_packages": [], + "scan_errors": [] + } + ] +} \ No newline at end of file diff --git a/tests/packagedcode/data/pypi/pylock/sample-pylock.toml-expected.json b/tests/packagedcode/data/pypi/pylock/sample-pylock.toml-expected.json new file mode 100644 index 0000000000..37bbc11b28 --- /dev/null +++ b/tests/packagedcode/data/pypi/pylock/sample-pylock.toml-expected.json @@ -0,0 +1,368 @@ +[ + { + "type": "pypi", + "namespace": null, + "name": null, + "version": null, + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": null, + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": null, + "download_url": null, + "size": null, + "sha1": null, + "md5": null, + "sha256": null, + "sha512": null, + "bug_tracking_url": null, + "code_view_url": null, + "vcs_url": null, + "copyright": null, + "holder": null, + "declared_license_expression": null, + "declared_license_expression_spdx": null, + "license_detections": [], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": null, + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": false, + "extra_data": { + "lock_version": "1.0", + "python_requires": ">=3.9", + "created_by": "uv", + "environments": [ + "sys_platform == 'linux'", + "sys_platform == 'win32'" + ] + }, + "dependencies": [ + { + "purl": "pkg:pypi/attrs@25.1.0?file_name=attrs-25.1.0.tar.gz", + "extracted_requirement": null, + "scope": null, + "is_runtime": true, + "is_optional": false, + "is_pinned": true, + "is_direct": false, + "resolved_package": { + "type": "pypi", + "namespace": null, + "name": "attrs", + "version": "25.1.0", + "qualifiers": { + "file_name": "attrs-25.1.0.tar.gz" + }, + "subpath": null, + "primary_language": "Python", + "description": null, + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": null, + "download_url": null, + "size": null, + "sha1": null, + "md5": null, + "sha256": "1c97078a80c814273a76b2a8da89c3b3b4b5e3e9c4b0c1d2e3f4a5b6c7d8e9f0", + "sha512": null, + "bug_tracking_url": null, + "code_view_url": null, + "vcs_url": null, + "copyright": null, + "holder": null, + "declared_license_expression": null, + "declared_license_expression_spdx": null, + "license_detections": [], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": null, + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": true, + "extra_data": { + "index": "https://pypi.org/simple" + }, + "dependencies": [], + "repository_homepage_url": "https://pypi.org/project/attrs", + "repository_download_url": "https://files.pythonhosted.org/packages/source/a/attrs/attrs-25.1.0.tar.gz", + "api_data_url": "https://pypi.org/pypi/attrs/25.1.0/json", + "datasource_id": "pypi_pylock_toml", + "purl": "pkg:pypi/attrs@25.1.0?file_name=attrs-25.1.0.tar.gz" + }, + "extra_data": {} + }, + { + "purl": "pkg:pypi/cattrs@24.1.2?file_name=cattrs-24.1.2.tar.gz", + "extracted_requirement": null, + "scope": null, + "is_runtime": true, + "is_optional": false, + "is_pinned": true, + "is_direct": false, + "resolved_package": { + "type": "pypi", + "namespace": null, + "name": "cattrs", + "version": "24.1.2", + "qualifiers": { + "file_name": "cattrs-24.1.2.tar.gz" + }, + "subpath": null, + "primary_language": "Python", + "description": null, + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": null, + "download_url": null, + "size": null, + "sha1": null, + "md5": null, + "sha256": "8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85", + "sha512": null, + "bug_tracking_url": null, + "code_view_url": null, + "vcs_url": null, + "copyright": null, + "holder": null, + "declared_license_expression": null, + "declared_license_expression_spdx": null, + "license_detections": [], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": null, + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": true, + "extra_data": { + "index": "https://pypi.org/simple" + }, + "dependencies": [ + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + } + ], + "repository_homepage_url": "https://pypi.org/project/cattrs", + "repository_download_url": "https://files.pythonhosted.org/packages/source/c/cattrs/cattrs-24.1.2.tar.gz", + "api_data_url": "https://pypi.org/pypi/cattrs/24.1.2/json", + "datasource_id": "pypi_pylock_toml", + "purl": "pkg:pypi/cattrs@24.1.2?file_name=cattrs-24.1.2.tar.gz" + }, + "extra_data": {} + }, + { + "purl": "pkg:pypi/tomli@2.0.1?file_name=tomli-2.0.1.tar.gz", + "extracted_requirement": null, + "scope": null, + "is_runtime": true, + "is_optional": false, + "is_pinned": true, + "is_direct": false, + "resolved_package": { + "type": "pypi", + "namespace": null, + "name": "tomli", + "version": "2.0.1", + "qualifiers": { + "file_name": "tomli-2.0.1.tar.gz" + }, + "subpath": null, + "primary_language": "Python", + "description": null, + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": null, + "download_url": null, + "size": null, + "sha1": null, + "md5": null, + "sha256": "de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f", + "sha512": null, + "bug_tracking_url": null, + "code_view_url": null, + "vcs_url": null, + "copyright": null, + "holder": null, + "declared_license_expression": null, + "declared_license_expression_spdx": null, + "license_detections": [], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": null, + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": true, + "extra_data": { + "index": "https://pypi.org/simple", + "marker": "python_version < '3.11'" + }, + "dependencies": [], + "repository_homepage_url": "https://pypi.org/project/tomli", + "repository_download_url": "https://files.pythonhosted.org/packages/source/t/tomli/tomli-2.0.1.tar.gz", + "api_data_url": "https://pypi.org/pypi/tomli/2.0.1/json", + "datasource_id": "pypi_pylock_toml", + "purl": "pkg:pypi/tomli@2.0.1?file_name=tomli-2.0.1.tar.gz" + }, + "extra_data": {} + }, + { + "purl": "pkg:pypi/examplelib@1.2.3", + "extracted_requirement": null, + "scope": null, + "is_runtime": true, + "is_optional": false, + "is_pinned": true, + "is_direct": false, + "resolved_package": { + "type": "pypi", + "namespace": null, + "name": "examplelib", + "version": "1.2.3", + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": null, + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": null, + "download_url": null, + "size": null, + "sha1": null, + "md5": null, + "sha256": null, + "sha512": null, + "bug_tracking_url": null, + "code_view_url": null, + "vcs_url": "https://github.com/example/examplelib.git", + "copyright": null, + "holder": null, + "declared_license_expression": null, + "declared_license_expression_spdx": null, + "license_detections": [], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": null, + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": true, + "extra_data": { + "source_type": "vcs", + "vcs_commit_id": "fde1660f7f5b3b3b3b3b3b3b3b3b3b3b3b3b3b3b" + }, + "dependencies": [ + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + } + ], + "repository_homepage_url": null, + "repository_download_url": null, + "api_data_url": null, + "datasource_id": "pypi_pylock_toml", + "purl": "pkg:pypi/examplelib@1.2.3" + }, + "extra_data": {} + }, + { + "purl": "pkg:pypi/localproject", + "extracted_requirement": null, + "scope": null, + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": false, + "resolved_package": { + "type": "pypi", + "namespace": null, + "name": "localproject", + "version": null, + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": null, + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": null, + "download_url": null, + "size": null, + "sha1": null, + "md5": null, + "sha256": null, + "sha512": null, + "bug_tracking_url": null, + "code_view_url": null, + "vcs_url": null, + "copyright": null, + "holder": null, + "declared_license_expression": null, + "declared_license_expression_spdx": null, + "license_detections": [], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": null, + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": true, + "extra_data": { + "source_type": "directory", + "directory": "." + }, + "dependencies": [], + "repository_homepage_url": null, + "repository_download_url": null, + "api_data_url": null, + "datasource_id": "pypi_pylock_toml", + "purl": "pkg:pypi/localproject" + }, + "extra_data": {} + } + ], + "repository_homepage_url": null, + "repository_download_url": null, + "api_data_url": null, + "datasource_id": "pypi_pylock_toml", + "purl": null + } +] \ No newline at end of file diff --git a/tests/packagedcode/data/pypi/pylock/sample/pylock.toml b/tests/packagedcode/data/pypi/pylock/sample/pylock.toml new file mode 100644 index 0000000000..1ab1761d7c --- /dev/null +++ b/tests/packagedcode/data/pypi/pylock/sample/pylock.toml @@ -0,0 +1,43 @@ +lock-version = "1.0" +environments = ["sys_platform == 'linux'", "sys_platform == 'win32'"] +requires-python = ">=3.9" +created-by = "uv" + +[[packages]] +name = "attrs" +version = "25.1.0" +requires-python = ">=3.8" +index = "https://pypi.org/simple" +sdist = {name = "attrs-25.1.0.tar.gz", url = "https://files.pythonhosted.org/packages/source/a/attrs/attrs-25.1.0.tar.gz", size = 810562, hashes = {sha256 = "1c97078a80c814273a76b2a8da89c3b3b4b5e3e9c4b0c1d2e3f4a5b6c7d8e9f0"}} +wheels = [{name = "attrs-25.1.0-py3-none-any.whl", url = "https://files.pythonhosted.org/packages/py3/a/attrs/attrs-25.1.0-py3-none-any.whl", size = 63152, hashes = {sha256 = "c75a69e28a550a7e93789579886901d0f06d3fa8fd1ec9a5e5b5b5b5b5b5b5b5"}}] + +[[packages]] +name = "cattrs" +version = "24.1.2" +index = "https://pypi.org/simple" +dependencies = [{name = "attrs"}] +sdist = {name = "cattrs-24.1.2.tar.gz", url = "https://files.pythonhosted.org/packages/source/c/cattrs/cattrs-24.1.2.tar.gz", size = 426414, hashes = {sha256 = "8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85"}} +wheels = [{name = "cattrs-24.1.2-py3-none-any.whl", url = "https://files.pythonhosted.org/packages/py3/c/cattrs/cattrs-24.1.2-py3-none-any.whl", size = 66446, hashes = {sha256 = "67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0"}}] + +[[packages]] +name = "tomli" +version = "2.0.1" +marker = "python_version < '3.11'" +index = "https://pypi.org/simple" +sdist = {name = "tomli-2.0.1.tar.gz", url = "https://files.pythonhosted.org/packages/source/t/tomli/tomli-2.0.1.tar.gz", hashes = {sha256 = "de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}} + +[[packages]] +name = "examplelib" +version = "1.2.3" +dependencies = [{name = "attrs"}] +[packages.vcs] +type = "git" +url = "https://github.com/example/examplelib.git" +requested-revision = "main" +commit-id = "fde1660f7f5b3b3b3b3b3b3b3b3b3b3b3b3b3b3b" + +[[packages]] +name = "localproject" +[packages.directory] +path = "." +editable = true diff --git a/tests/packagedcode/test_pypi.py b/tests/packagedcode/test_pypi.py index 20afae813d..d6cfba5757 100644 --- a/tests/packagedcode/test_pypi.py +++ b/tests/packagedcode/test_pypi.py @@ -458,6 +458,40 @@ def test_package_scan_uv_end_to_end(self): check_json_scan(expected_file, result_file, remove_uuid=True, regen=REGEN_TEST_FIXTURES) +class TestPylockTomlHandler(PackageTester): + # PEP 751 pylock.toml fixtures, see https://peps.python.org/pep-0751/ + test_data_dir = os.path.join(os.path.dirname(__file__), 'data') + + def test_is_pylock_toml(self): + test_file = self.get_test_loc('pypi/pylock/sample/pylock.toml') + assert pypi.PylockTomlHandler.is_datafile(test_file) + + def test_is_pylock_toml_named_variant(self): + test_file = self.get_test_loc('pypi/pylock/named/pylock.dev.toml') + assert pypi.PylockTomlHandler.is_datafile(test_file) + + def test_parse_pylock_toml(self): + test_file = self.get_test_loc('pypi/pylock/sample/pylock.toml') + package = pypi.PylockTomlHandler.parse(test_file) + expected_loc = self.get_test_loc( + 'pypi/pylock/sample-pylock.toml-expected.json', + must_exist=False, + ) + self.check_packages_data( + package, expected_loc, must_exist=False, regen=REGEN_TEST_FIXTURES, + ) + + def test_package_scan_pylock_end_to_end(self): + test_dir = self.get_test_loc('pypi/pylock/sample/') + result_file = self.get_temp_file('json') + expected_file = self.get_test_loc( + 'pypi/pylock/sample-package-assembly-expected.json', + must_exist=False, + ) + run_scan_click(['--package', '--processes', '-1', test_dir, '--json-pp', result_file]) + check_json_scan(expected_file, result_file, remove_uuid=True, regen=REGEN_TEST_FIXTURES) + + class TestPipInspectDeplockHandler(PackageTester): test_data_dir = os.path.join(os.path.dirname(__file__), 'data') From 1ad9eed337f0ff1b89d4511dc591a67e44f7f812 Mon Sep 17 00:00:00 2001 From: Guillem Serra Cazorla Date: Fri, 5 Jun 2026 16:07:38 +0100 Subject: [PATCH 2/2] Add pylock.toml to the --list-packages snapshot fixture Signed-off-by: Guillem Serra Cazorla --- .../reference/scancode-supported-packages.rst | 94 ++++++------------- .../data/plugin/plugins_list_linux.txt | 7 ++ 2 files changed, 35 insertions(+), 66 deletions(-) diff --git a/docs/source/reference/scancode-supported-packages.rst b/docs/source/reference/scancode-supported-packages.rst index d2ad15803f..ebd7177017 100644 --- a/docs/source/reference/scancode-supported-packages.rst +++ b/docs/source/reference/scancode-supported-packages.rst @@ -1,9 +1,11 @@ -.. _supported-packages: + + +.. _supported_packages: Supported package manifests and package datafiles ------------------------------------------------- -ScanCode supports a wide variety of package manifests, lockfiles +Scancode supports a wide variety of package manifests, lockfiles and other package datafiles containing package and dependency information. @@ -138,13 +140,6 @@ parsers in scancode-toolkit during documentation builds. - ``cargo_toml`` - Rust - https://doc.rust-lang.org/cargo/reference/manifest.html - * - Rust binary - - None - - ``cargo`` - - ``linux``, ``win``, ``mac`` - - ``rust_binary`` - - Rust - - https://github.com/rust-secure-code/cargo-auditable/blob/master/PARSING.md * - Chef cookbook metadata.json - ``*/metadata.json`` - ``chef`` @@ -442,7 +437,7 @@ parsers in scancode-toolkit during documentation builds. - https://guides.rubygems.org/specification-reference/ * - RubyGems Bundler Gemfile - ``*/Gemfile`` - ``*/*.gemfile`` + ``*.gemfile`` ``*/Gemfile-*`` - ``gem`` - ``linux``, ``win``, ``mac`` @@ -505,13 +500,6 @@ parsers in scancode-toolkit during documentation builds. - ``godeps`` - Go - https://github.com/tools/godep - * - Go binary - - None - - ``golang`` - - ``linux``, ``win``, ``mac`` - - ``golang_binary`` - - Go - - https://github.com/nexB/go-inspector/ * - Haxe haxelib.json metadata file - ``*/haxelib.json`` - ``haxe`` @@ -622,13 +610,6 @@ parsers in scancode-toolkit during documentation builds. - ``mozilla_xpi`` - JavaScript - https://en.wikipedia.org/wiki/XPInstall - * - Microsoft MSI installer - - ``*.msi`` - - ``msi`` - - ``linux`` - - ``msi_installer`` - - None - - https://docs.microsoft.com/en-us/windows/win32/msi/windows-installer-portal * - npm package.json - ``*/package.json`` - ``npm`` @@ -812,6 +793,14 @@ parsers in scancode-toolkit during documentation builds. - ``pypi_poetry_pyproject_toml`` - Python - https://packaging.python.org/en/latest/specifications/pyproject-toml/ + * - PEP 751 pylock.toml Python lockfile + - ``*pylock.toml`` + ``*pylock.*.toml`` + - ``pypi`` + - ``linux``, ``win``, ``mac`` + - ``pypi_pylock_toml`` + - Python + - https://peps.python.org/pep-0751/ * - Python pyproject.toml - ``*pyproject.toml`` - ``pypi`` @@ -840,6 +829,20 @@ parsers in scancode-toolkit during documentation builds. - ``pypi_setup_py`` - Python - https://docs.python.org/3.11/distutils/setupscript.html + * - Python UV lockfile + - ``*uv.lock`` + - ``pypi`` + - ``linux``, ``win``, ``mac`` + - ``pypi_uv_lock`` + - Python + - https://docs.astral.sh/uv/concepts/projects/sync/#the-uvlock-file + * - Python UV pyproject.toml + - ``*pyproject.toml`` + - ``pypi`` + - ``linux``, ``win``, ``mac`` + - ``pypi_uv_pyproject_toml`` + - Python + - https://docs.astral.sh/uv/concepts/projects/ * - PyPI wheel - ``*.whl`` - ``pypi`` @@ -876,27 +879,6 @@ parsers in scancode-toolkit during documentation builds. - ``rpm_archive`` - None - https://en.wikipedia.org/wiki/RPM_Package_Manager - * - RPM installed package BDB database - - ``*var/lib/rpm/Packages`` - - ``rpm`` - - ``linux`` - - ``rpm_installed_database_bdb`` - - None - - https://man7.org/linux/man-pages/man8/rpmdb.8.html - * - RPM installed package NDB database - - ``*usr/lib/sysimage/rpm/Packages.db`` - - ``rpm`` - - ``linux`` - - ``rpm_installed_database_ndb`` - - None - - https://fedoraproject.org/wiki/Changes/NewRpmDBFormat - * - RPM installed package SQLite database - - ``*rpm/rpmdb.sqlite`` - - ``rpm`` - - ``linux`` - - ``rpm_installed_database_sqlite`` - - None - - https://fedoraproject.org/wiki/Changes/Sqlite_Rpmdb * - RPM mariner distroless package manifest - ``*var/lib/rpmmanifest/container-manifest-2`` - ``rpm`` @@ -970,27 +952,6 @@ parsers in scancode-toolkit during documentation builds. - ``java_war_web_xml`` - Java - https://en.wikipedia.org/wiki/WAR_(file_format) - * - Windows Registry Installed Program - Docker SOFTWARE - - ``*/Files/Windows/System32/config/SOFTWARE`` - - ``windows-program`` - - ``linux`` - - ``win_reg_installed_programs_docker_file_software`` - - None - - https://en.wikipedia.org/wiki/Windows_Registry - * - Windows Registry Installed Program - Docker Software Delta - - ``*/Hives/Software_Delta`` - - ``windows-program`` - - ``linux`` - - ``win_reg_installed_programs_docker_software_delta`` - - None - - https://en.wikipedia.org/wiki/Windows_Registry - * - Windows Registry Installed Program - Docker UtilityVM SOFTWARE - - ``*/UtilityVM/Files/Windows/System32/config/SOFTWARE`` - - ``windows-program`` - - ``linux`` - - ``win_reg_installed_programs_docker_utility_software`` - - None - - https://en.wikipedia.org/wiki/Windows_Registry * - Microsoft Update Manifest .mum file - ``*.mum`` - ``windows-update`` @@ -1021,3 +982,4 @@ parsers in scancode-toolkit during documentation builds. - ``windows_executable`` - None - https://en.wikipedia.org/wiki/Portable_Executable + \ No newline at end of file diff --git a/tests/packagedcode/data/plugin/plugins_list_linux.txt b/tests/packagedcode/data/plugin/plugins_list_linux.txt index 34078bc580..15bdac5845 100755 --- a/tests/packagedcode/data/plugin/plugins_list_linux.txt +++ b/tests/packagedcode/data/plugin/plugins_list_linux.txt @@ -762,6 +762,13 @@ Package type: pypi description: Python poetry pyproject.toml path_patterns: '*pyproject.toml' -------------------------------------------- +Package type: pypi + datasource_id: pypi_pylock_toml + documentation URL: https://peps.python.org/pep-0751/ + primary language: Python + description: PEP 751 pylock.toml Python lockfile + path_patterns: '*pylock.toml', '*pylock.*.toml' +-------------------------------------------- Package type: pypi datasource_id: pypi_pyproject_toml documentation URL: https://packaging.python.org/en/latest/specifications/pyproject-toml/