diff --git a/src/packagedcode/cargo.py b/src/packagedcode/cargo.py index 3b2d342d828..cf75257b857 100644 --- a/src/packagedcode/cargo.py +++ b/src/packagedcode/cargo.py @@ -66,19 +66,14 @@ def assemble(cls, package_data, resource, codebase, package_adder): for attribute in attributes_to_copy: package_data.extra_data[attribute] = 'workspace' workspace_package_data[attribute] = getattr(package_data, attribute) + + datafile_path_patterns = CargoTomlHandler.path_patterns + CargoLockHandler.path_patterns - workspace_root = resource.parent(codebase) - if not workspace_root: - # If there's no parent (e.g., scanning a single file), use the directory part of the resource path - workspace_root_path = os.path.dirname(resource.path) - else: - workspace_root_path = workspace_root.path - - if workspace_package_data and workspace_members: - + root_resource = resource.parent(codebase) + if root_resource and workspace_package_data and workspace_members: # TODO: support glob patterns found in cargo workspaces for workspace_member_path in workspace_members: - workspace_directory_path = os.path.join(workspace_root_path, workspace_member_path) + workspace_directory_path = os.path.join(root_resource.path, workspace_member_path) workspace_directory = codebase.get_resource(path=workspace_directory_path) if not workspace_directory: continue @@ -103,20 +98,21 @@ def assemble(cls, package_data, resource, codebase, package_adder): resource.save(codebase) yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=('Cargo.toml', 'cargo.toml', 'Cargo.lock', 'cargo.lock'), - directory=workspace_directory, + datafile_path_patterns=datafile_path_patterns, + resource=workspace_directory, codebase=codebase, package_adder=package_adder, ) else: - parent_resource = resource.parent(codebase) - if parent_resource: - yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=('Cargo.toml', 'cargo.toml', 'Cargo.lock', 'cargo.lock'), - directory=parent_resource, - codebase=codebase, - package_adder=package_adder, - ) + if not root_resource: + root_resource = resource + + yield from cls.assemble_from_many_datafiles( + datafile_path_patterns=datafile_path_patterns, + resource=root_resource, + codebase=codebase, + package_adder=package_adder, + ) @classmethod def update_resource_package_data(cls, workspace, workspace_package_data, resource_package_data, mapping=None): diff --git a/src/packagedcode/chef.py b/src/packagedcode/chef.py index d5df6a2f6c4..d8951f0fdc7 100644 --- a/src/packagedcode/chef.py +++ b/src/packagedcode/chef.py @@ -146,9 +146,16 @@ def assemble(cls, package_data, resource, codebase, package_adder): """ Assemble Package from Chef metadata.rb, then from metadata.json files. """ + datafile_path_patterns = ( + ChefMetadataRbHandler.path_patterns + + ChefMetadataJsonHandler.path_patterns + ) + root_resource = resource.parent(codebase) + if not root_resource: + root_resource = resource yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=('metadata.rb', 'metadata.json',), - directory=resource.parent(codebase), + datafile_path_patterns=datafile_path_patterns, + resource=root_resource, codebase=codebase, package_adder=package_adder, ) diff --git a/src/packagedcode/cocoapods.py b/src/packagedcode/cocoapods.py index 863ac16b33e..69dafde71a6 100644 --- a/src/packagedcode/cocoapods.py +++ b/src/packagedcode/cocoapods.py @@ -139,73 +139,71 @@ def assemble(cls, package_data, resource, codebase, package_adder): """ if codebase.has_single_resource: yield from models.DatafileHandler.assemble(package_data, resource, codebase) - else: - # do we have more than one podspec? - parent = resource.parent(codebase) - sibling_podspecs = [ - r for r in parent.children(codebase) - if r.name.endswith('.podspec') - ] - - siblings_counts = len(sibling_podspecs) - has_single_podspec = siblings_counts == 1 - has_multiple_podspec = siblings_counts > 1 - - datafile_name_patterns = ( - 'Podfile.lock', - 'Podfile', + return + + # do we have more than one podspec? + parent = resource.parent(codebase) + sibling_podspecs = [ + r for r in parent.children(codebase) + if r.name.endswith('.podspec') + ] + + siblings_counts = len(sibling_podspecs) + has_single_podspec = siblings_counts == 1 + has_multiple_podspec = siblings_counts > 1 + + datafile_path_patterns = ( + PodfileLockHandler.path_patterns + + PodfileHandler.path_patterns + ) + if has_single_podspec: + # we can treat all podfile/spec as being for one package + podspec_path_patterns = (f"*{sibling_podspecs[0].name}",) + yield from cls.assemble_from_many_datafiles( + datafile_path_patterns=podspec_path_patterns + datafile_path_patterns, + resource=parent, + codebase=codebase, + package_adder=package_adder, ) - if has_single_podspec: - # we can treat all podfile/spec as being for one package - datafile_name_patterns = (sibling_podspecs[0].name,) + datafile_name_patterns - - yield from models.DatafileHandler.assemble_from_many_datafiles( - datafile_name_patterns=datafile_name_patterns, - directory=parent, - codebase=codebase, - package_adder=package_adder, - ) - - elif has_multiple_podspec: - # treat each of podspec and podfile alone without meraging - # as we cannot determine easily which podfile is for which - # podspec - podspec = sibling_podspecs.pop() - datafile_name_patterns = (podspec.name,) + datafile_name_patterns - - yield from models.DatafileHandler.assemble_from_many_datafiles( - datafile_name_patterns=datafile_name_patterns, - directory=parent, - codebase=codebase, - package_adder=package_adder, - ) + elif has_multiple_podspec: + # treat each of podspec and podfile alone without meraging + # as we cannot determine easily which podfile is for which + # podspec + podspec = sibling_podspecs.pop() + podspec_path_patterns = (f"*{podspec.name}",) + yield from cls.assemble_from_many_datafiles( + datafile_path_patterns=podspec_path_patterns + datafile_path_patterns, + resource=parent, + codebase=codebase, + package_adder=package_adder, + ) - for resource in sibling_podspecs: - datafile_path = resource.path - for package_data in resource.package_data: - package_data = models.PackageData.from_dict(package_data) - package = models.Package.from_package_data( - package_data=package_data, - datafile_path=datafile_path, - ) - cls.assign_package_to_resources( - package=package, - resource=resource, - codebase=codebase, - package_adder=package_adder, - ) - yield package - yield resource + for resource in sibling_podspecs: + datafile_path = resource.path + for package_data in resource.package_data: + package_data = models.PackageData.from_dict(package_data) + package = models.Package.from_package_data( + package_data=package_data, + datafile_path=datafile_path, + ) + cls.assign_package_to_resources( + package=package, + resource=resource, + codebase=codebase, + package_adder=package_adder, + ) + yield package + yield resource - else: - # has_no_podspec: - yield from models.DatafileHandler.assemble_from_many_datafiles( - datafile_name_patterns=datafile_name_patterns, - directory=parent, - codebase=codebase, - package_adder=package_adder, - ) + else: + # has_no_podspec: + yield from cls.assemble_from_many_datafiles( + datafile_path_patterns=datafile_path_patterns, + resource=parent, + codebase=codebase, + package_adder=package_adder, + ) class PodspecHandler(BasePodHandler): diff --git a/src/packagedcode/golang.py b/src/packagedcode/golang.py index c45be7a5e3a..f5817287144 100644 --- a/src/packagedcode/golang.py +++ b/src/packagedcode/golang.py @@ -32,9 +32,15 @@ def assemble(cls, package_data, resource, codebase, package_adder): """ Always use go.mod first then go.sum """ + datafile_path_patterns = ( + GoModHandler.path_patterns + GoSumHandler.path_patterns + ) + root_resource = resource.parent(codebase) + if not root_resource: + root_resource = resource yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=('go.mod', 'go.sum',), - directory=resource.parent(codebase), + datafile_path_patterns=datafile_path_patterns, + resource=root_resource, codebase=codebase, package_adder=package_adder, ) diff --git a/src/packagedcode/models.py b/src/packagedcode/models.py index 0c4ffb9e56e..841492fadb1 100644 --- a/src/packagedcode/models.py +++ b/src/packagedcode/models.py @@ -1360,15 +1360,16 @@ def assemble_from_many( @classmethod def assemble_from_many_datafiles( cls, - datafile_name_patterns, - directory, + datafile_path_patterns, + resource, codebase, package_adder=add_to_package, ): """ Assemble Package and Dependency from package data of the datafiles found - in multiple ``datafile_name_patterns`` name patterns (case- sensitive) - found in the ``directory`` Resource. + in potentially multiple ``datafile_name_patterns`` name patterns + (case- sensitive) found in the ``resource``. A ``resource`` can be a single + file, or a directory in which case we look for manifests in the directory. Create a Package from the first package data item. Update this package with other items. Assign to this Package the file tree from the parent @@ -1383,22 +1384,20 @@ def assemble_from_many_datafiles( multiple PackageData for unrelated Packages. """ if TRACE: - logger_debug(f'assemble_from_many_datafiles: datafile_name_patterns: {datafile_name_patterns!r}') + logger_debug(f'assemble_from_many_datafiles: datafile_path_patterns: {datafile_path_patterns!r}') - if not codebase.has_single_resource: - siblings = list(directory.children(codebase)) - else: - if directory: - siblings = [directory] - else: - siblings = [] + siblings = [] + if resource and resource.is_file: + siblings = [resource] + elif resource and resource.is_dir: + siblings = list(resource.children(codebase)) pkgdata_resources = [] # we iterate on datafile_name_patterns because their order matters - for datafile_name_pattern in datafile_name_patterns: + for path_pattern in datafile_path_patterns: for sibling in siblings: - if fnmatchcase(sibling.name, datafile_name_pattern): + if fnmatchcase(sibling.location, path_pattern): for package_data in sibling.package_data: package_data = PackageData.from_dict(package_data) pkgdata_resources.append((package_data, sibling,)) diff --git a/src/packagedcode/phpcomposer.py b/src/packagedcode/phpcomposer.py index 5a3ee59af1f..9701da2b500 100644 --- a/src/packagedcode/phpcomposer.py +++ b/src/packagedcode/phpcomposer.py @@ -26,9 +26,9 @@ class BasePhpComposerHandler(models.DatafileHandler): @classmethod def assemble(cls, package_data, resource, codebase, package_adder): - datafile_name_patterns = ( - 'composer.json', - 'composer.lock', + datafile_path_patterns = ( + PhpComposerJsonHandler.path_patterns + + PhpComposerLockHandler.path_patterns ) if resource.has_parent(): @@ -37,8 +37,8 @@ def assemble(cls, package_data, resource, codebase, package_adder): dir_resource = resource yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=datafile_name_patterns, - directory=dir_resource, + datafile_path_patterns=datafile_path_patterns, + resource=dir_resource, codebase=codebase, package_adder=package_adder, ) diff --git a/src/packagedcode/pubspec.py b/src/packagedcode/pubspec.py index bbc36038c0d..d5483c53823 100644 --- a/src/packagedcode/pubspec.py +++ b/src/packagedcode/pubspec.py @@ -35,8 +35,10 @@ class BaseDartPubspecHandler(models.DatafileHandler): @classmethod def assemble(cls, package_data, resource, codebase, package_adder): - datafile_name_patterns = \ - DartPubspecYamlHandler.path_patterns + DartPubspecLockHandler.path_patterns + datafile_path_patterns = ( + DartPubspecYamlHandler.path_patterns + + DartPubspecLockHandler.path_patterns + ) if resource.has_parent(): dir_resource = resource.parent(codebase) @@ -44,8 +46,8 @@ def assemble(cls, package_data, resource, codebase, package_adder): dir_resource = resource yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=datafile_name_patterns, - directory=dir_resource, + datafile_path_patterns=datafile_path_patterns, + resource=dir_resource, codebase=codebase, package_adder=package_adder, ) diff --git a/src/packagedcode/pypi.py b/src/packagedcode/pypi.py index b5588ed7ca9..345c4eff904 100644 --- a/src/packagedcode/pypi.py +++ b/src/packagedcode/pypi.py @@ -166,6 +166,10 @@ class BaseExtractedPythonLayout(models.DatafileHandler): @classmethod def assemble(cls, package_data, resource, codebase, package_adder): + if codebase.has_single_resource: + yield from models.DatafileHandler.assemble(package_data, resource, codebase) + return + # a source distribution can have many manifests datafile_name_patterns = ( PipfileHandler.path_patterns + PipfileLockHandler.path_patterns @@ -555,7 +559,7 @@ def assemble(cls, package_data, resource, codebase, package_adder): if codebase.has_single_resource: yield from models.DatafileHandler.assemble(package_data, resource, codebase, package_adder) return - + assert len(package_resource.package_data) == 1, f'Invalid pyproject.toml for {package_resource.path}' pkg_data = package_resource.package_data[0] pkg_data = models.PackageData.from_dict(pkg_data) diff --git a/src/packagedcode/rubygems.py b/src/packagedcode/rubygems.py index 9cbbf6d7553..f61ebdf6479 100644 --- a/src/packagedcode/rubygems.py +++ b/src/packagedcode/rubygems.py @@ -56,18 +56,20 @@ def assemble_extracted_gem(cls, package_data, resource, codebase, package_adder) An assemble implementation shared by handlers for manifests found in an extracted gem using extractcode. """ - datafile_name_patterns = ( - 'metadata.gz-extract/metadata.gz-extract', - 'data.gz-extract/*.gemspec', - 'data.gz-extract/Gemfile', - 'data.gz-extract/Gemfile.lock', + datafile_path_patterns = ( + GemMetadataArchiveExtractedHandler.path_patterns + + GemspecHandler.path_patterns + + GemfileHandler.path_patterns + + GemfileLockHandler.path_patterns ) gemroot = get_ancestor(levels_up=2, resource=resource, codebase=codebase) + if not gemroot: + gemroot == resource yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=datafile_name_patterns, - directory=gemroot, + datafile_path_patterns=datafile_path_patterns, + resource=gemroot, codebase=codebase, package_adder=package_adder, ) @@ -104,15 +106,17 @@ class BaseGemProjectHandler(models.DatafileHandler): @classmethod def assemble(cls, package_data, resource, codebase, package_adder): - datafile_name_patterns = ( - '*.gemspec', - 'Gemfile', - 'Gemfile.lock', + datafile_path_patterns = ( + GemspecHandler.path_patterns + + GemfileHandler.path_patterns + + GemfileLockHandler.path_patterns ) - + root_resource = resource.parent(codebase) + if not root_resource: + root_resource = resource yield from cls.assemble_from_many_datafiles( - datafile_name_patterns=datafile_name_patterns, - directory=resource.parent(codebase), + datafile_path_patterns=datafile_path_patterns, + resource=root_resource, codebase=codebase, package_adder=package_adder, ) diff --git a/tests/packagedcode/data/cargo/cargo_toml/single-file-scan/Cargo.toml.expected b/tests/packagedcode/data/cargo/cargo_toml/single-file-scan/Cargo.toml.expected index ff00223cc82..2b2b04b5bab 100644 --- a/tests/packagedcode/data/cargo/cargo_toml/single-file-scan/Cargo.toml.expected +++ b/tests/packagedcode/data/cargo/cargo_toml/single-file-scan/Cargo.toml.expected @@ -1,6 +1,131 @@ { - "packages": [], - "dependencies": [], + "packages": [ + { + "type": "cargo", + "namespace": null, + "name": "constant_time_eq", + "version": "0.4.2", + "qualifiers": {}, + "subpath": null, + "primary_language": "Rust", + "description": "Compares two equal-sized byte strings in constant time.", + "release_date": null, + "parties": [ + { + "type": "person", + "role": "author", + "name": "Cesar Eduardo Barros", + "email": "cesarb@cesarb.eti.br", + "url": null + } + ], + "keywords": [ + "constant_time", + "cryptography", + "no-std" + ], + "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/cesarb/constant_time_eq", + "copyright": null, + "holder": null, + "declared_license_expression": "cc0-1.0 OR mit-0 OR apache-2.0", + "declared_license_expression_spdx": "CC0-1.0 OR MIT-0 OR Apache-2.0", + "license_detections": [ + { + "license_expression": "cc0-1.0 OR mit-0 OR apache-2.0", + "license_expression_spdx": "CC0-1.0 OR MIT-0 OR Apache-2.0", + "matches": [ + { + "license_expression": "cc0-1.0 OR mit-0 OR apache-2.0", + "license_expression_spdx": "CC0-1.0 OR MIT-0 OR Apache-2.0", + "from_file": "Cargo.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-spdx-id", + "score": 100.0, + "matched_length": 10, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "spdx-license-identifier-cc0_1_0_or_mit_0_or_apache_2_0-f44a2ec174eb034bd3c662f728664281e507b20d", + "rule_url": null, + "matched_text": "CC0-1.0 OR MIT-0 OR Apache-2.0" + } + ], + "identifier": "cc0_1_0_or_mit_0_or_apache_2_0-3f14dd48-7cd8-cf28-d4e1-3b0174a587ee" + } + ], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": "CC0-1.0 OR MIT-0 OR Apache-2.0", + "notice_text": null, + "source_packages": [], + "is_private": false, + "is_virtual": false, + "extra_data": { + "documentation_url": "https://docs.rs/constant_time_eq", + "rust_version": "1.85.0", + "rust_edition": "2024" + }, + "repository_homepage_url": "https://crates.io/crates/constant_time_eq", + "repository_download_url": "https://crates.io/api/v1/crates/constant_time_eq/0.4.2/download", + "api_data_url": "https://crates.io/api/v1/crates/constant_time_eq", + "package_uid": "pkg:cargo/constant_time_eq@0.4.2?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "Cargo.toml" + ], + "datasource_ids": [ + "cargo_toml" + ], + "purl": "pkg:cargo/constant_time_eq@0.4.2" + } + ], + "dependencies": [ + { + "purl": "pkg:cargo/criterion", + "extracted_requirement": "0.5.1", + "scope": "dev-dependencies", + "is_runtime": false, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": { + "version": "0.5.1", + "features": [ + "cargo_bench_support", + "html_reports" + ] + }, + "dependency_uid": "pkg:cargo/criterion?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:cargo/constant_time_eq@0.4.2?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "Cargo.toml", + "datasource_id": "cargo_toml" + }, + { + "purl": "pkg:cargo/count_instructions", + "extracted_requirement": "0.2.0", + "scope": "dev-dependencies", + "is_runtime": false, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:cargo/count_instructions?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:cargo/constant_time_eq@0.4.2?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "Cargo.toml", + "datasource_id": "cargo_toml" + } + ], "files": [ { "path": "Cargo.toml", @@ -119,8 +244,10 @@ "purl": "pkg:cargo/constant_time_eq@0.4.2" } ], - "for_packages": [], + "for_packages": [ + "pkg:cargo/constant_time_eq@0.4.2?uuid=fixed-uid-done-for-testing-5642512d1758" + ], "scan_errors": [] } ] -} +} \ No newline at end of file diff --git a/tests/packagedcode/data/pypi/pyproject-toml/poetry/packages-gerapy-pyproject.toml-expected.json b/tests/packagedcode/data/pypi/pyproject-toml/poetry/packages-gerapy-pyproject.toml-expected.json new file mode 100644 index 00000000000..697a92a3d0d --- /dev/null +++ b/tests/packagedcode/data/pypi/pyproject-toml/poetry/packages-gerapy-pyproject.toml-expected.json @@ -0,0 +1,775 @@ +{ + "packages": [ + { + "type": "pypi", + "namespace": null, + "name": "gerapy", + "version": "0.9.13", + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": "Distributed Crawler Management Framework Based on Scrapy, Scrapyd, Scrapyd-Client, Scrapyd-API, Django and Vue.js.", + "release_date": null, + "parties": [ + { + "type": "person", + "role": "author", + "name": "Germey", + "email": "cqc@cuiqingcai.com", + "url": null + } + ], + "keywords": [ + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy" + ], + "homepage_url": "https://github.com/Gerapy/Gerapy", + "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": "mit", + "declared_license_expression_spdx": "MIT", + "license_detections": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-spdx-id", + "score": 100.0, + "matched_length": 1, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06", + "rule_url": null, + "matched_text": "MIT" + } + ], + "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf" + }, + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "pypi_mit_license.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/pypi_mit_license.RULE", + "matched_text": "- 'License :: OSI Approved :: MIT License'" + } + ], + "identifier": "mit-24a5293c-14d7-5403-efac-1a8b7532c0e8" + } + ], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": "license: MIT\nclassifiers:\n - 'License :: OSI Approved :: MIT License'\n", + "notice_text": null, + "source_packages": [], + "is_private": false, + "is_virtual": false, + "extra_data": {}, + "repository_homepage_url": "https://pypi.org/project/gerapy", + "repository_download_url": "https://pypi.org/packages/source/g/gerapy/gerapy-0.9.13.tar.gz", + "api_data_url": "https://pypi.org/pypi/gerapy/0.9.13/json", + "package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "pyproject.toml" + ], + "datasource_ids": [ + "pypi_poetry_pyproject_toml" + ], + "purl": "pkg:pypi/gerapy@0.9.13" + } + ], + "dependencies": [ + { + "purl": "pkg:pypi/apscheduler", + "extracted_requirement": ">=3.5.1,<=3.7.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/apscheduler?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/cryptography", + "extracted_requirement": ">=2.8", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/cryptography?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/django", + "extracted_requirement": ">=2.2,<3.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/django?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/django-cors-headers", + "extracted_requirement": ">=3.2.0,<=3.7.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/django-cors-headers?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/django-apscheduler", + "extracted_requirement": ">=0.3.0,<=0.6.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/django-apscheduler?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/furl", + "extracted_requirement": ">=2.1.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/furl?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/jinja2", + "extracted_requirement": ">=2.11.3", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/jinja2?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/scrapy", + "extracted_requirement": ">=2.7.1", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/scrapy?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/scrapy-redis", + "extracted_requirement": ">=0.6.8", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/scrapy-redis?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/scrapy-splash", + "extracted_requirement": ">=0.7.2", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/scrapy-splash?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/python-scrapyd-api", + "extracted_requirement": ">=2.1.2", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/python-scrapyd-api?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/redis", + "extracted_requirement": ">=2.10.5", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/redis?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/requests", + "extracted_requirement": ">=2.20.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/requests?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/pymongo", + "extracted_requirement": ">=3.9.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pymongo?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/pymysql", + "extracted_requirement": ">=0.7.10", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pymysql?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/pyquery", + "extracted_requirement": ">=1.2.17", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pyquery?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/beautifulsoup4", + "extracted_requirement": ">=4.7.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/beautifulsoup4?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/djangorestframework", + "extracted_requirement": ">=3.11.2", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/djangorestframework?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/websocket", + "extracted_requirement": ">=0.2.1", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/websocket?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/pyppeteer", + "extracted_requirement": ">=0.0.25", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pyppeteer?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + }, + { + "purl": "pkg:pypi/uberegg", + "extracted_requirement": "^0.1.1", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/uberegg?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_poetry_pyproject_toml" + } + ], + "files": [ + { + "path": "pyproject.toml", + "type": "file", + "package_data": [ + { + "type": "pypi", + "namespace": null, + "name": "gerapy", + "version": "0.9.13", + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": "Distributed Crawler Management Framework Based on Scrapy, Scrapyd, Scrapyd-Client, Scrapyd-API, Django and Vue.js.", + "release_date": null, + "parties": [ + { + "type": "person", + "role": "author", + "name": "Germey", + "email": "cqc@cuiqingcai.com", + "url": null + } + ], + "keywords": [ + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy" + ], + "homepage_url": "https://github.com/Gerapy/Gerapy", + "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": "mit", + "declared_license_expression_spdx": "MIT", + "license_detections": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-spdx-id", + "score": 100.0, + "matched_length": 1, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06", + "rule_url": null, + "matched_text": "MIT" + } + ], + "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf" + }, + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "pypi_mit_license.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/pypi_mit_license.RULE", + "matched_text": "- 'License :: OSI Approved :: MIT License'" + } + ], + "identifier": "mit-24a5293c-14d7-5403-efac-1a8b7532c0e8" + } + ], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": "license: MIT\nclassifiers:\n - 'License :: OSI Approved :: MIT License'\n", + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": false, + "extra_data": {}, + "dependencies": [ + { + "purl": "pkg:pypi/apscheduler", + "extracted_requirement": ">=3.5.1,<=3.7.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/cryptography", + "extracted_requirement": ">=2.8", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/django", + "extracted_requirement": ">=2.2,<3.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/django-cors-headers", + "extracted_requirement": ">=3.2.0,<=3.7.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/django-apscheduler", + "extracted_requirement": ">=0.3.0,<=0.6.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/furl", + "extracted_requirement": ">=2.1.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/jinja2", + "extracted_requirement": ">=2.11.3", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/scrapy", + "extracted_requirement": ">=2.7.1", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/scrapy-redis", + "extracted_requirement": ">=0.6.8", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/scrapy-splash", + "extracted_requirement": ">=0.7.2", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/python-scrapyd-api", + "extracted_requirement": ">=2.1.2", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/redis", + "extracted_requirement": ">=2.10.5", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/requests", + "extracted_requirement": ">=2.20.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pymongo", + "extracted_requirement": ">=3.9.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pymysql", + "extracted_requirement": ">=0.7.10", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pyquery", + "extracted_requirement": ">=1.2.17", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/beautifulsoup4", + "extracted_requirement": ">=4.7.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/djangorestframework", + "extracted_requirement": ">=3.11.2", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/websocket", + "extracted_requirement": ">=0.2.1", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pyppeteer", + "extracted_requirement": ">=0.0.25", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/uberegg", + "extracted_requirement": "^0.1.1", + "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/gerapy", + "repository_download_url": "https://pypi.org/packages/source/g/gerapy/gerapy-0.9.13.tar.gz", + "api_data_url": "https://pypi.org/pypi/gerapy/0.9.13/json", + "datasource_id": "pypi_poetry_pyproject_toml", + "purl": "pkg:pypi/gerapy@0.9.13" + } + ], + "for_packages": [ + "pkg:pypi/gerapy@0.9.13?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "scan_errors": [] + } + ] +} \ No newline at end of file diff --git a/tests/packagedcode/data/pypi/pyproject-toml/standard/packages-attrs-pyproject.toml-expected.json b/tests/packagedcode/data/pypi/pyproject-toml/standard/packages-attrs-pyproject.toml-expected.json new file mode 100644 index 00000000000..3ffef8f9947 --- /dev/null +++ b/tests/packagedcode/data/pypi/pyproject-toml/standard/packages-attrs-pyproject.toml-expected.json @@ -0,0 +1,763 @@ +{ + "packages": [ + { + "type": "pypi", + "namespace": null, + "name": "attrs", + "version": null, + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": "Classes Without Boilerplate", + "release_date": null, + "parties": [ + { + "type": "person", + "role": "author", + "name": "Hynek Schlawack", + "email": "hs@ox.cx", + "url": null + } + ], + "keywords": [ + "class", + "attribute", + "boilerplate", + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Typing :: Typed" + ], + "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/python-attrs/attrs", + "copyright": null, + "holder": null, + "declared_license_expression": "mit", + "declared_license_expression_spdx": "MIT", + "license_detections": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-spdx-id", + "score": 100.0, + "matched_length": 1, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06", + "rule_url": null, + "matched_text": "MIT" + } + ], + "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf" + }, + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "pypi_mit_license.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/pypi_mit_license.RULE", + "matched_text": "- 'License :: OSI Approved :: MIT License'" + } + ], + "identifier": "mit-24a5293c-14d7-5403-efac-1a8b7532c0e8" + } + ], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": "license: MIT\nclassifiers:\n - 'License :: OSI Approved :: MIT License'\n", + "notice_text": null, + "source_packages": [], + "is_private": false, + "is_virtual": false, + "extra_data": { + "Documentation": "https://www.attrs.org/", + "Changelog": "https://www.attrs.org/en/stable/changelog.html", + "Funding": "https://github.com/sponsors/hynek", + "Tidelift": "https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi" + }, + "repository_homepage_url": "https://pypi.org/project/attrs", + "repository_download_url": null, + "api_data_url": "https://pypi.org/pypi/attrs/json", + "package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "pyproject.toml" + ], + "datasource_ids": [ + "pypi_pyproject_toml" + ], + "purl": "pkg:pypi/attrs" + } + ], + "dependencies": [ + { + "purl": "pkg:pypi/importlib-metadata", + "extracted_requirement": null, + "scope": "install", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": { + "python_version": "< 3.8" + }, + "dependency_uid": "pkg:pypi/importlib-metadata?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/pytest-mypy-plugins", + "extracted_requirement": null, + "scope": "tests-mypy", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": { + "python_version": ">= 3.8" + }, + "dependency_uid": "pkg:pypi/pytest-mypy-plugins?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/mypy", + "extracted_requirement": "<1.10,>=1.6", + "scope": "tests-mypy", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": { + "python_version": ">= 3.8" + }, + "dependency_uid": "pkg:pypi/mypy?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/cloudpickle", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/cloudpickle?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/hypothesis", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/hypothesis?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/pympler", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pympler?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/pytest", + "extracted_requirement": ">=4.3.0", + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pytest?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/pytest-xdist", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pytest-xdist?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "cov", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/coverage", + "extracted_requirement": ">=5.3", + "scope": "cov", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/coverage?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/furo", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/furo?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/myst-parser", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/myst-parser?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/sphinx", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/sphinx?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/sphinx-notfound-page", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/sphinx-notfound-page?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/sphinxcontrib-towncrier", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/sphinxcontrib-towncrier?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/towncrier", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/towncrier?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "dev", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + }, + { + "purl": "pkg:pypi/pre-commit", + "extracted_requirement": null, + "scope": "dev", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/pre-commit?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "pyproject.toml", + "datasource_id": "pypi_pyproject_toml" + } + ], + "files": [ + { + "path": "pyproject.toml", + "type": "file", + "package_data": [ + { + "type": "pypi", + "namespace": null, + "name": "attrs", + "version": null, + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": "Classes Without Boilerplate", + "release_date": null, + "parties": [ + { + "type": "person", + "role": "author", + "name": "Hynek Schlawack", + "email": "hs@ox.cx", + "url": null + } + ], + "keywords": [ + "class", + "attribute", + "boilerplate", + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Typing :: Typed" + ], + "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/python-attrs/attrs", + "copyright": null, + "holder": null, + "declared_license_expression": "mit", + "declared_license_expression_spdx": "MIT", + "license_detections": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-spdx-id", + "score": 100.0, + "matched_length": 1, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06", + "rule_url": null, + "matched_text": "MIT" + } + ], + "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf" + }, + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "pyproject.toml", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "pypi_mit_license.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/pypi_mit_license.RULE", + "matched_text": "- 'License :: OSI Approved :: MIT License'" + } + ], + "identifier": "mit-24a5293c-14d7-5403-efac-1a8b7532c0e8" + } + ], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": "license: MIT\nclassifiers:\n - 'License :: OSI Approved :: MIT License'\n", + "notice_text": null, + "source_packages": [], + "file_references": [], + "is_private": false, + "is_virtual": false, + "extra_data": { + "Documentation": "https://www.attrs.org/", + "Changelog": "https://www.attrs.org/en/stable/changelog.html", + "Funding": "https://github.com/sponsors/hynek", + "Tidelift": "https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi" + }, + "dependencies": [ + { + "purl": "pkg:pypi/importlib-metadata", + "extracted_requirement": null, + "scope": "install", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": { + "python_version": "< 3.8" + } + }, + { + "purl": "pkg:pypi/pytest-mypy-plugins", + "extracted_requirement": null, + "scope": "tests-mypy", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": { + "python_version": ">= 3.8" + } + }, + { + "purl": "pkg:pypi/mypy", + "extracted_requirement": "<1.10,>=1.6", + "scope": "tests-mypy", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": { + "python_version": ">= 3.8" + } + }, + { + "purl": "pkg:pypi/cloudpickle", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/hypothesis", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pympler", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pytest", + "extracted_requirement": ">=4.3.0", + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pytest-xdist", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "tests", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "cov", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/coverage", + "extracted_requirement": ">=5.3", + "scope": "cov", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/furo", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/myst-parser", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/sphinx", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/sphinx-notfound-page", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/sphinxcontrib-towncrier", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/towncrier", + "extracted_requirement": null, + "scope": "docs", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/attrs", + "extracted_requirement": null, + "scope": "dev", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + }, + { + "purl": "pkg:pypi/pre-commit", + "extracted_requirement": null, + "scope": "dev", + "is_runtime": true, + "is_optional": true, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {} + } + ], + "repository_homepage_url": "https://pypi.org/project/attrs", + "repository_download_url": null, + "api_data_url": "https://pypi.org/pypi/attrs/json", + "datasource_id": "pypi_pyproject_toml", + "purl": "pkg:pypi/attrs" + } + ], + "for_packages": [ + "pkg:pypi/attrs?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "scan_errors": [] + } + ] +} \ No newline at end of file diff --git a/tests/packagedcode/data/pypi/solo-setup/expected.json b/tests/packagedcode/data/pypi/solo-setup/expected.json index a397cd70f0d..2de963bbd19 100644 --- a/tests/packagedcode/data/pypi/solo-setup/expected.json +++ b/tests/packagedcode/data/pypi/solo-setup/expected.json @@ -1,6 +1,193 @@ { - "packages": [], - "dependencies": [], + "packages": [ + { + "type": "pypi", + "namespace": null, + "name": "cdp-seattle-backend", + "version": "1.0.0", + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": "Package containing the gather functions for Example.", + "release_date": null, + "parties": [ + { + "type": "person", + "role": "author", + "name": "Council Data Project Contributors", + "email": null, + "url": null + } + ], + "keywords": [ + "civic technology", + "open government", + "Development Status :: 2 - Pre-Alpha", + "Intended Audience :: Developers", + "Natural Language :: English", + "Programming Language :: Python :: 3.9" + ], + "homepage_url": "https://github.com/CouncilDataProject/seattle", + "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": "mit", + "declared_license_expression_spdx": "MIT", + "license_detections": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "setup.py", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 2, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "mit_14.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_14.RULE", + "matched_text": "MIT license" + } + ], + "identifier": "mit-9967e727-165e-9bb5-f090-7de5e47a3929" + }, + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "setup.py", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "pypi_mit_license.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/pypi_mit_license.RULE", + "matched_text": "- 'License :: OSI Approved :: MIT License'" + } + ], + "identifier": "mit-24a5293c-14d7-5403-efac-1a8b7532c0e8" + } + ], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": "license: MIT license\nclassifiers:\n - 'License :: OSI Approved :: MIT License'\n", + "notice_text": null, + "source_packages": [], + "is_private": false, + "is_virtual": false, + "extra_data": { + "python_requires": ">=3.9" + }, + "repository_homepage_url": "https://pypi.org/project/cdp-seattle-backend", + "repository_download_url": "https://pypi.org/packages/source/c/cdp-seattle-backend/cdp-seattle-backend-1.0.0.tar.gz", + "api_data_url": "https://pypi.org/pypi/cdp-seattle-backend/1.0.0/json", + "package_uid": "pkg:pypi/cdp-seattle-backend@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "setup.py" + ], + "datasource_ids": [ + "pypi_setup_py" + ], + "purl": "pkg:pypi/cdp-seattle-backend@1.0.0" + } + ], + "dependencies": [ + { + "purl": "pkg:pypi/cdp-backend@3.0.16", + "extracted_requirement": "==3.0.16", + "scope": "install", + "is_runtime": true, + "is_optional": false, + "is_pinned": true, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/cdp-backend@3.0.16?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/cdp-seattle-backend@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "setup.py", + "datasource_id": "pypi_setup_py" + }, + { + "purl": "pkg:pypi/cdp-scrapers", + "extracted_requirement": ">=0.4.0", + "scope": "install", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/cdp-scrapers?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/cdp-seattle-backend@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "setup.py", + "datasource_id": "pypi_setup_py" + }, + { + "purl": "pkg:pypi/black", + "extracted_requirement": ">=19.10b0", + "scope": "test", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/black?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/cdp-seattle-backend@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "setup.py", + "datasource_id": "pypi_setup_py" + }, + { + "purl": "pkg:pypi/flake8", + "extracted_requirement": ">=3.8.3", + "scope": "test", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/flake8?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/cdp-seattle-backend@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "setup.py", + "datasource_id": "pypi_setup_py" + }, + { + "purl": "pkg:pypi/flake8-debugger", + "extracted_requirement": ">=3.2.1", + "scope": "test", + "is_runtime": true, + "is_optional": false, + "is_pinned": false, + "is_direct": true, + "resolved_package": {}, + "extra_data": {}, + "dependency_uid": "pkg:pypi/flake8-debugger?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/cdp-seattle-backend@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "setup.py", + "datasource_id": "pypi_setup_py" + } + ], "files": [ { "path": "setup.py", @@ -169,7 +356,9 @@ "purl": "pkg:pypi/cdp-seattle-backend@1.0.0" } ], - "for_packages": [], + "for_packages": [ + "pkg:pypi/cdp-seattle-backend@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758" + ], "scan_errors": [] } ] diff --git a/tests/packagedcode/data/pypi/source-package/pip-22.0.4-pypi-package-setup-expected.json b/tests/packagedcode/data/pypi/source-package/pip-22.0.4-pypi-package-setup-expected.json index 09b19fdb9c8..8747897be30 100644 --- a/tests/packagedcode/data/pypi/source-package/pip-22.0.4-pypi-package-setup-expected.json +++ b/tests/packagedcode/data/pypi/source-package/pip-22.0.4-pypi-package-setup-expected.json @@ -1,5 +1,124 @@ { - "packages": [], + "packages": [ + { + "type": "pypi", + "namespace": null, + "name": "pip", + "version": "22.0.4", + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": "The PyPA recommended tool for installing Python packages.", + "release_date": null, + "parties": [ + { + "type": "person", + "role": "author", + "name": "The pip developers", + "email": "distutils-sig@python.org", + "url": null + } + ], + "keywords": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Topic :: Software Development :: Build Tools", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy" + ], + "homepage_url": "https://pip.pypa.io/", + "download_url": null, + "size": null, + "sha1": null, + "md5": null, + "sha256": null, + "sha512": null, + "bug_tracking_url": null, + "code_view_url": "https://github.com/pypa/pip", + "vcs_url": null, + "copyright": null, + "holder": null, + "declared_license_expression": "mit", + "declared_license_expression_spdx": "MIT", + "license_detections": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "setup.py", + "start_line": 1, + "end_line": 1, + "matcher": "1-spdx-id", + "score": 100.0, + "matched_length": 1, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06", + "rule_url": null, + "matched_text": "MIT" + } + ], + "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf" + }, + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "matches": [ + { + "license_expression": "mit", + "license_expression_spdx": "MIT", + "from_file": "setup.py", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_relevance": 100, + "rule_identifier": "pypi_mit_license.RULE", + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/pypi_mit_license.RULE", + "matched_text": "- 'License :: OSI Approved :: MIT License'" + } + ], + "identifier": "mit-24a5293c-14d7-5403-efac-1a8b7532c0e8" + } + ], + "other_license_expression": null, + "other_license_expression_spdx": null, + "other_license_detections": [], + "extracted_license_statement": "license: MIT\nclassifiers:\n - 'License :: OSI Approved :: MIT License'\n", + "notice_text": null, + "source_packages": [], + "is_private": false, + "is_virtual": false, + "extra_data": { + "Documentation": "https://pip.pypa.io", + "Changelog": "https://pip.pypa.io/en/stable/news/", + "python_requires": ">=3.7" + }, + "repository_homepage_url": "https://pypi.org/project/pip", + "repository_download_url": "https://pypi.org/packages/source/p/pip/pip-22.0.4.tar.gz", + "api_data_url": "https://pypi.org/pypi/pip/22.0.4/json", + "package_uid": "pkg:pypi/pip@22.0.4?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "setup.py" + ], + "datasource_ids": [ + "pypi_setup_py" + ], + "purl": "pkg:pypi/pip@22.0.4" + } + ], "dependencies": [], "files": [ { @@ -121,7 +240,9 @@ "purl": "pkg:pypi/pip@22.0.4" } ], - "for_packages": [], + "for_packages": [ + "pkg:pypi/pip@22.0.4?uuid=fixed-uid-done-for-testing-5642512d1758" + ], "scan_errors": [] } ] diff --git a/tests/packagedcode/test_cargo.py b/tests/packagedcode/test_cargo.py index e3309a438e2..e04691149ee 100644 --- a/tests/packagedcode/test_cargo.py +++ b/tests/packagedcode/test_cargo.py @@ -83,7 +83,7 @@ def test_parse_cargo_toml_workspace_with_dependencies_child(self): packages_data = cargo.CargoTomlHandler.parse(test_file) self.check_packages_data(packages_data, expected_loc, regen=REGEN_TEST_FIXTURES) - def test_parse_cargo_toml_single_file_no_crash(self): + def test_parse_cargo_toml_single_file(self): test_file = self.get_test_loc('cargo/cargo_toml/single-file-scan/Cargo.toml') expected_file = self.get_test_loc('cargo/cargo_toml/single-file-scan/Cargo.toml.expected') result_file = self.get_temp_file('results.json') diff --git a/tests/packagedcode/test_pypi.py b/tests/packagedcode/test_pypi.py index 3dcfa7d4268..f9248c41ff6 100644 --- a/tests/packagedcode/test_pypi.py +++ b/tests/packagedcode/test_pypi.py @@ -363,6 +363,13 @@ def test_parse_pyproject_toml_standard_lc0(self): expected_loc = self.get_test_loc('pypi/pyproject-toml/standard/lc0-pyproject.toml-expected.json') self.check_packages_data(package, expected_loc, regen=REGEN_TEST_FIXTURES) + def test_package_scan_pyproject_toml_end_to_end_full(self): + test_dir = self.get_test_loc('pypi/pyproject-toml/standard/attrs/pyproject.toml') + result_file = self.get_temp_file('json') + expected_file = self.get_test_loc('pypi/pyproject-toml/standard/packages-attrs-pyproject.toml-expected.json') + run_scan_click(['--package', '--strip-root', '--processes', '-1', test_dir, '--json', result_file]) + check_json_scan(expected_file, result_file, remove_uuid=True, regen=REGEN_TEST_FIXTURES) + class TestPoetryHandler(PackageTester): @@ -404,6 +411,13 @@ def test_parse_pyproject_toml_poetry_univers(self): expected_loc = self.get_test_loc('pypi/poetry/univers-pyproject.toml-expected.json') self.check_packages_data(package, expected_loc, regen=REGEN_TEST_FIXTURES) + def test_package_scan_poetry_pyproject_toml_end_to_end_full(self): + test_dir = self.get_test_loc('pypi/pyproject-toml/poetry/gerapy/pyproject.toml') + result_file = self.get_temp_file('json') + expected_file = self.get_test_loc('pypi/pyproject-toml/poetry/packages-gerapy-pyproject.toml-expected.json') + run_scan_click(['--package', '--strip-root', '--processes', '-1', test_dir, '--json', 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') diff --git a/tests/summarycode/data/todo/todo_present/incomplete-setup-cfg-expected.json b/tests/summarycode/data/todo/todo_present/incomplete-setup-cfg-expected.json index 38df592442d..42f0df84dc2 100644 --- a/tests/summarycode/data/todo/todo_present/incomplete-setup-cfg-expected.json +++ b/tests/summarycode/data/todo/todo_present/incomplete-setup-cfg-expected.json @@ -1,65 +1,61 @@ { - "todo": [ + "todo": [], + "packages": [ { - "detection_id": "pkg:pypi/scancode-toolkit-e7ce965e-449d-5c31-b5e4-5ad0dfd29f5c", - "review_comments": { - "cannot-create-top-level-package": "The package data detected couldn't be processed/merged into a scan-level package that is returned, and this is likely because the package assembly method for this specific type of package data is not implemented or there is a bug in the same. Please report this to scancode-toolkit github issues." - }, - "detection": { - "type": "pypi", - "namespace": null, - "name": "scancode-toolkit", - "version": null, - "qualifiers": {}, - "subpath": null, - "primary_language": "Python", - "description": null, - "release_date": null, - "parties": [], - "keywords": [], - "homepage_url": "https://github.com/nexB/scancode-toolkit", - "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": {}, - "dependencies": [], - "repository_homepage_url": null, - "repository_download_url": null, - "api_data_url": null, - "datasource_id": "pypi_setup_cfg", - "purl": "pkg:pypi/scancode-toolkit" - } + "type": "pypi", + "namespace": null, + "name": "scancode-toolkit", + "version": null, + "qualifiers": {}, + "subpath": null, + "primary_language": "Python", + "description": null, + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "https://github.com/nexB/scancode-toolkit", + "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": [], + "is_private": false, + "is_virtual": false, + "extra_data": {}, + "repository_homepage_url": null, + "repository_download_url": null, + "api_data_url": null, + "package_uid": "pkg:pypi/scancode-toolkit?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "incomplete-setup.cfg" + ], + "datasource_ids": [ + "pypi_setup_cfg" + ], + "purl": "pkg:pypi/scancode-toolkit" } ], - "packages": [], "dependencies": [], "files": [ { "path": "incomplete-setup.cfg", "type": "file", - "for_todo": [ - "pkg:pypi/scancode-toolkit-e7ce965e-449d-5c31-b5e4-5ad0dfd29f5c" - ], + "for_todo": [], "package_data": [ { "type": "pypi", @@ -106,7 +102,9 @@ "purl": "pkg:pypi/scancode-toolkit" } ], - "for_packages": [], + "for_packages": [ + "pkg:pypi/scancode-toolkit?uuid=fixed-uid-done-for-testing-5642512d1758" + ], "scan_errors": [] } ]