Skip to content

Commit c5efc8c

Browse files
authored
refactor: reuse internal helper bom_ref_from_str (#727)
fixes #722 Signed-off-by: Jan Kowalleck <[email protected]>
1 parent bca1d77 commit c5efc8c

File tree

7 files changed

+103
-18
lines changed

7 files changed

+103
-18
lines changed

cyclonedx/_internal/bom_ref.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,31 @@
2121
Everything might change without any notice.
2222
"""
2323

24-
from typing import Optional, Union
24+
from typing import Literal, Optional, Union, overload
2525

2626
from ..model.bom_ref import BomRef
2727

2828

29-
def bom_ref_from_str(bom_ref: Optional[Union[str, BomRef]]) -> BomRef:
29+
@overload
30+
def bom_ref_from_str(bom_ref: BomRef, optional: bool = ...) -> BomRef:
31+
... # pragma: no cover
32+
33+
34+
@overload
35+
def bom_ref_from_str(bom_ref: Optional[str], optional: Literal[False] = False) -> BomRef:
36+
... # pragma: no cover
37+
38+
39+
@overload
40+
def bom_ref_from_str(bom_ref: Optional[str], optional: Literal[True] = ...) -> Optional[BomRef]:
41+
... # pragma: no cover
42+
43+
44+
def bom_ref_from_str(bom_ref: Optional[Union[str, BomRef]], optional: bool = False) -> Optional[BomRef]:
3045
if isinstance(bom_ref, BomRef):
3146
return bom_ref
32-
else:
33-
return BomRef(value=str(bom_ref) if bom_ref else None)
47+
if bom_ref:
48+
return BomRef(value=str(bom_ref))
49+
return None \
50+
if optional \
51+
else BomRef()

cyclonedx/model/component.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from packageurl import PackageURL
2727
from sortedcontainers import SortedSet
2828

29+
from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str
2930
from .._internal.compare import ComparablePackageURL as _ComparablePackageURL, ComparableTuple as _ComparableTuple
3031
from .._internal.hash import file_sha1sum as _file_sha1sum
3132
from ..exception.model import InvalidOmniBorIdException, InvalidSwhidException, NoPropertiesProvidedException
@@ -1097,10 +1098,7 @@ def __init__(
10971098
) -> None:
10981099
self.type = type
10991100
self.mime_type = mime_type
1100-
if isinstance(bom_ref, BomRef):
1101-
self._bom_ref = bom_ref
1102-
else:
1103-
self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else None)
1101+
self._bom_ref = _bom_ref_from_str(bom_ref)
11041102
self.supplier = supplier
11051103
self.manufacturer = manufacturer
11061104
self.authors = authors or [] # type:ignore[assignment]

cyclonedx/model/contact.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import serializable
2222
from sortedcontainers import SortedSet
2323

24+
from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str
2425
from .._internal.compare import ComparableTuple as _ComparableTuple
2526
from ..exception.model import NoPropertiesProvidedException
2627
from ..schema.schema import SchemaVersion1Dot6
@@ -49,8 +50,7 @@ def __init__(
4950
postal_code: Optional[str] = None,
5051
street_address: Optional[str] = None,
5152
) -> None:
52-
self._bom_ref = bom_ref if isinstance(bom_ref, BomRef) else BomRef(
53-
value=bom_ref) if bom_ref else None
53+
self._bom_ref = _bom_ref_from_str(bom_ref, optional=True)
5454
self.country = country
5555
self.region = region
5656
self.locality = locality

cyclonedx/model/service.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
from cyclonedx.serialization import BomRefHelper, LicenseRepositoryHelper
3333

34+
from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str
3435
from .._internal.compare import ComparableTuple as _ComparableTuple
3536
from ..schema.schema import SchemaVersion1Dot3, SchemaVersion1Dot4, SchemaVersion1Dot5, SchemaVersion1Dot6
3637
from . import DataClassification, ExternalReference, Property, XsUri
@@ -68,10 +69,7 @@ def __init__(
6869
services: Optional[Iterable['Service']] = None,
6970
release_notes: Optional[ReleaseNotes] = None,
7071
) -> None:
71-
if isinstance(bom_ref, BomRef):
72-
self._bom_ref = bom_ref
73-
else:
74-
self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else None)
72+
self._bom_ref = _bom_ref_from_str(bom_ref)
7573
self.provider = provider
7674
self.group = group
7775
self.name = name

cyclonedx/model/vulnerability.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import serializable
3939
from sortedcontainers import SortedSet
4040

41+
from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str
4142
from .._internal.compare import ComparableTuple as _ComparableTuple
4243
from ..exception.model import MutuallyExclusivePropertiesException, NoPropertiesProvidedException
4344
from ..schema.schema import SchemaVersion1Dot4, SchemaVersion1Dot5, SchemaVersion1Dot6
@@ -959,10 +960,7 @@ def __init__(
959960
affects: Optional[Iterable[BomTarget]] = None,
960961
properties: Optional[Iterable[Property]] = None,
961962
) -> None:
962-
if isinstance(bom_ref, BomRef):
963-
self._bom_ref: BomRef = bom_ref
964-
else:
965-
self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else None)
963+
self._bom_ref = _bom_ref_from_str(bom_ref)
966964
self.id = id
967965
self.source = source
968966
self.references = references or [] # type:ignore[assignment]

tests/test_internal/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This file is part of CycloneDX Python Library
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
# Copyright (c) OWASP Foundation. All Rights Reserved.

tests/test_internal/test_bom_ref.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# This file is part of CycloneDX Python Library
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
# Copyright (c) OWASP Foundation. All Rights Reserved.
17+
18+
from unittest import TestCase
19+
20+
from cyclonedx._internal.bom_ref import bom_ref_from_str
21+
from cyclonedx.model.bom_ref import BomRef
22+
23+
24+
class TestInternalBomRefFromStr(TestCase):
25+
26+
def test_bomref_io(self) -> None:
27+
i = BomRef()
28+
o = bom_ref_from_str(i)
29+
self.assertIs(i, o)
30+
31+
def test_none_optional_is_none(self) -> None:
32+
o = bom_ref_from_str(None, optional=True)
33+
self.assertIsNone(o)
34+
35+
def test_none_mandatory_is_something(self) -> None:
36+
o = bom_ref_from_str(None, optional=False)
37+
self.assertIsInstance(o, BomRef)
38+
self.assertIsNone(o.value)
39+
40+
def test_nothing_optional_is_none(self) -> None:
41+
o = bom_ref_from_str('', optional=True)
42+
self.assertIsNone(o)
43+
44+
def test_nothing_mandatory_is_something(self) -> None:
45+
o = bom_ref_from_str('', optional=False)
46+
self.assertIsInstance(o, BomRef)
47+
self.assertIsNone(o.value)
48+
49+
def test_something_optional(self) -> None:
50+
o = bom_ref_from_str('foobar', optional=True)
51+
self.assertIsInstance(o, BomRef)
52+
self.assertEqual('foobar', o.value)
53+
54+
def test_something_mandatory(self) -> None:
55+
o = bom_ref_from_str('foobar', optional=False)
56+
self.assertIsInstance(o, BomRef)
57+
self.assertEqual('foobar', o.value)

0 commit comments

Comments
 (0)