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.
@@ -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
- from .bindings import *
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
- # Import all versions
2
- from . import v3_0_1
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,12 @@
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 sys
8
+
9
+ from .cmd import main
10
+
11
+ if __name__ == "__main__":
12
+ sys.exit(main())
@@ -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