spdx_tools.spdx.jsonschema.file_converter

 1# SPDX-FileCopyrightText: 2022 spdx contributors
 2#
 3# SPDX-License-Identifier: Apache-2.0
 4from beartype.typing import Any, Type
 5
 6from spdx_tools.spdx.jsonschema.annotation_converter import AnnotationConverter
 7from spdx_tools.spdx.jsonschema.checksum_converter import ChecksumConverter
 8from spdx_tools.spdx.jsonschema.converter import TypedConverter
 9from spdx_tools.spdx.jsonschema.file_properties import FileProperty
10from spdx_tools.spdx.jsonschema.json_property import JsonProperty
11from spdx_tools.spdx.jsonschema.optional_utils import apply_if_present
12from spdx_tools.spdx.model import Document, File
13
14
15class FileConverter(TypedConverter[File]):
16    annotation_converter: AnnotationConverter
17    checksum_converter: ChecksumConverter
18
19    def __init__(self):
20        self.annotation_converter = AnnotationConverter()
21        self.checksum_converter = ChecksumConverter()
22
23    def json_property_name(self, file_property: FileProperty) -> str:
24        if file_property == FileProperty.SPDX_ID:
25            return "SPDXID"
26        return super().json_property_name(file_property)
27
28    def _get_property_value(self, file: Any, file_property: FileProperty, document: Document = None) -> Any:
29        if file_property == FileProperty.SPDX_ID:
30            return file.spdx_id
31        elif file_property == FileProperty.ANNOTATIONS:
32            file_annotations = filter(lambda annotation: annotation.spdx_id == file.spdx_id, document.annotations)
33            return [self.annotation_converter.convert(annotation) for annotation in file_annotations] or None
34        elif file_property == FileProperty.ARTIFACT_OFS:
35            # Deprecated property, automatically converted during parsing
36            pass
37        elif file_property == FileProperty.ATTRIBUTION_TEXTS:
38            return file.attribution_texts or None
39        elif file_property == FileProperty.CHECKSUMS:
40            return [self.checksum_converter.convert(checksum) for checksum in file.checksums] or None
41        elif file_property == FileProperty.COMMENT:
42            return file.comment
43        elif file_property == FileProperty.COPYRIGHT_TEXT:
44            return apply_if_present(str, file.copyright_text)
45        elif file_property == FileProperty.FILE_CONTRIBUTORS:
46            return file.contributors or None
47        elif file_property == FileProperty.FILE_DEPENDENCIES:
48            # Deprecated property, automatically converted during parsing
49            pass
50        elif file_property == FileProperty.FILE_NAME:
51            return file.name
52        elif file_property == FileProperty.FILE_TYPES:
53            return [file_type.name for file_type in file.file_types] or None
54        elif file_property == FileProperty.LICENSE_COMMENTS:
55            return file.license_comment
56        elif file_property == FileProperty.LICENSE_CONCLUDED:
57            return apply_if_present(str, file.license_concluded)
58        elif file_property == FileProperty.LICENSE_INFO_IN_FILES:
59            return [str(license_expression) for license_expression in file.license_info_in_file] or None
60        elif file_property == FileProperty.NOTICE_TEXT:
61            return file.notice
62
63    def get_json_type(self) -> Type[JsonProperty]:
64        return FileProperty
65
66    def get_data_model_type(self) -> Type[File]:
67        return File
68
69    def requires_full_document(self) -> bool:
70        return True
16class FileConverter(TypedConverter[File]):
17    annotation_converter: AnnotationConverter
18    checksum_converter: ChecksumConverter
19
20    def __init__(self):
21        self.annotation_converter = AnnotationConverter()
22        self.checksum_converter = ChecksumConverter()
23
24    def json_property_name(self, file_property: FileProperty) -> str:
25        if file_property == FileProperty.SPDX_ID:
26            return "SPDXID"
27        return super().json_property_name(file_property)
28
29    def _get_property_value(self, file: Any, file_property: FileProperty, document: Document = None) -> Any:
30        if file_property == FileProperty.SPDX_ID:
31            return file.spdx_id
32        elif file_property == FileProperty.ANNOTATIONS:
33            file_annotations = filter(lambda annotation: annotation.spdx_id == file.spdx_id, document.annotations)
34            return [self.annotation_converter.convert(annotation) for annotation in file_annotations] or None
35        elif file_property == FileProperty.ARTIFACT_OFS:
36            # Deprecated property, automatically converted during parsing
37            pass
38        elif file_property == FileProperty.ATTRIBUTION_TEXTS:
39            return file.attribution_texts or None
40        elif file_property == FileProperty.CHECKSUMS:
41            return [self.checksum_converter.convert(checksum) for checksum in file.checksums] or None
42        elif file_property == FileProperty.COMMENT:
43            return file.comment
44        elif file_property == FileProperty.COPYRIGHT_TEXT:
45            return apply_if_present(str, file.copyright_text)
46        elif file_property == FileProperty.FILE_CONTRIBUTORS:
47            return file.contributors or None
48        elif file_property == FileProperty.FILE_DEPENDENCIES:
49            # Deprecated property, automatically converted during parsing
50            pass
51        elif file_property == FileProperty.FILE_NAME:
52            return file.name
53        elif file_property == FileProperty.FILE_TYPES:
54            return [file_type.name for file_type in file.file_types] or None
55        elif file_property == FileProperty.LICENSE_COMMENTS:
56            return file.license_comment
57        elif file_property == FileProperty.LICENSE_CONCLUDED:
58            return apply_if_present(str, file.license_concluded)
59        elif file_property == FileProperty.LICENSE_INFO_IN_FILES:
60            return [str(license_expression) for license_expression in file.license_info_in_file] or None
61        elif file_property == FileProperty.NOTICE_TEXT:
62            return file.notice
63
64    def get_json_type(self) -> Type[JsonProperty]:
65        return FileProperty
66
67    def get_data_model_type(self) -> Type[File]:
68        return File
69
70    def requires_full_document(self) -> bool:
71        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, file_property: spdx_tools.spdx.jsonschema.file_properties.FileProperty) -> str:
24    def json_property_name(self, file_property: FileProperty) -> str:
25        if file_property == FileProperty.SPDX_ID:
26            return "SPDXID"
27        return super().json_property_name(file_property)
def get_json_type(self) -> type[spdx_tools.spdx.jsonschema.json_property.JsonProperty]:
64    def get_json_type(self) -> Type[JsonProperty]:
65        return FileProperty
def get_data_model_type(self) -> type[spdx_tools.spdx.model.file.File]:
67    def get_data_model_type(self) -> Type[File]:
68        return File
def requires_full_document(self) -> bool:
70    def requires_full_document(self) -> bool:
71        return True