spdx_tools.spdx.jsonschema.snippet_converter

 1# SPDX-FileCopyrightText: 2022 spdx contributors
 2#
 3# SPDX-License-Identifier: Apache-2.0
 4from beartype.typing import Any, Dict, Tuple, Type
 5
 6from spdx_tools.spdx.jsonschema.annotation_converter import AnnotationConverter
 7from spdx_tools.spdx.jsonschema.converter import TypedConverter
 8from spdx_tools.spdx.jsonschema.json_property import JsonProperty
 9from spdx_tools.spdx.jsonschema.optional_utils import apply_if_present
10from spdx_tools.spdx.jsonschema.snippet_properties import SnippetProperty
11from spdx_tools.spdx.model import Document, Snippet
12
13
14class SnippetConverter(TypedConverter[Snippet]):
15    annotation_converter: AnnotationConverter
16
17    def __init__(self):
18        self.annotation_converter = AnnotationConverter()
19
20    def json_property_name(self, snippet_property: SnippetProperty) -> str:
21        if snippet_property == SnippetProperty.SPDX_ID:
22            return "SPDXID"
23        return super().json_property_name(snippet_property)
24
25    def _get_property_value(
26        self, snippet: Snippet, snippet_property: SnippetProperty, document: Document = None
27    ) -> Any:
28        if snippet_property == SnippetProperty.SPDX_ID:
29            return snippet.spdx_id
30        elif snippet_property == SnippetProperty.ANNOTATIONS:
31            snippet_annotations = filter(
32                lambda annotation: annotation.spdx_id == snippet.spdx_id, document.annotations
33            )
34            return [self.annotation_converter.convert(annotation) for annotation in snippet_annotations] or None
35        elif snippet_property == SnippetProperty.ATTRIBUTION_TEXTS:
36            return snippet.attribution_texts or None
37        elif snippet_property == SnippetProperty.COMMENT:
38            return snippet.comment
39        elif snippet_property == SnippetProperty.COPYRIGHT_TEXT:
40            return apply_if_present(str, snippet.copyright_text)
41        elif snippet_property == SnippetProperty.LICENSE_COMMENTS:
42            return snippet.license_comment
43        elif snippet_property == SnippetProperty.LICENSE_CONCLUDED:
44            return apply_if_present(str, snippet.license_concluded)
45        elif snippet_property == SnippetProperty.LICENSE_INFO_IN_SNIPPETS:
46            return [str(license_expression) for license_expression in snippet.license_info_in_snippet] or None
47        elif snippet_property == SnippetProperty.NAME:
48            return snippet.name
49        elif snippet_property == SnippetProperty.RANGES:
50            ranges = [convert_byte_range_to_dict(snippet.byte_range, snippet.file_spdx_id)]
51            if snippet.line_range:
52                ranges.append(convert_line_range_to_dict(snippet.line_range, snippet.file_spdx_id))
53            return ranges
54        elif snippet_property == SnippetProperty.SNIPPET_FROM_FILE:
55            return snippet.file_spdx_id
56
57    def get_json_type(self) -> Type[JsonProperty]:
58        return SnippetProperty
59
60    def get_data_model_type(self) -> Type[Snippet]:
61        return Snippet
62
63    def requires_full_document(self) -> bool:
64        return True
65
66
67def convert_line_range_to_dict(line_range: Tuple[int, int], file_id: str) -> Dict:
68    return _convert_range_to_dict(line_range, file_id, "lineNumber")
69
70
71def convert_byte_range_to_dict(byte_range: Tuple[int, int], file_id: str) -> Dict:
72    return _convert_range_to_dict(byte_range, file_id, "offset")
73
74
75def _convert_range_to_dict(int_range: Tuple[int, int], file_id: str, pointer_property: str) -> Dict:
76    return {
77        "startPointer": _pointer(file_id, int_range[0], pointer_property),
78        "endPointer": _pointer(file_id, int_range[1], pointer_property),
79    }
80
81
82def _pointer(reference: str, target: int, pointer_property: str) -> Dict:
83    return {"reference": reference, pointer_property: target}
15class SnippetConverter(TypedConverter[Snippet]):
16    annotation_converter: AnnotationConverter
17
18    def __init__(self):
19        self.annotation_converter = AnnotationConverter()
20
21    def json_property_name(self, snippet_property: SnippetProperty) -> str:
22        if snippet_property == SnippetProperty.SPDX_ID:
23            return "SPDXID"
24        return super().json_property_name(snippet_property)
25
26    def _get_property_value(
27        self, snippet: Snippet, snippet_property: SnippetProperty, document: Document = None
28    ) -> Any:
29        if snippet_property == SnippetProperty.SPDX_ID:
30            return snippet.spdx_id
31        elif snippet_property == SnippetProperty.ANNOTATIONS:
32            snippet_annotations = filter(
33                lambda annotation: annotation.spdx_id == snippet.spdx_id, document.annotations
34            )
35            return [self.annotation_converter.convert(annotation) for annotation in snippet_annotations] or None
36        elif snippet_property == SnippetProperty.ATTRIBUTION_TEXTS:
37            return snippet.attribution_texts or None
38        elif snippet_property == SnippetProperty.COMMENT:
39            return snippet.comment
40        elif snippet_property == SnippetProperty.COPYRIGHT_TEXT:
41            return apply_if_present(str, snippet.copyright_text)
42        elif snippet_property == SnippetProperty.LICENSE_COMMENTS:
43            return snippet.license_comment
44        elif snippet_property == SnippetProperty.LICENSE_CONCLUDED:
45            return apply_if_present(str, snippet.license_concluded)
46        elif snippet_property == SnippetProperty.LICENSE_INFO_IN_SNIPPETS:
47            return [str(license_expression) for license_expression in snippet.license_info_in_snippet] or None
48        elif snippet_property == SnippetProperty.NAME:
49            return snippet.name
50        elif snippet_property == SnippetProperty.RANGES:
51            ranges = [convert_byte_range_to_dict(snippet.byte_range, snippet.file_spdx_id)]
52            if snippet.line_range:
53                ranges.append(convert_line_range_to_dict(snippet.line_range, snippet.file_spdx_id))
54            return ranges
55        elif snippet_property == SnippetProperty.SNIPPET_FROM_FILE:
56            return snippet.file_spdx_id
57
58    def get_json_type(self) -> Type[JsonProperty]:
59        return SnippetProperty
60
61    def get_data_model_type(self) -> Type[Snippet]:
62        return Snippet
63
64    def requires_full_document(self) -> bool:
65        return True

Base class for all converters between an instance of the tools-python data model and the corresponding dictionary representation, following the json schema. The generic type T is the type according to the data model. Each converter has several methods:

  • get_json_type and get_data_model_type: return the data model type and the corresponding JsonProperty subclass. These methods are abstract in the base class and need to be implemented in subclasses.
  • json_property_name: converts an enum value of a JsonProperty subclass to the corresponding property name in the json schema. The default implementation simply converts from snake case to camel case. Can be overridden in case of exceptions like "SPDXID".
  • convert: converts an instance of type T (one of the data model types) to a dictionary representation. In some cases, the full document is required (see below). The logic should be generic for all types.
  • requires_full_document: indicates whether the full document is required for conversion. Returns False by default, can be overridden as needed for specific types.
  • _get_property_value: Retrieves the value of a specific json property from the data model instance. In some cases, the full document is required.
def json_property_name( self, snippet_property: spdx_tools.spdx.jsonschema.snippet_properties.SnippetProperty) -> str:
21    def json_property_name(self, snippet_property: SnippetProperty) -> str:
22        if snippet_property == SnippetProperty.SPDX_ID:
23            return "SPDXID"
24        return super().json_property_name(snippet_property)
def get_json_type(self) -> type[spdx_tools.spdx.jsonschema.json_property.JsonProperty]:
58    def get_json_type(self) -> Type[JsonProperty]:
59        return SnippetProperty
def get_data_model_type(self) -> type[spdx_tools.spdx.model.snippet.Snippet]:
61    def get_data_model_type(self) -> Type[Snippet]:
62        return Snippet
def requires_full_document(self) -> bool:
64    def requires_full_document(self) -> bool:
65        return True
def convert_line_range_to_dict(line_range: tuple[int, int], file_id: str) -> dict:
68def convert_line_range_to_dict(line_range: Tuple[int, int], file_id: str) -> Dict:
69    return _convert_range_to_dict(line_range, file_id, "lineNumber")
def convert_byte_range_to_dict(byte_range: tuple[int, int], file_id: str) -> dict:
72def convert_byte_range_to_dict(byte_range: Tuple[int, int], file_id: str) -> Dict:
73    return _convert_range_to_dict(byte_range, file_id, "offset")