Skip to content

Commit

Permalink
feat: complete SPDX license expression (#425)
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
  • Loading branch information
jkowalleck authored Sep 6, 2023
1 parent 13e441d commit e06f9fd
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 11 deletions.
25 changes: 18 additions & 7 deletions cyclonedx/spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@
#
# SPDX-License-Identifier: Apache-2.0

__all__ = ['is_supported_id', 'fixup_id', 'is_compound_expression']
__all__ = [
'is_supported_id', 'fixup_id',
'is_compound_expression'
]

from json import load as json_load
from os.path import dirname, join as path_join
from typing import Dict, Optional, Set
from typing import TYPE_CHECKING, Dict, Optional, Set

from license_expression import get_spdx_licensing # type: ignore

if TYPE_CHECKING:
from license_expression import Licensing

# region init
# python's internal module loader will assure that this init-part runs only once.
Expand All @@ -30,9 +38,11 @@

__IDS_LOWER_MAP: Dict[str, str] = dict((id_.lower(), id_) for id_ in __IDS)

__SPDX_EXPRESSION_LICENSING: 'Licensing' = get_spdx_licensing()

# endregion


def is_supported_id(value: str) -> bool:
"""Validate a SPDX-ID according to current spec."""
return value in __IDS
Expand All @@ -50,11 +60,12 @@ def is_compound_expression(value: str) -> bool:
"""Validate compound expression.
.. note::
Uses a best-effort detection of SPDX compound expression according to `SPDX license expression spec`_.
Utilizes `license-expression library`_ to
validate SPDX compound expression according to `SPDX license expression spec`_.
.. _SPDX license expression spec: https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions/
.. _license-expression library: https://github.com/nexB/license-expression
"""
# shortest known valid expression: (A or B) - 8 characters long
return len(value) >= 8 \
and value.startswith('(') \
and value.endswith(')')
return 0 == len(
__SPDX_EXPRESSION_LICENSING.validate(value).errors
)
33 changes: 32 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ python = "^3.7"
packageurl-python = ">= 0.11"
py-serializable = "^0.11.1"
sortedcontainers = "^2.4.0"
license-expression = "^30"

[tool.poetry.dev-dependencies]
ddt = "^1.6.0"
Expand Down
7 changes: 4 additions & 3 deletions tests/test_spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@

VALID_COMPOUND_EXPRESSIONS = {
# for valid test data see the spec: https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions/
'(MIT WITH Apache-2.0)',
'(BSD-2-Clause OR Apache-2.0)',
'(MIT AND Apache-2.0)',
'BSD-2-Clause OR Apache-2.0',
}


Expand Down Expand Up @@ -89,8 +89,9 @@ def test_positive(self, valid_expression: str) -> None:
self.assertTrue(actual)

@data(
'MIT AND Apache-2.0 OR something-unknown'
'something invalid',
'(c) John Doe'
'(c) John Doe',
)
def test_negative(self, invalid_expression: str) -> None:
actual = spdx.is_compound_expression(invalid_expression)
Expand Down

0 comments on commit e06f9fd

Please sign in to comment.