Skip to content

Commit bebda4f

Browse files
qkaiserjkowalleck
andauthored
fix: implement __lt__ for models still missing it (#899)
--------- Signed-off-by: Quentin Kaiser <quentin.kaiser@onekey.com> Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> Co-authored-by: Jan Kowalleck <jan.kowalleck@gmail.com>
1 parent 9425c67 commit bebda4f

14 files changed

+474
-0
lines changed

cyclonedx/model/bom.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,11 @@ def __eq__(self, other: object) -> bool:
307307
return self.__comparable_tuple() == other.__comparable_tuple()
308308
return False
309309

310+
def __lt__(self, other: object) -> bool:
311+
if isinstance(other, BomMetaData):
312+
return self.__comparable_tuple() == other.__comparable_tuple()
313+
return NotImplemented
314+
310315
def __hash__(self) -> int:
311316
return hash(self.__comparable_tuple())
312317

cyclonedx/model/component.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,11 @@ def __eq__(self, other: object) -> bool:
654654
return self.__comparable_tuple() == other.__comparable_tuple()
655655
return False
656656

657+
def __lt__(self, other: object) -> bool:
658+
if isinstance(other, Pedigree):
659+
return self.__comparable_tuple() < other.__comparable_tuple()
660+
return NotImplemented
661+
657662
def __hash__(self) -> int:
658663
return hash(self.__comparable_tuple())
659664

@@ -806,6 +811,11 @@ def __eq__(self, other: object) -> bool:
806811
return self.__comparable_tuple() == other.__comparable_tuple()
807812
return False
808813

814+
def __lt__(self, other: object) -> bool:
815+
if isinstance(other, Swid):
816+
return self.__comparable_tuple() < other.__comparable_tuple()
817+
return NotImplemented
818+
809819
def __hash__(self) -> int:
810820
return hash(self.__comparable_tuple())
811821

cyclonedx/model/component_evidence.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,11 @@ def __eq__(self, other: object) -> bool:
561561
return self.__comparable_tuple() == other.__comparable_tuple()
562562
return False
563563

564+
def __lt__(self, other: object) -> bool:
565+
if isinstance(other, CallStackFrame):
566+
return self.__comparable_tuple() < other.__comparable_tuple()
567+
return NotImplemented
568+
564569
def __hash__(self) -> int:
565570
return hash(self.__comparable_tuple())
566571

@@ -744,6 +749,11 @@ def __eq__(self, other: object) -> bool:
744749
return self.__comparable_tuple() == other.__comparable_tuple()
745750
return False
746751

752+
def __lt__(self, other: object) -> bool:
753+
if isinstance(other, ComponentEvidence):
754+
return self.__comparable_tuple() < other.__comparable_tuple()
755+
return NotImplemented
756+
747757
def __hash__(self) -> int:
748758
return hash(self.__comparable_tuple())
749759

cyclonedx/model/crypto.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,11 @@ def __eq__(self, other: object) -> bool:
507507
return self.__comparable_tuple() == other.__comparable_tuple()
508508
return False
509509

510+
def __lt__(self, other: object) -> bool:
511+
if isinstance(other, AlgorithmProperties):
512+
return self.__comparable_tuple() < other.__comparable_tuple()
513+
return NotImplemented
514+
510515
def __hash__(self) -> int:
511516
return hash(self.__comparable_tuple())
512517

@@ -683,6 +688,11 @@ def __eq__(self, other: object) -> bool:
683688
return self.__comparable_tuple() == other.__comparable_tuple()
684689
return False
685690

691+
def __lt__(self, other: object) -> bool:
692+
if isinstance(other, CertificateProperties):
693+
return self.__comparable_tuple() < other.__comparable_tuple()
694+
return NotImplemented
695+
686696
def __hash__(self) -> int:
687697
return hash(self.__comparable_tuple())
688698

@@ -810,6 +820,11 @@ def __eq__(self, other: object) -> bool:
810820
return self.__comparable_tuple() == other.__comparable_tuple()
811821
return False
812822

823+
def __lt__(self, other: object) -> bool:
824+
if isinstance(other, RelatedCryptoMaterialSecuredBy):
825+
return self.__comparable_tuple() < other.__comparable_tuple()
826+
return NotImplemented
827+
813828
def __hash__(self) -> int:
814829
return hash(self.__comparable_tuple())
815830

@@ -1055,6 +1070,11 @@ def __eq__(self, other: object) -> bool:
10551070
return self.__comparable_tuple() == other.__comparable_tuple()
10561071
return False
10571072

1073+
def __lt__(self, other: object) -> bool:
1074+
if isinstance(other, RelatedCryptoMaterialProperties):
1075+
return self.__comparable_tuple() < other.__comparable_tuple()
1076+
return NotImplemented
1077+
10581078
def __hash__(self) -> int:
10591079
return hash(self.__comparable_tuple())
10601080

@@ -1314,6 +1334,11 @@ def __eq__(self, other: object) -> bool:
13141334
return self.__comparable_tuple() == other.__comparable_tuple()
13151335
return False
13161336

1337+
def __lt__(self, other: object) -> bool:
1338+
if isinstance(other, Ikev2TransformTypes):
1339+
return self.__comparable_tuple() < other.__comparable_tuple()
1340+
return NotImplemented
1341+
13171342
def __hash__(self) -> int:
13181343
return hash(self.__comparable_tuple())
13191344

@@ -1440,6 +1465,11 @@ def __eq__(self, other: object) -> bool:
14401465
return self.__comparable_tuple() == other.__comparable_tuple()
14411466
return False
14421467

1468+
def __lt__(self, other: object) -> bool:
1469+
if isinstance(other, ProtocolProperties):
1470+
return self.__comparable_tuple() < other.__comparable_tuple()
1471+
return NotImplemented
1472+
14431473
def __hash__(self) -> int:
14441474
return hash(self.__comparable_tuple())
14451475

cyclonedx/model/release_note.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ def __eq__(self, other: object) -> bool:
250250
return self.__comparable_tuple() == other.__comparable_tuple()
251251
return False
252252

253+
def __lt__(self, other: object) -> bool:
254+
if isinstance(other, ReleaseNotes):
255+
return self.__comparable_tuple() < other.__comparable_tuple()
256+
return NotImplemented
257+
253258
def __hash__(self) -> int:
254259
return hash(self.__comparable_tuple())
255260

cyclonedx/model/tool.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@ def __eq__(self, other: object) -> bool:
266266
return self.__comparable_tuple() == other.__comparable_tuple()
267267
return False
268268

269+
def __lt__(self, other: object) -> bool:
270+
if isinstance(other, ToolRepository):
271+
return self.__comparable_tuple() < other.__comparable_tuple()
272+
return NotImplemented
273+
269274
def __hash__(self) -> int:
270275
return hash(self.__comparable_tuple())
271276

tests/_data/own/json/1.6/pr899.json

Lines changed: 170 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/test_deserialize_json.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,15 @@ def test_component_evidence_identity(self) -> None:
136136
json = json_loads(f.read())
137137
bom: Bom = Bom.from_json(json) # <<< is expected to not crash
138138
self.assertIsNotNone(bom)
139+
140+
def test_pr899(self) -> None:
141+
"""real world case from PR#899
142+
see https://github.com/CycloneDX/cyclonedx-python-lib/pull/899
143+
"""
144+
json_file = join(OWN_DATA_DIRECTORY, 'json',
145+
SchemaVersion.V1_6.to_version(),
146+
'pr899.json')
147+
with open(json_file) as f:
148+
json = json_loads(f.read())
149+
bom: Bom = Bom.from_json(json) # <<< is expected to not crash
150+
self.assertIsNotNone(bom)

tests/test_model_bom.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ def test_basic_bom_metadata(self) -> None:
107107
self.assertTrue(tools[0] in metadata.tools.tools)
108108
self.assertTrue(tools[1] in metadata.tools.tools)
109109

110+
def test_bom_metadata_sorting(self) -> None:
111+
"""Test that BomMetaData instances can be sorted without triggering TypeError"""
112+
metadata1 = BomMetaData(
113+
tools=[Tool(name='tool_a')],
114+
authors=[OrganizationalContact(name='contact_a')]
115+
)
116+
metadata2 = BomMetaData(
117+
tools=[Tool(name='tool_b')],
118+
authors=[OrganizationalContact(name='contact_b')]
119+
)
120+
metadata3 = BomMetaData(
121+
tools=[Tool(name='tool_c')],
122+
authors=[OrganizationalContact(name='contact_c')]
123+
)
124+
125+
# This should not raise TypeError: '<' not supported between instances
126+
metadata_list = [metadata3, metadata1, metadata2]
127+
sorted_metadata = sorted(metadata_list)
128+
self.assertEqual(len(sorted_metadata), 3)
129+
110130

111131
@ddt
112132
class TestBom(TestCase):

0 commit comments

Comments
 (0)