Skip to content

Commit e6f91fa

Browse files
jkowalleckwkootsemantic-release
authored
feat!: 9.0.1 (#777)
### BREAKING Changes * Fix: `model.vulnerability.VulnerabilityReference`'s properties are all mandatory ([#790](#790) via [#792](#792)) * Refactor: Rename `spdx.is_compund_expression` -> `spdx.is_expression` ([#779](#779)) * Behavior: `BomRef` affects comparison/hashing ([#754](#754) & [#780](#780)) This is only a breaking change if you relied on ordering of elements. * Behavior: streamline comparison/hashing functions ([#755](#755)) This is only a breaking change if you relied on ordering of elements. * Dependency: bump dependency `py-serializable >=2 <3`, was `>=1.1.1 <2` ([#775](#775)) This is only a breaking change if you have other packages depend on that specific version. --------- Signed-off-by: Jan Kowalleck <[email protected]> Signed-off-by: wkoot <[email protected]> Signed-off-by: semantic-release <[email protected]> Co-authored-by: wkoot <[email protected]> Co-authored-by: semantic-release <[email protected]>
1 parent 740aaf9 commit e6f91fa

File tree

56 files changed

+1337
-539
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1337
-539
lines changed

cyclonedx/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@
2222

2323
# !! version is managed by semantic_release
2424
# do not use typing here, or else `semantic_release` might have issues finding the variable
25-
__version__ = "8.9.0" # noqa:Q000
25+
__version__ = "9.0.1-rc.1" # noqa:Q000

cyclonedx/_internal/compare.py

+13-28
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def __lt__(self, other: Any) -> bool:
4242
return False
4343
if o is None:
4444
return True
45-
return True if s < o else False
45+
return bool(s < o)
4646
return False
4747

4848
def __gt__(self, other: Any) -> bool:
@@ -54,44 +54,29 @@ def __gt__(self, other: Any) -> bool:
5454
return True
5555
if o is None:
5656
return False
57-
return True if s > o else False
57+
return bool(s > o)
5858
return False
5959

6060

61-
class ComparableDict:
61+
class ComparableDict(ComparableTuple):
6262
"""
6363
Allows comparison of dictionaries, allowing for missing/None values.
6464
"""
6565

66-
def __init__(self, dict_: Dict[Any, Any]) -> None:
67-
self._dict = dict_
68-
69-
def __lt__(self, other: Any) -> bool:
70-
if not isinstance(other, ComparableDict):
71-
return True
72-
keys = sorted(self._dict.keys() | other._dict.keys())
73-
return ComparableTuple(self._dict.get(k) for k in keys) \
74-
< ComparableTuple(other._dict.get(k) for k in keys)
75-
76-
def __gt__(self, other: Any) -> bool:
77-
if not isinstance(other, ComparableDict):
78-
return False
79-
keys = sorted(self._dict.keys() | other._dict.keys())
80-
return ComparableTuple(self._dict.get(k) for k in keys) \
81-
> ComparableTuple(other._dict.get(k) for k in keys)
66+
def __new__(cls, d: Dict[Any, Any]) -> 'ComparableDict':
67+
return super(ComparableDict, cls).__new__(cls, sorted(d.items()))
8268

8369

8470
class ComparablePackageURL(ComparableTuple):
8571
"""
8672
Allows comparison of PackageURL, allowing for qualifiers.
8773
"""
8874

89-
def __new__(cls, purl: 'PackageURL') -> 'ComparablePackageURL':
90-
return super().__new__(
91-
ComparablePackageURL, (
92-
purl.type,
93-
purl.namespace,
94-
purl.version,
95-
ComparableDict(purl.qualifiers) if isinstance(purl.qualifiers, dict) else purl.qualifiers,
96-
purl.subpath
97-
))
75+
def __new__(cls, p: 'PackageURL') -> 'ComparablePackageURL':
76+
return super(ComparablePackageURL, cls).__new__(cls, (
77+
p.type,
78+
p.namespace,
79+
p.version,
80+
ComparableDict(p.qualifiers) if isinstance(p.qualifiers, dict) else p.qualifiers,
81+
p.subpath
82+
))

cyclonedx/factory/license.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from ..exception.factory import InvalidLicenseExpressionException, InvalidSpdxLicenseException
2121
from ..model.license import DisjunctiveLicense, LicenseExpression
22-
from ..spdx import fixup_id as spdx_fixup, is_compound_expression as is_spdx_compound_expression
22+
from ..spdx import fixup_id as spdx_fixup, is_expression as is_spdx_expression
2323

2424
if TYPE_CHECKING: # pragma: no cover
2525
from ..model import AttachedText, XsUri
@@ -57,11 +57,11 @@ def make_with_expression(self, expression: str, *,
5757
) -> LicenseExpression:
5858
"""Make a :class:`cyclonedx.model.license.LicenseExpression` with a compound expression.
5959
60-
Utilizes :func:`cyclonedx.spdx.is_compound_expression`.
60+
Utilizes :func:`cyclonedx.spdx.is_expression`.
6161
6262
:raises InvalidLicenseExpressionException: if param `value` is not known/supported license expression
6363
"""
64-
if is_spdx_compound_expression(expression):
64+
if is_spdx_expression(expression):
6565
return LicenseExpression(expression, acknowledgement=acknowledgement)
6666
raise InvalidLicenseExpressionException(expression)
6767

cyclonedx/model/__init__.py

+70-64
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from warnings import warn
3434
from xml.etree.ElementTree import Element as XmlElement # nosec B405
3535

36-
import serializable
36+
import py_serializable as serializable
3737
from sortedcontainers import SortedSet
3838

3939
from .._internal.compare import ComparableTuple as _ComparableTuple
@@ -128,22 +128,23 @@ def classification(self) -> str:
128128
def classification(self, classification: str) -> None:
129129
self._classification = classification
130130

131+
def __comparable_tuple(self) -> _ComparableTuple:
132+
return _ComparableTuple((
133+
self.flow, self.classification
134+
))
135+
131136
def __eq__(self, other: object) -> bool:
132137
if isinstance(other, DataClassification):
133-
return hash(other) == hash(self)
138+
return self.__comparable_tuple() == other.__comparable_tuple()
134139
return False
135140

136141
def __lt__(self, other: object) -> bool:
137142
if isinstance(other, DataClassification):
138-
return _ComparableTuple((
139-
self.flow, self.classification
140-
)) < _ComparableTuple((
141-
other.flow, other.classification
142-
))
143+
return self.__comparable_tuple() < other.__comparable_tuple()
143144
return NotImplemented
144145

145146
def __hash__(self) -> int:
146-
return hash((self.flow, self.classification))
147+
return hash(self.__comparable_tuple())
147148

148149
def __repr__(self) -> str:
149150
return f'<DataClassification flow={self.flow}>'
@@ -231,22 +232,23 @@ def content(self) -> str:
231232
def content(self, content: str) -> None:
232233
self._content = content
233234

235+
def __comparable_tuple(self) -> _ComparableTuple:
236+
return _ComparableTuple((
237+
self.content_type, self.encoding, self.content,
238+
))
239+
234240
def __eq__(self, other: object) -> bool:
235241
if isinstance(other, AttachedText):
236-
return hash(other) == hash(self)
242+
return self.__comparable_tuple() == other.__comparable_tuple()
237243
return False
238244

239245
def __lt__(self, other: Any) -> bool:
240246
if isinstance(other, AttachedText):
241-
return _ComparableTuple((
242-
self.content_type, self.content, self.encoding
243-
)) < _ComparableTuple((
244-
other.content_type, other.content, other.encoding
245-
))
247+
return self.__comparable_tuple() < other.__comparable_tuple()
246248
return NotImplemented
247249

248250
def __hash__(self) -> int:
249-
return hash((self.content, self.content_type, self.encoding))
251+
return hash(self.__comparable_tuple())
250252

251253
def __repr__(self) -> str:
252254
return f'<AttachedText content-type={self.content_type}, encoding={self.encoding}>'
@@ -510,22 +512,23 @@ def content(self) -> str:
510512
def content(self, content: str) -> None:
511513
self._content = content
512514

515+
def __comparable_tuple(self) -> _ComparableTuple:
516+
return _ComparableTuple((
517+
self.alg, self.content
518+
))
519+
513520
def __eq__(self, other: object) -> bool:
514521
if isinstance(other, HashType):
515-
return hash(other) == hash(self)
522+
return self.__comparable_tuple() == other.__comparable_tuple()
516523
return False
517524

518525
def __lt__(self, other: Any) -> bool:
519526
if isinstance(other, HashType):
520-
return _ComparableTuple((
521-
self.alg, self.content
522-
)) < _ComparableTuple((
523-
other.alg, other.content
524-
))
527+
return self.__comparable_tuple() < other.__comparable_tuple()
525528
return NotImplemented
526529

527530
def __hash__(self) -> int:
528-
return hash((self.alg, self.content))
531+
return hash(self.__comparable_tuple())
529532

530533
def __repr__(self) -> str:
531534
return f'<HashType {self.alg.name}:{self.content}>'
@@ -728,7 +731,7 @@ def __init__(self, uri: str) -> None:
728731

729732
def __eq__(self, other: Any) -> bool:
730733
if isinstance(other, XsUri):
731-
return hash(other) == hash(self)
734+
return self._uri == other._uri
732735
return False
733736

734737
def __lt__(self, other: Any) -> bool:
@@ -887,25 +890,24 @@ def hashes(self) -> 'SortedSet[HashType]':
887890
def hashes(self, hashes: Iterable[HashType]) -> None:
888891
self._hashes = SortedSet(hashes)
889892

893+
def __comparable_tuple(self) -> _ComparableTuple:
894+
return _ComparableTuple((
895+
self._type, self._url, self._comment,
896+
_ComparableTuple(self._hashes)
897+
))
898+
890899
def __eq__(self, other: object) -> bool:
891900
if isinstance(other, ExternalReference):
892-
return hash(other) == hash(self)
901+
return self.__comparable_tuple() == other.__comparable_tuple()
893902
return False
894903

895904
def __lt__(self, other: Any) -> bool:
896905
if isinstance(other, ExternalReference):
897-
return _ComparableTuple((
898-
self._type, self._url, self._comment
899-
)) < _ComparableTuple((
900-
other._type, other._url, other._comment
901-
))
906+
return self.__comparable_tuple() < other.__comparable_tuple()
902907
return NotImplemented
903908

904909
def __hash__(self) -> int:
905-
return hash((
906-
self._type, self._url, self._comment,
907-
tuple(sorted(self._hashes, key=hash))
908-
))
910+
return hash(self.__comparable_tuple())
909911

910912
def __repr__(self) -> str:
911913
return f'<ExternalReference {self.type.name}, {self.url}>'
@@ -964,22 +966,23 @@ def value(self) -> Optional[str]:
964966
def value(self, value: Optional[str]) -> None:
965967
self._value = value
966968

969+
def __comparable_tuple(self) -> _ComparableTuple:
970+
return _ComparableTuple((
971+
self.name, self.value
972+
))
973+
967974
def __eq__(self, other: object) -> bool:
968975
if isinstance(other, Property):
969-
return hash(other) == hash(self)
976+
return self.__comparable_tuple() == other.__comparable_tuple()
970977
return False
971978

972979
def __lt__(self, other: Any) -> bool:
973980
if isinstance(other, Property):
974-
return _ComparableTuple((
975-
self.name, self.value
976-
)) < _ComparableTuple((
977-
other.name, other.value
978-
))
981+
return self.__comparable_tuple() < other.__comparable_tuple()
979982
return NotImplemented
980983

981984
def __hash__(self) -> int:
982-
return hash((self.name, self.value))
985+
return hash(self.__comparable_tuple())
983986

984987
def __repr__(self) -> str:
985988
return f'<Property name={self.name}>'
@@ -1055,22 +1058,23 @@ def encoding(self) -> Optional[Encoding]:
10551058
def encoding(self, encoding: Optional[Encoding]) -> None:
10561059
self._encoding = encoding
10571060

1061+
def __comparable_tuple(self) -> _ComparableTuple:
1062+
return _ComparableTuple((
1063+
self.content, self.content_type, self.encoding
1064+
))
1065+
10581066
def __eq__(self, other: object) -> bool:
10591067
if isinstance(other, NoteText):
1060-
return hash(other) == hash(self)
1068+
return self.__comparable_tuple() == other.__comparable_tuple()
10611069
return False
10621070

10631071
def __lt__(self, other: Any) -> bool:
10641072
if isinstance(other, NoteText):
1065-
return _ComparableTuple((
1066-
self.content, self.content_type, self.encoding
1067-
)) < _ComparableTuple((
1068-
other.content, other.content_type, other.encoding
1069-
))
1073+
return self.__comparable_tuple() < other.__comparable_tuple()
10701074
return NotImplemented
10711075

10721076
def __hash__(self) -> int:
1073-
return hash((self.content, self.content_type, self.encoding))
1077+
return hash(self.__comparable_tuple())
10741078

10751079
def __repr__(self) -> str:
10761080
return f'<NoteText content_type={self.content_type}, encoding={self.encoding}>'
@@ -1139,22 +1143,23 @@ def locale(self, locale: Optional[str]) -> None:
11391143
" ISO-3166 (or higher) country code. according to ISO-639 format. Examples include: 'en', 'en-US'."
11401144
)
11411145

1146+
def __comparable_tuple(self) -> _ComparableTuple:
1147+
return _ComparableTuple((
1148+
self.locale, self.text
1149+
))
1150+
11421151
def __eq__(self, other: object) -> bool:
11431152
if isinstance(other, Note):
1144-
return hash(other) == hash(self)
1153+
return self.__comparable_tuple() == other.__comparable_tuple()
11451154
return False
11461155

11471156
def __lt__(self, other: Any) -> bool:
11481157
if isinstance(other, Note):
1149-
return _ComparableTuple((
1150-
self.locale, self.text
1151-
)) < _ComparableTuple((
1152-
other.locale, other.text
1153-
))
1158+
return self.__comparable_tuple() < other.__comparable_tuple()
11541159
return NotImplemented
11551160

11561161
def __hash__(self) -> int:
1157-
return hash((self.text, self.locale))
1162+
return hash(self.__comparable_tuple())
11581163

11591164
def __repr__(self) -> str:
11601165
return f'<Note id={id(self)}, locale={self.locale}>'
@@ -1224,22 +1229,23 @@ def email(self) -> Optional[str]:
12241229
def email(self, email: Optional[str]) -> None:
12251230
self._email = email
12261231

1232+
def __comparable_tuple(self) -> _ComparableTuple:
1233+
return _ComparableTuple((
1234+
self.timestamp, self.name, self.email
1235+
))
1236+
12271237
def __eq__(self, other: object) -> bool:
12281238
if isinstance(other, IdentifiableAction):
1229-
return hash(other) == hash(self)
1239+
return self.__comparable_tuple() == other.__comparable_tuple()
12301240
return False
12311241

12321242
def __lt__(self, other: Any) -> bool:
12331243
if isinstance(other, IdentifiableAction):
1234-
return _ComparableTuple((
1235-
self.timestamp, self.name, self.email
1236-
)) < _ComparableTuple((
1237-
other.timestamp, other.name, other.email
1238-
))
1244+
return self.__comparable_tuple() < other.__comparable_tuple()
12391245
return NotImplemented
12401246

12411247
def __hash__(self) -> int:
1242-
return hash((self.timestamp, self.name, self.email))
1248+
return hash(self.__comparable_tuple())
12431249

12441250
def __repr__(self) -> str:
12451251
return f'<IdentifiableAction name={self.name}, email={self.email}>'
@@ -1277,16 +1283,16 @@ def text(self, text: str) -> None:
12771283

12781284
def __eq__(self, other: object) -> bool:
12791285
if isinstance(other, Copyright):
1280-
return hash(other) == hash(self)
1286+
return self._text == other._text
12811287
return False
12821288

12831289
def __lt__(self, other: Any) -> bool:
12841290
if isinstance(other, Copyright):
1285-
return self.text < other.text
1291+
return self._text < other._text
12861292
return NotImplemented
12871293

12881294
def __hash__(self) -> int:
1289-
return hash(self.text)
1295+
return hash(self._text)
12901296

12911297
def __repr__(self) -> str:
12921298
return f'<Copyright text={self.text}>'

0 commit comments

Comments
 (0)