spdx-python-model 0.0.4__py3-none-any.whl → 0.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spdx_python_model/__init__.py +111 -3
- spdx_python_model/bindings/__init__.py +13 -2
- spdx_python_model/bindings/_reexport.pyi +14 -0
- spdx_python_model/bindings/v3_0_1/__init__.py +13 -0
- spdx_python_model/bindings/v3_0_1/__main__.py +12 -0
- spdx_python_model/bindings/v3_0_1/cmd.py +75 -0
- spdx_python_model/bindings/{v3_0_1.py → v3_0_1/model.py} +3160 -2669
- spdx_python_model/bindings/v3_0_1/model.pyi +3058 -0
- spdx_python_model/py.typed +0 -0
- spdx_python_model/version.py +3 -2
- spdx_python_model-0.0.6.dist-info/METADATA +202 -0
- spdx_python_model-0.0.6.dist-info/RECORD +14 -0
- {spdx_python_model-0.0.4.dist-info → spdx_python_model-0.0.6.dist-info}/WHEEL +1 -1
- spdx_python_model-0.0.4.dist-info/METADATA +0 -104
- spdx_python_model-0.0.4.dist-info/RECORD +0 -8
- {spdx_python_model-0.0.4.dist-info → spdx_python_model-0.0.6.dist-info}/licenses/LICENSE +0 -0
spdx_python_model/__init__.py
CHANGED
|
@@ -1,6 +1,114 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SPDX-FileType: SOURCE
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
3
|
+
"""
|
|
4
|
+
Python bindings for the SPDX 3 data model.
|
|
5
|
+
"""
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
import importlib
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from types import ModuleType
|
|
11
|
+
from typing import TYPE_CHECKING, Any, List, Tuple
|
|
12
|
+
|
|
13
|
+
from .bindings import _CONTEXT_TABLE
|
|
6
14
|
from .version import VERSION
|
|
15
|
+
from .version import VERSION as __version__
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
# Generated re-exports to give type checkers version types.
|
|
19
|
+
# Not imported during runtime.
|
|
20
|
+
from .bindings._reexport import * # noqa: F403
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"bindings", # generated # noqa: F405
|
|
24
|
+
"LoadError",
|
|
25
|
+
"VERSION",
|
|
26
|
+
"__version__",
|
|
27
|
+
"load",
|
|
28
|
+
"load_data",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
# Version submodule names accepted by __getattr__ for top-level import.
|
|
32
|
+
_VERSION_MODULES = frozenset(_CONTEXT_TABLE.values())
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class LoadError(Exception):
|
|
36
|
+
"""Raised when a SPDX document cannot be loaded."""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def __getattr__(name: str) -> ModuleType:
|
|
40
|
+
"""Lazily import a version's bindings on first top-level access (PEP 562)."""
|
|
41
|
+
if name in _VERSION_MODULES:
|
|
42
|
+
return importlib.import_module(f"{__name__}.bindings.{name}")
|
|
43
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def __dir__() -> List[str]:
|
|
47
|
+
return sorted(set(globals()) | _VERSION_MODULES)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def load_data(data: Any) -> Tuple[ModuleType, Any]:
|
|
51
|
+
"""
|
|
52
|
+
Automatically load a SPDX 3 JSON document with the correct model based on
|
|
53
|
+
its context
|
|
54
|
+
|
|
55
|
+
:param data: The decoded JSON data as a Python dict
|
|
56
|
+
|
|
57
|
+
:returns: A tuple that contains the model and the decoded SHACLObjectSet
|
|
58
|
+
|
|
59
|
+
:raises LoadError: If the data is missing a context or if the context is
|
|
60
|
+
not recognized
|
|
61
|
+
:raises TypeError: If the data is not a dictionary
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
if not isinstance(data, dict):
|
|
65
|
+
raise TypeError("Data must be a dictionary")
|
|
66
|
+
|
|
67
|
+
context = data.get("@context")
|
|
68
|
+
if not context:
|
|
69
|
+
raise LoadError("No @context in data")
|
|
70
|
+
|
|
71
|
+
context_url = None
|
|
72
|
+
|
|
73
|
+
if isinstance(context, str):
|
|
74
|
+
context_url = context
|
|
75
|
+
elif isinstance(context, list):
|
|
76
|
+
for item in context:
|
|
77
|
+
if isinstance(item, str):
|
|
78
|
+
context_url = item
|
|
79
|
+
break
|
|
80
|
+
|
|
81
|
+
if not context_url:
|
|
82
|
+
raise LoadError("No valid @context URL string found in data")
|
|
83
|
+
|
|
84
|
+
module_name = _CONTEXT_TABLE.get(context_url)
|
|
85
|
+
if module_name is None:
|
|
86
|
+
raise LoadError(f"Unknown context URL '{context_url}'")
|
|
87
|
+
|
|
88
|
+
model = importlib.import_module(f"{__name__}.bindings.{module_name}")
|
|
89
|
+
|
|
90
|
+
d = model.JSONLDDeserializer()
|
|
91
|
+
objset = model.SHACLObjectSet()
|
|
92
|
+
|
|
93
|
+
d.deserialize_data(data, objset)
|
|
94
|
+
|
|
95
|
+
return model, objset
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def load(path: Path) -> Tuple[ModuleType, Any]:
|
|
99
|
+
"""
|
|
100
|
+
Automatically load a SPDX 3 JSON document with the correct model based on
|
|
101
|
+
its context
|
|
102
|
+
|
|
103
|
+
:param path: The path to the SPDX 3 JSON file
|
|
104
|
+
|
|
105
|
+
:returns: A tuple that contains the model and the decoded SHACLObjectSet
|
|
106
|
+
|
|
107
|
+
:raises LoadError: If the data is missing a context or if the context is
|
|
108
|
+
not recognized
|
|
109
|
+
:raises TypeError: If the data is not a dictionary
|
|
110
|
+
"""
|
|
111
|
+
with path.open("r") as f:
|
|
112
|
+
data = json.load(f)
|
|
113
|
+
|
|
114
|
+
return load_data(data)
|
|
@@ -1,2 +1,13 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# SPDX-FileType: SOURCE
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Generated by generate-bindings at build time. DO NOT EDIT.
|
|
5
|
+
"""SPDX model bindings, one submodule per version.
|
|
6
|
+
|
|
7
|
+
Versions are not imported here, so importing one does not load the others.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# JSON-LD @context URL -> version submodule name, for lazy lookup by load().
|
|
11
|
+
_CONTEXT_TABLE = {
|
|
12
|
+
"https://spdx.org/rdf/3.0.1/spdx-context.jsonld": "v3_0_1",
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# SPDX-FileType: SOURCE
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Generated by generate-bindings at build time. DO NOT EDIT.
|
|
5
|
+
"""Type-checking-only re-exports so ``spdx_python_model.vX`` types resolve.
|
|
6
|
+
|
|
7
|
+
Imported under TYPE_CHECKING only; the runtime loads versions lazily via the
|
|
8
|
+
package __getattr__. __all__ marks the names as re-exports for --no-implicit-reexport.
|
|
9
|
+
"""
|
|
10
|
+
from . import v3_0_1
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"v3_0_1",
|
|
14
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#! /usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# This file was auto-generated by shacl2code 1.1.0. DO NOT MANUALLY MODIFY IT
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
|
|
7
|
+
from .model import * # noqa: F401, F403
|
|
8
|
+
|
|
9
|
+
# fmt: off
|
|
10
|
+
"""Format Guard"""
|
|
11
|
+
from .cmd import main # noqa: F401, I100, I202
|
|
12
|
+
"""Format Guard"""
|
|
13
|
+
# fmt on
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#! /usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# This file was auto-generated by shacl2code 1.1.0. DO NOT MANUALLY MODIFY IT
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Iterable, List
|
|
10
|
+
|
|
11
|
+
from .model import (
|
|
12
|
+
JSONLDDeserializer,
|
|
13
|
+
JSONLDSerializer,
|
|
14
|
+
ListProxy,
|
|
15
|
+
SHACLObject,
|
|
16
|
+
SHACLObjectSet,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def print_tree(objects: Iterable[SHACLObject], all_fields: bool = False) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Print object tree
|
|
23
|
+
"""
|
|
24
|
+
seen = set()
|
|
25
|
+
|
|
26
|
+
def callback(value: Any, path: List[str]) -> bool:
|
|
27
|
+
s = (" " * (len(path) - 1)) + f"{path[-1]}"
|
|
28
|
+
if isinstance(value, SHACLObject):
|
|
29
|
+
s += f" {value} ({id(value)})"
|
|
30
|
+
is_empty = False
|
|
31
|
+
elif isinstance(value, ListProxy):
|
|
32
|
+
is_empty = len(value) == 0
|
|
33
|
+
if is_empty:
|
|
34
|
+
s += " []"
|
|
35
|
+
else:
|
|
36
|
+
s += f" {value!r}"
|
|
37
|
+
is_empty = value is None
|
|
38
|
+
|
|
39
|
+
if all_fields or not is_empty:
|
|
40
|
+
print(s)
|
|
41
|
+
|
|
42
|
+
if isinstance(value, SHACLObject):
|
|
43
|
+
if value in seen:
|
|
44
|
+
return False
|
|
45
|
+
seen.add(value)
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
for o in objects:
|
|
51
|
+
o.walk(callback)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def main() -> int:
|
|
55
|
+
parser = argparse.ArgumentParser(description="Python SHACL model test")
|
|
56
|
+
parser.add_argument("infile", type=Path, help="Input file")
|
|
57
|
+
parser.add_argument("--print", action="store_true", help="Print object tree")
|
|
58
|
+
parser.add_argument("--outfile", type=Path, help="Output file")
|
|
59
|
+
|
|
60
|
+
args = parser.parse_args()
|
|
61
|
+
|
|
62
|
+
objectset = SHACLObjectSet()
|
|
63
|
+
with args.infile.open("r") as f:
|
|
64
|
+
d = JSONLDDeserializer()
|
|
65
|
+
d.read(f, objectset)
|
|
66
|
+
|
|
67
|
+
if args.print:
|
|
68
|
+
print_tree(objectset.objects)
|
|
69
|
+
|
|
70
|
+
if args.outfile:
|
|
71
|
+
with args.outfile.open("wb") as f:
|
|
72
|
+
s = JSONLDSerializer()
|
|
73
|
+
s.write(objectset, f)
|
|
74
|
+
|
|
75
|
+
return 0
|