├── .editorconfig ├── .flake8 ├── .github ├── dependabot.yml └── workflows │ ├── check_codestyle.yml │ ├── docs.yml │ ├── install_and_test.yml │ ├── integration_test.yml │ └── prepare_release.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── DOCUMENTATION.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── appveyor.yml ├── assets └── SPDXJSONExample-v2.3.spdx.png ├── dev └── publish_from_tag.sh ├── examples ├── spdx2_convert_format.py ├── spdx2_convert_to_spdx3.py ├── spdx2_document_from_scratch.py ├── spdx2_generate_graph.py └── spdx2_parse_file.py ├── pyproject.toml ├── setup.py ├── src └── spdx_tools │ ├── common │ ├── __init__.py │ ├── spdx_licensing.py │ └── typing │ │ ├── __init__.py │ │ ├── constructor_type_errors.py │ │ ├── dataclass_with_properties.py │ │ └── type_checks.py │ ├── spdx │ ├── __init__.py │ ├── casing_tools.py │ ├── clitools │ │ ├── __init__.py │ │ └── pyspdxtools.py │ ├── constants.py │ ├── datetime_conversions.py │ ├── document_utils.py │ ├── formats.py │ ├── graph_generation.py │ ├── jsonschema │ │ ├── __init__.py │ │ ├── annotation_converter.py │ │ ├── annotation_properties.py │ │ ├── checksum_converter.py │ │ ├── checksum_properties.py │ │ ├── converter.py │ │ ├── creation_info_converter.py │ │ ├── creation_info_properties.py │ │ ├── document_converter.py │ │ ├── document_properties.py │ │ ├── external_document_ref_converter.py │ │ ├── external_document_ref_properties.py │ │ ├── external_package_ref_converter.py │ │ ├── external_package_ref_properties.py │ │ ├── extracted_licensing_info_converter.py │ │ ├── extracted_licensing_info_properties.py │ │ ├── file_converter.py │ │ ├── file_properties.py │ │ ├── json_property.py │ │ ├── optional_utils.py │ │ ├── package_converter.py │ │ ├── package_properties.py │ │ ├── package_verification_code_converter.py │ │ ├── package_verification_code_properties.py │ │ ├── relationship_converter.py │ │ ├── relationship_properties.py │ │ ├── snippet_converter.py │ │ └── snippet_properties.py │ ├── model │ │ ├── __init__.py │ │ ├── actor.py │ │ ├── annotation.py │ │ ├── checksum.py │ │ ├── document.py │ │ ├── external_document_ref.py │ │ ├── extracted_licensing_info.py │ │ ├── file.py │ │ ├── package.py │ │ ├── relationship.py │ │ ├── relationship_filters.py │ │ ├── snippet.py │ │ ├── spdx_no_assertion.py │ │ ├── spdx_none.py │ │ └── version.py │ ├── parser │ │ ├── __init__.py │ │ ├── actor_parser.py │ │ ├── error.py │ │ ├── json │ │ │ ├── __init__.py │ │ │ └── json_parser.py │ │ ├── jsonlikedict │ │ │ ├── __init__.py │ │ │ ├── annotation_parser.py │ │ │ ├── checksum_parser.py │ │ │ ├── creation_info_parser.py │ │ │ ├── dict_parsing_functions.py │ │ │ ├── extracted_licensing_info_parser.py │ │ │ ├── file_parser.py │ │ │ ├── json_like_dict_parser.py │ │ │ ├── license_expression_parser.py │ │ │ ├── package_parser.py │ │ │ ├── relationship_parser.py │ │ │ └── snippet_parser.py │ │ ├── logger.py │ │ ├── parse_anything.py │ │ ├── parsing_functions.py │ │ ├── rdf │ │ │ ├── __init__.py │ │ │ ├── annotation_parser.py │ │ │ ├── checksum_parser.py │ │ │ ├── creation_info_parser.py │ │ │ ├── extracted_licensing_info_parser.py │ │ │ ├── file_parser.py │ │ │ ├── graph_parsing_functions.py │ │ │ ├── license_expression_parser.py │ │ │ ├── package_parser.py │ │ │ ├── rdf_parser.py │ │ │ ├── relationship_parser.py │ │ │ └── snippet_parser.py │ │ ├── tagvalue │ │ │ ├── __init__.py │ │ │ ├── helper_methods.py │ │ │ ├── lexer.py │ │ │ ├── parser.py │ │ │ └── tagvalue_parser.py │ │ ├── xml │ │ │ ├── __init__.py │ │ │ └── xml_parser.py │ │ └── yaml │ │ │ ├── __init__.py │ │ │ └── yaml_parser.py │ ├── py.typed │ ├── rdfschema │ │ ├── __init__.py │ │ └── namespace.py │ ├── spdx_element_utils.py │ ├── validation │ │ ├── __init__.py │ │ ├── actor_validator.py │ │ ├── annotation_validator.py │ │ ├── checksum_validator.py │ │ ├── creation_info_validator.py │ │ ├── document_validator.py │ │ ├── external_document_ref_validator.py │ │ ├── external_package_ref_validator.py │ │ ├── extracted_licensing_info_validator.py │ │ ├── file_validator.py │ │ ├── license_expression_validator.py │ │ ├── package_validator.py │ │ ├── package_verification_code_validator.py │ │ ├── relationship_validator.py │ │ ├── snippet_validator.py │ │ ├── spdx_id_validators.py │ │ ├── uri_validators.py │ │ └── validation_message.py │ └── writer │ │ ├── __init__.py │ │ ├── json │ │ ├── __init__.py │ │ └── json_writer.py │ │ ├── rdf │ │ ├── __init__.py │ │ ├── annotation_writer.py │ │ ├── checksum_writer.py │ │ ├── creation_info_writer.py │ │ ├── external_document_ref_writer.py │ │ ├── extracted_licensing_info_writer.py │ │ ├── file_writer.py │ │ ├── license_expression_writer.py │ │ ├── package_writer.py │ │ ├── rdf_writer.py │ │ ├── relationship_writer.py │ │ ├── snippet_writer.py │ │ └── writer_utils.py │ │ ├── tagvalue │ │ ├── __init__.py │ │ ├── annotation_writer.py │ │ ├── checksum_writer.py │ │ ├── creation_info_writer.py │ │ ├── extracted_licensing_info_writer.py │ │ ├── file_writer.py │ │ ├── package_writer.py │ │ ├── relationship_writer.py │ │ ├── snippet_writer.py │ │ ├── tagvalue_writer.py │ │ └── tagvalue_writer_helper_functions.py │ │ ├── write_anything.py │ │ ├── write_utils.py │ │ ├── xml │ │ ├── __init__.py │ │ └── xml_writer.py │ │ └── yaml │ │ ├── __init__.py │ │ └── yaml_writer.py │ └── spdx3 │ ├── __init__.py │ ├── bump_from_spdx2 │ ├── __init__.py │ ├── actor.py │ ├── annotation.py │ ├── bump_utils.py │ ├── checksum.py │ ├── creation_info.py │ ├── external_document_ref.py │ ├── file.py │ ├── license_expression.py │ ├── message.py │ ├── package.py │ ├── relationship.py │ ├── snippet.py │ └── spdx_document.py │ ├── clitools │ ├── __init__.py │ └── pyspdxtools3.py │ ├── model │ ├── __init__.py │ ├── agent.py │ ├── ai │ │ ├── __init__.py │ │ └── ai_package.py │ ├── annotation.py │ ├── artifact.py │ ├── bom.py │ ├── build │ │ ├── __init__.py │ │ └── build.py │ ├── bundle.py │ ├── creation_info.py │ ├── dataset │ │ ├── __init__.py │ │ └── dataset.py │ ├── element.py │ ├── external_identifier.py │ ├── external_map.py │ ├── external_reference.py │ ├── hash.py │ ├── integrity_method.py │ ├── licensing │ │ ├── __init__.py │ │ ├── any_license_info.py │ │ ├── conjunctive_license_set.py │ │ ├── custom_license.py │ │ ├── custom_license_addition.py │ │ ├── disjunctive_license_set.py │ │ ├── license.py │ │ ├── license_addition.py │ │ ├── license_field.py │ │ ├── listed_license.py │ │ ├── listed_license_exception.py │ │ ├── no_assertion_license.py │ │ ├── none_license.py │ │ ├── or_later_operator.py │ │ └── with_addition_operator.py │ ├── lifecycle_scoped_relationship.py │ ├── namespace_map.py │ ├── organization.py │ ├── person.py │ ├── positive_integer_range.py │ ├── profile_identifier.py │ ├── relationship.py │ ├── security │ │ ├── __init__.py │ │ ├── cvss_v2_vuln_assessment_relationship.py │ │ ├── cvss_v3_vuln_assessment_relationship.py │ │ ├── epss_vuln_assessment_relationship.py │ │ ├── exploit_catalog_vuln_assessment_relationship.py │ │ ├── ssvc_vuln_assessment_relationship.py │ │ ├── vex_affected_vuln_assessment_relationship.py │ │ ├── vex_fixed_vuln_assessment_relationship.py │ │ ├── vex_not_affected_vuln_assessment_relationship.py │ │ ├── vex_under_investigation_vuln_assessment_relationship.py │ │ ├── vex_vuln_assessment_relationship.py │ │ ├── vuln_assessment_relationship.py │ │ └── vulnerability.py │ ├── software │ │ ├── __init__.py │ │ ├── file.py │ │ ├── package.py │ │ ├── sbom.py │ │ ├── snippet.py │ │ ├── software_artifact.py │ │ ├── software_dependency_relationship.py │ │ └── software_purpose.py │ ├── software_agent.py │ ├── spdx_collection.py │ ├── spdx_document.py │ └── tool.py │ ├── payload.py │ ├── validation │ ├── __init__.py │ └── json_ld │ │ ├── __init__.py │ │ └── shacl_validation.py │ └── writer │ ├── __init__.py │ ├── console │ ├── __init__.py │ ├── agent_writer.py │ ├── ai │ │ ├── __init__.py │ │ └── ai_package_writer.py │ ├── annotation_writer.py │ ├── artifact_writer.py │ ├── bom_writer.py │ ├── build │ │ ├── __init__.py │ │ └── build_writer.py │ ├── bundle_writer.py │ ├── console.py │ ├── creation_info_writer.py │ ├── dataset │ │ ├── __init__.py │ │ └── dataset_writer.py │ ├── element_writer.py │ ├── external_identifier_writer.py │ ├── external_map_writer.py │ ├── external_reference_writer.py │ ├── hash_writer.py │ ├── integrity_method_writer.py │ ├── lifecycle_scoped_relationship_writer.py │ ├── namespace_map_writer.py │ ├── payload_writer.py │ ├── relationship_writer.py │ ├── software │ │ ├── __init__.py │ │ ├── file_writer.py │ │ ├── package_writer.py │ │ ├── sbom_writer.py │ │ ├── snippet_writer.py │ │ └── software_dependency_relationship_writer.py │ ├── spdx_collection_writer.py │ ├── spdx_document_writer.py │ └── tool_writer.py │ └── json_ld │ ├── SPDX_OWL.json │ ├── __init__.py │ ├── context.json │ ├── json_ld_converter.py │ ├── json_ld_writer.py │ ├── model.ttl │ ├── owl_to_context.py │ └── process.md ├── stdeb.cfg └── tests ├── __init__.py ├── spdx ├── __init__.py ├── data │ ├── SPDXJSONExample-UTF-16.spdx.json │ ├── SPDXJSONExample-v2.2.spdx.json │ ├── SPDXJSONExample-v2.3.spdx.json │ ├── SPDXLite.spdx │ ├── SPDXRdfExample-UTF-16.spdx.rdf.xml │ ├── SPDXRdfExample-v2.2.spdx.rdf.xml │ ├── SPDXRdfExample-v2.3.spdx.rdf.xml │ ├── SPDXTagExample-UTF-16.spdx │ ├── SPDXTagExample-v2.2.spdx │ ├── SPDXTagExample-v2.3.spdx │ ├── SPDXXMLExample-UTF-16.spdx.xml │ ├── SPDXXMLExample-v2.2.spdx.xml │ ├── SPDXXMLExample-v2.3.spdx.xml │ ├── SPDXYAMLExample-UTF-16.spdx.yaml │ ├── SPDXYAMLExample-v2.2.spdx.yaml │ ├── SPDXYAMLExample-v2.3.spdx.yaml │ ├── circleConversionTestInitialDocument.json │ └── invalid │ │ └── spdx-trivy-vmware_log-intelligence-fluentd-sha256_086af034f561f343f633be9d9f9e95f65ae6c61b8ddb2c6755ef5bb25b40f53a.json ├── examples │ ├── __init__.py │ ├── test_examples.py │ └── test_spdx2_document_from_scratch.py ├── fixtures.py ├── jsonschema │ ├── __init__.py │ ├── test_annotation_converter.py │ ├── test_checksum_converter.py │ ├── test_converter.py │ ├── test_creation_info_converter.py │ ├── test_document_converter.py │ ├── test_external_document_ref_converter.py │ ├── test_external_package_ref_converter.py │ ├── test_extracted_licensing_info_converter.py │ ├── test_file_converter.py │ ├── test_package_converter.py │ ├── test_package_verification_code_converter.py │ ├── test_relationship_converter.py │ └── test_snippet_converter.py ├── mock_utils.py ├── model │ ├── __init__.py │ ├── test_actor.py │ ├── test_annotation.py │ ├── test_checksum.py │ ├── test_creation_info.py │ ├── test_document.py │ ├── test_external_document_ref.py │ ├── test_external_package_reference.py │ ├── test_extracted_licensing_info.py │ ├── test_file.py │ ├── test_package.py │ ├── test_package_verification_code.py │ ├── test_relationship.py │ ├── test_snippet.py │ └── test_version.py ├── parser │ ├── __init__.py │ ├── all_formats │ │ ├── __init__.py │ │ └── test_parse_from_file.py │ ├── jsonlikedict │ │ ├── __init__.py │ │ ├── test_annotation_parser.py │ │ ├── test_checksum_parser.py │ │ ├── test_creation_info_parser.py │ │ ├── test_dict_parsing_functions.py │ │ ├── test_extracted_licensing_info_parser.py │ │ ├── test_file_parser.py │ │ ├── test_license_expression_parser.py │ │ ├── test_package_parser.py │ │ ├── test_relationship_parser.py │ │ └── test_snippet_parser.py │ ├── rdf │ │ ├── __init__.py │ │ ├── data │ │ │ ├── file_to_test_rdf_parser.rdf.xml │ │ │ └── invalid_documents │ │ │ │ ├── file_without_spdx_ids.xml │ │ │ │ ├── invalid_creation_info.rdf.xml │ │ │ │ └── invalid_creation_info_with_snippet.rdf.xml │ │ ├── test_annotation_parser.py │ │ ├── test_checksum_parser.py │ │ ├── test_creation_info_parser.py │ │ ├── test_extracted_licensing_info_parser.py │ │ ├── test_file_parser.py │ │ ├── test_graph_parsing_function.py │ │ ├── test_license_expression_parser.py │ │ ├── test_package_parser.py │ │ ├── test_relationship_parser.py │ │ └── test_snippet_parser.py │ └── tagvalue │ │ ├── __init__.py │ │ ├── test_annotation_parser.py │ │ ├── test_creation_info_parser.py │ │ ├── test_extracted_licensing_info_parser.py │ │ ├── test_file_parser.py │ │ ├── test_helper_methods.py │ │ ├── test_package_parser.py │ │ ├── test_relationship_parser.py │ │ ├── test_snippet_parser.py │ │ ├── test_tag_value_lexer.py │ │ └── test_tag_value_parser.py ├── test_actor_parser.py ├── test_casing_tools.py ├── test_checksum_calculation.py ├── test_cli.py ├── test_datetime_conversions.py ├── test_document_utils.py ├── test_graph_generation.py ├── validation │ ├── __init__.py │ ├── test_actor_validator.py │ ├── test_annotation_validator.py │ ├── test_checksum_validator.py │ ├── test_creation_info_validator.py │ ├── test_document_validator.py │ ├── test_external_document_ref_validator.py │ ├── test_external_package_ref_validator.py │ ├── test_extracted_licensing_info_validator.py │ ├── test_file_validator.py │ ├── test_license_expression_validator.py │ ├── test_package_validator.py │ ├── test_package_verification_code_validator.py │ ├── test_relationship_validator.py │ ├── test_snippet_validator.py │ ├── test_spdx_id_validators.py │ └── test_uri_validators.py └── writer │ ├── __init__.py │ ├── json │ ├── __init__.py │ ├── expected_results │ │ ├── __init__.py │ │ └── expected.json │ └── test_json_writer.py │ ├── rdf │ ├── __init__.py │ ├── test_annotation_writer.py │ ├── test_checksum_writer.py │ ├── test_creation_info_writer.py │ ├── test_external_document_ref_writer.py │ ├── test_extracted_licensing_info_writer.py │ ├── test_file_writer.py │ ├── test_license_expression_writer.py │ ├── test_package_writer.py │ ├── test_rdf_writer.py │ ├── test_relationship_writer.py │ ├── test_snippet_writer.py │ └── test_writer_utils.py │ └── tagvalue │ ├── __init__.py │ ├── expected_results │ └── expected_tag_value.spdx │ ├── test_annotation_writer.py │ ├── test_checksum_writer.py │ ├── test_creation_info_writer.py │ ├── test_extracted_licensing_info_writer.py │ ├── test_file_writer.py │ ├── test_package_writer.py │ ├── test_relationship_writer.py │ ├── test_snippet_writer.py │ ├── test_tagvalue_writer.py │ └── test_tagvalue_writer_helper_functions.py └── spdx3 ├── __init__.py ├── bump ├── __init__.py ├── test_actor_bump.py ├── test_bump_utils.py ├── test_checksum_bump.py ├── test_external_document_ref_bump.py ├── test_external_element_bump.py ├── test_file_bump.py ├── test_license_expression_bump.py ├── test_package_bump.py ├── test_relationship_bump.py ├── test_snippet_bump.py └── test_spdx_document_bump.py ├── fixtures.py ├── model ├── __init__.py ├── licensing │ ├── __init__.py │ ├── test_conjunctive_license_set.py │ ├── test_disjunctive_license_set.py │ ├── test_or_later_operator.py │ └── test_with_addition_operator.py ├── model_test_utils.py ├── test_abstract_classes.py ├── test_creation_info.py ├── test_element_and_licensing_subclasses.py ├── test_external_identifier.py ├── test_external_map.py ├── test_external_reference.py ├── test_hash.py └── test_namespace_map.py ├── validation ├── __init__.py └── json_ld │ ├── __init__.py │ └── test_shacl_validation.py └── writer ├── __init__.py ├── json_ld ├── __init__.py └── test_json_ld_writer.py └── tag_value └── test_write_document.py /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | insert_final_newline = true 8 | end_of_line = lf 9 | 10 | [*.{yml,yaml}] 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 119 3 | exclude = src/spdx_tools/spdx/parser/tagvalue/parsetab.py, __init__.py 4 | extend-ignore = E203 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/check_codestyle.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: Run Linter 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | pull_request: 12 | workflow_dispatch: 13 | 14 | jobs: 15 | check_code_style: 16 | runs-on: ${{ matrix.os }} 17 | defaults: 18 | run: 19 | shell: bash 20 | strategy: 21 | matrix: 22 | os: [ ubuntu-latest, macos-latest, windows-latest ] 23 | python-version: [ "3.8", "3.9", "3.10", "3.11" ] 24 | 25 | steps: 26 | - uses: actions/checkout@v3 27 | - name: Set up Python ${{ matrix.python-version }} 28 | uses: actions/setup-python@v4 29 | with: 30 | python-version: ${{ matrix.python-version }} 31 | - name: Installation 32 | run: pip install ".[code_style]" 33 | - name: Check code with isort 34 | run: | 35 | isort src tests --check 36 | black src tests --check 37 | flake8 src tests 38 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | name: Generate API docs 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Setup Python 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.11' 23 | - name: Install dependencies 24 | run: | 25 | sudo apt-get install graphviz-dev 26 | pip install -e ".[test,graph_generation]" 27 | pip install pdoc 28 | - name: Generate docs 29 | run: pdoc spdx_tools -o docs/ 30 | - name: Upload docs as artifact 31 | uses: actions/upload-pages-artifact@v1 32 | with: 33 | path: docs/ 34 | 35 | deploy: 36 | needs: build 37 | runs-on: ubuntu-latest 38 | permissions: 39 | pages: write 40 | id-token: write 41 | environment: 42 | name: github-pages 43 | url: ${{ steps.deployment.outputs.page_url }} 44 | steps: 45 | - id: deployment 46 | name: Deploy docs to GitHub pages 47 | uses: actions/deploy-pages@v2 48 | -------------------------------------------------------------------------------- /.github/workflows/install_and_test.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: Install and Test 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | pull_request: 12 | workflow_dispatch: 13 | 14 | jobs: 15 | install_and_test: 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: [ ubuntu-latest, macos-latest, windows-latest ] 20 | python-version: [ "3.8", "3.9", "3.10", "3.11" ] 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Set up Python ${{ matrix.python-version }} 25 | uses: actions/setup-python@v4 26 | with: 27 | python-version: ${{ matrix.python-version }} 28 | - name: Installation 29 | run: | 30 | python -m pip install --upgrade pip 31 | python -m pip install --upgrade setuptools wheel setuptools_scm build 32 | python -m build -nwx . 33 | python -m pip install --upgrade ./dist/*.whl 34 | python -m pip install pytest 35 | python -m pip install pyshacl 36 | python -m pip install tzdata 37 | python -m pip install networkx 38 | shell: bash 39 | - name: Run tests 40 | run: pytest 41 | - name: Run CLI 42 | run: pyspdxtools -i ./tests/spdx/data/SPDXJSONExample-v2.3.spdx.json 43 | -------------------------------------------------------------------------------- /.github/workflows/integration_test.yml: -------------------------------------------------------------------------------- 1 | name: Circle conversion test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | install_and_test: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Set up Python 3.11 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: 3.11 20 | - name: Installation 21 | run: | 22 | python -m pip install --upgrade pip 23 | python -m pip install --upgrade setuptools wheel setuptools_scm build 24 | python -m build -nwx . 25 | python -m pip install --upgrade ./dist/*.whl 26 | shell: bash 27 | - name: Install jd 28 | uses: jaxxstorm/action-install-gh-release@v1.10.0 29 | with: # Grab the latest version 30 | repo: josephburnett/jd 31 | platform: linux 32 | extension-matching: disable 33 | rename-to: jd 34 | chmod: 0755 35 | - name: Run CLI 36 | run: | 37 | pyspdxtools -i ./tests/spdx/data/circleConversionTestInitialDocument.json -o circleTest.yaml 38 | pyspdxtools -i circleTest.yaml -o circleTest.xml 39 | pyspdxtools -i circleTest.xml -o circleTest.rdf 40 | pyspdxtools -i circleTest.rdf -o circleTest.spdx 41 | pyspdxtools -i circleTest.spdx -o circleTest.json 42 | - name: Compare initial and final json document of the circle conversion test 43 | run: jd -set ./tests/spdx/data/circleConversionTestInitialDocument.json circleTest.json 44 | -------------------------------------------------------------------------------- /.github/workflows/prepare_release.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: Prepare release 6 | 7 | on: 8 | push: 9 | tags: [ 'v*.*.*'] 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: write 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Set up Python 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.8' 23 | - name: Set up dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | python -m pip install --upgrade setuptools wheel setuptools_scm build twine 27 | python -m pip install -e . 28 | shell: bash 29 | - name: Build wheel 30 | run: python -m build 31 | - name: Verify build 32 | run: twine check dist/* 33 | - name: Create build archive 34 | uses: a7ul/tar-action@v1.1.0 35 | with: 36 | command: c 37 | files: dist 38 | outPath: spdx_tools_dist.tar.gz 39 | - name: Create GitHub release 40 | uses: softprops/action-gh-release@v1 41 | with: 42 | files: spdx_tools_dist.tar.gz 43 | generate_release_notes: true 44 | draft: true 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *.out 4 | /build/ 5 | /dist*/ 6 | /tmp/ 7 | src/spdx_tools/spdx/parser/tagvalue/parsetab.py 8 | /.cache/ 9 | 10 | .tox 11 | venv* 12 | 13 | # virtualenv 14 | /bin 15 | /lib 16 | /Lib 17 | /local 18 | /local/ 19 | /.eggs/ 20 | *.egg-info/ 21 | /Include 22 | /include 23 | /pip-selfcheck.json 24 | .Python 25 | /share/ 26 | 27 | # IDEs 28 | .project 29 | .pydevproject 30 | .idea 31 | org.eclipse.core.resources.prefs 32 | .vscode 33 | .pytest_cache 34 | 35 | # Installer logs 36 | pip-log.txt 37 | 38 | # Unit test / coverage reports 39 | .cache 40 | .coverage 41 | .coverage.* 42 | nosetests.xml 43 | htmlcov 44 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft data 2 | graft examples 3 | graft spdx 4 | graft tests 5 | 6 | prune src/spdx_tools.egg-info 7 | 8 | include spdx/licenses.json 9 | include README.md 10 | include CHANGELOG.rst 11 | include LICENSE 12 | include MANIFEST.in 13 | include setup.py 14 | include setup.cfg 15 | include .gitignore 16 | include MANIFEST.in 17 | include .travis.yml 18 | include circle.yml 19 | include appveyor.yml 20 | 21 | global-exclude *.py[co] __pycache__ *.*~ 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | image: 3 | - Visual Studio 2019 4 | environment: 5 | matrix: 6 | - PYTHON_EXE: "C:\\Python37-x64\\python.exe" 7 | - PYTHON_EXE: "C:\\Python38-x64\\python.exe" 8 | - PYTHON_EXE: "C:\\Python39-x64\\python.exe" 9 | - PYTHON_EXE: "C:\\Python310-x64\\python.exe" 10 | 11 | install: 12 | - "%PYTHON_EXE% --version" 13 | - "%PYTHON_EXE% -m pip install --upgrade pip" 14 | - "%PYTHON_EXE% -m pip install --upgrade setuptools setuptools_scm wheel build pytest" 15 | - "%PYTHON_EXE% -m pip install --upgrade -e ." 16 | 17 | build: off 18 | 19 | test_script: 20 | - "%PYTHON_EXE% -m pytest" 21 | -------------------------------------------------------------------------------- /assets/SPDXJSONExample-v2.3.spdx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/assets/SPDXJSONExample-v2.3.spdx.png -------------------------------------------------------------------------------- /examples/spdx2_convert_format.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from os import path 5 | 6 | from spdx_tools.spdx.model import Document 7 | from spdx_tools.spdx.writer.write_anything import write_file 8 | from spdx_tools.spdx.parser.parse_anything import parse_file 9 | 10 | # This example demonstrates how to load an existing SPDX2 file and convert it to a different SPDX2 format 11 | 12 | # Provide a path to the input file in the originating format 13 | input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXLite.spdx") 14 | # Parse the original input file (format is deduced automatically from the file extension) 15 | document: Document = parse_file(input_path) 16 | # Write to a different file format (e.g. XML, format is deduced automatically from the file extension) 17 | write_file(document, "converted_format.xml") 18 | -------------------------------------------------------------------------------- /examples/spdx2_convert_to_spdx3.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from os import path 5 | 6 | from spdx_tools.spdx.model import Document 7 | from spdx_tools.spdx3.payload import Payload 8 | from spdx_tools.spdx3.writer.json_ld.json_ld_writer import write_payload 9 | from spdx_tools.spdx3.bump_from_spdx2.spdx_document import bump_spdx_document 10 | from spdx_tools.spdx.parser.parse_anything import parse_file 11 | 12 | # This example demonstrates how to load an existing SPDX2 file and convert it to the SPDX3 format 13 | 14 | # Provide a path to the input file 15 | input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXLite.spdx") 16 | # Parse the original SPDX2 input file 17 | spdx2_document: Document = parse_file(input_path) 18 | # Convert original document to an SPDX3 payload 19 | spdx3_payload: Payload = bump_spdx_document(spdx2_document) 20 | # Write SPDX3 payload in json-ld format 21 | write_payload(spdx3_payload, "spdx2_to_3") 22 | -------------------------------------------------------------------------------- /examples/spdx2_generate_graph.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from os import path 5 | 6 | from spdx_tools.spdx.graph_generation import export_graph_from_document 7 | from spdx_tools.spdx.model import Document 8 | from spdx_tools.spdx.parser.parse_anything import parse_file 9 | 10 | # This example demonstrates how to generate a relationship graph for an SPDX2 document 11 | 12 | # Provide a path to the input file 13 | input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXJSONExample-v2.3.spdx.json") 14 | # Parse the file 15 | document: Document = parse_file(input_path) 16 | # Generate the graph (note: you need to have installed the optional dependencies networkx and pygraphviz) 17 | export_graph_from_document(document, "graph.png") 18 | -------------------------------------------------------------------------------- /examples/spdx2_parse_file.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import logging 5 | from os import path 6 | 7 | from spdx_tools.spdx.model.document import Document 8 | from spdx_tools.spdx.parser.error import SPDXParsingError 9 | from spdx_tools.spdx.parser.parse_anything import parse_file 10 | 11 | # This example demonstrates how to parse an existing spdx file. 12 | 13 | # Provide a path to the input file 14 | input_path = path.join(path.dirname(__file__), "..", "tests", "spdx", "data", "SPDXLite.spdx") 15 | try: 16 | # Try to parse the input file. If successful, returns a Document, otherwise raises an SPDXParsingError 17 | document: Document = parse_file(input_path) 18 | except SPDXParsingError: 19 | logging.exception("Failed to parse spdx file") 20 | 21 | # We can now access attributes from the parsed document 22 | print(f"Parsed document name: {document.creation_info.name}") 23 | creators_as_str = ", ".join([creator.to_serialized_string() for creator in document.creation_info.creators]) 24 | print(f"Created on {document.creation_info.created} by {creators_as_str}") 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from setuptools import setup 4 | 5 | if __name__ == "__main__": 6 | setup() 7 | -------------------------------------------------------------------------------- /src/spdx_tools/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/common/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/common/spdx_licensing.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from license_expression import get_spdx_licensing 5 | 6 | # this getter takes quite long so we only call it once in this singleton module 7 | spdx_licensing = get_spdx_licensing() 8 | -------------------------------------------------------------------------------- /src/spdx_tools/common/typing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/common/typing/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/common/typing/constructor_type_errors.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List 5 | 6 | 7 | class ConstructorTypeErrors(TypeError): 8 | """ 9 | Helper class that holds a list of error messages. Intended to capture all TypeErrors encountered during a 10 | constructor call, instead of raising only the first one. 11 | """ 12 | 13 | messages: List[str] 14 | 15 | def __init__(self, messages: List[str]): 16 | self.messages = messages 17 | 18 | def get_messages(self): 19 | return list(self.messages) 20 | -------------------------------------------------------------------------------- /src/spdx_tools/common/typing/type_checks.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from dataclasses import fields 5 | 6 | from beartype.typing import Any, Dict 7 | 8 | from spdx_tools.common.typing.constructor_type_errors import ConstructorTypeErrors 9 | 10 | 11 | def check_types_and_set_values(instance_under_construction: Any, local_variables: Dict) -> None: 12 | """ 13 | Helper method to accumulate all type errors encountered during a constructor call and return them in a 14 | ConstructorTypeErrors instance. 15 | Background: Our setters are enhanced with runtime typechecks using beartype. However, this means that by 16 | default, a TypeError is raised on the first type violation that is encountered. We consider it more helpful to 17 | return all type violations in one go. 18 | As an aside, defining constructors "manually" using this utility method helps avoid a nasty PyCharm bug: 19 | https://youtrack.jetbrains.com/issue/PY-34569 20 | """ 21 | errors = [] 22 | for field in fields(instance_under_construction): 23 | key = field.name 24 | value = local_variables.get(key) 25 | try: 26 | setattr(instance_under_construction, key, value) 27 | except TypeError as err: 28 | error_message: str = err.args[0] 29 | errors.append(error_message) 30 | if errors: 31 | raise ConstructorTypeErrors(errors) 32 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/casing_tools.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from re import sub 5 | 6 | 7 | def snake_case_to_camel_case(snake_case_string: str) -> str: 8 | each_word_capitalized = sub(r"[_\-]+", " ", snake_case_string).title().replace(" ", "") 9 | return each_word_capitalized[0].lower() + each_word_capitalized[1:] 10 | 11 | 12 | def camel_case_to_snake_case(camel_case_string: str) -> str: 13 | snake_case_string = sub("(?!^)([A-Z]+)", r"_\1", camel_case_string).lower() 14 | return snake_case_string 15 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/clitools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/clitools/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/constants.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | DOCUMENT_SPDX_ID = "SPDXRef-DOCUMENT" 5 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/datetime_conversions.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from datetime import datetime, timezone 5 | 6 | 7 | def datetime_from_str(date_str: str) -> datetime: 8 | if not isinstance(date_str, str): 9 | raise TypeError(f"Could not convert str to datetime, invalid type: {type(date_str).__name__}") 10 | 11 | date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match 12 | return date 13 | 14 | 15 | def datetime_to_iso_string(date: datetime) -> str: 16 | """ 17 | Return an ISO-8601 representation of a datetime object. 18 | """ 19 | if date.tzinfo is not None: 20 | date = date.astimezone(timezone.utc) # Convert aware datetimes to UTC 21 | date = date.replace(tzinfo=None) # Convert to naive datetime 22 | 23 | if date.microsecond != 0: 24 | date = date.replace(microsecond=0) # SPDX does not support microseconds 25 | 26 | return date.isoformat() + "Z" 27 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/formats.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum, auto 5 | 6 | from spdx_tools.spdx.parser.error import SPDXParsingError 7 | 8 | 9 | class FileFormat(Enum): 10 | JSON = auto() 11 | YAML = auto() 12 | XML = auto() 13 | TAG_VALUE = auto() 14 | RDF_XML = auto() 15 | 16 | 17 | def file_name_to_format(file_name: str) -> FileFormat: 18 | if file_name.endswith(".rdf") or file_name.endswith(".rdf.xml"): 19 | return FileFormat.RDF_XML 20 | elif file_name.endswith(".tag") or file_name.endswith(".spdx"): 21 | return FileFormat.TAG_VALUE 22 | elif file_name.endswith(".json"): 23 | return FileFormat.JSON 24 | elif file_name.endswith(".xml"): 25 | return FileFormat.XML 26 | elif file_name.endswith(".yaml") or file_name.endswith(".yml"): 27 | return FileFormat.YAML 28 | else: 29 | raise SPDXParsingError(["Unsupported SPDX file type: " + str(file_name)]) 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/jsonschema/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/annotation_converter.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Any, Type 5 | 6 | from spdx_tools.spdx.datetime_conversions import datetime_to_iso_string 7 | from spdx_tools.spdx.jsonschema.annotation_properties import AnnotationProperty 8 | from spdx_tools.spdx.jsonschema.converter import TypedConverter 9 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 10 | from spdx_tools.spdx.model import Annotation, Document 11 | 12 | 13 | class AnnotationConverter(TypedConverter[Annotation]): 14 | def _get_property_value( 15 | self, annotation: Annotation, annotation_property: AnnotationProperty, document: Document = None 16 | ) -> Any: 17 | if annotation_property == AnnotationProperty.ANNOTATION_DATE: 18 | return datetime_to_iso_string(annotation.annotation_date) 19 | elif annotation_property == AnnotationProperty.ANNOTATION_TYPE: 20 | return annotation.annotation_type.name 21 | elif annotation_property == AnnotationProperty.ANNOTATOR: 22 | return annotation.annotator.to_serialized_string() 23 | elif annotation_property == AnnotationProperty.COMMENT: 24 | return annotation.annotation_comment 25 | 26 | def get_json_type(self) -> Type[JsonProperty]: 27 | return AnnotationProperty 28 | 29 | def get_data_model_type(self) -> Type[Annotation]: 30 | return Annotation 31 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/annotation_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class AnnotationProperty(JsonProperty): 10 | ANNOTATION_DATE = auto() 11 | ANNOTATION_TYPE = auto() 12 | ANNOTATOR = auto() 13 | COMMENT = auto() 14 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/checksum_converter.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Type 5 | 6 | from spdx_tools.spdx.jsonschema.checksum_properties import ChecksumProperty 7 | from spdx_tools.spdx.jsonschema.converter import TypedConverter 8 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 9 | from spdx_tools.spdx.model import Checksum, ChecksumAlgorithm, Document 10 | 11 | 12 | class ChecksumConverter(TypedConverter[Checksum]): 13 | def get_data_model_type(self) -> Type[Checksum]: 14 | return Checksum 15 | 16 | def get_json_type(self) -> Type[JsonProperty]: 17 | return ChecksumProperty 18 | 19 | def _get_property_value( 20 | self, checksum: Checksum, checksum_property: ChecksumProperty, _document: Document = None 21 | ) -> str: 22 | if checksum_property == ChecksumProperty.ALGORITHM: 23 | return algorithm_to_json_string(checksum.algorithm) 24 | elif checksum_property == ChecksumProperty.CHECKSUM_VALUE: 25 | return checksum.value 26 | 27 | 28 | def algorithm_to_json_string(algorithm: ChecksumAlgorithm) -> str: 29 | name_with_dash: str = algorithm.name.replace("_", "-") 30 | if "BLAKE2B" in name_with_dash: 31 | return name_with_dash.replace("BLAKE2B", "BLAKE2b") 32 | return name_with_dash 33 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/checksum_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class ChecksumProperty(JsonProperty): 10 | ALGORITHM = auto() 11 | CHECKSUM_VALUE = auto() 12 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/creation_info_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class CreationInfoProperty(JsonProperty): 10 | CREATED = auto() 11 | CREATORS = auto() 12 | LICENSE_LIST_VERSION = auto() 13 | COMMENT = auto() 14 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/document_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class DocumentProperty(JsonProperty): 10 | SPDX_ID = auto() 11 | ANNOTATIONS = auto() 12 | COMMENT = auto() 13 | CREATION_INFO = auto() 14 | DATA_LICENSE = auto() 15 | EXTERNAL_DOCUMENT_REFS = auto() 16 | HAS_EXTRACTED_LICENSING_INFOS = auto() 17 | NAME = auto() 18 | SPDX_VERSION = auto() 19 | DOCUMENT_NAMESPACE = auto() 20 | PACKAGES = auto() 21 | FILES = auto() 22 | SNIPPETS = auto() 23 | RELATIONSHIPS = auto() 24 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/external_document_ref_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class ExternalDocumentRefProperty(JsonProperty): 10 | EXTERNAL_DOCUMENT_ID = auto() 11 | SPDX_DOCUMENT = auto() 12 | CHECKSUM = auto() 13 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/external_package_ref_converter.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Any, Type 5 | 6 | from spdx_tools.spdx.jsonschema.converter import TypedConverter 7 | from spdx_tools.spdx.jsonschema.external_package_ref_properties import ExternalPackageRefProperty 8 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 9 | from spdx_tools.spdx.model import Document, ExternalPackageRef 10 | 11 | 12 | class ExternalPackageRefConverter(TypedConverter[ExternalPackageRef]): 13 | def _get_property_value( 14 | self, 15 | external_ref: ExternalPackageRef, 16 | external_ref_property: ExternalPackageRefProperty, 17 | document: Document = None, 18 | ) -> Any: 19 | if external_ref_property == ExternalPackageRefProperty.COMMENT: 20 | return external_ref.comment 21 | elif external_ref_property == ExternalPackageRefProperty.REFERENCE_CATEGORY: 22 | return external_ref.category.name 23 | elif external_ref_property == ExternalPackageRefProperty.REFERENCE_LOCATOR: 24 | return external_ref.locator 25 | elif external_ref_property == ExternalPackageRefProperty.REFERENCE_TYPE: 26 | return external_ref.reference_type 27 | 28 | def get_json_type(self) -> Type[JsonProperty]: 29 | return ExternalPackageRefProperty 30 | 31 | def get_data_model_type(self) -> Type[ExternalPackageRef]: 32 | return ExternalPackageRef 33 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/external_package_ref_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class ExternalPackageRefProperty(JsonProperty): 10 | COMMENT = auto() 11 | REFERENCE_CATEGORY = auto() 12 | REFERENCE_LOCATOR = auto() 13 | REFERENCE_TYPE = auto() 14 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/extracted_licensing_info_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class ExtractedLicensingInfoProperty(JsonProperty): 10 | COMMENT = auto() 11 | EXTRACTED_TEXT = auto() 12 | LICENSE_ID = auto() 13 | NAME = auto() 14 | SEE_ALSOS = auto() 15 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/file_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class FileProperty(JsonProperty): 10 | SPDX_ID = auto() 11 | ANNOTATIONS = auto() 12 | ARTIFACT_OFS = auto() 13 | ATTRIBUTION_TEXTS = auto() 14 | CHECKSUMS = auto() 15 | COMMENT = auto() 16 | COPYRIGHT_TEXT = auto() 17 | FILE_CONTRIBUTORS = auto() 18 | FILE_DEPENDENCIES = auto() 19 | FILE_NAME = auto() 20 | FILE_TYPES = auto() 21 | LICENSE_COMMENTS = auto() 22 | LICENSE_CONCLUDED = auto() 23 | LICENSE_INFO_IN_FILES = auto() 24 | NOTICE_TEXT = auto() 25 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/json_property.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum 5 | 6 | 7 | class JsonProperty(Enum): 8 | """ 9 | Parent class for all json property classes. Not meant to be instantiated directly, only to have a common parent 10 | type that can be used in type hints. 11 | In general, all the child enums list the properties of the corresponding objects from the json schema. 12 | """ 13 | 14 | pass 15 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/optional_utils.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Callable, Optional, TypeVar 5 | 6 | T = TypeVar("T") 7 | S = TypeVar("S") 8 | 9 | 10 | def apply_if_present(function: Callable[[T], S], optional_value: Optional[T]) -> Optional[S]: 11 | """ 12 | Apply the passed function to the optional value if it is not None. Else returns None. 13 | """ 14 | return function(optional_value) if optional_value is not None else None 15 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/package_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class PackageProperty(JsonProperty): 10 | SPDX_ID = auto() 11 | ANNOTATIONS = auto() 12 | ATTRIBUTION_TEXTS = auto() 13 | BUILT_DATE = auto() 14 | CHECKSUMS = auto() 15 | COMMENT = auto() 16 | COPYRIGHT_TEXT = auto() 17 | DESCRIPTION = auto() 18 | DOWNLOAD_LOCATION = auto() 19 | EXTERNAL_REFS = auto() 20 | FILES_ANALYZED = auto() 21 | HOMEPAGE = auto() 22 | LICENSE_COMMENTS = auto() 23 | LICENSE_CONCLUDED = auto() 24 | LICENSE_DECLARED = auto() 25 | LICENSE_INFO_FROM_FILES = auto() 26 | NAME = auto() 27 | ORIGINATOR = auto() 28 | PACKAGE_FILE_NAME = auto() 29 | PACKAGE_VERIFICATION_CODE = auto() 30 | PRIMARY_PACKAGE_PURPOSE = auto() 31 | RELEASE_DATE = auto() 32 | SOURCE_INFO = auto() 33 | SUMMARY = auto() 34 | SUPPLIER = auto() 35 | VALID_UNTIL_DATE = auto() 36 | VERSION_INFO = auto() 37 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/package_verification_code_converter.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Any, Type 5 | 6 | from spdx_tools.spdx.jsonschema.converter import TypedConverter 7 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 8 | from spdx_tools.spdx.jsonschema.package_verification_code_properties import PackageVerificationCodeProperty 9 | from spdx_tools.spdx.model import Document, PackageVerificationCode 10 | 11 | 12 | class PackageVerificationCodeConverter(TypedConverter[PackageVerificationCode]): 13 | def _get_property_value( 14 | self, 15 | verification_code: PackageVerificationCode, 16 | verification_code_property: PackageVerificationCodeProperty, 17 | document: Document = None, 18 | ) -> Any: 19 | if verification_code_property == PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES: 20 | return verification_code.excluded_files or None 21 | elif verification_code_property == PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_VALUE: 22 | return verification_code.value 23 | 24 | def get_json_type(self) -> Type[JsonProperty]: 25 | return PackageVerificationCodeProperty 26 | 27 | def get_data_model_type(self) -> Type[PackageVerificationCode]: 28 | return PackageVerificationCode 29 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/package_verification_code_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class PackageVerificationCodeProperty(JsonProperty): 10 | PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES = auto() 11 | PACKAGE_VERIFICATION_CODE_VALUE = auto() 12 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/relationship_converter.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Any, Type 5 | 6 | from spdx_tools.spdx.jsonschema.converter import TypedConverter 7 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 8 | from spdx_tools.spdx.jsonschema.relationship_properties import RelationshipProperty 9 | from spdx_tools.spdx.model import Document, Relationship 10 | 11 | 12 | class RelationshipConverter(TypedConverter[Relationship]): 13 | def _get_property_value( 14 | self, relationship: Relationship, relationship_property: RelationshipProperty, document: Document = None 15 | ) -> Any: 16 | if relationship_property == RelationshipProperty.SPDX_ELEMENT_ID: 17 | return relationship.spdx_element_id 18 | elif relationship_property == RelationshipProperty.COMMENT: 19 | return relationship.comment 20 | elif relationship_property == RelationshipProperty.RELATED_SPDX_ELEMENT: 21 | return str(relationship.related_spdx_element_id) 22 | elif relationship_property == RelationshipProperty.RELATIONSHIP_TYPE: 23 | return relationship.relationship_type.name 24 | 25 | def get_json_type(self) -> Type[JsonProperty]: 26 | return RelationshipProperty 27 | 28 | def get_data_model_type(self) -> Type[Relationship]: 29 | return Relationship 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/relationship_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class RelationshipProperty(JsonProperty): 10 | SPDX_ELEMENT_ID = auto() 11 | COMMENT = auto() 12 | RELATED_SPDX_ELEMENT = auto() 13 | RELATIONSHIP_TYPE = auto() 14 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/jsonschema/snippet_properties.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import auto 5 | 6 | from spdx_tools.spdx.jsonschema.json_property import JsonProperty 7 | 8 | 9 | class SnippetProperty(JsonProperty): 10 | SPDX_ID = auto() 11 | ANNOTATIONS = auto() 12 | ATTRIBUTION_TEXTS = auto() 13 | COMMENT = auto() 14 | COPYRIGHT_TEXT = auto() 15 | LICENSE_COMMENTS = auto() 16 | LICENSE_CONCLUDED = auto() 17 | LICENSE_INFO_IN_SNIPPETS = auto() 18 | NAME = auto() 19 | RANGES = auto() 20 | SNIPPET_FROM_FILE = auto() 21 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx.model.spdx_no_assertion import SpdxNoAssertion 5 | from spdx_tools.spdx.model.spdx_none import SpdxNone 6 | from spdx_tools.spdx.model.version import Version 7 | from spdx_tools.spdx.model.actor import Actor, ActorType 8 | from spdx_tools.spdx.model.annotation import Annotation, AnnotationType 9 | from spdx_tools.spdx.model.checksum import Checksum, ChecksumAlgorithm 10 | from spdx_tools.spdx.model.external_document_ref import ExternalDocumentRef 11 | from spdx_tools.spdx.model.extracted_licensing_info import ExtractedLicensingInfo 12 | from spdx_tools.spdx.model.file import File, FileType 13 | from spdx_tools.spdx.model.package import ( 14 | ExternalPackageRef, 15 | ExternalPackageRefCategory, 16 | Package, 17 | PackagePurpose, 18 | PackageVerificationCode, 19 | ) 20 | from spdx_tools.spdx.model.relationship import Relationship, RelationshipType 21 | from spdx_tools.spdx.model.snippet import Snippet 22 | from spdx_tools.spdx.model.document import CreationInfo, Document 23 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/actor.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum, auto 5 | 6 | from beartype.typing import Optional 7 | 8 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 9 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 10 | 11 | 12 | class ActorType(Enum): 13 | PERSON = auto() 14 | ORGANIZATION = auto() 15 | TOOL = auto() 16 | 17 | 18 | @dataclass_with_properties 19 | class Actor: 20 | actor_type: ActorType 21 | name: str 22 | email: Optional[str] = None 23 | 24 | def __init__(self, actor_type: ActorType, name: str, email: Optional[str] = None): 25 | check_types_and_set_values(self, locals()) 26 | 27 | def to_serialized_string(self) -> str: 28 | """ 29 | All serialization formats use the same representation of an actor, so this method is included in the data model 30 | """ 31 | optional_email = f" ({self.email})" if self.email else "" 32 | return "".join([f"{self.actor_type.name.title()}:", f" {self.name}", optional_email]) 33 | 34 | def __str__(self): 35 | return self.to_serialized_string() 36 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/annotation.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from datetime import datetime 5 | from enum import Enum, auto 6 | 7 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 8 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 9 | from spdx_tools.spdx.model import Actor 10 | 11 | 12 | class AnnotationType(Enum): 13 | REVIEW = auto() 14 | OTHER = auto() 15 | 16 | 17 | @dataclass_with_properties 18 | class Annotation: 19 | spdx_id: str 20 | annotation_type: AnnotationType 21 | annotator: Actor 22 | annotation_date: datetime 23 | annotation_comment: str 24 | 25 | def __init__( 26 | self, 27 | spdx_id: str, 28 | annotation_type: AnnotationType, 29 | annotator: Actor, 30 | annotation_date: datetime, 31 | annotation_comment: str, 32 | ): 33 | check_types_and_set_values(self, locals()) 34 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/checksum.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum, auto 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | 9 | 10 | class ChecksumAlgorithm(Enum): 11 | SHA1 = auto() 12 | SHA224 = auto() 13 | SHA256 = auto() 14 | SHA384 = auto() 15 | SHA512 = auto() 16 | SHA3_256 = auto() 17 | SHA3_384 = auto() 18 | SHA3_512 = auto() 19 | BLAKE2B_256 = auto() 20 | BLAKE2B_384 = auto() 21 | BLAKE2B_512 = auto() 22 | BLAKE3 = auto() 23 | MD2 = auto() 24 | MD4 = auto() 25 | MD5 = auto() 26 | MD6 = auto() 27 | ADLER32 = auto() 28 | 29 | 30 | @dataclass_with_properties 31 | class Checksum: 32 | algorithm: ChecksumAlgorithm 33 | value: str 34 | 35 | def __init__(self, algorithm: ChecksumAlgorithm, value: str): 36 | check_types_and_set_values(self, locals()) 37 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/external_document_ref.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 6 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 7 | from spdx_tools.spdx.model import Checksum 8 | 9 | 10 | @dataclass_with_properties 11 | class ExternalDocumentRef: 12 | document_ref_id: str # of the form "DocumentRef-[idstring]" 13 | document_uri: str 14 | checksum: Checksum 15 | 16 | def __init__(self, document_ref_id: str, document_uri: str, checksum: Checksum): 17 | check_types_and_set_values(self, locals()) 18 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/extracted_licensing_info.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from dataclasses import field 5 | 6 | from beartype.typing import List, Optional, Union 7 | 8 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 9 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 10 | from spdx_tools.spdx.model import SpdxNoAssertion 11 | 12 | 13 | @dataclass_with_properties 14 | class ExtractedLicensingInfo: 15 | license_id: Optional[str] = None 16 | extracted_text: Optional[str] = None 17 | license_name: Optional[Union[str, SpdxNoAssertion]] = None 18 | cross_references: List[str] = field(default_factory=list) 19 | comment: Optional[str] = None 20 | 21 | def __init__( 22 | self, 23 | license_id: Optional[str] = None, 24 | extracted_text: Optional[str] = None, 25 | license_name: Optional[Union[str, SpdxNoAssertion]] = None, 26 | cross_references: List[str] = None, 27 | comment: Optional[str] = None, 28 | ): 29 | cross_references = [] if cross_references is None else cross_references 30 | check_types_and_set_values(self, locals()) 31 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/spdx_no_assertion.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | SPDX_NO_ASSERTION_STRING = "NOASSERTION" 6 | 7 | 8 | class SpdxNoAssertion: 9 | """ 10 | Represents the SPDX NOASSERTION value. 11 | """ 12 | 13 | def __str__(self): 14 | return SPDX_NO_ASSERTION_STRING 15 | 16 | def __repr__(self): 17 | return SPDX_NO_ASSERTION_STRING 18 | 19 | def __eq__(self, other): 20 | return isinstance(other, SpdxNoAssertion) 21 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/spdx_none.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | SPDX_NONE_STRING = "NONE" 6 | 7 | 8 | class SpdxNone: 9 | """ 10 | Represents the SPDX NONE value. 11 | """ 12 | 13 | def __str__(self): 14 | return SPDX_NONE_STRING 15 | 16 | def __repr__(self): 17 | return SPDX_NONE_STRING 18 | 19 | def __eq__(self, other): 20 | return isinstance(other, SpdxNone) 21 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/model/version.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | 6 | import re 7 | from re import Pattern 8 | 9 | 10 | class Version: 11 | VERSION_REGEX: Pattern = re.compile(r"^(\d+)\.(\d+)$") 12 | 13 | major: int 14 | minor: int 15 | 16 | @classmethod 17 | def is_valid_version_string(cls, value: str) -> bool: 18 | return cls.VERSION_REGEX.match(value) is not None 19 | 20 | # No type hint for Python reasons. 21 | # See https://stackoverflow.com/questions/33533148/how-do-i-type-hint-a-method-with-the-type-of-the-enclosing-class 22 | @classmethod 23 | def from_string(cls, value: str): 24 | if not Version.is_valid_version_string(value): 25 | raise ValueError(f"{value} is not a valid version string") 26 | 27 | match = cls.VERSION_REGEX.match(value) 28 | return cls(int(match.group(1)), int(match.group(2))) 29 | 30 | def __init__(self, major: int, minor: int): 31 | self.major = major 32 | self.minor = minor 33 | 34 | def __str__(self): 35 | return f"{self.major}.{self.minor}" 36 | 37 | def __eq__(self, other): 38 | if not isinstance(other, Version): 39 | return False 40 | return self.major == other.major and self.minor == other.minor 41 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/parser/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/error.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List 5 | 6 | 7 | class SPDXParsingError(Exception): 8 | messages: List[str] 9 | 10 | def __init__(self, messages: List[str]): 11 | self.messages = messages 12 | 13 | def get_messages(self): 14 | return list(self.messages) 15 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/json/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/parser/json/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/json/json_parser.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import json 5 | 6 | from beartype.typing import Dict 7 | 8 | from spdx_tools.spdx.model import Document 9 | from spdx_tools.spdx.parser.jsonlikedict.json_like_dict_parser import JsonLikeDictParser 10 | 11 | 12 | def parse_from_file(file_name: str, encoding: str = "utf-8") -> Document: 13 | with open(file_name, encoding=encoding) as file: 14 | input_doc_as_dict: Dict = json.load(file) 15 | 16 | return JsonLikeDictParser().parse(input_doc_as_dict) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/jsonlikedict/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/parser/jsonlikedict/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/jsonlikedict/checksum_parser.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Dict, Optional 5 | 6 | from spdx_tools.spdx.model import Checksum, ChecksumAlgorithm 7 | from spdx_tools.spdx.parser.jsonlikedict.dict_parsing_functions import json_str_to_enum_name 8 | from spdx_tools.spdx.parser.logger import Logger 9 | from spdx_tools.spdx.parser.parsing_functions import ( 10 | construct_or_raise_parsing_error, 11 | raise_parsing_error_if_logger_has_messages, 12 | ) 13 | 14 | 15 | class ChecksumParser: 16 | logger: Logger 17 | 18 | def __init__(self): 19 | self.logger = Logger() 20 | 21 | @staticmethod 22 | def parse_checksum(checksum_dict: Dict) -> Checksum: 23 | logger = Logger() 24 | algorithm: str = json_str_to_enum_name(checksum_dict.get("algorithm", "")) 25 | try: 26 | checksum_algorithm = ChecksumAlgorithm[algorithm] 27 | except KeyError: 28 | logger.append(f"Invalid ChecksumAlgorithm: {algorithm}") 29 | checksum_algorithm = None 30 | checksum_value: Optional[str] = checksum_dict.get("checksumValue") 31 | raise_parsing_error_if_logger_has_messages(logger, "Checksum") 32 | checksum = construct_or_raise_parsing_error(Checksum, dict(algorithm=checksum_algorithm, value=checksum_value)) 33 | return checksum 34 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/jsonlikedict/license_expression_parser.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Union 5 | from license_expression import ExpressionError, LicenseExpression 6 | 7 | from spdx_tools.common.spdx_licensing import spdx_licensing 8 | from spdx_tools.spdx.model import SpdxNoAssertion, SpdxNone 9 | from spdx_tools.spdx.parser.error import SPDXParsingError 10 | 11 | 12 | class LicenseExpressionParser: 13 | @staticmethod 14 | def parse_license_expression(license_expression_str: str) -> Union[LicenseExpression, SpdxNone, SpdxNoAssertion]: 15 | if isinstance(license_expression_str, str): 16 | if license_expression_str.upper() == "NOASSERTION": 17 | return SpdxNoAssertion() 18 | if license_expression_str.upper() == "NONE": 19 | return SpdxNone() 20 | 21 | try: 22 | license_expression = spdx_licensing.parse(license_expression_str) 23 | except ExpressionError as err: 24 | err_msg = f'Error parsing LicenseExpression: "{license_expression_str}"' 25 | if err.args: 26 | err_msg += f": {err.args[0]}" 27 | raise SPDXParsingError([err_msg]) 28 | 29 | return license_expression 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/logger.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List 5 | 6 | 7 | class Logger: 8 | messages: List[str] 9 | 10 | def __init__(self): 11 | self.messages = [] 12 | 13 | def append(self, message: str): 14 | self.messages.append(message) 15 | 16 | def extend(self, messages_to_append: List[str]): 17 | self.messages.extend(messages_to_append) 18 | 19 | def has_messages(self): 20 | return bool(self.messages) 21 | 22 | def get_messages(self): 23 | return list(self.messages) 24 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/parsing_functions.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Any, Dict 5 | 6 | from spdx_tools.common.typing.constructor_type_errors import ConstructorTypeErrors 7 | from spdx_tools.spdx.parser.error import SPDXParsingError 8 | from spdx_tools.spdx.parser.logger import Logger 9 | 10 | 11 | def construct_or_raise_parsing_error(object_to_construct: Any, args_for_construction: Dict) -> Any: 12 | try: 13 | constructed_object = object_to_construct(**args_for_construction) 14 | except ConstructorTypeErrors as err: 15 | raise SPDXParsingError([f"Error while constructing {object_to_construct.__name__}: {err.get_messages()}"]) 16 | except TypeError as err: 17 | raise SPDXParsingError([f"Error while constructing {object_to_construct.__name__}: {err.args[0]}"]) 18 | return constructed_object 19 | 20 | 21 | def raise_parsing_error_if_logger_has_messages(logger: Logger, parsed_object_name: str = None): 22 | if logger.has_messages(): 23 | if parsed_object_name: 24 | raise SPDXParsingError([f"Error while parsing {parsed_object_name}: {logger.get_messages()}"]) 25 | else: 26 | raise SPDXParsingError(logger.get_messages()) 27 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/rdf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/parser/rdf/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/tagvalue/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/parser/tagvalue/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/tagvalue/tagvalue_parser.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx.model import Document 5 | from spdx_tools.spdx.parser.tagvalue.parser import Parser 6 | 7 | 8 | def parse_from_file(file_name: str, encoding: str = "utf-8") -> Document: 9 | parser = Parser() 10 | with open(file_name, encoding=encoding) as file: 11 | data = file.read() 12 | document: Document = parser.parse(data) 13 | return document 14 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/xml/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/parser/xml/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/yaml/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/parser/yaml/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/parser/yaml/yaml_parser.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import yaml 5 | from beartype.typing import Dict 6 | 7 | from spdx_tools.spdx.model import Document 8 | from spdx_tools.spdx.parser.jsonlikedict.json_like_dict_parser import JsonLikeDictParser 9 | 10 | 11 | def parse_from_file(file_name: str, encoding: str = "utf-8") -> Document: 12 | with open(file_name, encoding=encoding) as file: 13 | input_doc_as_dict: Dict = yaml.safe_load(file) 14 | 15 | return JsonLikeDictParser().parse(input_doc_as_dict) 16 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/py.typed -------------------------------------------------------------------------------- /src/spdx_tools/spdx/rdfschema/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/rdfschema/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/rdfschema/namespace.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from rdflib import Namespace 5 | 6 | SPDX_NAMESPACE = Namespace("http://spdx.org/rdf/terms#") 7 | POINTER_NAMESPACE = Namespace("http://www.w3.org/2009/pointers#") 8 | REFERENCE_NAMESPACE = Namespace("http://spdx.org/rdf/references/") 9 | LICENSE_NAMESPACE = Namespace("http://spdx.org/licenses/") 10 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/validation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/validation/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/validation/actor_validator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from beartype.typing import List 6 | 7 | from spdx_tools.spdx.model import Actor, ActorType 8 | from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage 9 | 10 | 11 | def validate_actors(actors: List[Actor], parent_id: str) -> List[ValidationMessage]: 12 | validation_messages = [] 13 | for actor in actors: 14 | validation_messages.extend(validate_actor(actor, parent_id)) 15 | 16 | return validation_messages 17 | 18 | 19 | def validate_actor(actor: Actor, parent_id: str) -> List[ValidationMessage]: 20 | validation_messages = [] 21 | 22 | if actor.actor_type == ActorType.TOOL and actor.email is not None: 23 | validation_messages.append( 24 | ValidationMessage( 25 | f"email must be None if actor_type is TOOL, but is: {actor.email}", 26 | ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR, full_element=actor), 27 | ) 28 | ) 29 | 30 | return validation_messages 31 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/validation/annotation_validator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from beartype.typing import List 6 | 7 | from spdx_tools.spdx.model import Annotation, Document 8 | from spdx_tools.spdx.validation.actor_validator import validate_actor 9 | from spdx_tools.spdx.validation.spdx_id_validators import validate_spdx_id 10 | from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage 11 | 12 | 13 | def validate_annotations(annotations: List[Annotation], document: Document) -> List[ValidationMessage]: 14 | validation_messages = [] 15 | for annotation in annotations: 16 | validation_messages.extend(validate_annotation(annotation, document)) 17 | 18 | return validation_messages 19 | 20 | 21 | def validate_annotation(annotation: Annotation, document: Document) -> List[ValidationMessage]: 22 | validation_messages = [] 23 | context = ValidationContext(element_type=SpdxElementType.ANNOTATION, full_element=annotation) 24 | 25 | validation_messages.extend(validate_actor(annotation.annotator, "annotation")) 26 | 27 | messages: List[str] = validate_spdx_id(annotation.spdx_id, document, check_document=True) 28 | for message in messages: 29 | validation_messages.append(ValidationMessage(message, context)) 30 | 31 | return validation_messages 32 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/validation/package_verification_code_validator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import re 6 | 7 | from beartype.typing import List 8 | 9 | from spdx_tools.spdx.model import PackageVerificationCode 10 | from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage 11 | 12 | 13 | def validate_verification_code(verification_code: PackageVerificationCode, parent_id: str) -> List[ValidationMessage]: 14 | validation_messages: List[ValidationMessage] = [] 15 | context = ValidationContext( 16 | parent_id=parent_id, element_type=SpdxElementType.PACKAGE_VERIFICATION_CODE, full_element=verification_code 17 | ) 18 | 19 | for file in verification_code.excluded_files: 20 | if file.startswith("/"): 21 | validation_messages.append( 22 | ValidationMessage(f'file name must not be an absolute path starting with "/", but is: {file}', context) 23 | ) 24 | 25 | value: str = verification_code.value 26 | if not re.match("^[0-9a-f]{40}$", value): 27 | validation_messages.append( 28 | ValidationMessage( 29 | f"value of verification_code must consist of 40 lowercase hexadecimal digits, but is: {value} " 30 | f"(length: {len(value)} digits)", 31 | context, 32 | ) 33 | ) 34 | 35 | return validation_messages 36 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/validation/validation_message.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from dataclasses import dataclass 6 | from enum import Enum, auto 7 | 8 | from beartype.typing import Any, Optional 9 | 10 | 11 | class SpdxElementType(Enum): 12 | LICENSE_EXPRESSION = auto() 13 | PACKAGE_VERIFICATION_CODE = auto() 14 | EXTERNAL_DOCUMENT_REF = auto() 15 | CHECKSUM = auto() 16 | EXTERNAL_PACKAGE_REF = auto() 17 | ACTOR = auto() 18 | DOCUMENT = auto() 19 | CREATION_INFO = auto() 20 | PACKAGE = auto() 21 | FILE = auto() 22 | SNIPPET = auto() 23 | ANNOTATION = auto() 24 | RELATIONSHIP = auto() 25 | EXTRACTED_LICENSING_INFO = auto() 26 | 27 | 28 | @dataclass(frozen=True) 29 | class ValidationContext: 30 | spdx_id: Optional[str] = None # not every type has an id, or it might be missing 31 | parent_id: Optional[str] = None # if a parent is known and has a valid id 32 | element_type: Optional[SpdxElementType] = None 33 | full_element: Any = None # can be any class of the data model 34 | 35 | 36 | @dataclass(frozen=True) 37 | class ValidationMessage: 38 | validation_message: str 39 | context: ValidationContext 40 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/writer/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/json/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/writer/json/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/json/json_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import json 5 | 6 | from beartype.typing import IO 7 | 8 | from spdx_tools.spdx.jsonschema.document_converter import DocumentConverter 9 | from spdx_tools.spdx.model import Document 10 | from spdx_tools.spdx.writer.write_utils import convert, validate_and_deduplicate 11 | 12 | 13 | def write_document_to_stream( 14 | document: Document, 15 | stream: IO[str], 16 | validate: bool = True, 17 | converter: DocumentConverter = None, 18 | drop_duplicates: bool = True, 19 | ): 20 | """ 21 | Serializes the provided document to json and writes it to a file with the provided name. Unless validate is set 22 | to False, validates the document before serialization. Unless a DocumentConverter instance is provided, 23 | a new one is created. 24 | """ 25 | document = validate_and_deduplicate(document, validate, drop_duplicates) 26 | document_dict = convert(document, converter) 27 | json.dump(document_dict, stream, indent=4) 28 | 29 | 30 | def write_document_to_file( 31 | document: Document, 32 | file_name: str, 33 | validate: bool = True, 34 | converter: DocumentConverter = None, 35 | drop_duplicates: bool = True, 36 | ): 37 | with open(file_name, "w", encoding="utf-8") as out: 38 | write_document_to_stream(document, out, validate, converter, drop_duplicates) 39 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/rdf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/writer/rdf/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/rdf/checksum_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from rdflib import RDF, BNode, Graph, Literal, URIRef 5 | 6 | from spdx_tools.spdx.model import Checksum, ChecksumAlgorithm 7 | from spdx_tools.spdx.rdfschema.namespace import SPDX_NAMESPACE 8 | 9 | 10 | def add_checksum_to_graph(checksum: Checksum, graph: Graph, parent: URIRef): 11 | checksum_node = BNode() 12 | graph.add((checksum_node, RDF.type, SPDX_NAMESPACE.Checksum)) 13 | graph.add((checksum_node, SPDX_NAMESPACE.algorithm, algorithm_to_rdf_string(checksum.algorithm))) 14 | graph.add((checksum_node, SPDX_NAMESPACE.checksumValue, Literal(checksum.value))) 15 | 16 | graph.add((parent, SPDX_NAMESPACE.checksum, checksum_node)) 17 | 18 | 19 | def algorithm_to_rdf_string(algorithm: ChecksumAlgorithm) -> URIRef: 20 | if "BLAKE2B" in algorithm.name: 21 | algorithm_rdf_string = algorithm.name.replace("_", "").lower() 22 | else: 23 | algorithm_rdf_string = algorithm.name.lower() 24 | 25 | return SPDX_NAMESPACE[f"checksumAlgorithm_{algorithm_rdf_string}"] 26 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/rdf/external_document_ref_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from rdflib import RDF, Graph, URIRef 5 | 6 | from spdx_tools.spdx.model import ExternalDocumentRef 7 | from spdx_tools.spdx.rdfschema.namespace import SPDX_NAMESPACE 8 | from spdx_tools.spdx.writer.rdf.checksum_writer import add_checksum_to_graph 9 | 10 | 11 | def add_external_document_ref_to_graph( 12 | external_document_ref: ExternalDocumentRef, graph: Graph, doc_node: URIRef, doc_namespace: str 13 | ): 14 | external_document_ref_resource = URIRef(f"{doc_namespace}#{external_document_ref.document_ref_id}") 15 | graph.add((external_document_ref_resource, RDF.type, SPDX_NAMESPACE.ExternalDocumentRef)) 16 | graph.add( 17 | (external_document_ref_resource, SPDX_NAMESPACE.spdxDocument, URIRef(external_document_ref.document_uri)) 18 | ) 19 | add_checksum_to_graph(external_document_ref.checksum, graph, external_document_ref_resource) 20 | 21 | graph.add((doc_node, SPDX_NAMESPACE.externalDocumentRef, external_document_ref_resource)) 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/tagvalue/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/writer/tagvalue/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/tagvalue/annotation_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright (c) 2022 spdx contributors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | from beartype.typing import TextIO 13 | 14 | from spdx_tools.spdx.datetime_conversions import datetime_to_iso_string 15 | from spdx_tools.spdx.model import Annotation 16 | from spdx_tools.spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_text_value, write_value 17 | 18 | 19 | def write_annotation(annotation: Annotation, text_output: TextIO): 20 | write_value("Annotator", annotation.annotator.to_serialized_string(), text_output) 21 | write_value("AnnotationDate", datetime_to_iso_string(annotation.annotation_date), text_output) 22 | write_value("AnnotationType", annotation.annotation_type.name, text_output) 23 | write_value("SPDXREF", annotation.spdx_id, text_output) 24 | write_text_value("AnnotationComment", annotation.annotation_comment, text_output) 25 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/tagvalue/extracted_licensing_info_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright (c) 2022 spdx contributors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | from beartype.typing import TextIO 13 | 14 | from spdx_tools.spdx.model import ExtractedLicensingInfo 15 | from spdx_tools.spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_text_value, write_value 16 | 17 | 18 | def write_extracted_licensing_info(extracted_licensing_info: ExtractedLicensingInfo, text_output: TextIO): 19 | write_value("LicenseID", extracted_licensing_info.license_id, text_output) 20 | write_text_value("ExtractedText", extracted_licensing_info.extracted_text, text_output) 21 | write_value("LicenseName", extracted_licensing_info.license_name, text_output) 22 | 23 | for cross_reference in sorted(extracted_licensing_info.cross_references): 24 | write_value("LicenseCrossReference", cross_reference, text_output) 25 | 26 | write_text_value("LicenseComment", extracted_licensing_info.comment, text_output) 27 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/tagvalue/relationship_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright (c) 2022 spdx contributors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | from beartype.typing import TextIO 13 | 14 | from spdx_tools.spdx.model import Relationship 15 | from spdx_tools.spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_text_value, write_value 16 | 17 | 18 | def write_relationship(relationship: Relationship, text_output: TextIO): 19 | write_value( 20 | "Relationship", 21 | " ".join( 22 | [ 23 | relationship.spdx_element_id, 24 | relationship.relationship_type.name, 25 | str(relationship.related_spdx_element_id), 26 | ] 27 | ), 28 | text_output, 29 | ) 30 | write_text_value("RelationshipComment", relationship.comment, text_output) 31 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/write_anything.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx.formats import FileFormat, file_name_to_format 5 | from spdx_tools.spdx.model import Document 6 | from spdx_tools.spdx.writer.json import json_writer 7 | from spdx_tools.spdx.writer.rdf import rdf_writer 8 | from spdx_tools.spdx.writer.tagvalue import tagvalue_writer 9 | from spdx_tools.spdx.writer.xml import xml_writer 10 | from spdx_tools.spdx.writer.yaml import yaml_writer 11 | 12 | 13 | def write_file(document: Document, file_name: str, validate: bool = True): 14 | output_format = file_name_to_format(file_name) 15 | if output_format == FileFormat.JSON: 16 | json_writer.write_document_to_file(document, file_name, validate) 17 | elif output_format == FileFormat.YAML: 18 | yaml_writer.write_document_to_file(document, file_name, validate) 19 | elif output_format == FileFormat.XML: 20 | xml_writer.write_document_to_file(document, file_name, validate) 21 | elif output_format == FileFormat.TAG_VALUE: 22 | tagvalue_writer.write_document_to_file(document, file_name, validate) 23 | elif output_format == FileFormat.RDF_XML: 24 | rdf_writer.write_document_to_file(document, file_name, validate) 25 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/write_utils.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List 5 | 6 | from spdx_tools.spdx.document_utils import create_document_without_duplicates 7 | from spdx_tools.spdx.jsonschema.document_converter import DocumentConverter 8 | from spdx_tools.spdx.model import Document 9 | from spdx_tools.spdx.validation.document_validator import validate_full_spdx_document 10 | from spdx_tools.spdx.validation.validation_message import ValidationMessage 11 | 12 | 13 | def validate_and_deduplicate(document: Document, validate: bool = True, drop_duplicates: bool = True) -> Document: 14 | if validate: 15 | validation_messages: List[ValidationMessage] = validate_full_spdx_document(document) 16 | if validation_messages: 17 | raise ValueError(f"Document is not valid. The following errors were detected: {validation_messages}") 18 | if drop_duplicates: 19 | document = create_document_without_duplicates(document) 20 | return document 21 | 22 | 23 | def convert(document: Document, converter: DocumentConverter) -> dict: 24 | if converter is None: 25 | converter = DocumentConverter() 26 | return converter.convert(document) 27 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/xml/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/writer/xml/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/xml/xml_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import xmltodict 5 | from beartype.typing import IO 6 | 7 | from spdx_tools.spdx.jsonschema.document_converter import DocumentConverter 8 | from spdx_tools.spdx.model import Document 9 | from spdx_tools.spdx.writer.write_utils import convert, validate_and_deduplicate 10 | 11 | 12 | def write_document_to_stream( 13 | document: Document, 14 | stream: IO[str], 15 | validate: bool = True, 16 | converter: DocumentConverter = None, 17 | drop_duplicates: bool = True, 18 | ): 19 | """ 20 | Serializes the provided document to XML and writes it to a file with the provided name. Unless validate is set 21 | to False, validates the document before serialization. Unless a DocumentConverter instance is provided, 22 | a new one is created. 23 | """ 24 | document = validate_and_deduplicate(document, validate, drop_duplicates) 25 | document_dict = {"Document": convert(document, converter)} 26 | xmltodict.unparse(document_dict, stream, encoding="utf-8", pretty=True) 27 | 28 | 29 | def write_document_to_file( 30 | document: Document, 31 | file_name: str, 32 | validate: bool = True, 33 | converter: DocumentConverter = None, 34 | drop_duplicates: bool = True, 35 | ): 36 | with open(file_name, "w", encoding="utf-8") as out: 37 | write_document_to_stream(document, out, validate, converter, drop_duplicates) 38 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/yaml/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx/writer/yaml/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx/writer/yaml/yaml_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import yaml 5 | from beartype.typing import IO 6 | 7 | from spdx_tools.spdx.jsonschema.document_converter import DocumentConverter 8 | from spdx_tools.spdx.model import Document 9 | from spdx_tools.spdx.writer.write_utils import convert, validate_and_deduplicate 10 | 11 | 12 | def write_document_to_stream( 13 | document: Document, 14 | stream: IO[str], 15 | validate: bool = True, 16 | converter: DocumentConverter = None, 17 | drop_duplicates: bool = True, 18 | ): 19 | """ 20 | Serializes the provided document to yaml and writes it to a file with the provided name. Unless validate is set 21 | to False, validates the document before serialization. Unless a DocumentConverter instance is provided, 22 | a new one is created. 23 | """ 24 | document = validate_and_deduplicate(document, validate, drop_duplicates) 25 | document_dict = convert(document, converter) 26 | yaml.safe_dump(document_dict, stream, indent=2) 27 | 28 | 29 | def write_document_to_file( 30 | document: Document, 31 | file_name: str, 32 | validate: bool = True, 33 | converter: DocumentConverter = None, 34 | drop_duplicates: bool = True, 35 | ): 36 | with open(file_name, "w", encoding="utf-8") as out: 37 | write_document_to_stream(document, out, validate, converter, drop_duplicates) 38 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/bump_from_spdx2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/bump_from_spdx2/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/bump_from_spdx2/bump_utils.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Optional, Union 5 | 6 | from spdx_tools.spdx.model.spdx_no_assertion import SpdxNoAssertion 7 | from spdx_tools.spdx.model.spdx_none import SpdxNone 8 | 9 | 10 | def handle_no_assertion_or_none(field: Union[SpdxNone, SpdxNoAssertion, str], field_name: str) -> Optional[str]: 11 | if isinstance(field, SpdxNone): 12 | print(f"{field_name}: Missing conversion for SpdxNone.") 13 | return None 14 | if isinstance(field, SpdxNoAssertion): 15 | return None 16 | if isinstance(field, str): 17 | return field 18 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/bump_from_spdx2/checksum.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model import Hash, HashAlgorithm 5 | from spdx_tools.spdx.model.checksum import Checksum as Spdx2_Checksum 6 | from spdx_tools.spdx.model.checksum import ChecksumAlgorithm 7 | 8 | 9 | def bump_checksum(spdx2_checksum: Spdx2_Checksum) -> Hash: 10 | algorithm: HashAlgorithm = convert_checksum_algorithm_to_hash_algorithm(spdx2_checksum.algorithm) 11 | value: str = spdx2_checksum.value 12 | 13 | return Hash(algorithm, value) 14 | 15 | 16 | def convert_checksum_algorithm_to_hash_algorithm(checksum_algorithm: ChecksumAlgorithm) -> HashAlgorithm: 17 | if checksum_algorithm.name.startswith("BLAKE"): 18 | return HashAlgorithm[checksum_algorithm.name.replace("_", "")] 19 | if checksum_algorithm == ChecksumAlgorithm.ADLER32: 20 | return HashAlgorithm.OTHER 21 | return HashAlgorithm[checksum_algorithm.name] 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/bump_from_spdx2/external_document_ref.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Tuple 5 | 6 | from spdx_tools.spdx3.bump_from_spdx2.checksum import bump_checksum 7 | from spdx_tools.spdx3.model import ExternalMap, Hash, NamespaceMap 8 | from spdx_tools.spdx.model.external_document_ref import ExternalDocumentRef 9 | 10 | 11 | def bump_external_document_ref(external_document_ref: ExternalDocumentRef) -> Tuple[NamespaceMap, ExternalMap]: 12 | verified_using: List[Hash] = [bump_checksum(external_document_ref.checksum)] 13 | 14 | return NamespaceMap(external_document_ref.document_ref_id, external_document_ref.document_uri + "#"), ExternalMap( 15 | external_id=f"{external_document_ref.document_ref_id}:SPDXRef-DOCUMENT", 16 | verified_using=verified_using, 17 | ) 18 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/bump_from_spdx2/message.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import sys 6 | 7 | MISSING_CONVERSION_REASONS = {0: "missing conversion rule", 1: "missing implementation"} 8 | 9 | 10 | def print_missing_conversion(field: str, reason, additional_information: str = ""): 11 | print(f"{field} not converted: {MISSING_CONVERSION_REASONS[reason]} {additional_information}", file=sys.stderr) 12 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/clitools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/clitools/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model.profile_identifier import ProfileIdentifierType 5 | from spdx_tools.spdx3.model.creation_info import CreationInfo 6 | from spdx_tools.spdx3.model.integrity_method import IntegrityMethod 7 | from spdx_tools.spdx3.model.hash import Hash, HashAlgorithm 8 | from spdx_tools.spdx3.model.external_reference import ExternalReference, ExternalReferenceType 9 | from spdx_tools.spdx3.model.external_identifier import ExternalIdentifier, ExternalIdentifierType 10 | from spdx_tools.spdx3.model.external_map import ExternalMap 11 | from spdx_tools.spdx3.model.namespace_map import NamespaceMap 12 | from spdx_tools.spdx3.model.element import Element 13 | from spdx_tools.spdx3.model.agent import Agent 14 | from spdx_tools.spdx3.model.person import Person 15 | from spdx_tools.spdx3.model.organization import Organization 16 | from spdx_tools.spdx3.model.software_agent import SoftwareAgent 17 | from spdx_tools.spdx3.model.tool import Tool 18 | from spdx_tools.spdx3.model.spdx_collection import ElementCollection 19 | from spdx_tools.spdx3.model.bundle import Bundle 20 | from spdx_tools.spdx3.model.bom import Bom 21 | from spdx_tools.spdx3.model.spdx_document import SpdxDocument 22 | from spdx_tools.spdx3.model.annotation import Annotation, AnnotationType 23 | from spdx_tools.spdx3.model.relationship import Relationship, RelationshipType, RelationshipCompleteness 24 | from spdx_tools.spdx3.model.lifecycle_scoped_relationship import LifecycleScopedRelationship, LifecycleScopeType 25 | from spdx_tools.spdx3.model.artifact import Artifact 26 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/agent.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model import CreationInfo, Element, ExternalIdentifier, ExternalReference, IntegrityMethod 9 | 10 | 11 | @dataclass_with_properties 12 | class Agent(Element): 13 | def __init__( 14 | self, 15 | spdx_id: str, 16 | creation_info: Optional[CreationInfo] = None, 17 | name: Optional[str] = None, 18 | summary: Optional[str] = None, 19 | description: Optional[str] = None, 20 | comment: Optional[str] = None, 21 | verified_using: List[IntegrityMethod] = None, 22 | external_reference: List[ExternalReference] = None, 23 | external_identifier: List[ExternalIdentifier] = None, 24 | extension: Optional[str] = None, 25 | ): 26 | verified_using = [] if verified_using is None else verified_using 27 | external_reference = [] if external_reference is None else external_reference 28 | external_identifier = [] if external_identifier is None else external_identifier 29 | check_types_and_set_values(self, locals()) 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/ai/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model.ai.ai_package import AIPackage 5 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/artifact.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import abstractmethod 5 | from dataclasses import field 6 | from datetime import datetime 7 | 8 | from beartype.typing import List, Optional 9 | 10 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 11 | from spdx_tools.spdx3.model import Element 12 | 13 | 14 | @dataclass_with_properties 15 | class Artifact(Element): 16 | originated_by: List[str] = field(default_factory=list) # SPDXID of the Agent/Tool 17 | supplied_by: List[str] = field(default_factory=list) # SPDXID of the Agent/Tool 18 | built_time: Optional[datetime] = None 19 | release_time: Optional[datetime] = None 20 | valid_until_time: Optional[datetime] = None 21 | standard: List[str] = field(default_factory=list) 22 | 23 | @abstractmethod 24 | def __init__(self): 25 | pass 26 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/build/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model.build.build import Build 5 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/creation_info.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from dataclasses import field 5 | from datetime import datetime 6 | 7 | from beartype.typing import List, Optional 8 | from semantic_version import Version 9 | 10 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 11 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 12 | from spdx_tools.spdx3.model import ProfileIdentifierType 13 | 14 | 15 | @dataclass_with_properties 16 | class CreationInfo: 17 | spec_version: Version 18 | created: datetime 19 | created_by: List[str] # SPDXID of Agents 20 | profile: List[ProfileIdentifierType] 21 | data_license: Optional[str] = "CC0-1.0" 22 | created_using: List[str] = field(default_factory=list) # SPDXID of Tools 23 | comment: Optional[str] = None 24 | 25 | def __init__( 26 | self, 27 | spec_version: Version, 28 | created: datetime, 29 | created_by: List[str], 30 | profile: List[ProfileIdentifierType], 31 | data_license: Optional[str] = "CC0-1.0", 32 | created_using: List[str] = None, 33 | comment: Optional[str] = None, 34 | ): 35 | created_using = [] if created_using is None else created_using 36 | check_types_and_set_values(self, locals()) 37 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/dataset/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model.dataset.dataset import Dataset, DatasetAvailabilityType, ConfidentialityLevelType 5 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/element.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import ABC, abstractmethod 5 | from dataclasses import field 6 | 7 | from beartype.typing import List, Optional 8 | 9 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 10 | from spdx_tools.spdx3.model import CreationInfo, ExternalIdentifier, ExternalReference, IntegrityMethod 11 | 12 | 13 | @dataclass_with_properties 14 | class Element(ABC): 15 | spdx_id: str # IRI 16 | creation_info: Optional[CreationInfo] = None 17 | name: Optional[str] = None 18 | summary: Optional[str] = None 19 | description: Optional[str] = None 20 | comment: Optional[str] = None 21 | verified_using: List[IntegrityMethod] = field(default_factory=list) 22 | external_reference: List[ExternalReference] = field(default_factory=list) 23 | external_identifier: List[ExternalIdentifier] = field(default_factory=list) 24 | extension: Optional[str] = None # placeholder for extension 25 | 26 | @abstractmethod 27 | def __init__(self): 28 | pass 29 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/external_identifier.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from dataclasses import field 5 | from enum import Enum, auto 6 | 7 | from beartype.typing import List, Optional 8 | 9 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 10 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 11 | 12 | 13 | class ExternalIdentifierType(Enum): 14 | CPE22 = auto() 15 | CPE23 = auto() 16 | CVE = auto() 17 | EMAIL = auto() 18 | GITOID = auto() 19 | PURL = auto() 20 | SECURITY_OTHER = auto() 21 | SWHID = auto() 22 | SWID = auto() 23 | URL_SCHEME = auto() 24 | OTHER = auto() 25 | 26 | 27 | @dataclass_with_properties 28 | class ExternalIdentifier: 29 | external_identifier_type: ExternalIdentifierType 30 | identifier: str 31 | comment: Optional[str] = None 32 | identifier_locator: List[str] = field(default_factory=list) 33 | issuing_authority: Optional[str] = None 34 | 35 | def __init__( 36 | self, 37 | external_identifier_type: ExternalIdentifierType, 38 | identifier: str, 39 | comment: Optional[str] = None, 40 | identifier_locator: List[str] = None, 41 | issuing_authority: Optional[str] = None, 42 | ): 43 | identifier_locator = [] if identifier_locator is None else identifier_locator 44 | check_types_and_set_values(self, locals()) 45 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/external_map.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from dataclasses import field 5 | 6 | from beartype.typing import List, Optional 7 | 8 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 9 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 10 | from spdx_tools.spdx3.model import IntegrityMethod 11 | 12 | 13 | @dataclass_with_properties 14 | class ExternalMap: 15 | external_id: str # anyURI 16 | verified_using: List[IntegrityMethod] = field(default_factory=list) 17 | location_hint: Optional[str] = None # anyURI 18 | defining_document: Optional[str] = None 19 | 20 | def __init__( 21 | self, 22 | external_id: str, 23 | verified_using: List[IntegrityMethod] = None, 24 | location_hint: Optional[str] = None, 25 | defining_document: Optional[str] = None, 26 | ): 27 | verified_using = [] if verified_using is None else verified_using 28 | check_types_and_set_values(self, locals()) 29 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/hash.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum, auto 5 | 6 | from beartype.typing import Optional 7 | 8 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 9 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 10 | from spdx_tools.spdx3.model import IntegrityMethod 11 | 12 | 13 | class HashAlgorithm(Enum): 14 | BLAKE2B256 = auto() 15 | BLAKE2B384 = auto() 16 | BLAKE2B512 = auto() 17 | BLAKE3 = auto() 18 | CRYSTALS_KYBER = auto() 19 | CRYSTALS_DILITHIUM = auto() 20 | FALCON = auto() 21 | MD2 = auto() 22 | MD4 = auto() 23 | MD5 = auto() 24 | MD6 = auto() 25 | OTHER = auto() 26 | SHA1 = auto() 27 | SHA224 = auto() 28 | SHA256 = auto() 29 | SHA3_224 = auto() 30 | SHA3_256 = auto() 31 | SHA3_384 = auto() 32 | SHA3_512 = auto() 33 | SHA384 = auto() 34 | SHA512 = auto() 35 | SPDXPVCSHA1 = auto() 36 | SPDXPVCSHA256 = auto() 37 | SPHINCS_PLUS = auto() 38 | 39 | 40 | @dataclass_with_properties 41 | class Hash(IntegrityMethod): 42 | algorithm: HashAlgorithm = None 43 | hash_value: str = None 44 | 45 | def __init__(self, algorithm: HashAlgorithm, hash_value: str, comment: Optional[str] = None): 46 | check_types_and_set_values(self, locals()) 47 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/integrity_method.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import ABC, abstractmethod 5 | 6 | from beartype.typing import Optional 7 | 8 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 9 | 10 | 11 | @dataclass_with_properties 12 | class IntegrityMethod(ABC): 13 | comment: Optional[str] = None 14 | 15 | @abstractmethod 16 | def __init__(self): 17 | pass 18 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from .any_license_info import AnyLicenseInfo 5 | from .conjunctive_license_set import ConjunctiveLicenseSet 6 | from .custom_license import CustomLicense 7 | from .custom_license_addition import CustomLicenseAddition 8 | from .disjunctive_license_set import DisjunctiveLicenseSet 9 | from .license import License 10 | from .license_addition import LicenseAddition 11 | from .license_field import LicenseField 12 | from .listed_license import ListedLicense 13 | from .listed_license_exception import ListedLicenseException 14 | from .no_assertion_license import NoAssertionLicense 15 | from .none_license import NoneLicense 16 | from .or_later_operator import OrLaterOperator 17 | from .with_addition_operator import WithAdditionOperator 18 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/any_license_info.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import abstractmethod 5 | 6 | from spdx_tools.spdx3.model.licensing.license_field import LicenseField 7 | 8 | 9 | class AnyLicenseInfo(LicenseField): 10 | @abstractmethod 11 | def __init__(self): 12 | pass 13 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/conjunctive_license_set.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model.licensing.any_license_info import AnyLicenseInfo 9 | 10 | 11 | @dataclass_with_properties 12 | class ConjunctiveLicenseSet(AnyLicenseInfo): 13 | member: List[AnyLicenseInfo] 14 | 15 | def __init__(self, member: List[AnyLicenseInfo]): 16 | check_types_and_set_values(self, locals()) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/custom_license.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model.licensing.license import License 9 | 10 | 11 | @dataclass_with_properties 12 | class CustomLicense(License): 13 | def __init__( 14 | self, 15 | license_id: str, 16 | license_name: str, 17 | license_text: str, 18 | license_comment: Optional[str] = None, 19 | see_also: List[str] = None, 20 | is_osi_approved: Optional[bool] = None, 21 | is_fsf_libre: Optional[bool] = None, 22 | standard_license_header: Optional[str] = None, 23 | standard_license_template: Optional[str] = None, 24 | is_deprecated_license_id: Optional[bool] = None, 25 | obsoleted_by: Optional[str] = None, 26 | ): 27 | see_also = [] if see_also is None else see_also 28 | check_types_and_set_values(self, locals()) 29 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/custom_license_addition.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model.licensing.license_addition import LicenseAddition 9 | 10 | 11 | @dataclass_with_properties 12 | class CustomLicenseAddition(LicenseAddition): 13 | def __init__( 14 | self, 15 | addition_id: str, 16 | addition_name: str, 17 | addition_text: str, 18 | addition_comment: Optional[str] = None, 19 | see_also: List[str] = None, 20 | standard_addition_template: Optional[str] = None, 21 | is_deprecated_addition_id: Optional[bool] = None, 22 | obsoleted_by: Optional[str] = None, 23 | ): 24 | see_also = [] if see_also is None else see_also 25 | check_types_and_set_values(self, locals()) 26 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/disjunctive_license_set.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model.licensing.any_license_info import AnyLicenseInfo 9 | 10 | 11 | @dataclass_with_properties 12 | class DisjunctiveLicenseSet(AnyLicenseInfo): 13 | member: List[AnyLicenseInfo] 14 | 15 | def __init__(self, member: List[AnyLicenseInfo]): 16 | check_types_and_set_values(self, locals()) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/license.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import abstractmethod 5 | from dataclasses import field 6 | 7 | from beartype.typing import List, Optional 8 | 9 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 10 | from spdx_tools.spdx3.model.licensing.any_license_info import AnyLicenseInfo 11 | 12 | 13 | @dataclass_with_properties 14 | class License(AnyLicenseInfo): 15 | license_id: str 16 | license_name: str 17 | license_text: str 18 | license_comment: Optional[str] = None 19 | see_also: List[str] = field(default_factory=list) 20 | is_osi_approved: Optional[bool] = None 21 | is_fsf_libre: Optional[bool] = None 22 | standard_license_header: Optional[str] = None 23 | standard_license_template: Optional[str] = None 24 | is_deprecated_license_id: Optional[bool] = None 25 | obsoleted_by: Optional[str] = None 26 | 27 | @abstractmethod 28 | def __init__(self): 29 | pass 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/license_addition.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import ABC, abstractmethod 5 | from dataclasses import field 6 | 7 | from beartype.typing import List, Optional 8 | 9 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 10 | 11 | 12 | @dataclass_with_properties 13 | class LicenseAddition(ABC): 14 | addition_id: str 15 | addition_name: str 16 | addition_text: str 17 | addition_comment: Optional[str] = None 18 | see_also: List[str] = field(default_factory=list) 19 | standard_addition_template: Optional[str] = None 20 | is_deprecated_addition_id: Optional[bool] = None 21 | obsoleted_by: Optional[str] = None 22 | 23 | @abstractmethod 24 | def __init__(self): 25 | pass 26 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/license_field.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import ABC, abstractmethod 5 | 6 | 7 | class LicenseField(ABC): 8 | @abstractmethod 9 | def __init__(self): 10 | pass 11 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/listed_license.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model.licensing.license import License 9 | 10 | 11 | @dataclass_with_properties 12 | class ListedLicense(License): 13 | list_version_added: Optional[str] = None 14 | deprecated_version: Optional[str] = None 15 | 16 | def __init__( 17 | self, 18 | license_id: str, 19 | license_name: str, 20 | license_text: str, 21 | license_comment: Optional[str] = None, 22 | see_also: List[str] = None, 23 | is_osi_approved: Optional[bool] = None, 24 | is_fsf_libre: Optional[bool] = None, 25 | standard_license_header: Optional[str] = None, 26 | standard_license_template: Optional[str] = None, 27 | is_deprecated_license_id: Optional[bool] = None, 28 | obsoleted_by: Optional[str] = None, 29 | list_version_added: Optional[str] = None, 30 | deprecated_version: Optional[str] = None, 31 | ): 32 | see_also = [] if see_also is None else see_also 33 | check_types_and_set_values(self, locals()) 34 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/listed_license_exception.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model.licensing.license_addition import LicenseAddition 9 | 10 | 11 | @dataclass_with_properties 12 | class ListedLicenseException(LicenseAddition): 13 | list_version_added: Optional[str] = None 14 | deprecated_version: Optional[str] = None 15 | 16 | def __init__( 17 | self, 18 | addition_id: str, 19 | addition_name: str, 20 | addition_text: str, 21 | addition_comment: Optional[str] = None, 22 | see_also: List[str] = None, 23 | standard_addition_template: Optional[str] = None, 24 | is_deprecated_addition_id: Optional[bool] = None, 25 | obsoleted_by: Optional[str] = None, 26 | list_version_added: Optional[str] = None, 27 | deprecated_version: Optional[str] = None, 28 | ): 29 | see_also = [] if see_also is None else see_also 30 | check_types_and_set_values(self, locals()) 31 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/no_assertion_license.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model.licensing.license_field import LicenseField 5 | 6 | 7 | class NoAssertionLicense(LicenseField): 8 | def __init__(self): 9 | pass 10 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/none_license.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model.licensing.license_field import LicenseField 5 | 6 | 7 | class NoneLicense(LicenseField): 8 | def __init__(self): 9 | pass 10 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/or_later_operator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 5 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 6 | from spdx_tools.spdx3.model.licensing.any_license_info import AnyLicenseInfo 7 | from spdx_tools.spdx3.model.licensing.license import License 8 | 9 | 10 | @dataclass_with_properties 11 | class OrLaterOperator(AnyLicenseInfo): 12 | subject_license: License 13 | 14 | def __init__(self, subject_license: License): 15 | check_types_and_set_values(self, locals()) 16 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/licensing/with_addition_operator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 5 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 6 | from spdx_tools.spdx3.model.licensing.any_license_info import AnyLicenseInfo 7 | from spdx_tools.spdx3.model.licensing.license import License 8 | from spdx_tools.spdx3.model.licensing.license_addition import LicenseAddition 9 | 10 | 11 | @dataclass_with_properties 12 | class WithAdditionOperator(AnyLicenseInfo): 13 | subject_license: License 14 | subject_addition: LicenseAddition 15 | 16 | def __init__(self, subject_license: License, subject_addition: LicenseAddition): 17 | check_types_and_set_values(self, locals()) 18 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/namespace_map.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 5 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 6 | 7 | 8 | @dataclass_with_properties 9 | class NamespaceMap: 10 | prefix: str 11 | namespace: str # anyURI 12 | 13 | def __init__(self, prefix: str, namespace: str): 14 | check_types_and_set_values(self, locals()) 15 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/organization.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model import Agent, CreationInfo, ExternalIdentifier, ExternalReference, IntegrityMethod 9 | 10 | 11 | @dataclass_with_properties 12 | class Organization(Agent): 13 | def __init__( 14 | self, 15 | spdx_id: str, 16 | creation_info: Optional[CreationInfo] = None, 17 | name: Optional[str] = None, 18 | summary: Optional[str] = None, 19 | description: Optional[str] = None, 20 | comment: Optional[str] = None, 21 | verified_using: List[IntegrityMethod] = None, 22 | external_reference: List[ExternalReference] = None, 23 | external_identifier: List[ExternalIdentifier] = None, 24 | extension: Optional[str] = None, 25 | ): 26 | verified_using = [] if verified_using is None else verified_using 27 | external_reference = [] if external_reference is None else external_reference 28 | external_identifier = [] if external_identifier is None else external_identifier 29 | check_types_and_set_values(self, locals()) 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/person.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model import Agent, CreationInfo, ExternalIdentifier, ExternalReference, IntegrityMethod 9 | 10 | 11 | @dataclass_with_properties 12 | class Person(Agent): 13 | def __init__( 14 | self, 15 | spdx_id: str, 16 | creation_info: Optional[CreationInfo] = None, 17 | name: Optional[str] = None, 18 | summary: Optional[str] = None, 19 | description: Optional[str] = None, 20 | comment: Optional[str] = None, 21 | verified_using: List[IntegrityMethod] = None, 22 | external_reference: List[ExternalReference] = None, 23 | external_identifier: List[ExternalIdentifier] = None, 24 | extension: Optional[str] = None, 25 | ): 26 | verified_using = [] if verified_using is None else verified_using 27 | external_reference = [] if external_reference is None else external_reference 28 | external_identifier = [] if external_identifier is None else external_identifier 29 | check_types_and_set_values(self, locals()) 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/positive_integer_range.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 5 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 6 | 7 | 8 | @dataclass_with_properties 9 | class PositiveIntegerRange: 10 | begin: int 11 | end: int 12 | 13 | def __init__( 14 | self, 15 | begin: int, 16 | end: int, 17 | ): 18 | check_types_and_set_values(self, locals()) 19 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/profile_identifier.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum, auto 5 | 6 | 7 | class ProfileIdentifierType(Enum): 8 | CORE = auto() 9 | SOFTWARE = auto() 10 | LICENSING = auto() 11 | SECURITY = auto() 12 | BUILD = auto() 13 | AI = auto() 14 | DATASET = auto() 15 | USAGE = auto() 16 | EXTENSION = auto() 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/security/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from .cvss_v2_vuln_assessment_relationship import CvssV2VulnAssessmentRelationship 5 | from .cvss_v3_vuln_assessment_relationship import CvssV3VulnAssessmentRelationship 6 | from .epss_vuln_assessment_relationship import EpssVulnAssessmentRelationship 7 | from .exploit_catalog_vuln_assessment_relationship import ExploitCatalogVulnAssessmentRelationship, ExploitCatalogType 8 | from .ssvc_vuln_assessment_relationship import SsvcVulnAssessmentRelationship, SsvcDecisionType 9 | from .vex_affected_vuln_assessment_relationship import VexAffectedVulnAssessmentRelationship 10 | from .vex_fixed_vuln_assessment_relationship import VexFixedVulnAssessmentRelationship 11 | from .vex_not_affected_vuln_assessment_relationship import ( 12 | VexNotAffectedVulnAssessmentRelationship, 13 | VexJustificationType, 14 | ) 15 | from .vex_under_investigation_vuln_assessment_relationship import VexUnderInvestigationVulnAssessmentRelationship 16 | from .vex_vuln_assessment_relationship import VexVulnAssessmentRelationship 17 | from .vuln_assessment_relationship import VulnAssessmentRelationship 18 | from .vulnerability import Vulnerability 19 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/security/vex_vuln_assessment_relationship.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import abstractmethod 5 | 6 | from beartype.typing import Optional 7 | 8 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 9 | from spdx_tools.spdx3.model.security.vuln_assessment_relationship import VulnAssessmentRelationship 10 | 11 | 12 | @dataclass_with_properties 13 | class VexVulnAssessmentRelationship(VulnAssessmentRelationship): 14 | vex_version: Optional[str] = None 15 | status_notes: Optional[str] = None 16 | 17 | @abstractmethod 18 | def __init__(self): 19 | pass 20 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/security/vuln_assessment_relationship.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import abstractmethod 5 | from datetime import datetime 6 | 7 | from beartype.typing import Optional 8 | 9 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 10 | from spdx_tools.spdx3.model import Relationship 11 | 12 | 13 | @dataclass_with_properties 14 | class VulnAssessmentRelationship(Relationship): 15 | assessed_element: Optional[str] = None # id of the element 16 | published_time: Optional[datetime] = None 17 | supplied_by: Optional[str] = None 18 | modified_time: Optional[datetime] = None 19 | withdrawn_time: Optional[datetime] = None 20 | 21 | @abstractmethod 22 | def __init__(self): 23 | pass 24 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/software/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from spdx_tools.spdx3.model.software.software_purpose import SoftwarePurpose 5 | from spdx_tools.spdx3.model.software.file import File 6 | from spdx_tools.spdx3.model.software.package import Package 7 | from spdx_tools.spdx3.model.software.snippet import Snippet 8 | from spdx_tools.spdx3.model.software.sbom import Sbom, SBOMType 9 | from spdx_tools.spdx3.model.software.software_dependency_relationship import ( 10 | SoftwareDependencyRelationship, 11 | SoftwareDependencyLinkType, 12 | DependencyConditionalityType, 13 | ) 14 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/software/software_artifact.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import abstractmethod 5 | from dataclasses import field 6 | 7 | from beartype.typing import List, Optional 8 | 9 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 10 | from spdx_tools.spdx3.model import Artifact 11 | from spdx_tools.spdx3.model.licensing import LicenseField 12 | from spdx_tools.spdx3.model.software import SoftwarePurpose 13 | 14 | 15 | @dataclass_with_properties 16 | class SoftwareArtifact(Artifact): 17 | content_identifier: Optional[str] = None 18 | primary_purpose: Optional[SoftwarePurpose] = None 19 | additional_purpose: List[SoftwarePurpose] = field(default_factory=list) 20 | concluded_license: Optional[LicenseField] = None 21 | declared_license: Optional[LicenseField] = None 22 | copyright_text: Optional[str] = None 23 | attribution_text: Optional[str] = None 24 | 25 | @abstractmethod 26 | def __init__(self): 27 | pass 28 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/software/software_purpose.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum, auto 5 | 6 | 7 | class SoftwarePurpose(Enum): 8 | APPLICATION = auto() 9 | ARCHIVE = auto() 10 | BOM = auto() 11 | CONFIGURATION = auto() 12 | CONTAINER = auto() 13 | DATA = auto() 14 | DEVICE = auto() 15 | DOCUMENTATION = auto() 16 | EXECUTABLE = auto() 17 | FILE = auto() 18 | FIRMWARE = auto() 19 | FRAMEWORK = auto() 20 | INSTALL = auto() 21 | LIBRARY = auto() 22 | MODEL = auto() 23 | MODULE = auto() 24 | OPERATING_SYSTEM = auto() 25 | OTHER = auto() 26 | PATCH = auto() 27 | REQUIREMENT = auto() 28 | SOURCE = auto() 29 | TEST = auto() 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/software_agent.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model import Agent, CreationInfo, ExternalIdentifier, ExternalReference, IntegrityMethod 9 | 10 | 11 | @dataclass_with_properties 12 | class SoftwareAgent(Agent): 13 | def __init__( 14 | self, 15 | spdx_id: str, 16 | creation_info: Optional[CreationInfo] = None, 17 | name: Optional[str] = None, 18 | summary: Optional[str] = None, 19 | description: Optional[str] = None, 20 | comment: Optional[str] = None, 21 | verified_using: List[IntegrityMethod] = None, 22 | external_reference: List[ExternalReference] = None, 23 | external_identifier: List[ExternalIdentifier] = None, 24 | extension: Optional[str] = None, 25 | ): 26 | verified_using = [] if verified_using is None else verified_using 27 | external_reference = [] if external_reference is None else external_reference 28 | external_identifier = [] if external_identifier is None else external_identifier 29 | check_types_and_set_values(self, locals()) 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/spdx_collection.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from abc import abstractmethod 5 | from dataclasses import field 6 | 7 | from beartype.typing import List 8 | 9 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 10 | from spdx_tools.spdx3.model import Element, ExternalMap, NamespaceMap 11 | 12 | 13 | @dataclass_with_properties 14 | class ElementCollection(Element): 15 | # due to the inheritance we need to make all fields non-default in the __annotation__, 16 | # the __init__ method still raises an error if required fields are not set 17 | element: List[str] = field(default_factory=list) 18 | root_element: List[str] = field(default_factory=list) 19 | namespaces: List[NamespaceMap] = field(default_factory=list) 20 | imports: List[ExternalMap] = field(default_factory=list) 21 | 22 | @abstractmethod 23 | def __init__(self): 24 | pass 25 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/model/tool.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import List, Optional 5 | 6 | from spdx_tools.common.typing.dataclass_with_properties import dataclass_with_properties 7 | from spdx_tools.common.typing.type_checks import check_types_and_set_values 8 | from spdx_tools.spdx3.model import CreationInfo, Element, ExternalIdentifier, ExternalReference, IntegrityMethod 9 | 10 | 11 | @dataclass_with_properties 12 | class Tool(Element): 13 | def __init__( 14 | self, 15 | spdx_id: str, 16 | creation_info: Optional[CreationInfo] = None, 17 | name: Optional[str] = None, 18 | summary: Optional[str] = None, 19 | description: Optional[str] = None, 20 | comment: Optional[str] = None, 21 | verified_using: List[IntegrityMethod] = None, 22 | external_reference: List[ExternalReference] = None, 23 | external_identifier: List[ExternalIdentifier] = None, 24 | extension: Optional[str] = None, 25 | ): 26 | verified_using = [] if verified_using is None else verified_using 27 | external_reference = [] if external_reference is None else external_reference 28 | external_identifier = [] if external_identifier is None else external_identifier 29 | check_types_and_set_values(self, locals()) 30 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/payload.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Dict 5 | 6 | from spdx_tools.spdx3.model import Element 7 | 8 | 9 | class Payload: 10 | _spdx_id_map: Dict[str, Element] 11 | 12 | def __init__(self, spdx_id_map: Dict[str, Element] = None): 13 | self._spdx_id_map = spdx_id_map if spdx_id_map else {} 14 | 15 | def add_element(self, element: Element): 16 | self._spdx_id_map[element.spdx_id] = element 17 | 18 | def get_element(self, spdx_id: str) -> Element: 19 | return self._spdx_id_map[spdx_id] 20 | 21 | def get_full_map(self) -> Dict[str, Element]: 22 | return self._spdx_id_map 23 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/validation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/validation/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/validation/json_ld/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/validation/json_ld/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/validation/json_ld/shacl_validation.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import Optional 5 | from pyshacl import validate 6 | from rdflib import Graph 7 | 8 | 9 | def validate_against_shacl_from_file( 10 | data_file: str, shacl_file: str, data_format: Optional[str] = "json-ld", shacl_format: Optional[str] = "ttl" 11 | ): 12 | data_graph = Graph() 13 | with open(data_file) as file: 14 | data_graph.parse(file, format=data_format) 15 | 16 | shacl_graph = Graph() 17 | with open(shacl_file) as file: 18 | shacl_graph.parse(file, format=shacl_format) 19 | 20 | return validate(data_graph=data_graph, shacl_graph=shacl_graph, ont_graph=shacl_graph) 21 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/writer/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | """This is a temporary package to write the implemented model of spdx_tools.spdx3.0 to console. As soon as 5 | serialization formats are properly defined this package can be deleted.""" 6 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/agent_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import Agent, Organization, Person, SoftwareAgent 7 | from spdx_tools.spdx3.writer.console.element_writer import write_element_properties 8 | 9 | 10 | def write_agent(agent: Agent, text_output: TextIO, heading: bool = True): 11 | if heading: 12 | if isinstance(agent, Person): 13 | text_output.write("## Person\n") 14 | if isinstance(agent, Organization): 15 | text_output.write("## Organization\n") 16 | if isinstance(agent, SoftwareAgent): 17 | text_output.write("## SoftwareAgent\n") 18 | write_element_properties(agent, text_output) 19 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/ai/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/writer/console/ai/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/ai/ai_package_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model.ai import AIPackage 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.software.package_writer import write_package 9 | 10 | 11 | def write_ai_package(ai_package: AIPackage, text_output: TextIO): 12 | text_output.write("## AI Package\n") 13 | write_package(ai_package, text_output, False) 14 | 15 | for property_name in AIPackage.__annotations__.keys(): 16 | write_value(property_name, getattr(ai_package, property_name), text_output) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/annotation_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import Annotation 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.element_writer import write_element_properties 9 | 10 | 11 | def write_annotation(annotation: Annotation, text_output: TextIO): 12 | text_output.write("## Annotation\n") 13 | write_element_properties(annotation, text_output) 14 | 15 | for property_name in Annotation.__annotations__.keys(): 16 | write_value(property_name, getattr(annotation, property_name), text_output) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/artifact_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import Artifact 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.element_writer import write_element_properties 9 | 10 | 11 | def write_artifact_properties(artifact: Artifact, text_output: TextIO): 12 | write_element_properties(artifact, text_output) 13 | 14 | for property_name in Artifact.__annotations__.keys(): 15 | write_value(property_name, getattr(artifact, property_name), text_output) 16 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/bom_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import Bom 7 | from spdx_tools.spdx3.writer.console.bundle_writer import write_bundle 8 | 9 | 10 | def write_bom(bom: Bom, text_output: TextIO, heading: bool = True): 11 | if heading: 12 | text_output.write("## Bom\n") 13 | write_bundle(bom, text_output, False) 14 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/build/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/writer/console/build/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/build/build_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model.build import Build 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.element_writer import write_element_properties 9 | from spdx_tools.spdx3.writer.console.hash_writer import write_hash 10 | from spdx_tools.spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_optional_heading 11 | 12 | 13 | def write_build(build: Build, text_output: TextIO): 14 | text_output.write("## Build\n") 15 | write_element_properties(build, text_output) 16 | 17 | for property_name in Build.__annotations__.keys(): 18 | if property_name == "config_source_digest": 19 | write_optional_heading(build.config_source_digest, "config_source_digest", text_output) 20 | for digest_hash in build.config_source_digest: 21 | write_hash(digest_hash, text_output, heading=False) 22 | continue 23 | 24 | write_value(property_name, getattr(build, property_name), text_output) 25 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/bundle_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import Bundle 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.spdx_collection_writer import write_collection 9 | 10 | 11 | def write_bundle(bundle: Bundle, text_output: TextIO, heading: bool = True): 12 | if heading: 13 | text_output.write("## Bundle\n") 14 | write_collection(bundle, text_output) 15 | write_value("context", bundle.context, text_output) 16 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/console.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from enum import Enum 5 | 6 | from beartype.typing import Optional, TextIO, Union 7 | 8 | 9 | def write_value(tag: str, value: Optional[Union[bool, str, dict, list, Enum]], out: TextIO, indent: bool = False): 10 | """This function is duplicated from spdx_tools.spdx.writer.tagvalue.tag_value_writer_helper_functions 11 | and slightly adapted to make indentation of output possible.""" 12 | if not value: 13 | return 14 | if isinstance(value, dict): 15 | value = ", ".join([f"{tag}: ({key}: {val})" for key, val in value.items()]) 16 | if isinstance(value, list): 17 | value = ", ".join([entry for entry in value]) 18 | if isinstance(value, Enum): 19 | value = value.name 20 | write_and_possibly_indent(f"{tag}: {value}", indent, out) 21 | 22 | 23 | def write_and_possibly_indent(text: str, indent: bool, out: TextIO): 24 | if indent: 25 | out.write(f" {text}\n") 26 | else: 27 | out.write(f"{text}\n") 28 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/creation_info_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import CreationInfo 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx.datetime_conversions import datetime_to_iso_string 9 | 10 | 11 | def write_creation_info(creation_info: CreationInfo, text_output: TextIO, indent: bool = True): 12 | text_output.write("# Creation Information\n") 13 | write_value("specVersion", str(creation_info.spec_version), text_output, indent) 14 | write_value("created", datetime_to_iso_string(creation_info.created), text_output, indent) 15 | for created_by in creation_info.created_by: 16 | write_value("created by", created_by, text_output, indent) 17 | for created_using in creation_info.created_using: 18 | write_value("created using", created_using, text_output, indent) 19 | write_value("profile", [profile.name for profile in creation_info.profile], text_output, indent) 20 | write_value("data license", creation_info.data_license, text_output, indent) 21 | write_value("comment", creation_info.comment, text_output, indent) 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/dataset/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/writer/console/dataset/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/dataset/dataset_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model.dataset import Dataset 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.software.package_writer import write_package 9 | 10 | 11 | def write_dataset(dataset: Dataset, text_output: TextIO): 12 | text_output.write("## Dataset\n") 13 | write_package(dataset, text_output, False) 14 | 15 | for property_name in Dataset.__annotations__.keys(): 16 | write_value(property_name, getattr(dataset, property_name), text_output) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/external_identifier_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import ExternalIdentifier 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | 9 | 10 | def write_external_identifier(external_identifier: ExternalIdentifier, text_output: TextIO): 11 | for property_name in ExternalIdentifier.__annotations__.keys(): 12 | write_value(property_name, getattr(external_identifier, property_name), text_output) 13 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/external_map_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import ExternalMap 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.hash_writer import write_hash 9 | from spdx_tools.spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_optional_heading 10 | 11 | 12 | def write_external_map(external_map: ExternalMap, text_output: TextIO): 13 | write_value("external_id", external_map.external_id, text_output) 14 | write_optional_heading(external_map.verified_using, "verified using\n", text_output) 15 | for integrity_method in external_map.verified_using: 16 | # for now Hash is the only child class of the abstract class IntegrityMethod, 17 | # as soon as there are more inherited classes we need to implement a logic 18 | # that determines the correct write function for the "integrity_method" object 19 | write_hash(integrity_method, text_output, heading=False) 20 | write_value("location_hint", external_map.location_hint, text_output) 21 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/external_reference_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import ExternalReference 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | 9 | 10 | def write_external_reference(external_reference: ExternalReference, text_output: TextIO): 11 | for property_name in ExternalReference.__annotations__.keys(): 12 | write_value(property_name, getattr(external_reference, property_name), text_output) 13 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/hash_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import Hash 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.integrity_method_writer import write_integrity_method 9 | 10 | 11 | def write_hash(hash_object: Hash, text_output: TextIO, heading: bool, indent: bool = True): 12 | if heading: 13 | text_output.write("## Hash\n") 14 | write_value("algorithm", hash_object.algorithm, text_output, indent) 15 | write_value("hash_value", hash_object.hash_value, text_output, indent) 16 | write_integrity_method(hash_object, text_output, indent) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/integrity_method_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import IntegrityMethod 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | 9 | 10 | def write_integrity_method(integrity_method: IntegrityMethod, text_output: TextIO, indent: bool = True): 11 | write_value("comment", integrity_method.comment, text_output, indent) 12 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/lifecycle_scoped_relationship_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from beartype.typing import TextIO 6 | 7 | from spdx_tools.spdx3.model import LifecycleScopedRelationship 8 | from spdx_tools.spdx3.writer.console.console import write_value 9 | from spdx_tools.spdx3.writer.console.relationship_writer import write_relationship 10 | 11 | 12 | def write_lifecycle_scoped_relationship( 13 | relationship: LifecycleScopedRelationship, text_output: TextIO, heading: bool = True 14 | ): 15 | if heading: 16 | text_output.write("## LifecycleScopedRelationship\n") 17 | write_relationship(relationship, text_output, heading=False) 18 | 19 | for property_name in LifecycleScopedRelationship.__annotations__.keys(): 20 | write_value(property_name, getattr(relationship, property_name), text_output) 21 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/namespace_map_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import NamespaceMap 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | 9 | 10 | def write_namespace_map(namespace_map: NamespaceMap, text_output: TextIO): 11 | for property_name in NamespaceMap.__annotations__.keys(): 12 | write_value(property_name, getattr(namespace_map, property_name), text_output) 13 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/relationship_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import Relationship 7 | from spdx_tools.spdx3.writer.console.console import write_value 8 | from spdx_tools.spdx3.writer.console.element_writer import write_element_properties 9 | 10 | 11 | def write_relationship(relationship: Relationship, text_output: TextIO, heading: bool = True): 12 | if heading: 13 | text_output.write("## Relationship\n") 14 | write_element_properties(relationship, text_output) 15 | for property_name in relationship.__annotations__.keys(): 16 | write_value(property_name, getattr(relationship, property_name), text_output) 17 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/software/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/writer/console/software/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/software/file_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model.software import File 7 | from spdx_tools.spdx3.writer.console.artifact_writer import write_artifact_properties 8 | from spdx_tools.spdx3.writer.console.console import write_value 9 | 10 | 11 | def write_file(file: File, text_output: TextIO): 12 | text_output.write("## File\n") 13 | write_artifact_properties(file, text_output) 14 | 15 | for property_name in File.__annotations__.keys(): 16 | if property_name == "file_purpose": 17 | write_value( 18 | property_name, ", ".join([purpose.name for purpose in getattr(file, property_name)]), text_output 19 | ) 20 | continue 21 | write_value(property_name, getattr(file, property_name), text_output) 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/software/package_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model.software import Package 7 | from spdx_tools.spdx3.writer.console.artifact_writer import write_artifact_properties 8 | from spdx_tools.spdx3.writer.console.console import write_value 9 | 10 | 11 | def write_package(package: Package, text_output: TextIO, heading: bool = True): 12 | if heading: 13 | text_output.write("## Package\n") 14 | write_artifact_properties(package, text_output) 15 | 16 | for property_name in Package.__annotations__.keys(): 17 | if property_name == "package_purpose": 18 | write_value( 19 | property_name, ", ".join([purpose.name for purpose in getattr(package, property_name)]), text_output 20 | ) 21 | continue 22 | write_value(property_name, getattr(package, property_name), text_output) 23 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/software/sbom_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model.software import Sbom 7 | from spdx_tools.spdx3.writer.console.bom_writer import write_bom 8 | 9 | 10 | def write_sbom(sbom: Sbom, text_output: TextIO): 11 | text_output.write("## Sbom\n") 12 | write_bom(sbom, text_output, False) 13 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/software/snippet_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model.software import Snippet 7 | from spdx_tools.spdx3.writer.console.artifact_writer import write_artifact_properties 8 | from spdx_tools.spdx3.writer.console.console import write_value 9 | 10 | 11 | def write_snippet(snippet: Snippet, text_output: TextIO): 12 | text_output.write("## Snippet\n") 13 | write_artifact_properties(snippet, text_output) 14 | 15 | for property_name in Snippet.__annotations__.keys(): 16 | if property_name == "snippet_purpose": 17 | write_value( 18 | property_name, ", ".join([purpose.name for purpose in getattr(snippet, property_name)]), text_output 19 | ) 20 | continue 21 | write_value(property_name, getattr(snippet, property_name), text_output) 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/software/software_dependency_relationship_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from beartype.typing import TextIO 6 | 7 | from spdx_tools.spdx3.model.software import SoftwareDependencyRelationship 8 | from spdx_tools.spdx3.writer.console.console import write_value 9 | from spdx_tools.spdx3.writer.console.lifecycle_scoped_relationship_writer import write_lifecycle_scoped_relationship 10 | 11 | 12 | def write_software_dependency_relationship( 13 | relationship: SoftwareDependencyRelationship, text_output: TextIO, heading: bool = True 14 | ): 15 | if heading: 16 | text_output.write("## SoftwareDependencyRelationship\n") 17 | write_lifecycle_scoped_relationship(relationship, text_output, heading=False) 18 | 19 | for property_name in SoftwareDependencyRelationship.__annotations__.keys(): 20 | write_value(property_name, getattr(relationship, property_name), text_output) 21 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/spdx_collection_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import ElementCollection 7 | from spdx_tools.spdx3.writer.console.element_writer import write_element_properties 8 | from spdx_tools.spdx3.writer.console.external_map_writer import write_external_map 9 | from spdx_tools.spdx3.writer.console.namespace_map_writer import write_namespace_map 10 | from spdx_tools.spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_optional_heading 11 | 12 | 13 | def write_collection(collection: ElementCollection, text_output: TextIO): 14 | write_element_properties(collection, text_output) 15 | text_output.write(f"elements: {', '.join(collection.element)}\n") 16 | write_optional_heading(collection.namespaces, "# Namespaces\n", text_output) 17 | for namespace_map in collection.namespaces: 18 | write_namespace_map(namespace_map, text_output) 19 | write_optional_heading(collection.imports, "# Imports\n", text_output) 20 | for external_map in collection.imports: 21 | write_external_map(external_map, text_output) 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/spdx_document_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from beartype.typing import TextIO 5 | 6 | from spdx_tools.spdx3.model import SpdxDocument 7 | from spdx_tools.spdx3.writer.console.bundle_writer import write_bundle 8 | 9 | 10 | def write_spdx_document(spdx_document: SpdxDocument, text_output: TextIO): 11 | text_output.write("## SPDX Document\n") 12 | write_bundle(spdx_document, text_output, False) 13 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/console/tool_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright (c) 2023 spdx contributors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | from beartype.typing import TextIO 13 | 14 | from spdx_tools.spdx3.model import Tool 15 | from spdx_tools.spdx3.writer.console.element_writer import write_element_properties 16 | 17 | 18 | def write_tool(tool: Tool, text_output: TextIO, heading: bool = True): 19 | if heading: 20 | text_output.write("## Tool\n") 21 | write_element_properties(tool, text_output) 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/json_ld/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/src/spdx_tools/spdx3/writer/json_ld/__init__.py -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/json_ld/json_ld_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import json 5 | import os 6 | 7 | from spdx_tools.spdx3.payload import Payload 8 | from spdx_tools.spdx3.writer.json_ld.json_ld_converter import convert_payload_to_json_ld_list_of_elements 9 | 10 | 11 | def write_payload(payload: Payload, file_name: str): 12 | element_list = convert_payload_to_json_ld_list_of_elements(payload) 13 | 14 | # this will be obsolete as soon as the context is publicly available under some URI 15 | with open(os.path.join(os.path.dirname(__file__), "context.json"), "r") as infile: 16 | context = json.load(infile) 17 | 18 | complete_dict = {"@context": context, "@graph": element_list} 19 | 20 | with open(file_name + ".jsonld", "w") as out: 21 | json.dump(complete_dict, out, indent=2) 22 | -------------------------------------------------------------------------------- /src/spdx_tools/spdx3/writer/json_ld/process.md: -------------------------------------------------------------------------------- 1 | ### Workflow 2 | 3 | Process to produce context file and a serialization example: 4 | 5 | 1. Run 6 | ``` 7 | spec-parser --gen-md --gen-refs --gen-rdf ../spdx-3-model/model 8 | ``` 9 | - spdx-3-model (commit: 6cb4316, last commit where spec-parser is able to run)
10 | - spec-parser (main with commits from PR 44, 45) 11 | 12 | 2. Convert the generated `spec-parser/md_generated/model.ttl` to a json-ld file using https://frogcat.github.io/ttl2jsonld/demo/. 13 | 3. Convert owl to context using `convert_spdx_owl_to_jsonld_context("SPDX_OWL.json")`. 14 | 4. Place the generated `context.json` in `spdx_tools/spdx3/writer/jsonld/`. 15 | 5. To generate the jsonld from the testfile run 16 | ``` 17 | pyspdxtools3 -i ./tests/spdx/data/SPDXJSONExample-v2.3.spdx.json -o example_with_context 18 | ``` 19 | 20 | 21 | ### Manually 22 | 23 | 24 | ### Known limitations 25 | - Validation of enums does not work 26 | - Additional keys seem to be ignored in validation 27 | - inherited properties aren't validated 28 | -------------------------------------------------------------------------------- /stdeb.cfg: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | Depends = python-rdflib (>= 4.1.2), python-ply (>= 3.4) 3 | Copyright-File = LICENSE 4 | 5 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/__init__.py -------------------------------------------------------------------------------- /tests/spdx/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/__init__.py -------------------------------------------------------------------------------- /tests/spdx/data/SPDXJSONExample-UTF-16.spdx.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/data/SPDXJSONExample-UTF-16.spdx.json -------------------------------------------------------------------------------- /tests/spdx/data/SPDXLite.spdx: -------------------------------------------------------------------------------- 1 | # from https://github.com/OpenChain-Project/OpenChain-JWG/blob/4675d7a61ad552e8f9780419c54dddbdf87f6018/subgroups/sbom-sg/outcomes/SPDX-Lite/sample/SPDX-tools-spdxlite.txt 2 | ## 2 Document Creation Information 3 | 4 | SPDXVersion: SPDX-2.2 5 | DataLicense: CC0-1.0 6 | SPDXID: SPDXRef-DOCUMENT 7 | DocumentName: example-v1.0 8 | DocumentNamespace: https://example.com/example-v1.0 9 | Creator: Person: someone 10 | Created: 2021-04-05T01:23:45Z 11 | 12 | ## 3 Package Information 13 | 14 | PackageName: SPDX tools 15 | SPDXID: SPDXRef-spdxtools 16 | PackageVersion: 2.0.3 17 | PackageFileName: spdx-tools-2.0.2-jar-with-dependencies.jar 18 | PackageDownloadLocation: NONE 19 | FilesAnalyzed: false 20 | PackageHomePage: https://spdx.org/tools 21 | PackageLicenseConcluded: Apache-2.0 22 | PackageLicenseDeclared: Apache-2.0 23 | PackageLicenseComments: 24 | PackageCopyrightText: software copyright (c) 2000-2003, BEA Systems, 25 | PackageComment: 26 | ModificationRecord: NO 27 | CompileOptions: --some-option 28 | LinkMethodology: Dynamic 29 | 30 | 31 | ## 6 Other Licensing Information Detected 32 | 33 | LicenseID: LicenseRef-1 34 | ExtractedText: hoge 35 | LicenseName: NOASSERTION 36 | LicenseComment: 37 | -------------------------------------------------------------------------------- /tests/spdx/data/SPDXRdfExample-UTF-16.spdx.rdf.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/data/SPDXRdfExample-UTF-16.spdx.rdf.xml -------------------------------------------------------------------------------- /tests/spdx/data/SPDXTagExample-UTF-16.spdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/data/SPDXTagExample-UTF-16.spdx -------------------------------------------------------------------------------- /tests/spdx/data/SPDXXMLExample-UTF-16.spdx.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/data/SPDXXMLExample-UTF-16.spdx.xml -------------------------------------------------------------------------------- /tests/spdx/data/SPDXYAMLExample-UTF-16.spdx.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/data/SPDXYAMLExample-UTF-16.spdx.yaml -------------------------------------------------------------------------------- /tests/spdx/examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/examples/__init__.py -------------------------------------------------------------------------------- /tests/spdx/jsonschema/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/jsonschema/__init__.py -------------------------------------------------------------------------------- /tests/spdx/jsonschema/test_checksum_converter.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx.jsonschema.checksum_converter import ChecksumConverter 7 | from spdx_tools.spdx.jsonschema.checksum_properties import ChecksumProperty 8 | from spdx_tools.spdx.model import Checksum, ChecksumAlgorithm 9 | 10 | 11 | @pytest.fixture 12 | def converter() -> ChecksumConverter: 13 | return ChecksumConverter() 14 | 15 | 16 | @pytest.mark.parametrize( 17 | "checksum_property,expected", 18 | [(ChecksumProperty.ALGORITHM, "algorithm"), (ChecksumProperty.CHECKSUM_VALUE, "checksumValue")], 19 | ) 20 | def test_json_property_names(converter: ChecksumConverter, checksum_property: ChecksumProperty, expected: str): 21 | assert converter.json_property_name(checksum_property) == expected 22 | 23 | 24 | def test_successful_conversion(converter: ChecksumConverter): 25 | checksum = Checksum(ChecksumAlgorithm.SHA1, "123") 26 | 27 | converted_dict = converter.convert(checksum) 28 | 29 | assert converted_dict == { 30 | converter.json_property_name(ChecksumProperty.ALGORITHM): "SHA1", 31 | converter.json_property_name(ChecksumProperty.CHECKSUM_VALUE): "123", 32 | } 33 | 34 | 35 | def test_json_type(converter: ChecksumConverter): 36 | assert converter.get_json_type() == ChecksumProperty 37 | 38 | 39 | def test_data_model_type(converter: ChecksumConverter): 40 | assert converter.get_data_model_type() == Checksum 41 | -------------------------------------------------------------------------------- /tests/spdx/mock_utils.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from unittest.mock import NonCallableMagicMock 5 | 6 | 7 | def assert_mock_method_called_with_arguments(mock_object: NonCallableMagicMock, method_name: str, *args): 8 | assert len(mock_object.method_calls) == len(args) 9 | for running_index in range(len(args)): 10 | call = mock_object.method_calls[running_index] 11 | assert call[0] == method_name 12 | assert call[1][0] == args[running_index] 13 | 14 | 15 | def assert_no_mock_methods_called(mock_object: NonCallableMagicMock): 16 | assert len(mock_object.method_calls) == 0 17 | -------------------------------------------------------------------------------- /tests/spdx/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/model/__init__.py -------------------------------------------------------------------------------- /tests/spdx/model/test_checksum.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import pytest 6 | 7 | from spdx_tools.spdx.model import Checksum, ChecksumAlgorithm 8 | 9 | 10 | def test_correct_initialization(): 11 | checksum = Checksum(ChecksumAlgorithm.BLAKE2B_256, "value") 12 | assert checksum.algorithm == ChecksumAlgorithm.BLAKE2B_256 13 | assert checksum.value == "value" 14 | 15 | 16 | def test_wrong_type_in_algorithm(): 17 | with pytest.raises(TypeError): 18 | Checksum(42, "value") 19 | 20 | 21 | def test_wrong_type_in_value(): 22 | with pytest.raises(TypeError): 23 | Checksum(ChecksumAlgorithm.BLAKE2B_256, 42) 24 | -------------------------------------------------------------------------------- /tests/spdx/model/test_external_document_ref.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from unittest import mock 6 | 7 | import pytest 8 | 9 | from spdx_tools.spdx.model import ExternalDocumentRef 10 | 11 | 12 | @mock.patch("spdx_tools.spdx.model.Checksum", autospec=True) 13 | def test_correct_initialization(checksum): 14 | external_document_ref = ExternalDocumentRef("id", "uri", checksum) 15 | assert external_document_ref.document_ref_id == "id" 16 | assert external_document_ref.document_uri == "uri" 17 | assert external_document_ref.checksum == checksum 18 | 19 | 20 | @mock.patch("spdx_tools.spdx.model.Checksum", autospec=True) 21 | def test_wrong_type_in_spdx_id(checksum): 22 | with pytest.raises(TypeError): 23 | ExternalDocumentRef(42, "uri", checksum) 24 | 25 | 26 | @mock.patch("spdx_tools.spdx.model.Checksum", autospec=True) 27 | def test_wrong_type_in_document_uri(checksum): 28 | with pytest.raises(TypeError): 29 | ExternalDocumentRef("id", 42, checksum) 30 | 31 | 32 | def test_wrong_type_in_checksum(): 33 | with pytest.raises(TypeError): 34 | ExternalDocumentRef("id", "uri", 42) 35 | -------------------------------------------------------------------------------- /tests/spdx/model/test_external_package_reference.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import pytest 6 | 7 | from spdx_tools.spdx.model import ExternalPackageRef, ExternalPackageRefCategory 8 | 9 | 10 | def test_correct_initialization(): 11 | external_package_reference = ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", "locator", "comment") 12 | assert external_package_reference.category == ExternalPackageRefCategory.OTHER 13 | assert external_package_reference.reference_type == "type" 14 | assert external_package_reference.locator == "locator" 15 | assert external_package_reference.comment == "comment" 16 | 17 | 18 | def test_wrong_type_in_category(): 19 | with pytest.raises(TypeError): 20 | ExternalPackageRef([ExternalPackageRefCategory.OTHER], "type", "locator") 21 | 22 | 23 | def test_wrong_type_in_reference_type(): 24 | with pytest.raises(TypeError): 25 | ExternalPackageRef(ExternalPackageRefCategory.OTHER, 42, "locator") 26 | 27 | 28 | def test_wrong_type_in_locator(): 29 | with pytest.raises(TypeError): 30 | ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", 42) 31 | 32 | 33 | def test_wrong_type_in_comment(): 34 | with pytest.raises(TypeError): 35 | ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", "locator", []) 36 | -------------------------------------------------------------------------------- /tests/spdx/model/test_extracted_licensing_info.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import pytest 6 | 7 | from spdx_tools.spdx.model import ExtractedLicensingInfo 8 | 9 | 10 | def test_correct_initialization(): 11 | extracted_licensing_info = ExtractedLicensingInfo("id", "text", "name", ["reference"], "comment") 12 | assert extracted_licensing_info.license_id == "id" 13 | assert extracted_licensing_info.extracted_text == "text" 14 | assert extracted_licensing_info.license_name == "name" 15 | assert extracted_licensing_info.cross_references == ["reference"] 16 | assert extracted_licensing_info.comment == "comment" 17 | 18 | 19 | def test_wrong_type_in_license_id(): 20 | with pytest.raises(TypeError): 21 | ExtractedLicensingInfo(license_id=42) 22 | 23 | 24 | def test_wrong_type_in_extracted_text(): 25 | with pytest.raises(TypeError): 26 | ExtractedLicensingInfo(extracted_text=42) 27 | 28 | 29 | def test_wrong_type_in_license_name(): 30 | with pytest.raises(TypeError): 31 | ExtractedLicensingInfo(license_name=42) 32 | 33 | 34 | def test_wrong_type_in_cross_references(): 35 | with pytest.raises(TypeError): 36 | ExtractedLicensingInfo(cross_references=[41, 42]) 37 | 38 | 39 | def test_wrong_type_in_comment(): 40 | with pytest.raises(TypeError): 41 | ExtractedLicensingInfo(comment=42) 42 | -------------------------------------------------------------------------------- /tests/spdx/model/test_package_verification_code.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import pytest 6 | 7 | from spdx_tools.spdx.model import PackageVerificationCode 8 | 9 | 10 | def test_correct_initialization(): 11 | package_verification_code = PackageVerificationCode("value", ["file1", "file2"]) 12 | assert package_verification_code.value == "value" 13 | assert package_verification_code.excluded_files == ["file1", "file2"] 14 | 15 | 16 | def test_wrong_type_in_value(): 17 | with pytest.raises(TypeError): 18 | PackageVerificationCode(42, ["file1", "file2"]) 19 | 20 | 21 | def test_wrong_type_in_excluded_files(): 22 | with pytest.raises(TypeError): 23 | PackageVerificationCode("value", "file1") 24 | -------------------------------------------------------------------------------- /tests/spdx/model/test_relationship.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import pytest 6 | 7 | from spdx_tools.spdx.model import Relationship, RelationshipType, SpdxNoAssertion 8 | 9 | 10 | def test_correct_initialization(): 11 | relationship = Relationship("id", RelationshipType.OTHER, SpdxNoAssertion(), "comment") 12 | assert relationship.spdx_element_id == "id" 13 | assert relationship.relationship_type == RelationshipType.OTHER 14 | assert relationship.related_spdx_element_id == SpdxNoAssertion() 15 | assert relationship.comment == "comment" 16 | 17 | 18 | def test_wrong_type_in_spdx_element_id(): 19 | with pytest.raises(TypeError): 20 | Relationship(SpdxNoAssertion(), RelationshipType.OTHER, "other_id") 21 | 22 | 23 | def test_wrong_type_in_relationship_type(): 24 | with pytest.raises(TypeError): 25 | Relationship("id", 42, "other_id") 26 | 27 | 28 | def test_wrong_type_in_related_spdx_element_id(): 29 | with pytest.raises(TypeError): 30 | Relationship("id", RelationshipType.OTHER, 42) 31 | 32 | 33 | def test_wrong_type_in_comment(): 34 | with pytest.raises(TypeError): 35 | Relationship("id", RelationshipType.OTHER, "other_id", 42) 36 | -------------------------------------------------------------------------------- /tests/spdx/model/test_version.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import pytest 6 | 7 | from spdx_tools.spdx.model import Version 8 | 9 | 10 | @pytest.mark.parametrize("input_string,expected", [("1.2", Version(1, 2)), ("12.345", Version(12, 345))]) 11 | def test_version_from_string(input_string, expected): 12 | assert Version.is_valid_version_string(input_string) 13 | version: Version = Version.from_string(input_string) 14 | assert version == expected 15 | 16 | 17 | @pytest.mark.parametrize("input_string", ["1", "1-2", "1.a", "a", "a.b", "a.1", "v1.2", "1.2v"]) 18 | def test_invalid_version_string(input_string): 19 | assert not Version.is_valid_version_string(input_string) 20 | with pytest.raises(ValueError) as error: 21 | Version.from_string(input_string) 22 | assert str(error.value) == f"{input_string} is not a valid version string" 23 | -------------------------------------------------------------------------------- /tests/spdx/parser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/parser/__init__.py -------------------------------------------------------------------------------- /tests/spdx/parser/all_formats/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/parser/all_formats/__init__.py -------------------------------------------------------------------------------- /tests/spdx/parser/jsonlikedict/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/parser/jsonlikedict/__init__.py -------------------------------------------------------------------------------- /tests/spdx/parser/jsonlikedict/test_checksum_parser.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from unittest import TestCase 5 | 6 | import pytest 7 | 8 | from spdx_tools.spdx.model import ChecksumAlgorithm 9 | from spdx_tools.spdx.parser.error import SPDXParsingError 10 | from spdx_tools.spdx.parser.jsonlikedict.checksum_parser import ChecksumParser 11 | 12 | 13 | def test_parse_checksum(): 14 | checksum_parser = ChecksumParser() 15 | checksum_dict = {"algorithm": "SHA1", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759"} 16 | 17 | checksum = checksum_parser.parse_checksum(checksum_dict) 18 | 19 | assert checksum.value == "d6a770ba38583ed4bb4525bd96e50461655d2759" 20 | assert checksum.algorithm == ChecksumAlgorithm.SHA1 21 | 22 | 23 | def test_parse_invalid_checksum(): 24 | checksum_parser = ChecksumParser() 25 | checksum_dict = {"algorithm": "SHA", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759"} 26 | 27 | with pytest.raises(SPDXParsingError) as err: 28 | checksum_parser.parse_checksum(checksum_dict) 29 | 30 | TestCase().assertCountEqual( 31 | err.value.get_messages(), ["Error while parsing Checksum: ['Invalid ChecksumAlgorithm: SHA']"] 32 | ) 33 | 34 | 35 | def test_parse_incomplete_checksum(): 36 | checksum_parser = ChecksumParser() 37 | checksum_dict = {"algorithm": "SHA1"} 38 | 39 | with pytest.raises(SPDXParsingError): 40 | checksum_parser.parse_checksum(checksum_dict) 41 | -------------------------------------------------------------------------------- /tests/spdx/parser/rdf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/parser/rdf/__init__.py -------------------------------------------------------------------------------- /tests/spdx/parser/rdf/data/invalid_documents/invalid_creation_info.rdf.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | documentComment 9 | documentName 10 | 11 | 12 | 13 | 3.19 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/spdx/parser/rdf/test_annotation_parser.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import os 5 | from datetime import datetime 6 | 7 | from rdflib import BNode, Graph, URIRef 8 | 9 | from spdx_tools.spdx.model import Actor, ActorType, AnnotationType 10 | from spdx_tools.spdx.parser.rdf.annotation_parser import parse_annotation 11 | from spdx_tools.spdx.rdfschema.namespace import SPDX_NAMESPACE 12 | 13 | 14 | def test_parse_annotation(): 15 | graph = Graph().parse(os.path.join(os.path.dirname(__file__), "data/file_to_test_rdf_parser.rdf.xml")) 16 | doc_namespace = "https://some.namespace" 17 | file_node = URIRef(f"{doc_namespace}#SPDXRef-File") 18 | annotation_node = graph.value(subject=file_node, predicate=SPDX_NAMESPACE.annotation) 19 | assert isinstance(annotation_node, BNode) 20 | 21 | annotation = parse_annotation(annotation_node, graph, file_node, doc_namespace) 22 | 23 | assert annotation.spdx_id == "SPDXRef-File" 24 | assert annotation.annotation_type == AnnotationType.REVIEW 25 | assert annotation.annotator == Actor(ActorType.PERSON, "annotatorName", "some@mail.com") 26 | assert annotation.annotation_date == datetime(2022, 12, 1, 0, 0) 27 | assert annotation.annotation_comment == "annotationComment" 28 | -------------------------------------------------------------------------------- /tests/spdx/parser/rdf/test_graph_parsing_function.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | from rdflib import Graph, Namespace, URIRef 6 | 7 | from spdx_tools.spdx.parser.rdf.graph_parsing_functions import parse_spdx_id, remove_prefix 8 | 9 | 10 | @pytest.mark.parametrize( 11 | "resource,doc_namespace,ext_namespace_mapping,expected", 12 | [ 13 | (URIRef("docNamespace#SPDXRef-Test"), "docNamespace", ("", Namespace("")), "SPDXRef-Test"), 14 | (URIRef("docNamespaceSPDXRef-Test"), "docNamespace", ("", Namespace("")), "docNamespaceSPDXRef-Test"), 15 | ( 16 | URIRef("differentNamespace#SPDXRef-Test"), 17 | "docNamespace", 18 | ("extDoc", Namespace("differentNamespace#")), 19 | "extDoc:SPDXRef-Test", 20 | ), 21 | (None, "", ("", Namespace("")), None), 22 | ], 23 | ) 24 | def test_parse_spdx_id(resource, doc_namespace, ext_namespace_mapping, expected): 25 | graph = Graph() 26 | graph.bind(*ext_namespace_mapping) 27 | spdx_id = parse_spdx_id(resource, doc_namespace, graph) 28 | 29 | assert spdx_id == expected 30 | 31 | 32 | @pytest.mark.parametrize( 33 | "string,prefix,expected", [("prefixString", "prefix", "String"), ("prefixString", "refix", "prefixString")] 34 | ) 35 | def test_remove_prefix(string, prefix, expected): 36 | shorten_string = remove_prefix(string, prefix) 37 | 38 | assert expected == shorten_string 39 | -------------------------------------------------------------------------------- /tests/spdx/parser/tagvalue/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/parser/tagvalue/__init__.py -------------------------------------------------------------------------------- /tests/spdx/test_casing_tools.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx.casing_tools import camel_case_to_snake_case, snake_case_to_camel_case 7 | 8 | 9 | @pytest.mark.parametrize("snake_case_str,camel_case_str", [("snake_case", "snakeCase")]) 10 | def test_snake_case_to_camel_case(snake_case_str, camel_case_str): 11 | camel_case = snake_case_to_camel_case(snake_case_str) 12 | 13 | assert camel_case == camel_case_str 14 | 15 | 16 | @pytest.mark.parametrize( 17 | "camel_case_str,snake_case_str", 18 | [("camelCase", "camel_case"), ("camelCaseMore", "camel_case_more"), ("CamelCase", "camel_case")], 19 | ) 20 | def test_camel_case_to_snake_case(camel_case_str, snake_case_str): 21 | snake_case = camel_case_to_snake_case(camel_case_str) 22 | 23 | assert snake_case == snake_case_str 24 | -------------------------------------------------------------------------------- /tests/spdx/validation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/validation/__init__.py -------------------------------------------------------------------------------- /tests/spdx/validation/test_actor_validator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from typing import List 6 | 7 | import pytest 8 | 9 | from spdx_tools.spdx.constants import DOCUMENT_SPDX_ID 10 | from spdx_tools.spdx.model import ActorType 11 | from spdx_tools.spdx.validation.actor_validator import validate_actor 12 | from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage 13 | from tests.spdx.fixtures import actor_fixture 14 | 15 | 16 | def test_valid_actor_person(): 17 | actor = actor_fixture() 18 | validation_messages: List[ValidationMessage] = validate_actor(actor, DOCUMENT_SPDX_ID) 19 | 20 | assert validation_messages == [] 21 | 22 | 23 | @pytest.mark.parametrize( 24 | "actor, expected_message", 25 | [ 26 | ( 27 | actor_fixture(actor_type=ActorType.TOOL, email="mail@mail.com"), 28 | "email must be None if actor_type is TOOL, but is: mail@mail.com", 29 | ), 30 | ], 31 | ) 32 | def test_invalid_actor(actor, expected_message): 33 | parent_id = DOCUMENT_SPDX_ID 34 | validation_messages: List[ValidationMessage] = validate_actor(actor, parent_id) 35 | 36 | expected = ValidationMessage( 37 | expected_message, 38 | ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR, full_element=actor), 39 | ) 40 | 41 | assert validation_messages == [expected] 42 | -------------------------------------------------------------------------------- /tests/spdx/validation/test_annotation_validator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from typing import List 6 | 7 | import pytest 8 | 9 | from spdx_tools.spdx.model import Annotation, Document 10 | from spdx_tools.spdx.validation.annotation_validator import validate_annotation 11 | from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage 12 | from tests.spdx.fixtures import annotation_fixture, document_fixture, file_fixture 13 | 14 | 15 | def test_valid_annotation(): 16 | validation_messages: List[ValidationMessage] = validate_annotation(annotation_fixture(), document_fixture()) 17 | 18 | assert validation_messages == [] 19 | 20 | 21 | @pytest.mark.parametrize( 22 | "annotation_id, file_id, expected_message", 23 | [ 24 | ( 25 | "SPDXRef-File", 26 | "SPDXRef-hiddenFile", 27 | 'did not find the referenced spdx_id "SPDXRef-File" in the SPDX document', 28 | ) 29 | ], 30 | ) 31 | def test_invalid_annotation(annotation_id, file_id, expected_message): 32 | annotation: Annotation = annotation_fixture(spdx_id=annotation_id) 33 | document: Document = document_fixture(files=[file_fixture(spdx_id=file_id)]) 34 | validation_messages: List[ValidationMessage] = validate_annotation(annotation, document) 35 | 36 | expected = ValidationMessage( 37 | expected_message, ValidationContext(element_type=SpdxElementType.ANNOTATION, full_element=annotation) 38 | ) 39 | 40 | assert validation_messages == [expected] 41 | -------------------------------------------------------------------------------- /tests/spdx/validation/test_external_document_ref_validator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from typing import List 6 | 7 | from spdx_tools.spdx.validation.external_document_ref_validator import validate_external_document_ref 8 | from spdx_tools.spdx.validation.validation_message import ValidationMessage 9 | from tests.spdx.fixtures import external_document_ref_fixture 10 | 11 | 12 | def test_valid_external_document_ref(): 13 | external_document_ref = external_document_ref_fixture() 14 | validation_messages: List[ValidationMessage] = validate_external_document_ref( 15 | external_document_ref, "parent_id", "SPDX-2.3" 16 | ) 17 | 18 | assert validation_messages == [] 19 | -------------------------------------------------------------------------------- /tests/spdx/writer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/writer/__init__.py -------------------------------------------------------------------------------- /tests/spdx/writer/json/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/writer/json/__init__.py -------------------------------------------------------------------------------- /tests/spdx/writer/json/expected_results/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/writer/json/expected_results/__init__.py -------------------------------------------------------------------------------- /tests/spdx/writer/rdf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/writer/rdf/__init__.py -------------------------------------------------------------------------------- /tests/spdx/writer/rdf/test_annotation_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from rdflib import RDF, RDFS, Graph, Literal, URIRef 5 | 6 | from spdx_tools.spdx.datetime_conversions import datetime_to_iso_string 7 | from spdx_tools.spdx.rdfschema.namespace import SPDX_NAMESPACE 8 | from spdx_tools.spdx.writer.rdf.annotation_writer import add_annotation_to_graph 9 | from tests.spdx.fixtures import annotation_fixture 10 | 11 | 12 | def test_add_annotation_to_graph(): 13 | graph = Graph() 14 | annotation = annotation_fixture() 15 | 16 | add_annotation_to_graph(annotation, graph, "docNamespace", {}) 17 | 18 | assert (URIRef("docNamespace#SPDXRef-File"), SPDX_NAMESPACE.annotation, None) in graph 19 | assert (None, RDF.type, SPDX_NAMESPACE.Annotation) in graph 20 | assert (None, SPDX_NAMESPACE.annotationType, SPDX_NAMESPACE.annotationType_review) in graph 21 | assert (None, SPDX_NAMESPACE.annotationDate, Literal(datetime_to_iso_string(annotation.annotation_date))) in graph 22 | assert (None, SPDX_NAMESPACE.annotator, Literal(annotation.annotator.to_serialized_string())) in graph 23 | assert (None, RDFS.comment, Literal(annotation.annotation_comment)) in graph 24 | -------------------------------------------------------------------------------- /tests/spdx/writer/rdf/test_external_document_ref_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from rdflib import RDF, Graph, URIRef 5 | 6 | from spdx_tools.spdx.rdfschema.namespace import SPDX_NAMESPACE 7 | from spdx_tools.spdx.writer.rdf.external_document_ref_writer import add_external_document_ref_to_graph 8 | from tests.spdx.fixtures import external_document_ref_fixture 9 | 10 | 11 | def test_add_external_document_ref_to_graph(): 12 | graph = Graph() 13 | external_document_ref = external_document_ref_fixture() 14 | 15 | add_external_document_ref_to_graph(external_document_ref, graph, URIRef("docNode"), "docNamespace") 16 | 17 | assert ( 18 | URIRef("docNode"), 19 | SPDX_NAMESPACE.externalDocumentRef, 20 | URIRef("docNamespace#DocumentRef-external"), 21 | ) in graph 22 | assert (None, RDF.type, SPDX_NAMESPACE.ExternalDocumentRef) in graph 23 | assert (None, SPDX_NAMESPACE.checksum, None) in graph 24 | assert (None, RDF.type, SPDX_NAMESPACE.Checksum) in graph 25 | assert (None, SPDX_NAMESPACE.spdxDocument, URIRef(external_document_ref.document_uri)) in graph 26 | -------------------------------------------------------------------------------- /tests/spdx/writer/rdf/test_extracted_licensing_info_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from rdflib import RDF, RDFS, Graph, Literal, URIRef 5 | 6 | from spdx_tools.spdx.rdfschema.namespace import SPDX_NAMESPACE 7 | from spdx_tools.spdx.writer.rdf.extracted_licensing_info_writer import add_extracted_licensing_info_to_graph 8 | from tests.spdx.fixtures import extracted_licensing_info_fixture 9 | 10 | 11 | def test_add_extracted_licensing_info_to_graph(): 12 | graph = Graph() 13 | extracted_licensing_info = extracted_licensing_info_fixture() 14 | 15 | add_extracted_licensing_info_to_graph(extracted_licensing_info, graph, URIRef("docNode"), "docNamespace") 16 | 17 | assert (URIRef("docNode"), SPDX_NAMESPACE.hasExtractedLicensingInfo, None) in graph 18 | assert (URIRef("docNamespace#LicenseRef-1"), RDF.type, SPDX_NAMESPACE.ExtractedLicensingInfo) in graph 19 | assert (None, SPDX_NAMESPACE.licenseId, Literal(extracted_licensing_info.license_id)) in graph 20 | assert (None, SPDX_NAMESPACE.extractedText, Literal(extracted_licensing_info.extracted_text)) in graph 21 | assert (None, RDFS.seeAlso, Literal(extracted_licensing_info.cross_references[0])) in graph 22 | assert (None, SPDX_NAMESPACE.name, Literal(extracted_licensing_info.license_name)) in graph 23 | assert (None, RDFS.comment, Literal(extracted_licensing_info.comment)) in graph 24 | -------------------------------------------------------------------------------- /tests/spdx/writer/rdf/test_rdf_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import os 5 | 6 | import pytest 7 | 8 | from spdx_tools.spdx.model import Document 9 | from spdx_tools.spdx.writer.rdf.rdf_writer import write_document_to_file 10 | from tests.spdx.fixtures import document_fixture 11 | 12 | 13 | @pytest.fixture 14 | def temporary_file_path() -> str: 15 | temporary_file_path = "temp_test_rdf_writer_output.rdf.xml" 16 | yield temporary_file_path 17 | os.remove(temporary_file_path) 18 | 19 | 20 | def test_write_document_to_file(temporary_file_path: str): 21 | document: Document = document_fixture() 22 | 23 | write_document_to_file(document, temporary_file_path, False) 24 | -------------------------------------------------------------------------------- /tests/spdx/writer/rdf/test_relationship_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from rdflib import RDFS, Graph, Literal, URIRef 5 | 6 | from spdx_tools.spdx.constants import DOCUMENT_SPDX_ID 7 | from spdx_tools.spdx.rdfschema.namespace import SPDX_NAMESPACE 8 | from spdx_tools.spdx.writer.rdf.relationship_writer import add_relationship_to_graph 9 | from tests.spdx.fixtures import relationship_fixture 10 | 11 | 12 | def test_add_relationship_to_graph(): 13 | relationship = relationship_fixture() 14 | graph = Graph() 15 | add_relationship_to_graph(relationship, graph, "docNamespace", {}) 16 | 17 | assert (URIRef(f"docNamespace#{DOCUMENT_SPDX_ID}"), SPDX_NAMESPACE.relationship, None) in graph 18 | assert (None, SPDX_NAMESPACE.relationshipType, SPDX_NAMESPACE.relationshipType_describes) in graph 19 | assert (None, SPDX_NAMESPACE.relatedSpdxElement, URIRef("docNamespace#SPDXRef-File")) in graph 20 | assert (None, RDFS.comment, Literal(relationship.comment)) in graph 21 | -------------------------------------------------------------------------------- /tests/spdx/writer/rdf/test_writer_utils.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id 7 | 8 | 9 | @pytest.mark.parametrize( 10 | "spdx_id,namespace,external_namespaces,expected", 11 | [ 12 | ("SPDXRef-File", "docNamespace", {}, "docNamespace#SPDXRef-File"), 13 | ( 14 | "externalDoc:SPDXRef-File", 15 | "docNamespace", 16 | {"externalDoc": "externalNamespace"}, 17 | "externalNamespace#SPDXRef-File", 18 | ), 19 | ("externalDoc#A-Ref", "", {}, "externalDoc#A-Ref"), 20 | ("externalDoc:A-Ref", "", {}, "externalDoc:A-Ref"), 21 | ], 22 | ) 23 | def test_add_namespace_to_spdx_id(spdx_id, namespace, expected, external_namespaces): 24 | extended_spdx_id = add_namespace_to_spdx_id(spdx_id, namespace, external_namespaces) 25 | 26 | assert extended_spdx_id == expected 27 | -------------------------------------------------------------------------------- /tests/spdx/writer/tagvalue/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx/writer/tagvalue/__init__.py -------------------------------------------------------------------------------- /tests/spdx/writer/tagvalue/expected_results/expected_tag_value.spdx: -------------------------------------------------------------------------------- 1 | ## Document Information 2 | SPDXVersion: spdxVersion 3 | DataLicense: dataLicense 4 | SPDXID: documentId 5 | DocumentName: documentName 6 | DocumentNamespace: documentNamespace 7 | DocumentComment: comment 8 | 9 | ## External Document References 10 | ExternalDocumentRef: docRefId externalDocumentUri SHA1: externalRefSha1 11 | 12 | ## Creation Information 13 | LicenseListVersion: spdxVersion 14 | Creator: Tool: tools-python (tools-python@github.com) 15 | Created: 2022-12-01T00:00:00Z 16 | 17 | ## File Information 18 | FileName: fileName 19 | SPDXID: fileId 20 | FileChecksum: SHA1: fileSha1 21 | 22 | ## Snippet Information 23 | SnippetSPDXID: snippetId 24 | SnippetFromFileSPDXID: fileId 25 | SnippetByteRange: 1:2 26 | 27 | ## Package Information 28 | PackageName: packageName 29 | SPDXID: packageId 30 | PackageDownloadLocation: NONE 31 | FilesAnalyzed: True 32 | 33 | ## License Information 34 | LicenseID: licenseId 35 | ExtractedText: licenseText 36 | 37 | ## Relationships 38 | Relationship: documentId DESCRIBES packageId 39 | Relationship: documentId DESCRIBES fileId 40 | RelationshipComment: relationshipComment 41 | Relationship: relationshipOriginId AMENDS relationShipTargetId 42 | 43 | ## Annotations 44 | Annotator: Person: reviewerName 45 | AnnotationDate: 2022-12-02T00:00:00Z 46 | AnnotationType: REVIEW 47 | SPDXREF: documentId 48 | AnnotationComment: reviewComment 49 | 50 | Annotator: Tool: toolName 51 | AnnotationDate: 2022-12-03T00:00:00Z 52 | AnnotationType: OTHER 53 | SPDXREF: fileId 54 | AnnotationComment: otherComment 55 | -------------------------------------------------------------------------------- /tests/spdx/writer/tagvalue/test_annotation_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from unittest.mock import MagicMock, call, mock_open, patch 5 | 6 | from spdx_tools.spdx.writer.tagvalue.annotation_writer import write_annotation 7 | from tests.spdx.fixtures import annotation_fixture 8 | 9 | 10 | def test_annotation_writer(): 11 | annotation = annotation_fixture() 12 | 13 | mock: MagicMock = mock_open() 14 | with patch(f"{__name__}.open", mock, create=True): 15 | with open("foo", "w") as file: 16 | write_annotation(annotation, file) 17 | 18 | mock.assert_called_once_with("foo", "w") 19 | handle = mock() 20 | handle.write.assert_has_calls( 21 | [ 22 | call(f"Annotator: Person: {annotation.annotator.name} ({annotation.annotator.email})\n"), 23 | call("AnnotationDate: 2022-12-24T00:00:00Z\n"), 24 | call(f"AnnotationType: {annotation.annotation_type.name}\n"), 25 | call(f"SPDXREF: {annotation.spdx_id}\n"), 26 | call(f"AnnotationComment: {annotation.annotation_comment}\n"), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /tests/spdx/writer/tagvalue/test_checksum_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx.model import ChecksumAlgorithm 7 | from spdx_tools.spdx.writer.tagvalue.checksum_writer import write_checksum_to_tag_value 8 | from tests.spdx.fixtures import checksum_fixture 9 | 10 | 11 | @pytest.mark.parametrize( 12 | "checksum, expected_string", 13 | [ 14 | (checksum_fixture(), "SHA1: 71c4025dd9897b364f3ebbb42c484ff43d00791c"), 15 | (checksum_fixture(algorithm=ChecksumAlgorithm.SHA3_256, value="fdsef"), "SHA3-256: fdsef"), 16 | (checksum_fixture(algorithm=ChecksumAlgorithm.SHA3_384, value="fdsef"), "SHA3-384: fdsef"), 17 | (checksum_fixture(algorithm=ChecksumAlgorithm.SHA3_512, value="fdsef"), "SHA3-512: fdsef"), 18 | (checksum_fixture(algorithm=ChecksumAlgorithm.BLAKE2B_256, value="fdsef"), "BLAKE2b-256: fdsef"), 19 | (checksum_fixture(algorithm=ChecksumAlgorithm.BLAKE2B_384, value="fdsef"), "BLAKE2b-384: fdsef"), 20 | (checksum_fixture(algorithm=ChecksumAlgorithm.BLAKE2B_512, value="fdsef"), "BLAKE2b-512: fdsef"), 21 | ], 22 | ) 23 | def test_checksum_writer(checksum, expected_string): 24 | checksum_string = write_checksum_to_tag_value(checksum) 25 | 26 | assert checksum_string == expected_string 27 | -------------------------------------------------------------------------------- /tests/spdx/writer/tagvalue/test_extracted_licensing_info_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from unittest.mock import MagicMock, call, mock_open, patch 5 | 6 | from spdx_tools.spdx.writer.tagvalue.extracted_licensing_info_writer import write_extracted_licensing_info 7 | from tests.spdx.fixtures import extracted_licensing_info_fixture 8 | 9 | 10 | def test_extracted_licensing_info_writer(): 11 | extracted_licensing_info = extracted_licensing_info_fixture() 12 | 13 | mock: MagicMock = mock_open() 14 | with patch(f"{__name__}.open", mock, create=True): 15 | with open("foo", "w") as file: 16 | write_extracted_licensing_info(extracted_licensing_info, file) 17 | 18 | mock.assert_called_once_with("foo", "w") 19 | handle = mock() 20 | handle.write.assert_has_calls( 21 | [ 22 | call(f"LicenseID: {extracted_licensing_info.license_id}\n"), 23 | call(f"ExtractedText: {extracted_licensing_info.extracted_text}\n"), 24 | call(f"LicenseName: {extracted_licensing_info.license_name}\n"), 25 | call(f"LicenseCrossReference: {extracted_licensing_info.cross_references[0]}\n"), 26 | call(f"LicenseComment: {extracted_licensing_info.comment}\n"), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /tests/spdx3/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/bump/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/bump/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/bump/test_bump_utils.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 spdx contributors 2 | 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.bump_from_spdx2.bump_utils import handle_no_assertion_or_none 7 | from spdx_tools.spdx.model.spdx_no_assertion import SpdxNoAssertion 8 | from spdx_tools.spdx.model.spdx_none import SpdxNone 9 | 10 | 11 | @pytest.mark.parametrize( 12 | "input_argument,expected_value,expected_stdout", 13 | [ 14 | (SpdxNone(), None, "test_field: Missing conversion for SpdxNone.\n"), 15 | (SpdxNoAssertion(), None, ""), 16 | ("test_string", "test_string", ""), 17 | ], 18 | ) 19 | def test_handle_no_assertion_or_none(input_argument, expected_value, expected_stdout, capsys): 20 | value = handle_no_assertion_or_none(input_argument, "test_field") 21 | 22 | captured = capsys.readouterr() 23 | 24 | assert value == expected_value 25 | assert captured.out == expected_stdout 26 | -------------------------------------------------------------------------------- /tests/spdx3/bump/test_file_bump.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from spdx_tools.spdx3.bump_from_spdx2.file import bump_file 6 | from spdx_tools.spdx3.model import Hash, HashAlgorithm 7 | from spdx_tools.spdx3.model.software import File 8 | from spdx_tools.spdx3.payload import Payload 9 | from spdx_tools.spdx.model.file import File as Spdx2_File 10 | from tests.spdx.fixtures import file_fixture 11 | 12 | 13 | def test_bump_file(): 14 | payload = Payload() 15 | document_namespace = "https://doc.namespace" 16 | spdx2_file: Spdx2_File = file_fixture() 17 | integrity_method: Hash = Hash(HashAlgorithm.SHA1, "71c4025dd9897b364f3ebbb42c484ff43d00791c") 18 | expected_new_file_id = f"{document_namespace}#{spdx2_file.spdx_id}" 19 | 20 | bump_file(spdx2_file, payload, document_namespace, [], []) 21 | file = payload.get_element(expected_new_file_id) 22 | 23 | assert isinstance(file, File) 24 | assert file.spdx_id == expected_new_file_id 25 | assert file.verified_using == [integrity_method] 26 | assert file.copyright_text == spdx2_file.copyright_text 27 | assert file.attribution_text == spdx2_file.attribution_texts[0] 28 | -------------------------------------------------------------------------------- /tests/spdx3/bump/test_snippet_bump.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | from spdx_tools.spdx3.bump_from_spdx2.snippet import bump_snippet 6 | from spdx_tools.spdx3.model.software import Snippet 7 | from spdx_tools.spdx3.payload import Payload 8 | from spdx_tools.spdx.model.snippet import Snippet as Spdx2_Snippet 9 | from tests.spdx.fixtures import snippet_fixture 10 | 11 | 12 | def test_bump_snippet(): 13 | payload = Payload() 14 | document_namespace = "https://doc.namespace" 15 | spdx2_snippet: Spdx2_Snippet = snippet_fixture() 16 | expected_new_snippet_id = f"{document_namespace}#{spdx2_snippet.spdx_id}" 17 | 18 | bump_snippet(spdx2_snippet, payload, document_namespace, [], []) 19 | snippet = payload.get_element(expected_new_snippet_id) 20 | 21 | assert isinstance(snippet, Snippet) 22 | assert snippet.spdx_id == expected_new_snippet_id 23 | assert snippet.copyright_text == spdx2_snippet.copyright_text 24 | assert snippet.attribution_text == spdx2_snippet.attribution_texts[0] 25 | -------------------------------------------------------------------------------- /tests/spdx3/bump/test_spdx_document_bump.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import sys 5 | 6 | from spdx_tools.spdx3.bump_from_spdx2.spdx_document import bump_spdx_document 7 | from spdx_tools.spdx3.payload import Payload 8 | from spdx_tools.spdx3.writer.console.payload_writer import write_payload 9 | from spdx_tools.spdx.model.actor import ActorType 10 | from spdx_tools.spdx.model.document import Document as Spdx2_Document 11 | from tests.spdx.fixtures import actor_fixture, annotation_fixture, creation_info_fixture, document_fixture 12 | 13 | 14 | def test_bump_spdx_document(): 15 | spdx2_document: Spdx2_Document = document_fixture() 16 | spdx2_document.creation_info.creators.append(actor_fixture(ActorType.TOOL, "tool_name", None)) 17 | document_namespace = document_fixture().creation_info.document_namespace 18 | 19 | payload: Payload = bump_spdx_document(spdx2_document) 20 | 21 | write_payload(payload, sys.stdout) 22 | 23 | assert f"{document_namespace}#SPDXRef-Package" in payload.get_full_map() 24 | assert len(payload.get_full_map()) == 11 25 | 26 | # this is more of a temporary test to make sure the dates don't get messed up again 27 | assert ( 28 | payload.get_element("#".join([document_namespace, "SPDXRef-DOCUMENT"])).creation_info.created 29 | == creation_info_fixture().created 30 | ) 31 | assert ( 32 | payload.get_element("#".join([document_namespace, "SPDXRef-Annotation-0"])).creation_info.created 33 | == annotation_fixture().annotation_date 34 | ) 35 | -------------------------------------------------------------------------------- /tests/spdx3/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/model/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/model/licensing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/model/licensing/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/model/licensing/test_conjunctive_license_set.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model.licensing import ConjunctiveLicenseSet, ListedLicense 7 | from tests.spdx3.fixtures import fixture_factory 8 | 9 | 10 | def test_valid_initialization(): 11 | lic = fixture_factory(ListedLicense) 12 | conjunctive_license_set = ConjunctiveLicenseSet([lic, lic]) 13 | 14 | assert conjunctive_license_set.member == [lic, lic] 15 | 16 | 17 | def test_invalid_initialization(): 18 | lic = fixture_factory(ListedLicense) 19 | with pytest.raises(TypeError) as err: 20 | ConjunctiveLicenseSet(lic) 21 | 22 | assert len(err.value.args[0]) == 1 23 | assert err.value.args[0][0].startswith("SetterError ConjunctiveLicenseSet:") 24 | -------------------------------------------------------------------------------- /tests/spdx3/model/licensing/test_disjunctive_license_set.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model.licensing import DisjunctiveLicenseSet, ListedLicense 7 | from tests.spdx3.fixtures import fixture_factory 8 | 9 | 10 | def test_valid_initialization(): 11 | lic = fixture_factory(ListedLicense) 12 | disjunctive_license_set = DisjunctiveLicenseSet([lic, lic]) 13 | 14 | assert disjunctive_license_set.member == [lic, lic] 15 | 16 | 17 | def test_invalid_initialization(): 18 | lic = fixture_factory(ListedLicense) 19 | with pytest.raises(TypeError) as err: 20 | DisjunctiveLicenseSet(lic) 21 | 22 | assert len(err.value.args[0]) == 1 23 | assert err.value.args[0][0].startswith("SetterError DisjunctiveLicenseSet:") 24 | -------------------------------------------------------------------------------- /tests/spdx3/model/licensing/test_or_later_operator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model.licensing import ListedLicense, OrLaterOperator 7 | from tests.spdx3.fixtures import fixture_factory 8 | 9 | 10 | def test_valid_initialization(): 11 | lic = fixture_factory(ListedLicense) 12 | or_later_operator = OrLaterOperator(lic) 13 | 14 | assert or_later_operator.subject_license == lic 15 | 16 | 17 | def test_invalid_initialization(): 18 | with pytest.raises(TypeError) as err: 19 | OrLaterOperator("License") 20 | 21 | assert len(err.value.args[0]) == 1 22 | assert err.value.args[0][0].startswith("SetterError OrLaterOperator:") 23 | -------------------------------------------------------------------------------- /tests/spdx3/model/licensing/test_with_addition_operator.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model.licensing import ListedLicense, ListedLicenseException, WithAdditionOperator 7 | from tests.spdx3.fixtures import fixture_factory 8 | 9 | 10 | def test_valid_initialization(): 11 | lic = fixture_factory(ListedLicense) 12 | lic_addition = fixture_factory(ListedLicenseException) 13 | with_addition_operator = WithAdditionOperator(lic, lic_addition) 14 | 15 | assert with_addition_operator.subject_license == lic 16 | 17 | 18 | def test_invalid_initialization(): 19 | with pytest.raises(TypeError) as err: 20 | WithAdditionOperator("License", "LicenseAddition") 21 | 22 | assert len(err.value.args[0]) == 2 23 | for arg in err.value.args[0]: 24 | assert arg.startswith("SetterError WithAdditionOperator:") 25 | -------------------------------------------------------------------------------- /tests/spdx3/model/model_test_utils.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from typing import Any, List, Type 5 | 6 | 7 | def get_property_names(clazz: Type[Any]) -> List[str]: 8 | return [ 9 | attribute 10 | for attribute in dir(clazz) 11 | if not attribute.startswith("_") and not callable(getattr(clazz, attribute)) 12 | ] 13 | 14 | 15 | class InvalidTypeClass: 16 | pass 17 | -------------------------------------------------------------------------------- /tests/spdx3/model/test_abstract_classes.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model import Artifact, Element, ElementCollection, IntegrityMethod 7 | 8 | 9 | @pytest.mark.parametrize("abstract_class", [Element, Artifact, ElementCollection, IntegrityMethod]) 10 | def test_initialization_throws_error(abstract_class): 11 | with pytest.raises(TypeError) as err: 12 | abstract_class() 13 | 14 | assert f"Can't instantiate abstract class {abstract_class.__name__}" in err.value.args[0] 15 | -------------------------------------------------------------------------------- /tests/spdx3/model/test_external_identifier.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model import ExternalIdentifier, ExternalIdentifierType 7 | from tests.spdx3.fixtures import external_identifier_fixture 8 | from tests.spdx3.model.model_test_utils import get_property_names 9 | 10 | 11 | def test_correct_initialization(): 12 | external_identifier = external_identifier_fixture() 13 | 14 | for property_name in get_property_names(ExternalIdentifier): 15 | assert getattr(external_identifier, property_name) is not None 16 | 17 | assert external_identifier.external_identifier_type == ExternalIdentifierType.OTHER 18 | assert external_identifier.identifier == "externalIdentifierIdentifier" 19 | assert external_identifier.comment == "externalIdentifierComment" 20 | assert external_identifier.identifier_locator == [ 21 | "https://spdx.test/tools-python/external_identifier_identifier_locator" 22 | ] 23 | assert ( 24 | external_identifier.issuing_authority == "https://spdx.test/tools-python/external_identifier_issuing_authority" 25 | ) 26 | 27 | 28 | def test_invalid_initialization(): 29 | with pytest.raises(TypeError) as err: 30 | ExternalIdentifier("CPE22", ["identifier", "another_identifier"], 34, "locator", True) 31 | 32 | assert len(err.value.args[0]) == 5 33 | for error in err.value.args[0]: 34 | assert error.startswith("SetterError ExternalIdentifier:") 35 | -------------------------------------------------------------------------------- /tests/spdx3/model/test_external_map.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | import pytest 6 | 7 | from spdx_tools.spdx3.model import ExternalMap 8 | from tests.spdx3.fixtures import external_map_fixture, hash_fixture 9 | from tests.spdx3.model.model_test_utils import get_property_names 10 | 11 | 12 | def test_correct_initialization(): 13 | external_map = external_map_fixture() 14 | 15 | for property_name in get_property_names(ExternalMap): 16 | assert getattr(external_map, property_name) is not None 17 | 18 | assert external_map.external_id == "https://spdx.test/tools-python/external_map_external_id" 19 | assert external_map.verified_using == [hash_fixture()] 20 | assert external_map.location_hint == "https://spdx.test/tools-python/external_map_location_hint" 21 | assert external_map.defining_document == "https://spdx.test/tools-python/defining_document" 22 | 23 | 24 | def test_invalid_initialization(): 25 | with pytest.raises(TypeError) as err: 26 | ExternalMap(234, None, ["location hints"]) 27 | 28 | assert len(err.value.args[0]) == 2 29 | for error in err.value.args[0]: 30 | assert error.startswith("SetterError ExternalMap:") 31 | -------------------------------------------------------------------------------- /tests/spdx3/model/test_external_reference.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model import ExternalReference, ExternalReferenceType 7 | from tests.spdx3.fixtures import external_reference_fixture 8 | from tests.spdx3.model.model_test_utils import get_property_names 9 | 10 | 11 | def test_correct_initialization(): 12 | external_reference = external_reference_fixture() 13 | 14 | for property_name in get_property_names(ExternalReference): 15 | assert getattr(external_reference, property_name) is not None 16 | 17 | assert external_reference.external_reference_type == ExternalReferenceType.OTHER 18 | assert external_reference.locator == ["org.apache.tomcat:tomcat:9.0.0.M4"] 19 | assert external_reference.content_type == "externalReferenceContentType" 20 | assert external_reference.comment == "externalReferenceComment" 21 | 22 | 23 | def test_invalid_initialization(): 24 | with pytest.raises(TypeError) as err: 25 | ExternalReference("OTHER", "a URI", 34, True) 26 | 27 | assert len(err.value.args[0]) == 4 28 | for error in err.value.args[0]: 29 | assert error.startswith("SetterError ExternalReference:") 30 | -------------------------------------------------------------------------------- /tests/spdx3/model/test_hash.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model import Hash, HashAlgorithm 7 | from tests.spdx3.fixtures import hash_fixture 8 | from tests.spdx3.model.model_test_utils import get_property_names 9 | 10 | 11 | def test_correct_initialization(): 12 | hash = hash_fixture() 13 | 14 | for property_name in get_property_names(Hash): 15 | assert getattr(hash, property_name) is not None 16 | 17 | assert hash.algorithm == HashAlgorithm.SHA1 18 | assert hash.hash_value == "71c4025dd9897b364f3ebbb42c484ff43d00791c" 19 | assert hash.comment == "hashComment" 20 | 21 | 22 | def test_invalid_initialization(): 23 | with pytest.raises(TypeError) as err: 24 | Hash("SHA1", 345) 25 | 26 | assert len(err.value.args[0]) == 2 27 | for error in err.value.args[0]: 28 | assert error.startswith("SetterError Hash:") 29 | -------------------------------------------------------------------------------- /tests/spdx3/model/test_namespace_map.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import pytest 5 | 6 | from spdx_tools.spdx3.model import NamespaceMap 7 | from tests.spdx3.fixtures import namespace_map_fixture 8 | from tests.spdx3.model.model_test_utils import get_property_names 9 | 10 | 11 | def test_correct_initialization(): 12 | namespace_map = namespace_map_fixture() 13 | 14 | for property_name in get_property_names(NamespaceMap): 15 | assert getattr(namespace_map, property_name) is not None 16 | 17 | assert namespace_map.prefix == "namespaceMapPrefix" 18 | assert namespace_map.namespace == "https://spdx.test/tools-python/namespace_map_namespace" 19 | 20 | 21 | def test_invalid_initialization(): 22 | with pytest.raises(TypeError) as err: 23 | NamespaceMap(34, ["list of namespaces"]) 24 | 25 | assert len(err.value.args[0]) == 2 26 | for error in err.value.args[0]: 27 | assert error.startswith("SetterError NamespaceMap:") 28 | -------------------------------------------------------------------------------- /tests/spdx3/validation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/validation/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/validation/json_ld/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/validation/json_ld/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/validation/json_ld/test_shacl_validation.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import os 5 | 6 | import pytest 7 | 8 | from spdx_tools.spdx3.validation.json_ld.shacl_validation import validate_against_shacl_from_file 9 | 10 | 11 | @pytest.mark.skip("Currently the validation against SHACL fails, refer to process.md and the known limitations.") 12 | def test_shacl_validation(): 13 | # insert path to example json ld 14 | conforms, results_graph, results_text = validate_against_shacl_from_file( 15 | data_file=os.path.join(os.path.dirname(__file__), "../../../SPDX3_jsonld_test.jsonld"), 16 | shacl_file=os.path.join( 17 | os.path.dirname(__file__), "../../../../src/spdx_tools/spdx3/writer/json_ld/model.ttl" 18 | ), 19 | ) 20 | # results_graph.serialize("validation_result.rdf.xml", format="pretty-xml") 21 | print(results_text) 22 | assert conforms 23 | -------------------------------------------------------------------------------- /tests/spdx3/writer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/writer/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/writer/json_ld/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spdx/tools-python/8dc336f783e993d7e347d20b8ecd50b8808abf70/tests/spdx3/writer/json_ld/__init__.py -------------------------------------------------------------------------------- /tests/spdx3/writer/json_ld/test_json_ld_writer.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import os 5 | 6 | from spdx_tools.spdx3.bump_from_spdx2.spdx_document import bump_spdx_document 7 | from spdx_tools.spdx3.payload import Payload 8 | from spdx_tools.spdx3.writer.json_ld.json_ld_writer import write_payload 9 | from spdx_tools.spdx.model.document import Document as Spdx2_Document 10 | from tests.spdx.fixtures import document_fixture 11 | 12 | 13 | def test_json_writer(): 14 | spdx2_document: Spdx2_Document = document_fixture() 15 | payload: Payload = bump_spdx_document(spdx2_document) 16 | 17 | # this currently generates an actual file to look at, this should be changed to a temp file later 18 | write_payload(payload, os.path.join(os.path.dirname(__file__), "../../../SPDX3_jsonld_test")) 19 | -------------------------------------------------------------------------------- /tests/spdx3/writer/tag_value/test_write_document.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 spdx contributors 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | import io 5 | from datetime import datetime 6 | 7 | from semantic_version import Version 8 | 9 | from spdx_tools.spdx3.model import CreationInfo, ProfileIdentifierType, SpdxDocument 10 | from spdx_tools.spdx3.writer.console.spdx_document_writer import write_spdx_document 11 | 12 | 13 | def test_render_creation_info(): 14 | fake_datetime = datetime(year=2024, month=1, day=1) 15 | spec_version = Version("3.0.0") 16 | creation_info = CreationInfo( 17 | spec_version=spec_version, 18 | created=fake_datetime, 19 | created_by=[], 20 | profile=[ProfileIdentifierType.SOFTWARE], 21 | ) 22 | spdx_document = SpdxDocument( 23 | spdx_id="SPDXRef-FOO", 24 | name="BAR", 25 | element=[], 26 | root_element=[], 27 | creation_info=creation_info, 28 | ) 29 | output_str = io.StringIO() 30 | write_spdx_document(spdx_document, text_output=output_str) 31 | 32 | assert ( 33 | output_str.getvalue() 34 | == """\ 35 | ## SPDX Document 36 | SPDXID: SPDXRef-FOO 37 | name: BAR 38 | # Creation Information 39 | specVersion: 3.0.0 40 | created: 2024-01-01T00:00:00Z 41 | profile: SOFTWARE 42 | data license: CC0-1.0 43 | elements: 44 | """ # noqa: W291 # elements: are printed with a space 45 | ) 46 | --------------------------------------------------------------------------------