spdx_tools.spdx.jsonschema.package_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.datetime_conversions import datetime_to_iso_string
  7from spdx_tools.spdx.jsonschema.annotation_converter import AnnotationConverter
  8from spdx_tools.spdx.jsonschema.checksum_converter import ChecksumConverter
  9from spdx_tools.spdx.jsonschema.converter import TypedConverter
 10from spdx_tools.spdx.jsonschema.external_package_ref_converter import ExternalPackageRefConverter
 11from spdx_tools.spdx.jsonschema.json_property import JsonProperty
 12from spdx_tools.spdx.jsonschema.optional_utils import apply_if_present
 13from spdx_tools.spdx.jsonschema.package_properties import PackageProperty
 14from spdx_tools.spdx.jsonschema.package_verification_code_converter import PackageVerificationCodeConverter
 15from spdx_tools.spdx.model import Actor, Document, Package
 16
 17
 18class PackageConverter(TypedConverter[Package]):
 19    annotation_converter: AnnotationConverter
 20    checksum_converter: ChecksumConverter
 21    external_package_ref_converter: ExternalPackageRefConverter
 22    package_verification_code_converter: PackageVerificationCodeConverter
 23
 24    def __init__(self):
 25        self.annotation_converter = AnnotationConverter()
 26        self.checksum_converter = ChecksumConverter()
 27        self.external_package_ref_converter = ExternalPackageRefConverter()
 28        self.package_verification_code_converter = PackageVerificationCodeConverter()
 29
 30    def json_property_name(self, package_property: PackageProperty) -> str:
 31        if package_property == PackageProperty.SPDX_ID:
 32            return "SPDXID"
 33        return super().json_property_name(package_property)
 34
 35    def _get_property_value(
 36        self, package: Package, package_property: PackageProperty, document: Document = None
 37    ) -> Any:
 38        if package_property == PackageProperty.SPDX_ID:
 39            return package.spdx_id
 40        elif package_property == PackageProperty.ANNOTATIONS:
 41            package_annotations = filter(
 42                lambda annotation: annotation.spdx_id == package.spdx_id, document.annotations
 43            )
 44            return [
 45                self.annotation_converter.convert(annotation, document) for annotation in package_annotations
 46            ] or None
 47        elif package_property == PackageProperty.ATTRIBUTION_TEXTS:
 48            return package.attribution_texts or None
 49        elif package_property == PackageProperty.BUILT_DATE:
 50            return apply_if_present(datetime_to_iso_string, package.built_date)
 51        elif package_property == PackageProperty.CHECKSUMS:
 52            return [self.checksum_converter.convert(checksum, document) for checksum in package.checksums] or None
 53        elif package_property == PackageProperty.COMMENT:
 54            return package.comment
 55        elif package_property == PackageProperty.COPYRIGHT_TEXT:
 56            return apply_if_present(str, package.copyright_text)
 57        elif package_property == PackageProperty.DESCRIPTION:
 58            return package.description
 59        elif package_property == PackageProperty.DOWNLOAD_LOCATION:
 60            return str(package.download_location)
 61        elif package_property == PackageProperty.EXTERNAL_REFS:
 62            return [
 63                self.external_package_ref_converter.convert(external_ref)
 64                for external_ref in package.external_references
 65            ] or None
 66        elif package_property == PackageProperty.FILES_ANALYZED:
 67            return package.files_analyzed
 68        elif package_property == PackageProperty.HOMEPAGE:
 69            return apply_if_present(str, package.homepage)
 70        elif package_property == PackageProperty.LICENSE_COMMENTS:
 71            return package.license_comment
 72        elif package_property == PackageProperty.LICENSE_CONCLUDED:
 73            return apply_if_present(str, package.license_concluded)
 74        elif package_property == PackageProperty.LICENSE_DECLARED:
 75            return apply_if_present(str, package.license_declared)
 76        elif package_property == PackageProperty.LICENSE_INFO_FROM_FILES:
 77            return [str(license_expression) for license_expression in package.license_info_from_files] or None
 78        elif package_property == PackageProperty.NAME:
 79            return package.name
 80        elif package_property == PackageProperty.ORIGINATOR:
 81            if isinstance(package.originator, Actor):
 82                return package.originator.to_serialized_string()
 83            return apply_if_present(str, package.originator)
 84        elif package_property == PackageProperty.PACKAGE_FILE_NAME:
 85            return package.file_name
 86        elif package_property == PackageProperty.PACKAGE_VERIFICATION_CODE:
 87            return apply_if_present(self.package_verification_code_converter.convert, package.verification_code)
 88        elif package_property == PackageProperty.PRIMARY_PACKAGE_PURPOSE:
 89            return package.primary_package_purpose.name if package.primary_package_purpose is not None else None
 90        elif package_property == PackageProperty.RELEASE_DATE:
 91            return apply_if_present(datetime_to_iso_string, package.release_date)
 92        elif package_property == PackageProperty.SOURCE_INFO:
 93            return package.source_info
 94        elif package_property == PackageProperty.SUMMARY:
 95            return package.summary
 96        elif package_property == PackageProperty.SUPPLIER:
 97            if isinstance(package.supplier, Actor):
 98                return package.supplier.to_serialized_string()
 99            return apply_if_present(str, package.supplier)
100        elif package_property == PackageProperty.VALID_UNTIL_DATE:
101            return apply_if_present(datetime_to_iso_string, package.valid_until_date)
102        elif package_property == PackageProperty.VERSION_INFO:
103            return package.version
104
105    def get_json_type(self) -> Type[JsonProperty]:
106        return PackageProperty
107
108    def get_data_model_type(self) -> Type[Package]:
109        return Package
110
111    def requires_full_document(self) -> bool:
112        return True
 19class PackageConverter(TypedConverter[Package]):
 20    annotation_converter: AnnotationConverter
 21    checksum_converter: ChecksumConverter
 22    external_package_ref_converter: ExternalPackageRefConverter
 23    package_verification_code_converter: PackageVerificationCodeConverter
 24
 25    def __init__(self):
 26        self.annotation_converter = AnnotationConverter()
 27        self.checksum_converter = ChecksumConverter()
 28        self.external_package_ref_converter = ExternalPackageRefConverter()
 29        self.package_verification_code_converter = PackageVerificationCodeConverter()
 30
 31    def json_property_name(self, package_property: PackageProperty) -> str:
 32        if package_property == PackageProperty.SPDX_ID:
 33            return "SPDXID"
 34        return super().json_property_name(package_property)
 35
 36    def _get_property_value(
 37        self, package: Package, package_property: PackageProperty, document: Document = None
 38    ) -> Any:
 39        if package_property == PackageProperty.SPDX_ID:
 40            return package.spdx_id
 41        elif package_property == PackageProperty.ANNOTATIONS:
 42            package_annotations = filter(
 43                lambda annotation: annotation.spdx_id == package.spdx_id, document.annotations
 44            )
 45            return [
 46                self.annotation_converter.convert(annotation, document) for annotation in package_annotations
 47            ] or None
 48        elif package_property == PackageProperty.ATTRIBUTION_TEXTS:
 49            return package.attribution_texts or None
 50        elif package_property == PackageProperty.BUILT_DATE:
 51            return apply_if_present(datetime_to_iso_string, package.built_date)
 52        elif package_property == PackageProperty.CHECKSUMS:
 53            return [self.checksum_converter.convert(checksum, document) for checksum in package.checksums] or None
 54        elif package_property == PackageProperty.COMMENT:
 55            return package.comment
 56        elif package_property == PackageProperty.COPYRIGHT_TEXT:
 57            return apply_if_present(str, package.copyright_text)
 58        elif package_property == PackageProperty.DESCRIPTION:
 59            return package.description
 60        elif package_property == PackageProperty.DOWNLOAD_LOCATION:
 61            return str(package.download_location)
 62        elif package_property == PackageProperty.EXTERNAL_REFS:
 63            return [
 64                self.external_package_ref_converter.convert(external_ref)
 65                for external_ref in package.external_references
 66            ] or None
 67        elif package_property == PackageProperty.FILES_ANALYZED:
 68            return package.files_analyzed
 69        elif package_property == PackageProperty.HOMEPAGE:
 70            return apply_if_present(str, package.homepage)
 71        elif package_property == PackageProperty.LICENSE_COMMENTS:
 72            return package.license_comment
 73        elif package_property == PackageProperty.LICENSE_CONCLUDED:
 74            return apply_if_present(str, package.license_concluded)
 75        elif package_property == PackageProperty.LICENSE_DECLARED:
 76            return apply_if_present(str, package.license_declared)
 77        elif package_property == PackageProperty.LICENSE_INFO_FROM_FILES:
 78            return [str(license_expression) for license_expression in package.license_info_from_files] or None
 79        elif package_property == PackageProperty.NAME:
 80            return package.name
 81        elif package_property == PackageProperty.ORIGINATOR:
 82            if isinstance(package.originator, Actor):
 83                return package.originator.to_serialized_string()
 84            return apply_if_present(str, package.originator)
 85        elif package_property == PackageProperty.PACKAGE_FILE_NAME:
 86            return package.file_name
 87        elif package_property == PackageProperty.PACKAGE_VERIFICATION_CODE:
 88            return apply_if_present(self.package_verification_code_converter.convert, package.verification_code)
 89        elif package_property == PackageProperty.PRIMARY_PACKAGE_PURPOSE:
 90            return package.primary_package_purpose.name if package.primary_package_purpose is not None else None
 91        elif package_property == PackageProperty.RELEASE_DATE:
 92            return apply_if_present(datetime_to_iso_string, package.release_date)
 93        elif package_property == PackageProperty.SOURCE_INFO:
 94            return package.source_info
 95        elif package_property == PackageProperty.SUMMARY:
 96            return package.summary
 97        elif package_property == PackageProperty.SUPPLIER:
 98            if isinstance(package.supplier, Actor):
 99                return package.supplier.to_serialized_string()
100            return apply_if_present(str, package.supplier)
101        elif package_property == PackageProperty.VALID_UNTIL_DATE:
102            return apply_if_present(datetime_to_iso_string, package.valid_until_date)
103        elif package_property == PackageProperty.VERSION_INFO:
104            return package.version
105
106    def get_json_type(self) -> Type[JsonProperty]:
107        return PackageProperty
108
109    def get_data_model_type(self) -> Type[Package]:
110        return Package
111
112    def requires_full_document(self) -> bool:
113        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, package_property: spdx_tools.spdx.jsonschema.package_properties.PackageProperty) -> str:
31    def json_property_name(self, package_property: PackageProperty) -> str:
32        if package_property == PackageProperty.SPDX_ID:
33            return "SPDXID"
34        return super().json_property_name(package_property)
def get_json_type(self) -> type[spdx_tools.spdx.jsonschema.json_property.JsonProperty]:
106    def get_json_type(self) -> Type[JsonProperty]:
107        return PackageProperty
def get_data_model_type(self) -> type[spdx_tools.spdx.model.package.Package]:
109    def get_data_model_type(self) -> Type[Package]:
110        return Package
def requires_full_document(self) -> bool:
112    def requires_full_document(self) -> bool:
113        return True