spdx_tools.spdx.parser.tagvalue.helper_methods

  1# SPDX-FileCopyrightText: 2023 spdx contributors
  2#
  3# SPDX-License-Identifier: Apache-2.0
  4import re
  5
  6from beartype.typing import Any, Callable, Dict, Optional
  7from ply.yacc import YaccProduction
  8
  9from spdx_tools.spdx.casing_tools import camel_case_to_snake_case
 10from spdx_tools.spdx.model import (
 11    Annotation,
 12    Checksum,
 13    ChecksumAlgorithm,
 14    CreationInfo,
 15    ExtractedLicensingInfo,
 16    File,
 17    Package,
 18    Snippet,
 19)
 20from spdx_tools.spdx.parser.error import SPDXParsingError
 21
 22
 23def grammar_rule(doc):
 24    # this is a helper method to use decorators for the parsing methods instead of docstrings
 25    def decorate(func):
 26        func.__doc__ = doc
 27        return func
 28
 29    return decorate
 30
 31
 32def str_from_text(text: Optional[str]) -> Optional[str]:
 33    regex = re.compile("<text>((.|\n)+)</text>", re.UNICODE)
 34    match = regex.match(text)
 35    if match:
 36        return match.group(1)
 37    elif isinstance(text, str):
 38        return text
 39    else:
 40        return None
 41
 42
 43def parse_checksum(checksum_str: str) -> Checksum:
 44    # The lexer and the corresponding regex for the token CHECKSUM and EXT_DOC_REF_CHECKSUM ensure that the passed
 45    # checksum_str is formatted in the way that the following lines of code can't cause an error.
 46    algorithm, value = checksum_str.split(":")
 47    algorithm = ChecksumAlgorithm[algorithm.upper().replace("-", "_")]
 48    value = value.strip()
 49    checksum = Checksum(algorithm, value)
 50    return checksum
 51
 52
 53def set_value(
 54    parsed_value: YaccProduction,
 55    dict_to_fill: Dict[str, Any],
 56    argument_name: Optional[str] = None,
 57    method_to_apply: Callable = lambda x: x,
 58):
 59    if not argument_name:
 60        argument_name = get_property_name(parsed_value[1])
 61    if argument_name in dict_to_fill:
 62        dict_to_fill["logger"].append(f"Multiple values for {parsed_value[1]} found. Line: {parsed_value.lineno(1)}")
 63        return
 64    try:
 65        dict_to_fill[argument_name] = method_to_apply(parsed_value[2])
 66    except SPDXParsingError as err:
 67        dict_to_fill["logger"].append(err.get_messages())
 68    except ValueError as err:
 69        dict_to_fill["logger"].append(err.args[0])
 70    except KeyError:
 71        dict_to_fill["logger"].append(f"Invalid {parsed_value[1]}: {parsed_value[2]}. Line: {parsed_value.lineno(1)}")
 72
 73
 74def get_property_name(tag: str):
 75    if tag not in TAG_DATA_MODEL_FIELD.keys():
 76        return camel_case_to_snake_case(tag)
 77    return TAG_DATA_MODEL_FIELD[tag][1]
 78
 79
 80# This dictionary serves as a mapping from a tag to the corresponding class and field in the internal data model.
 81# This mapping is not complete as we only list the values which can be parsed by a generic method and don't need any
 82# individual logic.
 83TAG_DATA_MODEL_FIELD = {
 84    "SPDXVersion": (CreationInfo, "spdx_version"),
 85    "DataLicense": (CreationInfo, "data_license"),
 86    "DocumentName": (CreationInfo, "name"),
 87    "DocumentComment": (CreationInfo, "document_comment"),
 88    "DocumentNamespace": (CreationInfo, "document_namespace"),
 89    "Creator": (CreationInfo, "creator"),
 90    "Created": (CreationInfo, "created"),
 91    "CreatorComment": (CreationInfo, "creator_comment"),
 92    "LicenseListVersion": (CreationInfo, "license_list_version"),
 93    "ExternalDocumentRef": (CreationInfo, "external_document_refs"),
 94    "FileName": (File, "name"),
 95    "FileType": (File, "file_type"),
 96    "FileChecksum": (File, "checksums"),
 97    "FileNotice": (File, "notice"),
 98    "FileCopyrightText": (File, "copyright_text"),
 99    "LicenseComments": (File, "license_comment"),
100    "FileComment": (File, "comment"),
101    "LicenseConcluded": (File, "license_concluded"),
102    "LicenseDeclared": (File, "license_declared"),
103    "PackageName": (Package, "name"),
104    "PackageComment": (Package, "comment"),
105    "PackageCopyrightText": (Package, "copyright_text"),
106    "PackageLicenseComments": (Package, "license_comment"),
107    "PackageLicenseDeclared": (Package, "license_declared"),
108    "PackageLicenseConcluded": (Package, "license_concluded"),
109    "PackageFileName": (Package, "file_name"),
110    "PackageVersion": (Package, "version"),
111    "PackageDownloadLocation": (Package, "download_location"),
112    "PackageSummary": (Package, "summary"),
113    "PackageSourceInfo": (Package, "source_info"),
114    "PackageSupplier": (Package, "supplier"),
115    "PackageOriginator": (Package, "originator"),
116    "PackageDescription": (Package, "description"),
117    "PackageHomePage": (Package, "homepage"),
118    "SnippetSPDXID": (Snippet, "spdx_id"),
119    "SnippetFromFileSPDXID": (Snippet, "file_spdx_id"),
120    "SnippetName": (Snippet, "name"),
121    "SnippetComment": (Snippet, "comment"),
122    "SnippetCopyrightText": (Snippet, "copyright_text"),
123    "SnippetLicenseComments": (Snippet, "license_comment"),
124    "SnippetLicenseConcluded": (Snippet, "license_concluded"),
125    "SnippetByteRange": (Snippet, "byte_range"),
126    "SnippetLineRange": (Snippet, "line_range"),
127    "Annotator": (Annotation, "annotator"),
128    "SPDXREF": (Annotation, "spdx_id"),
129    "AnnotationComment": (Annotation, "annotation_comment"),
130    "LicenseID": (ExtractedLicensingInfo, "license_id"),
131    "ExtractedText": (ExtractedLicensingInfo, "extracted_text"),
132    "LicenseComment": (ExtractedLicensingInfo, "comment"),
133    "LicenseName": (ExtractedLicensingInfo, "license_name"),
134}
def grammar_rule(doc):
24def grammar_rule(doc):
25    # this is a helper method to use decorators for the parsing methods instead of docstrings
26    def decorate(func):
27        func.__doc__ = doc
28        return func
29
30    return decorate
def str_from_text(text: Optional[str]) -> Optional[str]:
33def str_from_text(text: Optional[str]) -> Optional[str]:
34    regex = re.compile("<text>((.|\n)+)</text>", re.UNICODE)
35    match = regex.match(text)
36    if match:
37        return match.group(1)
38    elif isinstance(text, str):
39        return text
40    else:
41        return None
def parse_checksum(checksum_str: str) -> spdx_tools.spdx.model.checksum.Checksum:
44def parse_checksum(checksum_str: str) -> Checksum:
45    # The lexer and the corresponding regex for the token CHECKSUM and EXT_DOC_REF_CHECKSUM ensure that the passed
46    # checksum_str is formatted in the way that the following lines of code can't cause an error.
47    algorithm, value = checksum_str.split(":")
48    algorithm = ChecksumAlgorithm[algorithm.upper().replace("-", "_")]
49    value = value.strip()
50    checksum = Checksum(algorithm, value)
51    return checksum
def set_value( parsed_value: ply.yacc.YaccProduction, dict_to_fill: dict[str, typing.Any], argument_name: Optional[str] = None, method_to_apply: collections.abc.Callable = <function <lambda>>):
54def set_value(
55    parsed_value: YaccProduction,
56    dict_to_fill: Dict[str, Any],
57    argument_name: Optional[str] = None,
58    method_to_apply: Callable = lambda x: x,
59):
60    if not argument_name:
61        argument_name = get_property_name(parsed_value[1])
62    if argument_name in dict_to_fill:
63        dict_to_fill["logger"].append(f"Multiple values for {parsed_value[1]} found. Line: {parsed_value.lineno(1)}")
64        return
65    try:
66        dict_to_fill[argument_name] = method_to_apply(parsed_value[2])
67    except SPDXParsingError as err:
68        dict_to_fill["logger"].append(err.get_messages())
69    except ValueError as err:
70        dict_to_fill["logger"].append(err.args[0])
71    except KeyError:
72        dict_to_fill["logger"].append(f"Invalid {parsed_value[1]}: {parsed_value[2]}. Line: {parsed_value.lineno(1)}")
def get_property_name(tag: str):
75def get_property_name(tag: str):
76    if tag not in TAG_DATA_MODEL_FIELD.keys():
77        return camel_case_to_snake_case(tag)
78    return TAG_DATA_MODEL_FIELD[tag][1]
TAG_DATA_MODEL_FIELD = {'SPDXVersion': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'spdx_version'), 'DataLicense': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'data_license'), 'DocumentName': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'name'), 'DocumentComment': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'document_comment'), 'DocumentNamespace': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'document_namespace'), 'Creator': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'creator'), 'Created': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'created'), 'CreatorComment': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'creator_comment'), 'LicenseListVersion': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'license_list_version'), 'ExternalDocumentRef': (<class 'spdx_tools.spdx.model.document.CreationInfo'>, 'external_document_refs'), 'FileName': (<class 'spdx_tools.spdx.model.file.File'>, 'name'), 'FileType': (<class 'spdx_tools.spdx.model.file.File'>, 'file_type'), 'FileChecksum': (<class 'spdx_tools.spdx.model.file.File'>, 'checksums'), 'FileNotice': (<class 'spdx_tools.spdx.model.file.File'>, 'notice'), 'FileCopyrightText': (<class 'spdx_tools.spdx.model.file.File'>, 'copyright_text'), 'LicenseComments': (<class 'spdx_tools.spdx.model.file.File'>, 'license_comment'), 'FileComment': (<class 'spdx_tools.spdx.model.file.File'>, 'comment'), 'LicenseConcluded': (<class 'spdx_tools.spdx.model.file.File'>, 'license_concluded'), 'LicenseDeclared': (<class 'spdx_tools.spdx.model.file.File'>, 'license_declared'), 'PackageName': (<class 'spdx_tools.spdx.model.package.Package'>, 'name'), 'PackageComment': (<class 'spdx_tools.spdx.model.package.Package'>, 'comment'), 'PackageCopyrightText': (<class 'spdx_tools.spdx.model.package.Package'>, 'copyright_text'), 'PackageLicenseComments': (<class 'spdx_tools.spdx.model.package.Package'>, 'license_comment'), 'PackageLicenseDeclared': (<class 'spdx_tools.spdx.model.package.Package'>, 'license_declared'), 'PackageLicenseConcluded': (<class 'spdx_tools.spdx.model.package.Package'>, 'license_concluded'), 'PackageFileName': (<class 'spdx_tools.spdx.model.package.Package'>, 'file_name'), 'PackageVersion': (<class 'spdx_tools.spdx.model.package.Package'>, 'version'), 'PackageDownloadLocation': (<class 'spdx_tools.spdx.model.package.Package'>, 'download_location'), 'PackageSummary': (<class 'spdx_tools.spdx.model.package.Package'>, 'summary'), 'PackageSourceInfo': (<class 'spdx_tools.spdx.model.package.Package'>, 'source_info'), 'PackageSupplier': (<class 'spdx_tools.spdx.model.package.Package'>, 'supplier'), 'PackageOriginator': (<class 'spdx_tools.spdx.model.package.Package'>, 'originator'), 'PackageDescription': (<class 'spdx_tools.spdx.model.package.Package'>, 'description'), 'PackageHomePage': (<class 'spdx_tools.spdx.model.package.Package'>, 'homepage'), 'SnippetSPDXID': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'spdx_id'), 'SnippetFromFileSPDXID': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'file_spdx_id'), 'SnippetName': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'name'), 'SnippetComment': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'comment'), 'SnippetCopyrightText': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'copyright_text'), 'SnippetLicenseComments': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'license_comment'), 'SnippetLicenseConcluded': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'license_concluded'), 'SnippetByteRange': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'byte_range'), 'SnippetLineRange': (<class 'spdx_tools.spdx.model.snippet.Snippet'>, 'line_range'), 'Annotator': (<class 'spdx_tools.spdx.model.annotation.Annotation'>, 'annotator'), 'SPDXREF': (<class 'spdx_tools.spdx.model.annotation.Annotation'>, 'spdx_id'), 'AnnotationComment': (<class 'spdx_tools.spdx.model.annotation.Annotation'>, 'annotation_comment'), 'LicenseID': (<class 'spdx_tools.spdx.model.extracted_licensing_info.ExtractedLicensingInfo'>, 'license_id'), 'ExtractedText': (<class 'spdx_tools.spdx.model.extracted_licensing_info.ExtractedLicensingInfo'>, 'extracted_text'), 'LicenseComment': (<class 'spdx_tools.spdx.model.extracted_licensing_info.ExtractedLicensingInfo'>, 'comment'), 'LicenseName': (<class 'spdx_tools.spdx.model.extracted_licensing_info.ExtractedLicensingInfo'>, 'license_name')}