From e9256054a803aa30ba7e95d565c1458ebbca1b49 Mon Sep 17 00:00:00 2001 From: Arthit Suriyawongkul Date: Tue, 23 Jun 2026 15:04:38 +0100 Subject: [PATCH 1/3] Add tutorial in HTML Signed-off-by: Arthit Suriyawongkul --- .github/workflows/docs.yaml | 54 +- www/index.html | 9 +- www/tutorial/spdx-python-model-tutorial.ipynb | 1438 +++++++++++++++++ 3 files changed, 1490 insertions(+), 11 deletions(-) create mode 100644 www/tutorial/spdx-python-model-tutorial.ipynb diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index e1a4fbe..5ab622b 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -6,8 +6,11 @@ # https://spdx.github.io/spdx-python-model/doc/stable/ -- latest release # https://spdx.github.io/spdx-python-model/doc/dev/ -- from main branch (unreleased) # https://spdx.github.io/spdx-python-model/doc/1.0/ -- for specific version (all 1.0.x will all published to this URL) +# +# Publish tutorials to +# https://spdx.github.io/spdx-python-model/tutorial/ -name: Publish API docs +name: Publish docs on: push: @@ -60,8 +63,10 @@ jobs: - name: Install pdoc run: pip install pdoc + - name: Install nbconvert + run: pip install nbconvert + - name: Get version - id: get_version run: | if [[ "${{ github.event_name }}" == "release" ]]; then VERSION_RAW="${{ github.event.release.tag_name }}" @@ -75,13 +80,20 @@ jobs: echo "IS_RELEASE=false" >> $GITHUB_ENV fi - - name: Build docs + - name: Build landing page + run: | + if [[ -f www/index.html ]]; then + cp www/index.html pages/index.html + else + echo '' > pages/index.html + fi + + - name: Build API docs run: | OUT="pages/doc/$MAJOR_MINOR" mkdir -p "$OUT" - # Build API docs into the versioned output directory. pdoc spdx_python_model \ --logo "https://raw.githubusercontent.com/spdx/outreach/main/assets/SPDX_Logo/svg/SPDX%20logo%20color.svg" \ --logo-link "/spdx-python-model/doc/$MAJOR_MINOR/" \ @@ -98,11 +110,35 @@ jobs: mkdir -p pages/doc echo '' > pages/doc/index.html - # Root landing page from repo; fallback to redirect if not present. - if [[ -f www/index.html ]]; then - cp www/index.html pages/index.html - else - echo '' > pages/index.html + - name: Build tutorials + run: | + if [[ ! -d www/tutorial ]]; then + exit 0 + fi + + mkdir -p pages/tutorial + + for nb in www/tutorial/*.ipynb; do + jupyter nbconvert --to html --output-dir pages/tutorial "$nb" + cp "$nb" pages/tutorial/ + done + + # Generate /tutorial/ index listing all tutorials. + if [[ ! -f www/tutorial/index.html ]]; then + { + echo '' + echo '' + echo 'Tutorials – spdx-python-model' + echo '' + echo '' + echo '

spdx-python-model

' + echo '

Tutorials

' + } > pages/tutorial/index.html fi - name: Setup Pages diff --git a/www/index.html b/www/index.html index f98233a..8fc095c 100644 --- a/www/index.html +++ b/www/index.html @@ -51,10 +51,15 @@

Install

Install the latest version from PyPI:

pip install spdx-python-model
+

Tutorial

+ +

API documentation

Documentation for each version of the SPDX 3 model is in the spdx_python_model.bindings.VERSION.model submodule. diff --git a/www/tutorial/spdx-python-model-tutorial.ipynb b/www/tutorial/spdx-python-model-tutorial.ipynb new file mode 100644 index 0000000..70f1b1d --- /dev/null +++ b/www/tutorial/spdx-python-model-tutorial.ipynb @@ -0,0 +1,1438 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyOys2TFWeUKaj6M6TfFA+yY", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "source": [ + "# SPDX-FileCopyrightText: 2025-present Arthit Suriyawongkul \n", + "# SPDX-FileType: SOURCE\n", + "# SPDX-License-Identifier: Apache-2.0" + ], + "metadata": { + "id": "fTKOUcN_esq8" + }, + "execution_count": 1, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Using SPDX 3 in Python with spdx-python-model\n", + "\n", + "- This tutorial demonstrates how to use the [spdx-python-model][] library to:\n", + " - read the software bill of materials (SBOM) data in the [System Package Data Exchange (SPDX)][spdx] format from an [SPDX 3 JSON][spdx-3-json] file;\n", + " - access SPDX objects and their relationships; and\n", + " - create a simple SPDX object (also demonstrating the built-in data validation of the library)\n", + "\n", + "- The SBOM 3 JSON file examples are taken from [AI Example 2][ai-example-2] and [Software Example 14][sw-example-14] of the spdx-examples repository.\n", + "- This documentation is a contribution to the [NTIA Conformance Checker][ntia-conformance-checker] as part of the [Google Summer of Code 2025 program][gsoc-2025] (mentors: Gary O'Neall and John Speed Meyers).\n", + "\n", + "by [@bact][bact] - Arthit Suriyawongkul\n", + "\n", + "## Change log\n", + "\n", + "- Update: 21 May 2026 - fix handling of unresolved references (spdxId) ([reported](https://github.com/spdx/spdx-python-model/issues/34) by @vargenau and suggested a fix by @benjarobin - thank you both!)\n", + "- Update: 23 February 2026 - add a section on SPDX object creation and validation\n", + "- First published: 7 July 2025\n", + "\n", + "[spdx]: https://spdx.dev/use/specifications/\n", + "[spdx-python-model]: https://github.com/spdx/spdx-python-model\n", + "[spdx-3-json]: https://github.com/spdx/spdx-spec/blob/develop/docs/serializations.md#serialization-in-spdx-3-json\n", + "[ai-example-2]: https://github.com/spdx/spdx-examples/tree/master/ai/example02/\n", + "[sw-example-14]: https://github.com/spdx/spdx-examples/tree/master/software/example14/\n", + "[ntia-conformance-checker]: https://github.com/spdx/ntia-conformance-checker\n", + "[gsoc-2025]: https://summerofcode.withgoogle.com/programs/2025/projects/CeR3hQTq\n", + "[bact]: https://github.com/bact/" + ], + "metadata": { + "id": "09M0uv5_Bk7B" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Install the spdx-python-model library" + ], + "metadata": { + "id": "_ZRVMOBvQDuO" + } + }, + { + "cell_type": "code", + "source": [ + "!pip install spdx-python-model" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JsENPjgwHlHc", + "outputId": "0c5b73dc-52c8-4bb1-b60b-8a1640df09da" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: spdx-python-model in /usr/local/lib/python3.12/dist-packages (0.0.5)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Import and check library version" + ], + "metadata": { + "id": "0rhToD4DQQ0-" + } + }, + { + "cell_type": "code", + "source": [ + "from spdx_python_model import VERSION, bindings\n", + "\n", + "print(f\"spdx-python-model library version: {VERSION}\")\n", + "\n", + "print(\"Available SPDX bindings in spdx_python_model module:\")\n", + "for name in dir(bindings):\n", + " if not name.startswith(\"__\"):\n", + " print(name)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "977gguFuH1Nt", + "outputId": "71a52e69-ff00-4efc-e918-63e0e78fff7d" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "spdx-python-model library version: 0.0.5\n", + "Available SPDX bindings in spdx_python_model module:\n", + "v3_0_1\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "To use a Python binding, import a specific version of the model.\n", + "\n", + "For example, to import a binding for SPDX model version 3.0.1, import `v3_0_1`." + ], + "metadata": { + "id": "yuweD-jan0A8" + } + }, + { + "cell_type": "code", + "source": [ + "from spdx_python_model import v3_0_1" + ], + "metadata": { + "id": "MW10UJY2n7Ot" + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Or you may like to assign it to a versionless alias,\n", + "so you can update the version easily later.\n", + "\n", + "For example, this will set the import alias as `spdx3`." + ], + "metadata": { + "id": "v7E3Ys6BoBKQ" + } + }, + { + "cell_type": "code", + "source": [ + "from spdx_python_model import v3_0_1 as spdx3" + ], + "metadata": { + "id": "bgKEojPtn_yC" + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "If a new version (e.g., v3_1) is released, you only need to update the import line and can keep the rest of your code intact.\n", + "\n", + "For example, `from spdx_python_model import v3_1 as spdx3`." + ], + "metadata": { + "id": "PC_h1XmSpIF3" + } + }, + { + "cell_type": "markdown", + "source": [ + "Once imported, we can now access SPDX 3 model.\n", + "\n", + "Let's print some \"named individuals\" from the model." + ], + "metadata": { + "id": "9bWRkIYvpkzO" + } + }, + { + "cell_type": "code", + "source": [ + "list(spdx3.NAMED_INDIVIDUALS)[:8]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "jh4qYAep0d-L", + "outputId": "6334a3f2-9d54-428f-f92f-a89adc8950ca" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "['https://spdx.org/rdf/3.0.1/terms/Core/ExternalIdentifierType/email',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Dataset/DatasetAvailabilityType/registration',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/hasDocumentation',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/usesTool',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Dataset/DatasetType/audio',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Software/SbomType/analyzed',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/hasDataFile',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/ExternalIdentifierType/urlScheme']" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Some of these could be entries in SPDX 3 vocabularies (enum)." + ], + "metadata": { + "id": "x6C0wvWRqDIP" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Read SPDX data from SPDX 3 JSON file" + ], + "metadata": { + "id": "LeTPh0lsQZBw" + } + }, + { + "cell_type": "markdown", + "source": [ + "The library offers a built-in JSON-LD deserializer.\n", + "To use it, provide the path to your SPDX 3 JSON file and an instance of SHACLObjectSet.\n", + "The deserializer will read the JSON file and populate the SHACLObjectSet.\n", + "\n", + "SHACLObjectSet holds SHACLObjects, which are the primary data structures for\n", + "interaction within this library. It also includes helpful utilities, such as\n", + "a generator (iterator) for accessing objects by their type.\n", + "\n", + "In this example, we will first download the JSON file from the `spdx-examples` repository." + ], + "metadata": { + "id": "wak3vYKObfXI" + } + }, + { + "cell_type": "code", + "source": [ + "from urllib.request import urlretrieve\n", + "\n", + "# url = \"https://raw.githubusercontent.com/spdx/spdx-examples/refs/heads/master/ai/example02/spdx3.0/sbom.spdx3.json\"\n", + "url = \"https://raw.githubusercontent.com/spdx/spdx-examples/refs/heads/master/software/example14/spdx3.0/examplemaven-0.0.1-enriched.spdx3.json\"\n", + "filename = \"sbom.spdx.json\"\n", + "filepath, _ = urlretrieve(url, filename) # download from url; get the filepath\n", + "\n", + "object_set = spdx3.SHACLObjectSet()\n", + "\n", + "with open(filepath, \"r\", encoding=\"utf-8\") as f:\n", + " spdx3.JSONLDDeserializer().read(f, object_set)\n", + "\n", + "print(object_set)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JQ9lTkNdIckN", + "outputId": "c5f14a5c-8db2-45d3-b93e-521d704d3823" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Some internal works of SHACLObjectSet" + ], + "metadata": { + "id": "8llGik8aQdct" + } + }, + { + "cell_type": "markdown", + "source": [ + "Internally SHACLObjectSet keeps objects in its `objects` set." + ], + "metadata": { + "id": "jbEuuu53b0Eb" + } + }, + { + "cell_type": "code", + "source": [ + "# see what is inside\n", + "print(list(object_set.objects)[:3])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "y1z84-MK6cnx", + "outputId": "cd938a15-85c0-4bc9-f0e9-7e880e769ff7" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[, , ]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Internally, for faster lookup, SHACLObjectSet maintains two indexes:\n", + "`obj_by_id` and `obj_by_type`.\n", + "\n", + "`obj_by_id` is a dictionary where:\n", + "- Keys are the `spdxId` property values of the objects.\n", + "- Values are the corresponding SHACLObject instances.\n", + "\n", + "`obj_by_type` is a dictionary where:\n", + "- Keys are the `type` property values of the objects.\n", + " (e.g., \"SpdxDocument\", \"software_Package\", \"simplelicensing_LicenseExpression\").\n", + " Note: Core Profile types do not require a prefix, while other Profiles do (e.g., \"software_\").\n", + "- Values are sets of tuples. Each tuple contains:\n", + " 1. A boolean indicating if the SHACLObject in this tuple is an exact type match (True)\n", + " or a subclass match (False); and\n", + " 2. The SHACLObject instance itself." + ], + "metadata": { + "id": "4sqtE2vVcDnx" + } + }, + { + "cell_type": "code", + "source": [ + "any_license_infos = object_set.obj_by_type[\"simplelicensing_AnyLicenseInfo\"]\n", + "print(any_license_infos)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xb-edy3n4eRh", + "outputId": "c06a9ae7-8f19-4398-e1f8-5862673a04f5" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{(False, ), (False, ), (False, ), (False, )}\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's begin with a quick check.\n", + "\n", + "For example, we can see how many SpdxDocument objects are present\n", + "and if it is according to the specification.\n", + "\n", + "See: https://spdx.github.io/spdx-spec/v3.0.1/serializations/#serialization-information" + ], + "metadata": { + "id": "S17Cuqt5cgiY" + } + }, + { + "cell_type": "code", + "source": [ + "spdx_documents = list(object_set.obj_by_type[\"SpdxDocument\"])\n", + "\n", + "if len(spdx_documents) > 1:\n", + " print(\"Warning: A serialization must not contain more than one SpdxDocument.\")\n", + "else:\n", + " print(\"Looks good.\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "S-Q78uecJ-m9", + "outputId": "7b81ac18-6b6c-47d7-de6a-195795da0898" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Looks good.\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Get all objects of type \"Relationship\", including its subclasses\n", + "relationships = object_set.obj_by_type[\"Relationship\"]\n", + "print(\"Relationship found:\", len(relationships))\n", + "for o in relationships:\n", + " print(o)\n", + "print()\n", + "\n", + "# Get all objects of type \"LifecycleScopedRelationship\", including its subclasses\n", + "lifecycle_scoped_relationships = object_set.obj_by_type[\"LifecycleScopedRelationship\"]\n", + "print(\"LifecycleScopedRelationship found:\", len(lifecycle_scoped_relationships))\n", + "for o in lifecycle_scoped_relationships:\n", + " print(o)\n", + "print()\n", + "\n", + "# Get all objects of type \"Softare/Package\", including its subclasses\n", + "packages = object_set.obj_by_type[\"software_Package\"]\n", + "print(\"software_Package found:\", len(packages))\n", + "for o in packages:\n", + " print(o)\n", + "\n", + "print()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1tiaPV-FKmZh", + "outputId": "0055c4f4-315c-43ce-a81f-9e6b4a55ee74" + }, + "execution_count": 11, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Relationship found: 28\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(False, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "\n", + "LifecycleScopedRelationship found: 1\n", + "(True, )\n", + "\n", + "software_Package found: 6\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## A proper way to get access to SPDX objects" + ], + "metadata": { + "id": "qY3_-XIGQoKT" + } + }, + { + "cell_type": "markdown", + "source": [ + "While direct access to `obj_by_id` and `obj_by_type` is possible,\n", + "it is generally recommended to use the provided access methods for better\n", + "encapsulation. These methods include `find_by_id` and `foreach_type`.\n", + "\n", + "SHACLObjectSet offers the `find_by_id` method to retrieve a specific object\n", + "using its unique `spdxId`." + ], + "metadata": { + "id": "uqNOwXXAczeW" + } + }, + { + "cell_type": "code", + "source": [ + "obj = object_set.find_by_id(\"https://spdx.org/spdxdocs/Sbom1-b1b4ff24-5ada-4c22-a9c9-7bd7121978ff\")\n", + "print(obj)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "c-28HXbkudie", + "outputId": "267cf2f5-ec77-4fd5-fbe4-721b4d591cb7" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "None\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "SHACLObjectSet also provides `foreach_type`, a generator method that\n", + "iterates over all objects of a specified type.\n", + "\n", + "By default, `foreach_type` will also return instances of subclasses." + ], + "metadata": { + "id": "wyvA-i5fdB80" + } + }, + { + "cell_type": "code", + "source": [ + "for obj in object_set.foreach_type(\"Relationship\"):\n", + " print(obj)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Qjz-D9iz_p8n", + "outputId": "25136d1e-b2e0-4b95-85b0-929c761f1320" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd32')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd23')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd33')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd7')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd5')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd13')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd36')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd38')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd21')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd39')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd14')\n", + "LifecycleScopedRelationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd45')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd46')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd25')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd48')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd16')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd15')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd3')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd11')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd24')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd27')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd10')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd8')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd29')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd18')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd28')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd31')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd20')\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Notice the presence of `LifecycleScopedRelationship`, which is a subclass of `Relationship`." + ], + "metadata": { + "id": "24pEngfddGw1" + } + }, + { + "cell_type": "markdown", + "source": [ + "Set `match_subclass` argument to False, to exclude subclasses.\n" + ], + "metadata": { + "id": "6YbhPUpqdSZ9" + } + }, + { + "cell_type": "code", + "source": [ + "for obj in object_set.foreach_type(\"Relationship\", match_subclass=False):\n", + " print(obj)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CLSKgtC7yRmt", + "outputId": "2a310168-97c0-448d-d2bb-ef407fb5f16b" + }, + "execution_count": 14, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd32')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd23')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd33')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd7')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd5')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd13')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd36')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd38')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd21')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd39')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd14')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd46')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd25')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd48')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd16')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd15')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd3')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd11')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd24')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd27')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd10')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd8')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd29')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd18')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd28')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd31')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd20')\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Notice the absence of `LifecycleScopedRelationship` this time." + ], + "metadata": { + "id": "_uwUlUordW9R" + } + }, + { + "cell_type": "markdown", + "source": [ + "Because `foreach_type` is a generator, you can use it like this as well:\n", + "\n", + "\n" + ], + "metadata": { + "id": "pDSVRsAXdcqM" + } + }, + { + "cell_type": "code", + "source": [ + "objs = set(object_set.foreach_type(\"Relationship\", match_subclass=False))\n", + "print(len(objs))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1uVFmeYQAcSC", + "outputId": "bac9e6b2-ff5e-481a-ef68-fe974cad4e02" + }, + "execution_count": 15, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "27\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Accessing SPDX properties" + ], + "metadata": { + "id": "0GpZV9m1QzI1" + } + }, + { + "cell_type": "markdown", + "source": [ + "SPDX objects and their properties can be accessed directly from Python attributes.\n", + "\n", + "For example, this SpdxDocument `doc` has an attribute `creationInfo`\n", + "and the value of `creationInfo` is a CreationInfo object.\n", + "We can directly access `specVersion` attribute of the CreationInfo object like this." + ], + "metadata": { + "id": "vnpIoFf1dli8" + } + }, + { + "cell_type": "code", + "source": [ + "doc = list(object_set.foreach_type(\"SpdxDocument\", match_subclass=False))[0]\n", + "print(\"SPDX Spec Version:\", doc.creationInfo.specVersion)\n", + "\n", + "root_element = doc.rootElement[0] # assume we have only one root element\n", + "print(\"Root element ID:\", root_element.spdxId)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pXl50kABJXnw", + "outputId": "6712992f-9fe3-4100-8c47-92d6b171b0d9" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "SPDX Spec Version: 3.0.1\n", + "Root element ID: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "The SPDX specification defines the classes and properties of SPDX models.\n", + "\n", + "For example, the SpdxDocument class is detailed at: https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Classes/SpdxDocument/" + ], + "metadata": { + "id": "VgA7RhdiPZjl" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Put things together\n", + "\n", + "We can now perform basic object access.\n", + "Let's try to visualize an SPDX 3 SBOM.\n", + "\n", + "The example below will iterate through all relationships and print relationship types between SPDX objects." + ], + "metadata": { + "id": "rNdl2dqiPht8" + } + }, + { + "cell_type": "code", + "source": [ + "def print_object_info(obj, prefix=\"\"):\n", + " \"\"\"helper function to print a box containing object info.\n", + " obj can be either SHACLObject or just spdxId (string).\"\"\"\n", + " print(f\"{prefix}┏\" + \"━\"*50 + \"┅\")\n", + " if isinstance(obj, spdx3.SHACLObject):\n", + " print(f\"{prefix}┃ {obj.__class__.__name__}\")\n", + " print(f\"{prefix}┃ - name: {getattr(obj, 'name', 'N/A')}\")\n", + " print(f\"{prefix}┃ - spdxId: {obj.spdxId}\")\n", + " else: # assume it's an spdxId for an external object\n", + " print(f\"{prefix}┃ (Unresolved spdxId)\")\n", + " print(f\"{prefix}┃ - spdxId: {obj}\")\n", + " print(f\"{prefix}┗\" + \"━\"*50 + \"┅\")\n", + "\n", + "for rel in object_set.foreach_type(\"Relationship\"):\n", + " # spdx-python-model uses \"from_\" instead of \"from\" to avoid the Python keyword\n", + " from_obj = getattr(rel, \"from_\")\n", + " to_objs = getattr(rel, \"to\")\n", + " # print only the type name, not the full URL, for conciseness\n", + " rel_type = getattr(rel, \"relationshipType\").split(\"/\")[-1]\n", + "\n", + " print_object_info(from_obj)\n", + "\n", + " print( \" │\")\n", + " print(f\" {rel_type}\")\n", + " print( \" ↓\")\n", + "\n", + " for o in to_objs:\n", + " print_object_info(o, prefix=\" \")\n", + "\n", + " print()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pAgJZnDJU4Jf", + "outputId": "5bcfcb33-f0f0-4350-ffa0-ecbaa30bc62b" + }, + "execution_count": 17, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j SLF4J Binding\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j API\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_File\n", + "┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " generates\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_Package\n", + " ┃ - name: examplemaven\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " contains\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_File\n", + " ┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasTestCase\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_File\n", + " ┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDistributionArtifact\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_File\n", + " ┃ - name: examplemaven-0.0.1.jar\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd35\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j API\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDynamicLink\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_Package\n", + " ┃ - name: examplemaven\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ (Unresolved spdxId)\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1#SPDXRef-DOCUMENT\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " amendedBy\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ SpdxDocument\n", + " ┃ - name: examplemaven\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/document0\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_File\n", + "┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " dependsOn\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_Package\n", + " ┃ - name: JUnit\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: JUnit\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: SLF4J API Module\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDynamicLink\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_Package\n", + " ┃ - name: examplemaven\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: JUnit\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd49\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j Core\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDynamicLink\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_Package\n", + " ┃ - name: examplemaven\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_File\n", + "┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ SpdxDocument\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/document0\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " describes\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_Package\n", + " ┃ - name: examplemaven\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: examplemaven\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " contains\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_File\n", + " ┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j API\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: SLF4J API Module\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_File\n", + "┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_File\n", + "┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j SLF4J Binding\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDynamicLink\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ software_Package\n", + " ┃ - name: examplemaven\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j Core\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: SLF4J API Module\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j SLF4J Binding\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasConcludedLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "┃ software_Package\n", + "┃ - name: Apache Log4j Core\n", + "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " │\n", + " hasDeclaredLicense\n", + " ↓\n", + " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + " ┃ simplelicensing_LicenseExpression\n", + " ┃ - name: None\n", + " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## SPDX object creation and built-in validation\n", + "\n", + "To create an SPDX object,\n", + "simply use the standard constructor as you would with any native Python class." + ], + "metadata": { + "id": "D2PljHcL5iH_" + } + }, + { + "cell_type": "code", + "source": [ + "package = spdx3.ai_AIPackage()\n", + "package" + ], + "metadata": { + "id": "9hjARbwm6DUd", + "outputId": "d93e5e20-7271-4f09-9635-62c2511fa923", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 18, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "The spdx-python-model library features built-in SHACL-based validation derived\n", + "directly from the [SPDX 3 model][spdx-3-model].\n", + "This validation ensures data integrity by rejecting invalid types at runtime.\n", + "\n", + "For example, the `domain` property of [`/AI/AIPackage`][ai-package] has a\n", + "[cardinality] of 0..* (minimum count: 0, maximum count: unbounded).\n", + "This requires the value to be a list;\n", + "if a different type is provided, the library will raise a `TypeError`.\n", + "\n", + "[spdx-3-model]: https://spdx.org/rdf/3.0.1/spdx-model.ttl\n", + "[ai-package]: https://spdx.github.io/spdx-spec/v3.0.1/model/AI/Classes/AIPackage/\n", + "[cardinality]: https://spdx.github.io/spdx-spec/v3.0.1/conformance/" + ], + "metadata": { + "id": "68j1H6Fw6xtf" + } + }, + { + "cell_type": "code", + "source": [ + "package.ai_domain = \"nlp\"" + ], + "metadata": { + "id": "cAzCx9tV6wI-", + "outputId": "1c32fb63-fa35-4b0b-e442-9d439cb3e5de", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 318 + } + }, + "execution_count": 19, + "outputs": [ + { + "output_type": "error", + "ename": "TypeError", + "evalue": "Value must be one of type: list, ListProxy. Got str", + "traceback": [ + "\^[[0;31m---------------------------------------------------------------------------\^[[0m", + "\^[[0;31mTypeError\^[[0m Traceback (most recent call last)", + "\^[[0;32m/tmp/ipykernel_20264/179762956.py\^[[0m in \^[[0;36m\^[[0;34m()\^[[0m\n\^[[0;32m----> 1\^[[0;31m \^[[0mpackage\^[[0m\^[[0;34m.\^[[0m\^[[0mai_domain\^[[0m \^[[0;34m=\^[[0m \^[[0;34m\"nlp\"\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m", + "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36m__setattr__\^[[0;34m(self, name, value)\^[[0m\n\^[[1;32m 1061\^[[0m \^[[0;32mreturn\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 1062\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[0;32m-> 1063\^[[0;31m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0m__set\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0m__get_attr\^[[0m\^[[0;34m(\^[[0m\^[[0mname\^[[0m\^[[0;34m)\^[[0m\^[[0;34m,\^[[0m \^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 1064\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 1065\^[[0m \^[[0;32mdef\^[[0m \^[[0m__getattr__\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m,\^[[0m \^[[0mname\^[[0m\^[[0;34m:\^[[0m \^[[0mstr\^[[0m\^[[0;34m)\^[[0m \^[[0;34m->\^[[0m \^[[0mAny\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n", + "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36m__set\^[[0;34m(self, p, value)\^[[0m\n\^[[1;32m 1034\^[[0m )\n\^[[1;32m 1035\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[0;32m-> 1036\^[[0;31m \^[[0mp\^[[0m\^[[0;34m.\^[[0m\^[[0mprop\^[[0m\^[[0;34m.\^[[0m\^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 1037\^[[0m \^[[0;32mif\^[[0m \^[[0mp\^[[0m\^[[0;34m.\^[[0m\^[[0mdeprecated\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 1038\^[[0m warnings.warn(\n", + "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36mvalidate\^[[0;34m(self, value)\^[[0m\n\^[[1;32m 568\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 569\^[[0m \^[[0;32mdef\^[[0m \^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m,\^[[0m \^[[0mvalue\^[[0m\^[[0;34m:\^[[0m \^[[0mAny\^[[0m\^[[0;34m)\^[[0m \^[[0;34m->\^[[0m \^[[0;32mNone\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0;32m--> 570\^[[0;31m \^[[0msuper\^[[0m\^[[0;34m(\^[[0m\^[[0;34m)\^[[0m\^[[0;34m.\^[[0m\^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 571\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 572\^[[0m \^[[0;32mfor\^[[0m \^[[0mi\^[[0m \^[[0;32min\^[[0m \^[[0mvalue\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n", + "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36mvalidate\^[[0;34m(self, value)\^[[0m\n\^[[1;32m 76\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 77\^[[0m \^[[0;32mdef\^[[0m \^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m,\^[[0m \^[[0mvalue\^[[0m\^[[0;34m:\^[[0m \^[[0mAny\^[[0m\^[[0;34m)\^[[0m \^[[0;34m->\^[[0m \^[[0;32mNone\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0;32m---> 78\^[[0;31m \^[[0mcheck_type\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m,\^[[0m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0mVALID_TYPES\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 79\^[[0m if self.pattern is not None and not re.search(\n\^[[1;32m 80\^[[0m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0mpattern\^[[0m\^[[0;34m,\^[[0m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0mto_string\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n", + "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36mcheck_type\^[[0;34m(obj, types)\^[[0m\n\^[[1;32m 51\^[[0m \^[[0;32mif\^[[0m \^[[0;32mnot\^[[0m \^[[0misinstance\^[[0m\^[[0;34m(\^[[0m\^[[0mobj\^[[0m\^[[0;34m,\^[[0m \^[[0mtypes\^[[0m\^[[0;34m)\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 52\^[[0m \^[[0;32mif\^[[0m \^[[0misinstance\^[[0m\^[[0;34m(\^[[0m\^[[0mtypes\^[[0m\^[[0;34m,\^[[0m \^[[0;34m(\^[[0m\^[[0mlist\^[[0m\^[[0;34m,\^[[0m \^[[0mtuple\^[[0m\^[[0;34m)\^[[0m\^[[0;34m)\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0;32m---> 53\^[[0;31m raise TypeError(\n\^[[0m\^[[1;32m 54\^[[0m \^[[0;34mf\"Value must be one of type: {', '.join(t.__name__ for t in types)}. Got {type(obj).__name__}\"\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 55\^[[0m )\n", + "\^[[0;31mTypeError\^[[0m: Value must be one of type: list, ListProxy. Got str" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Even if there is only a single entry, you must provide it as a single-element\n", + "list to satisfy the property's cardinality:" + ], + "metadata": { + "id": "WWdZwqP9EfnP" + } + }, + { + "cell_type": "code", + "source": [ + "package.ai_domain = [\"nlp\"]\n", + "package.ai_domain" + ], + "metadata": { + "id": "H6LeOd3_D8rQ", + "outputId": "b9977956-3c4e-4493-a1ef-369b845e0167", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 20, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "['nlp']" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Refer to the [SPDX specification][spdx-spec]\n", + "for detailed information on property types and cardinality.\n", + "\n", + "[spdx-spec]: https://spdx.github.io/spdx-spec/" + ], + "metadata": { + "id": "quqpF4E0E6fv" + } + }, + { + "cell_type": "markdown", + "source": [ + "## That's it\n", + "\n", + "That's it for now! Hope you enjoyed the tutorial.\n", + "\n", + "Special thanks to Joshua Watt for the spdx-python-model library, making SPDX 3 more accessible for Python developers.\n", + "\n", + "Find more examples of how to use the library:\n", + "\n", + "- `spdx-python-model` tests: https://github.com/spdx/spdx-python-model/blob/main/tests/test_import.py\n", + "- `shacl2code` (which generates spdx-python-model's Python binding) tests: https://github.com/JPEWdev/shacl2code/blob/main/tests/test_python.py\n", + "\n", + "There are many ways to [get involved](https://github.com/spdx/spdx-3-model/blob/develop/Contributing.md) with the SPDX community. If you have questions about using SPDX, feel free to join one of our [online meetings](https://github.com/spdx/meetings/)!\n", + "\n", + "--\n", + "\n", + "Check out my current project, *[Pitloom](https://github.com/bact/pitloom)*, an SBOM generator for Python projects and AI models. It extracts metadata from fastText, GGUF, ONNX, PyTorch, and Safetensors models, and builds SBOMs directly from Hugging Face URLs. It also includes native Hatchling build-hook support and works with setuptools and Poetry." + ], + "metadata": { + "id": "lqg60qPeLaI3" + } + } + ] +} From b1575da79624de21a717e49d7fa994d45d8bf43e Mon Sep 17 00:00:00 2001 From: Arthit Suriyawongkul Date: Tue, 23 Jun 2026 15:25:18 +0100 Subject: [PATCH 2/3] Move tutorial dir to root Signed-off-by: Arthit Suriyawongkul --- .github/workflows/docs.yaml | 12 +- tutorial/using-spdx3.ipynb | 1438 +++++++++++++++++ www/index.html | 2 +- www/tutorial/spdx-python-model-tutorial.ipynb | 1438 ----------------- 4 files changed, 1445 insertions(+), 1445 deletions(-) create mode 100644 tutorial/using-spdx3.ipynb delete mode 100644 www/tutorial/spdx-python-model-tutorial.ipynb diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 5ab622b..ff43607 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -20,6 +20,7 @@ on: - '.github/workflows/docs.yaml' - 'gen/**' - 'src/**' + - 'tutorial/**' - 'www/**' - 'README.md' - 'pyproject.toml' @@ -112,30 +113,29 @@ jobs: - name: Build tutorials run: | - if [[ ! -d www/tutorial ]]; then + if [[ ! -d tutorial ]]; then exit 0 fi mkdir -p pages/tutorial - for nb in www/tutorial/*.ipynb; do + for nb in tutorial/*.ipynb; do jupyter nbconvert --to html --output-dir pages/tutorial "$nb" - cp "$nb" pages/tutorial/ done # Generate /tutorial/ index listing all tutorials. - if [[ ! -f www/tutorial/index.html ]]; then + if [[ ! -f tutorial/index.html ]]; then { echo '' echo '' - echo 'Tutorials – spdx-python-model' + echo 'Tutorials - spdx-python-model' echo '' echo '' echo '

spdx-python-model

' echo '

Tutorials

' } > pages/tutorial/index.html diff --git a/tutorial/using-spdx3.ipynb b/tutorial/using-spdx3.ipynb new file mode 100644 index 0000000..84613c5 --- /dev/null +++ b/tutorial/using-spdx3.ipynb @@ -0,0 +1,1438 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyOys2TFWeUKaj6M6TfFA+yY", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "source": [ + "# SPDX-FileCopyrightText: 2025-present Arthit Suriyawongkul \n", + "# SPDX-FileType: SOURCE\n", + "# SPDX-License-Identifier: Apache-2.0" + ], + "metadata": { + "id": "fTKOUcN_esq8" + }, + "execution_count": 1, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Using SPDX 3 in Python with spdx-python-model\n", + "\n", + "- This tutorial demonstrates how to use the [spdx-python-model][] library to:\n", + " - read the software bill of materials (SBOM) data in the [System Package Data Exchange (SPDX)][spdx] format from an [SPDX 3 JSON][spdx-3-json] file;\n", + " - access SPDX objects and their relationships; and\n", + " - create a simple SPDX object (also demonstrating the built-in data validation of the library)\n", + "\n", + "- The SBOM 3 JSON file examples are taken from [AI Example 2][ai-example-2] and [Software Example 14][sw-example-14] of the spdx-examples repository.\n", + "- This documentation is a contribution to the [NTIA Conformance Checker][ntia-conformance-checker] as part of the [Google Summer of Code 2025 program][gsoc-2025] (mentors: Gary O'Neall and John Speed Meyers).\n", + "\n", + "by [@bact][bact] - Arthit Suriyawongkul\n", + "\n", + "## Change log\n", + "\n", + "- Update: 21 May 2026 - fix handling of unresolved references (spdxId) ([reported](https://github.com/spdx/spdx-python-model/issues/34) by @vargenau and suggested a fix by @benjarobin - thank you both!)\n", + "- Update: 23 February 2026 - add a section on SPDX object creation and validation\n", + "- First published: 7 July 2025\n", + "\n", + "[spdx]: https://spdx.dev/use/specifications/\n", + "[spdx-python-model]: https://github.com/spdx/spdx-python-model\n", + "[spdx-3-json]: https://github.com/spdx/spdx-spec/blob/develop/docs/serializations.md#serialization-in-spdx-3-json\n", + "[ai-example-2]: https://github.com/spdx/spdx-examples/tree/master/ai/example02/\n", + "[sw-example-14]: https://github.com/spdx/spdx-examples/tree/master/software/example14/\n", + "[ntia-conformance-checker]: https://github.com/spdx/ntia-conformance-checker\n", + "[gsoc-2025]: https://summerofcode.withgoogle.com/programs/2025/projects/CeR3hQTq\n", + "[bact]: https://github.com/bact/" + ], + "metadata": { + "id": "09M0uv5_Bk7B" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Install the spdx-python-model library" + ], + "metadata": { + "id": "_ZRVMOBvQDuO" + } + }, + { + "cell_type": "code", + "source": [ + "!pip install spdx-python-model" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JsENPjgwHlHc", + "outputId": "0c5b73dc-52c8-4bb1-b60b-8a1640df09da" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: spdx-python-model in /usr/local/lib/python3.12/dist-packages (0.0.5)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Import and check library version" + ], + "metadata": { + "id": "0rhToD4DQQ0-" + } + }, + { + "cell_type": "code", + "source": [ + "from spdx_python_model import VERSION, bindings\n", + "\n", + "print(f\"spdx-python-model library version: {VERSION}\")\n", + "\n", + "print(\"Available SPDX bindings in spdx_python_model module:\")\n", + "for name in dir(bindings):\n", + " if not name.startswith(\"__\"):\n", + " print(name)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "977gguFuH1Nt", + "outputId": "71a52e69-ff00-4efc-e918-63e0e78fff7d" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "spdx-python-model library version: 0.0.5\n", + "Available SPDX bindings in spdx_python_model module:\n", + "v3_0_1\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "To use a Python binding, import a specific version of the model.\n", + "\n", + "For example, to import a binding for SPDX model version 3.0.1, import `v3_0_1`." + ], + "metadata": { + "id": "yuweD-jan0A8" + } + }, + { + "cell_type": "code", + "source": [ + "from spdx_python_model import v3_0_1" + ], + "metadata": { + "id": "MW10UJY2n7Ot" + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Or you may like to assign it to a versionless alias,\n", + "so you can update the version easily later.\n", + "\n", + "For example, this will set the import alias as `spdx3`." + ], + "metadata": { + "id": "v7E3Ys6BoBKQ" + } + }, + { + "cell_type": "code", + "source": [ + "from spdx_python_model import v3_0_1 as spdx3" + ], + "metadata": { + "id": "bgKEojPtn_yC" + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "If a new version (e.g., v3_1) is released, you only need to update the import line and can keep the rest of your code intact.\n", + "\n", + "For example, `from spdx_python_model import v3_1 as spdx3`." + ], + "metadata": { + "id": "PC_h1XmSpIF3" + } + }, + { + "cell_type": "markdown", + "source": [ + "Once imported, we can now access SPDX 3 model.\n", + "\n", + "Let's print some \"named individuals\" from the model." + ], + "metadata": { + "id": "9bWRkIYvpkzO" + } + }, + { + "cell_type": "code", + "source": [ + "list(spdx3.NAMED_INDIVIDUALS)[:8]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "jh4qYAep0d-L", + "outputId": "6334a3f2-9d54-428f-f92f-a89adc8950ca" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "['https://spdx.org/rdf/3.0.1/terms/Core/ExternalIdentifierType/email',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Dataset/DatasetAvailabilityType/registration',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/hasDocumentation',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/usesTool',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Dataset/DatasetType/audio',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Software/SbomType/analyzed',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/hasDataFile',\n", + " 'https://spdx.org/rdf/3.0.1/terms/Core/ExternalIdentifierType/urlScheme']" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Some of these could be entries in SPDX 3 vocabularies (enum)." + ], + "metadata": { + "id": "x6C0wvWRqDIP" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Read SPDX data from SPDX 3 JSON file" + ], + "metadata": { + "id": "LeTPh0lsQZBw" + } + }, + { + "cell_type": "markdown", + "source": [ + "The library offers a built-in JSON-LD deserializer.\n", + "To use it, provide the path to your SPDX 3 JSON file and an instance of SHACLObjectSet.\n", + "The deserializer will read the JSON file and populate the SHACLObjectSet.\n", + "\n", + "SHACLObjectSet holds SHACLObjects, which are the primary data structures for\n", + "interaction within this library. It also includes helpful utilities, such as\n", + "a generator (iterator) for accessing objects by their type.\n", + "\n", + "In this example, we will first download the JSON file from the `spdx-examples` repository." + ], + "metadata": { + "id": "wak3vYKObfXI" + } + }, + { + "cell_type": "code", + "source": [ + "from urllib.request import urlretrieve\n", + "\n", + "# url = \"https://raw.githubusercontent.com/spdx/spdx-examples/refs/heads/master/ai/example02/spdx3.0/sbom.spdx3.json\"\n", + "url = \"https://raw.githubusercontent.com/spdx/spdx-examples/refs/heads/master/software/example14/spdx3.0/examplemaven-0.0.1-enriched.spdx3.json\"\n", + "filename = \"sbom.spdx.json\"\n", + "filepath, _ = urlretrieve(url, filename) # download from url; get the filepath\n", + "\n", + "object_set = spdx3.SHACLObjectSet()\n", + "\n", + "with open(filepath, \"r\", encoding=\"utf-8\") as f:\n", + " spdx3.JSONLDDeserializer().read(f, object_set)\n", + "\n", + "print(object_set)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JQ9lTkNdIckN", + "outputId": "c5f14a5c-8db2-45d3-b93e-521d704d3823" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Some internal works of SHACLObjectSet" + ], + "metadata": { + "id": "8llGik8aQdct" + } + }, + { + "cell_type": "markdown", + "source": [ + "Internally SHACLObjectSet keeps objects in its `objects` set." + ], + "metadata": { + "id": "jbEuuu53b0Eb" + } + }, + { + "cell_type": "code", + "source": [ + "# see what is inside\n", + "print(list(object_set.objects)[:3])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "y1z84-MK6cnx", + "outputId": "cd938a15-85c0-4bc9-f0e9-7e880e769ff7" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[, , ]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Internally, for faster lookup, SHACLObjectSet maintains two indexes:\n", + "`obj_by_id` and `obj_by_type`.\n", + "\n", + "`obj_by_id` is a dictionary where:\n", + "- Keys are the `spdxId` property values of the objects.\n", + "- Values are the corresponding SHACLObject instances.\n", + "\n", + "`obj_by_type` is a dictionary where:\n", + "- Keys are the `type` property values of the objects.\n", + " (e.g., \"SpdxDocument\", \"software_Package\", \"simplelicensing_LicenseExpression\").\n", + " Note: Core Profile types do not require a prefix, while other Profiles do (e.g., \"software_\").\n", + "- Values are sets of tuples. Each tuple contains:\n", + " 1. A boolean indicating if the SHACLObject in this tuple is an exact type match (True)\n", + " or a subclass match (False); and\n", + " 2. The SHACLObject instance itself." + ], + "metadata": { + "id": "4sqtE2vVcDnx" + } + }, + { + "cell_type": "code", + "source": [ + "any_license_infos = object_set.obj_by_type[\"simplelicensing_AnyLicenseInfo\"]\n", + "print(any_license_infos)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xb-edy3n4eRh", + "outputId": "c06a9ae7-8f19-4398-e1f8-5862673a04f5" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{(False, ), (False, ), (False, ), (False, )}\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's begin with a quick check.\n", + "\n", + "For example, we can see how many SpdxDocument objects are present\n", + "and if it is according to the specification.\n", + "\n", + "See: https://spdx.github.io/spdx-spec/v3.0.1/serializations/#serialization-information" + ], + "metadata": { + "id": "S17Cuqt5cgiY" + } + }, + { + "cell_type": "code", + "source": [ + "spdx_documents = list(object_set.obj_by_type[\"SpdxDocument\"])\n", + "\n", + "if len(spdx_documents) > 1:\n", + " print(\"Warning: A serialization must not contain more than one SpdxDocument.\")\n", + "else:\n", + " print(\"Looks good.\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "S-Q78uecJ-m9", + "outputId": "7b81ac18-6b6c-47d7-de6a-195795da0898" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Looks good.\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Get all objects of type \"Relationship\", including its subclasses\n", + "relationships = object_set.obj_by_type[\"Relationship\"]\n", + "print(\"Relationship found:\", len(relationships))\n", + "for o in relationships:\n", + " print(o)\n", + "print()\n", + "\n", + "# Get all objects of type \"LifecycleScopedRelationship\", including its subclasses\n", + "lifecycle_scoped_relationships = object_set.obj_by_type[\"LifecycleScopedRelationship\"]\n", + "print(\"LifecycleScopedRelationship found:\", len(lifecycle_scoped_relationships))\n", + "for o in lifecycle_scoped_relationships:\n", + " print(o)\n", + "print()\n", + "\n", + "# Get all objects of type \"Softare/Package\", including its subclasses\n", + "packages = object_set.obj_by_type[\"software_Package\"]\n", + "print(\"software_Package found:\", len(packages))\n", + "for o in packages:\n", + " print(o)\n", + "\n", + "print()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1tiaPV-FKmZh", + "outputId": "0055c4f4-315c-43ce-a81f-9e6b4a55ee74" + }, + "execution_count": 11, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Relationship found: 28\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(False, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "\n", + "LifecycleScopedRelationship found: 1\n", + "(True, )\n", + "\n", + "software_Package found: 6\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "(True, )\n", + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## A proper way to get access to SPDX objects" + ], + "metadata": { + "id": "qY3_-XIGQoKT" + } + }, + { + "cell_type": "markdown", + "source": [ + "While direct access to `obj_by_id` and `obj_by_type` is possible,\n", + "it is generally recommended to use the provided access methods for better\n", + "encapsulation. These methods include `find_by_id` and `foreach_type`.\n", + "\n", + "SHACLObjectSet offers the `find_by_id` method to retrieve a specific object\n", + "using its unique `spdxId`." + ], + "metadata": { + "id": "uqNOwXXAczeW" + } + }, + { + "cell_type": "code", + "source": [ + "obj = object_set.find_by_id(\"https://spdx.org/spdxdocs/Sbom1-b1b4ff24-5ada-4c22-a9c9-7bd7121978ff\")\n", + "print(obj)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "c-28HXbkudie", + "outputId": "267cf2f5-ec77-4fd5-fbe4-721b4d591cb7" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "None\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "SHACLObjectSet also provides `foreach_type`, a generator method that\n", + "iterates over all objects of a specified type.\n", + "\n", + "By default, `foreach_type` will also return instances of subclasses." + ], + "metadata": { + "id": "wyvA-i5fdB80" + } + }, + { + "cell_type": "code", + "source": [ + "for obj in object_set.foreach_type(\"Relationship\"):\n", + " print(obj)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Qjz-D9iz_p8n", + "outputId": "25136d1e-b2e0-4b95-85b0-929c761f1320" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd32')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd23')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd33')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd7')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd5')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd13')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd36')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd38')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd21')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd39')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd14')\n", + "LifecycleScopedRelationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd45')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd46')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd25')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd48')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd16')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd15')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd3')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd11')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd24')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd27')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd10')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd8')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd29')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd18')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd28')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd31')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd20')\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Notice the presence of `LifecycleScopedRelationship`, which is a subclass of `Relationship`." + ], + "metadata": { + "id": "24pEngfddGw1" + } + }, + { + "cell_type": "markdown", + "source": [ + "Set `match_subclass` argument to False, to exclude subclasses.\n" + ], + "metadata": { + "id": "6YbhPUpqdSZ9" + } + }, + { + "cell_type": "code", + "source": [ + "for obj in object_set.foreach_type(\"Relationship\", match_subclass=False):\n", + " print(obj)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CLSKgtC7yRmt", + "outputId": "2a310168-97c0-448d-d2bb-ef407fb5f16b" + }, + "execution_count": 14, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd32')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd23')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd33')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd7')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd5')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd13')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd36')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd38')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd21')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd39')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd14')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd46')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd25')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd48')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd16')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd15')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd3')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd11')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd24')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd27')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd10')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd8')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd29')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd18')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd28')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd31')\n", + "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd20')\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Notice the absence of `LifecycleScopedRelationship` this time." + ], + "metadata": { + "id": "_uwUlUordW9R" + } + }, + { + "cell_type": "markdown", + "source": [ + "Because `foreach_type` is a generator, you can use it like this as well:\n", + "\n", + "\n" + ], + "metadata": { + "id": "pDSVRsAXdcqM" + } + }, + { + "cell_type": "code", + "source": [ + "objs = set(object_set.foreach_type(\"Relationship\", match_subclass=False))\n", + "print(len(objs))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1uVFmeYQAcSC", + "outputId": "bac9e6b2-ff5e-481a-ef68-fe974cad4e02" + }, + "execution_count": 15, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "27\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Accessing SPDX properties" + ], + "metadata": { + "id": "0GpZV9m1QzI1" + } + }, + { + "cell_type": "markdown", + "source": [ + "SPDX objects and their properties can be accessed directly from Python attributes.\n", + "\n", + "For example, this SpdxDocument `doc` has an attribute `creationInfo`\n", + "and the value of `creationInfo` is a CreationInfo object.\n", + "We can directly access `specVersion` attribute of the CreationInfo object like this." + ], + "metadata": { + "id": "vnpIoFf1dli8" + } + }, + { + "cell_type": "code", + "source": [ + "doc = list(object_set.foreach_type(\"SpdxDocument\", match_subclass=False))[0]\n", + "print(\"SPDX Spec Version:\", doc.creationInfo.specVersion)\n", + "\n", + "root_element = doc.rootElement[0] # assume we have only one root element\n", + "print(\"Root element ID:\", root_element.spdxId)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pXl50kABJXnw", + "outputId": "6712992f-9fe3-4100-8c47-92d6b171b0d9" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "SPDX Spec Version: 3.0.1\n", + "Root element ID: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "The SPDX specification defines the classes and properties of SPDX models.\n", + "\n", + "For example, the SpdxDocument class is detailed at: https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Classes/SpdxDocument/" + ], + "metadata": { + "id": "VgA7RhdiPZjl" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Put things together\n", + "\n", + "We can now perform basic object access.\n", + "Let's try to visualize an SPDX 3 SBOM.\n", + "\n", + "The example below will iterate through all relationships and print relationship types between SPDX objects." + ], + "metadata": { + "id": "rNdl2dqiPht8" + } + }, + { + "cell_type": "code", + "source": [ + "def print_object_info(obj, prefix=\"\"):\n", + " \"\"\"helper function to print a box containing object info.\n", + " obj can be either SHACLObject or just spdxId (string).\"\"\"\n", + " print(f\"{prefix}\u250f\" + \"\u2501\"*50 + \"\u2505\")\n", + " if isinstance(obj, spdx3.SHACLObject):\n", + " print(f\"{prefix}\u2503 {obj.__class__.__name__}\")\n", + " print(f\"{prefix}\u2503 - name: {getattr(obj, 'name', 'N/A')}\")\n", + " print(f\"{prefix}\u2503 - spdxId: {obj.spdxId}\")\n", + " else: # assume it's an spdxId for an external object\n", + " print(f\"{prefix}\u2503 (Unresolved spdxId)\")\n", + " print(f\"{prefix}\u2503 - spdxId: {obj}\")\n", + " print(f\"{prefix}\u2517\" + \"\u2501\"*50 + \"\u2505\")\n", + "\n", + "for rel in object_set.foreach_type(\"Relationship\"):\n", + " # spdx-python-model uses \"from_\" instead of \"from\" to avoid the Python keyword\n", + " from_obj = getattr(rel, \"from_\")\n", + " to_objs = getattr(rel, \"to\")\n", + " # print only the type name, not the full URL, for conciseness\n", + " rel_type = getattr(rel, \"relationshipType\").split(\"/\")[-1]\n", + "\n", + " print_object_info(from_obj)\n", + "\n", + " print( \" \u2502\")\n", + " print(f\" {rel_type}\")\n", + " print( \" \u2193\")\n", + "\n", + " for o in to_objs:\n", + " print_object_info(o, prefix=\" \")\n", + "\n", + " print()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pAgJZnDJU4Jf", + "outputId": "5bcfcb33-f0f0-4350-ffa0-ecbaa30bc62b" + }, + "execution_count": 17, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j SLF4J Binding\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j API\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_File\n", + "\u2503 - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " generates\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_Package\n", + " \u2503 - name: examplemaven\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " contains\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_File\n", + " \u2503 - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasTestCase\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_File\n", + " \u2503 - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDistributionArtifact\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_File\n", + " \u2503 - name: examplemaven-0.0.1.jar\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd35\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j API\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDynamicLink\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_Package\n", + " \u2503 - name: examplemaven\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 (Unresolved spdxId)\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1#SPDXRef-DOCUMENT\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " amendedBy\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 SpdxDocument\n", + " \u2503 - name: examplemaven\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/document0\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_File\n", + "\u2503 - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " dependsOn\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_Package\n", + " \u2503 - name: JUnit\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: JUnit\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: SLF4J API Module\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDynamicLink\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_Package\n", + " \u2503 - name: examplemaven\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: JUnit\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd49\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j Core\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDynamicLink\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_Package\n", + " \u2503 - name: examplemaven\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_File\n", + "\u2503 - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 SpdxDocument\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/document0\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " describes\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_Package\n", + " \u2503 - name: examplemaven\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: examplemaven\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " contains\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_File\n", + " \u2503 - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j API\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: SLF4J API Module\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_File\n", + "\u2503 - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_File\n", + "\u2503 - name: ./src/main/java/org/spdx/examplemaven/App.java\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j SLF4J Binding\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDynamicLink\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 software_Package\n", + " \u2503 - name: examplemaven\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j Core\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: SLF4J API Module\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j SLF4J Binding\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasConcludedLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n", + "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\u2503 software_Package\n", + "\u2503 - name: Apache Log4j Core\n", + "\u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", + "\u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2502\n", + " hasDeclaredLicense\n", + " \u2193\n", + " \u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + " \u2503 simplelicensing_LicenseExpression\n", + " \u2503 - name: None\n", + " \u2503 - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", + " \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2505\n", + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## SPDX object creation and built-in validation\n", + "\n", + "To create an SPDX object,\n", + "simply use the standard constructor as you would with any native Python class." + ], + "metadata": { + "id": "D2PljHcL5iH_" + } + }, + { + "cell_type": "code", + "source": [ + "package = spdx3.ai_AIPackage()\n", + "package" + ], + "metadata": { + "id": "9hjARbwm6DUd", + "outputId": "d93e5e20-7271-4f09-9635-62c2511fa923", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 18, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "The spdx-python-model library features built-in SHACL-based validation derived\n", + "directly from the [SPDX 3 model][spdx-3-model].\n", + "This validation ensures data integrity by rejecting invalid types at runtime.\n", + "\n", + "For example, the `domain` property of [`/AI/AIPackage`][ai-package] has a\n", + "[cardinality] of 0..* (minimum count: 0, maximum count: unbounded).\n", + "This requires the value to be a list;\n", + "if a different type is provided, the library will raise a `TypeError`.\n", + "\n", + "[spdx-3-model]: https://spdx.org/rdf/3.0.1/spdx-model.ttl\n", + "[ai-package]: https://spdx.github.io/spdx-spec/v3.0.1/model/AI/Classes/AIPackage/\n", + "[cardinality]: https://spdx.github.io/spdx-spec/v3.0.1/conformance/" + ], + "metadata": { + "id": "68j1H6Fw6xtf" + } + }, + { + "cell_type": "code", + "source": [ + "package.ai_domain = \"nlp\"" + ], + "metadata": { + "id": "cAzCx9tV6wI-", + "outputId": "1c32fb63-fa35-4b0b-e442-9d439cb3e5de", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 318 + } + }, + "execution_count": 19, + "outputs": [ + { + "output_type": "error", + "ename": "TypeError", + "evalue": "Value must be one of type: list, ListProxy. Got str", + "traceback": [ + "\\^[[0;31m---------------------------------------------------------------------------\\^[[0m", + "\\^[[0;31mTypeError\\^[[0m Traceback (most recent call last)", + "\\^[[0;32m/tmp/ipykernel_20264/179762956.py\\^[[0m in \\^[[0;36m\\^[[0;34m()\\^[[0m\n\\^[[0;32m----> 1\\^[[0;31m \\^[[0mpackage\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mai_domain\\^[[0m \\^[[0;34m=\\^[[0m \\^[[0;34m\"nlp\"\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0m", + "\\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\\^[[0m in \\^[[0;36m__setattr__\\^[[0;34m(self, name, value)\\^[[0m\n\\^[[1;32m 1061\\^[[0m \\^[[0;32mreturn\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 1062\\^[[0m \\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0;32m-> 1063\\^[[0;31m \\^[[0mself\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0m__set\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mself\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0m__get_attr\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mname\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mvalue\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0m\\^[[1;32m 1064\\^[[0m \\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 1065\\^[[0m \\^[[0;32mdef\\^[[0m \\^[[0m__getattr__\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mself\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mname\\^[[0m\\^[[0;34m:\\^[[0m \\^[[0mstr\\^[[0m\\^[[0;34m)\\^[[0m \\^[[0;34m->\\^[[0m \\^[[0mAny\\^[[0m\\^[[0;34m:\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n", + "\\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\\^[[0m in \\^[[0;36m__set\\^[[0;34m(self, p, value)\\^[[0m\n\\^[[1;32m 1034\\^[[0m )\n\\^[[1;32m 1035\\^[[0m \\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0;32m-> 1036\\^[[0;31m \\^[[0mp\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mprop\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mvalidate\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mvalue\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0m\\^[[1;32m 1037\\^[[0m \\^[[0;32mif\\^[[0m \\^[[0mp\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mdeprecated\\^[[0m\\^[[0;34m:\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 1038\\^[[0m warnings.warn(\n", + "\\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\\^[[0m in \\^[[0;36mvalidate\\^[[0;34m(self, value)\\^[[0m\n\\^[[1;32m 568\\^[[0m \\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 569\\^[[0m \\^[[0;32mdef\\^[[0m \\^[[0mvalidate\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mself\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mvalue\\^[[0m\\^[[0;34m:\\^[[0m \\^[[0mAny\\^[[0m\\^[[0;34m)\\^[[0m \\^[[0;34m->\\^[[0m \\^[[0;32mNone\\^[[0m\\^[[0;34m:\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0;32m--> 570\\^[[0;31m \\^[[0msuper\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mvalidate\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mvalue\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0m\\^[[1;32m 571\\^[[0m \\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 572\\^[[0m \\^[[0;32mfor\\^[[0m \\^[[0mi\\^[[0m \\^[[0;32min\\^[[0m \\^[[0mvalue\\^[[0m\\^[[0;34m:\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n", + "\\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\\^[[0m in \\^[[0;36mvalidate\\^[[0;34m(self, value)\\^[[0m\n\\^[[1;32m 76\\^[[0m \\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 77\\^[[0m \\^[[0;32mdef\\^[[0m \\^[[0mvalidate\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mself\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mvalue\\^[[0m\\^[[0;34m:\\^[[0m \\^[[0mAny\\^[[0m\\^[[0;34m)\\^[[0m \\^[[0;34m->\\^[[0m \\^[[0;32mNone\\^[[0m\\^[[0;34m:\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0;32m---> 78\\^[[0;31m \\^[[0mcheck_type\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mvalue\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mself\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mVALID_TYPES\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0m\\^[[1;32m 79\\^[[0m if self.pattern is not None and not re.search(\n\\^[[1;32m 80\\^[[0m \\^[[0mself\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mpattern\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mself\\^[[0m\\^[[0;34m.\\^[[0m\\^[[0mto_string\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mvalue\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n", + "\\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\\^[[0m in \\^[[0;36mcheck_type\\^[[0;34m(obj, types)\\^[[0m\n\\^[[1;32m 51\\^[[0m \\^[[0;32mif\\^[[0m \\^[[0;32mnot\\^[[0m \\^[[0misinstance\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mobj\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mtypes\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m:\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 52\\^[[0m \\^[[0;32mif\\^[[0m \\^[[0misinstance\\^[[0m\\^[[0;34m(\\^[[0m\\^[[0mtypes\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0;34m(\\^[[0m\\^[[0mlist\\^[[0m\\^[[0;34m,\\^[[0m \\^[[0mtuple\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m)\\^[[0m\\^[[0;34m:\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[0;32m---> 53\\^[[0;31m raise TypeError(\n\\^[[0m\\^[[1;32m 54\\^[[0m \\^[[0;34mf\"Value must be one of type: {', '.join(t.__name__ for t in types)}. Got {type(obj).__name__}\"\\^[[0m\\^[[0;34m\\^[[0m\\^[[0;34m\\^[[0m\\^[[0m\n\\^[[1;32m 55\\^[[0m )\n", + "\\^[[0;31mTypeError\\^[[0m: Value must be one of type: list, ListProxy. Got str" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Even if there is only a single entry, you must provide it as a single-element\n", + "list to satisfy the property's cardinality:" + ], + "metadata": { + "id": "WWdZwqP9EfnP" + } + }, + { + "cell_type": "code", + "source": [ + "package.ai_domain = [\"nlp\"]\n", + "package.ai_domain" + ], + "metadata": { + "id": "H6LeOd3_D8rQ", + "outputId": "b9977956-3c4e-4493-a1ef-369b845e0167", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 20, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "['nlp']" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Refer to the [SPDX specification][spdx-spec]\n", + "for detailed information on property types and cardinality.\n", + "\n", + "[spdx-spec]: https://spdx.github.io/spdx-spec/" + ], + "metadata": { + "id": "quqpF4E0E6fv" + } + }, + { + "cell_type": "markdown", + "source": [ + "## That's it\n", + "\n", + "That's it for now! Hope you enjoyed the tutorial.\n", + "\n", + "Special thanks to Joshua Watt for the spdx-python-model library, making SPDX 3 more accessible for Python developers.\n", + "\n", + "Find more examples of how to use the library:\n", + "\n", + "- `spdx-python-model` tests: https://github.com/spdx/spdx-python-model/blob/main/tests/test_import.py\n", + "- `shacl2code` (which generates spdx-python-model's Python binding) tests: https://github.com/JPEWdev/shacl2code/blob/main/tests/test_python.py\n", + "\n", + "There are many ways to [get involved](https://github.com/spdx/spdx-3-model/blob/develop/Contributing.md) with the SPDX community. If you have questions about using SPDX, feel free to join one of our [online meetings](https://github.com/spdx/meetings/)!\n", + "\n", + "--\n", + "\n", + "Check out my current project, *[Pitloom](https://github.com/bact/pitloom)*, an SBOM generator for Python projects and AI models. It extracts metadata from fastText, GGUF, ONNX, PyTorch, and Safetensors models, and builds SBOMs directly from Hugging Face URLs. It also includes native Hatchling build-hook support and works with setuptools and Poetry." + ], + "metadata": { + "id": "lqg60qPeLaI3" + } + } + ] +} \ No newline at end of file diff --git a/www/index.html b/www/index.html index 8fc095c..92ab7a2 100644 --- a/www/index.html +++ b/www/index.html @@ -53,7 +53,7 @@

Install

Tutorial

API documentation

diff --git a/www/tutorial/spdx-python-model-tutorial.ipynb b/www/tutorial/spdx-python-model-tutorial.ipynb deleted file mode 100644 index 70f1b1d..0000000 --- a/www/tutorial/spdx-python-model-tutorial.ipynb +++ /dev/null @@ -1,1438 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [], - "authorship_tag": "ABX9TyOys2TFWeUKaj6M6TfFA+yY", - "include_colab_link": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "code", - "source": [ - "# SPDX-FileCopyrightText: 2025-present Arthit Suriyawongkul \n", - "# SPDX-FileType: SOURCE\n", - "# SPDX-License-Identifier: Apache-2.0" - ], - "metadata": { - "id": "fTKOUcN_esq8" - }, - "execution_count": 1, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# Using SPDX 3 in Python with spdx-python-model\n", - "\n", - "- This tutorial demonstrates how to use the [spdx-python-model][] library to:\n", - " - read the software bill of materials (SBOM) data in the [System Package Data Exchange (SPDX)][spdx] format from an [SPDX 3 JSON][spdx-3-json] file;\n", - " - access SPDX objects and their relationships; and\n", - " - create a simple SPDX object (also demonstrating the built-in data validation of the library)\n", - "\n", - "- The SBOM 3 JSON file examples are taken from [AI Example 2][ai-example-2] and [Software Example 14][sw-example-14] of the spdx-examples repository.\n", - "- This documentation is a contribution to the [NTIA Conformance Checker][ntia-conformance-checker] as part of the [Google Summer of Code 2025 program][gsoc-2025] (mentors: Gary O'Neall and John Speed Meyers).\n", - "\n", - "by [@bact][bact] - Arthit Suriyawongkul\n", - "\n", - "## Change log\n", - "\n", - "- Update: 21 May 2026 - fix handling of unresolved references (spdxId) ([reported](https://github.com/spdx/spdx-python-model/issues/34) by @vargenau and suggested a fix by @benjarobin - thank you both!)\n", - "- Update: 23 February 2026 - add a section on SPDX object creation and validation\n", - "- First published: 7 July 2025\n", - "\n", - "[spdx]: https://spdx.dev/use/specifications/\n", - "[spdx-python-model]: https://github.com/spdx/spdx-python-model\n", - "[spdx-3-json]: https://github.com/spdx/spdx-spec/blob/develop/docs/serializations.md#serialization-in-spdx-3-json\n", - "[ai-example-2]: https://github.com/spdx/spdx-examples/tree/master/ai/example02/\n", - "[sw-example-14]: https://github.com/spdx/spdx-examples/tree/master/software/example14/\n", - "[ntia-conformance-checker]: https://github.com/spdx/ntia-conformance-checker\n", - "[gsoc-2025]: https://summerofcode.withgoogle.com/programs/2025/projects/CeR3hQTq\n", - "[bact]: https://github.com/bact/" - ], - "metadata": { - "id": "09M0uv5_Bk7B" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Install the spdx-python-model library" - ], - "metadata": { - "id": "_ZRVMOBvQDuO" - } - }, - { - "cell_type": "code", - "source": [ - "!pip install spdx-python-model" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "JsENPjgwHlHc", - "outputId": "0c5b73dc-52c8-4bb1-b60b-8a1640df09da" - }, - "execution_count": 2, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Requirement already satisfied: spdx-python-model in /usr/local/lib/python3.12/dist-packages (0.0.5)\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "## Import and check library version" - ], - "metadata": { - "id": "0rhToD4DQQ0-" - } - }, - { - "cell_type": "code", - "source": [ - "from spdx_python_model import VERSION, bindings\n", - "\n", - "print(f\"spdx-python-model library version: {VERSION}\")\n", - "\n", - "print(\"Available SPDX bindings in spdx_python_model module:\")\n", - "for name in dir(bindings):\n", - " if not name.startswith(\"__\"):\n", - " print(name)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "977gguFuH1Nt", - "outputId": "71a52e69-ff00-4efc-e918-63e0e78fff7d" - }, - "execution_count": 3, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "spdx-python-model library version: 0.0.5\n", - "Available SPDX bindings in spdx_python_model module:\n", - "v3_0_1\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "To use a Python binding, import a specific version of the model.\n", - "\n", - "For example, to import a binding for SPDX model version 3.0.1, import `v3_0_1`." - ], - "metadata": { - "id": "yuweD-jan0A8" - } - }, - { - "cell_type": "code", - "source": [ - "from spdx_python_model import v3_0_1" - ], - "metadata": { - "id": "MW10UJY2n7Ot" - }, - "execution_count": 4, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "Or you may like to assign it to a versionless alias,\n", - "so you can update the version easily later.\n", - "\n", - "For example, this will set the import alias as `spdx3`." - ], - "metadata": { - "id": "v7E3Ys6BoBKQ" - } - }, - { - "cell_type": "code", - "source": [ - "from spdx_python_model import v3_0_1 as spdx3" - ], - "metadata": { - "id": "bgKEojPtn_yC" - }, - "execution_count": 5, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "If a new version (e.g., v3_1) is released, you only need to update the import line and can keep the rest of your code intact.\n", - "\n", - "For example, `from spdx_python_model import v3_1 as spdx3`." - ], - "metadata": { - "id": "PC_h1XmSpIF3" - } - }, - { - "cell_type": "markdown", - "source": [ - "Once imported, we can now access SPDX 3 model.\n", - "\n", - "Let's print some \"named individuals\" from the model." - ], - "metadata": { - "id": "9bWRkIYvpkzO" - } - }, - { - "cell_type": "code", - "source": [ - "list(spdx3.NAMED_INDIVIDUALS)[:8]" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "jh4qYAep0d-L", - "outputId": "6334a3f2-9d54-428f-f92f-a89adc8950ca" - }, - "execution_count": 6, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "['https://spdx.org/rdf/3.0.1/terms/Core/ExternalIdentifierType/email',\n", - " 'https://spdx.org/rdf/3.0.1/terms/Dataset/DatasetAvailabilityType/registration',\n", - " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/hasDocumentation',\n", - " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/usesTool',\n", - " 'https://spdx.org/rdf/3.0.1/terms/Dataset/DatasetType/audio',\n", - " 'https://spdx.org/rdf/3.0.1/terms/Software/SbomType/analyzed',\n", - " 'https://spdx.org/rdf/3.0.1/terms/Core/RelationshipType/hasDataFile',\n", - " 'https://spdx.org/rdf/3.0.1/terms/Core/ExternalIdentifierType/urlScheme']" - ] - }, - "metadata": {}, - "execution_count": 6 - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "Some of these could be entries in SPDX 3 vocabularies (enum)." - ], - "metadata": { - "id": "x6C0wvWRqDIP" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Read SPDX data from SPDX 3 JSON file" - ], - "metadata": { - "id": "LeTPh0lsQZBw" - } - }, - { - "cell_type": "markdown", - "source": [ - "The library offers a built-in JSON-LD deserializer.\n", - "To use it, provide the path to your SPDX 3 JSON file and an instance of SHACLObjectSet.\n", - "The deserializer will read the JSON file and populate the SHACLObjectSet.\n", - "\n", - "SHACLObjectSet holds SHACLObjects, which are the primary data structures for\n", - "interaction within this library. It also includes helpful utilities, such as\n", - "a generator (iterator) for accessing objects by their type.\n", - "\n", - "In this example, we will first download the JSON file from the `spdx-examples` repository." - ], - "metadata": { - "id": "wak3vYKObfXI" - } - }, - { - "cell_type": "code", - "source": [ - "from urllib.request import urlretrieve\n", - "\n", - "# url = \"https://raw.githubusercontent.com/spdx/spdx-examples/refs/heads/master/ai/example02/spdx3.0/sbom.spdx3.json\"\n", - "url = \"https://raw.githubusercontent.com/spdx/spdx-examples/refs/heads/master/software/example14/spdx3.0/examplemaven-0.0.1-enriched.spdx3.json\"\n", - "filename = \"sbom.spdx.json\"\n", - "filepath, _ = urlretrieve(url, filename) # download from url; get the filepath\n", - "\n", - "object_set = spdx3.SHACLObjectSet()\n", - "\n", - "with open(filepath, \"r\", encoding=\"utf-8\") as f:\n", - " spdx3.JSONLDDeserializer().read(f, object_set)\n", - "\n", - "print(object_set)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "JQ9lTkNdIckN", - "outputId": "c5f14a5c-8db2-45d3-b93e-521d704d3823" - }, - "execution_count": 7, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "## Some internal works of SHACLObjectSet" - ], - "metadata": { - "id": "8llGik8aQdct" - } - }, - { - "cell_type": "markdown", - "source": [ - "Internally SHACLObjectSet keeps objects in its `objects` set." - ], - "metadata": { - "id": "jbEuuu53b0Eb" - } - }, - { - "cell_type": "code", - "source": [ - "# see what is inside\n", - "print(list(object_set.objects)[:3])" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "y1z84-MK6cnx", - "outputId": "cd938a15-85c0-4bc9-f0e9-7e880e769ff7" - }, - "execution_count": 8, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "[, , ]\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "Internally, for faster lookup, SHACLObjectSet maintains two indexes:\n", - "`obj_by_id` and `obj_by_type`.\n", - "\n", - "`obj_by_id` is a dictionary where:\n", - "- Keys are the `spdxId` property values of the objects.\n", - "- Values are the corresponding SHACLObject instances.\n", - "\n", - "`obj_by_type` is a dictionary where:\n", - "- Keys are the `type` property values of the objects.\n", - " (e.g., \"SpdxDocument\", \"software_Package\", \"simplelicensing_LicenseExpression\").\n", - " Note: Core Profile types do not require a prefix, while other Profiles do (e.g., \"software_\").\n", - "- Values are sets of tuples. Each tuple contains:\n", - " 1. A boolean indicating if the SHACLObject in this tuple is an exact type match (True)\n", - " or a subclass match (False); and\n", - " 2. The SHACLObject instance itself." - ], - "metadata": { - "id": "4sqtE2vVcDnx" - } - }, - { - "cell_type": "code", - "source": [ - "any_license_infos = object_set.obj_by_type[\"simplelicensing_AnyLicenseInfo\"]\n", - "print(any_license_infos)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "xb-edy3n4eRh", - "outputId": "c06a9ae7-8f19-4398-e1f8-5862673a04f5" - }, - "execution_count": 9, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "{(False, ), (False, ), (False, ), (False, )}\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "Let's begin with a quick check.\n", - "\n", - "For example, we can see how many SpdxDocument objects are present\n", - "and if it is according to the specification.\n", - "\n", - "See: https://spdx.github.io/spdx-spec/v3.0.1/serializations/#serialization-information" - ], - "metadata": { - "id": "S17Cuqt5cgiY" - } - }, - { - "cell_type": "code", - "source": [ - "spdx_documents = list(object_set.obj_by_type[\"SpdxDocument\"])\n", - "\n", - "if len(spdx_documents) > 1:\n", - " print(\"Warning: A serialization must not contain more than one SpdxDocument.\")\n", - "else:\n", - " print(\"Looks good.\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "S-Q78uecJ-m9", - "outputId": "7b81ac18-6b6c-47d7-de6a-195795da0898" - }, - "execution_count": 10, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Looks good.\n" - ] - } - ] - }, - { - "cell_type": "code", - "source": [ - "# Get all objects of type \"Relationship\", including its subclasses\n", - "relationships = object_set.obj_by_type[\"Relationship\"]\n", - "print(\"Relationship found:\", len(relationships))\n", - "for o in relationships:\n", - " print(o)\n", - "print()\n", - "\n", - "# Get all objects of type \"LifecycleScopedRelationship\", including its subclasses\n", - "lifecycle_scoped_relationships = object_set.obj_by_type[\"LifecycleScopedRelationship\"]\n", - "print(\"LifecycleScopedRelationship found:\", len(lifecycle_scoped_relationships))\n", - "for o in lifecycle_scoped_relationships:\n", - " print(o)\n", - "print()\n", - "\n", - "# Get all objects of type \"Softare/Package\", including its subclasses\n", - "packages = object_set.obj_by_type[\"software_Package\"]\n", - "print(\"software_Package found:\", len(packages))\n", - "for o in packages:\n", - " print(o)\n", - "\n", - "print()" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "1tiaPV-FKmZh", - "outputId": "0055c4f4-315c-43ce-a81f-9e6b4a55ee74" - }, - "execution_count": 11, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Relationship found: 28\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(False, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "\n", - "LifecycleScopedRelationship found: 1\n", - "(True, )\n", - "\n", - "software_Package found: 6\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "(True, )\n", - "\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "## A proper way to get access to SPDX objects" - ], - "metadata": { - "id": "qY3_-XIGQoKT" - } - }, - { - "cell_type": "markdown", - "source": [ - "While direct access to `obj_by_id` and `obj_by_type` is possible,\n", - "it is generally recommended to use the provided access methods for better\n", - "encapsulation. These methods include `find_by_id` and `foreach_type`.\n", - "\n", - "SHACLObjectSet offers the `find_by_id` method to retrieve a specific object\n", - "using its unique `spdxId`." - ], - "metadata": { - "id": "uqNOwXXAczeW" - } - }, - { - "cell_type": "code", - "source": [ - "obj = object_set.find_by_id(\"https://spdx.org/spdxdocs/Sbom1-b1b4ff24-5ada-4c22-a9c9-7bd7121978ff\")\n", - "print(obj)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "c-28HXbkudie", - "outputId": "267cf2f5-ec77-4fd5-fbe4-721b4d591cb7" - }, - "execution_count": 12, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "None\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "SHACLObjectSet also provides `foreach_type`, a generator method that\n", - "iterates over all objects of a specified type.\n", - "\n", - "By default, `foreach_type` will also return instances of subclasses." - ], - "metadata": { - "id": "wyvA-i5fdB80" - } - }, - { - "cell_type": "code", - "source": [ - "for obj in object_set.foreach_type(\"Relationship\"):\n", - " print(obj)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "Qjz-D9iz_p8n", - "outputId": "25136d1e-b2e0-4b95-85b0-929c761f1320" - }, - "execution_count": 13, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd32')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd23')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd33')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd7')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd5')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd13')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd36')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd38')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd21')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd39')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd14')\n", - "LifecycleScopedRelationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd45')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd46')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd25')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd48')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd16')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd15')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd3')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd11')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd24')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd27')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd10')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd8')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd29')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd18')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd28')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd31')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd20')\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "Notice the presence of `LifecycleScopedRelationship`, which is a subclass of `Relationship`." - ], - "metadata": { - "id": "24pEngfddGw1" - } - }, - { - "cell_type": "markdown", - "source": [ - "Set `match_subclass` argument to False, to exclude subclasses.\n" - ], - "metadata": { - "id": "6YbhPUpqdSZ9" - } - }, - { - "cell_type": "code", - "source": [ - "for obj in object_set.foreach_type(\"Relationship\", match_subclass=False):\n", - " print(obj)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "CLSKgtC7yRmt", - "outputId": "2a310168-97c0-448d-d2bb-ef407fb5f16b" - }, - "execution_count": 14, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd32')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd23')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd33')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd7')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd5')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd13')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd36')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd38')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd21')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd39')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd14')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd46')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd25')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd48')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd16')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd15')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd3')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd11')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd24')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd27')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd10')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd8')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd29')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd18')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd28')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd31')\n", - "Relationship(@id='http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd20')\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "Notice the absence of `LifecycleScopedRelationship` this time." - ], - "metadata": { - "id": "_uwUlUordW9R" - } - }, - { - "cell_type": "markdown", - "source": [ - "Because `foreach_type` is a generator, you can use it like this as well:\n", - "\n", - "\n" - ], - "metadata": { - "id": "pDSVRsAXdcqM" - } - }, - { - "cell_type": "code", - "source": [ - "objs = set(object_set.foreach_type(\"Relationship\", match_subclass=False))\n", - "print(len(objs))" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "1uVFmeYQAcSC", - "outputId": "bac9e6b2-ff5e-481a-ef68-fe974cad4e02" - }, - "execution_count": 15, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "27\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "## Accessing SPDX properties" - ], - "metadata": { - "id": "0GpZV9m1QzI1" - } - }, - { - "cell_type": "markdown", - "source": [ - "SPDX objects and their properties can be accessed directly from Python attributes.\n", - "\n", - "For example, this SpdxDocument `doc` has an attribute `creationInfo`\n", - "and the value of `creationInfo` is a CreationInfo object.\n", - "We can directly access `specVersion` attribute of the CreationInfo object like this." - ], - "metadata": { - "id": "vnpIoFf1dli8" - } - }, - { - "cell_type": "code", - "source": [ - "doc = list(object_set.foreach_type(\"SpdxDocument\", match_subclass=False))[0]\n", - "print(\"SPDX Spec Version:\", doc.creationInfo.specVersion)\n", - "\n", - "root_element = doc.rootElement[0] # assume we have only one root element\n", - "print(\"Root element ID:\", root_element.spdxId)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "pXl50kABJXnw", - "outputId": "6712992f-9fe3-4100-8c47-92d6b171b0d9" - }, - "execution_count": 16, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "SPDX Spec Version: 3.0.1\n", - "Root element ID: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "The SPDX specification defines the classes and properties of SPDX models.\n", - "\n", - "For example, the SpdxDocument class is detailed at: https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Classes/SpdxDocument/" - ], - "metadata": { - "id": "VgA7RhdiPZjl" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Put things together\n", - "\n", - "We can now perform basic object access.\n", - "Let's try to visualize an SPDX 3 SBOM.\n", - "\n", - "The example below will iterate through all relationships and print relationship types between SPDX objects." - ], - "metadata": { - "id": "rNdl2dqiPht8" - } - }, - { - "cell_type": "code", - "source": [ - "def print_object_info(obj, prefix=\"\"):\n", - " \"\"\"helper function to print a box containing object info.\n", - " obj can be either SHACLObject or just spdxId (string).\"\"\"\n", - " print(f\"{prefix}┏\" + \"━\"*50 + \"┅\")\n", - " if isinstance(obj, spdx3.SHACLObject):\n", - " print(f\"{prefix}┃ {obj.__class__.__name__}\")\n", - " print(f\"{prefix}┃ - name: {getattr(obj, 'name', 'N/A')}\")\n", - " print(f\"{prefix}┃ - spdxId: {obj.spdxId}\")\n", - " else: # assume it's an spdxId for an external object\n", - " print(f\"{prefix}┃ (Unresolved spdxId)\")\n", - " print(f\"{prefix}┃ - spdxId: {obj}\")\n", - " print(f\"{prefix}┗\" + \"━\"*50 + \"┅\")\n", - "\n", - "for rel in object_set.foreach_type(\"Relationship\"):\n", - " # spdx-python-model uses \"from_\" instead of \"from\" to avoid the Python keyword\n", - " from_obj = getattr(rel, \"from_\")\n", - " to_objs = getattr(rel, \"to\")\n", - " # print only the type name, not the full URL, for conciseness\n", - " rel_type = getattr(rel, \"relationshipType\").split(\"/\")[-1]\n", - "\n", - " print_object_info(from_obj)\n", - "\n", - " print( \" │\")\n", - " print(f\" {rel_type}\")\n", - " print( \" ↓\")\n", - "\n", - " for o in to_objs:\n", - " print_object_info(o, prefix=\" \")\n", - "\n", - " print()" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "pAgJZnDJU4Jf", - "outputId": "5bcfcb33-f0f0-4350-ffa0-ecbaa30bc62b" - }, - "execution_count": 17, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j SLF4J Binding\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j API\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_File\n", - "┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " generates\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_Package\n", - " ┃ - name: examplemaven\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " contains\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_File\n", - " ┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasTestCase\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_File\n", - " ┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDistributionArtifact\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_File\n", - " ┃ - name: examplemaven-0.0.1.jar\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd35\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j API\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDynamicLink\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_Package\n", - " ┃ - name: examplemaven\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ (Unresolved spdxId)\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1#SPDXRef-DOCUMENT\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " amendedBy\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ SpdxDocument\n", - " ┃ - name: examplemaven\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/document0\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_File\n", - "┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " dependsOn\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_Package\n", - " ┃ - name: JUnit\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: JUnit\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: SLF4J API Module\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDynamicLink\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_Package\n", - " ┃ - name: examplemaven\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: JUnit\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd44\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd49\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j Core\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDynamicLink\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_Package\n", - " ┃ - name: examplemaven\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_File\n", - "┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ SpdxDocument\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/document0\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " describes\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_Package\n", - " ┃ - name: examplemaven\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: examplemaven\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " contains\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_File\n", - " ┃ - name: ./src/test/java/org/spdx/examplemaven/AppTest.java\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd12\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j API\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd22\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: SLF4J API Module\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_File\n", - "┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_File\n", - "┃ - name: ./src/main/java/org/spdx/examplemaven/App.java\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd6\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd9\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j SLF4J Binding\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDynamicLink\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ software_Package\n", - " ┃ - name: examplemaven\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd4\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j Core\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: SLF4J API Module\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd26\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j SLF4J Binding\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd30\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasConcludedLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n", - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "┃ software_Package\n", - "┃ - name: Apache Log4j Core\n", - "┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd17\n", - "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " │\n", - " hasDeclaredLicense\n", - " ↓\n", - " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - " ┃ simplelicensing_LicenseExpression\n", - " ┃ - name: None\n", - " ┃ - spdxId: http://spdx.org/documents/examplemaven-0.0.1/enriched-specv3/SPDXRef-gnrtd19\n", - " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┅\n", - "\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "## SPDX object creation and built-in validation\n", - "\n", - "To create an SPDX object,\n", - "simply use the standard constructor as you would with any native Python class." - ], - "metadata": { - "id": "D2PljHcL5iH_" - } - }, - { - "cell_type": "code", - "source": [ - "package = spdx3.ai_AIPackage()\n", - "package" - ], - "metadata": { - "id": "9hjARbwm6DUd", - "outputId": "d93e5e20-7271-4f09-9635-62c2511fa923", - "colab": { - "base_uri": "https://localhost:8080/" - } - }, - "execution_count": 18, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "" - ] - }, - "metadata": {}, - "execution_count": 18 - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "The spdx-python-model library features built-in SHACL-based validation derived\n", - "directly from the [SPDX 3 model][spdx-3-model].\n", - "This validation ensures data integrity by rejecting invalid types at runtime.\n", - "\n", - "For example, the `domain` property of [`/AI/AIPackage`][ai-package] has a\n", - "[cardinality] of 0..* (minimum count: 0, maximum count: unbounded).\n", - "This requires the value to be a list;\n", - "if a different type is provided, the library will raise a `TypeError`.\n", - "\n", - "[spdx-3-model]: https://spdx.org/rdf/3.0.1/spdx-model.ttl\n", - "[ai-package]: https://spdx.github.io/spdx-spec/v3.0.1/model/AI/Classes/AIPackage/\n", - "[cardinality]: https://spdx.github.io/spdx-spec/v3.0.1/conformance/" - ], - "metadata": { - "id": "68j1H6Fw6xtf" - } - }, - { - "cell_type": "code", - "source": [ - "package.ai_domain = \"nlp\"" - ], - "metadata": { - "id": "cAzCx9tV6wI-", - "outputId": "1c32fb63-fa35-4b0b-e442-9d439cb3e5de", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 318 - } - }, - "execution_count": 19, - "outputs": [ - { - "output_type": "error", - "ename": "TypeError", - "evalue": "Value must be one of type: list, ListProxy. Got str", - "traceback": [ - "\^[[0;31m---------------------------------------------------------------------------\^[[0m", - "\^[[0;31mTypeError\^[[0m Traceback (most recent call last)", - "\^[[0;32m/tmp/ipykernel_20264/179762956.py\^[[0m in \^[[0;36m\^[[0;34m()\^[[0m\n\^[[0;32m----> 1\^[[0;31m \^[[0mpackage\^[[0m\^[[0;34m.\^[[0m\^[[0mai_domain\^[[0m \^[[0;34m=\^[[0m \^[[0;34m\"nlp\"\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m", - "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36m__setattr__\^[[0;34m(self, name, value)\^[[0m\n\^[[1;32m 1061\^[[0m \^[[0;32mreturn\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 1062\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[0;32m-> 1063\^[[0;31m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0m__set\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0m__get_attr\^[[0m\^[[0;34m(\^[[0m\^[[0mname\^[[0m\^[[0;34m)\^[[0m\^[[0;34m,\^[[0m \^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 1064\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 1065\^[[0m \^[[0;32mdef\^[[0m \^[[0m__getattr__\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m,\^[[0m \^[[0mname\^[[0m\^[[0;34m:\^[[0m \^[[0mstr\^[[0m\^[[0;34m)\^[[0m \^[[0;34m->\^[[0m \^[[0mAny\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n", - "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36m__set\^[[0;34m(self, p, value)\^[[0m\n\^[[1;32m 1034\^[[0m )\n\^[[1;32m 1035\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[0;32m-> 1036\^[[0;31m \^[[0mp\^[[0m\^[[0;34m.\^[[0m\^[[0mprop\^[[0m\^[[0;34m.\^[[0m\^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 1037\^[[0m \^[[0;32mif\^[[0m \^[[0mp\^[[0m\^[[0;34m.\^[[0m\^[[0mdeprecated\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 1038\^[[0m warnings.warn(\n", - "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36mvalidate\^[[0;34m(self, value)\^[[0m\n\^[[1;32m 568\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 569\^[[0m \^[[0;32mdef\^[[0m \^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m,\^[[0m \^[[0mvalue\^[[0m\^[[0;34m:\^[[0m \^[[0mAny\^[[0m\^[[0;34m)\^[[0m \^[[0;34m->\^[[0m \^[[0;32mNone\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0;32m--> 570\^[[0;31m \^[[0msuper\^[[0m\^[[0;34m(\^[[0m\^[[0;34m)\^[[0m\^[[0;34m.\^[[0m\^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 571\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 572\^[[0m \^[[0;32mfor\^[[0m \^[[0mi\^[[0m \^[[0;32min\^[[0m \^[[0mvalue\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n", - "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36mvalidate\^[[0;34m(self, value)\^[[0m\n\^[[1;32m 76\^[[0m \^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 77\^[[0m \^[[0;32mdef\^[[0m \^[[0mvalidate\^[[0m\^[[0;34m(\^[[0m\^[[0mself\^[[0m\^[[0;34m,\^[[0m \^[[0mvalue\^[[0m\^[[0;34m:\^[[0m \^[[0mAny\^[[0m\^[[0;34m)\^[[0m \^[[0;34m->\^[[0m \^[[0;32mNone\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0;32m---> 78\^[[0;31m \^[[0mcheck_type\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m,\^[[0m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0mVALID_TYPES\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0m\^[[1;32m 79\^[[0m if self.pattern is not None and not re.search(\n\^[[1;32m 80\^[[0m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0mpattern\^[[0m\^[[0;34m,\^[[0m \^[[0mself\^[[0m\^[[0;34m.\^[[0m\^[[0mto_string\^[[0m\^[[0;34m(\^[[0m\^[[0mvalue\^[[0m\^[[0;34m)\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n", - "\^[[0;32m/usr/local/lib/python3.12/dist-packages/spdx_python_model/bindings/v3_0_1/model.py\^[[0m in \^[[0;36mcheck_type\^[[0;34m(obj, types)\^[[0m\n\^[[1;32m 51\^[[0m \^[[0;32mif\^[[0m \^[[0;32mnot\^[[0m \^[[0misinstance\^[[0m\^[[0;34m(\^[[0m\^[[0mobj\^[[0m\^[[0;34m,\^[[0m \^[[0mtypes\^[[0m\^[[0;34m)\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 52\^[[0m \^[[0;32mif\^[[0m \^[[0misinstance\^[[0m\^[[0;34m(\^[[0m\^[[0mtypes\^[[0m\^[[0;34m,\^[[0m \^[[0;34m(\^[[0m\^[[0mlist\^[[0m\^[[0;34m,\^[[0m \^[[0mtuple\^[[0m\^[[0;34m)\^[[0m\^[[0;34m)\^[[0m\^[[0;34m:\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[0;32m---> 53\^[[0;31m raise TypeError(\n\^[[0m\^[[1;32m 54\^[[0m \^[[0;34mf\"Value must be one of type: {', '.join(t.__name__ for t in types)}. Got {type(obj).__name__}\"\^[[0m\^[[0;34m\^[[0m\^[[0;34m\^[[0m\^[[0m\n\^[[1;32m 55\^[[0m )\n", - "\^[[0;31mTypeError\^[[0m: Value must be one of type: list, ListProxy. Got str" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "Even if there is only a single entry, you must provide it as a single-element\n", - "list to satisfy the property's cardinality:" - ], - "metadata": { - "id": "WWdZwqP9EfnP" - } - }, - { - "cell_type": "code", - "source": [ - "package.ai_domain = [\"nlp\"]\n", - "package.ai_domain" - ], - "metadata": { - "id": "H6LeOd3_D8rQ", - "outputId": "b9977956-3c4e-4493-a1ef-369b845e0167", - "colab": { - "base_uri": "https://localhost:8080/" - } - }, - "execution_count": 20, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "['nlp']" - ] - }, - "metadata": {}, - "execution_count": 20 - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "Refer to the [SPDX specification][spdx-spec]\n", - "for detailed information on property types and cardinality.\n", - "\n", - "[spdx-spec]: https://spdx.github.io/spdx-spec/" - ], - "metadata": { - "id": "quqpF4E0E6fv" - } - }, - { - "cell_type": "markdown", - "source": [ - "## That's it\n", - "\n", - "That's it for now! Hope you enjoyed the tutorial.\n", - "\n", - "Special thanks to Joshua Watt for the spdx-python-model library, making SPDX 3 more accessible for Python developers.\n", - "\n", - "Find more examples of how to use the library:\n", - "\n", - "- `spdx-python-model` tests: https://github.com/spdx/spdx-python-model/blob/main/tests/test_import.py\n", - "- `shacl2code` (which generates spdx-python-model's Python binding) tests: https://github.com/JPEWdev/shacl2code/blob/main/tests/test_python.py\n", - "\n", - "There are many ways to [get involved](https://github.com/spdx/spdx-3-model/blob/develop/Contributing.md) with the SPDX community. If you have questions about using SPDX, feel free to join one of our [online meetings](https://github.com/spdx/meetings/)!\n", - "\n", - "--\n", - "\n", - "Check out my current project, *[Pitloom](https://github.com/bact/pitloom)*, an SBOM generator for Python projects and AI models. It extracts metadata from fastText, GGUF, ONNX, PyTorch, and Safetensors models, and builds SBOMs directly from Hugging Face URLs. It also includes native Hatchling build-hook support and works with setuptools and Poetry." - ], - "metadata": { - "id": "lqg60qPeLaI3" - } - } - ] -} From 726d27f6b672ccad3e61eb8e58ca8a6a11fbc4a2 Mon Sep 17 00:00:00 2001 From: Arthit Suriyawongkul Date: Tue, 23 Jun 2026 15:34:18 +0100 Subject: [PATCH 3/3] Skip index.html in tutorial list Signed-off-by: Arthit Suriyawongkul --- .github/workflows/docs.yaml | 1 + README.md | 5 +++++ www/index.html | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index ff43607..877db26 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -134,6 +134,7 @@ jobs: echo '

spdx-python-model

' echo '

Tutorials

    ' for html in pages/tutorial/*.html; do + [[ "$(basename "$html")" == "index.html" ]] && continue name=$(basename "$html" .html) echo "
  • $name (download .ipynb)
  • " done diff --git a/README.md b/README.md index 23170f2..fb2fa73 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,11 @@ model, objset = spdx_python_model.load(path) p = model.Person() ``` +Check out this short [Python notebook tutorial][tutorial] +to get started with spdx-python-model. + +[tutorial]: https://spdx.github.io/spdx-python-model/tutorial/using-spdx3.html + ## Testing This repository has support for running tests against the bindings using `pytest`. diff --git a/www/index.html b/www/index.html index 92ab7a2..e4d09dc 100644 --- a/www/index.html +++ b/www/index.html @@ -53,7 +53,7 @@

    Install

    Tutorial

    API documentation