Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,5 @@ cython_debug/
#.idea/

src/spdx_python_model/bindings/
gen/*.py
gen/*.pyi
gen/**/*.py
gen/**/*.pyi
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ from spdx_python_model import v3_0_1 as spdx_3_0
p = spdx_3_0.Person()
```

You can also have the bindings automatically detect the correct version to use
using the `load()` API:

```python
import spdx_python_model

path = Path("/path/to/file.spdx3.json")

model, objset = spdx_python_model.load(path)

p = model.Person()
```

## Testing

This repository has support for running tests against the bindings using `pytest`.
Expand Down
22 changes: 20 additions & 2 deletions gen/generate-bindings
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,43 @@ mkdir -p "gen"

echo "# Import all versions" > __init__.py

get_context_url() {
echo "https://spdx.org/rdf/$1/spdx-context.jsonld"
}

for v in $SPDX_VERSIONS; do
MODNAME="v$(echo "$v" | sed 's/[^a-zA-Z0-9_]/_/g')"

CONTEXT_URL="$(get_context_url "$v")"
if [ -n "${SHACL2CODE_SPDX_DIR}" ] && [ -d "${SHACL2CODE_SPDX_DIR}/$v" ]
then
shacl2code generate --input "file://${SHACL2CODE_SPDX_DIR}/$v/spdx-model.ttl" \
--input "file://${SHACL2CODE_SPDX_DIR}/$v/spdx-json-serialize-annotations.ttl" \
--context-url "file://${SHACL2CODE_SPDX_DIR}/$v/spdx-context.jsonld" https://spdx.org/rdf/$v/spdx-context.jsonld \
--context-url "file://${SHACL2CODE_SPDX_DIR}/$v/spdx-context.jsonld" $CONTEXT_URL \
--license Apache-2.0 \
python \
--output "$MODNAME"
else
shacl2code generate --input https://spdx.org/rdf/$v/spdx-model.ttl \
--input https://spdx.org/rdf/$v/spdx-json-serialize-annotations.ttl \
--context https://spdx.org/rdf/$v/spdx-context.jsonld \
--context $CONTEXT_URL \
--license Apache-2.0 \
python \
--output "$MODNAME"
fi

echo "from . import $MODNAME" >> __init__.py
done

MODNAME=""
CONTEXT_URL=""

echo >> __init__.py
echo "# Generate context table" >> __init__.py
echo "_CONTEXT_TABLE = {" >> __init__.py
for v in $SPDX_VERSIONS; do
MODNAME="v$(echo "$v" | sed 's/[^a-zA-Z0-9_]/_/g')"
CONTEXT_URL="$(get_context_url "$v")"
echo " '$CONTEXT_URL': $MODNAME" >> __init__.py
done
echo "}" >> __init__.py
74 changes: 74 additions & 0 deletions src/spdx_python_model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,77 @@

from .bindings import *
from .version import VERSION

from .bindings import _CONTEXT_TABLE

from pathlib import Path
import json


class LoadError(Exception):
pass


def load_data(data):
"""
Automatically load a SPDX 3 JSON document with the correct model based on
its context

:param data: The decoded JSON data as a Python dict

:returns: A tuple that contains the model and the decoded SHACLObjectSet

:raises LoadError: If the data is missing a context or if the context is
not recognized
:raises TypeError: If the data is not a dictionary
"""

if not isinstance(data, dict):
raise TypeError("Data must be a dictionary")

if "@context" not in data:
raise LoadError("No @context in data")

context_url = None

if isinstance(data["@context"], str):
context_url = data["@context"]
elif isinstance(data["@context"], list):
for item in data["@context"]:
if isinstance(item, str):
context_url = item
break

if not context_url:
raise LoadError("No valid @context URL string found in data")

if context_url not in _CONTEXT_TABLE:
raise LoadError(f"Unknown context URL '{context}'")

model = _CONTEXT_TABLE[context_url]

d = model.JSONLDDeserializer()
objset = model.SHACLObjectSet()

d.deserialize_data(data, objset)

return model, objset


def load(path: Path):
"""
Automatically load a SPDX 3 JSON document with the correct model based on
its context

:param data: The path to the SPDX 3 JSON file

:returns: A tuple that contains the model and the decoded SHACLObjectSet

:raises LoadError: If the data is missing a context or if the context is
not recognized
:raises TypeError: If the data is not a dictionary
"""
with path.open("r") as f:
data = json.load(f)

return load_data(data)
238 changes: 238 additions & 0 deletions tests/data/3.0.1/example.spdx3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
{
"@context" : "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
"@graph" : [ {
"@id" : "_:creationInfo_0",
"type" : "CreationInfo",
"specVersion" : "3.0.1",
"createdBy" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd0" ],
"createdUsing" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/additionalToolSPDXRef-gnrtd2", "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/additionalToolSPDXRef-gnrtd1" ],
"created" : "2021-08-26T01:46:00Z"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd3",
"type" : "Relationship",
"relationshipType" : "describes",
"completeness" : "noAssertion",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/document0",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd5",
"type" : "Relationship",
"relationshipType" : "contains",
"completeness" : "noAssertion",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd6" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd7",
"type" : "Relationship",
"relationshipType" : "hasConcludedLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd6",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd9",
"type" : "Relationship",
"relationshipType" : "hasDeclaredLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd6",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd10",
"type" : "Relationship",
"relationshipType" : "contains",
"completeness" : "noAssertion",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd11" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd12",
"type" : "Relationship",
"relationshipType" : "generates",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd11" ],
"completeness" : "noAssertion",
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd13",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd15",
"type" : "Relationship",
"relationshipType" : "hasConcludedLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd13",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd16",
"type" : "Relationship",
"relationshipType" : "hasDeclaredLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd13",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd17",
"type" : "Relationship",
"relationshipType" : "generates",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd11" ],
"completeness" : "noAssertion",
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd6",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd18",
"type" : "Relationship",
"relationshipType" : "hasConcludedLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd11",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd19",
"type" : "Relationship",
"relationshipType" : "hasDeclaredLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd20" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd11",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd21",
"type" : "Relationship",
"relationshipType" : "contains",
"completeness" : "noAssertion",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd13" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd22",
"type" : "Relationship",
"relationshipType" : "hasConcludedLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd23",
"type" : "Relationship",
"relationshipType" : "hasDeclaredLicense",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8" ],
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/document0",
"type" : "SpdxDocument",
"dataLicense" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd24",
"rootElement" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4" ],
"name" : "hello",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/additionalToolSPDXRef-gnrtd1",
"type" : "Tool",
"name" : "github.com/spdx/tools-golang/builder",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/additionalToolSPDXRef-gnrtd2",
"type" : "Tool",
"name" : "github.com/spdx/tools-golang/idsearcher",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd8",
"type" : "simplelicensing_LicenseExpression",
"simplelicensing_licenseExpression" : "GPL-3.0-or-later",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd20",
"type" : "simplelicensing_LicenseExpression",
"simplelicensing_licenseExpression" : "NOASSERTION",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd24",
"type" : "simplelicensing_LicenseExpression",
"simplelicensing_licenseExpression" : "CC0-1.0",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd14",
"type" : "LifecycleScopedRelationship",
"relationshipType" : "usesTool",
"scope" : "build",
"to" : [ "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd13" ],
"completeness" : "noAssertion",
"from" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd0",
"type" : "Person",
"externalIdentifier" : [ {
"type" : "ExternalIdentifier",
"identifier" : "steve@swinslow.net",
"externalIdentifierType" : "email"
} ],
"name" : "Steve Winslow",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd6",
"type" : "software_File",
"software_copyrightText" : "Copyright Contributors to the spdx-examples project.",
"verifiedUsing" : [ {
"type" : "Hash",
"algorithm" : "md5",
"hashValue" : "935054fe899ca782e11003bbae5e166c"
}, {
"type" : "Hash",
"algorithm" : "sha1",
"hashValue" : "20862a6d08391d07d09344029533ec644fac6b21"
}, {
"type" : "Hash",
"algorithm" : "sha256",
"hashValue" : "b4e5ca56d1f9110ca94ed0bf4e6d9ac11c2186eb7cd95159c6fdb50e8db5a823"
} ],
"name" : "./src/hello.c",
"software_primaryPurpose" : "source",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd11",
"type" : "software_File",
"software_copyrightText" : "NOASSERTION",
"verifiedUsing" : [ {
"type" : "Hash",
"algorithm" : "sha1",
"hashValue" : "20291a81ef065ff891b537b64d4fdccaf6f5ac02"
}, {
"type" : "Hash",
"algorithm" : "sha256",
"hashValue" : "83a33ff09648bb5fc5272baca88cf2b59fd81ac4cc6817b86998136af368708e"
}, {
"type" : "Hash",
"algorithm" : "md5",
"hashValue" : "08a12c966d776864cc1eb41fd03c3c3d"
} ],
"name" : "./build/hello",
"contentType" : "application/octet-stream",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd13",
"type" : "software_File",
"software_copyrightText" : "NOASSERTION",
"verifiedUsing" : [ {
"type" : "Hash",
"algorithm" : "sha1",
"hashValue" : "69a2e85696fff1865c3f0686d6c3824b59915c80"
}, {
"type" : "Hash",
"algorithm" : "sha256",
"hashValue" : "5da19033ba058e322e21c90e6d6d859c90b1b544e7840859c12cae5da005e79c"
}, {
"type" : "Hash",
"algorithm" : "md5",
"hashValue" : "559424589a4f3f75fd542810473d8bc1"
} ],
"name" : "./src/Makefile",
"software_primaryPurpose" : "source",
"creationInfo" : "_:creationInfo_0"
}, {
"spdxId" : "https://swinslow.net/spdx-examples/example1/hello-v3-specv3/SPDXRef-gnrtd4",
"type" : "software_Package",
"software_copyrightText" : "NOASSERTION",
"software_downloadLocation" : "git+https://github.com/swinslow/spdx-examples.git#example1/content",
"verifiedUsing" : [ {
"type" : "PackageVerificationCode",
"algorithm" : "sha1",
"hashValue" : "9d20237bb72087e87069f96afb41c6ca2fa2a342"
} ],
"name" : "hello",
"creationInfo" : "_:creationInfo_0"
} ]
}
Loading