diff --git a/examples/spdx2_convert_format.py b/examples/spdx2_convert_format.py new file mode 100644 index 000000000..63cb4a67a --- /dev/null +++ b/examples/spdx2_convert_format.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2023 spdx contributors +# +# SPDX-License-Identifier: Apache-2.0 +from os import path + +from spdx_tools.spdx.model import Document +from spdx_tools.spdx.writer.write_anything import write_file +from spdx_tools.spdx.parser.parse_anything import parse_file + +# This example demonstrates how to load an existing SPDX2 file and convert it to a different SPDX2 format + +# Provide a path to the input file in the originating format +input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXLite.spdx") +# Parse the original input file (format is deduced automatically from the file extension) +document: Document = parse_file(input_path) +# Write to a different file format (e.g. XML, format is deduced automatically from the file extension) +write_file(document, "converted_format.xml") diff --git a/examples/spdx2_convert_to_spdx3.py b/examples/spdx2_convert_to_spdx3.py new file mode 100644 index 000000000..ebbbbc7c7 --- /dev/null +++ b/examples/spdx2_convert_to_spdx3.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2023 spdx contributors +# +# SPDX-License-Identifier: Apache-2.0 +from os import path + +from spdx_tools.spdx.model import Document +from spdx_tools.spdx3.payload import Payload +from spdx_tools.spdx3.writer.json_ld.json_ld_writer import write_payload +from spdx_tools.spdx3.bump_from_spdx2.spdx_document import bump_spdx_document +from spdx_tools.spdx.parser.parse_anything import parse_file + +# This example demonstrates how to load an existing SPDX2 file and convert it to the SPDX3 format + +# Provide a path to the input file +input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXLite.spdx") +# Parse the original SPDX2 input file +spdx2_document: Document = parse_file(input_path) +# Convert original document to an SPDX3 payload +spdx3_payload: Payload = bump_spdx_document(spdx2_document) +# Write SPDX3 payload in json-ld format +write_payload(spdx3_payload, "spdx2_to_3") diff --git a/examples/spdx2_generate_graph.py b/examples/spdx2_generate_graph.py new file mode 100644 index 000000000..dad7dcfce --- /dev/null +++ b/examples/spdx2_generate_graph.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2023 spdx contributors +# +# SPDX-License-Identifier: Apache-2.0 +from os import path + +from spdx_tools.spdx.graph_generation import export_graph_from_document +from spdx_tools.spdx.model import Document +from spdx_tools.spdx.parser.parse_anything import parse_file + +# This example demonstrates how to generate a relationship graph for an SPDX2 document + +# Provide a path to the input file +input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXJSONExample-v2.3.spdx.json") +# Parse the file +document: Document = parse_file(input_path) +# Generate the graph (note: you need to have installed the optional dependencies networkx and pygraphviz) +export_graph_from_document(document, "graph.png") diff --git a/examples/spdx2_parse_file.py b/examples/spdx2_parse_file.py new file mode 100644 index 000000000..a6564e127 --- /dev/null +++ b/examples/spdx2_parse_file.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2023 spdx contributors +# +# SPDX-License-Identifier: Apache-2.0 +import logging +from os import path + +from spdx_tools.spdx.model.document import Document +from spdx_tools.spdx.parser.error import SPDXParsingError +from spdx_tools.spdx.parser.parse_anything import parse_file + +# This example demonstrates how to parse an existing spdx file. + +# Provide a path to the input file +input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXLite.spdx") +try: + # Try to parse the input file. If successful, returns a Document, otherwise raises an SPDXParsingError + document: Document = parse_file(input_path) +except SPDXParsingError: + logging.exception("Failed to parse spdx file") + +# We can now access attributes from the parsed document +print(f"Parsed document name: {document.creation_info.name}") +creators_as_str = ", ".join([creator.to_serialized_string() for creator in document.creation_info.creators]) +print(f"Created on {document.creation_info.created} by {creators_as_str}") diff --git a/src/spdx_tools/spdx3/bump_from_spdx2/creation_info.py b/src/spdx_tools/spdx3/bump_from_spdx2/creation_info.py index 4a59f81e2..54ac666eb 100644 --- a/src/spdx_tools/spdx3/bump_from_spdx2/creation_info.py +++ b/src/spdx_tools/spdx3/bump_from_spdx2/creation_info.py @@ -19,11 +19,15 @@ def bump_creation_info(spdx2_creation_info: Spdx2_CreationInfo, payload: Payload print_missing_conversion("creation_info.document_namespace", 0, "https://github.com/spdx/spdx-3-model/issues/87") - namespaces, imports = zip( - *[ - bump_external_document_ref(external_document_ref) - for external_document_ref in spdx2_creation_info.external_document_refs - ] + namespaces, imports = ( + zip( + *[ + bump_external_document_ref(external_document_ref) + for external_document_ref in spdx2_creation_info.external_document_refs + ] + ) + if spdx2_creation_info.external_document_refs + else ([], []) ) namespaces = list(namespaces) imports = list(imports) diff --git a/src/spdx_tools/spdx3/bump_from_spdx2/package.py b/src/spdx_tools/spdx3/bump_from_spdx2/package.py index a7414d1b4..3d358babd 100644 --- a/src/spdx_tools/spdx3/bump_from_spdx2/package.py +++ b/src/spdx_tools/spdx3/bump_from_spdx2/package.py @@ -83,7 +83,9 @@ def bump_package( elif isinstance(id_or_ref, ExternalIdentifier): external_identifier.append(id_or_ref) - package_purpose = SoftwarePurpose[spdx2_package.primary_package_purpose.name] + package_purpose = ( + SoftwarePurpose[spdx2_package.primary_package_purpose.name] if spdx2_package.primary_package_purpose else None + ) payload.add_element( Package( diff --git a/tests/spdx/examples/test_examples.py b/tests/spdx/examples/test_examples.py new file mode 100644 index 000000000..95de85576 --- /dev/null +++ b/tests/spdx/examples/test_examples.py @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: 2023 spdx contributors +# +# SPDX-License-Identifier: Apache-2.0 +import os.path +import runpy + +import pytest + + +@pytest.fixture +def cleanup_output_files(): + yield + + files_to_delete = ["spdx2_to_3.jsonld", "my_spdx_document.spdx.json", "converted_format.xml", "graph.png"] + for file in files_to_delete: + if os.path.exists(file): + os.remove(file) + + +def run_example(example_file: str): + file_path = os.path.join(os.path.dirname(__file__), "../../../examples/", example_file) + runpy.run_path(file_path) + + +def test_spdx2_parse_file(): + run_example("spdx2_parse_file.py") + + +@pytest.mark.usefixtures("cleanup_output_files") +def test_spdx2_convert_to_spdx3(): + run_example("spdx2_convert_to_spdx3.py") + assert os.path.exists("spdx2_to_3.jsonld") + + +@pytest.mark.usefixtures("cleanup_output_files") +def test_spdx2_document_from_scratch(): + run_example("spdx2_document_from_scratch.py") + assert os.path.exists("my_spdx_document.spdx.json") + + +@pytest.mark.usefixtures("cleanup_output_files") +def test_spdx2_convert_format(): + run_example("spdx2_convert_format.py") + assert os.path.exists("converted_format.xml") + + +@pytest.mark.usefixtures("cleanup_output_files") +def test_spdx2_generate_graph(): + try: + import networkx # noqa F401 + import pygraphviz # noqa F401 + except ImportError: + pytest.skip("Missing optional dependencies") + + run_example("spdx2_generate_graph.py") + assert os.path.exists("graph.png")